Bug 1641812 - Apply pointer guidelines to RuntimeService.cpp r=sg,dom-workers-and-storage-reviewers,asuth
authorYaron Tausky <ytausky@mozilla.com>
Tue, 02 Jun 2020 08:53:52 +0000
changeset 597609 a8654b179f2bfce9a4b6698d16583510458afeb7
parent 597608 d29525eebe79ccc056a9e7bb668fd1007934f731
child 597610 655e0b63e61ef91e16865bec4f6fc86da8850cbb
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssg, dom-workers-and-storage-reviewers, asuth
bugs1641812
milestone79.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 1641812 - Apply pointer guidelines to RuntimeService.cpp r=sg,dom-workers-and-storage-reviewers,asuth Differential Revision: https://phabricator.services.mozilla.com/D77431
dom/base/nsGlobalWindowInner.cpp
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/WorkerCommon.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerThread.cpp
dom/workers/WorkerThread.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1054,17 +1054,17 @@ void nsGlobalWindowInner::FreeInnerObjec
   // other members that the window destroyed observers could
   // re-create.
   NotifyDOMWindowDestroyed(this);
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
     reporter->ObserveDOMWindowDetached(this);
   }
 
   // Kill all of the workers for this window.
-  CancelWorkersForWindow(this);
+  CancelWorkersForWindow(*this);
 
   nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator iter(
       mSharedWorkers);
   while (iter.HasMore()) {
     iter.GetNext()->Close();
   }
 
   if (mTimeoutManager) {
@@ -5183,17 +5183,17 @@ void nsGlobalWindowInner::Suspend() {
   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   if (ac) {
     for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
       ac->RemoveWindowListener(mEnabledSensors[i], this);
   }
   DisableGamepadUpdates();
   DisableVRUpdates();
 
-  SuspendWorkersForWindow(this);
+  SuspendWorkersForWindow(*this);
 
   nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator iter(
       mSharedWorkers);
   while (iter.HasMore()) {
     iter.GetNext()->Suspend();
   }
 
   SuspendIdleRequests();
@@ -5253,17 +5253,17 @@ void 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);
+  ResumeWorkersForWindow(*this);
 
   nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator iter(
       mSharedWorkers);
   while (iter.HasMore()) {
     iter.GetNext()->Resume();
   }
 }
 
@@ -5288,17 +5288,17 @@ void nsGlobalWindowInner::FreezeInternal
   CallOnInProcessChildren(&nsGlobalWindowInner::FreezeInternal);
 
   mFreezeDepth += 1;
   MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
   if (mFreezeDepth != 1) {
     return;
   }
 
-  FreezeWorkersForWindow(this);
+  FreezeWorkersForWindow(*this);
 
   nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator iter(
       mSharedWorkers);
   while (iter.HasMore()) {
     iter.GetNext()->Freeze();
   }
 
   mTimeoutManager->Freeze();
@@ -5329,17 +5329,17 @@ void nsGlobalWindowInner::ThawInternal()
     return;
   }
 
   if (mClientSource) {
     mClientSource->Thaw();
   }
   mTimeoutManager->Thaw();
 
-  ThawWorkersForWindow(this);
+  ThawWorkersForWindow(*this);
 
   nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator iter(
       mSharedWorkers);
   while (iter.HasMore()) {
     iter.GetNext()->Thaw();
   }
 
   NotifyDOMWindowThawed(this);
