Bug 1438945 - Part 3: SharedWorkerService and SharedWorkerManager. r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 19 Nov 2018 15:18:21 -0800
changeset 503565 062638f850a0bef1cfd94e62419ac2f00325c40b
parent 503564 d77e06240f3c05f592381bbbbed176eb78c4c7de
child 503566 5de8d2303240d72cbca56a1fd1d50f575ec3b2de
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 3: SharedWorkerService and SharedWorkerManager. r=asuth
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/ScriptLoader.h
dom/workers/WorkerLoadInfo.cpp
dom/workers/WorkerLoadInfo.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/moz.build
dom/workers/sharedworkers/PSharedWorker.ipdl
dom/workers/sharedworkers/SharedWorker.cpp
dom/workers/sharedworkers/SharedWorker.h
dom/workers/sharedworkers/SharedWorkerChild.cpp
dom/workers/sharedworkers/SharedWorkerChild.h
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/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -234,16 +234,17 @@
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/NavigatorBinding.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/InstallTriggerBinding.h"
 #include "mozilla/dom/Report.h"
 #include "mozilla/dom/ReportingObserver.h"
+#include "mozilla/dom/SharedWorker.h"
 #include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerRegistration.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
 #include "mozilla/dom/U2F.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/Worklet.h"
 #ifdef HAVE_SIDEBAR
 #include "mozilla/dom/ExternalBinding.h"
@@ -1171,16 +1172,22 @@ nsGlobalWindowInner::FreeInnerObjects(bo
   NotifyDOMWindowDestroyed(this);
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
     reporter->ObserveDOMWindowDetached(this);
   }
 
   // Kill all of the workers for this window.
   CancelWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Close();
+  }
+
   if (mTimeoutManager) {
     mTimeoutManager->ClearAllTimeouts();
   }
 
   if (mIdleTimer) {
     mIdleTimer->Cancel();
     mIdleTimer = nullptr;
   }
@@ -1319,16 +1326,18 @@ nsGlobalWindowInner::FreeInnerObjects(bo
 
   mPaintWorklet = nullptr;
 
   mExternal = nullptr;
   mInstallTrigger = nullptr;
 
   mPerformance = nullptr;
 
+  mSharedWorkers.Clear();
+
 #ifdef MOZ_WEBSPEECH
   mSpeechSynthesis = nullptr;
 #endif
 
   mParentTarget = nullptr;
 
   if (mCleanMessageManager) {
     MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
@@ -1429,17 +1438,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
       cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
     });
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
-
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
@@ -1523,16 +1532,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // while unlinking.
 
   tmp->UpdateTopInnerWindow();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
   if (tmp->mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
   }
   if (tmp->mIndexedDB) {
     tmp->mIndexedDB->DisconnectFromWindow(tmp);
@@ -5944,16 +5954,22 @@ nsGlobalWindowInner::Suspend()
     for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
       ac->RemoveWindowListener(mEnabledSensors[i], this);
   }
   DisableGamepadUpdates();
   DisableVRUpdates();
 
   SuspendWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Suspend();
+  }
+
   SuspendIdleRequests();
 
   mTimeoutManager->Suspend();
 
   // Suspend all of the AudioContexts for this window
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     ErrorResult dummy;
     RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
@@ -6005,16 +6021,22 @@ nsGlobalWindowInner::Resume()
   mTimeoutManager->Resume();
 
   ResumeIdleRequests();
 
   // Resume all of the workers for this window.  We must do this
   // after timeouts since workers may have queued events that can trigger
   // a setTimeout().
   ResumeWorkersForWindow(this);
+
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Resume();
+  }
 }
 
 bool
 nsGlobalWindowInner::IsSuspended() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mSuspendDepth != 0;
 }
@@ -6039,16 +6061,22 @@ nsGlobalWindowInner::FreezeInternal()
   mFreezeDepth += 1;
   MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
   if (mFreezeDepth != 1) {
     return;
   }
 
   FreezeWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Freeze();
+  }
+
   mTimeoutManager->Freeze();
   if (mClientSource) {
     mClientSource->Freeze();
   }
 
   NotifyDOMWindowFrozen(this);
 }
 
@@ -6078,16 +6106,22 @@ nsGlobalWindowInner::ThawInternal()
 
   if (mClientSource) {
     mClientSource->Thaw();
   }
   mTimeoutManager->Thaw();
 
   ThawWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Thaw();
+  }
+
   NotifyDOMWindowThawed(this);
 }
 
 bool
 nsGlobalWindowInner::IsFrozen() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   bool frozen = mFreezeDepth != 0;
@@ -7923,16 +7957,34 @@ nsGlobalWindowInner::GetIntlUtils(ErrorR
 {
   if (!mIntlUtils) {
     mIntlUtils = new IntlUtils(this);
   }
 
   return mIntlUtils;
 }
 
+void
+nsGlobalWindowInner::StoreSharedWorker(SharedWorker* aSharedWorker)
+{
+  MOZ_ASSERT(aSharedWorker);
+  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
+
+  mSharedWorkers.AppendElement(aSharedWorker);
+}
+
+void
+nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker)
+{
+  MOZ_ASSERT(aSharedWorker);
+  MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
+
+  mSharedWorkers.RemoveElement(aSharedWorker);
+}
+
 mozilla::dom::TabGroup*
 nsPIDOMWindowInner::TabGroup()
 {
   return nsGlobalWindowInner::Cast(this)->TabGroupInner();
 }
 
 /* static */ already_AddRefed<nsGlobalWindowInner>
 nsGlobalWindowInner::Create(nsGlobalWindowOuter *aOuterWindow, bool aIsChrome)
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -114,16 +114,17 @@ class InstallTriggerImpl;
 class IntlUtils;
 class Location;
 class MediaQueryList;
 class OwningExternalOrWindowProxy;
 class Promise;
 class PostMessageEvent;
 struct RequestInit;
 class RequestOrUSVString;
+class SharedWorker;
 class Selection;
 class SpeechSynthesis;
 class TabGroup;
 class Timeout;
 class U2F;
 class VisualViewport;
 class VRDisplay;
 enum class VRDisplayEventReason : uint8_t;
@@ -707,16 +708,22 @@ public:
   GetPaintWorklet(mozilla::ErrorResult& aRv);
 
   void
   GetRegionalPrefsLocales(nsTArray<nsString>& aLocales);
 
   mozilla::dom::IntlUtils*
   GetIntlUtils(mozilla::ErrorResult& aRv);
 
