Bug 1438945 - Part 9: RemoteWorker in SharedWorkerManager. r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 19 Nov 2018 15:18:33 -0800
changeset 503571 b3d9a379c852669a1fa005148bee537b99c91c6f
parent 503570 6059af9c85adc62a51d9b38b9cdcba3904d4d824
child 503572 9482aa753a31fd3adc22704e4c3ad1466f110150
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1438945
milestone65.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 1438945 - Part 9: RemoteWorker in SharedWorkerManager. r=asuth
dom/fetch/Fetch.cpp
dom/workers/RuntimeService.cpp
dom/workers/WorkerError.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/remoteworkers/PRemoteWorker.ipdl
dom/workers/remoteworkers/RemoteWorkerChild.cpp
dom/workers/remoteworkers/RemoteWorkerChild.h
dom/workers/remoteworkers/RemoteWorkerController.cpp
dom/workers/remoteworkers/RemoteWorkerController.h
dom/workers/remoteworkers/RemoteWorkerParent.cpp
dom/workers/remoteworkers/RemoteWorkerParent.h
dom/workers/remoteworkers/RemoteWorkerService.cpp
dom/workers/remoteworkers/RemoteWorkerService.h
dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh
dom/workers/sharedworkers/PSharedWorker.ipdl
dom/workers/sharedworkers/SharedWorker.cpp
dom/workers/sharedworkers/SharedWorkerManager.cpp
dom/workers/sharedworkers/SharedWorkerManager.h
dom/workers/sharedworkers/SharedWorkerParent.cpp
dom/workers/sharedworkers/SharedWorkerParent.h
dom/workers/sharedworkers/SharedWorkerService.cpp
dom/workers/sharedworkers/SharedWorkerService.h
dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
dom/workers/sharedworkers/moz.build
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -28,20 +28,20 @@
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/FetchDriver.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/MutableBlobStreamListener.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/Telemetry.h"
 
 #include "BodyExtractor.h"
 #include "EmptyBody.h"
 #include "FetchObserver.h"
 #include "InternalRequest.h"
 #include "InternalResponse.h"
@@ -902,17 +902,17 @@ WorkerFetchResolver::FlushConsoleReport(
   if (worker->IsServiceWorker()) {
     // Flush to service worker
     mReporter->FlushReportsToConsoleForServiceWorkerScope(worker->ServiceWorkerScope());
     return;
   }
 
   if (worker->IsSharedWorker()) {
     // Flush to shared worker
-    worker->GetSharedWorkerManager()->FlushReportsToActorsOnMainThread(mReporter);
+    worker->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter);
     return;
   }
 
   // Flush to dedicated worker
   mReporter->FlushConsoleReports(worker->GetLoadGroup());
 }
 
 nsresult
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -42,19 +42,19 @@
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PerformanceService.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/SharedWorkerManager.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsContentUtils.h"
@@ -1528,17 +1528,17 @@ RuntimeService::UnregisterWorker(WorkerP
   if (aWorkerPrivate->IsServiceWorker()) {
     AssertIsOnMainThread();
     Telemetry::AccumulateTimeDelta(Telemetry::SERVICE_WORKER_LIFE_TIME,
                                    aWorkerPrivate->CreationTimeStamp());
   }
 
   if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
-    aWorkerPrivate->GetSharedWorkerManager()->CloseActorsOnMainThread();
+    aWorkerPrivate->GetRemoteWorkerController()->CloseWorkerOnMainThread();
   }
 
   if (parent) {
     parent->RemoveChildWorker(aWorkerPrivate);
   }
   else if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
 
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.cpp
@@ -4,18 +4,17 @@
  * 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 "WorkerError.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
-#include "mozilla/dom/PSharedWorker.h"
-#include "mozilla/dom/SharedWorkerManager.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindowInner.h"
 #include "nsIConsoleService.h"
 #include "nsScriptError.h"
@@ -198,19 +197,19 @@ private:
       // care of naturally.
       MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
       // Similarly for paused windows; all its workers should have been informed.
       // (Subworkers are unaffected by paused windows.)
       MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
       if (aWorkerPrivate->IsSharedWorker()) {
-        aWorkerPrivate->GetSharedWorkerManager()
-                      ->BroadcastErrorToActorsOnMainThread(&mReport,
-                                                           /* isErrorEvent */ true);
+        aWorkerPrivate->GetRemoteWorkerController()
+                      ->ErrorPropagationOnMainThread(&mReport,
+                                                     /* isErrorEvent */ true);
         return true;
       }
 
       // Service workers do not have a main thread parent global, so normal
       // worker error reporting will crash.  Instead, pass the error to
       // the ServiceWorkerManager to report on any controlled documents.
       if (aWorkerPrivate->IsServiceWorker()) {
         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
@@ -289,18 +288,18 @@ private:
     // care of naturally.
     MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
     // Similarly for paused windows; all its workers should have been informed.
     // (Subworkers are unaffected by paused windows.)
     MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
     if (aWorkerPrivate->IsSharedWorker()) {
-      aWorkerPrivate->GetSharedWorkerManager()
-                    ->BroadcastErrorToActorsOnMainThread(nullptr, false);
+      aWorkerPrivate->GetRemoteWorkerController()
+                    ->ErrorPropagationOnMainThread(nullptr, false);
       return true;
     }
 
     if (aWorkerPrivate->IsServiceWorker()) {
       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
       if (swm) {
         swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
                          aWorkerPrivate->ServiceWorkerScope(),
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -25,17 +25,17 @@
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PerformanceStorageWorker.h"
 #include "mozilla/dom/PromiseDebugging.h"
-#include "mozilla/dom/SharedWorkerManager.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/ThreadEventQueue.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsCycleCollector.h"
 #include "nsGlobalWindowInner.h"
 #include "nsNetUtil.h"
@@ -1883,17 +1883,17 @@ WorkerPrivate::Close()
   return true;
 }
 
 bool
 WorkerPrivate::ModifyBusyCount(bool aIncrease)
 {
   AssertIsOnParentThread();
 
-  NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
+  MOZ_ASSERT(aIncrease || mBusyCount, "Mismatched busy count mods!");
 
   if (aIncrease) {
     mBusyCount++;
     return true;
   }
 
   if (--mBusyCount == 0) {
 
@@ -4902,17 +4902,17 @@ WorkerPrivate::EndCTypesCall()
   AssertIsOnWorkerThread();
 
   // Make sure the periodic timer is running before we start running JS again.
   SetGCTimerMode(PeriodicTimer);
 }
 
 bool
 WorkerPrivate::ConnectMessagePort(JSContext* aCx,
-                                  MessagePortIdentifier& aIdentifier)
+                                  const MessagePortIdentifier& aIdentifier)
 {
   AssertIsOnWorkerThread();
 
   WorkerGlobalScope* globalScope = GlobalScope();
 
   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
   MOZ_ASSERT(jsGlobal);
 
@@ -5070,31 +5070,31 @@ PerformanceStorage*
 WorkerPrivate::GetPerformanceStorage()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mPerformanceStorage);
   return mPerformanceStorage;
 }
 
 void
-WorkerPrivate::SetSharedWorkerManager(SharedWorkerManager* aManager)
+WorkerPrivate::SetRemoteWorkerController(RemoteWorkerChild* aController)
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aManager);
-  MOZ_ASSERT(!mSharedWorkerManager);
-
-  mSharedWorkerManager = aManager;
+  MOZ_ASSERT(aController);
+  MOZ_ASSERT(!mRemoteWorkerController);
+
+  mRemoteWorkerController = aController;
 }
 
-SharedWorkerManager*
-WorkerPrivate::GetSharedWorkerManager()
+RemoteWorkerChild*
+WorkerPrivate::GetRemoteWorkerController()
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(mSharedWorkerManager);
-  return mSharedWorkerManager;
+  MOZ_ASSERT(mRemoteWorkerController);
+  return mRemoteWorkerController;
 }
 
 NS_IMPL_ADDREF(WorkerPrivate::EventTarget)
 NS_IMPL_RELEASE(WorkerPrivate::EventTarget)
 
 NS_INTERFACE_MAP_BEGIN(WorkerPrivate::EventTarget)
   NS_INTERFACE_MAP_ENTRY(nsISerialEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIEventTarget)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -39,17 +39,17 @@ enum WorkerType
 };
 
 class ClientInfo;
 class ClientSource;
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PerformanceStorage;
-class SharedWorkerManager;
+class RemoteWorkerChild;
 class WorkerControlRunnable;
 class WorkerCSPEventListener;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerErrorReport;
 class WorkerEventTarget;
 class WorkerGlobalScope;
 class WorkerRunnable;
@@ -456,17 +456,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, MessagePortIdentifier& aIdentifier);
+  ConnectMessagePort(JSContext* aCx, const MessagePortIdentifier& aIdentifier);
 
   WorkerGlobalScope*
   GetOrCreateGlobalScope(JSContext* aCx);
 
   WorkerDebuggerGlobalScope*
   CreateDebuggerGlobalScope(JSContext* aCx);
 
   bool
@@ -1074,21 +1074,21 @@ public:
   // top level script.
   void
   SetLoadingWorkerScript(bool aLoadingWorkerScript)
   {
     // any thread
     mLoadingWorkerScript = aLoadingWorkerScript;
   }
 
-  SharedWorkerManager*
-  GetSharedWorkerManager();
+  RemoteWorkerChild*
+  GetRemoteWorkerController();
 
   void
-  SetSharedWorkerManager(SharedWorkerManager* aWorkerManager);
+  SetRemoteWorkerController(RemoteWorkerChild* aController);
 
   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
   // as these are only used for globals going in and out of the bfcache.
   bool
   Freeze(nsPIDOMWindowInner* aWindow);
 
   bool
   Thaw(nsPIDOMWindowInner* aWindow);
@@ -1388,17 +1388,17 @@ private:
   RefPtr<PerformanceStorage> mPerformanceStorage;
 
   RefPtr<WorkerCSPEventListener> mCSPEventListener;
 
   // Protected by mMutex.
   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
 
   // Only touched on the parent thread. This is set only if IsSharedWorker().
-  RefPtr<SharedWorkerManager> mSharedWorkerManager;
+  RefPtr<RemoteWorkerChild> mRemoteWorkerController;
 
   JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
   TimeStamp mKillTime;
   WorkerStatus mParentStatus;
   WorkerStatus mStatus;
 
   // This is touched on parent thread only, but it can be read on a different
   // thread before crashing because hanging.
