Bug 1308956 - Get rid of MessagePortList - part 1 - MessagePortList removed from events, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 13 Oct 2016 15:19:24 +0200
changeset 317854 f9d090c04d8fc96ac07691a45dcffc575aa3eb33
parent 317853 4c0c548d98c0baf23a3774709759d6b055e63c2f
child 317855 36d6e588e7d497d8d9154e9ed0e8732f8a42cd43
push id30819
push usercbook@mozilla.com
push dateFri, 14 Oct 2016 09:59:32 +0000
treeherdermozilla-central@1391a2889aeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1308956
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1308956 - Get rid of MessagePortList - part 1 - MessagePortList removed from events, r=smaug
devtools/client/shared/components/test/mochitest/test_reps_event.html
dom/base/PostMessageEvent.cpp
dom/events/MessageEvent.cpp
dom/events/MessageEvent.h
dom/events/test/mochitest.ini
dom/events/test/test_messageEvent_init.html
dom/messagechannel/MessagePort.cpp
dom/webidl/ExtendableMessageEvent.webidl
dom/webidl/MessageEvent.webidl
dom/webidl/ServiceWorkerMessageEvent.webidl
dom/workers/ServiceWorkerClient.cpp
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerEvents.h
dom/workers/ServiceWorkerMessageEvent.cpp
dom/workers/ServiceWorkerMessageEvent.h
dom/workers/WorkerPrivate.cpp
--- a/devtools/client/shared/components/test/mochitest/test_reps_event.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_event.html
@@ -244,17 +244,17 @@ window.onload = Task.async(function* () 
                 "ownPropertyLength": 760,
                 "preview": {
                   "kind": "ObjectWithURL",
                   "url": ""
                 }
               },
               "ports": {
                 "type": "object",
-                "class": "MessagePortList",
+                "class": "Array",
                 "actor": "server1.conn3.obj37",
                 "extensible": true,
                 "frozen": false,
                 "sealed": false,
                 "ownPropertyLength": 0
               },
               "currentTarget": {
                 "type": "object",
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -145,19 +145,17 @@ PostMessageEvent::Run()
   source.SetValue().SetAsWindowProxy() = mSource ? mSource->AsOuter() : nullptr;
 
   event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
                           false /*non-bubbling */, false /*cancelable */,
                           messageData, mCallerOrigin,
                           EmptyString(), source, nullptr);
 
   nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
-
-  event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
-                                      ports));
+  event->SetPorts(Move(ports));
 
   // We can't simply call dispatchEvent on the window because doing so ends
   // up flipping the trusted bit on the event, and we don't want that to
   // happen because then untrusted content can call postMessage on a chrome
   // window if it can get a reference to it.
 
   nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
   RefPtr<nsPresContext> presContext;
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
-#include "mozilla/dom/MessagePortList.h"
 
 #include "mozilla/HoldDropJSObjects.h"
 #include "jsapi.h"
 #include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
 
 namespace mozilla {
 namespace dom {
 
@@ -42,16 +41,17 @@ NS_INTERFACE_MAP_END_INHERITING(Event)
 NS_IMPL_ADDREF_INHERITED(MessageEvent, Event)
 NS_IMPL_RELEASE_INHERITED(MessageEvent, Event)
 
 MessageEvent::MessageEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetEvent* aEvent)
   : Event(aOwner, aPresContext, aEvent)
   , mData(JS::UndefinedValue())
+  , mPortsSet(false)
 {
 }
 
 MessageEvent::~MessageEvent()
 {
   mData.setUndefined();
   DropJSObjects(this);
 }
@@ -135,22 +135,18 @@ MessageEvent::Constructor(EventTarget* a
     } else {
       event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
     }
 
     MOZ_ASSERT(event->mWindowSource || event->mPortSource);
   }
 
   if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
-    nsTArray<RefPtr<MessagePort>> ports;
-    for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
-      ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
-    }
-
-    event->mPorts = new MessagePortList(static_cast<Event*>(event), ports);
+    event->mPorts.AppendElements(aParam.mPorts.Value().Value());
+    event->mPortsSet = true;
   }
 
   return event.forget();
 }
 
 void
 MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType,
                                bool aCanBubble, bool aCancelable,