+  void
+  StoreSharedWorker(mozilla::dom::SharedWorker* aSharedWorker);
+
+  void
+  ForgetSharedWorker(mozilla::dom::SharedWorker* aSharedWorker);
+
 public:
   void Alert(nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   void Alert(const nsAString& aMessage,
              nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   bool Confirm(const nsAString& aMessage,
                nsIPrincipal& aSubjectPrincipal,
@@ -1400,16 +1407,18 @@ protected:
   RefPtr<mozilla::dom::Storage> mLocalStorage;
   RefPtr<mozilla::dom::Storage> mSessionStorage;
 
   RefPtr<mozilla::EventListenerManager> mListenerManager;
   RefPtr<mozilla::dom::Location> mLocation;
   RefPtr<nsHistory>           mHistory;
   RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>> mSharedWorkers;
+
   RefPtr<mozilla::dom::VisualViewport> mVisualViewport;
 
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
   // mTabChild is only ever populated in the content process.
   nsCOMPtr<nsITabChild>  mTabChild;
 
   uint32_t mSuspendDepth;
   uint32_t mFreezeDepth;
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -28,34 +28,32 @@
 #include <algorithm>
 #include "mozilla/ipc/BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "jsfriendapi.h"
 #include "js/LocaleSensitive.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/ArrayUtils.h"
-#include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PerformanceService.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/SharedWorker.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"
@@ -1402,38 +1400,16 @@ RuntimeService::RegisterWorker(WorkerPri
       domainInfo->mChildWorkerCount++;
     }
     else if (isServiceWorker) {
       domainInfo->mActiveServiceWorkers.AppendElement(aWorkerPrivate);
     }
     else {
       domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
     }
-
-/* TODO
-    if (isSharedWorker) {
-#ifdef DEBUG
-      for (const UniquePtr<SharedWorkerInfo>& data : domainInfo->mSharedWorkerInfos) {
-         if (data->mScriptSpec == sharedWorkerScriptSpec &&
-             data->mName == aWorkerPrivate->WorkerName() &&
-             // We want to be sure that the window's principal subsumes the
-             // SharedWorker's principal and vice versa.
-             data->mWorkerPrivate->GetPrincipal()->Subsumes(aWorkerPrivate->GetPrincipal()) &&
-             aWorkerPrivate->GetPrincipal()->Subsumes(data->mWorkerPrivate->GetPrincipal())) {
-           MOZ_CRASH("We should not instantiate a new SharedWorker!");
-         }
-      }
-#endif
-
-      UniquePtr<SharedWorkerInfo> sharedWorkerInfo(
-        new SharedWorkerInfo(aWorkerPrivate, sharedWorkerScriptSpec,
-                             aWorkerPrivate->WorkerName()));
-      domainInfo->mSharedWorkerInfos.AppendElement(std::move(sharedWorkerInfo));
-    }
-*/
   }
 
   // From here on out we must call UnregisterWorker if something fails!
   if (parent) {
     if (!parent->AddChildWorker(aWorkerPrivate)) {
       UnregisterWorker(aWorkerPrivate);
       return false;
     }
@@ -1479,32 +1455,16 @@ RuntimeService::RegisterWorker(WorkerPri
   if (isServiceWorker) {
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1);
   }
   return true;
 }
 
 void
-RuntimeService::RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
-                                   WorkerPrivate* aWorkerPrivate)
-{
-/* TODO
-  for (uint32_t i = 0; i < aDomainInfo->mSharedWorkerInfos.Length(); ++i) {
-    const UniquePtr<SharedWorkerInfo>& data =
-      aDomainInfo->mSharedWorkerInfos[i];
-    if (data->mWorkerPrivate == aWorkerPrivate) {
-      aDomainInfo->mSharedWorkerInfos.RemoveElementAt(i);
-      break;
-    }
-  }
-*/
-}
-
-void
 RuntimeService::UnregisterWorker(WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnParentThread();
 
   WorkerPrivate* parent = aWorkerPrivate->GetParent();
   if (!parent) {
     AssertIsOnMainThread();
   }
@@ -1536,20 +1496,16 @@ RuntimeService::UnregisterWorker(WorkerP
       domainInfo->mActiveServiceWorkers.RemoveElement(aWorkerPrivate);
     }
     else {
       MOZ_ASSERT(domainInfo->mActiveWorkers.Contains(aWorkerPrivate),
                  "Don't know about this worker!");
       domainInfo->mActiveWorkers.RemoveElement(aWorkerPrivate);
     }
 
-    if (aWorkerPrivate->IsSharedWorker()) {
-      RemoveSharedWorker(domainInfo, aWorkerPrivate);
-    }
-
     // See if there's a queued worker we can schedule.
     if (domainInfo->ActiveWorkerCount() < gMaxWorkersPerDomain &&
         !domainInfo->mQueuedWorkers.IsEmpty()) {
       queuedWorker = domainInfo->mQueuedWorkers[0];
       domainInfo->mQueuedWorkers.RemoveElementAt(0);
 
       if (queuedWorker->GetParent()) {
         domainInfo->mChildWorkerCount++;
@@ -2208,78 +2164,78 @@ RuntimeService::CancelWorkersForWindow(n
   AssertIsOnMainThread();
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   if (!workers.IsEmpty()) {
     for (uint32_t index = 0; index < workers.Length(); index++) {
       WorkerPrivate*& worker = workers[index];
-
-      if (worker->IsSharedWorker()) {
-        worker->CloseSharedWorkersForWindow(aWindow);
-      } else {
-        worker->Cancel();
-      }
+      MOZ_ASSERT(!worker->IsSharedWorker());
+      worker->Cancel();
     }
   }
 }
 
 void
 RuntimeService::FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->Freeze(aWindow);
   }
 }
 
 void
 RuntimeService::ThawWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->Thaw(aWindow);
   }
 }
 
 void
 RuntimeService::SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowPaused();
   }
 }
 
 void
 RuntimeService::ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowResumed();
   }
 }
 
 void
 RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
@@ -2290,155 +2246,16 @@ RuntimeService::PropagateFirstPartyStora
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
 
-nsresult
-RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
-                                               WorkerLoadInfo* aLoadInfo,
-                                               const nsAString& aScriptURL,
-                                               const nsAString& aName,
-                                               SharedWorker** aSharedWorker)
-{
-/* TODO
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aLoadInfo);
-  MOZ_ASSERT(aLoadInfo->mResolvedScriptURI);
-
-  RefPtr<WorkerPrivate> workerPrivate;
-  {
-    MutexAutoLock lock(mMutex);
-
-    nsCString scriptSpec;
-    nsresult rv = aLoadInfo->mResolvedScriptURI->GetSpec(scriptSpec);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    MOZ_DIAGNOSTIC_ASSERT(aLoadInfo->mPrincipal && aLoadInfo->mLoadingPrincipal);
-
-    WorkerDomainInfo* domainInfo;
-    if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo)) {
-      for (const UniquePtr<SharedWorkerInfo>& data : domainInfo->mSharedWorkerInfos) {
-        if (data->mScriptSpec == scriptSpec &&
-            data->mName == aName &&
-            // We want to be sure that the window's principal subsumes the
-            // SharedWorker's loading principal and vice versa.
-            aLoadInfo->mLoadingPrincipal->Subsumes(data->mWorkerPrivate->GetLoadingPrincipal()) &&
-            data->mWorkerPrivate->GetLoadingPrincipal()->Subsumes(aLoadInfo->mLoadingPrincipal)) {
-          workerPrivate = data->mWorkerPrivate;
-          break;
-        }
-      }
-    }
-  }
-
-  // Keep a reference to the window before spawning the worker. If the worker is
-  // a Shared/Service worker and the worker script loads and executes before
-  // the SharedWorker object itself is created before then WorkerScriptLoaded()
-  // will reset the loadInfo's window.
-  nsCOMPtr<nsPIDOMWindowInner> window = aLoadInfo->mWindow;
-
-  // shouldAttachToWorkerPrivate tracks whether our SharedWorker should actually
-  // get attached to the WorkerPrivate we're using.  It will become false if the
-  // WorkerPrivate already exists and its secure context state doesn't match
-  // what we want for the new SharedWorker.
-  bool shouldAttachToWorkerPrivate = true;
-  bool created = false;
-  ErrorResult rv;
-  if (!workerPrivate) {
-    workerPrivate =
-      WorkerPrivate::Constructor(aCx, aScriptURL, false,
-                                 WorkerTypeShared, aName, VoidCString(),
-                                 aLoadInfo, rv);
-    NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
-
-    created = true;
-  } else {
-    // Check whether the secure context state matches.  The current realm
-    // of aCx is the realm of the SharedWorker constructor that was invoked,
-    // which is the realm of the document that will be hooked up to the worker,
-    // so that's what we want to check.
-    shouldAttachToWorkerPrivate =
-      workerPrivate->IsSecureContext() ==
-        JS::GetIsSecureContext(js::GetContextRealm(aCx));
-
-    // If we're attaching to an existing SharedWorker private, then we
-    // must update the overriden load group to account for our document's
-    // load group.
-    if (shouldAttachToWorkerPrivate) {
-      workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
-    }
-  }
-
-  // We don't actually care about this MessageChannel, but we use it to 'steal'
-  // its 2 connected ports.
-  RefPtr<MessageChannel> channel =
-    MessageChannel::Constructor(window->AsGlobal(), rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
-
-  RefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
-                                                       channel->Port1());
-
-  if (!shouldAttachToWorkerPrivate) {
-    // We're done here.  Just queue up our error event and return our
-    // dead-on-arrival SharedWorker.
-    RefPtr<AsyncEventDispatcher> errorEvent =
-      new AsyncEventDispatcher(sharedWorker,
-                               NS_LITERAL_STRING("error"),
-                               CanBubble::eNo);
-    errorEvent->PostDOMEvent();
-    sharedWorker.forget(aSharedWorker);
-    return NS_OK;
-  }
-
-  if (!workerPrivate->RegisterSharedWorker(sharedWorker, channel->Port2())) {
-    NS_WARNING("Worker is unreachable, this shouldn't happen!");
-    sharedWorker->Close();
-    return NS_ERROR_FAILURE;
-  }
-
-  // This is normally handled in RegisterWorker, but that wasn't called if the
-  // worker already existed.
-  if (!created) {
-    nsTArray<WorkerPrivate*>* windowArray;
-    if (!mWindowMap.Get(window, &windowArray)) {
-      windowArray = new nsTArray<WorkerPrivate*>(1);
-      mWindowMap.Put(window, windowArray);
-    }
-
-    if (!windowArray->Contains(workerPrivate)) {
-      windowArray->AppendElement(workerPrivate);
-    }
-  }
-
-  sharedWorker.forget(aSharedWorker);
-*/
-  return NS_OK;
-}
-
-void
-RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aWorkerPrivate);
-  MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
-
-  MutexAutoLock lock(mMutex);
-
-  WorkerDomainInfo* domainInfo;
-  if (mDomainMap.Get(aWorkerPrivate->Domain(), &domainInfo)) {
-    RemoveSharedWorker(domainInfo, aWorkerPrivate);
-  }
-}
-
 void
 RuntimeService::NoteIdleThread(WorkerThread* aThread)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aThread);
 
   bool shutdownThread = mShuttingDown;
   bool scheduleTimer = false;
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -18,44 +18,29 @@
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 
 class nsITimer;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