--- a/dom/workers/remoteworkers/PRemoteWorker.ipdl
+++ b/dom/workers/remoteworkers/PRemoteWorker.ipdl
@@ -1,24 +1,75 @@
 /* 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 protocol PBackground;
 
+include DOMTypes;
+include RemoteWorkerTypes;
+
 namespace mozilla {
 namespace dom {
 
+struct RemoteWorkerSuspendOp
+{};
+
+struct RemoteWorkerResumeOp
+{};
+
+struct RemoteWorkerFreezeOp
+{};
+
+struct RemoteWorkerThawOp
+{};
+
+struct RemoteWorkerTerminateOp
+{};
+
+struct RemoteWorkerPortIdentifierOp
+{
+  MessagePortIdentifier portIdentifier;
+};
+
+struct RemoteWorkerAddWindowIDOp
+{
+  uint64_t windowID;
+};
+
+struct RemoteWorkerRemoveWindowIDOp
+{
+  uint64_t windowID;
+};
+
+union RemoteWorkerOp {
+  RemoteWorkerSuspendOp;
+  RemoteWorkerResumeOp;
+  RemoteWorkerFreezeOp;
+  RemoteWorkerThawOp;
+  RemoteWorkerTerminateOp;
+  RemoteWorkerPortIdentifierOp;
+  RemoteWorkerAddWindowIDOp;
+  RemoteWorkerRemoveWindowIDOp;
+};
+
 // This protocol is used to make a remote worker controllable from the parent
 // process. The parent process will receive operations from the
 // PRemoteWorkerController protocol.
 protocol PRemoteWorker
 {
   manager PBackground;
 
 parent:
+  async Created(bool aStatus);
+
+  async Error(ErrorValue aValue);
+
+  async Close();
+
+child:
   async __delete__();
 
-  async Created(bool aStatus);
+  async ExecOp(RemoteWorkerOp op);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -1,18 +1,743 @@
 /* -*- 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 "RemoteWorkerChild.h"
+#include "RemoteWorkerService.h"
+#include "mozilla/dom/IndexedDatabaseManager.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
+#include "mozilla/dom/ServiceWorkerInterceptController.h"
+#include "mozilla/dom/workerinternals/ScriptLoader.h"
+#include "mozilla/dom/WorkerError.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRef.h"
+#include "mozilla/dom/WorkerRunnable.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "nsIConsoleReportCollector.h"
+#include "nsIPrincipal.h"
+#include "nsNetUtil.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
+
+using namespace ipc;
+
 namespace dom {
 
+using workerinternals::ChannelFromScriptURLMainThread;
+
+namespace {
+
+nsresult
+PopulateContentSecurityPolicy(nsIContentSecurityPolicy* aCSP,
+                              const nsTArray<ContentSecurityPolicy>& aPolicies)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aCSP);
+  MOZ_ASSERT(!aPolicies.IsEmpty());
+
+  for (const ContentSecurityPolicy& policy : aPolicies) {
+    nsresult rv = aCSP->AppendPolicy(policy.policy(),
+                                     policy.reportOnlyFlag(),
+                                     policy.deliveredViaMetaTagFlag());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+PopulatePrincipalContentSecurityPolicy(nsIPrincipal* aPrincipal,
+                                       const nsTArray<ContentSecurityPolicy>& aPolicies,
+                                       const nsTArray<ContentSecurityPolicy>& aPreloadPolicies)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+
+  if (!aPolicies.IsEmpty()) {
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    aPrincipal->EnsureCSP(nullptr, getter_AddRefs(csp));
+    nsresult rv = PopulateContentSecurityPolicy(csp, aPolicies);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  if (!aPreloadPolicies.IsEmpty()) {
+    nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
+    aPrincipal->EnsurePreloadCSP(nullptr, getter_AddRefs(preloadCsp));
+    nsresult rv = PopulateContentSecurityPolicy(preloadCsp, aPreloadPolicies);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
+class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  SharedWorkerInterfaceRequestor()
+    : mSWController(new ServiceWorkerInterceptController())
+  {}
+
+  NS_IMETHOD
+  GetInterface(const nsIID& aIID, void** aSink) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
+      // If asked for the network intercept controller, ask the outer requestor,
+      // which could be the docshell.
+      RefPtr<ServiceWorkerInterceptController> swController = mSWController;
+      swController.forget(aSink);
+      return NS_OK;
+    }
+
+    return NS_NOINTERFACE;
+  }
+
+private:
+  ~SharedWorkerInterfaceRequestor() = default;
+
+  RefPtr<ServiceWorkerInterceptController> mSWController;
+};
+
+NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
+NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
+NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
+
+// Normal runnable because AddPortIdentifier() is going to exec JS code.
+class MessagePortIdentifierRunnable final : public WorkerRunnable
+{
+public:
+  MessagePortIdentifierRunnable(WorkerPrivate* aWorkerPrivate,
+                                RemoteWorkerChild* aActor,
+                                const MessagePortIdentifier& aPortIdentifier)
+    : WorkerRunnable(aWorkerPrivate)
+    , mActor(aActor)
+    , mPortIdentifier(aPortIdentifier)
+  {}
+
+private:
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    mActor->AddPortIdentifier(aCx, aWorkerPrivate, mPortIdentifier);
+    return true;
+  }
+
+  nsresult
+  Cancel() override
+  {
+    MessagePort::ForceClose(mPortIdentifier);
+    return WorkerRunnable::Cancel();
+  }
+
+  virtual bool
+  PreDispatch(WorkerPrivate* aWorkerPrivate) override
+  {
+    // Silence bad assertions.
+    return true;
+  }
+
+  virtual void
+  PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+  {
+    // Silence bad assertions.
+  }
+
+  bool
+  PreRun(WorkerPrivate* aWorkerPrivate) override
+  {
+    // Silence bad assertions.
+    return true;
+  }
+
+  void
+  PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+          bool aRunResult) override
+  {
+    // Silence bad assertions.
+    return;
+  }
+
+
+  RefPtr<RemoteWorkerChild> mActor;
+  MessagePortIdentifier mPortIdentifier;
+};
+
+} // anonymous
+
+class RemoteWorkerChild::InitializeWorkerRunnable final : public WorkerRunnable
+{
+public:
+  InitializeWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                           RemoteWorkerChild* aActor)
+    : WorkerRunnable(aWorkerPrivate)
+    , mActor(aActor)
+  {}
+
+private:
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    mActor->InitializeOnWorker(aWorkerPrivate);
+    return true;
+  }
+
+  nsresult
+  Cancel() override
+  {
+    mActor->CreationFailedOnAnyThread();
+    mActor->ShutdownOnWorker();
+    return WorkerRunnable::Cancel();
+  }
+
+  RefPtr<RemoteWorkerChild> mActor;
+};
+
 RemoteWorkerChild::RemoteWorkerChild()
-{}
+  : mIPCActive(true)
+  , mWorkerState(ePending)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+}
+
+RemoteWorkerChild::~RemoteWorkerChild()
+{
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+
+  NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
+                  target, mWorkerPrivate.forget());
+}
+
+void
+RemoteWorkerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIPCActive = false;
+  mPendingOps.Clear();
+}
+
+void
+RemoteWorkerChild::ExecWorker(const RemoteWorkerData& aData)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+  MOZ_ASSERT(mIPCActive);
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ExecWorker",
+                           [self, aData]() {
+      nsresult rv = self->ExecWorkerOnMainThread(aData);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        self->CreationFailedOnAnyThread();
+      }
+  });
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+nsresult
+RemoteWorkerChild::ExecWorkerOnMainThread(const RemoteWorkerData& aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Ensure that the IndexedDatabaseManager is initialized
+  Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
+
+  nsresult rv = NS_OK;
+
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = PopulatePrincipalContentSecurityPolicy(principal,
+                                              aData.principalCsp(),
+                                              aData.principalPreloadCsp());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIPrincipal> loadingPrincipal =
+    PrincipalInfoToPrincipal(aData.loadingPrincipalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = PopulatePrincipalContentSecurityPolicy(loadingPrincipal,
+                                              aData.loadingPrincipalCsp(),
+                                              aData.loadingPrincipalPreloadCsp());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  WorkerLoadInfo info;
+  rv = NS_NewURI(getter_AddRefs(info.mBaseURI), aData.baseScriptURL(),
+                 nullptr, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = NS_NewURI(getter_AddRefs(info.mResolvedScriptURI),
+                 aData.resolvedScriptURL(), nullptr, info.mBaseURI);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  info.mPrincipalInfo = new PrincipalInfo(aData.principalInfo());
+
+  info.mDomain = aData.domain();
+  info.mPrincipal = principal;
+  info.mLoadingPrincipal = loadingPrincipal;
+
+  nsContentUtils::StorageAccess access =
+    nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
+  info.mStorageAllowed =
+    access > nsContentUtils::StorageAccess::ePrivateBrowsing;
+  info.mOriginAttributes =
+    BasePrincipal::Cast(principal)->OriginAttributesRef();
+
+  // Default CSP permissions for now.  These will be overrided if necessary
+  // based on the script CSP headers during load in ScriptLoader.
+  info.mEvalAllowed = true;
+  info.mReportCSPViolations = false;
+  info.mSecureContext = aData.isSecureContext()
+    ? WorkerLoadInfo::eSecureContext : WorkerLoadInfo::eInsecureContext;
+
+  WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mLoadingPrincipal);
+
+  RefPtr<SharedWorkerInterfaceRequestor> requestor =
+    new SharedWorkerInterfaceRequestor();
+  info.mInterfaceRequestor->SetOuterRequestor(requestor);
+
+  rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  Maybe<ClientInfo> clientInfo;
+  if (aData.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
+    clientInfo.emplace(ClientInfo(aData.clientInfo().get_IPCClientInfo()));
+  }
+
+  // Top level workers' main script use the document charset for the script
+  // uri encoding.
+  rv = ChannelFromScriptURLMainThread(info.mLoadingPrincipal,
+                                      info.mBaseURI,
+                                      nullptr /* parent document */,
+                                      info.mLoadGroup,
+                                      aData.originalScriptURL(),
+                                      clientInfo,
+                                      aData.isSharedWorker()
+                                        ? nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
+                                        : nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER,
+                                      false /* default encoding */,
+                                      getter_AddRefs(info.mChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+
+  ErrorResult error;
+  mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
+                                              aData.originalScriptURL(),
+                                              false,
+                                              aData.isSharedWorker()
+                                                ? WorkerTypeShared
+                                                : WorkerTypeService,
+                                              aData.name(),
+                                              VoidCString(),
+                                              &info, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.StealNSResult();
+  }
+
+  RefPtr<InitializeWorkerRunnable> runnable =
+    new InitializeWorkerRunnable(mWorkerPrivate, this);
+  if (NS_WARN_IF(!runnable->Dispatch())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mWorkerPrivate->SetRemoteWorkerController(this);
+  return NS_OK;
+}
+
+void
+RemoteWorkerChild::InitializeOnWorker(WorkerPrivate* aWorkerPrivate)
+{
+  MOZ_ASSERT(aWorkerPrivate);
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  RefPtr<RemoteWorkerChild> self = this;
+  mWorkerRef = WeakWorkerRef::Create(mWorkerPrivate, [self]() {
+      self->ShutdownOnWorker();
+    });
+
+  if (NS_WARN_IF(!mWorkerRef)) {
+    CreationFailedOnAnyThread();
+    ShutdownOnWorker();
+    return;
+  }
+
+  CreationSucceededOnAnyThread();
+}
+
+void
+RemoteWorkerChild::ShutdownOnWorker()
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+
+  // This will release the worker.
+  mWorkerRef = nullptr;
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+
+  NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
+                  target, mWorkerPrivate.forget());
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ShutdownOnWorker",
+                           [self]() {
+      self->WorkerTerminated();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::WorkerTerminated()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  mWorkerState = eTerminated;
+  mPendingOps.Clear();
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendClose();
+  mIPCActive = false;
+}
+
+void
+RemoteWorkerChild::ErrorPropagationDispatch(nsresult aError)
+{
+  MOZ_ASSERT(NS_FAILED(aError));
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationDispatch",
+                           [self, aError]() {
+      self->ErrorPropagation(aError);
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
+                                                bool aIsErrorEvent)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ErrorValue value;
+  if (aIsErrorEvent) {
+    nsTArray<ErrorDataNote> notes;
+    for (size_t i = 0, len = aReport->mNotes.Length(); i < len; i++) {
+      const WorkerErrorNote& note = aReport->mNotes.ElementAt(i);
+      notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
+                                        note.mMessage, note.mFilename));
+    }
 