@@ -173,33 +169,44 @@ MessageEvent::InitMessageEvent(JSContext
     if (aSource.Value().IsWindowProxy()) {
       auto* windowProxy = aSource.Value().GetAsWindowProxy();
       mWindowSource = windowProxy ? windowProxy->GetCurrentInnerWindow() : nullptr;
     } else {
       mPortSource = &aSource.Value().GetAsMessagePort();
     }
   }
 
-  mPorts = nullptr;
+  mPorts.Clear();
+  mPortsSet = false;
 
   if (!aPorts.IsNull()) {
-    nsTArray<RefPtr<MessagePort>> ports;
-    for (uint32_t i = 0, len = aPorts.Value().Length(); i < len; ++i) {
-      ports.AppendElement(aPorts.Value()[i]);
-    }
+    mPorts.AppendElements(aPorts.Value());
+    mPortsSet = true;
+  }
 
-    mPorts = new MessagePortList(static_cast<Event*>(this), ports);
-  }
+  MessageEventBinding::ClearCachedPortsValue(this);
 }
 
 void
-MessageEvent::SetPorts(MessagePortList* aPorts)
+MessageEvent::GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts)
 {
-  MOZ_ASSERT(!mPorts && aPorts);
-  mPorts = aPorts;
+  if (!mPortsSet) {
+    aPorts.SetNull();
+    return;
+  }
+
+  aPorts.SetValue(mPorts);
+}
+
+void
+MessageEvent::SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts)
+{
+  MOZ_ASSERT(mPorts.IsEmpty() && !mPortsSet);
+  mPorts = Move(aPorts);
+  mPortsSet = true;
 }
 
 void
 MessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
 {
   mPortSource = aPort;
 }
 
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -4,25 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_MessageEvent_h_
 #define mozilla_dom_MessageEvent_h_
 
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/MessagePortList.h"
 #include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
 struct MessageEventInit;
 class MessagePort;
-class MessagePortList;
 class OwningWindowProxyOrMessagePort;
 class WindowProxyOrMessagePort;
 
 /**
  * Implements the MessageEvent event, used for cross-document messaging and
  * server-sent events.
  *
  * See http://www.whatwg.org/specs/web-apps/current-work/#messageevent for
@@ -44,22 +42,19 @@ public:
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
                ErrorResult& aRv);
   void GetOrigin(nsAString&) const;
   void GetLastEventId(nsAString&) const;
   void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
 
-  MessagePortList* GetPorts()
-  {
-    return mPorts;
-  }
+  void GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts);
 
-  void SetPorts(MessagePortList* aPorts);
+  void SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts);
 
   // Non WebIDL methods
   void SetSource(mozilla::dom::MessagePort* aPort);
 
   void SetSource(nsPIDOMWindowInner* aWindow)
   {
     mWindowSource = aWindow;
   }
@@ -86,15 +81,17 @@ protected:
   ~MessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   RefPtr<nsPIDOMWindowInner> mWindowSource;
   RefPtr<MessagePort> mPortSource;
-  RefPtr<MessagePortList> mPorts;
+
+  nsTArray<RefPtr<MessagePort>> mPorts;
+  bool mPortsSet;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MessageEvent_h_
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -196,8 +196,9 @@ support-files =
 [test_eventhandler_scoping.html]
 [test_bug1013412.html]
 skip-if = buildapp == 'b2g' # no wheel events on b2g
 [test_dom_activate_event.html]
 [test_bug1264380.html]
 run-if = (e10s && os != "win") # Bug 1270043, crash at windows platforms; Bug1264380 comment 20, nsDragService::InvokeDragSessionImpl behaves differently among platform implementations in non-e10s mode which prevents us to check the validity of nsIDragService::getCurrentSession() consistently via synthesize mouse clicks in non-e10s mode.
 [test_passive_listeners.html]
 [test_paste_image.html]
+[test_messageEvent_init.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_messageEvent_init.html
@@ -0,0 +1,28 @@
+<html><head>
+<title>Test for bug 1308956</title>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+
+<body>
+  <script>
+
+var a = new MessageEvent("message")
+ok(!!a, "We have a MessageEvent");
+is(a.ports, null, "By default MessageEvent.ports is null");
+
+a.initMessageEvent("message", true, false, {}, window.location.href, "", null, []);
+ok(Array.isArray(a.ports), "After InitMessageEvent() we have an array");
+is(a.ports.length, 0, "Length is 0");
+
+var mc = new MessageChannel();
+a.initMessageEvent("message", true, false, {}, window.location.href, "", null, [mc.port1]);
+ok(Array.isArray(a.ports), "After InitMessageEvent() we have an array");
+is(a.ports.length, 1, "Length is 1");
+
+a.initMessageEvent("message", true, false, {}, window.location.href, "", null, null);
+is(a.ports, null, "By default MessageEvent.ports is null");
+
+  </script>
+</body>
+</html>
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -10,17 +10,16 @@
 #include "MessagePortChild.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortChild.h"
-#include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/MessagePortTimelineMarker.h"
 #include "mozilla/TimelineConsumers.h"
@@ -138,21 +137,17 @@ private:
     event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
                             false /* non-bubbling */,
                             false /* cancelable */, value, EmptyString(),
                             EmptyString(), nullptr, nullptr);
     event->SetTrusted(true);
     event->SetSource(mPort);
 
     nsTArray<RefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
