Bug 1204775 - SharedWorker.port should be a 'real' MessagePort, r=khuey
☠☠ backed out by 2ad7f8d8c042 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 16 Sep 2015 00:47:19 +0800
changeset 295222 ccfddcbccdac3dabe0ffadd556b9e0e641cd4fb8
parent 295221 1023659e341377d894b12f030226afcdab35dbb5
child 295223 0ec5494e9d4cafd559f36b1765d74164b7af44b9
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1204775
milestone43.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 1204775 - SharedWorker.port should be a 'real' MessagePort, r=khuey
dom/base/PostMessageEvent.cpp
dom/base/PostMessageEvent.h
dom/base/StructuredCloneHelper.cpp
dom/base/StructuredCloneHelper.h
dom/bindings/Bindings.conf
dom/events/MessageEvent.cpp
dom/events/MessageEvent.h
dom/messagechannel/MessageChannel.cpp
dom/messagechannel/MessageChannel.h
dom/messagechannel/MessagePort.cpp
dom/messagechannel/MessagePort.h
dom/messagechannel/MessagePortList.h
dom/workers/MessagePort.cpp
dom/workers/MessagePort.h
dom/workers/RuntimeService.cpp
dom/workers/ServiceWorkerClient.cpp
dom/workers/ServiceWorkerRegistrar.cpp
dom/workers/SharedWorker.cpp
dom/workers/SharedWorker.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/moz.build
dom/workers/test/mochitest.ini
dom/workers/test/sharedWorker_ports.js
dom/workers/test/test_sharedWorker_ports.html
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -109,18 +109,17 @@ PostMessageEvent::Run()
     do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
   nsRefPtr<MessageEvent> event =
     new MessageEvent(eventTarget, nullptr, nullptr);
 
   event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
                           false /*cancelable */, messageData, mCallerOrigin,
                           EmptyString(), mSource);
 
-  nsTArray<nsRefPtr<MessagePortBase>> ports;
-  TakeTransferredPorts(ports);
+  nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
 
   event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
                                       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.
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -15,19 +15,16 @@
 
 class nsGlobalWindow;
 class nsIPrincipal;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
-class MessagePortBase;
-class MessagePortIdentifier;
-
 /**
  * Class used to represent events generated by calls to Window.postMessage,
  * which asynchronously creates and dispatches events.
  */
 class PostMessageEvent final : public nsRunnable
                              , public StructuredCloneHelper
 {
 public:
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -1067,26 +1067,24 @@ StructuredCloneHelper::WriteTransferCall
                                              void** aContent,
                                              uint64_t* aExtraData)
 {
   if (!mSupportsTransferring) {
     return false;
   }
 
   {
-    MessagePortBase* port = nullptr;
+    MessagePort* port = nullptr;
     nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
     if (NS_SUCCEEDED(rv)) {
       // We use aExtraData to store the index of this new port identifier.
       *aExtraData = mPortIdentifiers.Length();
       MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
 
-      if (!port->CloneAndDisentangle(*identifier)) {
-        return false;
-      }
+      port->CloneAndDisentangle(*identifier);
 
       *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
       *aOwnership = JS::SCTAG_TMO_CUSTOM;
       *aContent = nullptr;
 
       return true;
     }
   }
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef mozilla_dom_StructuredCloneHelper_h
 #define mozilla_dom_StructuredCloneHelper_h
 
 #include "js/StructuredClone.h"
+#include "mozilla/Move.h"
 #include "nsAutoPtr.h"
 #include "nsISupports.h"
 #include "nsTArray.h"
 
 #ifdef DEBUG
 #include "nsIThread.h"
 #endif
 
@@ -106,17 +107,17 @@ protected:
   nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
 
 #ifdef DEBUG
   bool mShutdownCalled;
 #endif
 };
 
 class BlobImpl;
-class MessagePortBase;
+class MessagePort;
 class MessagePortIdentifier;
 
 class StructuredCloneHelper : public StructuredCloneHelperInternal
 {
 public:
   enum CloningSupport
   {
     CloningSupported,
@@ -186,21 +187,20 @@ public:
   nsISupports* ParentDuringRead() const
   {
     return mParent;
   }
 
   // This must be called if the transferring has ports generated by Read().
   // MessagePorts are not thread-safe and they must be retrieved in the thread
   // where they are created.
-  void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
+  nsTArray<nsRefPtr<MessagePort>>&& TakeTransferredPorts()
   {
     MOZ_ASSERT(mSupportsTransferring);
-    MOZ_ASSERT(aPorts.IsEmpty());
-    aPorts.SwapElements(mTransferredPorts);
+    return Move(mTransferredPorts);
   }
 
   nsTArray<MessagePortIdentifier>& PortIdentifiers()
   {
     MOZ_ASSERT(mSupportsTransferring);
     return mPortIdentifiers;
   }
 
@@ -286,17 +286,17 @@ protected:
   nsTArray<nsRefPtr<layers::Image>> mClonedImages;
 
   // This raw pointer is set and unset into the ::Read(). It's always null
   // outside that method. For this reason it's a raw pointer.
   nsISupports* MOZ_NON_OWNING_REF mParent;
 
   // This array contains the ports once we've finished the reading. It's
   // generated from the mPortIdentifiers array.
-  nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
+  nsTArray<nsRefPtr<MessagePort>> mTransferredPorts;
 
   // This array contains the identifiers of the MessagePorts. Based on these we
   // are able to reconnect the new transferred ports with the other
   // MessageChannel ports.
   nsTArray<MessagePortIdentifier> mPortIdentifiers;
 
 #ifdef DEBUG
   nsCOMPtr<nsIThread> mCreationThread;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -734,21 +734,16 @@ DOMInterfaces = {
 'MediaStreamTrack': {
     'concrete': False
 },
 
 'MediaRecorder': {
     'headerFile': 'MediaRecorder.h',
 },
 
-'MessagePort': {
-    'nativeType': 'mozilla::dom::MessagePortBase',
-    'headerFile': 'mozilla/dom/MessagePort.h',
-},
-
 'MimeType': {
     'headerFile' : 'nsMimeTypeArray.h',
     'nativeType': 'nsMimeType',
 },
 
 'MimeTypeArray': {
     'nativeType': 'nsMimeTypeArray',
 },
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -162,17 +162,17 @@ 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<nsRefPtr<MessagePortBase>> ports;
+    nsTArray<nsRefPtr<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);
   }
 
   return event.forget();
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -12,17 +12,16 @@
 #include "nsIDOMMessageEvent.h"
 #include "mozilla/dom/MessagePortList.h"
 
 namespace mozilla {
 namespace dom {
 
 struct MessageEventInit;
 class MessagePort;
-class MessagePortBase;
 class MessagePortList;
 class OwningWindowProxyOrMessagePortOrClient;
 
 namespace workers {
 
 class ServiceWorkerClient;
 
 } // namespace workers
@@ -89,17 +88,17 @@ public:
 protected:
   ~MessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   nsCOMPtr<nsIDOMWindow> mWindowSource;
-  nsRefPtr<MessagePortBase> mPortSource;
+  nsRefPtr<MessagePort> mPortSource;
   nsRefPtr<workers::ServiceWorkerClient> mClientSource;
   nsRefPtr<MessagePortList> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 already_AddRefed<mozilla::dom::MessageEvent>
--- a/dom/messagechannel/MessageChannel.cpp
+++ b/dom/messagechannel/MessageChannel.cpp
@@ -44,37 +44,42 @@ MessageChannel::WrapObject(JSContext* aC
   return MessageChannelBinding::Wrap(aCx, this, aGivenProto);
 }
 
 /* static */ already_AddRefed<MessageChannel>
 MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   // window can be null in workers.
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  return Constructor(window, aRv);
+}
 
+/* static */ already_AddRefed<MessageChannel>
+MessageChannel::Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv)
+{
   nsID portUUID1;
   aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsID portUUID2;
   aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  nsRefPtr<MessageChannel> channel = new MessageChannel(window);
+  nsRefPtr<MessageChannel> channel = new MessageChannel(aWindow);
 
-  channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
+  channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv);
+  channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   channel->mPort1->UnshippedEntangle(channel->mPort2);
   channel->mPort2->UnshippedEntangle(channel->mPort1);
 
   return channel.forget();
--- a/dom/messagechannel/MessageChannel.h
+++ b/dom/messagechannel/MessageChannel.h
@@ -35,16 +35,19 @@ public:
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<MessageChannel>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
+  static already_AddRefed<MessageChannel>
+  Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv);
+
   MessagePort*
   Port1() const
   {
     return mPort1;
   }
 
   MessagePort*
   Port2() const
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -135,18 +135,17 @@ public:
 
     event->InitMessageEvent(NS_LITERAL_STRING("message"),
                             false /* non-bubbling */,
                             false /* cancelable */, value, EmptyString(),
                             EmptyString(), nullptr);
     event->SetTrusted(true);
     event->SetSource(mPort);
 