-class SharedWorker;
 struct WorkerLoadInfo;
 class WorkerThread;
 
 namespace workerinternals {
 
 class RuntimeService final : public nsIObserver
 {
-  struct SharedWorkerInfo
-  {
-    WorkerPrivate* mWorkerPrivate;
-    nsCString mScriptSpec;
-    nsString mName;
-
-    SharedWorkerInfo(WorkerPrivate* aWorkerPrivate,
-                     const nsACString& aScriptSpec,
-                     const nsAString& aName)
-    : mWorkerPrivate(aWorkerPrivate), mScriptSpec(aScriptSpec), mName(aName)
-    { }
-  };
-
   struct WorkerDomainInfo
   {
     nsCString mDomain;
     nsTArray<WorkerPrivate*> mActiveWorkers;
     nsTArray<WorkerPrivate*> mActiveServiceWorkers;
     nsTArray<WorkerPrivate*> mQueuedWorkers;
-    nsTArray<UniquePtr<SharedWorkerInfo>> mSharedWorkerInfos;
     uint32_t mChildWorkerCount;
 
     WorkerDomainInfo()
     : mActiveWorkers(1), mChildWorkerCount(0)
     { }
 
     uint32_t
     ActiveWorkerCount() const
@@ -129,20 +114,16 @@ public:
 
   bool
   RegisterWorker(WorkerPrivate* aWorkerPrivate);
 
   void
   UnregisterWorker(WorkerPrivate* aWorkerPrivate);
 
   void
-  RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
-                     WorkerPrivate* aWorkerPrivate);
-
-  void
   CancelWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   ThawWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
@@ -150,19 +131,16 @@ public:
   SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow);
 
-  void
-  ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);
-
   const NavigatorProperties&
   GetNavigatorProperties() const
   {
     return mNavigatorProperties;
   }
 
   void
   NoteIdleThread(WorkerThread* aThread);
@@ -255,22 +233,15 @@ private:
   GetWorkersForWindow(nsPIDOMWindowInner* aWindow,
                       nsTArray<WorkerPrivate*>& aWorkers);
 
   bool
   ScheduleWorker(WorkerPrivate* aWorkerPrivate);
 
   static void
   ShutdownIdleThreads(nsITimer* aTimer, void* aClosure);
-
-  nsresult
-  CreateSharedWorkerFromLoadInfo(JSContext* aCx,
-                                 WorkerLoadInfo* aLoadInfo,
-                                 const nsAString& aScriptURL,
-                                 const nsAString& aName,
-                                 SharedWorker** aSharedWorker);
 };
 
 } // workerinternals namespace
 } // dom namespace
 } // mozilla namespace
 
 #endif /* mozilla_dom_workers_runtimeservice_h__ */
--- a/dom/workers/ScriptLoader.h
+++ b/dom/workers/ScriptLoader.h
@@ -2,17 +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/. */
 
 #ifndef mozilla_dom_workers_scriptloader_h__
 #define mozilla_dom_workers_scriptloader_h__
 
-#include "WorkerCommon.h"
+#include "mozilla/dom/WorkerCommon.h"
 #include "nsIContentPolicy.h"
 #include "nsStringFwd.h"
 
 class nsIPrincipal;
 class nsIURI;
 class nsIDocument;
 class nsILoadGroup;
 class nsIChannel;
--- a/dom/workers/WorkerLoadInfo.cpp
+++ b/dom/workers/WorkerLoadInfo.cpp
@@ -91,16 +91,17 @@ WorkerLoadInfo::WorkerLoadInfo()
   , mFromWindow(false)
   , mEvalAllowed(false)
   , mReportCSPViolations(false)
   , mXHRParamsAllowed(false)
   , mPrincipalIsSystem(false)
   , mStorageAllowed(false)
   , mFirstPartyStorageAccessGranted(false)
   , mServiceWorkersTestingInWindow(false)
+  , mSecureContext(eNotSet)
 {
   MOZ_COUNT_CTOR(WorkerLoadInfo);
 }
 
 WorkerLoadInfo::~WorkerLoadInfo()
 {
   MOZ_COUNT_DTOR(WorkerLoadInfo);
 }
@@ -154,16 +155,17 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo
   mReportCSPViolations = aOther.mReportCSPViolations;
   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
   mStorageAllowed = aOther.mStorageAllowed;
   mFirstPartyStorageAccessGranted = aOther.mFirstPartyStorageAccessGranted;
   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
   mOriginAttributes = aOther.mOriginAttributes;
   mParentController = aOther.mParentController;
+  mSecureContext = aOther.mSecureContext;
 }
 
 nsresult
 WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
                                          nsILoadGroup* aLoadGroup)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
--- a/dom/workers/WorkerLoadInfo.h
+++ b/dom/workers/WorkerLoadInfo.h
@@ -102,16 +102,22 @@ struct WorkerLoadInfo
   bool mReportCSPViolations;
   bool mXHRParamsAllowed;
   bool mPrincipalIsSystem;
   bool mStorageAllowed;
   bool mFirstPartyStorageAccessGranted;
   bool mServiceWorkersTestingInWindow;
   OriginAttributes mOriginAttributes;
 
+  enum {
+    eNotSet,
+    eInsecureContext,
+    eSecureContext,
+  } mSecureContext;
+
   WorkerLoadInfo();
   ~WorkerLoadInfo();
 
   void StealFrom(WorkerLoadInfo& aOther);
 
   nsresult
   SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -881,49 +881,16 @@ public:
 #ifdef DEBUG
 static bool
 StartsWithExplicit(nsACString& s)
 {
     return StringBeginsWith(s, NS_LITERAL_CSTRING("explicit/"));
 }
 #endif
 