@@ -7179,17 +7179,17 @@ void nsGlobalWindowInner::StoreSharedWor
 void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) {
   MOZ_ASSERT(aSharedWorker);
   MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
 
   mSharedWorkers.RemoveElement(aSharedWorker);
 }
 
 void nsGlobalWindowInner::StorageAccessGranted() {
-  PropagateFirstPartyStorageAccessGrantedToWorkers(this);
+  PropagateFirstPartyStorageAccessGrantedToWorkers(*this);
 
   // If we have a partitioned localStorage, it's time to replace it with a real
   // one in order to receive notifications.
 
   if (mLocalStorage) {
     IgnoredErrorResult error;
     GetLocalStorage(error);
     if (NS_WARN_IF(error.Failed())) {
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -970,46 +970,47 @@ class WorkerJSContext final : public moz
 };
 
 namespace workerinternals {
 
 namespace {
 
 class WorkerThreadPrimaryRunnable final : public Runnable {
   WorkerPrivate* mWorkerPrivate;
-  RefPtr<WorkerThread> mThread;
+  SafeRefPtr<WorkerThread> mThread;
   JSRuntime* mParentRuntime;
 
   class FinishedRunnable final : public Runnable {
-    RefPtr<WorkerThread> mThread;
+    SafeRefPtr<WorkerThread> mThread;
 
    public:
-    explicit FinishedRunnable(already_AddRefed<WorkerThread> aThread)
+    explicit FinishedRunnable(SafeRefPtr<WorkerThread> aThread)
         : Runnable("WorkerThreadPrimaryRunnable::FinishedRunnable"),
-          mThread(aThread) {
+          mThread(std::move(aThread)) {
       MOZ_ASSERT(mThread);
     }
 
     NS_INLINE_DECL_REFCOUNTING_INHERITED(FinishedRunnable, Runnable)
 
    private:
     ~FinishedRunnable() = default;
 
     NS_DECL_NSIRUNNABLE
   };
 
  public:
   WorkerThreadPrimaryRunnable(WorkerPrivate* aWorkerPrivate,
-                              WorkerThread* aThread, JSRuntime* aParentRuntime)
+                              SafeRefPtr<WorkerThread> aThread,
+                              JSRuntime* aParentRuntime)
       : mozilla::Runnable("WorkerThreadPrimaryRunnable"),
         mWorkerPrivate(aWorkerPrivate),
-        mThread(aThread),
+        mThread(std::move(aThread)),
         mParentRuntime(aParentRuntime) {
     MOZ_ASSERT(aWorkerPrivate);
-    MOZ_ASSERT(aThread);
+    MOZ_ASSERT(mThread);
   }
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThreadPrimaryRunnable, Runnable)
 
  private:
   ~WorkerThreadPrimaryRunnable() = default;
 
   NS_DECL_NSIRUNNABLE
@@ -1105,41 +1106,41 @@ RuntimeService* RuntimeService::GetOrCre
   }
 
   return gRuntimeService;
 }
 
 // static
 RuntimeService* RuntimeService::GetService() { return gRuntimeService; }
 
-bool RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) {
-  aWorkerPrivate->AssertIsOnParentThread();
-
-  WorkerPrivate* parent = aWorkerPrivate->GetParent();
+bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) {
+  aWorkerPrivate.AssertIsOnParentThread();
+
+  WorkerPrivate* parent = aWorkerPrivate.GetParent();
   if (!parent) {
     AssertIsOnMainThread();
 
     if (mShuttingDown) {
       return false;
     }
   }
 
-  const bool isServiceWorker = aWorkerPrivate->IsServiceWorker();
-  const bool isSharedWorker = aWorkerPrivate->IsSharedWorker();
-  const bool isDedicatedWorker = aWorkerPrivate->IsDedicatedWorker();
+  const bool isServiceWorker = aWorkerPrivate.IsServiceWorker();
+  const bool isSharedWorker = aWorkerPrivate.IsSharedWorker();
+  const bool isDedicatedWorker = aWorkerPrivate.IsDedicatedWorker();
   if (isServiceWorker) {
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1);
   }
 
   nsCString sharedWorkerScriptSpec;
   if (isSharedWorker) {
     AssertIsOnMainThread();
 
-    nsCOMPtr<nsIURI> scriptURI = aWorkerPrivate->GetResolvedScriptURI();
+    nsCOMPtr<nsIURI> scriptURI = aWorkerPrivate.GetResolvedScriptURI();
     NS_ASSERTION(scriptURI, "Null script URI!");
 
     nsresult rv = scriptURI->GetSpec(sharedWorkerScriptSpec);
     if (NS_FAILED(rv)) {
       NS_WARNING("GetSpec failed?!");
       return false;
     }
 
@@ -1148,17 +1149,17 @@ bool RuntimeService::RegisterWorker(Work
 
   bool exemptFromPerDomainMax = false;
   if (isServiceWorker) {
     AssertIsOnMainThread();
     exemptFromPerDomainMax = Preferences::GetBool(
         "dom.serviceWorkers.exemptFromPerDomainMax", false);
   }
 
-  const nsCString& domain = aWorkerPrivate->Domain();
+  const nsCString& domain = aWorkerPrivate.Domain();
 
   bool queued = false;
   {
     MutexAutoLock lock(mMutex);
 
     const auto& domainInfo =
         mDomainMap.LookupForAdd(domain).OrInsert([&domain, parent]() {
           NS_ASSERTION(!parent, "Shouldn't have a parent here!");
@@ -1169,126 +1170,126 @@ bool RuntimeService::RegisterWorker(Work
           return wdi;
         });
 
     queued = gMaxWorkersPerDomain &&
              domainInfo->ActiveWorkerCount() >= gMaxWorkersPerDomain &&
              !domain.IsEmpty() && !exemptFromPerDomainMax;
 
     if (queued) {
-      domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate);
+      domainInfo->mQueuedWorkers.AppendElement(&aWorkerPrivate);
 
       // Worker spawn gets queued due to hitting max workers per domain
       // limit so let's log a warning.
       WorkerPrivate::ReportErrorToConsole("HittingMaxWorkersPerDomain2");
 
       if (isServiceWorker) {
         Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
       } else if (isSharedWorker) {
         Telemetry::Accumulate(Telemetry::SHARED_WORKER_SPAWN_GETS_QUEUED, 1);
       } else if (isDedicatedWorker) {
         Telemetry::Accumulate(Telemetry::DEDICATED_WORKER_SPAWN_GETS_QUEUED, 1);
       }
     } else if (parent) {
       domainInfo->mChildWorkerCount++;
     } else if (isServiceWorker) {
-      domainInfo->mActiveServiceWorkers.AppendElement(aWorkerPrivate);
+      domainInfo->mActiveServiceWorkers.AppendElement(&aWorkerPrivate);
     } else {
-      domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
+      domainInfo->mActiveWorkers.AppendElement(&aWorkerPrivate);
     }
   }
 
   // From here on out we must call UnregisterWorker if something fails!
   if (parent) {
-    if (!parent->AddChildWorker(aWorkerPrivate)) {
+    if (!parent->AddChildWorker(&aWorkerPrivate)) {
       UnregisterWorker(aWorkerPrivate);
       return false;
     }
   } else {
     if (!mNavigatorPropertiesLoaded) {
       Navigator::AppName(mNavigatorProperties.mAppName,
-                         aWorkerPrivate->GetPrincipal(),
+                         aWorkerPrivate.GetPrincipal(),
                          false /* aUsePrefOverriddenValue */);
       if (NS_FAILED(Navigator::GetAppVersion(
-              mNavigatorProperties.mAppVersion, aWorkerPrivate->GetPrincipal(),
+              mNavigatorProperties.mAppVersion, aWorkerPrivate.GetPrincipal(),
               false /* aUsePrefOverriddenValue */)) ||
           NS_FAILED(Navigator::GetPlatform(
-              mNavigatorProperties.mPlatform, aWorkerPrivate->GetPrincipal(),
+              mNavigatorProperties.mPlatform, aWorkerPrivate.GetPrincipal(),
               false /* aUsePrefOverriddenValue */))) {
         UnregisterWorker(aWorkerPrivate);
         return false;
       }
 
       // The navigator overridden properties should have already been read.
 
       Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages);
       mNavigatorPropertiesLoaded = true;
     }
 
-    nsPIDOMWindowInner* window = aWorkerPrivate->GetWindow();
+    nsPIDOMWindowInner* window = aWorkerPrivate.GetWindow();
 
     if (!isServiceWorker) {
       // Service workers are excluded since their lifetime is separate from
       // that of dom windows.
       const auto& windowArray = mWindowMap.LookupForAdd(window).OrInsert(
           []() { return new nsTArray<WorkerPrivate*>(1); });
-      if (!windowArray->Contains(aWorkerPrivate)) {
-        windowArray->AppendElement(aWorkerPrivate);
+      if (!windowArray->Contains(&aWorkerPrivate)) {
+        windowArray->AppendElement(&aWorkerPrivate);
       } else {
-        MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
+        MOZ_ASSERT(aWorkerPrivate.IsSharedWorker());
       }
     }
   }
 
   if (!queued && !ScheduleWorker(aWorkerPrivate)) {
     return false;
   }
 
   if (isServiceWorker) {
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1);
   }
   return true;
 }
 
-void RuntimeService::UnregisterWorker(WorkerPrivate* aWorkerPrivate) {
-  aWorkerPrivate->AssertIsOnParentThread();
-
-  WorkerPrivate* parent = aWorkerPrivate->GetParent();
+void RuntimeService::UnregisterWorker(WorkerPrivate& aWorkerPrivate) {
+  aWorkerPrivate.AssertIsOnParentThread();
+
+  WorkerPrivate* parent = aWorkerPrivate.GetParent();
   if (!parent) {
     AssertIsOnMainThread();
   }
 
-  const nsCString& domain = aWorkerPrivate->Domain();
+  const nsCString& domain = aWorkerPrivate.Domain();
 
   WorkerPrivate* queuedWorker = nullptr;
   {
     MutexAutoLock lock(mMutex);
 
     WorkerDomainInfo* domainInfo;
     if (!mDomainMap.Get(domain, &domainInfo)) {
       NS_ERROR("Don't have an entry for this domain!");
     }
 
     // Remove old worker from everywhere.
-    uint32_t index = domainInfo->mQueuedWorkers.IndexOf(aWorkerPrivate);
+    uint32_t index = domainInfo->mQueuedWorkers.IndexOf(&aWorkerPrivate);
     if (index != kNoIndex) {
       // Was queued, remove from the list.
       domainInfo->mQueuedWorkers.RemoveElementAt(index);
     } else if (parent) {
       MOZ_ASSERT(domainInfo->mChildWorkerCount, "Must be non-zero!");
       domainInfo->mChildWorkerCount--;
-    } else if (aWorkerPrivate->IsServiceWorker()) {
-      MOZ_ASSERT(domainInfo->mActiveServiceWorkers.Contains(aWorkerPrivate),
+    } else if (aWorkerPrivate.IsServiceWorker()) {
+      MOZ_ASSERT(domainInfo->mActiveServiceWorkers.Contains(&aWorkerPrivate),
                  "Don't know about this worker!");
-      domainInfo->mActiveServiceWorkers.RemoveElement(aWorkerPrivate);
+      domainInfo->mActiveServiceWorkers.RemoveElement(&aWorkerPrivate);
     } else {
-      MOZ_ASSERT(domainInfo->mActiveWorkers.Contains(aWorkerPrivate),
+      MOZ_ASSERT(domainInfo->mActiveWorkers.Contains(&aWorkerPrivate),
                  "Don't know about this worker!");
-      domainInfo->mActiveWorkers.RemoveElement(aWorkerPrivate);
+      domainInfo->mActiveWorkers.RemoveElement(&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);
 
@@ -1302,76 +1303,74 @@ void RuntimeService::UnregisterWorker(Wo
     }
 
     if (domainInfo->HasNoWorkers()) {
       MOZ_ASSERT(domainInfo->mQueuedWorkers.IsEmpty());
       mDomainMap.Remove(domain);
     }
   }
 
-  if (aWorkerPrivate->IsServiceWorker()) {
+  if (aWorkerPrivate.IsServiceWorker()) {
     AssertIsOnMainThread();
     Telemetry::AccumulateTimeDelta(Telemetry::SERVICE_WORKER_LIFE_TIME,
-                                   aWorkerPrivate->CreationTimeStamp());
+                                   aWorkerPrivate.CreationTimeStamp());
   }
 
   // NB: For Shared Workers we used to call ShutdownOnMainThread on the
   // RemoteWorkerController; however, that was redundant because
   // RemoteWorkerChild uses a WeakWorkerRef which notifies at about the
   // same time as us calling into the code here and would race with us.
 
   if (parent) {
-    parent->RemoveChildWorker(aWorkerPrivate);
-  } else if (aWorkerPrivate->IsSharedWorker()) {
+    parent->RemoveChildWorker(&aWorkerPrivate);
+  } else if (aWorkerPrivate.IsSharedWorker()) {
     AssertIsOnMainThread();
 
     for (auto iter = mWindowMap.Iter(); !iter.Done(); iter.Next()) {
       const auto& workers = iter.Data();
       MOZ_ASSERT(workers);
 
-      if (workers->RemoveElement(aWorkerPrivate)) {
-        MOZ_ASSERT(!workers->Contains(aWorkerPrivate),
+      if (workers->RemoveElement(&aWorkerPrivate)) {
+        MOZ_ASSERT(!workers->Contains(&aWorkerPrivate),
                    "Added worker more than once!");
 
         if (workers->IsEmpty()) {
           iter.Remove();
         }
       }
     }
-  } else if (aWorkerPrivate->IsDedicatedWorker()) {
+  } else if (aWorkerPrivate.IsDedicatedWorker()) {
     // May be null.
-    nsPIDOMWindowInner* window = aWorkerPrivate->GetWindow();
+    nsPIDOMWindowInner* window = aWorkerPrivate.GetWindow();
     if (auto entry = mWindowMap.Lookup(window)) {
-      MOZ_ALWAYS_TRUE(entry.Data()->RemoveElement(aWorkerPrivate));
+      MOZ_ALWAYS_TRUE(entry.Data()->RemoveElement(&aWorkerPrivate));
       if (entry.Data()->IsEmpty()) {
         entry.Remove();
       }
     } else {
       MOZ_ASSERT_UNREACHABLE("window is not in mWindowMap");
     }
   }
 
-  if (queuedWorker && !ScheduleWorker(queuedWorker)) {
-    UnregisterWorker(queuedWorker);
+  if (queuedWorker && !ScheduleWorker(*queuedWorker)) {
+    UnregisterWorker(*queuedWorker);
   }
 }
 
-bool RuntimeService::ScheduleWorker(WorkerPrivate* aWorkerPrivate) {
-  if (!aWorkerPrivate->Start()) {
+bool RuntimeService::ScheduleWorker(WorkerPrivate& aWorkerPrivate) {
+  if (!aWorkerPrivate.Start()) {
     // This is ok, means that we didn't need to make a thread for this worker.
     return true;
   }
 
-  RefPtr<WorkerThread> thread;
+  SafeRefPtr<WorkerThread> thread;
   {
     MutexAutoLock lock(mMutex);
     if (!mIdleThreadArray.IsEmpty()) {
-      uint32_t index = mIdleThreadArray.Length() - 1;
-      mIdleThreadArray[index].mThread.swap(thread);
-      mIdleThreadArray.RemoveElementAt(index);
+      thread = mIdleThreadArray.PopLastElement().mThread;
     }
   }
 
   const WorkerThreadFriendKey friendKey;
 
   if (!thread) {
     thread = WorkerThread::Create(friendKey);
     if (!thread) {
@@ -1379,20 +1378,20 @@ bool RuntimeService::ScheduleWorker(Work
       return false;
     }
   }
 
   if (NS_FAILED(thread->SetPriority(nsISupportsPriority::PRIORITY_NORMAL))) {
     NS_WARNING("Could not set the thread's priority!");
   }
 
-  aWorkerPrivate->SetThread(thread);
+  aWorkerPrivate.SetThread(thread.unsafeGetRawPtr());
   JSContext* cx = CycleCollectedJSContext::Get()->Context();
   nsCOMPtr<nsIRunnable> runnable = new WorkerThreadPrimaryRunnable(
-      aWorkerPrivate, thread, JS_GetParentRuntime(cx));
+      &aWorkerPrivate, thread.clonePtr(), JS_GetParentRuntime(cx));
   if (NS_FAILED(
           thread->DispatchPrimaryRunnable(friendKey, runnable.forget()))) {
     UnregisterWorker(aWorkerPrivate);
     return false;
   }
 
   return true;
 }
@@ -1407,30 +1406,29 @@ void RuntimeService::ShutdownIdleThreads
 
   NS_ASSERTION(aTimer == runtime->mIdleThreadTimer, "Wrong timer!");
 
   // Cheat a little and grab all threads that expire within one second of now.
   TimeStamp now = TimeStamp::NowLoRes() + TimeDuration::FromSeconds(1);
 
   TimeStamp nextExpiration;
 
-  AutoTArray<RefPtr<WorkerThread>, 20> expiredThreads;
+  AutoTArray<SafeRefPtr<WorkerThread>, 20> expiredThreads;
   {
     MutexAutoLock lock(runtime->mMutex);
 
     for (uint32_t index = 0; index < runtime->mIdleThreadArray.Length();
          index++) {
       IdleThreadInfo& info = runtime->mIdleThreadArray[index];
       if (info.mExpirationTime > now) {
         nextExpiration = info.mExpirationTime;
         break;
       }
 
-      RefPtr<WorkerThread>* thread = expiredThreads.AppendElement();
-      thread->swap(info.mThread);
+      expiredThreads.AppendElement(std::move(info.mThread));
     }
 
     if (!expiredThreads.IsEmpty()) {
       runtime->mIdleThreadArray.RemoveElementsAt(0, expiredThreads.Length());
     }
   }
 
   if (!nextExpiration.IsNull()) {
@@ -1747,24 +1745,24 @@ void RuntimeService::Cleanup() {
     AddAllTopLevelWorkersToArray(workers);
 
     if (!workers.IsEmpty()) {
       nsIThread* currentThread = NS_GetCurrentThread();
       NS_ASSERTION(currentThread, "This should never be null!");
 
       // Shut down any idle threads.
       if (!mIdleThreadArray.IsEmpty()) {
-        AutoTArray<RefPtr<WorkerThread>, 20> idleThreads;
+        AutoTArray<SafeRefPtr<WorkerThread>, 20> idleThreads;
 
         uint32_t idleThreadCount = mIdleThreadArray.Length();
         idleThreads.SetLength(idleThreadCount);
 
         for (uint32_t index = 0; index < idleThreadCount; index++) {
           NS_ASSERTION(mIdleThreadArray[index].mThread, "Null thread!");
-          idleThreads[index].swap(mIdleThreadArray[index].mThread);
+          idleThreads[index] = std::move(mIdleThreadArray[index].mThread);
         }
 
         mIdleThreadArray.Clear();
 
         MutexAutoUnlock unlock(mMutex);
 
         for (uint32_t index = 0; index < idleThreadCount; index++) {
           if (NS_FAILED(idleThreads[index]->Shutdown())) {
@@ -1868,113 +1866,102 @@ void RuntimeService::AddAllTopLevelWorke
       WorkerPrivate* worker = aData->mQueuedWorkers[index];
       if (!worker->GetParent()) {
         aWorkers.AppendElement(worker);
       }
     }
   }
 }
 
-void RuntimeService::GetWorkersForWindow(nsPIDOMWindowInner* aWindow,
-                                         nsTArray<WorkerPrivate*>& aWorkers) {
+nsTArray<WorkerPrivate*> RuntimeService::GetWorkersForWindow(
+    const nsPIDOMWindowInner& aWindow) const {
   AssertIsOnMainThread();
 
-  nsTArray<WorkerPrivate*>* workers;
-  if (mWindowMap.Get(aWindow, &workers)) {
+  nsTArray<WorkerPrivate*> result;
+  if (nsTArray<WorkerPrivate*>* const workers = mWindowMap.Get(&aWindow)) {
     NS_ASSERTION(!workers->IsEmpty(), "Should have been removed!");
-    aWorkers.AppendElements(*workers);
-  } else {
-    NS_ASSERTION(aWorkers.IsEmpty(), "Should be empty!");
+    result.AppendElements(*workers);
   }
+  return result;
 }
 
-void RuntimeService::CancelWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void RuntimeService::CancelWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
 
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   if (!workers.IsEmpty()) {
     for (uint32_t index = 0; index < workers.Length(); index++) {
-      WorkerPrivate*& worker = workers[index];
+      WorkerPrivate* const& worker = workers[index];
       MOZ_ASSERT(!worker->IsSharedWorker());
       worker->Cancel();
     }
   }
 }
 
-void RuntimeService::FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void RuntimeService::FreezeWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aWindow);
-
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     MOZ_ASSERT(!workers[index]->IsSharedWorker());
-    workers[index]->Freeze(aWindow);
+    workers[index]->Freeze(&aWindow);
   }
 }
 
-void RuntimeService::ThawWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void RuntimeService::ThawWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aWindow);
-
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     MOZ_ASSERT(!workers[index]->IsSharedWorker());
-    workers[index]->Thaw(aWindow);
+    workers[index]->Thaw(&aWindow);
   }
 }
 
-void RuntimeService::SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void RuntimeService::SuspendWorkersForWindow(
+    const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aWindow);
-
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowPaused();
   }
 }
 
-void RuntimeService::ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void RuntimeService::ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aWindow);
-
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowResumed();
   }
 }
 
 void RuntimeService::PropagateFirstPartyStorageAccessGranted(
-    nsPIDOMWindowInner* aWindow) {
+    const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aWindow);
-  MOZ_ASSERT_IF(aWindow->GetExtantDoc(), aWindow->GetExtantDoc()
-                                             ->CookieJarSettings()
-                                             ->GetRejectThirdPartyContexts());
-
-  nsTArray<WorkerPrivate*> workers;
-  GetWorkersForWindow(aWindow, workers);
+  MOZ_ASSERT_IF(aWindow.GetExtantDoc(), aWindow.GetExtantDoc()
+                                            ->CookieJarSettings()
+                                            ->GetRejectThirdPartyContexts());
+
+  const nsTArray<WorkerPrivate*> workers = GetWorkersForWindow(aWindow);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
 
-void RuntimeService::NoteIdleThread(WorkerThread* aThread) {
+void RuntimeService::NoteIdleThread(SafeRefPtr<WorkerThread> aThread) {
   AssertIsOnMainThread();
   MOZ_ASSERT(aThread);
 
   bool shutdownThread = mShuttingDown;
   bool scheduleTimer = false;
 
   if (!shutdownThread) {
     static TimeDuration timeout =
@@ -1983,17 +1970,17 @@ void RuntimeService::NoteIdleThread(Work
     TimeStamp expirationTime = TimeStamp::NowLoRes() + timeout;
 
     MutexAutoLock lock(mMutex);
 
     uint32_t previousIdleCount = mIdleThreadArray.Length();
 
     if (previousIdleCount < MAX_IDLE_THREADS) {
       IdleThreadInfo* info = mIdleThreadArray.AppendElement();
-      info->mThread = aThread;
+      info->mThread = std::move(aThread);
       info->mExpirationTime = expirationTime;
 
       scheduleTimer = previousIdleCount == 0;
     } else {
       shutdownThread = true;
     }
   }
 
@@ -2188,38 +2175,37 @@ WorkerThreadPrimaryRunnable::Run() {
 
   using mozilla::ipc::BackgroundChild;
 
   class MOZ_STACK_CLASS SetThreadHelper final {
     // Raw pointer: this class is on the stack.
     WorkerPrivate* mWorkerPrivate;
 
    public:
-    SetThreadHelper(WorkerPrivate* aWorkerPrivate, WorkerThread* aThread)
+    SetThreadHelper(WorkerPrivate* aWorkerPrivate, WorkerThread& aThread)
         : mWorkerPrivate(aWorkerPrivate) {
-      MOZ_ASSERT(aWorkerPrivate);
-      MOZ_ASSERT(aThread);
-
-      mWorkerPrivate->SetWorkerPrivateInWorkerThread(aThread);
+      MOZ_ASSERT(mWorkerPrivate);
+
+      mWorkerPrivate->SetWorkerPrivateInWorkerThread(&aThread);
     }
 
     ~SetThreadHelper() {
       if (mWorkerPrivate) {
         mWorkerPrivate->ResetWorkerPrivateInWorkerThread();
       }
     }
 
     void Nullify() {
       MOZ_ASSERT(mWorkerPrivate);
       mWorkerPrivate->ResetWorkerPrivateInWorkerThread();
       mWorkerPrivate = nullptr;
     }
   };
 
-  SetThreadHelper threadHelper(mWorkerPrivate, mThread);
+  SetThreadHelper threadHelper(mWorkerPrivate, *mThread);
 
   auto failureCleanup = MakeScopeExit([&]() {
     // The creation of threadHelper above is the point at which a worker is
     // considered to have run, because the `mPreStartRunnables` are all
     // re-dispatched after `mThread` is set.  We need to let the WorkerPrivate
     // know so it can clean up the various event loops and delete the worker.
     mWorkerPrivate->RunLoopNeverRan();
   });
@@ -2299,88 +2285,87 @@ WorkerThreadPrimaryRunnable::Run() {
   // It is no longer safe to touch mWorkerPrivate.
   mWorkerPrivate = nullptr;
 
   // Now recycle this thread.
   nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
   MOZ_ASSERT(mainTarget);
 
   RefPtr<FinishedRunnable> finishedRunnable =
-      new FinishedRunnable(mThread.forget());
+      new FinishedRunnable(std::move(mThread));
   MOZ_ALWAYS_SUCCEEDS(
       mainTarget->Dispatch(finishedRunnable, NS_DISPATCH_NORMAL));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::FinishedRunnable::Run() {
   AssertIsOnMainThread();
 
-  RefPtr<WorkerThread> thread;
-  mThread.swap(thread);
+  SafeRefPtr<WorkerThread> thread = std::move(mThread);
 
   RuntimeService* rts = RuntimeService::GetService();
   if (rts) {
-    rts->NoteIdleThread(thread);
+    rts->NoteIdleThread(std::move(thread));
   } else if (thread->ShutdownRequired()) {
     MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
   }
 
   return NS_OK;
 }
 
 }  // namespace workerinternals
 
-void CancelWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void CancelWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->CancelWorkersForWindow(aWindow);
   }
 }
 
-void FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void FreezeWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->FreezeWorkersForWindow(aWindow);
   }
 }
 
-void ThawWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void ThawWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->ThawWorkersForWindow(aWindow);
   }
 }
 
-void SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void SuspendWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->SuspendWorkersForWindow(aWindow);
   }
 }
 
