Backed out changeset ccfddcbccdac (bug 1204775) for sharedworker bustage
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Sep 2015 11:08:09 -0700
changeset 262624 2ad7f8d8c0421a8dcccafabb71a807a9337d2abc
parent 262623 27cdeffa4ae126a34f50413a73fffb66b272b114
child 262644 df10a3f6060f208bc3f5f0e1d9965e083076a952
child 262692 380817d573cdfbfc4a4b4a4647cf1a53bb52c3b9
push id15198
push userkwierso@gmail.com
push dateWed, 16 Sep 2015 00:21:31 +0000
treeherderfx-team@dbfddd6efb5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1204775
milestone43.0a1
backs outccfddcbccdac3dabe0ffadd556b9e0e641cd4fb8
Backed out changeset ccfddcbccdac (bug 1204775) for sharedworker bustage
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,17 +109,18 @@ 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<MessagePort>> ports = TakeTransferredPorts();
+  nsTArray<nsRefPtr<MessagePortBase>> ports;
+  TakeTransferredPorts(ports);
 
   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,16 +15,19 @@
 
 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,24 +1067,26 @@ StructuredCloneHelper::WriteTransferCall
                                              void** aContent,
                                              uint64_t* aExtraData)
 {
   if (!mSupportsTransferring) {
     return false;
   }
 
   {
-    MessagePort* port = nullptr;
+    MessagePortBase* 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();
 
-      port->CloneAndDisentangle(*identifier);
+      if (!port->CloneAndDisentangle(*identifier)) {
+        return false;
+      }
 
       *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,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/. */
 
 #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
 
@@ -107,17 +106,17 @@ protected:
   nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
 
 #ifdef DEBUG
   bool mShutdownCalled;
 #endif
 };
 
 class BlobImpl;
-class MessagePort;
+class MessagePortBase;
 class MessagePortIdentifier;
 
 class StructuredCloneHelper : public StructuredCloneHelperInternal
 {
 public:
   enum CloningSupport
   {
     CloningSupported,
@@ -187,20 +186,21 @@ 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.
-  nsTArray<nsRefPtr<MessagePort>>&& TakeTransferredPorts()
+  void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
   {
     MOZ_ASSERT(mSupportsTransferring);
-    return Move(mTransferredPorts);
+    MOZ_ASSERT(aPorts.IsEmpty());
+    aPorts.SwapElements(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<MessagePort>> mTransferredPorts;
+  nsTArray<nsRefPtr<MessagePortBase>> 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,16 +734,21 @@ 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<MessagePort>> ports;
+    nsTArray<nsRefPtr<MessagePortBase>> 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,16 +12,17 @@
 #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
@@ -88,17 +89,17 @@ public:
 protected:
   ~MessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   nsCOMPtr<nsIDOMWindow> mWindowSource;
-  nsRefPtr<MessagePort> mPortSource;
+  nsRefPtr<MessagePortBase> 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,42 +44,37 @@ 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(aWindow);
+  nsRefPtr<MessageChannel> channel = new MessageChannel(window);
 
-  channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
+  channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
+  channel->mPort2 = MessagePort::Create(window, 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,19 +35,16 @@ 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,17 +135,18 @@ public:
 
     event->InitMessageEvent(NS_LITERAL_STRING("message"),
                             false /* non-bubbling */,
                             false /* cancelable */, value, EmptyString(),
                             EmptyString(), nullptr);
     event->SetTrusted(true);
     event->SetSource(mPort);
 
-    nsTArray<nsRefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
+    nsTArray<nsRefPtr<MessagePortBase>> ports;
+    mData->TakeTransferredPorts(ports);
 
     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);
@@ -165,45 +166,54 @@ 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,
-                                                DOMEventTargetHelper)
+                                                MessagePortBase)
   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,
-                                                  DOMEventTargetHelper)
+                                                  MessagePortBase)
   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(DOMEventTargetHelper)
+NS_INTERFACE_MAP_END_INHERITING(MessagePortBase)
 
-NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
+NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
+NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
 
 namespace {
 
 class MessagePortFeature final : public workers::WorkerFeature
 {
   MessagePort* mPort;
 
 public:
@@ -272,17 +282,17 @@ private:
   const MessagePortIdentifier mIdentifier;
 };
 
 NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
 
 } // namespace
 
 MessagePort::MessagePort(nsPIDOMWindow* aWindow)
-  : DOMEventTargetHelper(aWindow)
+  : MessagePortBase(aWindow)
   , mInnerID(0)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
 {
   mIdentifier = new MessagePortIdentifier();
   mIdentifier->neutered() = true;
   mIdentifier->sequenceId() = 0;
 }
@@ -349,38 +359,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()) {
+  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 {
     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);
 }