-    nsTArray<nsRefPtr<MessagePortBase>> ports;
-    mData->TakeTransferredPorts(ports);
+    nsTArray<nsRefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
 
     nsRefPtr<MessagePortList> portList =
       new MessagePortList(static_cast<dom::Event*>(event.get()),
                           ports);
     event->SetPorts(portList);
 
     bool dummy;
     mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &dummy);
@@ -166,54 +165,45 @@ private:
   {}
 
   nsRefPtr<MessagePort> mPort;
   nsRefPtr<SharedMessagePortMessage> mData;
 };
 
 NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable)
 
-MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
-  : DOMEventTargetHelper(aWindow)
-{
-}
-
-MessagePortBase::MessagePortBase()
-{
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
-                                                MessagePortBase)
+                                                DOMEventTargetHelper)
   if (tmp->mDispatchRunnable) {
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessages);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnshippedEntangledPort);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
-                                                  MessagePortBase)
+                                                  DOMEventTargetHelper)
   if (tmp->mDispatchRunnable) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
   NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
-NS_INTERFACE_MAP_END_INHERITING(MessagePortBase)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
-NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
-NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
+NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
 
 namespace {
 
 class MessagePortFeature final : public workers::WorkerFeature
 {
   MessagePort* mPort;
 
 public:
@@ -282,17 +272,17 @@ private:
   const MessagePortIdentifier mIdentifier;
 };
 
 NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
 
 } // namespace
 
 MessagePort::MessagePort(nsPIDOMWindow* aWindow)
-  : MessagePortBase(aWindow)
+  : DOMEventTargetHelper(aWindow)
   , mInnerID(0)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
 {
   mIdentifier = new MessagePortIdentifier();
   mIdentifier->neutered() = true;
   mIdentifier->sequenceId() = 0;
 }
@@ -359,38 +349,38 @@ MessagePort::Initialize(const nsID& aUUI
     ConnectToPBackground();
   } else {
     MOZ_ASSERT(mState == eStateUnshippedEntangled);
   }
 
   // The port has to keep itself alive until it's entangled.
   UpdateMustKeepAlive();
 
-  if (NS_IsMainThread()) {
-    MOZ_ASSERT(GetOwner());
-    MOZ_ASSERT(GetOwner()->IsInnerWindow());
-    mInnerID = GetOwner()->WindowID();
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-      obs->AddObserver(this, "inner-window-destroyed", false);
-    }
-  } else {
+  if (!NS_IsMainThread()) {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
     MOZ_ASSERT(!mWorkerFeature);
 
     nsAutoPtr<WorkerFeature> feature(new MessagePortFeature(this));
     JSContext* cx = workerPrivate->GetJSContext();
     if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
     mWorkerFeature = Move(feature);
+  } else if (GetOwner()) {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(GetOwner()->IsInnerWindow());
+    mInnerID = GetOwner()->WindowID();
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->AddObserver(this, "inner-window-destroyed", false);
+    }
   }
 }
 
 JSObject*
 MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MessagePortBinding::Wrap(aCx, this, aGivenProto);
 }
@@ -409,17 +399,17 @@ MessagePort::PostMessage(JSContext* aCx,
 
     // Here we want to check if the transerable object list contains
     // this port. No other checks are done.
     for (const JS::Value& value : realTransferable) {
       if (!value.isObject()) {
         continue;
       }
 
-      MessagePortBase* port = nullptr;
+      MessagePort* port = nullptr;
       nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
       if (NS_FAILED(rv)) {
         continue;
       }
 
       if (port == this) {
         aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
         return;
@@ -515,37 +505,32 @@ MessagePort::Dispatch()
   mDispatchRunnable = new DispatchEventRunnable(this);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(mDispatchRunnable)));
 }
 
 void
 MessagePort::Close()
 {
-  // Not entangled yet, but already closed.
-  if (mNextStep != eNextStepNone) {
-    return;
-  }
-
   if (mState == eStateUnshippedEntangled) {
     MOZ_ASSERT(mUnshippedEntangledPort);
 
     // This avoids loops.
     nsRefPtr<MessagePort> port = Move(mUnshippedEntangledPort);
     MOZ_ASSERT(mUnshippedEntangledPort == nullptr);
 
     mState = eStateDisentangled;
     port->Close();
 
     UpdateMustKeepAlive();
     return;
   }
 
   // Not entangled yet, we have to wait.
-  if (mState < eStateEntangling) {
+  if (mState == eStateEntangling) {
     mNextStep = eNextStepClose;
     return;
   }
 
   if (mState > eStateEntangled) {
     return;
   }
 
@@ -694,34 +679,34 @@ MessagePort::Disentangle()
   mActor->SendDisentangle(messages);
 
   mActor->SetPort(nullptr);
   mActor = nullptr;
 
   UpdateMustKeepAlive();
 }
 
-bool
+void
 MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
 {
   MOZ_ASSERT(mIdentifier);
 
   // We can clone a port that has already been transfered. In this case, on the
   // otherside will have a neutered port. Here we set neutered to true so that
   // we are safe in case a early return.
   aIdentifier.neutered() = true;
 
   if (mState > eStateEntangled) {
-    return true;
+    return;
   }
 
   // We already have a 'next step'. We have to consider this port as already
   // cloned/closed/disentangled.
   if (mNextStep != eNextStepNone) {
-    return true;
+    return;
   }
 
   aIdentifier.uuid() = mIdentifier->uuid();
   aIdentifier.destinationUuid() = mIdentifier->destinationUuid();
   aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1;
   aIdentifier.neutered() = false;
 
   // We have to entangle first.
@@ -734,34 +719,33 @@ MessagePort::CloneAndDisentangle(Message
     mUnshippedEntangledPort = nullptr;
 
     // In this case, we don't need to be connected to the PBackground service.
     if (mMessages.IsEmpty()) {
       aIdentifier.sequenceId() = mIdentifier->sequenceId();
 
       mState = eStateDisentangled;
       UpdateMustKeepAlive();
-      return true;
+      return;
     }
 
     // Register this component to PBackground.
     ConnectToPBackground();
 
     mNextStep = eNextStepDisentangle;
-    return true;
+    return;
   }
 
   // Not entangled yet, we have to wait.
   if (mState < eStateEntangled) {
     mNextStep = eNextStepDisentangle;
-    return true;
+    return;
   }
 
   StartDisentangling();
-  return true;
 }
 
 void
 MessagePort::Closed()
 {
   if (mState == eStateDisentangled) {
     return;
   }
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -26,95 +26,61 @@ class MessagePortChild;
 class MessagePortIdentifier;
 class MessagePortMessage;
 class SharedMessagePortMessage;
 
 namespace workers {
 class WorkerFeature;
 } // namespace workers
 
-class MessagePortBase : public DOMEventTargetHelper
-{
-protected:
-  explicit MessagePortBase(nsPIDOMWindow* aWindow);
-  MessagePortBase();
-
-public:
-
-  virtual void
-  PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-              const Optional<Sequence<JS::Value>>& aTransferable,
-              ErrorResult& aRv) = 0;
-
-  virtual void
-  Start() = 0;
-
-  virtual void
-  Close() = 0;
-
-  // The 'message' event handler has to call |Start()| method, so we
-  // cannot use IMPL_EVENT_HANDLER macro here.
-  virtual EventHandlerNonNull*
-  GetOnmessage() = 0;
-
-  virtual void
-  SetOnmessage(EventHandlerNonNull* aCallback) = 0;
-
-  // Duplicate this message port. This method is used by the Structured Clone
-  // Algorithm and populates a MessagePortIdentifier object with the information
-  // useful to create new MessagePort.
-  virtual bool
-  CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0;
-};
-
-class MessagePort final : public MessagePortBase
+class MessagePort final : public DOMEventTargetHelper
                         , public nsIIPCBackgroundChildCreateCallback
                         , public nsIObserver
 {
   friend class DispatchEventRunnable;
 
 public:
   NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
   NS_DECL_NSIOBSERVER
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
-                                           MessagePortBase)
+                                           DOMEventTargetHelper)
 
   static already_AddRefed<MessagePort>
   Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
          const nsID& aDestinationUUID, ErrorResult& aRv);
 
   static already_AddRefed<MessagePort>
   Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier,
          ErrorResult& aRv);
 
   static void
   ForceClose(const MessagePortIdentifier& aIdentifier);
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  virtual void
+  void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
-              ErrorResult& aRv) override;
+              ErrorResult& aRv);
 
-  virtual void Start() override;
+  void Start();
 
-  virtual void Close() override;
+  void Close();
 