-void ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow) {
+void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->ResumeWorkersForWindow(aWindow);
   }
 }
 
 void PropagateFirstPartyStorageAccessGrantedToWorkers(
-    nsPIDOMWindowInner* aWindow) {
+    const nsPIDOMWindowInner& aWindow) {
   AssertIsOnMainThread();
-  MOZ_ASSERT_IF(aWindow->GetExtantDoc(), aWindow->GetExtantDoc()
-                                             ->CookieJarSettings()
-                                             ->GetRejectThirdPartyContexts());
+  MOZ_ASSERT_IF(aWindow.GetExtantDoc(), aWindow.GetExtantDoc()
+                                            ->CookieJarSettings()
+                                            ->GetRejectThirdPartyContexts());
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->PropagateFirstPartyStorageAccessGranted(aWindow);
   }
 }
 
 WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_workers_runtimeservice_h__
 
 #include "mozilla/dom/WorkerCommon.h"
 
 #include "nsIObserver.h"
 
 #include "js/ContextOptions.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/SafeRefPtr.h"
 #include "mozilla/dom/workerinternals/JSSettings.h"
 #include "mozilla/Mutex.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 
 class nsITimer;
 class nsPIDOMWindowInner;
@@ -48,30 +49,31 @@ class RuntimeService final : public nsIO
     }
 
     bool HasNoWorkers() const {
       return ActiveWorkerCount() == 0 && ActiveServiceWorkerCount() == 0;
     }
   };
 
   struct IdleThreadInfo {
-    RefPtr<WorkerThread> mThread;
+    SafeRefPtr<WorkerThread> mThread;
     mozilla::TimeStamp mExpirationTime;
   };
 
   mozilla::Mutex mMutex;
 
   // Protected by mMutex.
   nsClassHashtable<nsCStringHashKey, WorkerDomainInfo> mDomainMap;
 
   // Protected by mMutex.
   nsTArray<IdleThreadInfo> mIdleThreadArray;
 
   // *Not* protected by mMutex.