-
-    RefPtr<MessagePortList> portList =
-      new MessagePortList(static_cast<dom::Event*>(event.get()),
-                          ports);
-    event->SetPorts(portList);
+    event->SetPorts(Move(ports));
 
     bool dummy;
     mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &dummy);
 
     return NS_OK;
   }
 
 private:
--- a/dom/webidl/ExtendableMessageEvent.webidl
+++ b/dom/webidl/ExtendableMessageEvent.webidl
@@ -26,17 +26,18 @@ interface ExtendableMessageEvent : Exten
    */
   readonly attribute DOMString lastEventId;
 
   /**
    * The client, service worker or port which originated this event.
    */
   readonly attribute (Client or ServiceWorker or MessagePort)? source;
 
-  [SameObject] readonly attribute MessagePortList? ports;
+  [Constant, Cached, Frozen]
+  readonly attribute sequence<MessagePort>? ports;
 };
 
 dictionary ExtendableMessageEventInit : ExtendableEventInit {
   any data;
   DOMString origin = "";
   DOMString lastEventId = "";
   (Client or ServiceWorker or MessagePort)? source;
   sequence<MessagePort>? ports;
--- a/dom/webidl/MessageEvent.webidl
+++ b/dom/webidl/MessageEvent.webidl
@@ -35,17 +35,18 @@ interface MessageEvent : Event {
    */
   readonly attribute (WindowProxy or MessagePort)? source;
 
   /**
    * Initializes this event with the given data, in a manner analogous to
    * the similarly-named method on the nsIDOMEvent interface, also setting the
    * data, origin, source, and lastEventId attributes of this appropriately.
    */
-  readonly attribute MessagePortList? ports;
+  [Pure, Cached, Frozen]
+  readonly attribute sequence<MessagePort>? ports;
 
   void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable,
                         any data, DOMString origin, DOMString lastEventId,
                         (WindowProxy or MessagePort)? source,
                         sequence<MessagePort>? ports);
 };
 
 dictionary MessageEventInit : EventInit {
--- a/dom/webidl/ServiceWorkerMessageEvent.webidl
+++ b/dom/webidl/ServiceWorkerMessageEvent.webidl
@@ -30,17 +30,18 @@ interface ServiceWorkerMessageEvent : Ev
 
   /**
    * The service worker or port which originated this event.
    * FIXME: Use SameOject after IDL spec is updated
    * https://bugzilla.mozilla.org/show_bug.cgi?id=1196097
    */
   [Constant] readonly attribute (ServiceWorker or MessagePort)? source;
 
-  [SameObject] readonly attribute MessagePortList? ports;
+  [Constant, Cached, Frozen]
+  readonly attribute sequence<MessagePort>? ports;
 };
 
 dictionary ServiceWorkerMessageEventInit : EventInit
 {
   any data;
   DOMString origin;
   DOMString lastEventId;
   (ServiceWorker or MessagePort)? source;
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -171,21 +171,17 @@ private:
       init.mSource.Value().SetNull();
     }
 
     RefPtr<ServiceWorkerMessageEvent> event =
       ServiceWorkerMessageEvent::Constructor(aTargetContainer,
                                              NS_LITERAL_STRING("message"), init, rv);
 
     nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