-  virtual EventHandlerNonNull* GetOnmessage() override;
+  EventHandlerNonNull* GetOnmessage();
 
-  virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
+  void SetOnmessage(EventHandlerNonNull* aCallback);
 
   // Non WebIDL methods
 
   void UnshippedEntangle(MessagePort* aEntangledPort);
 
-  virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
+  void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
 
   // These methods are useful for MessagePortChild
 
   void Entangled(nsTArray<MessagePortMessage>& aMessages);
   void MessagesReceived(nsTArray<MessagePortMessage>& aMessages);
   void StopSendingDataConfirmed();
   void Closed();
 
--- a/dom/messagechannel/MessagePortList.h
+++ b/dom/messagechannel/MessagePortList.h
@@ -24,17 +24,17 @@ class MessagePortList final : public nsI
   ~MessagePortList() {}
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessagePortList)
 
 public:
   MessagePortList(nsISupports* aOwner,
-                  const nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
+                  const nsTArray<nsRefPtr<MessagePort>>& aPorts)
     : mOwner(aOwner)
     , mPorts(aPorts)
   {
   }
 
   nsISupports*
   GetParentObject() const
   {
@@ -45,34 +45,34 @@ public:
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   uint32_t
   Length() const
   {
     return mPorts.Length();
   }
 
-  MessagePortBase*
+  MessagePort*
   Item(uint32_t aIndex)
   {
     return mPorts.SafeElementAt(aIndex);
   }
 
-  MessagePortBase*
+  MessagePort*
   IndexedGetter(uint32_t aIndex, bool &aFound)
   {
     aFound = aIndex < mPorts.Length();
     if (!aFound) {
       return nullptr;
     }
     return mPorts[aIndex];
   }
 
 public:
   nsCOMPtr<nsISupports> mOwner;
-  nsTArray<nsRefPtr<MessagePortBase>> mPorts;
+  nsTArray<nsRefPtr<MessagePort>> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MessagePortList_h
 
deleted file mode 100644
--- a/dom/workers/MessagePort.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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 "MessagePort.h"
-
-#include "mozilla/EventDispatcher.h"
-#include "mozilla/dom/MessagePortBinding.h"
-#include "mozilla/dom/ScriptSettings.h"
-#include "nsIDOMEvent.h"
-
-#include "SharedWorker.h"
-#include "WorkerPrivate.h"
-#include "WorkerRunnable.h"
-
-using mozilla::dom::EventHandlerNonNull;
-using mozilla::dom::MessagePortBase;
-using mozilla::dom::MessagePortIdentifier;
-using mozilla::dom::Optional;
-using mozilla::dom::Sequence;
-using mozilla::dom::AutoNoJSAPI;
-using namespace mozilla;
-
-USING_WORKERS_NAMESPACE
-
-namespace {
-
-class DelayedEventRunnable final : public WorkerRunnable
-{
-  nsRefPtr<mozilla::dom::workers::MessagePort> mMessagePort;
-  nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
-
-public:
-  DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
-                       TargetAndBusyBehavior aBehavior,
-                       mozilla::dom::workers::MessagePort* aMessagePort,
-                       nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
-  : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aMessagePort);
-    MOZ_ASSERT(aEvents.Length());
-
-    mEvents.SwapElements(aEvents);
-  }
-
-  bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    if (mBehavior == WorkerThreadModifyBusyCount) {
-      return aWorkerPrivate->ModifyBusyCount(aCx, true);
-    }
-
-    return true;
-  }
-
-  void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-                    bool aDispatchResult)
-  {
-    if (!aDispatchResult) {
-      if (mBehavior == WorkerThreadModifyBusyCount) {
-        aWorkerPrivate->ModifyBusyCount(aCx, false);
-      }
-      if (aCx) {
-        JS_ReportPendingException(aCx);
-      }
-    }
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
-};
-
-} // namespace
-
-BEGIN_WORKERS_NAMESPACE
-
-MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
-                         uint64_t aSerial)
-: MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
-  mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aSharedWorker);
-}
-
-MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
-: mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
-{
-  aWorkerPrivate->AssertIsOnWorkerThread();
-}
-
-MessagePort::~MessagePort()
-{
-  Close();
-}
-
-void
-MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                         const Optional<Sequence<JS::Value>>& aTransferable,
-                         ErrorResult& aRv)
-{
-  AssertCorrectThread();
-
-  if (IsClosed()) {
-    aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
-    return;
-  }
-
-  if (mSharedWorker) {
-    mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
-  }
-  else {
-    mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
-                                                   aTransferable, aRv);
-  }
-}
-
-void
-MessagePort::Start()
-{
-  AssertCorrectThread();
-
-  if (IsClosed()) {
-    NS_WARNING("Called start() after calling close()!");
-    return;
-  }
-
-  if (mStarted) {
-    return;
-  }
-
-  mStarted = true;
-
-  if (!mQueuedEvents.IsEmpty()) {
-    WorkerPrivate* workerPrivate;
-    WorkerRunnable::TargetAndBusyBehavior behavior;
-
-    if (mWorkerPrivate) {
-      workerPrivate = mWorkerPrivate;
-      behavior = WorkerRunnable::WorkerThreadModifyBusyCount;
-    }
-    else {
-      workerPrivate = mSharedWorker->GetWorkerPrivate();
-      MOZ_ASSERT(workerPrivate);
-
-      behavior = WorkerRunnable::ParentThreadUnchangedBusyCount;
-    }
-
-    nsRefPtr<DelayedEventRunnable> runnable =
-      new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents);
-    runnable->Dispatch(nullptr);
-  }
-}
-
-void
-MessagePort::Close()
-{
-  AssertCorrectThread();
-
-  if (!IsClosed()) {
-    CloseInternal();
-  }
-}
-
-void
-MessagePort::QueueEvent(nsIDOMEvent* aEvent)
-{
-  AssertCorrectThread();
-  MOZ_ASSERT(aEvent);
-  MOZ_ASSERT(!IsClosed());
-  MOZ_ASSERT(!mStarted);
-
-  mQueuedEvents.AppendElement(aEvent);
-}
-
-EventHandlerNonNull*
-MessagePort::GetOnmessage()
-{
-  AssertCorrectThread();
-
-  return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
-                           : GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
-}
-
-void
-MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
-{
-  AssertCorrectThread();
-
-  if (NS_IsMainThread()) {
-    SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
-  }
-  else {
-    SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
-  }
-
-  Start();
-}
-
-bool
-MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
-{
-  NS_WARNING("Haven't implemented structured clone for these ports yet!");
-  return false;
-}
-
-void
-MessagePort::CloseInternal()
-{
-  AssertCorrectThread();
-  MOZ_ASSERT(!IsClosed());
-  MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
-
-  if (!mStarted) {
-    mQueuedEvents.Clear();
-  }
-
-  mSharedWorker = nullptr;
-  mWorkerPrivate = nullptr;
-}
-
-#ifdef DEBUG
-void
-MessagePort::AssertCorrectThread() const
-{
-  if (IsClosed()) {
-    return; // Can't assert anything if we nulled out our pointers.
-  }
-
-  MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
-             !(mSharedWorker && mWorkerPrivate));
-
-  if (mSharedWorker) {
-    AssertIsOnMainThread();
-  }
-  else {
-    mWorkerPrivate->AssertIsOnWorkerThread();
-  }
-}
-#endif
-
-NS_IMPL_ADDREF_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
-                                                  DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
-                                                DOMEventTargetHelper)
-  tmp->Close();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-JSObject*
-MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  AssertCorrectThread();
-
-  return MessagePortBinding::Wrap(aCx, this, aGivenProto);
-}
-
-nsresult
-MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor)
-{
-  AssertCorrectThread();
-
-  nsIDOMEvent*& event = aVisitor.mDOMEvent;
-
-  if (event) {
-    bool preventDispatch = false;
-
-    if (IsClosed()) {
-      preventDispatch = true;
-    } else if (NS_IsMainThread() && mSharedWorker->IsFrozen()) {
-      mSharedWorker->QueueEvent(event);
-      preventDispatch = true;
-    } else if (!mStarted) {
-      QueueEvent(event);
-      preventDispatch = true;
-    }
-
-    if (preventDispatch) {
-      aVisitor.mCanHandle = false;
-      aVisitor.mParentTarget = nullptr;
-      return NS_OK;
-    }
-  }
-
-  return DOMEventTargetHelper::PreHandleEvent(aVisitor);
-}
-
-END_WORKERS_NAMESPACE
-
-bool
-DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-{
-  MOZ_ASSERT(mMessagePort);
-  mMessagePort->AssertCorrectThread();
-  MOZ_ASSERT(mEvents.Length());
-
-  AutoNoJSAPI nojsapi;
-
-  bool ignored;
-  for (uint32_t i = 0; i < mEvents.Length(); i++) {
-    mMessagePort->DispatchEvent(mEvents[i], &ignored);
-  }
-
-  return true;
-}
deleted file mode 100644
--- a/dom/workers/MessagePort.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#ifndef mozilla_dom_workers_messageport_h_
-#define mozilla_dom_workers_messageport_h_
-
-#include "mozilla/dom/workers/Workers.h"
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/MessagePort.h"
-
-class nsIDOMEvent;
-class nsPIDOMWindow;
-
-namespace mozilla {
-class EventChainPreVisitor;
-} // namespace mozilla
-
-BEGIN_WORKERS_NAMESPACE
-
-class SharedWorker;
-class WorkerPrivate;
-
-class MessagePort final : public mozilla::dom::MessagePortBase
-{
-  friend class SharedWorker;
-  friend class WorkerPrivate;
-
-  typedef mozilla::ErrorResult ErrorResult;
-
-  nsRefPtr<SharedWorker> mSharedWorker;
-  WorkerPrivate* mWorkerPrivate;
-  nsTArray<nsCOMPtr<nsIDOMEvent>> mQueuedEvents;
-  uint64_t mSerial;
-  bool mStarted;
-
-public:
-  static bool
-  PrefEnabled();
-
-  virtual void
-  PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-              const Optional<Sequence<JS::Value>>& aTransferable,
-              ErrorResult& aRv) override;
-
-  virtual void
-  Start() override;
-
-  virtual void
-  Close() override;
-
-  uint64_t
-  Serial() const
-  {
-    return mSerial;
-  }
-
-  void
-  QueueEvent(nsIDOMEvent* aEvent);
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)
-
-  virtual EventHandlerNonNull*
-  GetOnmessage() override;
-
-  virtual void
-  SetOnmessage(EventHandlerNonNull* aCallback) override;
-
-  virtual bool
-  CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
-
-  bool
-  IsClosed() const
-  {
-    return !mSharedWorker && !mWorkerPrivate;
-  }
-
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  virtual nsresult
-  PreHandleEvent(EventChainPreVisitor& aVisitor) override;
-
-#ifdef DEBUG
-  void
-  AssertCorrectThread() const;
-#else
-  void
-  AssertCorrectThread() const { }
-#endif
-
-private:
-  // This class can only be created by SharedWorker or WorkerPrivate.
-  MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
-              uint64_t aSerial);
-  MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial);
-
-  // This class is reference-counted and will be destroyed from Release().
-  ~MessagePort();
-
-  void
-  CloseInternal();
-};
-
-END_WORKERS_NAMESPACE
-
-#endif // mozilla_dom_workers_messageport_h_
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
+#include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
@@ -2488,34 +2489,43 @@ RuntimeService::CreateSharedWorkerFromLo
 
   // Keep a reference to the window before spawning the worker. If the worker is
   // a Shared/Service worker and the worker script loads and executes before
   // the SharedWorker object itself is created before then WorkerScriptLoaded()
   // will reset the loadInfo's window.
   nsCOMPtr<nsPIDOMWindow> window = aLoadInfo->mWindow;
 
   bool created = false;