-  nsClassHashtable<nsPtrHashKey<nsPIDOMWindowInner>, nsTArray<WorkerPrivate*> >
+  nsClassHashtable<nsPtrHashKey<const nsPIDOMWindowInner>,
+                   nsTArray<WorkerPrivate*> >
       mWindowMap;
 
   // Only used on the main thread.
   nsCOMPtr<nsITimer> mIdleThreadTimer;
 
   static UniquePtr<workerinternals::JSSettings> sDefaultJSSettings;
 
  public:
@@ -96,37 +98,38 @@ class RuntimeService final : public nsIO
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   static RuntimeService* GetOrCreateService();
 
   static RuntimeService* GetService();
 
-  bool RegisterWorker(WorkerPrivate* aWorkerPrivate);
+  bool RegisterWorker(WorkerPrivate& aWorkerPrivate);
 
-  void UnregisterWorker(WorkerPrivate* aWorkerPrivate);
+  void UnregisterWorker(WorkerPrivate& aWorkerPrivate);
 
-  void CancelWorkersForWindow(nsPIDOMWindowInner* aWindow);
+  void CancelWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-  void FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow);
+  void FreezeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-  void ThawWorkersForWindow(nsPIDOMWindowInner* aWindow);
+  void ThawWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-  void SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow);
+  void SuspendWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-  void ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow);
+  void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-  void PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow);
+  void PropagateFirstPartyStorageAccessGranted(
+      const nsPIDOMWindowInner& aWindow);
 
   const NavigatorProperties& GetNavigatorProperties() const {
     return mNavigatorProperties;
   }
 