-
-    RefPtr<MessagePortList> portList =
-      new MessagePortList(static_cast<dom::Event*>(event.get()),
-                          ports);
-    event->SetPorts(portList);
+    event->SetPorts(Move(ports));
 
     event->SetTrusted(true);
     bool status = false;
     aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
                                     &status);
 
     if (!status) {
       return NS_ERROR_FAILURE;
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -29,17 +29,16 @@
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/BodyUtil.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/FetchEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
-#include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/PushEventBinding.h"
 #include "mozilla/dom/PushMessageDataBinding.h"
 #include "mozilla/dom/PushUtil.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/WorkerScope.h"
@@ -1167,16 +1166,17 @@ JSObject*
 PushEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::PushEventBinding::Wrap(aCx, this, aGivenProto);
 }
 
 ExtendableMessageEvent::ExtendableMessageEvent(EventTarget* aOwner)
   : ExtendableEvent(aOwner)
   , mData(JS::UndefinedValue())
+  , mPortsSet(false)
 {
   mozilla::HoldJSObjects(this);
 }
 
 ExtendableMessageEvent::~ExtendableMessageEvent()
 {
   mData.setUndefined();
   DropJSObjects(this);
@@ -1241,39 +1241,40 @@ ExtendableMessageEvent::Constructor(mozi
       event->mServiceWorker = aOptions.mSource.Value().Value().GetAsServiceWorker();
     } else if (aOptions.mSource.Value().Value().IsMessagePort()){
       event->mMessagePort = aOptions.mSource.Value().Value().GetAsMessagePort();
     }
     MOZ_ASSERT(event->mClient || event->mServiceWorker || event->mMessagePort);
   }
 
   if (aOptions.mPorts.WasPassed() && !aOptions.mPorts.Value().IsNull()) {
-    nsTArray<RefPtr<MessagePort>> ports;
-    const Sequence<OwningNonNull<MessagePort>>& portsParam =
-      aOptions.mPorts.Value().Value();
-    for (uint32_t i = 0, len = portsParam.Length(); i < len; ++i) {
-      ports.AppendElement(portsParam[i].get());
-    }
-    event->mPorts = new MessagePortList(static_cast<EventBase*>(event), ports);
+    event->mPorts.AppendElements(aOptions.mPorts.Value().Value());
+    event->mPortsSet = true;
   }
 
   return event.forget();
 }
 
-MessagePortList*
-ExtendableMessageEvent::GetPorts() const
+void
+ExtendableMessageEvent::GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts)
 {
-  return mPorts;
+  if (!mPortsSet) {
+    aPorts.SetNull();
+    return;
+  }
+
+  aPorts.SetValue(mPorts);
 }
 
 void