+  ErrorResult rv;
   if (!workerPrivate) {
-    ErrorResult rv;
     workerPrivate =
       WorkerPrivate::Constructor(aCx, aScriptURL, false,
                                  aType, aName, aLoadInfo, rv);
     NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
 
     created = true;
   } else {
     // If we're attaching to an existing SharedWorker private, then we
     // must update the overriden load group to account for our document's
     // load group.
     workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
   }
 
-  nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
-
-  if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
+  // We don't actually care about this MessageChannel, but we use it to 'steal'
+  // its 2 connected ports.
+  nsRefPtr<MessageChannel> channel = MessageChannel::Constructor(window, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
+                                                         channel->Port1());
+
+  if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker,
+                                           channel->Port2())) {
     NS_WARNING("Worker is unreachable, this shouldn't happen!");
     sharedWorker->Close();
     return NS_ERROR_FAILURE;
   }
 
   // This is normally handled in RegisterWorker, but that wasn't called if the
   // worker already existed.
   if (!created) {
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -133,18 +133,17 @@ private:
                                  EmptyString(),
                                  EmptyString(),
                                  nullptr);
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return NS_ERROR_FAILURE;
     }
 
-    nsTArray<nsRefPtr<MessagePortBase>> ports;
-    TakeTransferredPorts(ports);
+    nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
 
     nsRefPtr<MessagePortList> portList =
       new MessagePortList(static_cast<dom::Event*>(event.get()),
                           ports);
     event->SetPorts(portList);
 
     event->SetTrusted(true);
     bool status = false;
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -6,16 +6,17 @@
 
 #include "ServiceWorkerRegistrar.h"
 #include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
 
 #include "nsIEventTarget.h"
 #include "nsIInputStream.h"
 #include "nsILineInputStream.h"
 #include "nsIObserverService.h"
+#include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 
 #include "MainThreadUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ModuleUtils.h"
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -5,42 +5,40 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedWorker.h"
 
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/SharedWorkerBinding.h"
 #include "nsContentUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIDOMEvent.h"
 
-#include "MessagePort.h"
 #include "RuntimeService.h"
 #include "WorkerPrivate.h"
 
 using mozilla::dom::Optional;
 using mozilla::dom::Sequence;
 using namespace mozilla;
 
 USING_WORKERS_NAMESPACE
 
 SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
-                           WorkerPrivate* aWorkerPrivate)
-: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
-  mFrozen(false)
+                           WorkerPrivate* aWorkerPrivate,
+                           MessagePort* aMessagePort)
+: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate)
+, mMessagePort(aMessagePort)
+, mFrozen(false)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWorkerPrivate);
-
-  mSerial = aWorkerPrivate->NextMessagePortSerial();
-
-  mMessagePort = new MessagePort(aWindow, this, mSerial);
 }
 
 SharedWorker::~SharedWorker()
 {
   AssertIsOnMainThread();
   Close();
   MOZ_ASSERT(!mWorkerPrivate);
 }
@@ -71,23 +69,21 @@ SharedWorker::Constructor(const GlobalOb
   if (NS_FAILED(rv)) {
     aRv = rv;
     return nullptr;
   }
 
   return sharedWorker.forget();
 }
 
-already_AddRefed<mozilla::dom::workers::MessagePort>
+MessagePort*
 SharedWorker::Port()
 {
   AssertIsOnMainThread();
-
-  nsRefPtr<MessagePort> messagePort = mMessagePort;
-  return messagePort.forget();
+  return mMessagePort;
 }
 
 void
 SharedWorker::Freeze()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!IsFrozen());
 
@@ -152,18 +148,17 @@ void
 SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                           const Optional<Sequence<JS::Value>>& aTransferable,
                           ErrorResult& aRv)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mWorkerPrivate);
   MOZ_ASSERT(mMessagePort);
 
-  mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(),
-                                           aMessage, aTransferable, aRv);
+  mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
 }
 
 void
 SharedWorker::NoteDeadWorker(JSContext* aCx)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mWorkerPrivate);
 
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -5,61 +5,55 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_sharedworker_h__
 #define mozilla_dom_workers_sharedworker_h__
 
 #include "Workers.h"
 
 #include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/workers/bindings/MessagePort.h"
 #include "mozilla/DOMEventTargetHelper.h"
 
 class nsIDOMEvent;
 class nsPIDOMWindow;
 
 namespace mozilla {
 class EventChainPreVisitor;
+
+namespace dom {
+class MessagePort;
+}
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
-class MessagePort;
 class RuntimeService;
 class WorkerPrivate;
 
 class SharedWorker final : public DOMEventTargetHelper
 {
-  friend class MessagePort;
   friend class RuntimeService;
 
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
 
   nsRefPtr<WorkerPrivate> mWorkerPrivate;
   nsRefPtr<MessagePort> mMessagePort;
   nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
-  uint64_t mSerial;
   bool mFrozen;
 
 public:
   static already_AddRefed<SharedWorker>
   Constructor(const GlobalObject& aGlobal, JSContext* aCx,
               const nsAString& aScriptURL, const Optional<nsAString>& aName,
               ErrorResult& aRv);
 
-  already_AddRefed<mozilla::dom::workers::MessagePort>
+  MessagePort*
   Port();
 
-  uint64_t
-  Serial() const
-  {
-    return mSerial;
-  }
-
   bool
   IsFrozen() const
   {
     return mFrozen;
   }
 
   void
   Freeze();
@@ -88,17 +82,18 @@ public:
   GetWorkerPrivate() const
   {
     return mWorkerPrivate;
   }
 
 private:
   // This class can only be created from the RuntimeService.
   SharedWorker(nsPIDOMWindow* aWindow,
-               WorkerPrivate* aWorkerPrivate);
+               WorkerPrivate* aWorkerPrivate,
+               MessagePort* aMessagePort);
 
   // This class is reference-counted and will be destroyed from Release().
   ~SharedWorker();
 
   // Only called by MessagePort.
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -49,16 +49,17 @@
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/FunctionBinding.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/PMessagePort.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneHelper.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
@@ -83,17 +84,16 @@
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #ifdef DEBUG
 #include "nsThreadManager.h"
 #endif
 
-#include "MessagePort.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerWindowClient.h"
 #include "SharedWorker.h"
 #include "WorkerDebuggerManager.h"
@@ -589,31 +589,25 @@ private:
 
     aWorkerPrivate->CloseHandlerFinished();
   }
 };
 
 class MessageEventRunnable final : public WorkerRunnable
                                  , public StructuredCloneHelper
 {
-  uint64_t mMessagePortSerial;
-  bool mToMessagePort;
-
   // This is only used for messages dispatched to a service worker.
   nsAutoPtr<ServiceWorkerClientInfo> mEventSource;
 
 public:
   MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
-                       TargetAndBusyBehavior aBehavior,
-                       bool aToMessagePort, uint64_t aMessagePortSerial)
+                       TargetAndBusyBehavior aBehavior)
   : WorkerRunnable(aWorkerPrivate, aBehavior)
   , StructuredCloneHelper(CloningSupported, TransferringSupported,
                           SameProcessDifferentThread)