-  void NoteIdleThread(WorkerThread* aThread);
+  void NoteIdleThread(SafeRefPtr<WorkerThread> aThread);
 
   static void GetDefaultJSSettings(workerinternals::JSSettings& aSettings) {
     AssertIsOnMainThread();
     aSettings = *sDefaultJSSettings;
   }
 
   static void SetDefaultContextOptions(
       const JS::ContextOptions& aContextOptions) {
@@ -184,20 +187,20 @@ class RuntimeService final : public nsIO
   nsresult Init();
 
   void Shutdown();
 
   void Cleanup();
 
   void AddAllTopLevelWorkersToArray(nsTArray<WorkerPrivate*>& aWorkers);
 
-  void GetWorkersForWindow(nsPIDOMWindowInner* aWindow,
-                           nsTArray<WorkerPrivate*>& aWorkers);
+  nsTArray<WorkerPrivate*> GetWorkersForWindow(
+      const nsPIDOMWindowInner& aWindow) const;
 
-  bool ScheduleWorker(WorkerPrivate* aWorkerPrivate);
+  bool ScheduleWorker(WorkerPrivate& aWorkerPrivate);
 
   static void ShutdownIdleThreads(nsITimer* aTimer, void* aClosure);
 };
 
 }  // namespace workerinternals
 }  // namespace dom
 }  // namespace mozilla
 