-RemoteWorkerChild::~RemoteWorkerChild() = default;
+    ErrorData data(aReport->mLineNumber,
+                   aReport->mColumnNumber,
+                   aReport->mFlags,
+                   aReport->mMessage,
+                   aReport->mFilename,
+                   aReport->mLine,
+                   notes);
+    value = data;
+  } else {
+    value = void_t();
+  }
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationOnMainThread",
+                           [self, value]() {
+    self->ErrorPropagation(value);
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::ErrorPropagation(const ErrorValue& aValue)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendError(aValue);
+}
+
+void
+RemoteWorkerChild::CloseWorkerOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mWorkerState == ePending) {
+    mWorkerState = ePendingTerminated;
+    // Already released.
+    return;
+  }
+
+  // The holder will be notified by this.
+  if (mWorkerState == eRunning) {
+    MOZ_ASSERT(mWorkerPrivate);
+    mWorkerPrivate->Cancel();
+  }
+}
+
+void
+RemoteWorkerChild::FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  bool reportErrorToBrowserConsole = true;
+
+  // Flush the reports.
+  for (uint32_t i = 0, len = mWindowIDs.Length(); i < len; ++i) {
+    aReporter->FlushReportsToConsole(mWindowIDs[i],
+      nsIConsoleReportCollector::ReportAction::Save);
+    reportErrorToBrowserConsole = false;
+  }
+
+  // Finally report to browser console if there is no any window.
+  if (reportErrorToBrowserConsole) {
+    aReporter->FlushReportsToConsole(0);
+    return;
+  }
+
+  aReporter->ClearConsoleReports();
+}
+
+IPCResult
+RemoteWorkerChild::RecvExecOp(const RemoteWorkerOp& aOp)
+{
+  if (!mIPCActive) {
+    return IPC_OK();
+  }
+
+  // The worker is not ready yet.
+  if (mWorkerState == ePending) {
+    mPendingOps.AppendElement(aOp);
+    return IPC_OK();
+  }
+
+  if (mWorkerState == eTerminated || mWorkerState == ePendingTerminated) {
+    // No op.
+    return IPC_OK();
+  }
+
+  MOZ_ASSERT(mWorkerState == eRunning);
+
+  // Main-thread operations
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
+    RefPtr<RemoteWorkerChild> self = this;
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableFunction("RemoteWorkerChild::RecvExecOp",
+                             [self, aOp]() {
+        self->RecvExecOpOnMainThread(aOp);
+    });
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+    target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+    return IPC_OK();
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
+    const RemoteWorkerPortIdentifierOp& op =
+      aOp.get_RemoteWorkerPortIdentifierOp();
+    RefPtr<MessagePortIdentifierRunnable> runnable =
+      new MessagePortIdentifierRunnable(mWorkerPrivate, this,
+                                        op.portIdentifier());
+    if (NS_WARN_IF(!runnable->Dispatch())) {
+      ErrorPropagation(NS_ERROR_FAILURE);
+    }
+    return IPC_OK();
+  }
+
+  MOZ_CRASH("Unknown operation.");
+
+  return IPC_OK();
+}
+
+void
+RemoteWorkerChild::RecvExecOpOnMainThread(const RemoteWorkerOp& aOp)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->ParentWindowPaused();
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->ParentWindowResumed();
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->Freeze(nullptr);
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->Thaw(nullptr);
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp) {
+    CloseWorkerOnMainThread();
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
+    mWindowIDs.AppendElement(aOp.get_RemoteWorkerAddWindowIDOp().windowID());
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
+    mWindowIDs.RemoveElement(aOp.get_RemoteWorkerRemoveWindowIDOp().windowID());
+    return;
+  }
+
+  MOZ_CRASH("No other operations should be scheduled on main-thread.");
+}
+
+void
+RemoteWorkerChild::AddPortIdentifier(JSContext* aCx,
+                                     WorkerPrivate* aWorkerPrivate,
+                                     const MessagePortIdentifier& aPortIdentifier)
+{
+  if (NS_WARN_IF(!aWorkerPrivate->ConnectMessagePort(aCx, aPortIdentifier))) {
+    ErrorPropagationDispatch(NS_ERROR_FAILURE);
+  }
+}
+
+void
+RemoteWorkerChild::CreationSucceededOnAnyThread()
+{
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceededOnAnyThread",
+                           [self]() {
+    self->CreationSucceeded();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::CreationSucceeded()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  // The worker is created but we need to terminate it already.
+  if (mWorkerState == ePendingTerminated) {
+    RefPtr<RemoteWorkerChild> self = this;
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceeded",
+                             [self]() {
+        self->CloseWorkerOnMainThread();
+    });
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+    target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+    return;
+  }
+
+  mWorkerState = eRunning;
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  for (const RemoteWorkerOp& op : mPendingOps) {
+    RecvExecOp(op);
+  }
+
+  mPendingOps.Clear();
+
+  Unused << SendCreated(true);
+}
+
+void
+RemoteWorkerChild::CreationFailedOnAnyThread()
+{
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::CreationFailedOnAnyThread",
+                           [self]() {
+    self->CreationFailed();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::CreationFailed()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  mWorkerState = eTerminated;
+  mPendingOps.Clear();
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendCreated(false);
+}
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/remoteworkers/RemoteWorkerChild.h
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.h
@@ -3,23 +3,125 @@
 /* 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_RemoteWorkerChild_h
 #define mozilla_dom_RemoteWorkerChild_h
 
 #include "mozilla/dom/PRemoteWorkerChild.h"
+#include "mozilla/UniquePtr.h"
+#include "nsISupportsImpl.h"
+
+class nsIConsoleReportCollector;
 
 namespace mozilla {
 namespace dom {
 
+class RemoteWorkerData;
+class WeakWorkerRef;
+class WorkerErrorReport;
+class WorkerPrivate;
+class OptionalMessagePortIdentifier;
+
 class RemoteWorkerChild final : public PRemoteWorkerChild
 {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteWorkerChild)
+
   RemoteWorkerChild();
+
+  void
+  ExecWorker(const RemoteWorkerData& aData);
+
+  void
+  InitializeOnWorker(WorkerPrivate* aWorkerPrivate);
+
+  void
+  ShutdownOnWorker();
+
+  void
+  AddPortIdentifier(JSContext* aCx,
+                    WorkerPrivate* aWorkerPrivate,
+                    const MessagePortIdentifier& aPortIdentifier);
+
+  void
+  ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
+                               bool aIsErrorEvent);
+
+  void
+  CloseWorkerOnMainThread();
+
+  void
+  FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
+
+private:
+  class InitializeWorkerRunnable;
+
   ~RemoteWorkerChild();
+
+  void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  mozilla::ipc::IPCResult
+  RecvExecOp(const RemoteWorkerOp& aOp) override;
+
+  void
+  RecvExecOpOnMainThread(const RemoteWorkerOp& aOp);
+
+  nsresult
+  ExecWorkerOnMainThread(const RemoteWorkerData& aData);
+
+  void
+  ErrorPropagation(const ErrorValue& aValue);
+
+  void
+  ErrorPropagationDispatch(nsresult aError);
+
+  void
+  CreationSucceededOnAnyThread();
+
+  void
+  CreationSucceeded();
+
+  void
+  CreationFailedOnAnyThread();
+
+  void
+  CreationFailed();
+
+  void
+  WorkerTerminated();
+
+  // Touched on main-thread only.
+  nsTArray<uint64_t> mWindowIDs;
+
+  RefPtr<WorkerPrivate> mWorkerPrivate;
+  RefPtr<WeakWorkerRef> mWorkerRef;
+  bool mIPCActive;
+
+  enum WorkerState
+  {
+    // CreationSucceeded/CreationFailed not called yet.
+    ePending,
+
+    // The worker is not created yet, but we want to terminate as soon as
+    // possible.
+    ePendingTerminated,
+
+    // Worker up and running.
+    eRunning,
+
+    // Worker terminated.
+    eTerminated,
+  };
+
+  // Touched only on the owning thread (PBackground).
+  WorkerState mWorkerState;
+
+  // Touched only on the owning thread (PBackground).
+  nsTArray<RemoteWorkerOp> mPendingOps;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_RemoteWorkerChild_h
--- a/dom/workers/remoteworkers/RemoteWorkerController.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerController.cpp
@@ -1,39 +1,39 @@
 /* -*- 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 "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/MessagePortParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "RemoteWorkerController.h"
 #include "RemoteWorkerManager.h"
+#include "RemoteWorkerParent.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 /* static */ already_AddRefed<RemoteWorkerController>
-RemoteWorkerController::Create()
+RemoteWorkerController::Create(const RemoteWorkerData& aData)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(XRE_IsParentProcess());
 
   RefPtr<RemoteWorkerController> controller = new RemoteWorkerController();
 
-  // This will be populated, eventually.
-  RemoteWorkerData data;
-
   RefPtr<RemoteWorkerManager> manager = RemoteWorkerManager::GetOrCreate();
   MOZ_ASSERT(manager);
 
-  manager->Launch(controller, data);
+  manager->Launch(controller, aData);
 
   return controller.forget();
 }
 
 RemoteWorkerController::RemoteWorkerController()
   : mState(ePending)
 {
   AssertIsOnBackgroundThread();
@@ -57,28 +57,278 @@ RemoteWorkerController::SetWorkerActor(R
   mActor = aActor;
 }
 
 void
 RemoteWorkerController::CreationFailed()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(XRE_IsParentProcess());
-  MOZ_ASSERT(mActor);
+  MOZ_ASSERT(mState == ePending || mState == eTerminated);
 
-  mState = eTerminated;
-  mActor = nullptr;
+  // TODO: maybe notification?
+
+  Shutdown();
 }
 
 void
 RemoteWorkerController::CreationSucceeded()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == ePending || mState == eTerminated);