-ExtendableMessageEvent::SetPorts(MessagePortList* aPorts)
+ExtendableMessageEvent::SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts)
 {
-  MOZ_ASSERT(!mPorts && aPorts);
-  mPorts = aPorts;
+  MOZ_ASSERT(mPorts.IsEmpty() && !mPortsSet);
+  mPorts = Move(aPorts);
+  mPortsSet = true;
 }
 
 void
 ExtendableMessageEvent::SetSource(ServiceWorkerClient* aClient)
 {
   mClient = aClient;
 }
 
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -20,17 +20,16 @@
 #include "nsContentUtils.h"
 
 class nsIInterceptedChannel;
 
 namespace mozilla {
 namespace dom {
 class Blob;
 class MessagePort;
-class MessagePortList;
 class Request;
 class ResponseOrPromise;
 
 struct PushEventInit;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
@@ -255,17 +254,18 @@ public:
 class ExtendableMessageEvent final : public ExtendableEvent
 {
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   RefPtr<ServiceWorkerClient> mClient;
   RefPtr<ServiceWorker> mServiceWorker;
   RefPtr<MessagePort> mMessagePort;
-  RefPtr<MessagePortList> mPorts;
+  nsTArray<RefPtr<MessagePort>> mPorts;
+  bool mPortsSet;
 
 protected:
   explicit ExtendableMessageEvent(EventTarget* aOwner);
   ~ExtendableMessageEvent();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ExtendableMessageEvent,
@@ -303,19 +303,19 @@ public:
   }
 
   NS_IMETHOD GetLastEventId(nsAString& aLastEventId)
   {
     aLastEventId = mLastEventId;
     return NS_OK;
   }
 
-  MessagePortList* GetPorts() const;
+  void GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts);
 
-  void SetPorts(MessagePortList* aPorts);
+  void SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts);
 
   void SetSource(ServiceWorkerClient* aClient);
 
   void SetSource(ServiceWorker* aServiceWorker);
 };
 
 END_WORKERS_NAMESPACE
 
--- a/dom/workers/ServiceWorkerMessageEvent.cpp
+++ b/dom/workers/ServiceWorkerMessageEvent.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ServiceWorkerMessageEvent.h"
 #include "mozilla/dom/ServiceWorkerMessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
-#include "mozilla/dom/MessagePortList.h"
 
 #include "mozilla/HoldDropJSObjects.h"
 #include "jsapi.h"
 
 #include "ServiceWorker.h"
 
 namespace mozilla {
 namespace dom {
@@ -42,16 +41,17 @@ NS_INTERFACE_MAP_END_INHERITING(Event)
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerMessageEvent, Event)
 NS_IMPL_RELEASE_INHERITED(ServiceWorkerMessageEvent, Event)
 
 ServiceWorkerMessageEvent::ServiceWorkerMessageEvent(EventTarget* aOwner,
                                                      nsPresContext* aPresContext,
                                                      WidgetEvent* aEvent)
   : Event(aOwner, aPresContext, aEvent)
   , mData(JS::UndefinedValue())
+  , mPortsSet(false)
 {
   mozilla::HoldJSObjects(this);
 }
 
 ServiceWorkerMessageEvent::~ServiceWorkerMessageEvent()
 {
   mData.setUndefined();
   DropJSObjects(this);
@@ -106,26 +106,32 @@ ServiceWorkerMessageEvent::SetSource(moz
 
 void
 ServiceWorkerMessageEvent::SetSource(workers::ServiceWorker* aServiceWorker)
 {
   mServiceWorker = aServiceWorker;
 }
 
 void
-ServiceWorkerMessageEvent::SetPorts(MessagePortList* aPorts)
+ServiceWorkerMessageEvent::GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts)
 {
-  MOZ_ASSERT(!mPorts && aPorts);
-  mPorts = aPorts;
+  if (!mPortsSet) {
+    aPorts.SetNull();
+    return;
+  }
+
+  aPorts.SetValue(mPorts);
 }
 
-MessagePortList*
-ServiceWorkerMessageEvent::GetPorts() const
+void
+ServiceWorkerMessageEvent::SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts)
 {
-  return mPorts;
+  MOZ_ASSERT(mPorts.IsEmpty() && !mPortsSet);
+  mPorts = Move(aPorts);
+  mPortsSet = true;
 }
 
 /* static */ already_AddRefed<ServiceWorkerMessageEvent>
 ServiceWorkerMessageEvent::Constructor(const GlobalObject& aGlobal,
                                        const nsAString& aType,
                                        const ServiceWorkerMessageEventInit& aParam,
                                        ErrorResult& aRv)
 {
@@ -164,21 +170,17 @@ ServiceWorkerMessageEvent::Constructor(E
     } else {
       event->mMessagePort = aParam.mSource.Value().Value().GetAsMessagePort();
     }
 
     MOZ_ASSERT(event->mServiceWorker || event->mMessagePort);
   }
 
   if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
-    nsTArray<RefPtr<MessagePort>> ports;
-    for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
-      ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
-    }
-
-    event->mPorts = new MessagePortList(static_cast<EventBase*>(event), ports);
+    event->mPorts.AppendElements(aParam.mPorts.Value().Value());
+    event->mPortsSet = true;
   }
 
   return event.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerMessageEvent.h