--- a/dom/workers/WorkerCommon.h
+++ b/dom/workers/WorkerCommon.h
@@ -29,28 +29,28 @@ bool IsCurrentThreadRunningWorker();
 bool IsCurrentThreadRunningChromeWorker();
 
 JSContext* GetCurrentWorkerThreadJSContext();
 
 JSObject* GetCurrentThreadWorkerGlobal();
 
 JSObject* GetCurrentThreadWorkerDebuggerGlobal();
 
-void CancelWorkersForWindow(nsPIDOMWindowInner* aWindow);
+void CancelWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-void FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow);
+void FreezeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-void ThawWorkersForWindow(nsPIDOMWindowInner* aWindow);
+void ThawWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-void SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow);
+void SuspendWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
-void ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow);
+void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 
 void PropagateFirstPartyStorageAccessGrantedToWorkers(
-    nsPIDOMWindowInner* aWindow);
+    const nsPIDOMWindowInner& aWindow);
 
 // All of these are implemented in WorkerScope.cpp
 
 bool IsWorkerGlobal(JSObject* global);
 
 bool IsWorkerDebuggerGlobal(JSObject* global);
 
 bool IsWorkerDebuggerSandbox(JSObject* object);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -240,17 +240,17 @@ class WorkerFinishedRunnable final : pub
       NS_WARNING("Failed to dispatch, going to leak!");
     }
 
     RuntimeService* runtime = RuntimeService::GetService();
     NS_ASSERTION(runtime, "This should never be null!");
 
     mFinishedWorker->DisableDebugger();
 