@@ -399,17 +409,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;
       }
 
-      MessagePort* port = nullptr;
+      MessagePortBase* 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;
@@ -505,32 +515,37 @@ 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;
   }
 
@@ -679,34 +694,34 @@ MessagePort::Disentangle()
   mActor->SendDisentangle(messages);
 
   mActor->SetPort(nullptr);
   mActor = nullptr;
 
   UpdateMustKeepAlive();
 }
 
-void
+bool
 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;
+    return true;
   }
 
   // We already have a 'next step'. We have to consider this port as already
   // cloned/closed/disentangled.
   if (mNextStep != eNextStepNone) {
-    return;
+    return true;
   }
 
   aIdentifier.uuid() = mIdentifier->uuid();
   aIdentifier.destinationUuid() = mIdentifier->destinationUuid();
   aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1;
   aIdentifier.neutered() = false;
 
   // We have to entangle first.
@@ -719,33 +734,34 @@ 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;
+      return true;
     }
 
     // Register this component to PBackground.
     ConnectToPBackground();
 
     mNextStep = eNextStepDisentangle;
-    return;
+    return true;
   }
 
   // Not entangled yet, we have to wait.
   if (mState < eStateEntangled) {
     mNextStep = eNextStepDisentangle;
-    return;
+    return true;
   }
 
   StartDisentangling();
+  return true;
 }
 
 void
 MessagePort::Closed()
 {
   if (mState == eStateDisentangled) {
     return;
   }
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -26,61 +26,95 @@ class MessagePortChild;
 class MessagePortIdentifier;
 class MessagePortMessage;
 class SharedMessagePortMessage;
 
 namespace workers {
 class WorkerFeature;
 } // namespace workers
 
-class MessagePort final : public DOMEventTargetHelper
+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
                         , 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,
-                                           DOMEventTargetHelper)
+                                           MessagePortBase)
 
   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;
 
-  void
+  virtual void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
-              ErrorResult& aRv);
+              ErrorResult& aRv) override;
 
-  void Start();
+  virtual void Start() override;
 
-  void Close();
+  virtual void Close() override;
 
-  EventHandlerNonNull* GetOnmessage();
+  virtual EventHandlerNonNull* GetOnmessage() override;
 
-  void SetOnmessage(EventHandlerNonNull* aCallback);
+  virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
 
   // Non WebIDL methods
 
   void UnshippedEntangle(MessagePort* aEntangledPort);
 
-  void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
+  virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
 
   // 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<MessagePort>>& aPorts)
+                  const nsTArray<nsRefPtr<MessagePortBase>>& 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();
   }
 
-  MessagePort*
+  MessagePortBase*
   Item(uint32_t aIndex)
   {
     return mPorts.SafeElementAt(aIndex);
   }
 
-  MessagePort*
+  MessagePortBase*
   IndexedGetter(uint32_t aIndex, bool &aFound)
   {
     aFound = aIndex < mPorts.Length();
     if (!aFound) {
       return nullptr;
     }
     return mPorts[aIndex];
   }
 
 public:
   nsCOMPtr<nsISupports> mOwner;
-  nsTArray<nsRefPtr<MessagePort>> mPorts;
+  nsTArray<nsRefPtr<MessagePortBase>> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MessagePortList_h
 