-  , mMessagePortSerial(aMessagePortSerial)
-  , mToMessagePort(aToMessagePort)
   {
   }
 
   void
   SetMessageSource(ServiceWorkerClientInfo* aSource)
   {
     mEventSource = aSource;
   }
@@ -649,72 +643,52 @@ public:
       event->SetSource(client);
     }
 
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return false;
     }
 
-    nsTArray<nsRefPtr<MessagePortBase>> ports;
-    TakeTransferredPorts(ports);
+    nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
 
     event->SetTrusted(true);
     event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
                                         ports));
     nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
 
     nsEventStatus dummy = nsEventStatus_eIgnore;
     aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
     return true;
   }
 
 private:
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
-    MOZ_ASSERT_IF(mToMessagePort, aWorkerPrivate->IsSharedWorker());
-
     if (mBehavior == ParentThreadUnchangedBusyCount) {
       // Don't fire this event if the JS object has been disconnected from the
       // private object.
       if (!aWorkerPrivate->IsAcceptingEvents()) {
         return true;
       }
 
-      if (mToMessagePort) {
-        return
-          aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
-                                                            mMessagePortSerial,
-                                                            *this);
-      }
-
       if (aWorkerPrivate->IsFrozen()) {
         aWorkerPrivate->QueueRunnable(this);
         return true;
       }
 
       aWorkerPrivate->AssertInnerWindowIsCorrect();
 
       return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate,
                               !aWorkerPrivate->GetParent());
     }
 
     MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
 
-    if (mToMessagePort) {
-      nsRefPtr<workers::MessagePort> port =
-        aWorkerPrivate->GetMessagePort(mMessagePortSerial);
-      if (!port) {
-        // Must have been closed already.
-        return true;
-      }
-      return DispatchDOMEvent(aCx, aWorkerPrivate, port, false);
-    }
-
     return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
                             false);
   }
 };
 
 class DebuggerMessageEventRunnable : public WorkerDebuggerRunnable {
   nsString mMessage;
 
@@ -1516,42 +1490,38 @@ public:
     extras->location = nullptr;
 
     aCompartmentStats->extra = extras;
   }
 };
 
 class MessagePortRunnable final : public WorkerRunnable
 {
-  uint64_t mMessagePortSerial;
-  bool mConnect;
+  MessagePortIdentifier mPortIdentifier;
 
 public:
   MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
-                      uint64_t aMessagePortSerial,
-                      bool aConnect)
-  : WorkerRunnable(aWorkerPrivate, aConnect ?
-                                   WorkerThreadModifyBusyCount :
-                                   WorkerThreadUnchangedBusyCount),
-    mMessagePortSerial(aMessagePortSerial), mConnect(aConnect)
-  { }
+                      MessagePort* aPort)
+  : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+  {
+    MOZ_ASSERT(aPort);
+    // In order to move the port from one thread to another one, we have to
+    // close and disentangle it. The output will be a MessagePortIdentifier that
+    // will be used to recreate a new MessagePort on the other thread.
+    aPort->CloneAndDisentangle(mPortIdentifier);
+  }
 
 private:
   ~MessagePortRunnable()
   { }
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
-    if (mConnect) {
-      return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial);
-    }
-
-    aWorkerPrivate->DisconnectMessagePort(mMessagePortSerial);
-    return true;
+    return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
   }
 };
 
 class DummyRunnable final
   : public WorkerRunnable
 {
 public:
   explicit
@@ -2117,18 +2087,17 @@ WorkerPrivateParent<Derived>::WorkerPriv
                                            WorkerType aWorkerType,
                                            const nsACString& aSharedWorkerName,
                                            WorkerLoadInfo& aLoadInfo)
 : mMutex("WorkerPrivateParent Mutex"),
   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
   mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
   mParent(aParent), mScriptURL(aScriptURL),
   mSharedWorkerName(aSharedWorkerName), mLoadingWorkerScript(false),
-  mBusyCount(0), mMessagePortSerial(0),
-  mParentStatus(Pending), mParentFrozen(false),
+  mBusyCount(0), mParentStatus(Pending), mParentFrozen(false),
   mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
   mWorkerType(aWorkerType),
   mCreationTimeStamp(TimeStamp::Now()),
   mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
 {
   MOZ_ASSERT_IF(!IsDedicatedWorker(),
                 !aSharedWorkerName.IsVoid() && NS_IsMainThread());
   MOZ_ASSERT_IF(IsDedicatedWorker(), aSharedWorkerName.IsEmpty());
@@ -2482,65 +2451,39 @@ bool
 WorkerPrivateParent<Derived>::Freeze(JSContext* aCx, nsPIDOMWindow* aWindow)
 {
   AssertIsOnParentThread();
   MOZ_ASSERT(aCx);
 
   // Shared workers are only frozen if all of their owning documents are
   // frozen. It can happen that mSharedWorkers is empty but this thread has
   // not been unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
+  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
     AssertIsOnMainThread();
 
-    struct Closure
-    {
-      nsPIDOMWindow* mWindow;
-      bool mAllFrozen;
-
-      explicit Closure(nsPIDOMWindow* aWindow)
-      : mWindow(aWindow), mAllFrozen(true)
-      {
-        AssertIsOnMainThread();
-        // aWindow may be null here.
+    bool allFrozen = false;
+
+    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
+        // Calling Freeze() may change the refcount, ensure that the worker
+        // outlives this call.
+        nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
+
+        mSharedWorkers[i]->Freeze();
+      } else {
+        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
+                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+                                       aWindow));
+        if (!mSharedWorkers[i]->IsFrozen()) {
+          allFrozen = false;
+        }
       }
-
-      static PLDHashOperator
-      Freeze(const uint64_t& aKey,
-              SharedWorker* aSharedWorker,
-              void* aClosure)
-      {
-        AssertIsOnMainThread();
-        MOZ_ASSERT(aSharedWorker);
-        MOZ_ASSERT(aClosure);
-
-        auto closure = static_cast<Closure*>(aClosure);
-
-        if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
-          // Calling Freeze() may change the refcount, ensure that the worker
-          // outlives this call.
-          nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
-
-          aSharedWorker->Freeze();
-        } else {
-          MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
-                        !SameCOMIdentity(aSharedWorker->GetOwner(),
-                                         closure->mWindow));
-          if (!aSharedWorker->IsFrozen()) {
-            closure->mAllFrozen = false;
-          }
-        }
-        return PL_DHASH_NEXT;
-      }
-    };
-
-    Closure closure(aWindow);
-
-    mSharedWorkers.EnumerateRead(Closure::Freeze, &closure);
-
-    if (!closure.mAllFrozen || mParentFrozen) {
+    }
+
+    if (!allFrozen || mParentFrozen) {
       return true;
     }
   }
 
   mParentFrozen = true;
 
   {
     MutexAutoLock lock(mMutex);
@@ -2571,66 +2514,40 @@ WorkerPrivateParent<Derived>::Thaw(JSCon
     // parent was actually suspended (maybe during a sync XHR), and in this case
     // we don't need to thaw.
     return true;
   }
 
   // Shared workers are resumed if any of their owning documents are thawed.
   // It can happen that mSharedWorkers is empty but this thread has not been
   // unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
+  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
     AssertIsOnMainThread();
 
-    struct Closure
-    {
-      nsPIDOMWindow* mWindow;
-      bool mAnyRunning;
-
-      explicit Closure(nsPIDOMWindow* aWindow)
-      : mWindow(aWindow), mAnyRunning(false)
-      {
-        AssertIsOnMainThread();
-        // aWindow may be null here.
+    bool anyRunning = false;
+
+    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
+        // Calling Thaw() may change the refcount, ensure that the worker
+        // outlives this call.
+        nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
+
+        mSharedWorkers[i]->Thaw();
+        anyRunning = true;
+      } else {
+        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
+                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+                                       aWindow));
+        if (!mSharedWorkers[i]->IsFrozen()) {
+          anyRunning = true;
+        }
       }