-    runtime->UnregisterWorker(mFinishedWorker);
+    runtime->UnregisterWorker(*mFinishedWorker);
 
     mFinishedWorker->ClearSelfAndParentEventTargetRef();
     return true;
   }
 };
 
 class TopLevelWorkerFinishedRunnable final : public Runnable {
   WorkerPrivate* mFinishedWorker;
@@ -271,17 +271,17 @@ class TopLevelWorkerFinishedRunnable fin
   Run() override {
     AssertIsOnMainThread();
 
     RuntimeService* runtime = RuntimeService::GetService();
     MOZ_ASSERT(runtime);
 
     mFinishedWorker->DisableDebugger();
 
-    runtime->UnregisterWorker(mFinishedWorker);
+    runtime->UnregisterWorker(*mFinishedWorker);
 
     if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
       NS_WARNING("Failed to dispatch, going to leak!");
     }
 
     mFinishedWorker->ClearSelfAndParentEventTargetRef();
     return NS_OK;
   }
@@ -1626,17 +1626,17 @@ bool WorkerPrivate::Notify(WorkerStatus 
     mCancelingTimer->Cancel();
     mCancelingTimer = nullptr;
   }
 
   RefPtr<NotifyRunnable> runnable = new NotifyRunnable(this, aStatus);
   return runnable->Dispatch();
 }
 