-class MessagePortRunnable final : public WorkerRunnable
-{
-  MessagePortIdentifier mPortIdentifier;
-
-public:
-  MessagePortRunnable(WorkerPrivate* aWorkerPrivate, MessagePort* aPort)
-  : WorkerRunnable(aWorkerPrivate)
-  {
-    MOZ_ASSERT(aPort);
-    // In order to move the port from one thread to another one, we have to
-    // close and disentangle it. The output will be a MessagePortIdentifier that
-    // will be used to recreate a new MessagePort on the other thread.
-    aPort->CloneAndDisentangle(mPortIdentifier);
-  }
-
-private:
-  ~MessagePortRunnable()
-  { }
-
-  virtual bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
-  }
-
-  nsresult
-  Cancel() override
-  {
-    MessagePort::ForceClose(mPortIdentifier);
-    return WorkerRunnable::Cancel();
-  }
-};
-
 PRThread*
 PRThreadFromThread(nsIThread* aThread)
 {
   MOZ_ASSERT(aThread);
 
   PRThread* result;
   MOZ_ALWAYS_SUCCEEDS(aThread->GetPRThread(&result));
   MOZ_ASSERT(result);
@@ -1734,23 +1701,16 @@ WorkerPrivate::Notify(WorkerStatus aStat
     if (mParentStatus >= aStatus) {
       return true;
     }
 
     pending = mParentStatus == Pending;
     mParentStatus = aStatus;
   }
 
-  if (IsSharedWorker()) {
-    RuntimeService* runtime = RuntimeService::GetService();
-    MOZ_ASSERT(runtime);
-
-    runtime->ForgetSharedWorker(this);
-  }
-
   if (pending) {
 #ifdef DEBUG
     {
       // Fake a thread here just so that our assertions don't go off for no
       // reason.
       nsIThread* currentThread = NS_GetCurrentThread();
       MOZ_ASSERT(currentThread);
 
@@ -1775,45 +1735,16 @@ WorkerPrivate::Notify(WorkerStatus aStat
   return runnable->Dispatch();
 }
 
 bool
 WorkerPrivate::Freeze(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnParentThread();
 
-  // Shared workers are only frozen if all of their owning documents are
-  // frozen. It can happen that mSharedWorkers is empty but this thread has
-  // not been unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
-    AssertIsOnMainThread();
-
-    bool allFrozen = true;
-
-    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
-        // Calling Freeze() may change the refcount, ensure that the worker
-        // outlives this call.
-        RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
-
-        kungFuDeathGrip->Freeze();
-      } else {
-        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
-                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-        if (!mSharedWorkers[i]->IsFrozen()) {
-          allFrozen = false;
-        }
-      }
-    }
-
-    if (!allFrozen || mParentFrozen) {
-      return true;
-    }
-  }
-
   mParentFrozen = true;
 
   // WorkerDebuggeeRunnables sent from a worker to content must not be delivered
   // while the worker is frozen.
   //
   // Since a top-level worker and all its children share the same
   // mMainThreadDebuggeeEventTarget, it's sufficient to do this only in the
   // top-level worker.
@@ -1843,47 +1774,16 @@ WorkerPrivate::Freeze(nsPIDOMWindowInner
 
   return true;
 }
 
 bool
 WorkerPrivate::Thaw(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnParentThread();
-
-  // Shared workers are resumed if any of their owning documents are thawed.
-  // It can happen that mSharedWorkers is empty but this thread has not been
-  // unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
-    AssertIsOnMainThread();
-
-    bool anyRunning = false;
-
-    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
-        // Calling Thaw() may change the refcount, ensure that the worker
-        // outlives this call.
-        RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
-
-        kungFuDeathGrip->Thaw();
-        anyRunning = true;
-      } else {
-        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
-                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-        if (!mSharedWorkers[i]->IsFrozen()) {
-          anyRunning = true;
-        }
-      }
-    }
-
-    if (!anyRunning || !mParentFrozen) {
-      return true;
-    }
-  }
-
   MOZ_ASSERT(mParentFrozen);
 
   mParentFrozen = false;
 
   // Delivery of WorkerDebuggeeRunnables to the window may resume.
   //
   // Since a top-level worker and all its children share the same
   // mMainThreadDebuggeeEventTarget, it's sufficient to do this only in the
@@ -1915,38 +1815,34 @@ WorkerPrivate::Thaw(nsPIDOMWindowInner* 
 
   return true;
 }
 
 void
 WorkerPrivate::ParentWindowPaused()
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 0);
-  mParentWindowPausedDepth += 1;
+  MOZ_ASSERT(!mParentWindowPaused);
+  mParentWindowPaused = true;
 
   // This is called from WorkerPrivate construction, and we may not have
   // allocated mMainThreadDebuggeeEventTarget yet.
   if (mMainThreadDebuggeeEventTarget) {
     // Pausing a ThrottledEventQueue is infallible.
     MOZ_ALWAYS_SUCCEEDS(mMainThreadDebuggeeEventTarget->SetIsPaused(true));
   }
 }
 
 void
 WorkerPrivate::ParentWindowResumed()
 {
   AssertIsOnMainThread();
 
-  MOZ_ASSERT(mParentWindowPausedDepth > 0);
-  MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 1);
-  mParentWindowPausedDepth -= 1;
-  if (mParentWindowPausedDepth > 0) {
-    return;
-  }
+  MOZ_ASSERT(mParentWindowPaused);
+  mParentWindowPaused = false;
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mParentStatus >= Canceling) {
       return;
     }
   }
@@ -2183,43 +2079,16 @@ void
 WorkerPrivate::MemoryPressure(bool aDummy)
 {
   AssertIsOnParentThread();
 
   RefPtr<MemoryPressureRunnable> runnable = new MemoryPressureRunnable(this);
   Unused << NS_WARN_IF(!runnable->Dispatch());
 }
 
-bool
-WorkerPrivate::RegisterSharedWorker(SharedWorker* aSharedWorker,
-                                    MessagePort* aPort)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aSharedWorker);
-  MOZ_ASSERT(IsSharedWorker());
-  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
-
-  if (IsSharedWorker()) {
-    RefPtr<MessagePortRunnable> runnable = new MessagePortRunnable(this, aPort);
-    if (!runnable->Dispatch()) {
-      return false;
-    }
-  }
-
-  mSharedWorkers.AppendElement(aSharedWorker);
-
-  // If there were other SharedWorker objects attached to this worker then they
-  // may all have been frozen and this worker would need to be thawed.
-  if (mSharedWorkers.Length() > 1 && IsFrozen() && !Thaw(nullptr)) {
-    return false;
-  }
-
-  return true;
-}
-
 void
 WorkerPrivate::BroadcastErrorToSharedWorkers(
                                      JSContext* aCx,
                                      const WorkerErrorReport* aReport,
                                      bool aIsErrorEvent)
 {
   AssertIsOnMainThread();
 
@@ -2360,51 +2229,16 @@ WorkerPrivate::GetAllSharedWorkers(nsTAr
   }
 
   for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
     aSharedWorkers.AppendElement(mSharedWorkers[i]);
   }
 }
 
 void
-WorkerPrivate::CloseSharedWorkersForWindow(nsPIDOMWindowInner* aWindow)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-  MOZ_ASSERT(aWindow);
-
-  bool someRemoved = false;
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length();) {
-    if (mSharedWorkers[i]->GetOwner() == aWindow) {
-      mSharedWorkers[i]->Close();
-      mSharedWorkers.RemoveElementAt(i);
-      someRemoved = true;
-    } else {
-      MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-      ++i;
-    }
-  }
-
-  if (!someRemoved) {
-    return;
-  }
-
-  // If there are still SharedWorker objects attached to this worker then they
-  // may all be frozen and this worker would need to be frozen. Otherwise,
-  // if that was the last SharedWorker then it's time to cancel this worker.
-
-  if (!mSharedWorkers.IsEmpty()) {
-    Freeze(nullptr);
-  } else {
-    Cancel();
-  }
-}
-
-void
 WorkerPrivate::CloseAllSharedWorkers()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
 
   for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
     mSharedWorkers[i]->Close();
   }
@@ -2641,17 +2475,17 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
                                                    WorkerEventTarget::Behavior::Hybrid))
   , mParentStatus(Pending)
   , mStatus(Pending)
   , mBusyCount(0)
   , mLoadingWorkerScript(false)
   , mCreationTimeStamp(TimeStamp::Now())
   , mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
   , mWorkerThreadAccessible(aParent)
-  , mParentWindowPausedDepth(0)
+  , mParentWindowPaused(false)
   , mPendingEventQueueClearing(false)
   , mCancelAllPendingRunnables(false)
   , mWorkerScriptExecutedSuccessfully(false)
   , mFetchHandlerWasAdded(false)
   , mMainThreadObjectsForgotten(false)
   , mIsChromeWorker(aIsChromeWorker)
   , mParentFrozen(false)
   , mIsSecureContext(false)