-
-      static PLDHashOperator
-      Thaw(const uint64_t& aKey,
-              SharedWorker* aSharedWorker,
-              void* aClosure)
-      {
-        AssertIsOnMainThread();
-        MOZ_ASSERT(aSharedWorker);
-        MOZ_ASSERT(aClosure);
-
-        auto closure = static_cast<Closure*>(aClosure);
-
-        if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
-          // Calling Thaw() may change the refcount, ensure that the worker
-          // outlives this call.
-          nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
-
-          aSharedWorker->Thaw();
-          closure->mAnyRunning = true;
-        } else {
-          MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
-                        !SameCOMIdentity(aSharedWorker->GetOwner(),
-                                         closure->mWindow));
-          if (!aSharedWorker->IsFrozen()) {
-            closure->mAnyRunning = true;
-          }
-        }
-        return PL_DHASH_NEXT;
-      }
-    };
-
-    Closure closure(aWindow);
-
-    mSharedWorkers.EnumerateRead(Closure::Thaw, &closure);
-
-    if (!closure.mAnyRunning || !mParentFrozen) {
+    }
+
+    if (!anyRunning || !mParentFrozen) {
       return true;
     }
   }
 
   MOZ_ASSERT(mParentFrozen);
 
   mParentFrozen = false;
 
@@ -2757,18 +2674,16 @@ WorkerPrivateParent<Derived>::ForgetMain
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::PostMessageInternal(
                                             JSContext* aCx,
                                             JS::Handle<JS::Value> aMessage,
                                             const Optional<Sequence<JS::Value>>& aTransferable,
-                                            bool aToMessagePort,
-                                            uint64_t aMessagePortSerial,
                                             ServiceWorkerClientInfo* aClientInfo,
                                             ErrorResult& aRv)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     if (mParentStatus > Running) {
@@ -2792,18 +2707,17 @@ WorkerPrivateParent<Derived>::PostMessag
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
-                             WorkerRunnable::WorkerThreadModifyBusyCount,
-                             aToMessagePort, aMessagePortSerial);
+                             WorkerRunnable::WorkerThreadModifyBusyCount);
 
   runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   runnable->SetMessageSource(aClientInfo);
 
@@ -2816,98 +2730,17 @@ template <class Derived>
 void
 WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
                              JSContext* aCx, JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
                              ErrorResult& aRv)
 {
   AssertIsOnMainThread();
-  PostMessageInternal(aCx, aMessage, aTransferable, false, 0,
-                      aClientInfo.forget(), aRv);
-}
-
-template <class Derived>
-void
-WorkerPrivateParent<Derived>::PostMessageToMessagePort(
-                             JSContext* aCx,
-                             uint64_t aMessagePortSerial,
-                             JS::Handle<JS::Value> aMessage,
-                             const Optional<Sequence<JS::Value>>& aTransferable,
-                             ErrorResult& aRv)
-{
-  AssertIsOnMainThread();
-
-  PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
-                      nullptr, aRv);
-}
-
-template <class Derived>
-bool
-WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
-                                JSContext* aCx, uint64_t aMessagePortSerial,
-                                StructuredCloneHelper& aHelper)
-{
-  AssertIsOnMainThread();
-
-  SharedWorker* sharedWorker;
-  if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
-    // SharedWorker has already been unregistered?
-    return true;
-  }
-
-  nsRefPtr<MessagePort> port = sharedWorker->Port();
-  NS_ASSERTION(port, "SharedWorkers always have a port!");
-
-  if (port->IsClosed()) {
-    return true;
-  }
-
-  nsCOMPtr<nsISupports> parent = do_QueryInterface(port->GetParentObject());
-
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
-    return false;
-  }
-  JSContext* cx = jsapi.cx();
-
-  ErrorResult rv;
-  JS::Rooted<JS::Value> data(cx);
-  aHelper.Read(parent, cx, &data, rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    xpc::Throw(cx, rv.StealNSResult());
-    return false;
-  }
-
-  nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
-  rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
-                               EmptyString(), EmptyString(), nullptr);
-  if (NS_WARN_IF(rv.Failed())) {
-    xpc::Throw(cx, rv.StealNSResult());
-    return false;
-  }
-
-  nsTArray<nsRefPtr<MessagePortBase>> ports;
-  aHelper.TakeTransferredPorts(ports);
-
-  event->SetTrusted(true);
-  event->SetPorts(new MessagePortList(port, ports));
-
-  nsCOMPtr<nsIDOMEvent> domEvent;
-  CallQueryInterface(event.get(), getter_AddRefs(domEvent));
-  NS_ASSERTION(domEvent, "This should never fail!");
-
-  bool ignored;
-  rv = port->DispatchEvent(domEvent, &ignored);
-  if (NS_WARN_IF(rv.Failed())) {
-    xpc::Throw(cx, rv.StealNSResult());
-    return false;
-  }
-
-  return true;
+  PostMessageInternal(aCx, aMessage, aTransferable, aClientInfo.forget(), aRv);
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
                                     JSContext* aCx,
                                     const JS::RuntimeOptions& aRuntimeOptions)
 {
@@ -3085,67 +2918,60 @@ WorkerPrivate::OfflineStatusChangeEventI
   event->SetTrusted(true);
 
   globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
-                                                   SharedWorker* aSharedWorker)
+                                                   SharedWorker* aSharedWorker,
+                                                   MessagePort* aPort)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aSharedWorker);
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-  MOZ_ASSERT(!mSharedWorkers.Get(aSharedWorker->Serial()));
+  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
 
   if (IsSharedWorker()) {
     nsRefPtr<MessagePortRunnable> runnable =
-      new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
-                              true);
+      new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
     if (!runnable->Dispatch(aCx)) {
       return false;
     }
   }
 
-  mSharedWorkers.Put(aSharedWorker->Serial(), aSharedWorker);
+  mSharedWorkers.AppendElement(aSharedWorker);
 
   // If there were other SharedWorker objects attached to this worker then they
   // may all have been frozen and this worker would need to be thawed.
-  if (mSharedWorkers.Count() > 1 && !Thaw(aCx, nullptr)) {
+  if (mSharedWorkers.Length() > 1 && !Thaw(aCx, nullptr)) {
     return false;
   }
 
   return true;
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UnregisterSharedWorker(
                                                     JSContext* aCx,
                                                     SharedWorker* aSharedWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aSharedWorker);
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-  MOZ_ASSERT(mSharedWorkers.Get(aSharedWorker->Serial()));
-
-  nsRefPtr<MessagePortRunnable> runnable =
-    new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
-                            false);
-  if (!runnable->Dispatch(aCx)) {
-    JS_ReportPendingException(aCx);
-  }
-
-  mSharedWorkers.Remove(aSharedWorker->Serial());
+  MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
+
+  mSharedWorkers.RemoveElement(aSharedWorker);
 
   // If there are still SharedWorker objects attached to this worker then they
   // may all be frozen and this worker would need to be frozen. Otherwise,
   // if that was the last SharedWorker then it's time to cancel this worker.
-  if (mSharedWorkers.Count()) {
+  if (!mSharedWorkers.IsEmpty()) {
     if (!Freeze(aCx, nullptr)) {
       JS_ReportPendingException(aCx);
     }
   } else if (!Cancel(aCx)) {
     JS_ReportPendingException(aCx);
   }
 }
 
@@ -3273,91 +3099,47 @@ WorkerPrivateParent<Derived>::BroadcastE
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::GetAllSharedWorkers(
                                nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
 
-  struct Helper
-  {
-    static PLDHashOperator
-    Collect(const uint64_t& aKey,
-            SharedWorker* aSharedWorker,
-            void* aClosure)
-    {
-      AssertIsOnMainThread();
-      MOZ_ASSERT(aSharedWorker);
-      MOZ_ASSERT(aClosure);
-
-      auto array = static_cast<nsTArray<nsRefPtr<SharedWorker>>*>(aClosure);
-      array->AppendElement(aSharedWorker);
-
-      return PL_DHASH_NEXT;
-    }
-  };
-
   if (!aSharedWorkers.IsEmpty()) {
     aSharedWorkers.Clear();
   }
 
-  mSharedWorkers.EnumerateRead(Helper::Collect, &aSharedWorkers);
+  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+    aSharedWorkers.AppendElement(mSharedWorkers[i]);
+  }
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
                                                          nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
   MOZ_ASSERT(aWindow);
 