+
+  if (mState == eTerminated) {
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mPendingOps.IsEmpty());
+    // Nothing to do.
+    return;
+  }
+
   MOZ_ASSERT(mActor);
-
   mState = eReady;
 
-  // TODO: flush the pending op queue.
+  // TODO: maybe notification?
+
+  for (UniquePtr<Op>& op : mPendingOps) {
+    switch (op->mType) {
+      case Op::eTerminate:
+        Terminate();
+        break;
+
+      case Op::eSuspend:
+        Suspend();
+        break;
+
+      case Op::eResume:
+        Resume();
+        break;
+
+      case Op::eFreeze:
+        Freeze();
+        break;
+
+      case Op::eThaw:
+        Thaw();
+        break;
+
+      case Op::ePortIdentifier:
+        AddPortIdentifier(op->mPortIdentifier);
+        break;
+
+      case Op::eAddWindowID:
+        AddWindowID(op->mWindowID);
+        break;
+
+      case Op::eRemoveWindowID:
+        RemoveWindowID(op->mWindowID);
+        break;
+
+      default:
+        MOZ_CRASH("Unknown op.");
+    }
+
+    op->Completed();
+  }
+
+  mPendingOps.Clear();
+}
+
+void
+RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  // TODO: error propagation
+}
+
+void
+RemoteWorkerController::WorkerTerminated()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == eReady);
+
+  // TODO: worker terminated
+  Shutdown();
+}
+
+void
+RemoteWorkerController::Shutdown()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == ePending || mState == eReady);
+
+  mState = eTerminated;
+
+  mPendingOps.Clear();
+
+  if (mActor) {
+    mActor->SetController(nullptr);
+    Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
+    mActor = nullptr;
+  }
+}
+
+void
+RemoteWorkerController::AddWindowID(uint64_t aWindowID)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aWindowID);
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eAddWindowID, aWindowID));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerAddWindowIDOp(aWindowID));
+}
+
+void
+RemoteWorkerController::RemoveWindowID(uint64_t aWindowID)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aWindowID);
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eRemoveWindowID, aWindowID));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerRemoveWindowIDOp(aWindowID));
+}
+
+void
+RemoteWorkerController::AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(aPortIdentifier));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerPortIdentifierOp(aPortIdentifier));
+}
+
+void
+RemoteWorkerController::Terminate()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  Shutdown();
+}
+
+void
+RemoteWorkerController::Suspend()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eSuspend));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerSuspendOp());
+}
+
+void
+RemoteWorkerController::Resume()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eResume));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerResumeOp());
+}
+
+void
+RemoteWorkerController::Freeze()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eFreeze));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerFreezeOp());
+}
+
+void
+RemoteWorkerController::Thaw()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eThaw));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerThawOp());
+}
+
+RemoteWorkerController::Op::~Op()
+{
+  MOZ_COUNT_DTOR(Op);
+
+  // We don't want to leak the port if the operation has not been processed.
+  if (!mCompleted && mType == ePortIdentifier) {
+    MessagePortParent::ForceClose(mPortIdentifier.uuid(),
+                                  mPortIdentifier.destinationUuid(),
+                                  mPortIdentifier.sequenceId());
+  }
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/remoteworkers/RemoteWorkerController.h
+++ b/dom/workers/remoteworkers/RemoteWorkerController.h
@@ -73,48 +73,132 @@ namespace dom {
  * 7. RemoteWorkerChild is created on a selected process and it executes the
  *    WorkerPrivate.
  * 8. The RemoteWorkerParent actor is passed to the RemoteWorkerController.
  * 9. RemoteWorkerController now is ready to continue and it called
  *    RemoteWorkerObserver to inform that the operation is completed.
  *    In case there were pending operations, they are now executed.
  */
 
+class ErrorValue;
+class MessagePortIdentifier;
 class RemoteWorkerManager;
 class RemoteWorkerParent;
 
 class RemoteWorkerController final
 {
   friend class RemoteWorkerManager;
   friend class RemoteWorkerParent;
 
 public:
   NS_INLINE_DECL_REFCOUNTING(RemoteWorkerController)
 
   static already_AddRefed<RemoteWorkerController>
-  Create(); // TODO parameters?
+  Create(const RemoteWorkerData& aData);
+
+  void
+  AddWindowID(uint64_t aWindowID);
+
+  void
+  RemoveWindowID(uint64_t aWindowID);
+
+  void
+  AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier);
+
+  void
+  Terminate();
+
+  void
+  Suspend();
+
+  void
+  Resume();
+
+  void
+  Freeze();
+
+  void
+  Thaw();
 
 private:
   RemoteWorkerController();
   ~RemoteWorkerController();
 
   void
   SetWorkerActor(RemoteWorkerParent* aActor);
 
   void
+  ErrorPropagation(const ErrorValue& aValue);
+
+  void
+  WorkerTerminated();
+
+  void
+  Shutdown();
+
+  void
   CreationFailed();
 
   void
   CreationSucceeded();
 
   enum {
     ePending,
     eReady,
     eTerminated,
   } mState;
 
   RefPtr<RemoteWorkerParent> mActor;
+
+  struct Op {
+    enum Type {
+      eTerminate,
+      eSuspend,
+      eResume,
+      eFreeze,
+      eThaw,
+      ePortIdentifier,
+      eAddWindowID,
+      eRemoveWindowID,
+    };
+
+    explicit Op(Type aType, uint64_t aWindowID = 0)
+      : mType(aType)
+      , mWindowID(aWindowID)
+      , mCompleted(false)
+    {
+       MOZ_COUNT_CTOR(Op);
+    }
+
+    explicit Op(const MessagePortIdentifier& aPortIdentifier)
+      : mType(ePortIdentifier)
+      , mPortIdentifier(aPortIdentifier)
+      , mCompleted(false)
+    {
+       MOZ_COUNT_CTOR(Op);
+    }
+
+    // This object cannot be copied.
+    Op(Op const&) = delete;
+    Op& operator=(Op const&) = delete;
+
+    ~Op();
+
+    void
+    Completed()
+    {
+      mCompleted = true;
+    }
+
+    Type mType;
+
+    MessagePortIdentifier mPortIdentifier;
+    uint64_t mWindowID;
+    bool mCompleted;
+  };
+
+  nsTArray<UniquePtr<Op>> mPendingOps;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_RemoteWorkerController_h
--- a/dom/workers/remoteworkers/RemoteWorkerParent.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.cpp
@@ -2,16 +2,17 @@
 /* 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 "RemoteWorkerParent.h"
 #include "RemoteWorkerController.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/Unused.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 RemoteWorkerParent::RemoteWorkerParent()
@@ -49,16 +50,43 @@ RemoteWorkerParent::RecvCreated(const bo
     mController->CreationSucceeded();
   } else {
     mController->CreationFailed();
   }
 
   return IPC_OK();
 }
 
+IPCResult
+RemoteWorkerParent::RecvError(const ErrorValue& aValue)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mController) {
+    mController->ErrorPropagation(aValue);
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+RemoteWorkerParent::RecvClose()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mController) {
+    mController->WorkerTerminated();
+  }
+
+  Unused << Send__delete__(this);
+  return IPC_OK();
+}
+
 void
 RemoteWorkerParent::SetController(RemoteWorkerController* aController)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(XRE_IsParentProcess());
 
   mController = aController;
 }
--- a/dom/workers/remoteworkers/RemoteWorkerParent.h
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.h
@@ -26,16 +26,22 @@ public:
 
 private:
   ~RemoteWorkerParent();
 
   void
   ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
 
   mozilla::ipc::IPCResult
+  RecvError(const ErrorValue& aValue) override;
+
+  mozilla::ipc::IPCResult
+  RecvClose() override;
+
+  mozilla::ipc::IPCResult
   RecvCreated(const bool& aStatus) override;
 
   RefPtr<RemoteWorkerController> mController;
 };
 
 } // dom namespace
 } // mozilla namespace
 
--- a/dom/workers/remoteworkers/RemoteWorkerService.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerService.cpp
@@ -64,16 +64,25 @@ RemoteWorkerService::Initialize()
   nsresult rv = obs->AddObserver(service, "profile-after-change", false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   sRemoteWorkerService = service;
 }
 
+/* static */ nsIThread*
+RemoteWorkerService::Thread()
+{
+  StaticMutexAutoLock lock(sRemoteWorkerServiceMutex);
+  MOZ_ASSERT(sRemoteWorkerService);
+  MOZ_ASSERT(sRemoteWorkerService->mThread);
+  return sRemoteWorkerService->mThread;
+}
+
 nsresult
 RemoteWorkerService::InitializeOnMainThread()
 {
   // I would like to call this thread "DOM Remote Worker Launcher", but the max
   // length is 16 chars.
   nsresult rv = NS_NewNamedThread("Worker Launcher",
                                   getter_AddRefs(mThread));
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/workers/remoteworkers/RemoteWorkerService.h
+++ b/dom/workers/remoteworkers/RemoteWorkerService.h
@@ -22,16 +22,19 @@ class RemoteWorkerService final : public
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // To be called when a process is initialized on main-thread.
   static void
   Initialize();
 
+  static nsIThread*
+  Thread();
+
 private:
   RemoteWorkerService();
   ~RemoteWorkerService();
 
   nsresult
   InitializeOnMainThread();
 
   void
--- a/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh
+++ b/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh
@@ -1,13 +1,75 @@
 /* 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 ClientIPCTypes;
+include PBackgroundSharedTypes;
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
 namespace mozilla {
 namespace dom {
 
+struct ContentSecurityPolicy
+{
+  nsString policy;
+  bool reportOnlyFlag;
+  bool deliveredViaMetaTagFlag;
+};
+
 struct RemoteWorkerData
 {
+  nsString originalScriptURL;
+  nsCString baseScriptURL;
+  nsCString resolvedScriptURL;
+
+  nsString name;
+
+  PrincipalInfo loadingPrincipalInfo;
+  ContentSecurityPolicy[] loadingPrincipalCsp;
+  ContentSecurityPolicy[] loadingPrincipalPreloadCsp;
+
+  PrincipalInfo principalInfo;
+  ContentSecurityPolicy[] principalCsp;
+  ContentSecurityPolicy[] principalPreloadCsp;
+
+  nsCString domain;
+
+  bool isSecureContext;
+
+  OptionalIPCClientInfo clientInfo;
+
+  bool isSharedWorker;
+};
+
+// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
+// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
+// report complicated errors such as redeclarations that involve multiple
+// distinct lines.  For more generic error-propagation IPC structures, see bug
+// 1357463 on making ErrorResult usable over IPC.
+
+struct ErrorDataNote {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  nsString message;
+  nsString filename;
+};
+
+struct ErrorData {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  uint32_t flags;
+  nsString message;
+  nsString filename;
+  nsString line;
+  ErrorDataNote[] notes;
+};
+
+union ErrorValue {
+  nsresult;
+  ErrorData;
+  void_t;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/PSharedWorker.ipdl
+++ b/dom/workers/sharedworkers/PSharedWorker.ipdl
@@ -1,15 +1,15 @@
 /* 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 protocol PBackground;
 
-include SharedWorkerTypes;
+include RemoteWorkerTypes;
 
 namespace mozilla {
 namespace dom {
 
 protocol PSharedWorker
 {
   manager PBackground;
 
--- a/dom/workers/sharedworkers/SharedWorker.cpp
+++ b/dom/workers/sharedworkers/SharedWorker.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/PMessagePort.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/dom/SharedWorkerBinding.h"
 #include "mozilla/dom/SharedWorkerChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerLoadInfo.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
@@ -242,34 +243,35 @@ SharedWorker::Constructor(const GlobalOb
   OptionalIPCClientInfo ipcClientInfo;
   Maybe<ClientInfo> clientInfo = window->GetClientInfo();
   if (clientInfo.isSome()) {
     ipcClientInfo = clientInfo.value().ToIPC();
   } else {
     ipcClientInfo = void_t();
   }
 
-  SharedWorkerLoadInfo sharedWorkerLoadInfo(nsString(aScriptURL),
-                                            baseURL,
-                                            resolvedScriptURL,
-                                            name,
-                                            loadingPrincipalInfo,
-                                            loadingPrincipalCSP,
-                                            loadingPrincipalPreloadCSP,
-                                            principalInfo,
-                                            principalCSP,
-                                            principalPreloadCSP,
-                                            loadInfo.mDomain,
-                                            isSecureContext,
-                                            loadInfo.mWindowID,
-                                            ipcClientInfo,
-                                            portIdentifier);
+  RemoteWorkerData remoteWorkerData(nsString(aScriptURL),
+                                    baseURL,
+                                    resolvedScriptURL,
+                                    name,
+                                    loadingPrincipalInfo,
+                                    loadingPrincipalCSP,
+                                    loadingPrincipalPreloadCSP,
+                                    principalInfo,
+                                    principalCSP,
+                                    principalPreloadCSP,
+                                    loadInfo.mDomain,
+                                    isSecureContext,
+                                    ipcClientInfo,
+                                    true /* sharedWorker */);
 
   PSharedWorkerChild* pActor =
-    actorChild->SendPSharedWorkerConstructor(sharedWorkerLoadInfo);
+    actorChild->SendPSharedWorkerConstructor(remoteWorkerData,
+                                             loadInfo.mWindowID,
+                                             portIdentifier);
 
   RefPtr<SharedWorkerChild> actor = static_cast<SharedWorkerChild*>(pActor);
   MOZ_ASSERT(actor);
 
   RefPtr<SharedWorker> sharedWorker = new SharedWorker(window, actor,
                                                        channel->Port2());
 
   // Let's inform the window about this SharedWorker.
--- a/dom/workers/sharedworkers/SharedWorkerManager.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp
@@ -2,435 +2,198 @@
 /* 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 "SharedWorkerManager.h"
 #include "SharedWorkerParent.h"
 #include "SharedWorkerService.h"
-#include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/PSharedWorker.h"
-#include "mozilla/dom/ServiceWorkerInterceptController.h"
-#include "mozilla/dom/WorkerError.h"
-#include "mozilla/dom/WorkerPrivate.h"
-#include "mozilla/dom/WorkerRunnable.h"
-#include "mozilla/dom/workerinternals/ScriptLoader.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/dom/RemoteWorkerController.h"
 #include "nsIConsoleReportCollector.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPrincipal.h"
-#include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
-using workerinternals::ChannelFromScriptURLMainThread;
-
-namespace {
-
-class MessagePortRunnable final : public WorkerRunnable
-{
-  MessagePortIdentifier mPortIdentifier;
-
-public:
-  MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
-                      const MessagePortIdentifier& aPortIdentifier)
-    : WorkerRunnable(aWorkerPrivate)
-    , mPortIdentifier(aPortIdentifier)
-  {}
-
-private:
-  ~MessagePortRunnable() = default;
-
-  virtual bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
-  }
-
-  nsresult
-  Cancel() override
-  {
-    MessagePort::ForceClose(mPortIdentifier);
-    return WorkerRunnable::Cancel();
-  }
-};
-
-class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  SharedWorkerInterfaceRequestor()
-    : mSWController(new ServiceWorkerInterceptController())
-  {}
-
-  NS_IMETHOD
-  GetInterface(const nsIID& aIID, void** aSink) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
-      // If asked for the network intercept controller, ask the outer requestor,
-      // which could be the docshell.
-      RefPtr<ServiceWorkerInterceptController> swController = mSWController;
-      swController.forget(aSink);
-      return NS_OK;
-    }
-
-    return NS_NOINTERFACE;
-  }
-
-private:
-  ~SharedWorkerInterfaceRequestor() = default;
-
-  RefPtr<ServiceWorkerInterceptController> mSWController;
-};
-
-NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
-NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
-NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
-
-} // anonymous
-
 SharedWorkerManager::SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
-                                         const SharedWorkerLoadInfo& aInfo,
-                                         nsIPrincipal* aPrincipal,
+                                         const RemoteWorkerData& aData,
                                          nsIPrincipal* aLoadingPrincipal)
   : mPBackgroundEventTarget(aPBackgroundEventTarget)
-  , mInfo(aInfo)
-  , mPrincipal(aPrincipal)
   , mLoadingPrincipal(aLoadingPrincipal)
+  , mDomain(aData.domain())
+  , mResolvedScriptURL(aData.resolvedScriptURL())
+  , mName(aData.name())
+  , mIsSecureContext(aData.isSecureContext())
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aLoadingPrincipal);
 }
 
 SharedWorkerManager::~SharedWorkerManager()
 {
   nsCOMPtr<nsIEventTarget> target =
     SystemGroup::EventTargetFor(TaskCategory::Other);
 
-  NS_ProxyRelease("SharedWorkerManager::mPrincipal",
-                  target, mPrincipal.forget());
   NS_ProxyRelease("SharedWorkerManager::mLoadingPrincipal",
                   target, mLoadingPrincipal.forget());
-  NS_ProxyRelease("SharedWorkerManager::mWorkerPrivate",
-                  target, mWorkerPrivate.forget());
+  NS_ProxyRelease("SharedWorkerManager::mRemoteWorkerController",
+                  mPBackgroundEventTarget, mRemoteWorkerController.forget());
 }
 
-nsresult
-SharedWorkerManager::CreateWorkerOnMainThread()
+bool
+SharedWorkerManager::MaybeCreateRemoteWorker(const RemoteWorkerData& aData,
+                                             uint64_t aWindowID,
+                                             const MessagePortIdentifier& aPortIdentifier)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Ensure that the IndexedDatabaseManager is initialized
-  Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
+  AssertIsOnBackgroundThread();
 
-  WorkerLoadInfo info;
-  nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI),
-                          mInfo.baseScriptURL(),
-                          nullptr, nullptr);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = NS_NewURI(getter_AddRefs(info.mResolvedScriptURI),
-                 mInfo.resolvedScriptURL(), nullptr, info.mBaseURI);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  info.mPrincipalInfo = new PrincipalInfo();
-  rv = PrincipalToPrincipalInfo(mPrincipal, info.mPrincipalInfo);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  if (!mRemoteWorkerController) {
+    mRemoteWorkerController = RemoteWorkerController::Create(aData);
+    if (NS_WARN_IF(!mRemoteWorkerController)) {
+      return false;
+    }
   }
 
-  info.mResolvedScriptURI = info.mBaseURI;
-
-  info.mDomain = mInfo.domain();
-  info.mPrincipal = mPrincipal;
-  info.mLoadingPrincipal = mLoadingPrincipal;
-
-  nsContentUtils::StorageAccess access =
-    nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
-  info.mStorageAllowed =
-    access > nsContentUtils::StorageAccess::ePrivateBrowsing;
-  info.mOriginAttributes =
-    BasePrincipal::Cast(mPrincipal)->OriginAttributesRef();
-
-  // Default CSP permissions for now.  These will be overrided if necessary
-  // based on the script CSP headers during load in ScriptLoader.
-  info.mEvalAllowed = true;
-  info.mReportCSPViolations = false;
-  info.mSecureContext = mInfo.isSecureContext()
-    ? WorkerLoadInfo::eSecureContext : WorkerLoadInfo::eInsecureContext;
-
-  WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mLoadingPrincipal);
-
-  RefPtr<SharedWorkerInterfaceRequestor> requestor =
-    new SharedWorkerInterfaceRequestor();
-  info.mInterfaceRequestor->SetOuterRequestor(requestor);
-
-  rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  Maybe<ClientInfo> clientInfo;
-  if (mInfo.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
-    clientInfo.emplace(ClientInfo(mInfo.clientInfo().get_IPCClientInfo()));
+  if (aWindowID) {
+    mRemoteWorkerController->AddWindowID(aWindowID);
   }
 
-  // Top level workers' main script use the document charset for the script
-  // uri encoding.
-  rv = ChannelFromScriptURLMainThread(info.mLoadingPrincipal,
-                                      info.mBaseURI,
-                                      nullptr /* parent document */,
-                                      info.mLoadGroup,
-                                      mInfo.originalScriptURL(),
-                                      clientInfo,
-                                      nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER,
-                                      false /* default encoding */,
-                                      getter_AddRefs(info.mChannel));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  AutoJSAPI jsapi;
-  jsapi.Init();
-
-  ErrorResult error;
-  mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
-                                              mInfo.originalScriptURL(),
-                                              false,
-                                              WorkerTypeShared,
-                                              mInfo.name(),
-                                              VoidCString(),
-                                              &info, error);
-  if (NS_WARN_IF(error.Failed())) {
-    return error.StealNSResult();
-  }
-
-  mWorkerPrivate->SetSharedWorkerManager(this);
-  return NS_OK;
-}
-
-nsresult
-SharedWorkerManager::ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  RefPtr<MessagePortRunnable> runnable =
-    new MessagePortRunnable(mWorkerPrivate, aPortIdentifier);
-  if (NS_WARN_IF(!runnable->Dispatch())) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
+  mRemoteWorkerController->AddPortIdentifier(aPortIdentifier);
+  return true;
 }
 
 bool
 SharedWorkerManager::MatchOnMainThread(const nsACString& aDomain,
                                        const nsACString& aScriptURL,
                                        const nsAString& aName,
                                        nsIPrincipal* aLoadingPrincipal) const
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return aDomain == mInfo.domain() &&
-         aScriptURL == mInfo.resolvedScriptURL() &&
-         aName == mInfo.name() &&
+  return aDomain == mDomain &&
+         aScriptURL == mResolvedScriptURL &&
+         aName == mName &&
          // We want to be sure that the window's principal subsumes the
          // SharedWorker's loading principal and vice versa.
          mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
          aLoadingPrincipal->Subsumes(mLoadingPrincipal);
 }
 
 void
 SharedWorkerManager::AddActor(SharedWorkerParent* aParent)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(!mActors.Contains(aParent));
 