@@ -2684,21 +2518,18 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
   else {
     AssertIsOnMainThread();
 
     RuntimeService::GetDefaultJSSettings(mJSSettings);
 
     // Our secure context state depends on the kind of worker we have.
     if (UsesSystemPrincipal() || IsServiceWorker()) {
       mIsSecureContext = true;
-    } else if (mLoadInfo.mWindow) {
-      // Shared and dedicated workers both inherit the loading window's secure
-      // context state.  Shared workers then prevent windows with a different
-      // secure context state from attaching to them.
-      mIsSecureContext = mLoadInfo.mWindow->IsSecureContext();
+    } else if (mLoadInfo.mSecureContext != WorkerLoadInfo::eNotSet) {
+      mIsSecureContext = mLoadInfo.mSecureContext == WorkerLoadInfo::eSecureContext;
     } else {
       MOZ_ASSERT_UNREACHABLE("non-chrome worker that is not a service worker "
                              "that has no parent and no associated window");
     }
 
     if (mIsSecureContext) {
       mJSSettings.chrome.realmOptions
                  .creationOptions().setSecureContext(true);
@@ -3051,16 +2882,20 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
 
       loadInfo.mFromWindow = true;
       loadInfo.mWindowID = globalWindow->WindowID();
       nsContentUtils::StorageAccess access =
         nsContentUtils::StorageAllowedForWindow(globalWindow);
       loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
       loadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(document);
       loadInfo.mParentController = globalWindow->GetController();
+      loadInfo.mSecureContext =
+        loadInfo.mWindow->IsSecureContext()
+          ? WorkerLoadInfo::eSecureContext
+          : WorkerLoadInfo::eInsecureContext;
     } else {
       // Not a window
       MOZ_ASSERT(isChrome);
 
       // We're being created outside of a window. Need to figure out the script
       // that is creating us in order for us to use relative URIs later on.
       JS::AutoFilename fileName;
       if (JS::DescribeScriptedCaller(aCx, &fileName)) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -718,17 +718,17 @@ public:
     AssertIsOnParentThread();
     return mParentFrozen;
   }
 
   bool
   IsParentWindowPaused() const
   {
     AssertIsOnParentThread();
-    return mParentWindowPausedDepth > 0;
+    return mParentWindowPaused;
   }
 
   // When we debug a worker, we want to disconnect the window and the worker
   // communication. This happens calling this method.
   // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
   void
   ParentWindowPaused();
 
@@ -1075,42 +1075,32 @@ public:
   // top level script.
   void
   SetLoadingWorkerScript(bool aLoadingWorkerScript)
   {
     // any thread
     mLoadingWorkerScript = aLoadingWorkerScript;
   }
 
-  bool
-  RegisterSharedWorker(SharedWorker* aSharedWorker, MessagePort* aPort);
-
   void
   BroadcastErrorToSharedWorkers(JSContext* aCx,
                                 const WorkerErrorReport* aReport,
                                 bool aIsErrorEvent);
 
   void
   GetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>& aSharedWorkers);
 
   void
-  CloseSharedWorkersForWindow(nsPIDOMWindowInner* aWindow);
-
-  void
   CloseAllSharedWorkers();
 
   void
   FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
 
   // 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.
-  //
-  // XXXbz: This is a bald-faced lie given the uses in RegisterSharedWorker and
-  // CloseSharedWorkersForWindow, which pass null for aWindow to Thaw and Freeze
-  // respectively.  See bug 1251722.
   bool
   Freeze(nsPIDOMWindowInner* aWindow);
 
   bool
   Thaw(nsPIDOMWindowInner* aWindow);
 
   void
   PropagateFirstPartyStorageAccessGranted();
@@ -1459,19 +1449,17 @@ private:
     bool mTimerRunning;
     bool mRunningExpiredTimeouts;
     bool mPeriodicGCTimerRunning;
     bool mIdleGCTimerRunning;
     bool mOnLine;
   };
   ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
 
-  // SharedWorkers may have multiple windows paused, so this must be
-  // a count instead of just a boolean.
-  uint32_t mParentWindowPausedDepth;
+  bool mParentWindowPaused;
 
   bool mPendingEventQueueClearing;
   bool mCancelAllPendingRunnables;
   bool mWorkerScriptExecutedSuccessfully;
   bool mFetchHandlerWasAdded;
   bool mMainThreadObjectsForgotten;
   bool mIsChromeWorker;
   bool mParentFrozen;
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -27,16 +27,17 @@ EXPORTS.mozilla.dom += [
     'WorkerScope.h',
 ]
 
 # Private stuff.
 EXPORTS.mozilla.dom.workerinternals += [
     'JSSettings.h',
     'Queue.h',
     'RuntimeService.h',
+    'ScriptLoader.h',
 ]
 
 XPIDL_MODULE = 'dom_workers'
 
 XPIDL_SOURCES += [
     'nsIWorkerDebugger.idl',
     'nsIWorkerDebuggerManager.idl',
 ]