-  struct Closure
-  {
-    nsPIDOMWindow* mWindow;
-    nsAutoTArray<nsRefPtr<SharedWorker>, 10> mSharedWorkers;
-
-    explicit Closure(nsPIDOMWindow* aWindow)
-    : mWindow(aWindow)
-    {
-      AssertIsOnMainThread();
-      MOZ_ASSERT(aWindow);
-    }
-
-    static PLDHashOperator
-    Collect(const uint64_t& aKey,
-            SharedWorker* aSharedWorker,
-            void* aClosure)
-    {
-      AssertIsOnMainThread();
-      MOZ_ASSERT(aSharedWorker);
-      MOZ_ASSERT(aClosure);
-
-      auto closure = static_cast<Closure*>(aClosure);
-      MOZ_ASSERT(closure->mWindow);
-
-      if (aSharedWorker->GetOwner() == closure->mWindow) {
-        closure->mSharedWorkers.AppendElement(aSharedWorker);
-      } else {
-        MOZ_ASSERT(!SameCOMIdentity(aSharedWorker->GetOwner(),
-                                    closure->mWindow));
-      }
-
-      return PL_DHASH_NEXT;
-    }
-  };
-
-  Closure closure(aWindow);
-
-  mSharedWorkers.EnumerateRead(Closure::Collect, &closure);
-
-  for (uint32_t index = 0; index < closure.mSharedWorkers.Length(); index++) {
-    closure.mSharedWorkers[index]->Close();
+  nsAutoTArray<nsRefPtr<SharedWorker>, 10> sharedWorkers;
+
+  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+    if (mSharedWorkers[i]->GetOwner() == aWindow) {
+      sharedWorkers.AppendElement(mSharedWorkers[i]);
+    } else {
+      MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+                                  aWindow));
+    }
+  }
+
+  for (uint32_t index = 0; index < sharedWorkers.Length(); index++) {
+    sharedWorkers[index]->Close();
   }
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::WorkerScriptLoaded()
 {
   AssertIsOnMainThread();
@@ -4583,19 +4365,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
         if (!mControlQueue.IsEmpty()) {
           WorkerControlRunnable* runnable;
           while (mControlQueue.Pop(runnable)) {
             runnable->Cancel();
             runnable->Release();
           }
         }
 
-        // Clear away our MessagePorts.
-        mWorkerPorts.Clear();
-
         // Unroot the globals
         mScope = nullptr;
         mDebuggerScope = nullptr;
 
         return;
       }
     }
 
@@ -5523,18 +5302,16 @@ WorkerPrivate::AssertValidSyncLoop(nsIEv
 }
 #endif
 
 void
 WorkerPrivate::PostMessageToParentInternal(
                             JSContext* aCx,
                             JS::Handle<JS::Value> aMessage,
                             const Optional<Sequence<JS::Value>>& aTransferable,
-                            bool aToMessagePort,
-                            uint64_t aMessagePortSerial,
                             ErrorResult& aRv)
 {
   AssertIsOnWorkerThread();
 
   JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
   if (aTransferable.WasPassed()) {
     const Sequence<JS::Value>& realTransferable = aTransferable.Value();
 
@@ -5549,50 +5326,29 @@ WorkerPrivate::PostMessageToParentIntern
       aRv = NS_ERROR_OUT_OF_MEMORY;
       return;
     }
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(this,
-                             WorkerRunnable::ParentThreadUnchangedBusyCount,
-                             aToMessagePort, aMessagePortSerial);
+                             WorkerRunnable::ParentThreadUnchangedBusyCount);
 
   runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   if (!runnable->Dispatch(aCx)) {
     aRv = NS_ERROR_FAILURE;
   }
 }
 
 void
-WorkerPrivate::PostMessageToParentMessagePort(
-                             JSContext* aCx,
-                             uint64_t aMessagePortSerial,
-                             JS::Handle<JS::Value> aMessage,
-                             const Optional<Sequence<JS::Value>>& aTransferable,
-                             ErrorResult& aRv)
-{
-  AssertIsOnWorkerThread();
-
-  if (!mWorkerPorts.GetWeak(aMessagePortSerial)) {
-    // This port has been closed from the main thread. There's no point in
-    // sending this message so just bail.
-    return;
-  }
-
-  PostMessageToParentInternal(aCx, aMessage, aTransferable, true,
-                              aMessagePortSerial, aRv);
-}
-
-void
 WorkerPrivate::EnterDebuggerEventLoop()
 {
   AssertIsOnWorkerThread();
 
   JSContext* cx = GetJSContext();
   MOZ_ASSERT(cx);
 
   uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
@@ -6439,85 +6195,65 @@ WorkerPrivate::EndCTypesCall()
     mBlockedForMemoryReporter = false;
   }
 
   // Make sure the periodic timer is running before we start running JS again.
   SetGCTimerMode(PeriodicTimer);
 }
 
 bool
-WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
+WorkerPrivate::ConnectMessagePort(JSContext* aCx,
+                                  MessagePortIdentifier& aIdentifier)
 {
   AssertIsOnWorkerThread();
 
-  NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
-               "Already have this port registered!");
-
   WorkerGlobalScope* globalScope = GlobalScope();
 
   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
   MOZ_ASSERT(jsGlobal);
 
-  nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
+  // This MessagePortIdentifier is used to create a new port, still connected
+  // with the other one, but in the worker thread.
+  ErrorResult rv;
+  nsRefPtr<MessagePort> port = MessagePort::Create(nullptr, aIdentifier, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return false;
+  }
 
   GlobalObject globalObject(aCx, jsGlobal);
   if (globalObject.Failed()) {
     return false;
   }
 
   RootedDictionary<MessageEventInit> init(aCx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mSource.SetValue().SetAsMessagePort() = port;
 
-  ErrorResult rv;
-
   nsRefPtr<MessageEvent> event =
     MessageEvent::Constructor(globalObject,
                               NS_LITERAL_STRING("connect"), init, rv);
 
   event->SetTrusted(true);
 
-  nsTArray<nsRefPtr<MessagePortBase>> ports;
+  nsTArray<nsRefPtr<MessagePort>> ports;
   ports.AppendElement(port);
 
   nsRefPtr<MessagePortList> portList =
     new MessagePortList(static_cast<nsIDOMEventTarget*>(globalScope), ports);
   event->SetPorts(portList);
 
-  mWorkerPorts.Put(aMessagePortSerial, port);
-
   nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
 
   nsEventStatus dummy = nsEventStatus_eIgnore;
   globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
+
   return true;
 }
 
-void
-WorkerPrivate::DisconnectMessagePort(uint64_t aMessagePortSerial)
-{
-  AssertIsOnWorkerThread();
-
-  mWorkerPorts.Remove(aMessagePortSerial);
-}
-
-workers::MessagePort*
-WorkerPrivate::GetMessagePort(uint64_t aMessagePortSerial)
-{
-  AssertIsOnWorkerThread();
-
-  nsRefPtr<MessagePort> port;
-  if (mWorkerPorts.Get(aMessagePortSerial, getter_AddRefs(port))) {
-    return port;
-  }
-
-  return nullptr;
-}
-
 WorkerGlobalScope*
 WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
 {
   AssertIsOnWorkerThread();
 
   if (!mScope) {
     nsRefPtr<WorkerGlobalScope> globalScope;
     if (IsSharedWorker()) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -45,31 +45,32 @@ class nsIURI;
 
 namespace JS {
 struct RuntimeStats;
 } // namespace JS
 
 namespace mozilla {
 namespace dom {
 class Function;
+class MessagePort;
+class MessagePortIdentifier;
 class StructuredCloneHelper;
 } // namespace dom
 namespace ipc {
 class PrincipalInfo;
 } // namespace ipc
 } // namespace mozilla
 
 struct PRThread;
 
 class ReportDebuggerErrorRunnable;
 
 BEGIN_WORKERS_NAMESPACE
 
 class AutoSyncLoopHolder;
-class MessagePort;
 class SharedWorker;
 class ServiceWorkerClientInfo;
 class WorkerControlRunnable;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerGlobalScope;
 class WorkerPrivate;
 class WorkerRunnable;
@@ -172,20 +173,19 @@ private:
   // Only used for top level workers.
   nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
 
   // Protected by mMutex.
   JSSettings mJSSettings;
 
   // Only touched on the parent thread (currently this is always the main
   // thread as SharedWorkers are always top-level).
-  nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
+  nsTArray<SharedWorker*> mSharedWorkers;
 
   uint64_t mBusyCount;
-  uint64_t mMessagePortSerial;
   Status mParentStatus;
   bool mParentFrozen;
   bool mIsChromeWorker;
   bool mMainThreadObjectsForgotten;
   WorkerType mWorkerType;
   TimeStamp mCreationTimeStamp;
   DOMHighResTimeStamp mCreationTimeHighRes;
   TimeStamp mNowBaseTimeStamp;
@@ -221,17 +221,16 @@ private:
   TerminatePrivate(JSContext* aCx)
   {
     return NotifyPrivate(aCx, Terminating);
   }
 
   void
   PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const Optional<Sequence<JS::Value>>& aTransferable,
-                      bool aToMessagePort, uint64_t aMessagePortSerial,
                       ServiceWorkerClientInfo* aClientInfo,
                       ErrorResult& aRv);
 
   nsresult
   DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
 
 public:
   virtual JSObject*
@@ -323,39 +322,26 @@ public:
   void
   ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
 
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value> >& aTransferable,
               ErrorResult& aRv)
   {
-    PostMessageInternal(aCx, aMessage, aTransferable, false, 0, nullptr, aRv);
+    PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
   }
 
   void
   PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
                              ErrorResult& aRv);
 
   void