+  uint32_t frozen = 0;
+
+  for (SharedWorkerParent* actor : mActors) {
+    if (actor->IsFrozen()) {
+      ++frozen;
+    }
+  }
+
+  bool hadActors = !mActors.IsEmpty();
+
   mActors.AppendElement(aParent);
+
+  if (hadActors && frozen == mActors.Length() - 1) {
+    mRemoteWorkerController->Thaw();
+  }
 }
 
 void
 SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(mActors.Contains(aParent));
 
+  uint64_t windowID = aParent->WindowID();
+  if (windowID) {
+    mRemoteWorkerController->RemoveWindowID(windowID);
+  }
+
   mActors.RemoveElement(aParent);
 
   if (!mActors.IsEmpty()) {
     return;
   }
 
   // Time to go.
 
-  RefPtr<SharedWorkerManager> self = this;
-  nsCOMPtr<nsIRunnable> r =
-    NS_NewRunnableFunction("SharedWorkerManager::RemoveActor",
-                           [self]() {
-    self->CloseOnMainThread();
-  });
-
-  nsCOMPtr<nsIEventTarget> target =
-    SystemGroup::EventTargetFor(TaskCategory::Other);
-  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+  mRemoteWorkerController->Terminate();
+  mRemoteWorkerController = nullptr;
 
   // SharedWorkerService exists because it is kept alive by SharedWorkerParent.
   SharedWorkerService::Get()->RemoveWorkerManager(this);
 }
 
 void
 SharedWorkerManager::UpdateSuspend()
 {
   AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mRemoteWorkerController);
 
   uint32_t suspended = 0;
 
   for (SharedWorkerParent* actor : mActors) {
     if (actor->IsSuspended()) {
       ++suspended;
     }
   }
 
   if (suspended != 0 && suspended != mActors.Length()) {
     return;
   }
 