+++ b/dom/workers/ServiceWorkerMessageEvent.h
@@ -9,17 +9,16 @@
 
 #include "mozilla/dom/Event.h"
 
 namespace mozilla {
 namespace dom {
 
 struct ServiceWorkerMessageEventInit;
 class MessagePort;
-class MessagePortList;
 class OwningServiceWorkerOrMessagePort;
 
 namespace workers {
 
 class ServiceWorker;
 
 }
 
@@ -42,23 +41,23 @@ public:
                ErrorResult& aRv) const;
 
   void GetOrigin(nsAString& aOrigin) const;
 
   void GetLastEventId(nsAString& aLastEventId) const;
 
   void GetSource(Nullable<OwningServiceWorkerOrMessagePort>& aValue) const;
 
-  MessagePortList* GetPorts() const;
+  void GetPorts(Nullable<nsTArray<RefPtr<MessagePort>>>& aPorts);
 
   void SetSource(mozilla::dom::MessagePort* aPort);
 
   void SetSource(workers::ServiceWorker* aServiceWorker);
 
-  void SetPorts(MessagePortList* aPorts);
+  void SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts);
 
   static already_AddRefed<ServiceWorkerMessageEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const ServiceWorkerMessageEventInit& aEventInit,
               ErrorResult& aRv);
 
   static already_AddRefed<ServiceWorkerMessageEvent>
@@ -71,16 +70,18 @@ protected:
   ~ServiceWorkerMessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   RefPtr<workers::ServiceWorker> mServiceWorker;
   RefPtr<MessagePort> mMessagePort;
-  RefPtr<MessagePortList> mPorts;
+
+  nsTArray<RefPtr<MessagePort>> mPorts;
+  bool mPortsSet;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_workers_serviceworkermessageevent_h__ */
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -52,17 +52,16 @@
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/ExtendableMessageEventBinding.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
-#include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
@@ -705,32 +704,31 @@ public:
       ErrorResult rv;
       extendableEvent = ExtendableMessageEvent::Constructor(
         aTarget, NS_LITERAL_STRING("message"), init, rv);
       if (NS_WARN_IF(rv.Failed())) {
         rv.SuppressException();
         return false;
       }
       extendableEvent->SetSource(client);
-      extendableEvent->SetPorts(new MessagePortList(static_cast<dom::Event*>(extendableEvent.get()),
-                                                    ports));
+      extendableEvent->SetPorts(Move(ports));
+
       domEvent = do_QueryObject(extendableEvent);
     } else {
       RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
       event->InitMessageEvent(nullptr,
                               NS_LITERAL_STRING("message"),
                               false /* non-bubbling */,
                               false /* cancelable */,
                               messageData,
                               EmptyString(),
                               EmptyString(),
                               nullptr,
                               nullptr);
-      event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
-                                          ports));
+      event->SetPorts(Move(ports));
       domEvent = do_QueryObject(event);
     }
 
     domEvent->SetTrusted(true);
 
     nsEventStatus dummy = nsEventStatus_eIgnore;
     aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
 
@@ -6481,19 +6479,17 @@ WorkerPrivate::ConnectMessagePort(JSCont
     MessageEvent::Constructor(globalObject,
                               NS_LITERAL_STRING("connect"), init, rv);
 
   event->SetTrusted(true);
 
   nsTArray<RefPtr<MessagePort>> ports;
   ports.AppendElement(port);
 
-  RefPtr<MessagePortList> portList =
-    new MessagePortList(static_cast<nsIDOMEventTarget*>(globalScope), ports);
-  event->SetPorts(portList);
+  event->SetPorts(Move(ports));
 
   nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
 
   nsEventStatus dummy = nsEventStatus_eIgnore;
   globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
 
   return true;
 }