new file mode 100644
--- /dev/null
+++ b/dom/workers/MessagePort.cpp
@@ -0,0 +1,318 @@
+/* -*- 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;
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/MessagePort.h
@@ -0,0 +1,112 @@
+/* -*- 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,17 +29,16 @@
 #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"
@@ -2489,43 +2488,34 @@ 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);
   }
 
-  // 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())) {
+  nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
+
+  if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
     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,17 +133,18 @@ private:
                                  EmptyString(),
                                  EmptyString(),
                                  nullptr);
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return NS_ERROR_FAILURE;
     }
 
-    nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
+    nsTArray<nsRefPtr<MessagePortBase>> ports;
+    TakeTransferredPorts(ports);
 
     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,17 +6,16 @@
 
 #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,40 +5,42 @@
  * 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,
-                           MessagePort* aMessagePort)
-: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate)
-, mMessagePort(aMessagePort)
-, mFrozen(false)
+                           WorkerPrivate* aWorkerPrivate)
+: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
+  mFrozen(false)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWorkerPrivate);
+
+  mSerial = aWorkerPrivate->NextMessagePortSerial();
+
+  mMessagePort = new MessagePort(aWindow, this, mSerial);
 }
 
 SharedWorker::~SharedWorker()
 {
   AssertIsOnMainThread();
   Close();
   MOZ_ASSERT(!mWorkerPrivate);
 }
@@ -69,21 +71,23 @@ SharedWorker::Constructor(const GlobalOb
   if (NS_FAILED(rv)) {
     aRv = rv;
     return nullptr;
   }
 
   return sharedWorker.forget();
 }
 
-MessagePort*
+already_AddRefed<mozilla::dom::workers::MessagePort>
 SharedWorker::Port()
 {
   AssertIsOnMainThread();
-  return mMessagePort;
+
+  nsRefPtr<MessagePort> messagePort = mMessagePort;
+  return messagePort.forget();
 }
 
 void
 SharedWorker::Freeze()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!IsFrozen());
 
@@ -148,17 +152,18 @@ 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);
 
-  mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
+  mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(),
+                                           aMessage, aTransferable, aRv);
 }
 
 void
 SharedWorker::NoteDeadWorker(JSContext* aCx)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mWorkerPrivate);
 
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -5,55 +5,61 @@
  * 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);
 
-  MessagePort*
+  already_AddRefed<mozilla::dom::workers::MessagePort>
   Port();
 
+  uint64_t
+  Serial() const
+  {
+    return mSerial;
+  }
+
   bool
   IsFrozen() const
   {
     return mFrozen;
   }
 
   void
   Freeze();
@@ -82,18 +88,17 @@ public:
   GetWorkerPrivate() const
   {
     return mWorkerPrivate;
   }
 
 private:
   // This class can only be created from the RuntimeService.
   SharedWorker(nsPIDOMWindow* aWindow,
-               WorkerPrivate* aWorkerPrivate,
-               MessagePort* aMessagePort);
+               WorkerPrivate* aWorkerPrivate);
 
   // 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,17 +49,16 @@
 #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"
@@ -84,16 +83,17 @@
 #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,25 +589,31 @@ 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)
+                       TargetAndBusyBehavior aBehavior,
+                       bool aToMessagePort, uint64_t aMessagePortSerial)
   : WorkerRunnable(aWorkerPrivate, aBehavior)
   , StructuredCloneHelper(CloningSupported, TransferringSupported,
                           SameProcessDifferentThread)
+  , mMessagePortSerial(aMessagePortSerial)
+  , mToMessagePort(aToMessagePort)
   {
   }
 
   void
   SetMessageSource(ServiceWorkerClientInfo* aSource)
   {
     mEventSource = aSource;
   }
@@ -643,52 +649,72 @@ public:
       event->SetSource(client);
     }
 
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return false;
     }
 
-    nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
+    nsTArray<nsRefPtr<MessagePortBase>> ports;
+    TakeTransferredPorts(ports);
 
     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;
 
@@ -1490,38 +1516,42 @@ public:
     extras->location = nullptr;
 
     aCompartmentStats->extra = extras;
   }
 };
 
 class MessagePortRunnable final : public WorkerRunnable
 {
-  MessagePortIdentifier mPortIdentifier;
+  uint64_t mMessagePortSerial;
+  bool mConnect;
 
 public:
   MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
-                      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);
-  }
+                      uint64_t aMessagePortSerial,
+                      bool aConnect)
+  : WorkerRunnable(aWorkerPrivate, aConnect ?
+                                   WorkerThreadModifyBusyCount :
+                                   WorkerThreadUnchangedBusyCount),
+    mMessagePortSerial(aMessagePortSerial), mConnect(aConnect)
+  { }
 
 private:
   ~MessagePortRunnable()
   { }
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
-    return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
+    if (mConnect) {
+      return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial);
+    }
+
+    aWorkerPrivate->DisconnectMessagePort(mMessagePortSerial);
+    return true;
   }
 };
 
 class DummyRunnable final
   : public WorkerRunnable
 {
 public:
   explicit
@@ -2087,17 +2117,18 @@ 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), mParentStatus(Pending), mParentFrozen(false),
+  mBusyCount(0), mMessagePortSerial(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());
@@ -2451,39 +2482,65 @@ 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.IsEmpty()) {
+  if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
     AssertIsOnMainThread();
 
-    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;
+    struct Closure
+    {
+      nsPIDOMWindow* mWindow;
+      bool mAllFrozen;
+
+      explicit Closure(nsPIDOMWindow* aWindow)
+      : mWindow(aWindow), mAllFrozen(true)
+      {
+        AssertIsOnMainThread();
+        // aWindow may be null here.
+      }
+
+      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;
       }
-    }
-
-    if (!allFrozen || mParentFrozen) {
+    };
+
+    Closure closure(aWindow);
+
+    mSharedWorkers.EnumerateRead(Closure::Freeze, &closure);
+
+    if (!closure.mAllFrozen || mParentFrozen) {
       return true;
     }
   }
 
   mParentFrozen = true;
 
   {
     MutexAutoLock lock(mMutex);
@@ -2514,40 +2571,66 @@ 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.IsEmpty()) {
+  if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
     AssertIsOnMainThread();
 
-    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;
+    struct Closure
+    {
+      nsPIDOMWindow* mWindow;
+      bool mAnyRunning;
+
+      explicit Closure(nsPIDOMWindow* aWindow)
+      : mWindow(aWindow), mAnyRunning(false)
+      {
+        AssertIsOnMainThread();
+        // aWindow may be null here.
+      }
+
+      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;
       }
-    }
-
-    if (!anyRunning || !mParentFrozen) {
+    };
+
+    Closure closure(aWindow);
+
+    mSharedWorkers.EnumerateRead(Closure::Thaw, &closure);
+
+    if (!closure.mAnyRunning || !mParentFrozen) {
       return true;
     }
   }
 
   MOZ_ASSERT(mParentFrozen);
 
   mParentFrozen = false;
 
@@ -2674,16 +2757,18 @@ 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) {
@@ -2707,17 +2792,18 @@ WorkerPrivateParent<Derived>::PostMessag
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
-                             WorkerRunnable::WorkerThreadModifyBusyCount);
+                             WorkerRunnable::WorkerThreadModifyBusyCount,
+                             aToMessagePort, aMessagePortSerial);
 
   runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   runnable->SetMessageSource(aClientInfo);
 
@@ -2730,17 +2816,98 @@ 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, aClientInfo.forget(), aRv);
+  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;
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
                                     JSContext* aCx,
                                     const JS::RuntimeOptions& aRuntimeOptions)
 {
@@ -2918,60 +3085,67 @@ WorkerPrivate::OfflineStatusChangeEventI
   event->SetTrusted(true);
 
   globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
-                                                   SharedWorker* aSharedWorker,
-                                                   MessagePort* aPort)
+                                                   SharedWorker* aSharedWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aSharedWorker);
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
+  MOZ_ASSERT(!mSharedWorkers.Get(aSharedWorker->Serial()));
 
   if (IsSharedWorker()) {
     nsRefPtr<MessagePortRunnable> runnable =
-      new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
+      new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
+                              true);
     if (!runnable->Dispatch(aCx)) {
       return false;
     }
   }
 
-  mSharedWorkers.AppendElement(aSharedWorker);
+  mSharedWorkers.Put(aSharedWorker->Serial(), 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.Length() > 1 && !Thaw(aCx, nullptr)) {
+  if (mSharedWorkers.Count() > 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.Contains(aSharedWorker));
-
-  mSharedWorkers.RemoveElement(aSharedWorker);
+  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());
 
   // 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.IsEmpty()) {
+  if (mSharedWorkers.Count()) {
     if (!Freeze(aCx, nullptr)) {
       JS_ReportPendingException(aCx);
     }
   } else if (!Cancel(aCx)) {
     JS_ReportPendingException(aCx);
   }
 }
 
@@ -3099,47 +3273,91 @@ 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();
   }
 
-  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-    aSharedWorkers.AppendElement(mSharedWorkers[i]);
-  }
+  mSharedWorkers.EnumerateRead(Helper::Collect, &aSharedWorkers);
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
                                                          nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
   MOZ_ASSERT(aWindow);
 
-  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();
+  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();
   }
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::WorkerScriptLoaded()
 {
   AssertIsOnMainThread();
@@ -4365,16 +4583,19 @@ 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;
       }
     }
 
@@ -5302,16 +5523,18 @@ 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();
 
@@ -5326,29 +5549,50 @@ WorkerPrivate::PostMessageToParentIntern
       aRv = NS_ERROR_OUT_OF_MEMORY;
       return;
     }
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(this,
-                             WorkerRunnable::ParentThreadUnchangedBusyCount);
+                             WorkerRunnable::ParentThreadUnchangedBusyCount,
+                             aToMessagePort, aMessagePortSerial);
 
   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;
@@ -6195,65 +6439,85 @@ WorkerPrivate::EndCTypesCall()
     mBlockedForMemoryReporter = false;
   }
 
   // Make sure the periodic timer is running before we start running JS again.
   SetGCTimerMode(PeriodicTimer);
 }
 
 bool
-WorkerPrivate::ConnectMessagePort(JSContext* aCx,
-                                  MessagePortIdentifier& aIdentifier)
+WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
 {
   AssertIsOnWorkerThread();
 
+  NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
+               "Already have this port registered!");
+
   WorkerGlobalScope* globalScope = GlobalScope();
 
   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
   MOZ_ASSERT(jsGlobal);
 
-  // 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;
-  }
+  nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
 
   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<MessagePort>> ports;
+  nsTArray<nsRefPtr<MessagePortBase>> 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,32 +45,31 @@ 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;
@@ -173,19 +172,20 @@ 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).
-  nsTArray<SharedWorker*> mSharedWorkers;
+  nsDataHashtable<nsUint64HashKey, 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,16 +221,17 @@ 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*
@@ -322,26 +323,39 @@ 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, nullptr, aRv);
+    PostMessageInternal(aCx, aMessage, aTransferable, false, 0, 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);
@@ -360,18 +374,17 @@ public:
 
   void
   CycleCollect(JSContext* aCx, bool aDummy);
 
   void
   OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
 
   bool
-  RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker,
-                       MessagePort* aPort);
+  RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
 
   void
   UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
 
   void
   BroadcastErrorToSharedWorkers(JSContext* aCx,
                                 const nsAString& aMessage,
                                 const nsAString& aFilename,
@@ -740,16 +753,23 @@ public:
   }
 
   const nsCString&
   SharedWorkerName() const
   {
     return mSharedWorkerName;
   }
 
+  uint64_t
+  NextMessagePortSerial()
+  {
+    AssertIsOnMainThread();
+    return mMessagePortSerial++;
+  }
+
   bool
   IsStorageAllowed() const
   {
     return mLoadInfo.mStorageAllowed;
   }
 
   bool
   IsInPrivateBrowsing() const
@@ -927,16 +947,18 @@ 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;
@@ -1049,22 +1071,23 @@ public:
   }
 
   void
   PostMessageToParent(JSContext* aCx,
                       JS::Handle<JS::Value> aMessage,
                       const Optional<Sequence<JS::Value>>& aTransferable,
                       ErrorResult& aRv)
   {
-    PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
+    PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
   }
 
   void
   PostMessageToParentMessagePort(
                              JSContext* aCx,
+                             uint64_t aMessagePortSerial,
                              JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              ErrorResult& aRv);
 
   void
   EnterDebuggerEventLoop();
 
   void
@@ -1211,17 +1234,23 @@ 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, MessagePortIdentifier& aIdentifier);
+  ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
+
+  void
+  DisconnectMessagePort(uint64_t aMessagePortSerial);
+
+  MessagePort*
+  GetMessagePort(uint64_t aMessagePortSerial);
 
   WorkerGlobalScope*
   GetOrCreateGlobalScope(JSContext* aCx);
 
   WorkerDebuggerGlobalScope*
   CreateDebuggerGlobalScope(JSContext* aCx);
 
   bool
@@ -1411,16 +1440,18 @@ 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,16 +24,17 @@ 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',
@@ -50,16 +51,17 @@ 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,17 +105,16 @@ 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]
@@ -217,9 +216,8 @@ 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]
deleted file mode 100644
--- a/dom/workers/test/sharedWorker_ports.js
+++ /dev/null
@@ -1,23 +0,0 @@
-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"});
-      }
-    }
-  }
-}
deleted file mode 100644
--- a/dom/workers/test/test_sharedWorker_ports.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  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>
-