-  RefPtr<SharedWorkerManager> self = this;
-  nsCOMPtr<nsIRunnable> r =
-    NS_NewRunnableFunction("SharedWorkerManager::UpdateSuspend",
-                           [self, suspended]() {
-    if (suspended) {
-      self->SuspendOnMainThread();
-    } else {
-      self->ResumeOnMainThread();
-    }
-  });
-
-  nsCOMPtr<nsIEventTarget> target =
-    SystemGroup::EventTargetFor(TaskCategory::Other);
-  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+  if (suspended) {
+    mRemoteWorkerController->Suspend();
+  } else {
+    mRemoteWorkerController->Resume();
+  }
 }
 
 void
 SharedWorkerManager::UpdateFrozen()
 {
   AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mRemoteWorkerController);
 
   uint32_t frozen = 0;
 
   for (SharedWorkerParent* actor : mActors) {
     if (actor->IsFrozen()) {
       ++frozen;
     }
   }
 
   if (frozen != 0 && frozen != mActors.Length()) {
     return;
   }
 
-  RefPtr<SharedWorkerManager> self = this;
-  nsCOMPtr<nsIRunnable> r =
-    NS_NewRunnableFunction("SharedWorkerManager::UpdateFrozen",
-                           [self, frozen]() {
-    if (frozen) {
-      self->FreezeOnMainThread();
-    } else {
-      self->ThawOnMainThread();
-    }
-  });
-
-  nsCOMPtr<nsIEventTarget> target =
-    SystemGroup::EventTargetFor(TaskCategory::Other);
-  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+  if (frozen) {
+    mRemoteWorkerController->Freeze();
+  } else {
+    mRemoteWorkerController->Thaw();
+  }
 }
 
 bool
 SharedWorkerManager::IsSecureContext() const
 {
-  return mInfo.isSecureContext();
-}
-
-void
-SharedWorkerManager::FreezeOnMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!mWorkerPrivate || mWorkerPrivate->IsFrozen()) {
-    // Already released.
-    return;
-  }
-
-  mWorkerPrivate->Freeze(nullptr);
-}
-
-void
-SharedWorkerManager::ThawOnMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!mWorkerPrivate || !mWorkerPrivate->IsFrozen()) {
-    // Already released.
-    return;
-  }
-
-  mWorkerPrivate->Thaw(nullptr);
+  return mIsSecureContext;
 }
 