--- a/dom/workers/sharedworkers/PSharedWorker.ipdl
+++ b/dom/workers/sharedworkers/PSharedWorker.ipdl
@@ -6,15 +6,23 @@ include protocol PBackground;
 
 namespace mozilla {
 namespace dom {
 
 protocol PSharedWorker
 {
   manager PBackground;
 
+parent:
+  async Close();
+  async Suspend();
+  async Resume();
+  async Freeze();
+  async Thaw();
+
 child:
-  // TODO:
+  async Error(nsresult error);
+
   async __delete__();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorker.cpp
+++ b/dom/workers/sharedworkers/SharedWorker.cpp
@@ -1,56 +1,61 @@
 /* -*- 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 "SharedWorker.h"
 
+#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/PMessagePort.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"
 #include "nsContentUtils.h"
+#include "nsGlobalWindowInner.h"
 #include "nsPIDOMWindow.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 SharedWorker::SharedWorker(nsPIDOMWindowInner* aWindow,
                            SharedWorkerChild* aActor,
                            MessagePort* aMessagePort)
   : DOMEventTargetHelper(aWindow)
+  , mWindow(aWindow)
   , mActor(aActor)
   , mMessagePort(aMessagePort)
   , mFrozen(false)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(aMessagePort);
 }
 
 SharedWorker::~SharedWorker()
 {
   AssertIsOnMainThread();
+  Close();
 }
 
 // static
 already_AddRefed<SharedWorker>
 SharedWorker::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aScriptURL,
                           const StringOrWorkerOptions& aOptions,
                           ErrorResult& aRv)
@@ -139,57 +144,88 @@ SharedWorker::Constructor(const GlobalOb
   aRv = loadInfo.mBaseURI->GetSpec(baseURL);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // Register this component to PBackground.
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
 
+  bool isSecureContext = JS::GetIsSecureContext(js::GetContextRealm(cx));
+
+  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, principalInfo,
-                                            loadInfo.mDomain, portIdentifier);
+                                            loadInfo.mDomain, isSecureContext,
+                                            ipcClientInfo, portIdentifier);
 
   PSharedWorkerChild* pActor =
     actorChild->SendPSharedWorkerConstructor(sharedWorkerLoadInfo);
 
   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.
+  nsGlobalWindowInner::Cast(window)->StoreSharedWorker(sharedWorker);
+  actor->SetParent(sharedWorker);
+
   return sharedWorker.forget();
 }
 
 MessagePort*
 SharedWorker::Port()
 {
   AssertIsOnMainThread();
   return mMessagePort;
 }
 
 void
 SharedWorker::Freeze()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!IsFrozen());
 
+  if (mFrozen) {
+    return;
+  }
+
   mFrozen = true;
+
+  if (mActor) {
+    mActor->SendFreeze();
+  }
 }
 
 void
 SharedWorker::Thaw()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(IsFrozen());
 
+  if (!mFrozen) {
+    return;
+  }
+
   mFrozen = false;
 
+  if (mActor) {
+    mActor->SendThaw();
+  }
+
   if (!mFrozenEvents.IsEmpty()) {
     nsTArray<RefPtr<Event>> events;
     mFrozenEvents.SwapElements(events);
 
     for (uint32_t index = 0; index < events.Length(); index++) {
       RefPtr<Event>& event = events[index];
       MOZ_ASSERT(event);
 
@@ -213,22 +249,49 @@ SharedWorker::QueueEvent(Event* aEvent)
   mFrozenEvents.AppendElement(aEvent);
 }
 
 void
 SharedWorker::Close()
 {
   AssertIsOnMainThread();
 
+  if (mWindow) {
+    nsGlobalWindowInner::Cast(mWindow)->ForgetSharedWorker(this);
+    mWindow = nullptr;
+  }
+
+  if (mActor) {
+    mActor->SendClose();
+    mActor->SetParent(nullptr);
+    mActor = nullptr;
+  }
+
   if (mMessagePort) {
     mMessagePort->Close();
   }
 }
 
 void
+SharedWorker::Suspend()
+{
+  if (mActor) {
+    mActor->SendSuspend();
+  }
+}
+
+void
+SharedWorker::Resume()
+{
+  if (mActor) {
+    mActor->SendResume();
+  }
+}
+
+void
 SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                           const Sequence<JSObject*>& aTransferable,
                           ErrorResult& aRv)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mMessagePort);
 
   mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
@@ -239,22 +302,24 @@ NS_IMPL_RELEASE_INHERITED(SharedWorker, 
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SharedWorker)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker,
                                                   DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrozenEvents)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker,
                                                 DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrozenEvents)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 JSObject*
 SharedWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   AssertIsOnMainThread();
@@ -279,8 +344,22 @@ SharedWorker::GetEventTargetParent(Event
 
     aVisitor.mCanHandle = false;
     aVisitor.SetParentTarget(nullptr, false);
     return;
   }
 
   DOMEventTargetHelper::GetEventTargetParent(aVisitor);
 }
+
+void
+SharedWorker::ErrorPropagation(nsresult aError)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mActor);
+  MOZ_ASSERT(NS_FAILED(aError));
+
+  RefPtr<AsyncEventDispatcher> errorEvent =
+    new AsyncEventDispatcher(this, NS_LITERAL_STRING("error"), CanBubble::eNo);
+  errorEvent->PostDOMEvent();
+
+  Close();
+}
--- a/dom/workers/sharedworkers/SharedWorker.h
+++ b/dom/workers/sharedworkers/SharedWorker.h
@@ -20,29 +20,24 @@ class nsPIDOMWindowInner;
 namespace mozilla {
 class EventChainPreVisitor;
 
 namespace dom {
 class MessagePort;
 class StringOrWorkerOptions;
 class Event;
 
-namespace workerinternals {
-class RuntimeService;
-}
-
 class SharedWorkerChild;
 
 class SharedWorker final : public DOMEventTargetHelper
 {
-  friend class workerinternals::RuntimeService;
-
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
 
+  RefPtr<nsPIDOMWindowInner> mWindow;
   RefPtr<SharedWorkerChild> mActor;
   RefPtr<MessagePort> mMessagePort;
   nsTArray<RefPtr<Event>> mFrozenEvents;
   bool mFrozen;
 
 public:
   static already_AddRefed<SharedWorker>
   Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
@@ -53,39 +48,49 @@ public:
 
   bool
   IsFrozen() const
   {
     return mFrozen;
   }
 
   void
-  Freeze();
-
-  void
-  Thaw();
-
-  void
   QueueEvent(Event* aEvent);
 
-  void
-  Close();
-
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SharedWorker, DOMEventTargetHelper)
 
   IMPL_EVENT_HANDLER(error)
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
 
+  void
+  ErrorPropagation(nsresult aError);
+
+  // Methods called from the window.
+
+  void
+  Close();
+
+  void
+  Suspend();
+
+  void
+  Resume();
+
+  void
+  Freeze();
+
+  void
+  Thaw();
+
 private:
-  // This class can only be created from the RuntimeService.
   SharedWorker(nsPIDOMWindowInner* aWindow,
                SharedWorkerChild* aActor,
                MessagePort* aMessagePort);
 
   // This class is reference-counted and will be destroyed from Release().
   ~SharedWorker();
 
   // Only called by MessagePort.
--- a/dom/workers/sharedworkers/SharedWorkerChild.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerChild.cpp
@@ -2,18 +2,83 @@
 /* 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 "SharedWorkerChild.h"
 
 namespace mozilla {
+
+using namespace ipc;
+
 namespace dom {
 
 SharedWorkerChild::SharedWorkerChild()
+  : mParent(nullptr)
+  , mActive(true)
 {
 }
 
 SharedWorkerChild::~SharedWorkerChild() = default;
 
+void
+SharedWorkerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActive = false;
+}
+
+void
+SharedWorkerChild::SendClose()
+{
+  if (mActive) {
+    // This is the last message.
+    mActive = false;
+    PSharedWorkerChild::SendClose();
+  }
+}
+
+void
+SharedWorkerChild::SendSuspend()
+{
+  if (mActive) {
+    PSharedWorkerChild::SendSuspend();
+  }
+}
+
+void
+SharedWorkerChild::SendResume()
+{
+  if (mActive) {
+    PSharedWorkerChild::SendResume();
+  }
+}
+
+void
+SharedWorkerChild::SendFreeze()
+{
+  if (mActive) {
+    PSharedWorkerChild::SendFreeze();
+  }
+}
+
+void
+SharedWorkerChild::SendThaw()
+{
+  if (mActive) {
+    PSharedWorkerChild::SendThaw();
+  }
+}
+
+IPCResult
+SharedWorkerChild::RecvError(const nsresult& aError)
+{
+  MOZ_ASSERT(mActive);
+
+  if (mParent) {
+    mParent->ErrorPropagation(aError);
+  }
+
+  return IPC_OK();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorkerChild.h
+++ b/dom/workers/sharedworkers/SharedWorkerChild.h
@@ -17,18 +17,47 @@ class SharedWorker;
 
 class SharedWorkerChild final : public mozilla::dom::PSharedWorkerChild
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(SharedWorkerChild)
 
   SharedWorkerChild();
 
+  void
+  SetParent(SharedWorker* aSharedWorker)
+  {
+    mParent = aSharedWorker;
+  }
+
+  void
+  SendClose();
+
+  void
+  SendSuspend();
+
+  void
+  SendResume();
+
+  void
+  SendFreeze();
+
+  void
+  SendThaw();
+
 private:
   ~SharedWorkerChild();
 
-  void ActorDestroy(ActorDestroyReason aWhy) override;
+  mozilla::ipc::IPCResult
+  RecvError(const nsresult& error) override;
+
+  void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  // Raw pointer because mParent is set to null when released.
+  SharedWorker* MOZ_NON_OWNING_REF mParent;
+  bool mActive;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_dom_SharedWorkerChild_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp
@@ -0,0 +1,359 @@
+/* -*- 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 "SharedWorkerManager.h"
+#include "SharedWorkerParent.h"
+#include "SharedWorkerService.h"
+#include "mozilla/dom/IndexedDatabaseManager.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRunnable.h"
+#include "mozilla/dom/workerinternals/ScriptLoader.h"
+#include "mozilla/ipc/BackgroundParent.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();
+  }
+};
+
+} // anonymous
+
+SharedWorkerManager::SharedWorkerManager(const SharedWorkerLoadInfo& aInfo,
+                                         nsIPrincipal* aPrincipal,
+                                         nsIPrincipal* aLoadingPrincipal)
+  : mInfo(aInfo)
+  , mPrincipal(aPrincipal)
+  , mLoadingPrincipal(aLoadingPrincipal)
+{
+  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());
+}
+
+nsresult
+SharedWorkerManager::CreateWorkerOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Ensure that the IndexedDatabaseManager is initialized
+  Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
+
+  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;
+  }
+
+  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);
+
+  rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
+  Maybe<ClientInfo> clientInfo;
+  if (mInfo.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
+    clientInfo.emplace(ClientInfo(mInfo.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,
+                                      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();
+  }
+
+  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;
+}
+
+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() &&
+         // 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));
+
+  mActors.AppendElement(aParent);
+}
+
+void
+SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aParent);
+  MOZ_ASSERT(mActors.Contains(aParent));
+
+  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);
+
+  // SharedWorkerService exists because it is kept alive by SharedWorkerParent.
+  SharedWorkerService::Get()->RemoveWorkerManager(this);
+}
+
+void
+SharedWorkerManager::UpdateSuspend()
+{
+  AssertIsOnBackgroundThread();
+
+  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);
+}
+
+void
+SharedWorkerManager::UpdateFrozen()
+{
+  AssertIsOnBackgroundThread();
+
+  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);
+}
+
+bool
+SharedWorkerManager::IsSecureContext() const
+{
+  return mInfo.isSecureContext();
+}
+
+void
+SharedWorkerManager::FreezeOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mWorkerPrivate);
+
+  mWorkerPrivate->Freeze(nullptr);
+}
+
+void
+SharedWorkerManager::ThawOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mWorkerPrivate);
+
+  mWorkerPrivate->Thaw(nullptr);
+}
+
+void
+SharedWorkerManager::SuspendOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mWorkerPrivate);
+
+  mWorkerPrivate->ParentWindowPaused();
+}
+
+void
+SharedWorkerManager::ResumeOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mWorkerPrivate);
+
+  mWorkerPrivate->ParentWindowResumed();
+}
+
+void
+SharedWorkerManager::CloseOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mWorkerPrivate);
+
+  mWorkerPrivate->Cancel();
+  mWorkerPrivate = nullptr;
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/sharedworkers/SharedWorkerManager.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_SharedWorkerManager_h
+#define mozilla_dom_SharedWorkerManager_h
+
+#include "nsISupportsImpl.h"
+#include "nsTArray.h"
+
+class nsIPrincipal;
+
+namespace mozilla {
+namespace dom {
+
+class SharedWorkerLoadInfo;
+class SharedWorkerParent;
+class WorkerPrivate;
+
+class SharedWorkerManager final
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManager);
+
+  // Called on main-thread thread methods
+
+  SharedWorkerManager(const SharedWorkerLoadInfo& aInfo,
+                      nsIPrincipal* aPrincipal,
+                      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();
+
+  void
+  ResumeOnMainThread();
+
+  // Called on PBackground thread methods
+
+  void
+  AddActor(SharedWorkerParent* aParent);
+
+  void
+  RemoveActor(SharedWorkerParent* aParent);
+
+  void
+  UpdateSuspend();
+
+  void
+  UpdateFrozen();
+
+  bool
+  IsSecureContext() const;
+
+private:
+  ~SharedWorkerManager();
+
+  SharedWorkerLoadInfo mInfo;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
+
+  // 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;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_SharedWorkerManager_h
--- a/dom/workers/sharedworkers/SharedWorkerParent.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp
@@ -1,29 +1,183 @@
 /* -*- 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 "SharedWorkerParent.h"
+#include "SharedWorkerManager.h"
+#include "SharedWorkerService.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/Unused.h"
 
 namespace mozilla {
 
-using ipc::PrincipalInfo;
+using namespace ipc;
 
 namespace dom {
 
 SharedWorkerParent::SharedWorkerParent()
+  : mBackgroundEventTarget(GetCurrentThreadEventTarget())
+  , mStatus(eInit)
+  , mSuspended(false)
+  , mFrozen(false)
 {
-  // TODO
+  AssertIsOnBackgroundThread();
 }
 
 SharedWorkerParent::~SharedWorkerParent() = default;
 
 void
 SharedWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason aReason)
 {
-  // TODO
+  AssertIsOnBackgroundThread();
+
+  if (mWorkerManager) {
+    mWorkerManager->RemoveActor(this);
+    mWorkerManager = nullptr;
+  }
+}
+
+void
+SharedWorkerParent::Initialize(const SharedWorkerLoadInfo& aInfo)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mStatus == eInit);
+
+  // Let's keep the service alive.
+  mService = SharedWorkerService::GetOrCreate();
+  MOZ_ASSERT(mService);
+
+  mStatus = ePending;
+  mService->GetOrCreateWorkerManager(this, aInfo);
+}
+
+IPCResult
+SharedWorkerParent::RecvClose()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
+
+  mStatus = eClosed;
+
+  if (mWorkerManager) {
+    mWorkerManager->RemoveActor(this);
+    mWorkerManager = nullptr;
+  }
+
+  Unused << Send__delete__(this);
+  return IPC_OK();
+}
+
+IPCResult
+SharedWorkerParent::RecvSuspend()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(!mSuspended);
+  MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
+
+  mSuspended = true;
+
+  if (mStatus == eActive) {
+    MOZ_ASSERT(mWorkerManager);
+    mWorkerManager->UpdateSuspend();
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+SharedWorkerParent::RecvResume()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mSuspended);
+  MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
+
+  mSuspended = false;
+
+  if (mStatus == eActive) {
+    MOZ_ASSERT(mWorkerManager);
+    mWorkerManager->UpdateSuspend();
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+SharedWorkerParent::RecvFreeze()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(!mFrozen);
+  MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
+
+  mFrozen = true;
+
+  if (mStatus == eActive) {
+    MOZ_ASSERT(mWorkerManager);
+    mWorkerManager->UpdateFrozen();
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+SharedWorkerParent::RecvThaw()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mFrozen);
+  MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
+
+  mFrozen = false;
+
+  if (mStatus == eActive) {
+    MOZ_ASSERT(mWorkerManager);
+    mWorkerManager->UpdateFrozen();
+  }
+
+  return IPC_OK();
+}
+
+void
+SharedWorkerParent::ManagerCreated(SharedWorkerManager* aWorkerManager)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aWorkerManager);
+  MOZ_ASSERT(!mWorkerManager);
+  MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
+
+  // Already gone.
+  if (mStatus == eClosed) {
+    aWorkerManager->RemoveActor(this);
+    return;
+  }
+
+  mStatus = eActive;
+  mWorkerManager = aWorkerManager;
+
+  if (mFrozen) {
+    mWorkerManager->UpdateFrozen();
+  }
+
+  if (mSuspended) {
+    mWorkerManager->UpdateSuspend();
+  }
+}
+
+void
+SharedWorkerParent::ErrorPropagation(nsresult aError)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(NS_FAILED(aError));
+  MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
+
+  // Already gone.
+  if (mStatus == eClosed) {
+    return;
+  }
+
+  Unused << SendError(aError);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorkerParent.h
+++ b/dom/workers/sharedworkers/SharedWorkerParent.h
@@ -9,26 +9,80 @@
 
 #include "mozilla/dom/PSharedWorkerParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
+class SharedWorkerLoadInfo;
+class SharedWorkerManager;
+class SharedWorkerService;
+
 class SharedWorkerParent final : public mozilla::dom::PSharedWorkerParent
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerParent)
 
   SharedWorkerParent();
 
+  void
+  Initialize(const SharedWorkerLoadInfo& aInfo);
+
+  void
+  ManagerCreated(SharedWorkerManager* aWorkerManager);
+
+  void
+  ErrorPropagation(nsresult aError);
+
+  mozilla::ipc::IPCResult
+  RecvClose() override;
+
+  mozilla::ipc::IPCResult
+  RecvSuspend() override;
+
+  mozilla::ipc::IPCResult
+  RecvResume() override;
+
+  mozilla::ipc::IPCResult
+  RecvFreeze() override;
+
+  mozilla::ipc::IPCResult
+  RecvThaw() override;
+
+  bool
+  IsSuspended() const
+  {
+    return mSuspended;
+  }
+
+  bool
+  IsFrozen() const
+  {
+    return mSuspended;
+  }
+
 private:
   ~SharedWorkerParent();
 
   void
   ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
+
+  nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+  RefPtr<SharedWorkerManager> mWorkerManager;
+  RefPtr<SharedWorkerService> mService;
+
+  enum {
+    eInit,
+    ePending,
+    eActive,
+    eClosed,
+  } mStatus;
+
+  bool mSuspended;
+  bool mFrozen;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_dom_SharedWorkerParent_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/sharedworkers/SharedWorkerService.cpp
@@ -0,0 +1,292 @@
+/* -*- 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/ipc/BackgroundParent.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/SystemGroup.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+namespace {
+
+StaticMutex sSharedWorkerMutex;
+
+// Raw pointer because SharedWorkerParent keeps this object alive.
+SharedWorkerService* MOZ_NON_OWNING_REF sSharedWorkerService;
+
+class GetOrCreateWorkerManagerRunnable final : public Runnable
+{
+public:
+  GetOrCreateWorkerManagerRunnable(SharedWorkerParent* aActor,
+                                   const SharedWorkerLoadInfo& aInfo)
+    : Runnable("GetOrCreateWorkerManagerRunnable")
+    , mBackgroundEventTarget(GetCurrentThreadEventTarget())
+    , mActor(aActor)
+    , mInfo(aInfo)
+  {}
+
+  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);
+
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+  RefPtr<SharedWorkerParent> mActor;
+  SharedWorkerLoadInfo mInfo;
+};
+
+class RemoveWorkerManagerRunnable final : public Runnable
+{
+public:
+  RemoveWorkerManagerRunnable(SharedWorkerService* aService,
+                              SharedWorkerManager* aManager)
+    : Runnable("RemoveWorkerManagerRunnable")
+    , mService(aService)
+    , mManager(aManager)
+  {
+    MOZ_ASSERT(mService);
+    MOZ_ASSERT(mManager);
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    mService->RemoveWorkerManagerOnMainThread(mManager);
+    return NS_OK;
+  }
+
+private:
+  RefPtr<SharedWorkerService> mService;
+  RefPtr<SharedWorkerManager> mManager;
+};
+
+class WorkerManagerCreatedRunnable final : public Runnable
+{
+public:
+  WorkerManagerCreatedRunnable(SharedWorkerManager* aManager,
+                               SharedWorkerParent* aActor)
+    : Runnable("WorkerManagerCreatedRunnable")
+    , mManager(aManager)
+    , mActor(aActor)
+  {}
+
+  NS_IMETHOD
+  Run()
+  {
+    AssertIsOnBackgroundThread();
+    mManager->AddActor(mActor);
+    mActor->ManagerCreated(mManager);
+    return NS_OK;
+  }
+
+private:
+  RefPtr<SharedWorkerManager> mManager;
+  RefPtr<SharedWorkerParent> mActor;
+};
+
+class ErrorPropagationRunnable final : public Runnable
+{
+public:
+  ErrorPropagationRunnable(SharedWorkerParent* aActor,
+                           nsresult aError)
+    : Runnable("ErrorPropagationRunnable")
+    , mActor(aActor)
+    , mError(aError)
+  {}
+
+  NS_IMETHOD
+  Run()
+  {
+    AssertIsOnBackgroundThread();
+    mActor->ErrorPropagation(mError);
+    return NS_OK;
+  }
+
+private:
+  RefPtr<SharedWorkerParent> mActor;
+  nsresult mError;
+};
+
+}
+
+/* static */ already_AddRefed<SharedWorkerService>
+SharedWorkerService::GetOrCreate()
+{
+  AssertIsOnBackgroundThread();
+
+  StaticMutexAutoLock lock(sSharedWorkerMutex);
+
+  if (sSharedWorkerService) {
+    RefPtr<SharedWorkerService> instance = sSharedWorkerService;
+    return  instance.forget();
+  }
+
+  RefPtr<SharedWorkerService> instance = new SharedWorkerService();
+  return instance.forget();
+}
+
+/* static */ SharedWorkerService*
+SharedWorkerService::Get()
+{
+  StaticMutexAutoLock lock(sSharedWorkerMutex);
+
+  MOZ_ASSERT(sSharedWorkerService);
+  return sSharedWorkerService;
+}
+
+SharedWorkerService::SharedWorkerService()
+{
+  AssertIsOnBackgroundThread();
+
+  MOZ_ASSERT(!sSharedWorkerService);
+  sSharedWorkerService = this;
+}
+
+SharedWorkerService::~SharedWorkerService()
+{
+  StaticMutexAutoLock lock(sSharedWorkerMutex);
+
+  MOZ_ASSERT(sSharedWorkerService == this);
+  sSharedWorkerService = nullptr;
+}
+
+void
+SharedWorkerService::GetOrCreateWorkerManager(SharedWorkerParent* aActor,
+                                              const SharedWorkerLoadInfo& aInfo)
+{
+  AssertIsOnBackgroundThread();
+
+  // The real check happens on main-thread.
+  RefPtr<GetOrCreateWorkerManagerRunnable> r =
+    new GetOrCreateWorkerManagerRunnable(aActor, aInfo);
+
+  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)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aBackgroundEventTarget);
+  MOZ_ASSERT(aActor);
+
+  RefPtr<SharedWorkerManager> manager;
+
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(aInfo.principalInfo(), &rv);
+  if (NS_WARN_IF(!principal)) {
+    ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> loadingPrincipal =
+    PrincipalInfoToPrincipal(aInfo.loadingPrincipalInfo(), &rv);
+  if (NS_WARN_IF(!principal)) {
+    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)) {
+      manager = workerManager;
+      break;
+    }
+  }
+
+  // Let's create a new one.
+  if (!manager) {
+    manager = new SharedWorkerManager(aInfo, principal, loadingPrincipal);
+
+    rv = manager->CreateWorkerOnMainThread();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
+      return;
+    }
+
+    mWorkerManagers.AppendElement(manager);
+  } else {
+    // We are attaching the actor to an existing one.
+    if (manager->IsSecureContext() != aInfo.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);
+  aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+SharedWorkerService::ErrorPropagationOnMainThread(nsIEventTarget* aBackgroundEventTarget,
+                                                  SharedWorkerParent* aActor,
+                                                  nsresult aError)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aBackgroundEventTarget);
+  MOZ_ASSERT(aActor);
+  MOZ_ASSERT(NS_FAILED(aError));
+
+  RefPtr<ErrorPropagationRunnable> r =
+    new ErrorPropagationRunnable(aActor, aError);
+  aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+SharedWorkerService::RemoveWorkerManager(SharedWorkerManager* aManager)
+{
+  AssertIsOnBackgroundThread();
+
+  // We pass 'this' in order to be kept alive.
+  RefPtr<RemoveWorkerManagerRunnable> r =
+    new RemoveWorkerManagerRunnable(this, aManager);
+
+  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::RemoveWorkerManagerOnMainThread(SharedWorkerManager* aManager)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(mWorkerManagers.Contains(aManager));
+
+  mWorkerManagers.RemoveElement(aManager);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/sharedworkers/SharedWorkerService.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_SharedWorkerService_h
+#define mozilla_dom_SharedWorkerService_h
+
+#include "nsISupportsImpl.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+
+namespace ipc {
+class PrincipalInfo;
+}
+
+namespace dom {
+
+class SharedWorkerManager;
+class SharedWorkerParent;
+
+class SharedWorkerService final
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerService);
+
+  // This can be called on PBackground thread only.
+  static already_AddRefed<SharedWorkerService>
+  GetOrCreate();
+
+  // 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);
+
+  void
+  GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackgroundEventTarget,
+                                       SharedWorkerParent* aActor,
+                                       const SharedWorkerLoadInfo& aInfo);
+
+  // PBackground method only.
+  void
+  RemoveWorkerManager(SharedWorkerManager* aManager);
+
+  void
+  RemoveWorkerManagerOnMainThread(SharedWorkerManager* aManager);
+
+private:
+  SharedWorkerService();
+  ~SharedWorkerService();
+
+  void
+  ErrorPropagationOnMainThread(nsIEventTarget* aBackgroundEventTarget,
+                               SharedWorkerParent* aActor,
+                               nsresult aError);
+
+  // Touched on main-thread only.
+  nsTArray<RefPtr<SharedWorkerManager>> mWorkerManagers;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_SharedWorkerService_h
--- a/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
+++ b/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh
@@ -1,12 +1,13 @@
 /* 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 {
 
@@ -18,13 +19,17 @@ struct SharedWorkerLoadInfo
 
   nsString name;
 
   PrincipalInfo loadingPrincipalInfo;
   PrincipalInfo principalInfo;
 
   nsCString domain;
 
+  bool isSecureContext;
+
+  OptionalIPCClientInfo clientInfo;
+
   MessagePortIdentifier portIdentifier;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/sharedworkers/moz.build
+++ b/dom/workers/sharedworkers/moz.build
@@ -8,17 +8,19 @@ EXPORTS.mozilla.dom += [
     'SharedWorker.h',
     'SharedWorkerChild.h',
     'SharedWorkerParent.h',
 ]
 
 UNIFIED_SOURCES += [
     'SharedWorker.cpp',
     'SharedWorkerChild.cpp',
+    'SharedWorkerManager.cpp',
     'SharedWorkerParent.cpp',
+    'SharedWorkerService.cpp',
 ]
 
 IPDL_SOURCES += [
     'PSharedWorker.ipdl',
     'SharedWorkerTypes.ipdlh',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -390,16 +390,26 @@ BackgroundParentImpl::DeallocPPendingIPC
 mozilla::dom::PSharedWorkerParent*
 BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo)
 {
   RefPtr<dom::SharedWorkerParent> agent =
     new mozilla::dom::SharedWorkerParent();
   return agent.forget().take();
 }
 
+IPCResult
+BackgroundParentImpl::RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
+                                                   const mozilla::dom::SharedWorkerLoadInfo& aInfo)
+{
+  mozilla::dom::SharedWorkerParent* actor =
+    static_cast<mozilla::dom::SharedWorkerParent*>(aActor);
+  actor->Initialize(aInfo);
+  return IPC_OK();
+}
+
 bool
 BackgroundParentImpl::DeallocPSharedWorkerParent(mozilla::dom::PSharedWorkerParent* aActor)
 {
   RefPtr<mozilla::dom::SharedWorkerParent> actor =
     dont_AddRef(static_cast<mozilla::dom::SharedWorkerParent*>(aActor));
   return true;
 }
 
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -131,16 +131,20 @@ protected:
   RecvPTemporaryIPCBlobConstructor(PTemporaryIPCBlobParent* actor) override;
 
   virtual bool
   DeallocPTemporaryIPCBlobParent(PTemporaryIPCBlobParent* aActor) override;
 
   virtual mozilla::dom::PSharedWorkerParent*
   AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
+                               const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
+
   virtual bool
   DeallocPSharedWorkerParent(PSharedWorkerParent* aActor) override;
 
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const FileDescriptor& aFileDescriptor)
                                 override;
 
   virtual bool