-  PostMessageToMessagePort(JSContext* aCx,
-                           uint64_t aMessagePortSerial,
-                           JS::Handle<JS::Value> aMessage,
-                           const Optional<Sequence<JS::Value> >& aTransferable,
-                           ErrorResult& aRv);
-
-  bool
-  DispatchMessageEventToMessagePort(
-                               JSContext* aCx,
-                               uint64_t aMessagePortSerial,
-                               StructuredCloneHelper& aHelper);
-
-  void
   UpdateRuntimeOptions(JSContext* aCx,
                        const JS::RuntimeOptions& aRuntimeOptions);
 
   void
   UpdateLanguages(JSContext* aCx, const nsTArray<nsString>& aLanguages);
 
   void
   UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
@@ -374,17 +360,18 @@ public:
 
   void
   CycleCollect(JSContext* aCx, bool aDummy);
 
   void
   OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
 
   bool
-  RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
+  RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker,
+                       MessagePort* aPort);
 
   void
   UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
 
   void
   BroadcastErrorToSharedWorkers(JSContext* aCx,
                                 const nsAString& aMessage,
                                 const nsAString& aFilename,
@@ -753,23 +740,16 @@ public:
   }
 
   const nsCString&
   SharedWorkerName() const
   {
     return mSharedWorkerName;
   }
 
-  uint64_t
-  NextMessagePortSerial()
-  {
-    AssertIsOnMainThread();
-    return mMessagePortSerial++;
-  }
-
   bool
   IsStorageAllowed() const
   {
     return mLoadInfo.mStorageAllowed;
   }
 
   bool
   IsInPrivateBrowsing() const
@@ -947,18 +927,16 @@ class WorkerPrivate : public WorkerPriva
   nsCOMPtr<nsITimer> mTimer;
 
   nsCOMPtr<nsITimer> mGCTimer;
   nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget;
   nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget;
 
   nsRefPtr<MemoryReporter> mMemoryReporter;
 
-  nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
-
   // fired on the main thread if the worker script fails to load
   nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
 
   TimeStamp mKillTime;
   uint32_t mErrorHandlerRecursionCount;
   uint32_t mNextTimeoutId;
   Status mStatus;
   bool mFrozen;
@@ -1071,23 +1049,22 @@ public:
   }
 
   void
   PostMessageToParent(JSContext* aCx,
                       JS::Handle<JS::Value> aMessage,
                       const Optional<Sequence<JS::Value>>& aTransferable,
                       ErrorResult& aRv)
   {
-    PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
+    PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
   }
 
   void
   PostMessageToParentMessagePort(
                              JSContext* aCx,
-                             uint64_t aMessagePortSerial,
                              JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              ErrorResult& aRv);
 
   void
   EnterDebuggerEventLoop();
 
   void
@@ -1234,23 +1211,17 @@ public:
   EndCTypesCallback()
   {
     // If a callback is ending then we need to do the exact same thing as
     // when a ctypes call begins.
     BeginCTypesCall();
   }
 
   bool
-  ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
-
-  void
-  DisconnectMessagePort(uint64_t aMessagePortSerial);
-
-  MessagePort*
-  GetMessagePort(uint64_t aMessagePortSerial);
+  ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
 
   WorkerGlobalScope*
   GetOrCreateGlobalScope(JSContext* aCx);
 
   WorkerDebuggerGlobalScope*
   CreateDebuggerGlobalScope(JSContext* aCx);
 
   bool
@@ -1440,18 +1411,16 @@ private:
 
   void
   WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
 
   void
   PostMessageToParentInternal(JSContext* aCx,
                               JS::Handle<JS::Value> aMessage,
                               const Optional<Sequence<JS::Value>>& aTransferable,
-                              bool aToMessagePort,
-                              uint64_t aMessagePortSerial,
                               ErrorResult& aRv);
 
   void
   GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const
   {
     AssertIsOnWorkerThread();
     memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
   }
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -24,17 +24,16 @@ EXPORTS.mozilla.dom.workers += [
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
     'DataStore.h',
     'DataStoreCursor.h',
     'FileReaderSync.h',
     'Location.h',
-    'MessagePort.h',
     'Navigator.h',
     'Performance.h',
     'ServiceWorker.h',
     'ServiceWorkerClient.h',
     'ServiceWorkerClients.h',
     'ServiceWorkerWindowClient.h',
     'SharedWorker.h',
     'URL.h',
@@ -51,17 +50,16 @@ XPIDL_SOURCES += [
 ]
 
 UNIFIED_SOURCES += [
     'ChromeWorkerScope.cpp',
     'DataStore.cpp',
     'DataStoreCursor.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
-    'MessagePort.cpp',
     'Navigator.cpp',
     'Performance.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'ServiceWorker.cpp',
     'ServiceWorkerClient.cpp',
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -105,16 +105,17 @@ support-files =
   bug1132395_sharedWorker.js
   bug1132924_worker.js
   empty.html
   worker_performance_user_timing.js
   worker_performance_observer.js
   sharedworker_performance_user_timing.js
   referrer.sjs
   performance_observer.html
+  sharedWorker_ports.js
 
 [test_404.html]
 [test_atob.html]
 [test_blobConstructor.html]
 [test_blobWorkers.html]
 [test_bug949946.html]
 [test_bug978260.html]
 [test_bug998474.html]
@@ -216,8 +217,9 @@ skip-if = buildapp == 'b2g' || toolkit =
 skip-if = buildapp == 'b2g' || e10s
 [test_xhr_responseURL.html]
 [test_xhr_system.html]
 skip-if = buildapp == 'b2g' || e10s
 [test_xhr_timeout.html]
 skip-if = (os == "win") || (os == "mac") || toolkit == 'android' || e10s #bug 798220
 [test_xhrAbort.html]
 [test_referrer.html]
+[test_sharedWorker_ports.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/sharedWorker_ports.js
@@ -0,0 +1,23 @@
+var port;
+onconnect = function(evt) {
+  evt.source.postMessage({ type: "connected" });
+
+  if (!port) {
+    port = evt.source;
+    evt.source.onmessage = function(evtFromPort) {
+      port.postMessage({type: "status",
+                        test: "Port from the main-thread!" == evtFromPort.data,
+                        msg: "The message is coming from the main-thread"});
+      port.postMessage({type: "status",
+                        test: (evtFromPort.ports.length == 1),
+                        msg: "1 port transferred"});
+
+      evtFromPort.ports[0].onmessage = function(evtFromPort2) {
+        port.postMessage({type: "status",
+                          test: (evtFromPort2.data.type == "connected"),
+                          msg: "The original message received" });
+        port.postMessage({type: "finish"});
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_sharedWorker_ports.html
@@ -0,0 +1,42 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Test for MessagePort and SharedWorkers</title>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  </head>
+  <body>
+    <script class="testbody" type="text/javascript">
+
+SpecialPowers.pushPrefEnv({ set: [["dom.workers.sharedWorkers.enabled", true]]},
+function() {
+  var sw1 = new SharedWorker('sharedWorker_ports.js');
+  sw1.port.onmessage = function(event) {
+    if (event.data.type == "connected") {
+      ok(true, "The SharedWorker is alive.");
+
+      var sw2 = new SharedWorker('sharedWorker_ports.js');
+      sw1.port.postMessage("Port from the main-thread!", [sw2.port]);
+      return;
+    }
+
+    if (event.data.type == "status") {
+      ok(event.data.test, event.data.msg);
+      return;
+    }
+
+    if (event.data.type == "finish") {
+      SimpleTest.finish();
+    }
+  }
+});
+
+SimpleTest.waitForExplicitFinish();
+    </script>
+  </body>
+</html>
+