-void
-SharedWorkerManager::SuspendOnMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!mWorkerPrivate) {
-    // Already released.
-    return;
-  }
-
-  mWorkerPrivate->ParentWindowPaused();
-}
-
-void
-SharedWorkerManager::ResumeOnMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!mWorkerPrivate) {
-    // Already released.
-    return;
-  }
-
-  mWorkerPrivate->ParentWindowResumed();
-}
-
-void
-SharedWorkerManager::CloseOnMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!mWorkerPrivate) {
-    // Already released.
-    return;
-  }
-
-  mWorkerPrivate->Cancel();
-  mWorkerPrivate = nullptr;
-}
-
+/* TODO
 void
 SharedWorkerManager::BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
                                                         bool aIsErrorEvent)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ErrorValue value;
   if (aIsErrorEvent) {
@@ -525,11 +288,12 @@ SharedWorkerManager::FlushReportsToActor
   // worker.
   if (reportErrorToBrowserConsole) {
     aReporter->FlushReportsToConsole(0);
     return;
   }
 
   aReporter->ClearConsoleReports();
 }
+*/
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/sharedworkers/SharedWorkerManager.h
+++ b/dom/workers/sharedworkers/SharedWorkerManager.h
@@ -2,117 +2,81 @@
 /* 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_SharedWorkerManager_h
 #define mozilla_dom_SharedWorkerManager_h
 
-#include "mozilla/dom/SharedWorkerTypes.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 
-class nsIConsoleReportCollector;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
-class ErrorValue;
-class SharedWorkerLoadInfo;
+class MessagePortIdentifier;
+class RemoteWorkerData;
+class RemoteWorkerController;
 class SharedWorkerParent;
-class WorkerErrorReport;
-class WorkerPrivate;
 
 class SharedWorkerManager final
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManager);
 
   // Called on main-thread thread methods
 
   SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
-                      const SharedWorkerLoadInfo& aInfo,
-                      nsIPrincipal* aPrincipal,
+                      const RemoteWorkerData& aData,
                       nsIPrincipal* aLoadingPrincipal);
 
-  nsresult
-  CreateWorkerOnMainThread();
-
-  nsresult
-  ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier);
-
   bool
   MatchOnMainThread(const nsACString& aDomain,
                     const nsACString& aScriptURL,
                     const nsAString& aName,
                     nsIPrincipal* aLoadingPrincipal) const;
 
-  void
-  CloseOnMainThread();
-
-  void
-  FreezeOnMainThread();
-
-  void
-  ThawOnMainThread();
-
-  void
-  SuspendOnMainThread();
+  // Called on PBackground thread methods
 
-  void
-  ResumeOnMainThread();
-
-  void
-  BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
-                                     bool aIsErrorEvent);
-
-  void
-  CloseActorsOnMainThread();
-
-  void
-  FlushReportsToActorsOnMainThread(nsIConsoleReportCollector* aReporter);
-
-  // Called on PBackground thread methods
+  bool
+  MaybeCreateRemoteWorker(const RemoteWorkerData& aData,
+                          uint64_t aWindowID,
+                          const MessagePortIdentifier& aPortIdentifier);
 
   void
   AddActor(SharedWorkerParent* aParent);
 
   void
   RemoveActor(SharedWorkerParent* aParent);
 
   void
   UpdateSuspend();
 
   void
   UpdateFrozen();
 
   bool
   IsSecureContext() const;
 
-  void
-  CloseActors();
-
-  void
-  BroadcastErrorToActors(const ErrorValue& aValue);
-
 private:
   ~SharedWorkerManager();
 
   nsCOMPtr<nsIEventTarget> mPBackgroundEventTarget;
 
-  SharedWorkerLoadInfo mInfo;
-  nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
+  nsCString mDomain;
+  nsCString mResolvedScriptURL;
+  nsString mName;
+  bool mIsSecureContext;
 
   // Raw pointers because SharedWorkerParent unregisters itself in ActorDestroy().
   nsTArray<SharedWorkerParent*> mActors;
 
-  // With this patch, SharedWorker are executed on the parent process.
-  // This is going to change in the following parts.
-  RefPtr<WorkerPrivate> mWorkerPrivate;
+  RefPtr<RemoteWorkerController> mRemoteWorkerController;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_SharedWorkerManager_h
--- a/dom/workers/sharedworkers/SharedWorkerParent.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp
@@ -2,30 +2,30 @@
 /* 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 "SharedWorkerParent.h"
 #include "SharedWorkerManager.h"
 #include "SharedWorkerService.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 SharedWorkerParent::SharedWorkerParent()
   : mBackgroundEventTarget(GetCurrentThreadEventTarget())
   , mStatus(eInit)
-  , mWindowID(0)
   , mSuspended(false)
   , mFrozen(false)
 {
   AssertIsOnBackgroundThread();
 }
 
 SharedWorkerParent::~SharedWorkerParent() = default;
 
@@ -36,30 +36,31 @@ SharedWorkerParent::ActorDestroy(IProtoc
 
   if (mWorkerManager) {
     mWorkerManager->RemoveActor(this);
     mWorkerManager = nullptr;
   }
 }
 
 void
-SharedWorkerParent::Initialize(const SharedWorkerLoadInfo& aInfo)
+SharedWorkerParent::Initialize(const RemoteWorkerData& aData,
+                               uint64_t aWindowID,
+                               const MessagePortIdentifier& aPortIdentifier)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == eInit);
 
   // Let's keep the service alive.
   mService = SharedWorkerService::GetOrCreate();
   MOZ_ASSERT(mService);
 
-  // This is the only information we currently care.
-  mWindowID = aInfo.windowID();
+  mWindowID = aWindowID;
 
   mStatus = ePending;
-  mService->GetOrCreateWorkerManager(this, aInfo);
+  mService->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
 }
 
 IPCResult
 SharedWorkerParent::RecvClose()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
--- a/dom/workers/sharedworkers/SharedWorkerParent.h
+++ b/dom/workers/sharedworkers/SharedWorkerParent.h
@@ -9,29 +9,32 @@
 
 #include "mozilla/dom/PSharedWorkerParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
-class SharedWorkerLoadInfo;
+class MessagePortIdentifier;
+class RemoteWorkerData;
 class SharedWorkerManager;
 class SharedWorkerService;
 
 class SharedWorkerParent final : public mozilla::dom::PSharedWorkerParent
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerParent)
 
   SharedWorkerParent();
 
   void
-  Initialize(const SharedWorkerLoadInfo& aInfo);
+  Initialize(const RemoteWorkerData& aData,
+             uint64_t aWindowID,
+             const MessagePortIdentifier& aPortIdentifier);
 
   void
   ManagerCreated(SharedWorkerManager* aWorkerManager);
 
   void
   ErrorPropagation(nsresult aError);
 
   mozilla::ipc::IPCResult
--- a/dom/workers/sharedworkers/SharedWorkerService.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerService.cpp
@@ -1,15 +1,16 @@
 /* -*- 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 "SharedWorkerService.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/SystemGroup.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
@@ -70,40 +71,47 @@ PopulatePrincipalContentSecurityPolicy(n
 
   return NS_OK;
 }
 
 class GetOrCreateWorkerManagerRunnable final : public Runnable
 {
 public:
   GetOrCreateWorkerManagerRunnable(SharedWorkerParent* aActor,
-                                   const SharedWorkerLoadInfo& aInfo)
+                                   const RemoteWorkerData& aData,
+                                   uint64_t aWindowID,
+                                   const MessagePortIdentifier& aPortIdentifier)
     : Runnable("GetOrCreateWorkerManagerRunnable")
     , mBackgroundEventTarget(GetCurrentThreadEventTarget())
     , mActor(aActor)
-    , mInfo(aInfo)
+    , mData(aData)
+    , mWindowID(aWindowID)
+    , mPortIdentifier(aPortIdentifier)
   {}
 
   NS_IMETHOD
   Run()
   {
     // The service is always available because it's kept alive by the actor.
     SharedWorkerService* service = SharedWorkerService::Get();
     MOZ_ASSERT(service);
 
     service->GetOrCreateWorkerManagerOnMainThread(mBackgroundEventTarget,
-                                                  mActor, mInfo);
+                                                  mActor, mData, mWindowID,
+                                                  mPortIdentifier);
 
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
   RefPtr<SharedWorkerParent> mActor;
-  SharedWorkerLoadInfo mInfo;
+  RemoteWorkerData mData;
+  uint64_t mWindowID;
+  MessagePortIdentifier mPortIdentifier;
 };
 
 class RemoveWorkerManagerRunnable final : public Runnable
 {
 public:
   RemoveWorkerManagerRunnable(SharedWorkerService* aService,
                               SharedWorkerManager* aManager)
     : Runnable("RemoveWorkerManagerRunnable")
@@ -125,34 +133,50 @@ private:
   RefPtr<SharedWorkerService> mService;
   RefPtr<SharedWorkerManager> mManager;
 };
 
 class WorkerManagerCreatedRunnable final : public Runnable
 {
 public:
   WorkerManagerCreatedRunnable(SharedWorkerManager* aManager,
-                               SharedWorkerParent* aActor)
+                               SharedWorkerParent* aActor,
+                               const RemoteWorkerData& aData,
+                               uint64_t aWindowID,
+                               const MessagePortIdentifier& aPortIdentifier)
     : Runnable("WorkerManagerCreatedRunnable")
     , mManager(aManager)
     , mActor(aActor)
+    , mData(aData)
+    , mWindowID(aWindowID)
+    , mPortIdentifier(aPortIdentifier)
   {}
 
   NS_IMETHOD
   Run()
   {
     AssertIsOnBackgroundThread();
+
+    if (NS_WARN_IF(!mManager->MaybeCreateRemoteWorker(mData, mWindowID,
+                                                      mPortIdentifier))) {
+      mActor->ErrorPropagation(NS_ERROR_FAILURE);
+      return NS_OK;
+    }
+
     mManager->AddActor(mActor);
     mActor->ManagerCreated(mManager);
     return NS_OK;
   }
 
 private:
   RefPtr<SharedWorkerManager> mManager;
   RefPtr<SharedWorkerParent> mActor;
+  RemoteWorkerData mData;
+  uint64_t mWindowID;
+  MessagePortIdentifier mPortIdentifier;
 };
 
 class ErrorPropagationRunnable final : public Runnable
 {
 public:
   ErrorPropagationRunnable(SharedWorkerParent* aActor,
                            nsresult aError)
     : Runnable("ErrorPropagationRunnable")
@@ -213,110 +237,104 @@ SharedWorkerService::~SharedWorkerServic
   StaticMutexAutoLock lock(sSharedWorkerMutex);
 
   MOZ_ASSERT(sSharedWorkerService == this);
   sSharedWorkerService = nullptr;
 }
 
 void
 SharedWorkerService::GetOrCreateWorkerManager(SharedWorkerParent* aActor,
-                                              const SharedWorkerLoadInfo& aInfo)
+                                              const RemoteWorkerData& aData,
+                                              uint64_t aWindowID,
+                                              const MessagePortIdentifier& aPortIdentifier)
 {
   AssertIsOnBackgroundThread();
 
   // The real check happens on main-thread.
   RefPtr<GetOrCreateWorkerManagerRunnable> r =
-    new GetOrCreateWorkerManagerRunnable(aActor, aInfo);
+    new GetOrCreateWorkerManagerRunnable(aActor, aData, aWindowID,
+                                         aPortIdentifier);
 
   nsCOMPtr<nsIEventTarget> target = SystemGroup::EventTargetFor(TaskCategory::Other);
   nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 }
 
 void
 SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackgroundEventTarget,
                                                           SharedWorkerParent* aActor,
-                                                          const SharedWorkerLoadInfo& aInfo)
+                                                          const RemoteWorkerData& aData,
+                                                          uint64_t aWindowID,
+                                                          const MessagePortIdentifier& aPortIdentifier)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBackgroundEventTarget);
   MOZ_ASSERT(aActor);
 
   RefPtr<SharedWorkerManager> manager;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIPrincipal> principal =
-    PrincipalInfoToPrincipal(aInfo.principalInfo(), &rv);
+    PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
   if (NS_WARN_IF(!principal)) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
   rv = PopulatePrincipalContentSecurityPolicy(principal,
-                                              aInfo.principalCsp(),
-                                              aInfo.principalPreloadCsp());
+                                              aData.principalCsp(),
+                                              aData.principalPreloadCsp());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
   nsCOMPtr<nsIPrincipal> loadingPrincipal =
-    PrincipalInfoToPrincipal(aInfo.loadingPrincipalInfo(), &rv);
+    PrincipalInfoToPrincipal(aData.loadingPrincipalInfo(), &rv);
   if (NS_WARN_IF(!loadingPrincipal)) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
   rv = PopulatePrincipalContentSecurityPolicy(loadingPrincipal,
-                                              aInfo.loadingPrincipalCsp(),
-                                              aInfo.loadingPrincipalPreloadCsp());
+                                              aData.loadingPrincipalCsp(),
+                                              aData.loadingPrincipalPreloadCsp());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
   // Let's see if there is already a SharedWorker to share.
   for (SharedWorkerManager* workerManager : mWorkerManagers) {
-    if (workerManager->MatchOnMainThread(aInfo.domain(),
-                                         aInfo.resolvedScriptURL(),
-                                         aInfo.name(), loadingPrincipal)) {
+    if (workerManager->MatchOnMainThread(aData.domain(),
+                                         aData.resolvedScriptURL(),
+                                         aData.name(), loadingPrincipal)) {
       manager = workerManager;
       break;
     }
   }
 
   // Let's create a new one.
   if (!manager) {
-    manager = new SharedWorkerManager(aBackgroundEventTarget, aInfo,
-                                      principal, loadingPrincipal);
-
-    rv = manager->CreateWorkerOnMainThread();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
-      return;
-    }
+    manager = new SharedWorkerManager(aBackgroundEventTarget, aData,
+                                      loadingPrincipal);
 
     mWorkerManagers.AppendElement(manager);
   } else {
     // We are attaching the actor to an existing one.
-    if (manager->IsSecureContext() != aInfo.isSecureContext()) {
+    if (manager->IsSecureContext() != aData.isSecureContext()) {
       ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
                                    NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
   }
 
-  // If the SharedWorker(Manager) already existed and was frozen, the existence
-  // of a new, un-frozen actor should trigger the thawing of the SharedWorker.
-  manager->ThawOnMainThread();
-
-  manager->ConnectPortOnMainThread(aInfo.portIdentifier());
-
   RefPtr<WorkerManagerCreatedRunnable> r =
-    new WorkerManagerCreatedRunnable(manager, aActor);
+    new WorkerManagerCreatedRunnable(manager, aActor, aData, aWindowID,
+                                     aPortIdentifier);
   aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void
 SharedWorkerService::ErrorPropagationOnMainThread(nsIEventTarget* aBackgroundEventTarget,
                                                   SharedWorkerParent* aActor,
                                                   nsresult aError)
 {
--- a/dom/workers/sharedworkers/SharedWorkerService.h
+++ b/dom/workers/sharedworkers/SharedWorkerService.h
@@ -13,16 +13,18 @@
 namespace mozilla {
 
 namespace ipc {
 class PrincipalInfo;
 }
 
 namespace dom {
 
+class MessagePortIdentifier;
+class RemoteWorkerData;
 class SharedWorkerManager;
 class SharedWorkerParent;
 
 class SharedWorkerService final
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerService);
 
@@ -33,22 +35,26 @@ public:
   // The service, if already created, is available on any thread using this
   // method.
   static SharedWorkerService*
   Get();
 
   // PBackground method only.
   void
   GetOrCreateWorkerManager(SharedWorkerParent* aActor,
-                           const SharedWorkerLoadInfo& aInfo);
+                           const RemoteWorkerData& aData,
+                           uint64_t aWindowID,
+                           const MessagePortIdentifier& aPortIdentifier);
 
   void
   GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackgroundEventTarget,
                                        SharedWorkerParent* aActor,
-                                       const SharedWorkerLoadInfo& aInfo);
+                                       const RemoteWorkerData& aData,
+                                       uint64_t aWindowID,
+                                       const MessagePortIdentifier& aPortIdentifier);
 
   // PBackground method only.
   void
   RemoveWorkerManager(SharedWorkerManager* aManager);
 
   void
   RemoveWorkerManagerOnMainThread(SharedWorkerManager* aManager);
 
deleted file mode 100644
--- a/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
+++ /dev/null
@@ -1,78 +0,0 @@
-/* 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 ClientIPCTypes;
-include DOMTypes;
-include PBackgroundSharedTypes;
-
-using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
-
-namespace mozilla {
-namespace dom {
-
-struct ContentSecurityPolicy
-{
-  nsString policy;
-  bool reportOnlyFlag;
-  bool deliveredViaMetaTagFlag;
-};
-
-struct SharedWorkerLoadInfo
-{
-  nsString originalScriptURL;
-  nsCString baseScriptURL;
-  nsCString resolvedScriptURL;
-
-  nsString name;
-
-  PrincipalInfo loadingPrincipalInfo;
-  ContentSecurityPolicy[] loadingPrincipalCsp;
-  ContentSecurityPolicy[] loadingPrincipalPreloadCsp;
-
-  PrincipalInfo principalInfo;
-  ContentSecurityPolicy[] principalCsp;
-  ContentSecurityPolicy[] principalPreloadCsp;
-
-  nsCString domain;
-
-  bool isSecureContext;
-
-  uint64_t windowID;
-
-  OptionalIPCClientInfo clientInfo;
-
-  MessagePortIdentifier portIdentifier;
-};
-
-// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
-// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
-// report complicated errors such as redeclarations that involve multiple
-// distinct lines.  For more generic error-propagation IPC structures, see bug
-// 1357463 on making ErrorResult usable over IPC.
-
-struct ErrorDataNote {
-  uint32_t lineNumber;
-  uint32_t columnNumber;
-  nsString message;
-  nsString filename;
-};
-
-struct ErrorData {
-  uint32_t lineNumber;
-  uint32_t columnNumber;
-  uint32_t flags;
-  nsString message;
-  nsString filename;
-  nsString line;
-  ErrorDataNote[] notes;
-};
-
-union ErrorValue {
-  nsresult;
-  ErrorData;
-  void_t;
-};
-
-} // namespace dom
-} // namespace mozilla
--- a/dom/workers/sharedworkers/moz.build
+++ b/dom/workers/sharedworkers/moz.build
@@ -16,14 +16,13 @@ UNIFIED_SOURCES += [
     'SharedWorkerChild.cpp',
     'SharedWorkerManager.cpp',
     'SharedWorkerParent.cpp',
     'SharedWorkerService.cpp',
 ]
 
 IPDL_SOURCES += [
     'PSharedWorker.ipdl',
-    'SharedWorkerTypes.ipdlh',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -289,23 +289,34 @@ BackgroundChildImpl::DeallocPPendingIPCB
 {
   delete aActor;
   return true;
 }
 
 dom::PRemoteWorkerChild*
 BackgroundChildImpl::AllocPRemoteWorkerChild(const RemoteWorkerData& aData)
 {
-  return new dom::RemoteWorkerChild();
+  RefPtr<dom::RemoteWorkerChild> agent = new dom::RemoteWorkerChild();
+  return agent.forget().take();
+}
+
+IPCResult
+BackgroundChildImpl::RecvPRemoteWorkerConstructor(PRemoteWorkerChild* aActor,
+                                                  const RemoteWorkerData& aData)
+{
+  dom::RemoteWorkerChild* actor = static_cast<dom::RemoteWorkerChild*>(aActor);
+  actor->ExecWorker(aData);
+  return IPC_OK();
 }
 
 bool
 BackgroundChildImpl::DeallocPRemoteWorkerChild(dom::PRemoteWorkerChild* aActor)
 {
-  delete aActor;
+  RefPtr<dom::RemoteWorkerChild> actor =
+    dont_AddRef(static_cast<dom::RemoteWorkerChild*>(aActor));
   return true;
 }
 
 dom::PRemoteWorkerServiceChild*
 BackgroundChildImpl::AllocPRemoteWorkerServiceChild()
 {
   RefPtr<dom::RemoteWorkerServiceChild> agent =
     new dom::RemoteWorkerServiceChild();
@@ -316,17 +327,19 @@ bool
 BackgroundChildImpl::DeallocPRemoteWorkerServiceChild(dom::PRemoteWorkerServiceChild* aActor)
 {
   RefPtr<dom::RemoteWorkerServiceChild> actor =
     dont_AddRef(static_cast<dom::RemoteWorkerServiceChild*>(aActor));
   return true;
 }
 
 dom::PSharedWorkerChild*
-BackgroundChildImpl::AllocPSharedWorkerChild(const dom::SharedWorkerLoadInfo& aInfo)
+BackgroundChildImpl::AllocPSharedWorkerChild(const dom::RemoteWorkerData& aData,
+                                             const uint64_t& aWindowID,
+                                             const dom::MessagePortIdentifier& aPortIdentifier)
 {
   RefPtr<dom::SharedWorkerChild> agent = new dom::SharedWorkerChild();
   return agent.forget().take();
 }
 
 bool
 BackgroundChildImpl::DeallocPSharedWorkerChild(dom::PSharedWorkerChild* aActor)
 {
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -112,27 +112,33 @@ protected:
   AllocPTemporaryIPCBlobChild() override;
 
   virtual bool
   DeallocPTemporaryIPCBlobChild(PTemporaryIPCBlobChild* aActor) override;
 
   virtual mozilla::dom::PRemoteWorkerChild*
   AllocPRemoteWorkerChild(const RemoteWorkerData& aData) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvPRemoteWorkerConstructor(PRemoteWorkerChild* aActor,
+                               const RemoteWorkerData& aData) override;
+
   virtual bool
   DeallocPRemoteWorkerChild(mozilla::dom::PRemoteWorkerChild* aActor) override;
 
   virtual mozilla::dom::PRemoteWorkerServiceChild*
   AllocPRemoteWorkerServiceChild() override;
 
   virtual bool
   DeallocPRemoteWorkerServiceChild(mozilla::dom::PRemoteWorkerServiceChild* aActor) override;
 
   virtual mozilla::dom::PSharedWorkerChild*
-  AllocPSharedWorkerChild(const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
+  AllocPSharedWorkerChild(const mozilla::dom::RemoteWorkerData& aData,
+                          const uint64_t& aWindowID,
+                          const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
 
   virtual bool
   DeallocPSharedWorkerChild(mozilla::dom::PSharedWorkerChild* aActor) override;
 
   virtual PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const FileDescriptor& aFileDescriptor)
                                override;
 
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -422,30 +422,34 @@ BackgroundParentImpl::RecvPRemoteWorkerS
 bool
 BackgroundParentImpl::DeallocPRemoteWorkerServiceParent(mozilla::dom::PRemoteWorkerServiceParent* aActor)
 {
   delete aActor;
   return true;
 }
 
 mozilla::dom::PSharedWorkerParent*
-BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo)
+BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::RemoteWorkerData& aData,
+                                               const uint64_t& aWindowID,
+                                               const mozilla::dom::MessagePortIdentifier& aPortIdentifier)
 {
   RefPtr<dom::SharedWorkerParent> agent =
     new mozilla::dom::SharedWorkerParent();
   return agent.forget().take();
 }
 
 IPCResult
 BackgroundParentImpl::RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
-                                                   const mozilla::dom::SharedWorkerLoadInfo& aInfo)
+                                                   const mozilla::dom::RemoteWorkerData& aData,
+                                                   const uint64_t& aWindowID,
+                                                   const mozilla::dom::MessagePortIdentifier& aPortIdentifier)
 {
   mozilla::dom::SharedWorkerParent* actor =
     static_cast<mozilla::dom::SharedWorkerParent*>(aActor);
-  actor->Initialize(aInfo);
+  actor->Initialize(aData, aWindowID, aPortIdentifier);
   return IPC_OK();
 }
 
 bool
 BackgroundParentImpl::DeallocPSharedWorkerParent(mozilla::dom::PSharedWorkerParent* aActor)
 {
   RefPtr<mozilla::dom::SharedWorkerParent> actor =
     dont_AddRef(static_cast<mozilla::dom::SharedWorkerParent*>(aActor));
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -144,21 +144,25 @@ protected:
 
   virtual mozilla::ipc::IPCResult
   RecvPRemoteWorkerServiceConstructor(PRemoteWorkerServiceParent* aActor) override;
 
   virtual bool
   DeallocPRemoteWorkerServiceParent(PRemoteWorkerServiceParent* aActor) override;
 
   virtual mozilla::dom::PSharedWorkerParent*
-  AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
+  AllocPSharedWorkerParent(const mozilla::dom::RemoteWorkerData& aData,
+                           const uint64_t& aWindowID,
+                           const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
 
   virtual mozilla::ipc::IPCResult
   RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
-                               const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
+                               const mozilla::dom::RemoteWorkerData& aData,
+                               const uint64_t& aWindowID,
+                               const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
 
   virtual bool
   DeallocPSharedWorkerParent(PSharedWorkerParent* aActor) override;
 
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const FileDescriptor& aFileDescriptor)
                                 override;
 
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -44,17 +44,16 @@ include DOMTypes;
 include IPCBlob;
 include IPCServiceWorkerDescriptor;
 include IPCServiceWorkerRegistrationDescriptor;
 include PBackgroundSharedTypes;
 include PBackgroundIDBSharedTypes;
 include PFileSystemParams;
 include ProtocolTypes;
 include RemoteWorkerTypes;
-include SharedWorkerTypes;
 include MIDITypes;
 
 include "mozilla/dom/cache/IPCUtils.h";
 include "mozilla/layers/LayersMessageUtils.h";
 
 using mozilla::dom::cache::Namespace
   from "mozilla/dom/cache/Types.h";
 
@@ -156,17 +155,19 @@ parent:
   async PGamepadEventChannel();
 
   async PGamepadTestChannel();
 
   async PHttpBackgroundChannel(uint64_t channelId);
 
   async PWebAuthnTransaction();
 
-  async PSharedWorker(SharedWorkerLoadInfo loadInfo);
+  async PSharedWorker(RemoteWorkerData data,
+                      uint64_t windowID,
+                      MessagePortIdentifier portIdentifier);
 
   async PTemporaryIPCBlob();
 
   async PClientManager();
 
   async PMIDIManager();
   async PMIDIPort(MIDIPortInfo portInfo, bool sysexEnabled);