-bool WorkerPrivate::Freeze(nsPIDOMWindowInner* aWindow) {
+bool WorkerPrivate::Freeze(const nsPIDOMWindowInner* aWindow) {
   AssertIsOnParentThread();
 
   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
@@ -1664,17 +1664,17 @@ bool WorkerPrivate::Freeze(nsPIDOMWindow
   RefPtr<FreezeRunnable> runnable = new FreezeRunnable(this);
   if (!runnable->Dispatch()) {
     return false;
   }
 
   return true;
 }
 
-bool WorkerPrivate::Thaw(nsPIDOMWindowInner* aWindow) {
+bool WorkerPrivate::Thaw(const nsPIDOMWindowInner* aWindow) {
   AssertIsOnParentThread();
   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
@@ -2411,17 +2411,17 @@ already_AddRefed<WorkerPrivate> WorkerPr
   JS::UniqueChars defaultLocale = JS_GetDefaultLocale(aCx);
   if (NS_WARN_IF(!defaultLocale)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   worker->mDefaultLocale = std::move(defaultLocale);
 
-  if (!runtimeService->RegisterWorker(worker)) {
+  if (!runtimeService->RegisterWorker(*worker)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   worker->EnableDebugger();
 
   MOZ_DIAGNOSTIC_ASSERT(worker->PrincipalIsValid());
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -826,19 +826,19 @@ class WorkerPrivate : public RelativeTim
       ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef);
 
   ThreadSafeWeakPtr<RemoteWorkerChild> GetRemoteWorkerControllerWeakRef();
 
   RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag();
 
   // 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 Freeze(const nsPIDOMWindowInner* aWindow);
 
-  bool Thaw(nsPIDOMWindowInner* aWindow);
+  bool Thaw(const nsPIDOMWindowInner* aWindow);
 
   void PropagateFirstPartyStorageAccessGranted();
 
   void EnableDebugger();
 
   void DisableDebugger();
 
   already_AddRefed<WorkerRunnable> MaybeWrapAsWorkerRunnable(
--- a/dom/workers/WorkerThread.cpp
+++ b/dom/workers/WorkerThread.cpp
@@ -60,17 +60,17 @@ class WorkerThread::Observer final : pub
   NS_DECL_THREADSAFE_ISUPPORTS
 
  private:
   ~Observer() { mWorkerPrivate->AssertIsOnWorkerThread(); }
 
   NS_DECL_NSITHREADOBSERVER
 };
 
-WorkerThread::WorkerThread()
+WorkerThread::WorkerThread(ConstructorKey)
     : nsThread(MakeNotNull<ThreadEventQueue<mozilla::EventQueue>*>(
                    MakeUnique<mozilla::EventQueue>()),
                nsThread::NOT_MAIN_THREAD, kWorkerStackSize),
       mLock("WorkerThread::mLock"),
       mWorkerPrivateCondVar(mLock, "WorkerThread::mWorkerPrivateCondVar"),
       mWorkerPrivate(nullptr),
       mOtherThreadsDispatchingViaEventTarget(0)
 #ifdef DEBUG
@@ -82,27 +82,28 @@ WorkerThread::WorkerThread()
 
 WorkerThread::~WorkerThread() {
   MOZ_ASSERT(!mWorkerPrivate);
   MOZ_ASSERT(!mOtherThreadsDispatchingViaEventTarget);
   MOZ_ASSERT(mAcceptingNonWorkerRunnables);
 }
 
 // static
-already_AddRefed<WorkerThread> WorkerThread::Create(
+SafeRefPtr<WorkerThread> WorkerThread::Create(
     const WorkerThreadFriendKey& /* aKey */) {
-  RefPtr<WorkerThread> thread = new WorkerThread();
+  SafeRefPtr<WorkerThread> thread =
+      MakeSafeRefPtr<WorkerThread>(ConstructorKey());
   if (NS_FAILED(thread->Init(NS_LITERAL_CSTRING("DOM Worker")))) {
     NS_WARNING("Failed to create new thread!");
     return nullptr;
   }
   thread->mAbstractThread = AbstractThread::CreateXPCOMThreadWrapper(
-      thread, false /* aRequireTailDispatch */);
+      thread.unsafeGetRawPtr(), false /* aRequireTailDispatch */);
 
-  return thread.forget();
+  return thread;
 }
 
 void WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
                              WorkerPrivate* aWorkerPrivate) {
   MOZ_ASSERT(PR_GetCurrentThread() == mThread);
 
   if (aWorkerPrivate) {
     {
--- a/dom/workers/WorkerThread.h
+++ b/dom/workers/WorkerThread.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_WorkerThread_h__
 #define mozilla_dom_workers_WorkerThread_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/dom/SafeRefPtr.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/RefPtr.h"
 #include "nsThread.h"
 
 class nsIRunnable;
 
 namespace mozilla {
 class AbstractThread;
@@ -62,19 +63,24 @@ class WorkerThread final : public nsThre
   // An AbstractThread only need to exist on the current thread for Direct Task
   // dispatch to be available.
   RefPtr<AbstractThread> mAbstractThread;
 #ifdef DEBUG
   // Protected by nsThread::mLock.
   bool mAcceptingNonWorkerRunnables;
 #endif
 
+  // Using this struct we restrict access to the constructor while still being
+  // able to use MakeSafeRefPtr.
+  struct ConstructorKey {};
+
  public:
-  static already_AddRefed<WorkerThread> Create(
-      const WorkerThreadFriendKey& aKey);
+  explicit WorkerThread(ConstructorKey);
+
+  static SafeRefPtr<WorkerThread> Create(const WorkerThreadFriendKey& aKey);
 
   void SetWorker(const WorkerThreadFriendKey& aKey,
                  WorkerPrivate* aWorkerPrivate);
 
   nsresult DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
                                    already_AddRefed<nsIRunnable> aRunnable);
 
   nsresult DispatchAnyThread(const WorkerThreadFriendKey& aKey,
@@ -84,17 +90,16 @@ class WorkerThread final : public nsThre
 
   PerformanceCounter* GetPerformanceCounter(nsIRunnable* aEvent) const override;
 
   NS_IMETHODIMP Shutdown() override;
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThread, nsThread)
 
  private:
-  WorkerThread();
   ~WorkerThread();
 
   // This should only be called by consumers that have an
   // nsIEventTarget/nsIThread pointer.
   NS_IMETHOD
   Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override;
 
   NS_IMETHOD