LCOV - code coverage report
Current view: top level - dom/workers - WorkerPrivate.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 799 3081 25.9 %
Date: 2017-07-14 16:53:18 Functions: 102 417 24.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "WorkerPrivate.h"
       8             : 
       9             : #include "amIAddonManager.h"
      10             : #include "nsIClassInfo.h"
      11             : #include "nsIContentSecurityPolicy.h"
      12             : #include "nsIConsoleService.h"
      13             : #include "nsIDOMDOMException.h"
      14             : #include "nsIDOMEvent.h"
      15             : #include "nsIDocument.h"
      16             : #include "nsIDocShell.h"
      17             : #include "nsIInterfaceRequestor.h"
      18             : #include "nsIMemoryReporter.h"
      19             : #include "nsINetworkInterceptController.h"
      20             : #include "nsIPermissionManager.h"
      21             : #include "nsIScriptError.h"
      22             : #include "nsIScriptGlobalObject.h"
      23             : #include "nsIScriptSecurityManager.h"
      24             : #include "nsIScriptTimeoutHandler.h"
      25             : #include "nsITabChild.h"
      26             : #include "nsITextToSubURI.h"
      27             : #include "nsIThreadInternal.h"
      28             : #include "nsITimer.h"
      29             : #include "nsIURI.h"
      30             : #include "nsIURL.h"
      31             : #include "nsIWeakReferenceUtils.h"
      32             : #include "nsIWorkerDebugger.h"
      33             : #include "nsIXPConnect.h"
      34             : #include "nsPIDOMWindow.h"
      35             : #include "nsGlobalWindow.h"
      36             : 
      37             : #include <algorithm>
      38             : #include "ImageContainer.h"
      39             : #include "jsfriendapi.h"
      40             : #include "js/MemoryMetrics.h"
      41             : #include "mozilla/Assertions.h"
      42             : #include "mozilla/Attributes.h"
      43             : #include "mozilla/ContentEvents.h"
      44             : #include "mozilla/EventDispatcher.h"
      45             : #include "mozilla/Likely.h"
      46             : #include "mozilla/LoadContext.h"
      47             : #include "mozilla/Move.h"
      48             : #include "mozilla/dom/BindingUtils.h"
      49             : #include "mozilla/dom/Console.h"
      50             : #include "mozilla/dom/DocGroup.h"
      51             : #include "mozilla/dom/ErrorEvent.h"
      52             : #include "mozilla/dom/ErrorEventBinding.h"
      53             : #include "mozilla/dom/Exceptions.h"
      54             : #include "mozilla/dom/ExtendableMessageEventBinding.h"
      55             : #include "mozilla/dom/FunctionBinding.h"
      56             : #include "mozilla/dom/IndexedDatabaseManager.h"
      57             : #include "mozilla/dom/MessageEvent.h"
      58             : #include "mozilla/dom/MessageEventBinding.h"
      59             : #include "mozilla/dom/MessagePort.h"
      60             : #include "mozilla/dom/MessagePortBinding.h"
      61             : #include "mozilla/dom/nsCSPUtils.h"
      62             : #include "mozilla/dom/Performance.h"
      63             : #include "mozilla/dom/PMessagePort.h"
      64             : #include "mozilla/dom/Promise.h"
      65             : #include "mozilla/dom/PromiseDebugging.h"
      66             : #include "mozilla/dom/PromiseNativeHandler.h"
      67             : #include "mozilla/dom/SimpleGlobalObject.h"
      68             : #include "mozilla/dom/ScriptSettings.h"
      69             : #include "mozilla/dom/StructuredCloneHolder.h"
      70             : #include "mozilla/dom/TabChild.h"
      71             : #include "mozilla/dom/WorkerBinding.h"
      72             : #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
      73             : #include "mozilla/dom/WorkerGlobalScopeBinding.h"
      74             : #include "mozilla/Preferences.h"
      75             : #include "mozilla/SizePrintfMacros.h"
      76             : #include "mozilla/ThrottledEventQueue.h"
      77             : #include "mozilla/TimelineConsumers.h"
      78             : #include "mozilla/WorkerTimelineMarker.h"
      79             : #include "nsAlgorithm.h"
      80             : #include "nsContentUtils.h"
      81             : #include "nsCycleCollector.h"
      82             : #include "nsError.h"
      83             : #include "nsDOMJSUtils.h"
      84             : #include "nsHostObjectProtocolHandler.h"
      85             : #include "nsJSEnvironment.h"
      86             : #include "nsJSUtils.h"
      87             : #include "nsNetUtil.h"
      88             : #include "nsPrintfCString.h"
      89             : #include "nsProxyRelease.h"
      90             : #include "nsQueryObject.h"
      91             : #include "nsSandboxFlags.h"
      92             : #include "nsScriptError.h"
      93             : #include "nsUTF8Utils.h"
      94             : #include "prthread.h"
      95             : #include "xpcpublic.h"
      96             : 
      97             : #ifdef ANDROID
      98             : #include <android/log.h>
      99             : #endif
     100             : 
     101             : #ifdef DEBUG
     102             : #include "nsThreadManager.h"
     103             : #endif
     104             : 
     105             : #include "Navigator.h"
     106             : #include "Principal.h"
     107             : #include "RuntimeService.h"
     108             : #include "ScriptLoader.h"
     109             : #include "ServiceWorkerEvents.h"
     110             : #include "ServiceWorkerManager.h"
     111             : #include "SharedWorker.h"
     112             : #include "WorkerDebuggerManager.h"
     113             : #include "WorkerHolder.h"
     114             : #include "WorkerNavigator.h"
     115             : #include "WorkerRunnable.h"
     116             : #include "WorkerScope.h"
     117             : #include "WorkerThread.h"
     118             : 
     119             : // JS_MaybeGC will run once every second during normal execution.
     120             : #define PERIODIC_GC_TIMER_DELAY_SEC 1
     121             : 
     122             : // A shrinking GC will run five seconds after the last event is processed.
     123             : #define IDLE_GC_TIMER_DELAY_SEC 5
     124             : 
     125             : #define PREF_WORKERS_ENABLED "dom.workers.enabled"
     126             : 
     127             : static mozilla::LazyLogModule sWorkerPrivateLog("WorkerPrivate");
     128             : static mozilla::LazyLogModule sWorkerTimeoutsLog("WorkerTimeouts");
     129             : 
     130             : mozilla::LogModule*
     131         104 : WorkerLog()
     132             : {
     133         104 :   return sWorkerPrivateLog;
     134             : }
     135             : 
     136             : mozilla::LogModule*
     137           0 : TimeoutsLog()
     138             : {
     139           0 :   return sWorkerTimeoutsLog;
     140             : }
     141             : 
     142             : #define LOG(log, _args) MOZ_LOG(log, LogLevel::Debug, _args);
     143             : 
     144             : using namespace mozilla;
     145             : using namespace mozilla::dom;
     146             : using namespace mozilla::ipc;
     147             : 
     148             : USING_WORKERS_NAMESPACE
     149             : 
     150           0 : MOZ_DEFINE_MALLOC_SIZE_OF(JsWorkerMallocSizeOf)
     151             : 
     152             : #ifdef DEBUG
     153             : 
     154             : BEGIN_WORKERS_NAMESPACE
     155             : 
     156             : void
     157         555 : AssertIsOnMainThread()
     158             : {
     159         555 :   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
     160         555 : }
     161             : 
     162             : END_WORKERS_NAMESPACE
     163             : 
     164             : #endif
     165             : 
     166             : namespace {
     167             : 
     168             : #ifdef DEBUG
     169             : 
     170             : const nsIID kDEBUGWorkerEventTargetIID = {
     171             :   0xccaba3fa, 0x5be2, 0x4de2, { 0xba, 0x87, 0x3b, 0x3b, 0x5b, 0x1d, 0x5, 0xfb }
     172             : };
     173             : 
     174             : #endif
     175             : 
     176             : template <class T>
     177             : class AutoPtrComparator
     178             : {
     179             :   typedef nsAutoPtr<T> A;
     180             :   typedef T* B;
     181             : 
     182             : public:
     183           0 :   bool Equals(const A& a, const B& b) const {
     184           0 :     return a && b ? *a == *b : !a && !b ? true : false;
     185             :   }
     186           0 :   bool LessThan(const A& a, const B& b) const {
     187           0 :     return a && b ? *a < *b : b ? true : false;
     188             :   }
     189             : };
     190             : 
     191             : template <class T>
     192             : inline AutoPtrComparator<T>
     193           0 : GetAutoPtrComparator(const nsTArray<nsAutoPtr<T> >&)
     194             : {
     195           0 :   return AutoPtrComparator<T>();
     196             : }
     197             : 
     198             : // Specialize this if there's some class that has multiple nsISupports bases.
     199             : template <class T>
     200             : struct ISupportsBaseInfo
     201             : {
     202             :   typedef T ISupportsBase;
     203             : };
     204             : 
     205             : template <template <class> class SmartPtr, class T>
     206             : inline void
     207           0 : SwapToISupportsArray(SmartPtr<T>& aSrc,
     208             :                      nsTArray<nsCOMPtr<nsISupports> >& aDest)
     209             : {
     210           0 :   nsCOMPtr<nsISupports>* dest = aDest.AppendElement();
     211             : 
     212           0 :   T* raw = nullptr;
     213           0 :   aSrc.swap(raw);
     214             : 
     215             :   nsISupports* rawSupports =
     216           0 :     static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
     217           0 :   dest->swap(rawSupports);
     218           0 : }
     219             : 
     220             : // This class is used to wrap any runnables that the worker receives via the
     221             : // nsIEventTarget::Dispatch() method (either from NS_DispatchToCurrentThread or
     222             : // from the worker's EventTarget).
     223             : class ExternalRunnableWrapper final : public WorkerRunnable
     224             : {
     225             :   nsCOMPtr<nsIRunnable> mWrappedRunnable;
     226             : 
     227             : public:
     228           0 :   ExternalRunnableWrapper(WorkerPrivate* aWorkerPrivate,
     229             :                           nsIRunnable* aWrappedRunnable)
     230           0 :   : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
     231           0 :     mWrappedRunnable(aWrappedRunnable)
     232             :   {
     233           0 :     MOZ_ASSERT(aWorkerPrivate);
     234           0 :     MOZ_ASSERT(aWrappedRunnable);
     235           0 :   }
     236             : 
     237             :   NS_DECL_ISUPPORTS_INHERITED
     238             : 
     239             : private:
     240           0 :   ~ExternalRunnableWrapper()
     241           0 :   { }
     242             : 
     243             :   virtual bool
     244           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     245             :   {
     246           0 :     nsresult rv = mWrappedRunnable->Run();
     247           0 :     if (NS_FAILED(rv)) {
     248           0 :       if (!JS_IsExceptionPending(aCx)) {
     249           0 :         Throw(aCx, rv);
     250             :       }
     251           0 :       return false;
     252             :     }
     253           0 :     return true;
     254             :   }
     255             : 
     256             :   nsresult
     257           0 :   Cancel() override
     258             :   {
     259             :     nsresult rv;
     260             :     nsCOMPtr<nsICancelableRunnable> cancelable =
     261           0 :       do_QueryInterface(mWrappedRunnable);
     262           0 :     MOZ_ASSERT(cancelable); // We checked this earlier!
     263           0 :     rv = cancelable->Cancel();
     264           0 :     nsresult rv2 = WorkerRunnable::Cancel();
     265           0 :     return NS_FAILED(rv) ? rv : rv2;
     266             :   }
     267             : };
     268             : 
     269             : struct WindowAction
     270             : {
     271             :   nsPIDOMWindowInner* mWindow;
     272             :   bool mDefaultAction;
     273             : 
     274           0 :   MOZ_IMPLICIT WindowAction(nsPIDOMWindowInner* aWindow)
     275           0 :   : mWindow(aWindow), mDefaultAction(true)
     276           0 :   { }
     277             : 
     278             :   bool
     279           0 :   operator==(const WindowAction& aOther) const
     280             :   {
     281           0 :     return mWindow == aOther.mWindow;
     282             :   }
     283             : };
     284             : 
     285             : void
     286           0 : LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId)
     287             : {
     288           0 :   AssertIsOnMainThread();
     289             : 
     290           0 :   RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
     291           0 :   NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
     292             : 
     293           0 :   if (scriptError) {
     294           0 :     nsAutoCString category("Web Worker");
     295           0 :     if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage,
     296             :                                                 aReport.mFilename,
     297             :                                                 aReport.mLine,
     298             :                                                 aReport.mLineNumber,
     299             :                                                 aReport.mColumnNumber,
     300             :                                                 aReport.mFlags,
     301             :                                                 category,
     302             :                                                 aInnerWindowId))) {
     303           0 :       NS_WARNING("Failed to init script error!");
     304           0 :       scriptError = nullptr;
     305             :     }
     306             : 
     307           0 :     for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
     308           0 :       const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
     309             : 
     310           0 :       nsScriptErrorNote* noteObject = new nsScriptErrorNote();
     311           0 :       noteObject->Init(note.mMessage, note.mFilename,
     312           0 :                        note.mLineNumber, note.mColumnNumber);
     313           0 :       scriptError->AddNote(noteObject);
     314             :     }
     315             :   }
     316             : 
     317             :   nsCOMPtr<nsIConsoleService> consoleService =
     318           0 :     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     319           0 :   NS_WARNING_ASSERTION(consoleService, "Failed to get console service!");
     320             : 
     321           0 :   if (consoleService) {
     322           0 :     if (scriptError) {
     323           0 :       if (NS_SUCCEEDED(consoleService->LogMessage(scriptError))) {
     324           0 :         return;
     325             :       }
     326           0 :       NS_WARNING("LogMessage failed!");
     327           0 :     } else if (NS_SUCCEEDED(consoleService->LogStringMessage(
     328             :                               aReport.mMessage.BeginReading()))) {
     329           0 :       return;
     330             :     }
     331           0 :     NS_WARNING("LogStringMessage failed!");
     332             :   }
     333             : 
     334           0 :   NS_ConvertUTF16toUTF8 msg(aReport.mMessage);
     335           0 :   NS_ConvertUTF16toUTF8 filename(aReport.mFilename);
     336             : 
     337             :   static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]";
     338             : 
     339             : #ifdef ANDROID
     340             :   __android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(),
     341             :                       filename.get(), aReport.mLineNumber);
     342             : #endif
     343             : 
     344           0 :   fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber);
     345           0 :   fflush(stderr);
     346             : }
     347             : 
     348             : class MainThreadReleaseRunnable final : public Runnable
     349             : {
     350             :   nsTArray<nsCOMPtr<nsISupports>> mDoomed;
     351             :   nsCOMPtr<nsILoadGroup> mLoadGroupToCancel;
     352             : 
     353             : public:
     354           0 :   MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>& aDoomed,
     355             :                             nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
     356           0 :     : mozilla::Runnable("MainThreadReleaseRunnable")
     357             :   {
     358           0 :     mDoomed.SwapElements(aDoomed);
     359           0 :     mLoadGroupToCancel.swap(aLoadGroupToCancel);
     360           0 :   }
     361             : 
     362             :   NS_DECL_ISUPPORTS_INHERITED
     363             : 
     364             :   NS_IMETHOD
     365           0 :   Run() override
     366             :   {
     367           0 :     if (mLoadGroupToCancel) {
     368           0 :       mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
     369           0 :       mLoadGroupToCancel = nullptr;
     370             :     }
     371             : 
     372           0 :     mDoomed.Clear();
     373           0 :     return NS_OK;
     374             :   }
     375             : 
     376             : private:
     377           0 :   ~MainThreadReleaseRunnable()
     378           0 :   { }
     379             : };
     380             : 
     381           0 : class WorkerFinishedRunnable final : public WorkerControlRunnable
     382             : {
     383             :   WorkerPrivate* mFinishedWorker;
     384             : 
     385             : public:
     386           0 :   WorkerFinishedRunnable(WorkerPrivate* aWorkerPrivate,
     387             :                          WorkerPrivate* aFinishedWorker)
     388           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
     389           0 :     mFinishedWorker(aFinishedWorker)
     390           0 :   { }
     391             : 
     392             : private:
     393             :   virtual bool
     394           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
     395             :   {
     396             :     // Silence bad assertions.
     397           0 :     return true;
     398             :   }
     399             : 
     400             :   virtual void
     401           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
     402             :   {
     403             :     // Silence bad assertions.
     404           0 :   }
     405             : 
     406             :   virtual bool
     407           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     408             :   {
     409           0 :     if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
     410           0 :       NS_WARNING("Failed to dispatch, going to leak!");
     411             :     }
     412             : 
     413           0 :     RuntimeService* runtime = RuntimeService::GetService();
     414           0 :     NS_ASSERTION(runtime, "This should never be null!");
     415             : 
     416           0 :     mFinishedWorker->DisableDebugger();
     417             : 
     418           0 :     runtime->UnregisterWorker(mFinishedWorker);
     419             : 
     420           0 :     mFinishedWorker->ClearSelfRef();
     421           0 :     return true;
     422             :   }
     423             : };
     424             : 
     425             : class TopLevelWorkerFinishedRunnable final : public Runnable
     426             : {
     427             :   WorkerPrivate* mFinishedWorker;
     428             : 
     429             : public:
     430           0 :   explicit TopLevelWorkerFinishedRunnable(WorkerPrivate* aFinishedWorker)
     431           0 :     : mozilla::Runnable("TopLevelWorkerFinishedRunnable")
     432           0 :     , mFinishedWorker(aFinishedWorker)
     433             :   {
     434           0 :     aFinishedWorker->AssertIsOnWorkerThread();
     435           0 :   }
     436             : 
     437             :   NS_DECL_ISUPPORTS_INHERITED
     438             : 
     439             : private:
     440           0 :   ~TopLevelWorkerFinishedRunnable() {}
     441             : 
     442             :   NS_IMETHOD
     443           0 :   Run() override
     444             :   {
     445           0 :     AssertIsOnMainThread();
     446             : 
     447           0 :     RuntimeService* runtime = RuntimeService::GetService();
     448           0 :     MOZ_ASSERT(runtime);
     449             : 
     450           0 :     mFinishedWorker->DisableDebugger();
     451             : 
     452           0 :     runtime->UnregisterWorker(mFinishedWorker);
     453             : 
     454           0 :     if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
     455           0 :       NS_WARNING("Failed to dispatch, going to leak!");
     456             :     }
     457             : 
     458           0 :     mFinishedWorker->ClearSelfRef();
     459           0 :     return NS_OK;
     460             :   }
     461             : };
     462             : 
     463           3 : class ModifyBusyCountRunnable final : public WorkerControlRunnable
     464             : {
     465             :   bool mIncrease;
     466             : 
     467             : public:
     468           1 :   ModifyBusyCountRunnable(WorkerPrivate* aWorkerPrivate, bool aIncrease)
     469           1 :   : WorkerControlRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
     470           1 :     mIncrease(aIncrease)
     471           1 :   { }
     472             : 
     473             : private:
     474             :   virtual bool
     475           1 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     476             :   {
     477           1 :     return aWorkerPrivate->ModifyBusyCount(mIncrease);
     478             :   }
     479             : 
     480             :   virtual void
     481           1 :   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
     482             :           override
     483             :   {
     484           1 :     if (mIncrease) {
     485           1 :       WorkerControlRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
     486           1 :       return;
     487             :     }
     488             :     // Don't do anything here as it's possible that aWorkerPrivate has been
     489             :     // deleted.
     490             :   }
     491             : };
     492             : 
     493           0 : class ReportCompileErrorRunnable final : public WorkerRunnable
     494             : {
     495             : public:
     496             :   static void
     497           0 :   CreateAndDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
     498             :   {
     499           0 :     MOZ_ASSERT(aWorkerPrivate);
     500           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     501             : 
     502             :     RefPtr<ReportCompileErrorRunnable> runnable =
     503           0 :       new ReportCompileErrorRunnable(aCx, aWorkerPrivate);
     504           0 :     runnable->Dispatch();
     505           0 :   }
     506             : 
     507             : private:
     508           0 :   ReportCompileErrorRunnable(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
     509           0 :     : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount)
     510             :   {
     511           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     512           0 :   }
     513             : 
     514             :   void
     515           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
     516             :   {
     517           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     518             : 
     519             :     // Dispatch may fail if the worker was canceled, no need to report that as
     520             :     // an error, so don't call base class PostDispatch.
     521           0 :   }
     522             : 
     523             :   bool
     524           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     525             :   {
     526           0 :     if (aWorkerPrivate->IsFrozen() ||
     527           0 :         aWorkerPrivate->IsParentWindowPaused()) {
     528           0 :       MOZ_ASSERT(!IsDebuggerRunnable());
     529           0 :       aWorkerPrivate->QueueRunnable(this);
     530           0 :       return true;
     531             :     }
     532             : 
     533           0 :     if (aWorkerPrivate->IsSharedWorker()) {
     534           0 :       aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr,
     535           0 :                                                     /* isErrorEvent */ false);
     536           0 :       return true;
     537             :     }
     538             : 
     539           0 :     if (aWorkerPrivate->IsServiceWorker()) {
     540           0 :       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     541           0 :       if (swm) {
     542           0 :         swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
     543             :                          aWorkerPrivate->ServiceWorkerScope(),
     544             :                          aWorkerPrivate->ScriptURL(),
     545             :                          EmptyString(), EmptyString(), EmptyString(),
     546           0 :                          0, 0, JSREPORT_ERROR, JSEXN_ERR);
     547             :       }
     548           0 :       return true;
     549             :     }
     550             : 
     551           0 :     if (!aWorkerPrivate->IsAcceptingEvents()) {
     552           0 :       return true;
     553             :     }
     554             : 
     555             :     RefPtr<Event> event =
     556           0 :       Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"),
     557           0 :                          EventInit());
     558           0 :     event->SetTrusted(true);
     559             : 
     560           0 :     nsEventStatus status = nsEventStatus_eIgnore;
     561           0 :     aWorkerPrivate->DispatchDOMEvent(nullptr, event, nullptr, &status);
     562           0 :     return true;
     563             :   }
     564             : };
     565             : 
     566           0 : class CompileScriptRunnable final : public WorkerRunnable
     567             : {
     568             :   nsString mScriptURL;
     569             : 
     570             : public:
     571           1 :   explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate,
     572             :                                  const nsAString& aScriptURL)
     573           1 :   : WorkerRunnable(aWorkerPrivate),
     574           1 :     mScriptURL(aScriptURL)
     575           1 :   { }
     576             : 
     577             : private:
     578             :   // We can't implement PreRun effectively, because at the point when that would
     579             :   // run we have not yet done our load so don't know things like our final
     580             :   // principal and whatnot.
     581             : 
     582             :   virtual bool
     583           1 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     584             :   {
     585           1 :     aWorkerPrivate->AssertIsOnWorkerThread();
     586             : 
     587           1 :     ErrorResult rv;
     588           1 :     scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL, WorkerScript, rv);
     589           0 :     rv.WouldReportJSException();
     590             :     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     591             :     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     592             :     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     593             :     // events if our load is canceled with that error code.
     594           0 :     if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
     595           0 :       rv.SuppressException();
     596           0 :       return false;
     597             :     }
     598             : 
     599           0 :     WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope();
     600           0 :     if (NS_WARN_IF(!globalScope)) {
     601             :       // We never got as far as calling GetOrCreateGlobalScope, or it failed.
     602             :       // We have no way to enter a compartment, hence no sane way to report this
     603             :       // error.  :(
     604           0 :       rv.SuppressException();
     605           0 :       return false;
     606             :     }
     607             : 
     608             :     // Make sure to propagate exceptions from rv onto aCx, so that they will get
     609             :     // reported after we return.  We want to propagate just JS exceptions,
     610             :     // because all the other errors are handled when the script is loaded.
     611             :     // See: https://dom.spec.whatwg.org/#concept-event-fire
     612           0 :     if (rv.Failed() && !rv.IsJSException()) {
     613           0 :       ReportCompileErrorRunnable::CreateAndDispatch(aCx, aWorkerPrivate);
     614           0 :       rv.SuppressException();
     615           0 :       return false;
     616             :     }
     617             : 
     618             :     // This is a little dumb, but aCx is in the null compartment here because we
     619             :     // set it up that way in our Run(), since we had not created the global at
     620             :     // that point yet.  So we need to enter the compartment of our global,
     621             :     // because setting a pending exception on aCx involves wrapping into its
     622             :     // current compartment.  Luckily we have a global now.
     623           0 :     JSAutoCompartment ac(aCx, globalScope->GetGlobalJSObject());
     624           0 :     if (rv.MaybeSetPendingException(aCx)) {
     625           0 :       return false;
     626             :     }
     627             : 
     628           0 :     aWorkerPrivate->SetWorkerScriptExecutedSuccessfully();
     629           0 :     return true;
     630             :   }
     631             : };
     632             : 
     633           0 : class CompileDebuggerScriptRunnable final : public WorkerDebuggerRunnable
     634             : {
     635             :   nsString mScriptURL;
     636             : 
     637             : public:
     638           0 :   CompileDebuggerScriptRunnable(WorkerPrivate* aWorkerPrivate,
     639             :                                 const nsAString& aScriptURL)
     640           0 :   : WorkerDebuggerRunnable(aWorkerPrivate),
     641           0 :     mScriptURL(aScriptURL)
     642           0 :   { }
     643             : 
     644             : private:
     645             :   virtual bool
     646           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     647             :   {
     648           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     649             : 
     650             :     WorkerDebuggerGlobalScope* globalScope =
     651           0 :       aWorkerPrivate->CreateDebuggerGlobalScope(aCx);
     652           0 :     if (!globalScope) {
     653           0 :       NS_WARNING("Failed to make global!");
     654           0 :       return false;
     655             :     }
     656             : 
     657           0 :     JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
     658             : 
     659           0 :     ErrorResult rv;
     660           0 :     JSAutoCompartment ac(aCx, global);
     661           0 :     scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL,
     662           0 :                                  DebuggerScript, rv);
     663           0 :     rv.WouldReportJSException();
     664             :     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     665             :     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     666             :     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     667             :     // events if our load is canceled with that error code.
     668           0 :     if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
     669           0 :       rv.SuppressException();
     670           0 :       return false;
     671             :     }
     672             :     // Make sure to propagate exceptions from rv onto aCx, so that they will get
     673             :     // reported after we return.  We do this for all failures on rv, because now
     674             :     // we're using rv to track all the state we care about.
     675           0 :     if (rv.MaybeSetPendingException(aCx)) {
     676           0 :       return false;
     677             :     }
     678             : 
     679           0 :     return true;
     680             :   }
     681             : };
     682             : 
     683           0 : class MessageEventRunnable final : public WorkerRunnable
     684             :                                  , public StructuredCloneHolder
     685             : {
     686             : public:
     687           1 :   MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
     688             :                        TargetAndBusyBehavior aBehavior)
     689           1 :   : WorkerRunnable(aWorkerPrivate, aBehavior)
     690             :   , StructuredCloneHolder(CloningSupported, TransferringSupported,
     691           1 :                           StructuredCloneScope::SameProcessDifferentThread)
     692             :   {
     693           1 :   }
     694             : 
     695             :   bool
     696           0 :   DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
     697             :                    DOMEventTargetHelper* aTarget, bool aIsMainThread)
     698             :   {
     699           0 :     nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(aTarget->GetParentObject());
     700             : 
     701             :     // For some workers without window, parent is null and we try to find it
     702             :     // from the JS Context.
     703           0 :     if (!parent) {
     704           0 :       JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx));
     705           0 :       if (NS_WARN_IF(!globalObject)) {
     706           0 :         return false;
     707             :       }
     708             : 
     709           0 :       parent = xpc::NativeGlobal(globalObject);
     710           0 :       if (NS_WARN_IF(!parent)) {
     711           0 :         return false;
     712             :       }
     713             :     }
     714             : 
     715           0 :     MOZ_ASSERT(parent);
     716             : 
     717           0 :     JS::Rooted<JS::Value> messageData(aCx);
     718           0 :     ErrorResult rv;
     719             : 
     720           0 :     UniquePtr<AbstractTimelineMarker> start;
     721           0 :     UniquePtr<AbstractTimelineMarker> end;
     722           0 :     RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
     723           0 :     bool isTimelineRecording = timelines && !timelines->IsEmpty();
     724             : 
     725           0 :     if (isTimelineRecording) {
     726           0 :       start = MakeUnique<WorkerTimelineMarker>(aIsMainThread
     727           0 :         ? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
     728             :         : ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
     729           0 :         MarkerTracingType::START);
     730             :     }
     731             : 
     732           0 :     Read(parent, aCx, &messageData, rv);
     733             : 
     734           0 :     if (isTimelineRecording) {
     735           0 :       end = MakeUnique<WorkerTimelineMarker>(aIsMainThread
     736           0 :         ? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
     737             :         : ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
     738           0 :         MarkerTracingType::END);
     739           0 :       timelines->AddMarkerForAllObservedDocShells(start);
     740           0 :       timelines->AddMarkerForAllObservedDocShells(end);
     741             :     }
     742             : 
     743           0 :     if (NS_WARN_IF(rv.Failed())) {
     744           0 :       xpc::Throw(aCx, rv.StealNSResult());
     745           0 :       return false;
     746             :     }
     747             : 
     748           0 :     Sequence<OwningNonNull<MessagePort>> ports;
     749           0 :     if (!TakeTransferredPortsAsSequence(ports)) {
     750           0 :       return false;
     751             :     }
     752             : 
     753           0 :     nsCOMPtr<nsIDOMEvent> domEvent;
     754           0 :     RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
     755           0 :     event->InitMessageEvent(nullptr,
     756           0 :                             NS_LITERAL_STRING("message"),
     757             :                             false /* non-bubbling */,
     758             :                             false /* cancelable */,
     759             :                             messageData,
     760           0 :                             EmptyString(),
     761           0 :                             EmptyString(),
     762             :                             nullptr,
     763           0 :                             ports);
     764           0 :     domEvent = do_QueryObject(event);
     765             : 
     766           0 :     domEvent->SetTrusted(true);
     767             : 
     768           0 :     nsEventStatus dummy = nsEventStatus_eIgnore;
     769           0 :     aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
     770             : 
     771           0 :     return true;
     772             :   }
     773             : 
     774             : private:
     775             :   virtual bool
     776           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     777             :   {
     778           0 :     if (mBehavior == ParentThreadUnchangedBusyCount) {
     779             :       // Don't fire this event if the JS object has been disconnected from the
     780             :       // private object.
     781           0 :       if (!aWorkerPrivate->IsAcceptingEvents()) {
     782           0 :         return true;
     783             :       }
     784             : 
     785           0 :       if (aWorkerPrivate->IsFrozen() ||
     786           0 :           aWorkerPrivate->IsParentWindowPaused()) {
     787           0 :         MOZ_ASSERT(!IsDebuggerRunnable());
     788           0 :         aWorkerPrivate->QueueRunnable(this);
     789           0 :         return true;
     790             :       }
     791             : 
     792           0 :       aWorkerPrivate->AssertInnerWindowIsCorrect();
     793             : 
     794           0 :       return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate,
     795           0 :                               !aWorkerPrivate->GetParent());
     796             :     }
     797             : 
     798           0 :     MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
     799             : 
     800           0 :     return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
     801           0 :                             false);
     802             :   }
     803             : };
     804             : 
     805           0 : class DebuggerMessageEventRunnable : public WorkerDebuggerRunnable {
     806             :   nsString mMessage;
     807             : 
     808             : public:
     809           0 :   DebuggerMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
     810             :                                const nsAString& aMessage)
     811           0 :   : WorkerDebuggerRunnable(aWorkerPrivate),
     812           0 :     mMessage(aMessage)
     813             :   {
     814           0 :   }
     815             : 
     816             : private:
     817             :   virtual bool
     818           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     819             :   {
     820           0 :     WorkerDebuggerGlobalScope* globalScope = aWorkerPrivate->DebuggerGlobalScope();
     821           0 :     MOZ_ASSERT(globalScope);
     822             : 
     823           0 :     JS::Rooted<JSString*> message(aCx, JS_NewUCStringCopyN(aCx, mMessage.get(),
     824           0 :                                                            mMessage.Length()));
     825           0 :     if (!message) {
     826           0 :       return false;
     827             :     }
     828           0 :     JS::Rooted<JS::Value> data(aCx, JS::StringValue(message));
     829             : 
     830             :     RefPtr<MessageEvent> event = new MessageEvent(globalScope, nullptr,
     831           0 :                                                     nullptr);
     832           0 :     event->InitMessageEvent(nullptr,
     833           0 :                             NS_LITERAL_STRING("message"),
     834             :                             false, // canBubble
     835             :                             true, // cancelable
     836             :                             data,
     837           0 :                             EmptyString(),
     838           0 :                             EmptyString(),
     839             :                             nullptr,
     840           0 :                             Sequence<OwningNonNull<MessagePort>>());
     841           0 :     event->SetTrusted(true);
     842             : 
     843           0 :     nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
     844           0 :     nsEventStatus status = nsEventStatus_eIgnore;
     845           0 :     globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &status);
     846           0 :     return true;
     847             :   }
     848             : };
     849             : 
     850           0 : class NotifyRunnable final : public WorkerControlRunnable
     851             : {
     852             :   Status mStatus;
     853             : 
     854             : public:
     855           0 :   NotifyRunnable(WorkerPrivate* aWorkerPrivate, Status aStatus)
     856           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
     857           0 :     mStatus(aStatus)
     858             :   {
     859           0 :     MOZ_ASSERT(aStatus == Closing || aStatus == Terminating ||
     860             :                aStatus == Canceling || aStatus == Killing);
     861           0 :   }
     862             : 
     863             : private:
     864             :   virtual bool
     865           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
     866             :   {
     867           0 :     aWorkerPrivate->AssertIsOnParentThread();
     868           0 :     return aWorkerPrivate->ModifyBusyCount(true);
     869             :   }
     870             : 
     871             :   virtual void
     872           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
     873             :   {
     874           0 :     aWorkerPrivate->AssertIsOnParentThread();
     875           0 :     if (!aDispatchResult) {
     876             :       // We couldn't dispatch to the worker, which means it's already dead.
     877             :       // Undo the busy count modification.
     878           0 :       aWorkerPrivate->ModifyBusyCount(false);
     879             :     }
     880           0 :   }
     881             : 
     882             :   virtual void
     883           0 :   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
     884             :           override
     885             :   {
     886           0 :     aWorkerPrivate->ModifyBusyCountFromWorker(false);
     887           0 :     return;
     888             :   }
     889             : 
     890             :   virtual bool
     891           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     892             :   {
     893           0 :     bool ok = aWorkerPrivate->NotifyInternal(aCx, mStatus);
     894           0 :     MOZ_ASSERT(!JS_IsExceptionPending(aCx));
     895           0 :     return ok;
     896             :   }
     897             : };
     898             : 
     899           0 : class FreezeRunnable final : public WorkerControlRunnable
     900             : {
     901             : public:
     902           0 :   explicit FreezeRunnable(WorkerPrivate* aWorkerPrivate)
     903           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
     904           0 :   { }
     905             : 
     906             : private:
     907             :   virtual bool
     908           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     909             :   {
     910           0 :     return aWorkerPrivate->FreezeInternal();
     911             :   }
     912             : };
     913             : 
     914           0 : class ThawRunnable final : public WorkerControlRunnable
     915             : {
     916             : public:
     917           0 :   explicit ThawRunnable(WorkerPrivate* aWorkerPrivate)
     918           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
     919           0 :   { }
     920             : 
     921             : private:
     922             :   virtual bool
     923           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     924             :   {
     925           0 :     return aWorkerPrivate->ThawInternal();
     926             :   }
     927             : };
     928             : 
     929           0 : class ReportErrorToConsoleRunnable final : public WorkerRunnable
     930             : {
     931             :   const char* mMessage;
     932             : 
     933             : public:
     934             :   // aWorkerPrivate is the worker thread we're on (or the main thread, if null)
     935             :   static void
     936           0 :   Report(WorkerPrivate* aWorkerPrivate, const char* aMessage)
     937             :   {
     938           0 :     if (aWorkerPrivate) {
     939           0 :       aWorkerPrivate->AssertIsOnWorkerThread();
     940             :     } else {
     941           0 :       AssertIsOnMainThread();
     942             :     }
     943             : 
     944             :     // Now fire a runnable to do the same on the parent's thread if we can.
     945           0 :     if (aWorkerPrivate) {
     946             :       RefPtr<ReportErrorToConsoleRunnable> runnable =
     947           0 :         new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage);
     948           0 :       runnable->Dispatch();
     949           0 :       return;
     950             :     }
     951             : 
     952             :     // Log a warning to the console.
     953           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     954           0 :                                     NS_LITERAL_CSTRING("DOM"),
     955             :                                     nullptr,
     956             :                                     nsContentUtils::eDOM_PROPERTIES,
     957           0 :                                     aMessage);
     958             :   }
     959             : 
     960             : private:
     961           0 :   ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate, const char* aMessage)
     962           0 :   : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
     963           0 :     mMessage(aMessage)
     964           0 :   { }
     965             : 
     966             :   virtual void
     967           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
     968             :   {
     969           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
     970             : 
     971             :     // Dispatch may fail if the worker was canceled, no need to report that as
     972             :     // an error, so don't call base class PostDispatch.
     973           0 :   }
     974             : 
     975             :   virtual bool
     976           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
     977             :   {
     978           0 :     WorkerPrivate* parent = aWorkerPrivate->GetParent();
     979           0 :     MOZ_ASSERT_IF(!parent, NS_IsMainThread());
     980           0 :     Report(parent, mMessage);
     981           0 :     return true;
     982             :   }
     983             : };
     984             : 
     985           0 : class ReportErrorRunnable final : public WorkerRunnable
     986             : {
     987             :   WorkerErrorReport mReport;
     988             : 
     989             : public:
     990             :   // aWorkerPrivate is the worker thread we're on (or the main thread, if null)
     991             :   // aTarget is the worker object that we are going to fire an error at
     992             :   // (if any).
     993             :   static void
     994           0 :   ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
     995             :               bool aFireAtScope, WorkerPrivate* aTarget,
     996             :               const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
     997             :               JS::Handle<JS::Value> aException = JS::NullHandleValue)
     998             :   {
     999           0 :     if (aWorkerPrivate) {
    1000           0 :       aWorkerPrivate->AssertIsOnWorkerThread();
    1001             :     } else {
    1002           0 :       AssertIsOnMainThread();
    1003             :     }
    1004             : 
    1005             :     // We should not fire error events for warnings but instead make sure that
    1006             :     // they show up in the error console.
    1007           0 :     if (!JSREPORT_IS_WARNING(aReport.mFlags)) {
    1008             :       // First fire an ErrorEvent at the worker.
    1009           0 :       RootedDictionary<ErrorEventInit> init(aCx);
    1010             : 
    1011           0 :       if (aReport.mMutedError) {
    1012           0 :         init.mMessage.AssignLiteral("Script error.");
    1013             :       } else {
    1014           0 :         init.mMessage = aReport.mMessage;
    1015           0 :         init.mFilename = aReport.mFilename;
    1016           0 :         init.mLineno = aReport.mLineNumber;
    1017           0 :         init.mError = aException;
    1018             :       }
    1019             : 
    1020           0 :       init.mCancelable = true;
    1021           0 :       init.mBubbles = false;
    1022             : 
    1023           0 :       if (aTarget) {
    1024             :         RefPtr<ErrorEvent> event =
    1025           0 :           ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
    1026           0 :         event->SetTrusted(true);
    1027             : 
    1028           0 :         nsEventStatus status = nsEventStatus_eIgnore;
    1029           0 :         aTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
    1030             : 
    1031           0 :         if (status == nsEventStatus_eConsumeNoDefault) {
    1032           0 :           return;
    1033             :         }
    1034             :       }
    1035             : 
    1036             :       // Now fire an event at the global object, but don't do that if the error
    1037             :       // code is too much recursion and this is the same script threw the error.
    1038             :       // XXXbz the interaction of this with worker errors seems kinda broken.
    1039             :       // An overrecursion in the debugger or debugger sandbox will get turned
    1040             :       // into an error event on our parent worker!
    1041             :       // https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this
    1042             :       // better.
    1043           0 :       if (aFireAtScope &&
    1044           0 :           (aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) {
    1045           0 :         JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
    1046           0 :         NS_ASSERTION(global, "This should never be null!");
    1047             : 
    1048           0 :         nsEventStatus status = nsEventStatus_eIgnore;
    1049             :         nsIScriptGlobalObject* sgo;
    1050             : 
    1051           0 :         if (aWorkerPrivate) {
    1052           0 :           WorkerGlobalScope* globalScope = nullptr;
    1053           0 :           UNWRAP_OBJECT(WorkerGlobalScope, &global, globalScope);
    1054             : 
    1055           0 :           if (!globalScope) {
    1056           0 :             WorkerDebuggerGlobalScope* globalScope = nullptr;
    1057           0 :             UNWRAP_OBJECT(WorkerDebuggerGlobalScope, &global, globalScope);
    1058             : 
    1059           0 :             MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global);
    1060           0 :             if (globalScope || IsDebuggerSandbox(global)) {
    1061           0 :               aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber,
    1062           0 :                                                     aReport.mMessage);
    1063           0 :               return;
    1064             :             }
    1065             : 
    1066           0 :             MOZ_ASSERT(SimpleGlobalObject::SimpleGlobalType(global) ==
    1067             :                          SimpleGlobalObject::GlobalType::BindingDetail);
    1068             :             // XXXbz We should really log this to console, but unwinding out of
    1069             :             // this stuff without ending up firing any events is ... hard.  Just
    1070             :             // return for now.
    1071             :             // https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks
    1072             :             // making this better.
    1073           0 :             return;
    1074             :           }
    1075             : 
    1076           0 :           MOZ_ASSERT(globalScope->GetWrapperPreserveColor() == global);
    1077           0 :           nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalScope);
    1078             : 
    1079             :           RefPtr<ErrorEvent> event =
    1080           0 :             ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
    1081           0 :           event->SetTrusted(true);
    1082             : 
    1083           0 :           if (NS_FAILED(EventDispatcher::DispatchDOMEvent(target, nullptr,
    1084             :                                                           event, nullptr,
    1085             :                                                           &status))) {
    1086           0 :             NS_WARNING("Failed to dispatch worker thread error event!");
    1087           0 :             status = nsEventStatus_eIgnore;
    1088             :           }
    1089             :         }
    1090           0 :         else if ((sgo = nsJSUtils::GetStaticScriptGlobal(global))) {
    1091           0 :           MOZ_ASSERT(NS_IsMainThread());
    1092             : 
    1093           0 :           if (NS_FAILED(sgo->HandleScriptError(init, &status))) {
    1094           0 :             NS_WARNING("Failed to dispatch main thread error event!");
    1095           0 :             status = nsEventStatus_eIgnore;
    1096             :           }
    1097             :         }
    1098             : 
    1099             :         // Was preventDefault() called?
    1100           0 :         if (status == nsEventStatus_eConsumeNoDefault) {
    1101           0 :           return;
    1102             :         }
    1103             :       }
    1104             :     }
    1105             : 
    1106             :     // Now fire a runnable to do the same on the parent's thread if we can.
    1107           0 :     if (aWorkerPrivate) {
    1108             :       RefPtr<ReportErrorRunnable> runnable =
    1109           0 :         new ReportErrorRunnable(aWorkerPrivate, aReport);
    1110           0 :       runnable->Dispatch();
    1111           0 :       return;
    1112             :     }
    1113             : 
    1114             :     // Otherwise log an error to the error console.
    1115           0 :     LogErrorToConsole(aReport, aInnerWindowId);
    1116             :   }
    1117             : 
    1118             : private:
    1119           0 :   ReportErrorRunnable(WorkerPrivate* aWorkerPrivate,
    1120             :                       const WorkerErrorReport& aReport)
    1121           0 :   : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
    1122           0 :     mReport(aReport)
    1123           0 :   { }
    1124             : 
    1125             :   virtual void
    1126           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
    1127             :   {
    1128           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
    1129             : 
    1130             :     // Dispatch may fail if the worker was canceled, no need to report that as
    1131             :     // an error, so don't call base class PostDispatch.
    1132           0 :   }
    1133             : 
    1134             :   virtual bool
    1135           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1136             :   {
    1137           0 :     JS::Rooted<JSObject*> target(aCx, aWorkerPrivate->GetWrapper());
    1138             : 
    1139             :     uint64_t innerWindowId;
    1140           0 :     bool fireAtScope = true;
    1141             : 
    1142           0 :     bool workerIsAcceptingEvents = aWorkerPrivate->IsAcceptingEvents();
    1143             : 
    1144           0 :     WorkerPrivate* parent = aWorkerPrivate->GetParent();
    1145           0 :     if (parent) {
    1146           0 :       innerWindowId = 0;
    1147             :     }
    1148             :     else {
    1149           0 :       AssertIsOnMainThread();
    1150             : 
    1151           0 :       if (aWorkerPrivate->IsFrozen() ||
    1152           0 :           aWorkerPrivate->IsParentWindowPaused()) {
    1153           0 :         MOZ_ASSERT(!IsDebuggerRunnable());
    1154           0 :         aWorkerPrivate->QueueRunnable(this);
    1155           0 :         return true;
    1156             :       }
    1157             : 
    1158           0 :       if (aWorkerPrivate->IsSharedWorker()) {
    1159           0 :         aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport,
    1160           0 :                                                       /* isErrorEvent */ true);
    1161           0 :         return true;
    1162             :       }
    1163             : 
    1164             :       // Service workers do not have a main thread parent global, so normal
    1165             :       // worker error reporting will crash.  Instead, pass the error to
    1166             :       // the ServiceWorkerManager to report on any controlled documents.
    1167           0 :       if (aWorkerPrivate->IsServiceWorker()) {
    1168           0 :         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
    1169           0 :         if (swm) {
    1170           0 :           swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
    1171             :                            aWorkerPrivate->ServiceWorkerScope(),
    1172             :                            aWorkerPrivate->ScriptURL(),
    1173             :                            mReport.mMessage,
    1174             :                            mReport.mFilename, mReport.mLine, mReport.mLineNumber,
    1175             :                            mReport.mColumnNumber, mReport.mFlags,
    1176           0 :                            mReport.mExnType);
    1177             :         }
    1178           0 :         return true;
    1179             :       }
    1180             : 
    1181             :       // The innerWindowId is only required if we are going to ReportError
    1182             :       // below, which is gated on this condition. The inner window correctness
    1183             :       // check is only going to succeed when the worker is accepting events.
    1184           0 :       if (workerIsAcceptingEvents) {
    1185           0 :         aWorkerPrivate->AssertInnerWindowIsCorrect();
    1186           0 :         innerWindowId = aWorkerPrivate->WindowID();
    1187             :       }
    1188             :     }
    1189             : 
    1190             :     // Don't fire this event if the JS object has been disconnected from the
    1191             :     // private object.
    1192           0 :     if (!workerIsAcceptingEvents) {
    1193           0 :       return true;
    1194             :     }
    1195             : 
    1196           0 :     ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport,
    1197           0 :                 innerWindowId);
    1198           0 :     return true;
    1199             :   }
    1200             : };
    1201             : 
    1202             : class TimerRunnable final : public WorkerRunnable,
    1203             :                             public nsITimerCallback
    1204             : {
    1205             : public:
    1206             :   NS_DECL_ISUPPORTS_INHERITED
    1207             : 
    1208           0 :   explicit TimerRunnable(WorkerPrivate* aWorkerPrivate)
    1209           0 :   : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
    1210           0 :   { }
    1211             : 
    1212             : private:
    1213           0 :   ~TimerRunnable() {}
    1214             : 
    1215             :   virtual bool
    1216           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
    1217             :   {
    1218             :     // Silence bad assertions.
    1219           0 :     return true;
    1220             :   }
    1221             : 
    1222             :   virtual void
    1223           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
    1224             :   {
    1225             :     // Silence bad assertions.
    1226           0 :   }
    1227             : 
    1228             :   virtual bool
    1229           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1230             :   {
    1231           0 :     return aWorkerPrivate->RunExpiredTimeouts(aCx);
    1232             :   }
    1233             : 
    1234             :   NS_IMETHOD
    1235           0 :   Notify(nsITimer* aTimer) override
    1236             :   {
    1237           0 :     return Run();
    1238             :   }
    1239             : };
    1240             : 
    1241           0 : NS_IMPL_ISUPPORTS_INHERITED(TimerRunnable, WorkerRunnable, nsITimerCallback)
    1242             : 
    1243           0 : class DebuggerImmediateRunnable : public WorkerRunnable
    1244             : {
    1245             :   RefPtr<dom::Function> mHandler;
    1246             : 
    1247             : public:
    1248           0 :   explicit DebuggerImmediateRunnable(WorkerPrivate* aWorkerPrivate,
    1249             :                                      dom::Function& aHandler)
    1250           0 :   : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1251           0 :     mHandler(&aHandler)
    1252           0 :   { }
    1253             : 
    1254             : private:
    1255             :   virtual bool
    1256           0 :   IsDebuggerRunnable() const override
    1257             :   {
    1258           0 :     return true;
    1259             :   }
    1260             : 
    1261             :   virtual bool
    1262           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
    1263             :   {
    1264             :     // Silence bad assertions.
    1265           0 :     return true;
    1266             :   }
    1267             : 
    1268             :   virtual void
    1269           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
    1270             :   {
    1271             :     // Silence bad assertions.
    1272           0 :   }
    1273             : 
    1274             :   virtual bool
    1275           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1276             :   {
    1277           0 :     JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
    1278           0 :     JS::Rooted<JS::Value> callable(aCx, JS::ObjectOrNullValue(mHandler->CallableOrNull()));
    1279           0 :     JS::HandleValueArray args = JS::HandleValueArray::empty();
    1280           0 :     JS::Rooted<JS::Value> rval(aCx);
    1281           0 :     if (!JS_CallFunctionValue(aCx, global, callable, args, &rval)) {
    1282             :       // Just return false; WorkerRunnable::Run will report the exception.
    1283           0 :       return false;
    1284             :     }
    1285             : 
    1286           0 :     return true;
    1287             :   }
    1288             : };
    1289             : 
    1290             : void
    1291           0 : PeriodicGCTimerCallback(nsITimer* aTimer, void* aClosure)
    1292             : {
    1293           0 :   auto workerPrivate = static_cast<WorkerPrivate*>(aClosure);
    1294           0 :   MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
    1295           0 :   workerPrivate->AssertIsOnWorkerThread();
    1296           0 :   workerPrivate->GarbageCollectInternal(workerPrivate->GetJSContext(),
    1297             :                                         false /* shrinking */,
    1298           0 :                                         false /* collect children */);
    1299           0 : }
    1300             : 
    1301             : void
    1302           0 : IdleGCTimerCallback(nsITimer* aTimer, void* aClosure)
    1303             : {
    1304           0 :   auto workerPrivate = static_cast<WorkerPrivate*>(aClosure);
    1305           0 :   MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
    1306           0 :   workerPrivate->AssertIsOnWorkerThread();
    1307           0 :   workerPrivate->GarbageCollectInternal(workerPrivate->GetJSContext(),
    1308             :                                         true /* shrinking */,
    1309           0 :                                         false /* collect children */);
    1310           0 : }
    1311             : 
    1312           0 : class UpdateContextOptionsRunnable final : public WorkerControlRunnable
    1313             : {
    1314             :   JS::ContextOptions mContextOptions;
    1315             : 
    1316             : public:
    1317           0 :   UpdateContextOptionsRunnable(WorkerPrivate* aWorkerPrivate,
    1318             :                                const JS::ContextOptions& aContextOptions)
    1319           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1320           0 :     mContextOptions(aContextOptions)
    1321           0 :   { }
    1322             : 
    1323             : private:
    1324             :   virtual bool
    1325           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1326             :   {
    1327           0 :     aWorkerPrivate->UpdateContextOptionsInternal(aCx, mContextOptions);
    1328           0 :     return true;
    1329             :   }
    1330             : };
    1331             : 
    1332           0 : class UpdatePreferenceRunnable final : public WorkerControlRunnable
    1333             : {
    1334             :   WorkerPreference mPref;
    1335             :   bool mValue;
    1336             : 
    1337             : public:
    1338           0 :   UpdatePreferenceRunnable(WorkerPrivate* aWorkerPrivate,
    1339             :                            WorkerPreference aPref,
    1340             :                            bool aValue)
    1341           0 :     : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1342             :       mPref(aPref),
    1343           0 :       mValue(aValue)
    1344           0 :   { }
    1345             : 
    1346             :   virtual bool
    1347           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1348             :   {
    1349           0 :     aWorkerPrivate->UpdatePreferenceInternal(mPref, mValue);
    1350           0 :     return true;
    1351             :   }
    1352             : };
    1353             : 
    1354           0 : class UpdateLanguagesRunnable final : public WorkerRunnable
    1355             : {
    1356             :   nsTArray<nsString> mLanguages;
    1357             : 
    1358             : public:
    1359           0 :   UpdateLanguagesRunnable(WorkerPrivate* aWorkerPrivate,
    1360             :                           const nsTArray<nsString>& aLanguages)
    1361           0 :     : WorkerRunnable(aWorkerPrivate),
    1362           0 :       mLanguages(aLanguages)
    1363           0 :   { }
    1364             : 
    1365             :   virtual bool
    1366           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1367             :   {
    1368           0 :     aWorkerPrivate->UpdateLanguagesInternal(mLanguages);
    1369           0 :     return true;
    1370             :   }
    1371             : };
    1372             : 
    1373           0 : class UpdateJSWorkerMemoryParameterRunnable final :
    1374             :   public WorkerControlRunnable
    1375             : {
    1376             :   uint32_t mValue;
    1377             :   JSGCParamKey mKey;
    1378             : 
    1379             : public:
    1380           0 :   UpdateJSWorkerMemoryParameterRunnable(WorkerPrivate* aWorkerPrivate,
    1381             :                                         JSGCParamKey aKey,
    1382             :                                         uint32_t aValue)
    1383           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1384           0 :     mValue(aValue), mKey(aKey)
    1385           0 :   { }
    1386             : 
    1387             : private:
    1388             :   virtual bool
    1389           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1390             :   {
    1391           0 :     aWorkerPrivate->UpdateJSWorkerMemoryParameterInternal(aCx, mKey, mValue);
    1392           0 :     return true;
    1393             :   }
    1394             : };
    1395             : 
    1396             : #ifdef JS_GC_ZEAL
    1397           0 : class UpdateGCZealRunnable final : public WorkerControlRunnable
    1398             : {
    1399             :   uint8_t mGCZeal;
    1400             :   uint32_t mFrequency;
    1401             : 
    1402             : public:
    1403           0 :   UpdateGCZealRunnable(WorkerPrivate* aWorkerPrivate,
    1404             :                        uint8_t aGCZeal,
    1405             :                        uint32_t aFrequency)
    1406           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1407           0 :     mGCZeal(aGCZeal), mFrequency(aFrequency)
    1408           0 :   { }
    1409             : 
    1410             : private:
    1411             :   virtual bool
    1412           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1413             :   {
    1414           0 :     aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal, mFrequency);
    1415           0 :     return true;
    1416             :   }
    1417             : };
    1418             : #endif
    1419             : 
    1420           0 : class GarbageCollectRunnable final : public WorkerControlRunnable
    1421             : {
    1422             :   bool mShrinking;
    1423             :   bool mCollectChildren;
    1424             : 
    1425             : public:
    1426           0 :   GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
    1427             :                          bool aCollectChildren)
    1428           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1429           0 :     mShrinking(aShrinking), mCollectChildren(aCollectChildren)
    1430           0 :   { }
    1431             : 
    1432             : private:
    1433             :   virtual bool
    1434           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
    1435             :   {
    1436             :     // Silence bad assertions, this can be dispatched from either the main
    1437             :     // thread or the timer thread..
    1438           0 :     return true;
    1439             :   }
    1440             : 
    1441             :   virtual void
    1442           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
    1443             :   {
    1444             :     // Silence bad assertions, this can be dispatched from either the main
    1445             :     // thread or the timer thread..
    1446           0 :   }
    1447             : 
    1448             :   virtual bool
    1449           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1450             :   {
    1451           0 :     aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren);
    1452           0 :     return true;
    1453             :   }
    1454             : };
    1455             : 
    1456           0 : class CycleCollectRunnable : public WorkerControlRunnable
    1457             : {
    1458             :   bool mCollectChildren;
    1459             : 
    1460             : public:
    1461           0 :   CycleCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aCollectChildren)
    1462           0 :   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
    1463           0 :     mCollectChildren(aCollectChildren)
    1464           0 :   { }
    1465             : 
    1466             :   bool
    1467           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
    1468             :   {
    1469           0 :     aWorkerPrivate->CycleCollectInternal(mCollectChildren);
    1470           0 :     return true;
    1471             :   }
    1472             : };
    1473             : 
    1474           0 : class OfflineStatusChangeRunnable : public WorkerRunnable
    1475             : {
    1476             : public:
    1477           0 :   OfflineStatusChangeRunnable(WorkerPrivate* aWorkerPrivate, bool aIsOffline)
    1478           0 :     : WorkerRunnable(aWorkerPrivate),
    1479           0 :       mIsOffline(aIsOffline)
    1480             :   {
    1481           0 :   }
    1482             : 
    1483             :   bool
    1484           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
    1485             :   {
    1486           0 :     aWorkerPrivate->OfflineStatusChangeEventInternal(mIsOffline);
    1487           0 :     return true;
    1488             :   }
    1489             : 
    1490             : private:
    1491             :   bool mIsOffline;
    1492             : };
    1493             : 
    1494           0 : class MemoryPressureRunnable : public WorkerControlRunnable
    1495             : {
    1496             : public:
    1497           0 :   explicit MemoryPressureRunnable(WorkerPrivate* aWorkerPrivate)
    1498           0 :     : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
    1499           0 :   {}
    1500             : 
    1501             :   bool
    1502           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
    1503             :   {
    1504           0 :     aWorkerPrivate->MemoryPressureInternal();
    1505           0 :     return true;
    1506             :   }
    1507             : };
    1508             : 
    1509             : #ifdef DEBUG
    1510             : static bool
    1511           0 : StartsWithExplicit(nsACString& s)
    1512             : {
    1513           0 :     return StringBeginsWith(s, NS_LITERAL_CSTRING("explicit/"));
    1514             : }
    1515             : #endif
    1516             : 
    1517             : class MessagePortRunnable final : public WorkerRunnable
    1518             : {
    1519             :   MessagePortIdentifier mPortIdentifier;
    1520             : 
    1521             : public:
    1522           0 :   MessagePortRunnable(WorkerPrivate* aWorkerPrivate, MessagePort* aPort)
    1523           0 :   : WorkerRunnable(aWorkerPrivate)
    1524             :   {
    1525           0 :     MOZ_ASSERT(aPort);
    1526             :     // In order to move the port from one thread to another one, we have to
    1527             :     // close and disentangle it. The output will be a MessagePortIdentifier that
    1528             :     // will be used to recreate a new MessagePort on the other thread.
    1529           0 :     aPort->CloneAndDisentangle(mPortIdentifier);
    1530           0 :   }
    1531             : 
    1532             : private:
    1533           0 :   ~MessagePortRunnable()
    1534           0 :   { }
    1535             : 
    1536             :   virtual bool
    1537           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1538             :   {
    1539           0 :     return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
    1540             :   }
    1541             : 
    1542             :   nsresult
    1543           0 :   Cancel() override
    1544             :   {
    1545           0 :     MessagePort::ForceClose(mPortIdentifier);
    1546           0 :     return WorkerRunnable::Cancel();
    1547             :   }
    1548             : };
    1549             : 
    1550             : PRThread*
    1551           1 : PRThreadFromThread(nsIThread* aThread)
    1552             : {
    1553           1 :   MOZ_ASSERT(aThread);
    1554             : 
    1555             :   PRThread* result;
    1556           1 :   MOZ_ALWAYS_SUCCEEDS(aThread->GetPRThread(&result));
    1557           1 :   MOZ_ASSERT(result);
    1558             : 
    1559           1 :   return result;
    1560             : }
    1561             : 
    1562           0 : class SimpleWorkerHolder final : public WorkerHolder
    1563             : {
    1564             : public:
    1565           0 :   virtual bool Notify(Status aStatus) { return true; }
    1566             : };
    1567             : 
    1568             : } /* anonymous namespace */
    1569             : 
    1570           0 : NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, Runnable)
    1571             : 
    1572           0 : NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, Runnable)
    1573             : 
    1574             : namespace {
    1575             : 
    1576             : class WrappedControlRunnable final : public WorkerControlRunnable
    1577             : {
    1578             :   nsCOMPtr<nsIRunnable> mInner;
    1579             : 
    1580           0 :   ~WrappedControlRunnable()
    1581           0 :   {
    1582           0 :   }
    1583             : 
    1584             : public:
    1585           0 :   WrappedControlRunnable(WorkerPrivate* aWorkerPrivate,
    1586             :                          already_AddRefed<nsIRunnable>&& aInner)
    1587           0 :     : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
    1588           0 :     , mInner(aInner)
    1589             :   {
    1590           0 :   }
    1591             : 
    1592             :   virtual bool
    1593           0 :   PreDispatch(WorkerPrivate* aWorkerPrivate) override
    1594             :   {
    1595             :     // Silence bad assertions, this can be dispatched from any thread.
    1596           0 :     return true;
    1597             :   }
    1598             : 
    1599             :   virtual void
    1600           0 :   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
    1601             :   {
    1602             :     // Silence bad assertions, this can be dispatched from any thread.
    1603           0 :   }
    1604             : 
    1605             :   bool
    1606           0 :   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
    1607             :   {
    1608           0 :     mInner->Run();
    1609           0 :     return true;
    1610             :   }
    1611             : 
    1612             :   nsresult
    1613           0 :   Cancel() override
    1614             :   {
    1615             :     // First run the default cancelation code
    1616           0 :     WorkerControlRunnable::Cancel();
    1617             : 
    1618             :     // Attempt to cancel the inner runnable as well
    1619           0 :     nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner);
    1620           0 :     if (cr) {
    1621           0 :       return cr->Cancel();
    1622             :     }
    1623           0 :     return NS_OK;
    1624             :   }
    1625             : };
    1626             : 
    1627             : } // anonymous namespace
    1628             : 
    1629             : BEGIN_WORKERS_NAMESPACE
    1630             : 
    1631             : class WorkerControlEventTarget final : public nsIEventTarget
    1632             : {
    1633             :   mozilla::Mutex mMutex;
    1634             :   WorkerPrivate* mWorkerPrivate;
    1635             : 
    1636           0 :   ~WorkerControlEventTarget() = default;
    1637             : 
    1638             : public:
    1639           1 :   explicit WorkerControlEventTarget(WorkerPrivate* aWorkerPrivate)
    1640           1 :     : mMutex("WorkerControlEventTarget")
    1641           1 :     , mWorkerPrivate(aWorkerPrivate)
    1642             :   {
    1643           1 :     MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate);
    1644           1 :   }
    1645             : 
    1646             :   void
    1647           0 :   ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate)
    1648             :   {
    1649           0 :     MutexAutoLock lock(mMutex);
    1650           0 :     MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate == aWorkerPrivate);
    1651           0 :     mWorkerPrivate = nullptr;
    1652           0 :   }
    1653             : 
    1654             :   NS_IMETHOD
    1655           0 :   DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override
    1656             :   {
    1657           0 :     nsCOMPtr<nsIRunnable> runnable(aRunnable);
    1658           0 :     return Dispatch(runnable.forget(), aFlags);
    1659             :   }
    1660             : 
    1661             :   NS_IMETHOD
    1662           0 :   Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL) override
    1663             :   {
    1664           0 :     MutexAutoLock lock(mMutex);
    1665             : 
    1666           0 :     if (!mWorkerPrivate) {
    1667           0 :       return NS_ERROR_FAILURE;
    1668             :     }
    1669             : 
    1670             :     RefPtr<WorkerControlRunnable> r = new WrappedControlRunnable(mWorkerPrivate,
    1671           0 :                                                                  Move(aRunnable));
    1672           0 :     if (!r->Dispatch()) {
    1673           0 :       return NS_ERROR_FAILURE;
    1674             :     }
    1675             : 
    1676           0 :     return NS_OK;
    1677             :   }
    1678             : 
    1679             :   NS_IMETHOD
    1680           0 :   DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override
    1681             :   {
    1682           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1683             :   }
    1684             : 
    1685           0 :   NS_IMETHOD_(bool) IsOnCurrentThreadInfallible() override
    1686             :   {
    1687           0 :     MutexAutoLock lock(mMutex);
    1688             : 
    1689           0 :     if (!mWorkerPrivate) {
    1690           0 :       return false;
    1691             :     }
    1692             : 
    1693           0 :     return mWorkerPrivate->IsOnCurrentThread();
    1694             :   }
    1695             : 
    1696             :   NS_IMETHOD
    1697           0 :   IsOnCurrentThread(bool* aIsOnCurrentThread) override
    1698             :   {
    1699           0 :     MOZ_ASSERT(aIsOnCurrentThread);
    1700           0 :     *aIsOnCurrentThread = IsOnCurrentThreadInfallible();
    1701           0 :     return NS_OK;
    1702             :   }
    1703             : 
    1704             :   NS_DECL_THREADSAFE_ISUPPORTS
    1705             : };
    1706             : 
    1707         260 : NS_IMPL_ISUPPORTS(WorkerControlEventTarget, nsIEventTarget)
    1708             : 
    1709             : END_WORKERS_NAMESPACE
    1710             : 
    1711           3 : WorkerLoadInfo::WorkerLoadInfo()
    1712             :   : mLoadFlags(nsIRequest::LOAD_NORMAL)
    1713             :   , mWindowID(UINT64_MAX)
    1714             :   , mServiceWorkerID(0)
    1715             :   , mReferrerPolicy(net::RP_Unset)
    1716             :   , mFromWindow(false)
    1717             :   , mEvalAllowed(false)
    1718             :   , mReportCSPViolations(false)
    1719             :   , mXHRParamsAllowed(false)
    1720             :   , mPrincipalIsSystem(false)
    1721             :   , mStorageAllowed(false)
    1722           3 :   , mServiceWorkersTestingInWindow(false)
    1723             : {
    1724           3 :   MOZ_COUNT_CTOR(WorkerLoadInfo);
    1725           3 : }
    1726             : 
    1727           4 : WorkerLoadInfo::~WorkerLoadInfo()
    1728             : {
    1729           2 :   MOZ_COUNT_DTOR(WorkerLoadInfo);
    1730           2 : }
    1731             : 
    1732             : void
    1733           2 : WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
    1734             : {
    1735           2 :   MOZ_ASSERT(!mBaseURI);
    1736           2 :   aOther.mBaseURI.swap(mBaseURI);
    1737             : 
    1738           2 :   MOZ_ASSERT(!mResolvedScriptURI);
    1739           2 :   aOther.mResolvedScriptURI.swap(mResolvedScriptURI);
    1740             : 
    1741           2 :   MOZ_ASSERT(!mPrincipal);
    1742           2 :   aOther.mPrincipal.swap(mPrincipal);
    1743             : 
    1744           2 :   MOZ_ASSERT(!mScriptContext);
    1745           2 :   aOther.mScriptContext.swap(mScriptContext);
    1746             : 
    1747           2 :   MOZ_ASSERT(!mWindow);
    1748           2 :   aOther.mWindow.swap(mWindow);
    1749             : 
    1750           2 :   MOZ_ASSERT(!mCSP);
    1751           2 :   aOther.mCSP.swap(mCSP);
    1752             : 
    1753           2 :   MOZ_ASSERT(!mChannel);
    1754           2 :   aOther.mChannel.swap(mChannel);
    1755             : 
    1756           2 :   MOZ_ASSERT(!mLoadGroup);
    1757           2 :   aOther.mLoadGroup.swap(mLoadGroup);
    1758             : 
    1759           2 :   MOZ_ASSERT(!mLoadFailedAsyncRunnable);
    1760           2 :   aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
    1761             : 
    1762           2 :   MOZ_ASSERT(!mInterfaceRequestor);
    1763           2 :   aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
    1764             : 
    1765           2 :   MOZ_ASSERT(!mPrincipalInfo);
    1766           2 :   mPrincipalInfo = aOther.mPrincipalInfo.forget();
    1767             : 
    1768           2 :   mDomain = aOther.mDomain;
    1769           2 :   mOrigin = aOther.mOrigin;
    1770           2 :   mServiceWorkerCacheName = aOther.mServiceWorkerCacheName;
    1771           2 :   mLoadFlags = aOther.mLoadFlags;
    1772           2 :   mWindowID = aOther.mWindowID;
    1773           2 :   mServiceWorkerID = aOther.mServiceWorkerID;
    1774           2 :   mReferrerPolicy = aOther.mReferrerPolicy;
    1775           2 :   mFromWindow = aOther.mFromWindow;
    1776           2 :   mEvalAllowed = aOther.mEvalAllowed;
    1777           2 :   mReportCSPViolations = aOther.mReportCSPViolations;
    1778           2 :   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
    1779           2 :   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
    1780           2 :   mStorageAllowed = aOther.mStorageAllowed;
    1781           2 :   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
    1782           2 :   mOriginAttributes = aOther.mOriginAttributes;
    1783           2 : }
    1784             : 
    1785             : nsresult
    1786           2 : WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
    1787             :                                          nsILoadGroup* aLoadGroup)
    1788             : {
    1789           2 :   AssertIsOnMainThread();
    1790           2 :   MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
    1791             : 
    1792           2 :   mPrincipal = aPrincipal;
    1793           2 :   mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
    1794             : 
    1795           2 :   nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
    1796           2 :   NS_ENSURE_SUCCESS(rv, rv);
    1797             : 
    1798           2 :   if (mCSP) {
    1799           0 :     mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
    1800             :     // Set ReferrerPolicy
    1801           0 :     bool hasReferrerPolicy = false;
    1802           0 :     uint32_t rp = mozilla::net::RP_Unset;
    1803             : 
    1804           0 :     rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
    1805           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1806             : 
    1807           0 :     if (hasReferrerPolicy) {
    1808           0 :       mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
    1809             :     }
    1810             :   } else {
    1811           2 :     mEvalAllowed = true;
    1812           2 :     mReportCSPViolations = false;
    1813             :   }
    1814             : 
    1815           2 :   mLoadGroup = aLoadGroup;
    1816             : 
    1817           2 :   mPrincipalInfo = new PrincipalInfo();
    1818           2 :   mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
    1819             : 
    1820           2 :   rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
    1821           2 :   NS_ENSURE_SUCCESS(rv, rv);
    1822             : 
    1823           2 :   rv = nsContentUtils::GetUTFOrigin(aPrincipal, mOrigin);
    1824           2 :   NS_ENSURE_SUCCESS(rv, rv);
    1825             : 
    1826           2 :   return NS_OK;
    1827             : }
    1828             : 
    1829             : nsresult
    1830           3 : WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
    1831             :                                                     nsIPrincipal** aPrincipalOut,
    1832             :                                                     nsILoadGroup** aLoadGroupOut)
    1833             : {
    1834           3 :   AssertIsOnMainThread();
    1835           3 :   MOZ_DIAGNOSTIC_ASSERT(aChannel);
    1836           3 :   MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
    1837           3 :   MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
    1838             : 
    1839             :   // Initial triggering principal should be set
    1840           3 :   MOZ_DIAGNOSTIC_ASSERT(mPrincipal);
    1841             : 
    1842           3 :   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
    1843           3 :   MOZ_DIAGNOSTIC_ASSERT(ssm);
    1844             : 
    1845           6 :   nsCOMPtr<nsIPrincipal> channelPrincipal;
    1846           3 :   nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
    1847           3 :   NS_ENSURE_SUCCESS(rv, rv);
    1848             : 
    1849           6 :   nsCOMPtr<nsILoadGroup> channelLoadGroup;
    1850           3 :   rv = aChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
    1851           3 :   NS_ENSURE_SUCCESS(rv, rv);
    1852           3 :   MOZ_ASSERT(channelLoadGroup);
    1853             : 
    1854             :   // If the load principal is the system principal then the channel
    1855             :   // principal must also be the system principal (we do not allow chrome
    1856             :   // code to create workers with non-chrome scripts, and if we ever decide
    1857             :   // to change this we need to make sure we don't always set
    1858             :   // mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise
    1859             :   // this channel principal must be same origin with the load principal (we
    1860             :   // check again here in case redirects changed the location of the script).
    1861           3 :   if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
    1862           3 :     if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
    1863           6 :       nsCOMPtr<nsIURI> finalURI;
    1864           3 :       rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
    1865           3 :       NS_ENSURE_SUCCESS(rv, rv);
    1866             : 
    1867             :       // See if this is a resource URI. Since JSMs usually come from
    1868             :       // resource:// URIs we're currently considering all URIs with the
    1869             :       // URI_IS_UI_RESOURCE flag as valid for creating privileged workers.
    1870             :       bool isResource;
    1871           3 :       rv = NS_URIChainHasFlags(finalURI,
    1872             :                                nsIProtocolHandler::URI_IS_UI_RESOURCE,
    1873           3 :                                &isResource);
    1874           3 :       NS_ENSURE_SUCCESS(rv, rv);
    1875             : 
    1876           3 :       if (isResource) {
    1877             :         // Assign the system principal to the resource:// worker only if it
    1878             :         // was loaded from code using the system principal.
    1879           3 :         channelPrincipal = mPrincipal;
    1880             :       } else {
    1881           0 :         return NS_ERROR_DOM_BAD_URI;
    1882             :       }
    1883             :     }
    1884             :   }
    1885             : 
    1886             :   // The principal can change, but it should still match the original
    1887             :   // load group's appId and browser element flag.
    1888           3 :   MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
    1889             : 
    1890           3 :   channelPrincipal.forget(aPrincipalOut);
    1891           3 :   channelLoadGroup.forget(aLoadGroupOut);
    1892             : 
    1893           3 :   return NS_OK;
    1894             : }
    1895             : 
    1896             : nsresult
    1897           2 : WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
    1898             : {
    1899           2 :   AssertIsOnMainThread();
    1900             : 
    1901           4 :   nsCOMPtr<nsIPrincipal> principal;
    1902           4 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1903           4 :   nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
    1904           4 :                                                     getter_AddRefs(principal),
    1905           6 :                                                     getter_AddRefs(loadGroup));
    1906           2 :   NS_ENSURE_SUCCESS(rv, rv);
    1907             : 
    1908           2 :   return SetPrincipalOnMainThread(principal, loadGroup);
    1909             : }
    1910             : 
    1911             : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    1912             : bool
    1913           1 : WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
    1914             : {
    1915           1 :   AssertIsOnMainThread();
    1916             : 
    1917           2 :   nsCOMPtr<nsIPrincipal> principal;
    1918           2 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1919           2 :   nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
    1920           2 :                                                     getter_AddRefs(principal),
    1921           3 :                                                     getter_AddRefs(loadGroup));
    1922           1 :   NS_ENSURE_SUCCESS(rv, false);
    1923             : 
    1924             : 
    1925             :   // Verify that the channel is still a null principal.  We don't care
    1926             :   // if these are the exact same null principal object, though.  From
    1927             :   // the worker's perspective its the same effect.
    1928           1 :   if (principal->GetIsNullPrincipal() && mPrincipal->GetIsNullPrincipal()) {
    1929           0 :     return true;
    1930             :   }
    1931             : 
    1932             :   // Otherwise we require exact equality.  Redirects can happen, but they
    1933             :   // are not allowed to change our principal.
    1934           1 :   if (principal->Equals(mPrincipal)) {
    1935           1 :     return true;
    1936             :   }
    1937             : 
    1938           0 :   return false;
    1939             : }
    1940             : 
    1941             : bool
    1942           2 : WorkerLoadInfo::PrincipalIsValid() const
    1943             : {
    1944           6 :   return mPrincipal && mPrincipalInfo &&
    1945           6 :          mPrincipalInfo->type() != PrincipalInfo::T__None &&
    1946           4 :          mPrincipalInfo->type() <= PrincipalInfo::T__Last;
    1947             : }
    1948             : 
    1949             : bool
    1950           1 : WorkerLoadInfo::PrincipalURIMatchesScriptURL()
    1951             : {
    1952           1 :   AssertIsOnMainThread();
    1953             : 
    1954           2 :   nsAutoCString scheme;
    1955           1 :   nsresult rv = mBaseURI->GetScheme(scheme);
    1956           1 :   NS_ENSURE_SUCCESS(rv, false);
    1957             : 
    1958             :   // A system principal must either be a blob URL or a resource JSM.
    1959           1 :   if (mPrincipal->GetIsSystemPrincipal()) {
    1960           1 :     if (scheme == NS_LITERAL_CSTRING("blob")) {
    1961           0 :       return true;
    1962             :     }
    1963             : 
    1964           1 :     bool isResource = false;
    1965           1 :     nsresult rv = NS_URIChainHasFlags(mBaseURI,
    1966             :                                       nsIProtocolHandler::URI_IS_UI_RESOURCE,
    1967           1 :                                       &isResource);
    1968           1 :     NS_ENSURE_SUCCESS(rv, false);
    1969             : 
    1970           1 :     return isResource;
    1971             :   }
    1972             : 
    1973             :   // A null principal can occur for a data URL worker script or a blob URL
    1974             :   // worker script from a sandboxed iframe.
    1975           0 :   if (mPrincipal->GetIsNullPrincipal()) {
    1976           0 :     return scheme == NS_LITERAL_CSTRING("data") ||
    1977           0 :            scheme == NS_LITERAL_CSTRING("blob");
    1978             :   }
    1979             : 
    1980             :   // The principal for a blob: URL worker script does not have a matching URL.
    1981             :   // This is likely a bug in our referer setting logic, but exempt it for now.
    1982             :   // This is another reason we should fix bug 1340694 so that referer does not
    1983             :   // depend on the principal URI.
    1984           0 :   if (scheme == NS_LITERAL_CSTRING("blob")) {
    1985           0 :     return true;
    1986             :   }
    1987             : 
    1988           0 :   nsCOMPtr<nsIURI> principalURI;
    1989           0 :   rv = mPrincipal->GetURI(getter_AddRefs(principalURI));
    1990           0 :   NS_ENSURE_SUCCESS(rv, false);
    1991           0 :   NS_ENSURE_TRUE(principalURI, false);
    1992             : 
    1993           0 :   bool equal = false;
    1994           0 :   rv = principalURI->Equals(mBaseURI, &equal);
    1995           0 :   NS_ENSURE_SUCCESS(rv, false);
    1996             : 
    1997           0 :   return equal;
    1998             : }
    1999             : #endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
    2000             : 
    2001             : bool
    2002           0 : WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
    2003             : {
    2004           0 :   nsCOMPtr<nsILoadGroup> nullLoadGroup;
    2005           0 :   return ProxyReleaseMainThreadObjects(aWorkerPrivate, nullLoadGroup);
    2006             : }
    2007             : 
    2008             : bool
    2009           0 : WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
    2010             :                                               nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
    2011             : {
    2012             : 
    2013             :   static const uint32_t kDoomedCount = 10;
    2014           0 :   nsTArray<nsCOMPtr<nsISupports>> doomed(kDoomedCount);
    2015             : 
    2016           0 :   SwapToISupportsArray(mWindow, doomed);
    2017           0 :   SwapToISupportsArray(mScriptContext, doomed);
    2018           0 :   SwapToISupportsArray(mBaseURI, doomed);
    2019           0 :   SwapToISupportsArray(mResolvedScriptURI, doomed);
    2020           0 :   SwapToISupportsArray(mPrincipal, doomed);
    2021           0 :   SwapToISupportsArray(mChannel, doomed);
    2022           0 :   SwapToISupportsArray(mCSP, doomed);
    2023           0 :   SwapToISupportsArray(mLoadGroup, doomed);
    2024           0 :   SwapToISupportsArray(mLoadFailedAsyncRunnable, doomed);
    2025           0 :   SwapToISupportsArray(mInterfaceRequestor, doomed);
    2026             :   // Before adding anything here update kDoomedCount above!
    2027             : 
    2028           0 :   MOZ_ASSERT(doomed.Length() == kDoomedCount);
    2029             : 
    2030             :   RefPtr<MainThreadReleaseRunnable> runnable =
    2031           0 :     new MainThreadReleaseRunnable(doomed, aLoadGroupToCancel);
    2032           0 :   return NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(runnable.forget()));
    2033             : }
    2034             : 
    2035             : template <class Derived>
    2036             : class WorkerPrivateParent<Derived>::EventTarget final
    2037             :   : public nsISerialEventTarget
    2038             : {
    2039             :   // This mutex protects mWorkerPrivate and must be acquired *before* the
    2040             :   // WorkerPrivate's mutex whenever they must both be held.
    2041             :   mozilla::Mutex mMutex;
    2042             :   WorkerPrivate* mWorkerPrivate;
    2043             :   nsIEventTarget* mWeakNestedEventTarget;
    2044             :   nsCOMPtr<nsIEventTarget> mNestedEventTarget;
    2045             : 
    2046             : public:
    2047           1 :   explicit EventTarget(WorkerPrivate* aWorkerPrivate)
    2048             :   : mMutex("WorkerPrivateParent::EventTarget::mMutex"),
    2049           1 :     mWorkerPrivate(aWorkerPrivate), mWeakNestedEventTarget(nullptr)
    2050             :   {
    2051           1 :     MOZ_ASSERT(aWorkerPrivate);
    2052           1 :   }
    2053             : 
    2054          17 :   EventTarget(WorkerPrivate* aWorkerPrivate, nsIEventTarget* aNestedEventTarget)
    2055             :   : mMutex("WorkerPrivateParent::EventTarget::mMutex"),
    2056             :     mWorkerPrivate(aWorkerPrivate), mWeakNestedEventTarget(aNestedEventTarget),
    2057          17 :     mNestedEventTarget(aNestedEventTarget)
    2058             :   {
    2059          17 :     MOZ_ASSERT(aWorkerPrivate);
    2060          17 :     MOZ_ASSERT(aNestedEventTarget);
    2061          17 :   }
    2062             : 
    2063             :   void
    2064          13 :   Disable()
    2065             :   {
    2066          26 :     nsCOMPtr<nsIEventTarget> nestedEventTarget;
    2067             :     {
    2068          26 :       MutexAutoLock lock(mMutex);
    2069             : 
    2070             :       // Note, Disable() can be called more than once safely.
    2071          13 :       mWorkerPrivate = nullptr;
    2072          13 :       mNestedEventTarget.swap(nestedEventTarget);
    2073             :     }
    2074          13 :   }
    2075             : 
    2076             :   nsIEventTarget*
    2077          13 :   GetWeakNestedEventTarget() const
    2078             :   {
    2079          13 :     MOZ_ASSERT(mWeakNestedEventTarget);
    2080          13 :     return mWeakNestedEventTarget;
    2081             :   }
    2082             : 
    2083             :   NS_DECL_THREADSAFE_ISUPPORTS
    2084             :   NS_DECL_NSIEVENTTARGET_FULL
    2085             : 
    2086             : private:
    2087          13 :   ~EventTarget()
    2088          13 :   { }
    2089             : };
    2090             : 
    2091           1 : WorkerLoadInfo::
    2092             : InterfaceRequestor::InterfaceRequestor(nsIPrincipal* aPrincipal,
    2093           1 :                                        nsILoadGroup* aLoadGroup)
    2094             : {
    2095           1 :   MOZ_ASSERT(NS_IsMainThread());
    2096           1 :   MOZ_ASSERT(aPrincipal);
    2097             : 
    2098             :   // Look for an existing LoadContext.  This is optional and it's ok if
    2099             :   // we don't find one.
    2100           2 :   nsCOMPtr<nsILoadContext> baseContext;
    2101           1 :   if (aLoadGroup) {
    2102           0 :     nsCOMPtr<nsIInterfaceRequestor> callbacks;
    2103           0 :     aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
    2104           0 :     if (callbacks) {
    2105           0 :       callbacks->GetInterface(NS_GET_IID(nsILoadContext),
    2106           0 :                               getter_AddRefs(baseContext));
    2107             :     }
    2108           0 :     mOuterRequestor = callbacks;
    2109             :   }
    2110             : 
    2111           2 :   mLoadContext = new LoadContext(aPrincipal, baseContext);
    2112           1 : }
    2113             : 
    2114             : void
    2115           1 : WorkerLoadInfo::
    2116             : InterfaceRequestor::MaybeAddTabChild(nsILoadGroup* aLoadGroup)
    2117             : {
    2118           1 :   MOZ_ASSERT(NS_IsMainThread());
    2119             : 
    2120           1 :   if (!aLoadGroup) {
    2121           2 :     return;
    2122             :   }
    2123             : 
    2124           0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks;
    2125           0 :   aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
    2126           0 :   if (!callbacks) {
    2127           0 :     return;
    2128             :   }
    2129             : 
    2130           0 :   nsCOMPtr<nsITabChild> tabChild;
    2131           0 :   callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
    2132           0 :   if (!tabChild) {
    2133           0 :     return;
    2134             :   }
    2135             : 
    2136             :   // Use weak references to the tab child.  Holding a strong reference will
    2137             :   // not prevent an ActorDestroy() from being called on the TabChild.
    2138             :   // Therefore, we should let the TabChild destroy itself as soon as possible.
    2139           0 :   mTabChildList.AppendElement(do_GetWeakReference(tabChild));
    2140             : }
    2141             : 
    2142             : NS_IMETHODIMP
    2143          59 : WorkerLoadInfo::
    2144             : InterfaceRequestor::GetInterface(const nsIID& aIID, void** aSink)
    2145             : {
    2146          59 :   MOZ_ASSERT(NS_IsMainThread());
    2147          59 :   MOZ_ASSERT(mLoadContext);
    2148             : 
    2149          59 :   if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
    2150         102 :     nsCOMPtr<nsILoadContext> ref = mLoadContext;
    2151          51 :     ref.forget(aSink);
    2152          51 :     return NS_OK;
    2153             :   }
    2154             : 
    2155             :   // If we still have an active nsITabChild, then return it.  Its possible,
    2156             :   // though, that all of the TabChild objects have been destroyed.  In that
    2157             :   // case we return NS_NOINTERFACE.
    2158           8 :   if (aIID.Equals(NS_GET_IID(nsITabChild))) {
    2159           0 :     nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
    2160           0 :     if (!tabChild) {
    2161           0 :       return NS_NOINTERFACE;
    2162             :     }
    2163           0 :     tabChild.forget(aSink);
    2164           0 :     return NS_OK;
    2165             :   }
    2166             : 
    2167           8 :   if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
    2168           0 :       mOuterRequestor) {
    2169             :     // If asked for the network intercept controller, ask the outer requestor,
    2170             :     // which could be the docshell.
    2171           0 :     return mOuterRequestor->GetInterface(aIID, aSink);
    2172             :   }
    2173             : 
    2174           8 :   return NS_NOINTERFACE;
    2175             : }
    2176             : 
    2177             : already_AddRefed<nsITabChild>
    2178           0 : WorkerLoadInfo::
    2179             : InterfaceRequestor::GetAnyLiveTabChild()
    2180             : {
    2181           0 :   MOZ_ASSERT(NS_IsMainThread());
    2182             : 
    2183             :   // Search our list of known TabChild objects for one that still exists.
    2184           0 :   while (!mTabChildList.IsEmpty()) {
    2185             :     nsCOMPtr<nsITabChild> tabChild =
    2186           0 :       do_QueryReferent(mTabChildList.LastElement());
    2187             : 
    2188             :     // Does this tab child still exist?  If so, return it.  We are done.  If the
    2189             :     // PBrowser actor is no longer useful, don't bother returning this tab.
    2190           0 :     if (tabChild && !static_cast<TabChild*>(tabChild.get())->IsDestroyed()) {
    2191           0 :       return tabChild.forget();
    2192             :     }
    2193             : 
    2194             :     // Otherwise remove the stale weak reference and check the next one
    2195           0 :     mTabChildList.RemoveElementAt(mTabChildList.Length() - 1);
    2196             :   }
    2197             : 
    2198           0 :   return nullptr;
    2199             : }
    2200             : 
    2201         134 : NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
    2202         132 : NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
    2203          73 : NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor, nsIInterfaceRequestor)
    2204             : 
    2205             : struct WorkerPrivate::TimeoutInfo
    2206             : {
    2207           0 :   TimeoutInfo()
    2208           0 :   : mId(0), mIsInterval(false), mCanceled(false)
    2209             :   {
    2210           0 :     MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
    2211           0 :   }
    2212             : 
    2213           0 :   ~TimeoutInfo()
    2214           0 :   {
    2215           0 :     MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
    2216           0 :   }
    2217             : 
    2218           0 :   bool operator==(const TimeoutInfo& aOther)
    2219             :   {
    2220           0 :     return mTargetTime == aOther.mTargetTime;
    2221             :   }
    2222             : 
    2223           0 :   bool operator<(const TimeoutInfo& aOther)
    2224             :   {
    2225           0 :     return mTargetTime < aOther.mTargetTime;
    2226             :   }
    2227             : 
    2228             :   nsCOMPtr<nsIScriptTimeoutHandler> mHandler;
    2229             :   mozilla::TimeStamp mTargetTime;
    2230             :   mozilla::TimeDuration mInterval;
    2231             :   int32_t mId;
    2232             :   bool mIsInterval;
    2233             :   bool mCanceled;
    2234             : };
    2235             : 
    2236             : class WorkerJSContextStats final : public JS::RuntimeStats
    2237             : {
    2238             :   const nsCString mRtPath;
    2239             : 
    2240             : public:
    2241           0 :   explicit WorkerJSContextStats(const nsACString& aRtPath)
    2242           0 :   : JS::RuntimeStats(JsWorkerMallocSizeOf), mRtPath(aRtPath)
    2243           0 :   { }
    2244             : 
    2245           0 :   ~WorkerJSContextStats()
    2246           0 :   {
    2247           0 :     for (size_t i = 0; i != zoneStatsVector.length(); i++) {
    2248           0 :       delete static_cast<xpc::ZoneStatsExtras*>(zoneStatsVector[i].extra);
    2249             :     }
    2250             : 
    2251           0 :     for (size_t i = 0; i != compartmentStatsVector.length(); i++) {
    2252           0 :       delete static_cast<xpc::CompartmentStatsExtras*>(compartmentStatsVector[i].extra);
    2253             :     }
    2254           0 :   }
    2255             : 
    2256           0 :   const nsCString& Path() const
    2257             :   {
    2258           0 :     return mRtPath;
    2259             :   }
    2260             : 
    2261             :   virtual void
    2262           0 :   initExtraZoneStats(JS::Zone* aZone,
    2263             :                      JS::ZoneStats* aZoneStats)
    2264             :                      override
    2265             :   {
    2266           0 :     MOZ_ASSERT(!aZoneStats->extra);
    2267             : 
    2268             :     // ReportJSRuntimeExplicitTreeStats expects that
    2269             :     // aZoneStats->extra is a xpc::ZoneStatsExtras pointer.
    2270           0 :     xpc::ZoneStatsExtras* extras = new xpc::ZoneStatsExtras;
    2271           0 :     extras->pathPrefix = mRtPath;
    2272           0 :     extras->pathPrefix += nsPrintfCString("zone(0x%p)/", (void *)aZone);
    2273             : 
    2274           0 :     MOZ_ASSERT(StartsWithExplicit(extras->pathPrefix));
    2275             : 
    2276           0 :     aZoneStats->extra = extras;
    2277           0 :   }
    2278             : 
    2279             :   virtual void
    2280           0 :   initExtraCompartmentStats(JSCompartment* aCompartment,
    2281             :                             JS::CompartmentStats* aCompartmentStats)
    2282             :                             override
    2283             :   {
    2284           0 :     MOZ_ASSERT(!aCompartmentStats->extra);
    2285             : 
    2286             :     // ReportJSRuntimeExplicitTreeStats expects that
    2287             :     // aCompartmentStats->extra is a xpc::CompartmentStatsExtras pointer.
    2288           0 :     xpc::CompartmentStatsExtras* extras = new xpc::CompartmentStatsExtras;
    2289             : 
    2290             :     // This is the |jsPathPrefix|.  Each worker has exactly two compartments:
    2291             :     // one for atoms, and one for everything else.
    2292           0 :     extras->jsPathPrefix.Assign(mRtPath);
    2293           0 :     extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/",
    2294           0 :                                             (void *)js::GetCompartmentZone(aCompartment));
    2295           0 :     extras->jsPathPrefix += js::IsAtomsCompartment(aCompartment)
    2296           0 :                             ? NS_LITERAL_CSTRING("compartment(web-worker-atoms)/")
    2297           0 :                             : NS_LITERAL_CSTRING("compartment(web-worker)/");
    2298             : 
    2299             :     // This should never be used when reporting with workers (hence the "?!").
    2300           0 :     extras->domPathPrefix.AssignLiteral("explicit/workers/?!/");
    2301             : 
    2302           0 :     MOZ_ASSERT(StartsWithExplicit(extras->jsPathPrefix));
    2303           0 :     MOZ_ASSERT(StartsWithExplicit(extras->domPathPrefix));
    2304             : 
    2305           0 :     extras->location = nullptr;
    2306             : 
    2307           0 :     aCompartmentStats->extra = extras;
    2308           0 :   }
    2309             : };
    2310             : 
    2311             : class WorkerPrivate::MemoryReporter final : public nsIMemoryReporter
    2312             : {
    2313             :   NS_DECL_THREADSAFE_ISUPPORTS
    2314             : 
    2315             :   friend class WorkerPrivate;
    2316             : 
    2317             :   SharedMutex mMutex;
    2318             :   WorkerPrivate* mWorkerPrivate;
    2319             :   bool mAlreadyMappedToAddon;
    2320             : 
    2321             : public:
    2322           1 :   explicit MemoryReporter(WorkerPrivate* aWorkerPrivate)
    2323           1 :   : mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate),
    2324           1 :     mAlreadyMappedToAddon(false)
    2325             :   {
    2326           1 :     aWorkerPrivate->AssertIsOnWorkerThread();
    2327           1 :   }
    2328             : 
    2329             :   NS_IMETHOD
    2330             :   CollectReports(nsIHandleReportCallback* aHandleReport,
    2331             :                  nsISupports* aData, bool aAnonymize) override;
    2332             : 
    2333             : private:
    2334             :   class FinishCollectRunnable;
    2335             : 
    2336             :   class CollectReportsRunnable final : public MainThreadWorkerControlRunnable
    2337             :   {
    2338             :     RefPtr<FinishCollectRunnable> mFinishCollectRunnable;
    2339             :     const bool mAnonymize;
    2340             : 
    2341             :   public:
    2342             :     CollectReportsRunnable(
    2343             :       WorkerPrivate* aWorkerPrivate,
    2344             :       nsIHandleReportCallback* aHandleReport,
    2345             :       nsISupports* aHandlerData,
    2346             :       bool aAnonymize,
    2347             :       const nsACString& aPath);
    2348             : 
    2349             :   private:
    2350             :     bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
    2351             : 
    2352           0 :     ~CollectReportsRunnable()
    2353           0 :     {
    2354           0 :       if (NS_IsMainThread()) {
    2355           0 :         mFinishCollectRunnable->Run();
    2356           0 :         return;
    2357             :       }
    2358             : 
    2359           0 :       WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    2360           0 :       MOZ_ASSERT(workerPrivate);
    2361           0 :       MOZ_ALWAYS_SUCCEEDS(
    2362             :         workerPrivate->DispatchToMainThread(mFinishCollectRunnable.forget()));
    2363           0 :     }
    2364             :   };
    2365             : 
    2366             :   class FinishCollectRunnable final : public Runnable
    2367             :   {
    2368             :     nsCOMPtr<nsIHandleReportCallback> mHandleReport;
    2369             :     nsCOMPtr<nsISupports> mHandlerData;
    2370             :     const bool mAnonymize;
    2371             :     bool mSuccess;
    2372             : 
    2373             :   public:
    2374             :     WorkerJSContextStats mCxStats;
    2375             : 
    2376             :     explicit FinishCollectRunnable(
    2377             :       nsIHandleReportCallback* aHandleReport,
    2378             :       nsISupports* aHandlerData,
    2379             :       bool aAnonymize,
    2380             :       const nsACString& aPath);
    2381             : 
    2382             :     NS_IMETHOD Run() override;
    2383             : 
    2384           0 :     void SetSuccess(bool success)
    2385             :     {
    2386           0 :       mSuccess = success;
    2387           0 :     }
    2388             : 
    2389             :   private:
    2390           0 :     ~FinishCollectRunnable()
    2391           0 :     {
    2392             :       // mHandleReport and mHandlerData are released on the main thread.
    2393           0 :       AssertIsOnMainThread();
    2394           0 :     }
    2395             : 
    2396             :     FinishCollectRunnable(const FinishCollectRunnable&) = delete;
    2397             :     FinishCollectRunnable& operator=(const FinishCollectRunnable&) = delete;
    2398             :     FinishCollectRunnable& operator=(const FinishCollectRunnable&&) = delete;
    2399             :   };
    2400             : 
    2401           0 :   ~MemoryReporter()
    2402           0 :   {
    2403           0 :   }
    2404             : 
    2405             :   void
    2406           0 :   Disable()
    2407             :   {
    2408             :     // Called from WorkerPrivate::DisableMemoryReporter.
    2409           0 :     mMutex.AssertCurrentThreadOwns();
    2410             : 
    2411           0 :     NS_ASSERTION(mWorkerPrivate, "Disabled more than once!");
    2412           0 :     mWorkerPrivate = nullptr;
    2413           0 :   }
    2414             : 
    2415             :   // Only call this from the main thread and under mMutex lock.
    2416             :   void
    2417             :   TryToMapAddon(nsACString &path);
    2418             : };
    2419             : 
    2420           4 : NS_IMPL_ISUPPORTS(WorkerPrivate::MemoryReporter, nsIMemoryReporter)
    2421             : 
    2422             : NS_IMETHODIMP
    2423           0 : WorkerPrivate::MemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
    2424             :                                               nsISupports* aData,
    2425             :                                               bool aAnonymize)
    2426             : {
    2427           0 :   AssertIsOnMainThread();
    2428             : 
    2429           0 :   RefPtr<CollectReportsRunnable> runnable;
    2430             : 
    2431             :   {
    2432           0 :     MutexAutoLock lock(mMutex);
    2433             : 
    2434           0 :     if (!mWorkerPrivate) {
    2435             :       // This will effectively report 0 memory.
    2436             :       nsCOMPtr<nsIMemoryReporterManager> manager =
    2437           0 :         do_GetService("@mozilla.org/memory-reporter-manager;1");
    2438           0 :       if (manager) {
    2439           0 :         manager->EndReport();
    2440             :       }
    2441           0 :       return NS_OK;
    2442             :     }
    2443             : 
    2444           0 :     nsAutoCString path;
    2445           0 :     path.AppendLiteral("explicit/workers/workers(");
    2446           0 :     if (aAnonymize && !mWorkerPrivate->Domain().IsEmpty()) {
    2447           0 :       path.AppendLiteral("<anonymized-domain>)/worker(<anonymized-url>");
    2448             :     } else {
    2449           0 :       nsAutoCString escapedDomain(mWorkerPrivate->Domain());
    2450           0 :       if (escapedDomain.IsEmpty()) {
    2451           0 :         escapedDomain += "chrome";
    2452             :       } else {
    2453           0 :         escapedDomain.ReplaceChar('/', '\\');
    2454             :       }
    2455           0 :       path.Append(escapedDomain);
    2456           0 :       path.AppendLiteral(")/worker(");
    2457           0 :       NS_ConvertUTF16toUTF8 escapedURL(mWorkerPrivate->ScriptURL());
    2458           0 :       escapedURL.ReplaceChar('/', '\\');
    2459           0 :       path.Append(escapedURL);
    2460             :     }
    2461           0 :     path.AppendPrintf(", 0x%p)/", static_cast<void*>(mWorkerPrivate));
    2462             : 
    2463           0 :     TryToMapAddon(path);
    2464             : 
    2465             :     runnable =
    2466           0 :       new CollectReportsRunnable(mWorkerPrivate, aHandleReport, aData, aAnonymize, path);
    2467             :   }
    2468             : 
    2469           0 :   if (!runnable->Dispatch()) {
    2470           0 :     return NS_ERROR_UNEXPECTED;
    2471             :   }
    2472             : 
    2473           0 :   return NS_OK;
    2474             : }
    2475             : 
    2476             : void
    2477           0 : WorkerPrivate::MemoryReporter::TryToMapAddon(nsACString &path)
    2478             : {
    2479           0 :   AssertIsOnMainThread();
    2480           0 :   mMutex.AssertCurrentThreadOwns();
    2481             : 
    2482           0 :   if (mAlreadyMappedToAddon || !mWorkerPrivate) {
    2483           0 :     return;
    2484             :   }
    2485             : 
    2486           0 :   nsCOMPtr<nsIURI> scriptURI;
    2487           0 :   if (NS_FAILED(NS_NewURI(getter_AddRefs(scriptURI),
    2488             :                           mWorkerPrivate->ScriptURL()))) {
    2489           0 :     return;
    2490             :   }
    2491             : 
    2492           0 :   mAlreadyMappedToAddon = true;
    2493             : 
    2494           0 :   if (!XRE_IsParentProcess()) {
    2495             :     // Only try to access the service from the main process.
    2496           0 :     return;
    2497             :   }
    2498             : 
    2499           0 :   nsAutoCString addonId;
    2500             :   bool ok;
    2501             :   nsCOMPtr<amIAddonManager> addonManager =
    2502           0 :     do_GetService("@mozilla.org/addons/integration;1");
    2503             : 
    2504           0 :   if (!addonManager ||
    2505           0 :       NS_FAILED(addonManager->MapURIToAddonID(scriptURI, addonId, &ok)) ||
    2506           0 :       !ok) {
    2507           0 :     return;
    2508             :   }
    2509             : 
    2510             :   static const size_t explicitLength = strlen("explicit/");
    2511           0 :   addonId.Insert(NS_LITERAL_CSTRING("add-ons/"), 0);
    2512           0 :   addonId += "/";
    2513           0 :   path.Insert(addonId, explicitLength);
    2514             : }
    2515             : 
    2516           0 : WorkerPrivate::MemoryReporter::CollectReportsRunnable::CollectReportsRunnable(
    2517             :   WorkerPrivate* aWorkerPrivate,
    2518             :   nsIHandleReportCallback* aHandleReport,
    2519             :   nsISupports* aHandlerData,
    2520             :   bool aAnonymize,
    2521           0 :   const nsACString& aPath)
    2522             :   : MainThreadWorkerControlRunnable(aWorkerPrivate),
    2523             :     mFinishCollectRunnable(
    2524           0 :       new FinishCollectRunnable(aHandleReport, aHandlerData, aAnonymize, aPath)),
    2525           0 :     mAnonymize(aAnonymize)
    2526           0 : { }
    2527             : 
    2528             : bool
    2529           0 : WorkerPrivate::MemoryReporter::CollectReportsRunnable::WorkerRun(JSContext* aCx,
    2530             :                                                                  WorkerPrivate* aWorkerPrivate)
    2531             : {
    2532           0 :   aWorkerPrivate->AssertIsOnWorkerThread();
    2533             : 
    2534           0 :   mFinishCollectRunnable->SetSuccess(
    2535           0 :     aWorkerPrivate->CollectRuntimeStats(&mFinishCollectRunnable->mCxStats, mAnonymize));
    2536             : 
    2537           0 :   return true;
    2538             : }
    2539             : 
    2540           0 : WorkerPrivate::MemoryReporter::FinishCollectRunnable::FinishCollectRunnable(
    2541             :   nsIHandleReportCallback* aHandleReport,
    2542             :   nsISupports* aHandlerData,
    2543             :   bool aAnonymize,
    2544           0 :   const nsACString& aPath)
    2545             :   : mozilla::Runnable(
    2546             :       "dom::workers::WorkerPrivate::MemoryReporter::FinishCollectRunnable")
    2547             :   , mHandleReport(aHandleReport)
    2548             :   , mHandlerData(aHandlerData)
    2549             :   , mAnonymize(aAnonymize)
    2550             :   , mSuccess(false)
    2551           0 :   , mCxStats(aPath)
    2552           0 : { }
    2553             : 
    2554             : NS_IMETHODIMP
    2555           0 : WorkerPrivate::MemoryReporter::FinishCollectRunnable::Run()
    2556             : {
    2557           0 :   AssertIsOnMainThread();
    2558             : 
    2559             :   nsCOMPtr<nsIMemoryReporterManager> manager =
    2560           0 :     do_GetService("@mozilla.org/memory-reporter-manager;1");
    2561             : 
    2562           0 :   if (!manager)
    2563           0 :     return NS_OK;
    2564             : 
    2565           0 :   if (mSuccess) {
    2566           0 :     xpc::ReportJSRuntimeExplicitTreeStats(mCxStats, mCxStats.Path(),
    2567             :                                           mHandleReport, mHandlerData,
    2568           0 :                                           mAnonymize);
    2569             :   }
    2570             : 
    2571           0 :   manager->EndReport();
    2572             : 
    2573           0 :   return NS_OK;
    2574             : }
    2575             : 
    2576          17 : WorkerPrivate::SyncLoopInfo::SyncLoopInfo(EventTarget* aEventTarget)
    2577             : : mEventTarget(aEventTarget), mCompleted(false), mResult(false)
    2578             : #ifdef DEBUG
    2579          17 :   , mHasRun(false)
    2580             : #endif
    2581             : {
    2582          17 : }
    2583             : 
    2584             : template <class Derived>
    2585             : nsIDocument*
    2586          16 : WorkerPrivateParent<Derived>::GetDocument() const
    2587             : {
    2588          16 :   AssertIsOnMainThread();
    2589          16 :   if (mLoadInfo.mWindow) {
    2590           0 :     return mLoadInfo.mWindow->GetExtantDoc();
    2591             :   }
    2592             :   // if we don't have a document, we should query the document
    2593             :   // from the parent in case of a nested worker
    2594          16 :   WorkerPrivate* parent = mParent;
    2595          16 :   while (parent) {
    2596           0 :     if (parent->mLoadInfo.mWindow) {
    2597           0 :       return parent->mLoadInfo.mWindow->GetExtantDoc();
    2598             :     }
    2599           0 :     parent = parent->GetParent();
    2600             :   }
    2601             :   // couldn't query a document, give up and return nullptr
    2602          16 :   return nullptr;
    2603             : }
    2604             : 
    2605             : template <class Derived>
    2606             : void
    2607           0 : WorkerPrivateParent<Derived>::SetCSP(nsIContentSecurityPolicy* aCSP)
    2608             : {
    2609           0 :   AssertIsOnMainThread();
    2610           0 :   if (!aCSP) {
    2611           0 :     return;
    2612             :   }
    2613           0 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2614           0 :   aCSP->EnsureEventTarget(self->mMainThreadEventTarget);
    2615           0 :   mLoadInfo.mCSP = aCSP;
    2616             : }
    2617             : 
    2618             : template <class Derived>
    2619             : nsresult
    2620           1 : WorkerPrivateParent<Derived>::SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
    2621             :                                                      const nsACString& aCSPReportOnlyHeaderValue)
    2622             : {
    2623           1 :   AssertIsOnMainThread();
    2624           1 :   MOZ_DIAGNOSTIC_ASSERT(!mLoadInfo.mCSP);
    2625             : 
    2626           2 :   NS_ConvertASCIItoUTF16 cspHeaderValue(aCSPHeaderValue);
    2627           2 :   NS_ConvertASCIItoUTF16 cspROHeaderValue(aCSPReportOnlyHeaderValue);
    2628             : 
    2629           2 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    2630           1 :   nsresult rv = mLoadInfo.mPrincipal->EnsureCSP(nullptr, getter_AddRefs(csp));
    2631           1 :   if (!csp) {
    2632           1 :     return NS_OK;
    2633             :   }
    2634             : 
    2635           0 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2636           0 :   csp->EnsureEventTarget(self->mMainThreadEventTarget);
    2637             : 
    2638             :   // If there's a CSP header, apply it.
    2639           0 :   if (!cspHeaderValue.IsEmpty()) {
    2640           0 :     rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
    2641           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2642             :   }
    2643             :   // If there's a report-only CSP header, apply it.
    2644           0 :   if (!cspROHeaderValue.IsEmpty()) {
    2645           0 :     rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
    2646           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2647             :   }
    2648             : 
    2649             :   // Set evalAllowed, default value is set in GetAllowsEval
    2650           0 :   bool evalAllowed = false;
    2651           0 :   bool reportEvalViolations = false;
    2652           0 :   rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
    2653           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2654             : 
    2655             :   // Set ReferrerPolicy, default value is set in GetReferrerPolicy
    2656           0 :   bool hasReferrerPolicy = false;
    2657           0 :   uint32_t rp = mozilla::net::RP_Unset;
    2658           0 :   rv = csp->GetReferrerPolicy(&rp, &hasReferrerPolicy);
    2659           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2660             : 
    2661           0 :   mLoadInfo.mCSP = csp;
    2662           0 :   mLoadInfo.mEvalAllowed = evalAllowed;
    2663           0 :   mLoadInfo.mReportCSPViolations = reportEvalViolations;
    2664             : 
    2665           0 :   if (hasReferrerPolicy) {
    2666           0 :     mLoadInfo.mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
    2667             :   }
    2668             : 
    2669           0 :   return NS_OK;
    2670             : }
    2671             : 
    2672             : template <class Derived>
    2673             : void
    2674           1 : WorkerPrivateParent<Derived>::SetReferrerPolicyFromHeaderValue(
    2675             :                                   const nsACString& aReferrerPolicyHeaderValue)
    2676             : {
    2677           1 :   NS_ConvertUTF8toUTF16 headerValue(aReferrerPolicyHeaderValue);
    2678             : 
    2679           1 :   if (headerValue.IsEmpty()) {
    2680           1 :     return;
    2681             :   }
    2682             : 
    2683             :   net::ReferrerPolicy policy =
    2684           0 :     nsContentUtils::GetReferrerPolicyFromHeader(headerValue);
    2685           0 :   if (policy == net::RP_Unset) {
    2686           0 :     return;
    2687             :   }
    2688             : 
    2689           0 :   SetReferrerPolicy(policy);
    2690             : }
    2691             : 
    2692             : 
    2693             : // Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
    2694             : // templates.
    2695             : template <class Derived>
    2696             : typename WorkerPrivateParent<Derived>::cycleCollection
    2697             :   WorkerPrivateParent<Derived>::_cycleCollectorGlobal =
    2698             :     WorkerPrivateParent<Derived>::cycleCollection();
    2699             : 
    2700             : template <class Derived>
    2701           1 : WorkerPrivateParent<Derived>::WorkerPrivateParent(
    2702             :                                            WorkerPrivate* aParent,
    2703             :                                            const nsAString& aScriptURL,
    2704             :                                            bool aIsChromeWorker,
    2705             :                                            WorkerType aWorkerType,
    2706             :                                            const nsAString& aWorkerName,
    2707             :                                            const nsACString& aServiceWorkerScope,
    2708             :                                            WorkerLoadInfo& aLoadInfo)
    2709             : : mMutex("WorkerPrivateParent Mutex"),
    2710             :   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
    2711             :   mParent(aParent), mScriptURL(aScriptURL),
    2712             :   mWorkerName(aWorkerName), mServiceWorkerScope(aServiceWorkerScope),
    2713             :   mLoadingWorkerScript(false), mBusyCount(0), mParentWindowPausedDepth(0),
    2714             :   mParentStatus(Pending), mParentFrozen(false),
    2715             :   mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
    2716             :   mIsSecureContext(false), mWorkerType(aWorkerType),
    2717             :   mCreationTimeStamp(TimeStamp::Now()),
    2718           1 :   mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
    2719             : {
    2720           1 :   MOZ_ASSERT_IF(!IsDedicatedWorker(), NS_IsMainThread());
    2721             : 
    2722           1 :   if (aLoadInfo.mWindow) {
    2723           0 :     AssertIsOnMainThread();
    2724           0 :     MOZ_ASSERT(aLoadInfo.mWindow->IsInnerWindow(),
    2725             :                "Should have inner window here!");
    2726           0 :     BindToOwner(aLoadInfo.mWindow);
    2727             :   }
    2728             : 
    2729           1 :   mLoadInfo.StealFrom(aLoadInfo);
    2730             : 
    2731           1 :   if (aParent) {
    2732           0 :     aParent->AssertIsOnWorkerThread();
    2733             : 
    2734             :     // Note that this copies our parent's secure context state into mJSSettings.
    2735           0 :     aParent->CopyJSSettings(mJSSettings);
    2736             : 
    2737             :     // And manually set our mIsSecureContext, though it's not really relevant to
    2738             :     // dedicated workers...
    2739           0 :     mIsSecureContext = aParent->IsSecureContext();
    2740           0 :     MOZ_ASSERT_IF(mIsChromeWorker, mIsSecureContext);
    2741             : 
    2742           0 :     MOZ_ASSERT(IsDedicatedWorker());
    2743             : 
    2744           0 :     if (aParent->mParentFrozen) {
    2745           0 :       Freeze(nullptr);
    2746             :     }
    2747             :   }
    2748             :   else {
    2749           1 :     AssertIsOnMainThread();
    2750             : 
    2751           1 :     RuntimeService::GetDefaultJSSettings(mJSSettings);
    2752             : 
    2753             :     // Our secure context state depends on the kind of worker we have.
    2754           1 :     if (UsesSystemPrincipal() || IsServiceWorker()) {
    2755           1 :       mIsSecureContext = true;
    2756           0 :     } else if (mLoadInfo.mWindow) {
    2757             :       // Shared and dedicated workers both inherit the loading window's secure
    2758             :       // context state.  Shared workers then prevent windows with a different
    2759             :       // secure context state from attaching to them.
    2760           0 :       mIsSecureContext = mLoadInfo.mWindow->IsSecureContext();
    2761             :     } else {
    2762           0 :       MOZ_ASSERT_UNREACHABLE("non-chrome worker that is not a service worker "
    2763             :                              "that has no parent and no associated window");
    2764             :     }
    2765             : 
    2766           1 :     if (mIsSecureContext) {
    2767           1 :       mJSSettings.chrome.compartmentOptions
    2768           1 :                  .creationOptions().setSecureContext(true);
    2769           1 :       mJSSettings.content.compartmentOptions
    2770           1 :                  .creationOptions().setSecureContext(true);
    2771             :     }
    2772             : 
    2773             :     // Our parent can get suspended after it initiates the async creation
    2774             :     // of a new worker thread.  In this case suspend the new worker as well.
    2775           1 :     if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
    2776           0 :       ParentWindowPaused();
    2777             :     }
    2778             : 
    2779           1 :     if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsFrozen()) {
    2780           0 :       Freeze(mLoadInfo.mWindow);
    2781             :     }
    2782             :   }
    2783           1 : }
    2784             : 
    2785             : template <class Derived>
    2786           0 : WorkerPrivateParent<Derived>::~WorkerPrivateParent()
    2787             : {
    2788           0 :   DropJSObjects(this);
    2789           0 : }
    2790             : 
    2791             : template <class Derived>
    2792             : JSObject*
    2793           1 : WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    2794             : {
    2795           1 :   MOZ_ASSERT(!IsSharedWorker(),
    2796             :              "We should never wrap a WorkerPrivate for a SharedWorker");
    2797             : 
    2798           1 :   AssertIsOnParentThread();
    2799             : 
    2800             :   // XXXkhuey this should not need to be rooted, the analysis is dumb.
    2801             :   // See bug 980181.
    2802             :   JS::Rooted<JSObject*> wrapper(aCx,
    2803           2 :     WorkerBinding::Wrap(aCx, ParentAsWorkerPrivate(), aGivenProto));
    2804           1 :   if (wrapper) {
    2805           1 :     MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
    2806             :   }
    2807             : 
    2808           2 :   return wrapper;
    2809             : }
    2810             : 
    2811             : template <class Derived>
    2812             : nsresult
    2813          38 : WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable,
    2814             :                                               nsIEventTarget* aSyncLoopTarget)
    2815             : {
    2816             :   // May be called on any thread!
    2817          76 :   RefPtr<WorkerRunnable> runnable(aRunnable);
    2818             : 
    2819          38 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2820             : 
    2821             :   {
    2822          74 :     MutexAutoLock lock(mMutex);
    2823             : 
    2824          38 :     MOZ_ASSERT_IF(aSyncLoopTarget, self->mThread);
    2825             : 
    2826          38 :     if (!self->mThread) {
    2827           2 :       if (ParentStatus() == Pending || self->mStatus == Pending) {
    2828           2 :         mPreStartRunnables.AppendElement(runnable);
    2829           2 :         return NS_OK;
    2830             :       }
    2831             : 
    2832           0 :       NS_WARNING("Using a worker event target after the thread has already"
    2833             :                  "been released!");
    2834           0 :       return NS_ERROR_UNEXPECTED;
    2835             :     }
    2836             : 
    2837          36 :     if (self->mStatus == Dead ||
    2838           0 :         (!aSyncLoopTarget && ParentStatus() > Running)) {
    2839           0 :       NS_WARNING("A runnable was posted to a worker that is already shutting "
    2840             :                  "down!");
    2841           0 :       return NS_ERROR_UNEXPECTED;
    2842             :     }
    2843             : 
    2844             :     nsresult rv;
    2845          36 :     if (aSyncLoopTarget) {
    2846          36 :       rv = aSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
    2847             :     } else {
    2848           0 :       rv = self->mThread->DispatchAnyThread(WorkerThreadFriendKey(), runnable.forget());
    2849             :     }
    2850             : 
    2851          36 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2852           0 :       return rv;
    2853             :     }
    2854             : 
    2855          36 :     mCondVar.Notify();
    2856             :   }
    2857             : 
    2858          36 :   return NS_OK;
    2859             : }
    2860             : 
    2861             : template <class Derived>
    2862             : void
    2863           1 : WorkerPrivateParent<Derived>::EnableDebugger()
    2864             : {
    2865           1 :   AssertIsOnParentThread();
    2866             : 
    2867           1 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2868             : 
    2869           1 :   if (NS_FAILED(RegisterWorkerDebugger(self))) {
    2870           0 :     NS_WARNING("Failed to register worker debugger!");
    2871           0 :     return;
    2872             :   }
    2873             : }
    2874             : 
    2875             : template <class Derived>
    2876             : void
    2877           0 : WorkerPrivateParent<Derived>::DisableDebugger()
    2878             : {
    2879           0 :   AssertIsOnParentThread();
    2880             : 
    2881           0 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2882             : 
    2883           0 :   if (NS_FAILED(UnregisterWorkerDebugger(self))) {
    2884           0 :     NS_WARNING("Failed to unregister worker debugger!");
    2885             :   }
    2886           0 : }
    2887             : 
    2888             : template <class Derived>
    2889             : nsresult
    2890           0 : WorkerPrivateParent<Derived>::DispatchControlRunnable(
    2891             :   already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable)
    2892             : {
    2893             :   // May be called on any thread!
    2894           0 :   RefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
    2895           0 :   MOZ_ASSERT(runnable);
    2896             : 
    2897           0 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2898             : 
    2899             :   {
    2900           0 :     MutexAutoLock lock(mMutex);
    2901             : 
    2902           0 :     if (self->mStatus == Dead) {
    2903           0 :       return NS_ERROR_UNEXPECTED;
    2904             :     }
    2905             : 
    2906             :     // Transfer ownership to the control queue.
    2907           0 :     self->mControlQueue.Push(runnable.forget().take());
    2908             : 
    2909           0 :     if (JSContext* cx = self->mJSContext) {
    2910           0 :       MOZ_ASSERT(self->mThread);
    2911           0 :       JS_RequestInterruptCallback(cx);
    2912             :     }
    2913             : 
    2914           0 :     mCondVar.Notify();
    2915             :   }
    2916             : 
    2917           0 :   return NS_OK;
    2918             : }
    2919             : 
    2920             : template <class Derived>
    2921             : nsresult
    2922           0 : WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
    2923             :   already_AddRefed<WorkerRunnable> aDebuggerRunnable)
    2924             : {
    2925             :   // May be called on any thread!
    2926             : 
    2927           0 :   RefPtr<WorkerRunnable> runnable(aDebuggerRunnable);
    2928             : 
    2929           0 :   MOZ_ASSERT(runnable);
    2930             : 
    2931           0 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2932             : 
    2933             :   {
    2934           0 :     MutexAutoLock lock(mMutex);
    2935             : 
    2936           0 :     if (self->mStatus == Dead) {
    2937           0 :       NS_WARNING("A debugger runnable was posted to a worker that is already "
    2938             :                  "shutting down!");
    2939           0 :       return NS_ERROR_UNEXPECTED;
    2940             :     }
    2941             : 
    2942             :     // Transfer ownership to the debugger queue.
    2943           0 :     self->mDebuggerQueue.Push(runnable.forget().take());
    2944             : 
    2945           0 :     mCondVar.Notify();
    2946             :   }
    2947             : 
    2948           0 :   return NS_OK;
    2949             : }
    2950             : 
    2951             : template <class Derived>
    2952             : already_AddRefed<WorkerRunnable>
    2953          36 : WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable> aRunnable)
    2954             : {
    2955             :   // May be called on any thread!
    2956             : 
    2957          72 :   nsCOMPtr<nsIRunnable> runnable(aRunnable);
    2958          36 :   MOZ_ASSERT(runnable);
    2959             : 
    2960             :   RefPtr<WorkerRunnable> workerRunnable =
    2961          72 :     WorkerRunnable::FromRunnable(runnable);
    2962          36 :   if (workerRunnable) {
    2963          36 :     return workerRunnable.forget();
    2964             :   }
    2965             : 
    2966           0 :   nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
    2967           0 :   if (!cancelable) {
    2968           0 :     MOZ_CRASH("All runnables destined for a worker thread must be cancelable!");
    2969             :   }
    2970             : 
    2971           0 :   workerRunnable =
    2972           0 :     new ExternalRunnableWrapper(ParentAsWorkerPrivate(), runnable);
    2973           0 :   return workerRunnable.forget();
    2974             : }
    2975             : 
    2976             : template <class Derived>
    2977             : already_AddRefed<nsISerialEventTarget>
    2978           1 : WorkerPrivateParent<Derived>::GetEventTarget()
    2979             : {
    2980           1 :   WorkerPrivate* self = ParentAsWorkerPrivate();
    2981             : 
    2982           2 :   nsCOMPtr<nsISerialEventTarget> target;
    2983             : 
    2984           1 :   bool needAutoDisable = false;
    2985             : 
    2986             :   {
    2987           2 :     MutexAutoLock lock(mMutex);
    2988             : 
    2989           1 :     if (!mEventTarget) {
    2990           1 :       mEventTarget = new EventTarget(self);
    2991             : 
    2992             :       // If the worker is already shutting down then we want to
    2993             :       // immediately disable the event target.  This will cause
    2994             :       // the Dispatch() method to fail, but the event target
    2995             :       // will still exist.
    2996           1 :       if (self->mStatus > Running) {
    2997           0 :         needAutoDisable = true;
    2998             :       }
    2999             :     }
    3000             : 
    3001           1 :     target = mEventTarget;
    3002             :   }
    3003             : 
    3004             :   // Make sure to call Disable() outside of the mutex since it
    3005             :   // also internally locks a mutex.
    3006           1 :   if (needAutoDisable) {
    3007           0 :     mEventTarget->Disable();
    3008             :   }
    3009             : 
    3010             : 
    3011           1 :   MOZ_DIAGNOSTIC_ASSERT(target);
    3012           2 :   return target.forget();
    3013             : }
    3014             : 
    3015             : template <class Derived>
    3016             : bool
    3017           1 : WorkerPrivateParent<Derived>::Start()
    3018             : {
    3019             :   // May be called on any thread!
    3020             :   {
    3021           1 :     MutexAutoLock lock(mMutex);
    3022             : 
    3023           1 :     NS_ASSERTION(mParentStatus != Running, "How can this be?!");
    3024             : 
    3025           1 :     if (mParentStatus == Pending) {
    3026           1 :       mParentStatus = Running;
    3027           1 :       return true;
    3028             :     }
    3029             :   }
    3030             : 
    3031           0 :   return false;
    3032             : }
    3033             : 
    3034             : // aCx is null when called from the finalizer
    3035             : template <class Derived>
    3036             : bool
    3037           0 : WorkerPrivateParent<Derived>::NotifyPrivate(Status aStatus)
    3038             : {
    3039           0 :   AssertIsOnParentThread();
    3040             : 
    3041             :   bool pending;
    3042             :   {
    3043           0 :     MutexAutoLock lock(mMutex);
    3044             : 
    3045           0 :     if (mParentStatus >= aStatus) {
    3046           0 :       return true;
    3047             :     }
    3048             : 
    3049           0 :     pending = mParentStatus == Pending;
    3050           0 :     mParentStatus = aStatus;
    3051             :   }
    3052             : 
    3053           0 :   if (IsSharedWorker()) {
    3054           0 :     RuntimeService* runtime = RuntimeService::GetService();
    3055           0 :     MOZ_ASSERT(runtime);
    3056             : 
    3057           0 :     runtime->ForgetSharedWorker(ParentAsWorkerPrivate());
    3058             :   }
    3059             : 
    3060           0 :   if (pending) {
    3061           0 :     WorkerPrivate* self = ParentAsWorkerPrivate();
    3062             : 
    3063             : #ifdef DEBUG
    3064             :     {
    3065             :       // Fake a thread here just so that our assertions don't go off for no
    3066             :       // reason.
    3067           0 :       nsIThread* currentThread = NS_GetCurrentThread();
    3068           0 :       MOZ_ASSERT(currentThread);
    3069             : 
    3070           0 :       MOZ_ASSERT(!self->mPRThread);
    3071           0 :       self->mPRThread = PRThreadFromThread(currentThread);
    3072           0 :       MOZ_ASSERT(self->mPRThread);
    3073             :     }
    3074             : #endif
    3075             : 
    3076             :     // Worker never got a chance to run, go ahead and delete it.
    3077           0 :     self->ScheduleDeletion(WorkerPrivate::WorkerNeverRan);
    3078           0 :     return true;
    3079             :   }
    3080             : 
    3081           0 :   NS_ASSERTION(aStatus != Terminating || mQueuedRunnables.IsEmpty(),
    3082             :                "Shouldn't have anything queued!");
    3083             : 
    3084             :   // Anything queued will be discarded.
    3085           0 :   mQueuedRunnables.Clear();
    3086             : 
    3087             :   RefPtr<NotifyRunnable> runnable =
    3088           0 :     new NotifyRunnable(ParentAsWorkerPrivate(), aStatus);
    3089           0 :   return runnable->Dispatch();
    3090             : }
    3091             : 
    3092             : template <class Derived>
    3093             : bool
    3094           0 : WorkerPrivateParent<Derived>::Freeze(nsPIDOMWindowInner* aWindow)
    3095             : {
    3096           0 :   AssertIsOnParentThread();
    3097             : 
    3098             :   // Shared workers are only frozen if all of their owning documents are
    3099             :   // frozen. It can happen that mSharedWorkers is empty but this thread has
    3100             :   // not been unregistered yet.
    3101           0 :   if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
    3102           0 :     AssertIsOnMainThread();
    3103             : 
    3104           0 :     bool allFrozen = true;
    3105             : 
    3106           0 :     for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
    3107           0 :       if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
    3108             :         // Calling Freeze() may change the refcount, ensure that the worker
    3109             :         // outlives this call.
    3110           0 :         RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
    3111             : 
    3112           0 :         kungFuDeathGrip->Freeze();
    3113             :       } else {
    3114           0 :         MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
    3115             :                       !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
    3116             :                                        aWindow));
    3117           0 :         if (!mSharedWorkers[i]->IsFrozen()) {
    3118           0 :           allFrozen = false;
    3119             :         }
    3120             :       }
    3121             :     }
    3122             : 
    3123           0 :     if (!allFrozen || mParentFrozen) {
    3124           0 :       return true;
    3125             :     }
    3126             :   }
    3127             : 
    3128           0 :   mParentFrozen = true;
    3129             : 
    3130             :   {
    3131           0 :     MutexAutoLock lock(mMutex);
    3132             : 
    3133           0 :     if (mParentStatus >= Terminating) {
    3134           0 :       return true;
    3135             :     }
    3136             :   }
    3137             : 
    3138           0 :   DisableDebugger();
    3139             : 
    3140             :   RefPtr<FreezeRunnable> runnable =
    3141           0 :     new FreezeRunnable(ParentAsWorkerPrivate());
    3142           0 :   if (!runnable->Dispatch()) {
    3143           0 :     return false;
    3144             :   }
    3145             : 
    3146           0 :   return true;
    3147             : }
    3148             : 
    3149             : template <class Derived>
    3150             : bool
    3151           0 : WorkerPrivateParent<Derived>::Thaw(nsPIDOMWindowInner* aWindow)
    3152             : {
    3153           0 :   AssertIsOnParentThread();
    3154             : 
    3155           0 :   MOZ_ASSERT(mParentFrozen);
    3156             : 
    3157             :   // Shared workers are resumed if any of their owning documents are thawed.
    3158             :   // It can happen that mSharedWorkers is empty but this thread has not been
    3159             :   // unregistered yet.
    3160           0 :   if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
    3161           0 :     AssertIsOnMainThread();
    3162             : 
    3163           0 :     bool anyRunning = false;
    3164             : 
    3165           0 :     for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
    3166           0 :       if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
    3167             :         // Calling Thaw() may change the refcount, ensure that the worker
    3168             :         // outlives this call.
    3169           0 :         RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
    3170             : 
    3171           0 :         kungFuDeathGrip->Thaw();
    3172           0 :         anyRunning = true;
    3173             :       } else {
    3174           0 :         MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
    3175             :                       !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
    3176             :                                        aWindow));
    3177           0 :         if (!mSharedWorkers[i]->IsFrozen()) {
    3178           0 :           anyRunning = true;
    3179             :         }
    3180             :       }
    3181             :     }
    3182             : 
    3183           0 :     if (!anyRunning || !mParentFrozen) {
    3184           0 :       return true;
    3185             :     }
    3186             :   }
    3187             : 
    3188           0 :   MOZ_ASSERT(mParentFrozen);
    3189             : 
    3190           0 :   mParentFrozen = false;
    3191             : 
    3192             :   {
    3193           0 :     MutexAutoLock lock(mMutex);
    3194             : 
    3195           0 :     if (mParentStatus >= Terminating) {
    3196           0 :       return true;
    3197             :     }
    3198             :   }
    3199             : 
    3200           0 :   EnableDebugger();
    3201             : 
    3202             :   // Execute queued runnables before waking up the worker, otherwise the worker
    3203             :   // could post new messages before we run those that have been queued.
    3204           0 :   if (!IsParentWindowPaused() && !mQueuedRunnables.IsEmpty()) {
    3205           0 :     MOZ_ASSERT(IsDedicatedWorker());
    3206             : 
    3207           0 :     nsTArray<nsCOMPtr<nsIRunnable>> runnables;
    3208           0 :     mQueuedRunnables.SwapElements(runnables);
    3209             : 
    3210           0 :     for (uint32_t index = 0; index < runnables.Length(); index++) {
    3211           0 :       runnables[index]->Run();
    3212             :     }
    3213             :   }
    3214             : 
    3215             :   RefPtr<ThawRunnable> runnable =
    3216           0 :     new ThawRunnable(ParentAsWorkerPrivate());
    3217           0 :   if (!runnable->Dispatch()) {
    3218           0 :     return false;
    3219             :   }
    3220             : 
    3221           0 :   return true;
    3222             : }
    3223             : 
    3224             : template <class Derived>
    3225             : void
    3226           0 : WorkerPrivateParent<Derived>::ParentWindowPaused()
    3227             : {
    3228           0 :   AssertIsOnMainThread();
    3229           0 :   MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 0);
    3230           0 :   mParentWindowPausedDepth += 1;
    3231           0 : }
    3232             : 
    3233             : template <class Derived>
    3234             : void
    3235           0 : WorkerPrivateParent<Derived>::ParentWindowResumed()
    3236             : {
    3237           0 :   AssertIsOnMainThread();
    3238             : 
    3239           0 :   MOZ_ASSERT(mParentWindowPausedDepth > 0);
    3240           0 :   MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 1);
    3241           0 :   mParentWindowPausedDepth -= 1;
    3242           0 :   if (mParentWindowPausedDepth > 0) {
    3243           0 :     return;
    3244             :   }
    3245             : 
    3246             :   {
    3247           0 :     MutexAutoLock lock(mMutex);
    3248             : 
    3249           0 :     if (mParentStatus >= Terminating) {
    3250           0 :       return;
    3251             :     }
    3252             :   }
    3253             : 
    3254             :   // Execute queued runnables before waking up, otherwise the worker could post
    3255             :   // new messages before we run those that have been queued.
    3256           0 :   if (!IsFrozen() && !mQueuedRunnables.IsEmpty()) {
    3257           0 :     MOZ_ASSERT(IsDedicatedWorker());
    3258             : 
    3259           0 :     nsTArray<nsCOMPtr<nsIRunnable>> runnables;
    3260           0 :     mQueuedRunnables.SwapElements(runnables);
    3261             : 
    3262           0 :     for (uint32_t index = 0; index < runnables.Length(); index++) {
    3263           0 :       runnables[index]->Run();
    3264             :     }
    3265             :   }
    3266             : }
    3267             : 
    3268             : template <class Derived>
    3269             : bool
    3270           0 : WorkerPrivateParent<Derived>::Close()
    3271             : {
    3272           0 :   mMutex.AssertCurrentThreadOwns();
    3273             : 
    3274           0 :   if (mParentStatus < Closing) {
    3275           0 :     mParentStatus = Closing;
    3276             :   }
    3277             : 
    3278           0 :   return true;
    3279             : }
    3280             : 
    3281             : template <class Derived>
    3282             : bool
    3283           3 : WorkerPrivateParent<Derived>::ModifyBusyCount(bool aIncrease)
    3284             : {
    3285           3 :   AssertIsOnParentThread();
    3286             : 
    3287           3 :   NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
    3288             : 
    3289           3 :   if (aIncrease) {
    3290           3 :     mBusyCount++;
    3291           3 :     return true;
    3292             :   }
    3293             : 
    3294           0 :   if (--mBusyCount == 0) {
    3295             : 
    3296             :     bool shouldCancel;
    3297             :     {
    3298           0 :       MutexAutoLock lock(mMutex);
    3299           0 :       shouldCancel = mParentStatus == Terminating;
    3300             :     }
    3301             : 
    3302           0 :     if (shouldCancel && !Cancel()) {
    3303           0 :       return false;
    3304             :     }
    3305             :   }
    3306             : 
    3307           0 :   return true;
    3308             : }
    3309             : 
    3310             : template <class Derived>
    3311             : bool
    3312           0 : WorkerPrivateParent<Derived>::ProxyReleaseMainThreadObjects()
    3313             : {
    3314           0 :   AssertIsOnParentThread();
    3315           0 :   MOZ_ASSERT(!mMainThreadObjectsForgotten);
    3316             : 
    3317           0 :   nsCOMPtr<nsILoadGroup> loadGroupToCancel;
    3318             :   // If we're not overriden, then do nothing here.  Let the load group get
    3319             :   // handled in ForgetMainThreadObjects().
    3320           0 :   if (mLoadInfo.mInterfaceRequestor) {
    3321           0 :     mLoadInfo.mLoadGroup.swap(loadGroupToCancel);
    3322             :   }
    3323             : 
    3324             :   bool result = mLoadInfo.ProxyReleaseMainThreadObjects(ParentAsWorkerPrivate(),
    3325           0 :                                                         loadGroupToCancel);
    3326             : 
    3327           0 :   mMainThreadObjectsForgotten = true;
    3328             : 
    3329           0 :   return result;
    3330             : }
    3331             : 
    3332             : template <class Derived>
    3333             : void
    3334           1 : WorkerPrivateParent<Derived>::PostMessageInternal(JSContext* aCx,
    3335             :                                                   JS::Handle<JS::Value> aMessage,
    3336             :                                                   const Sequence<JSObject*>& aTransferable,
    3337             :                                                   ErrorResult& aRv)
    3338             : {
    3339           1 :   AssertIsOnParentThread();
    3340             : 
    3341             :   {
    3342           2 :     MutexAutoLock lock(mMutex);
    3343           1 :     if (mParentStatus > Running) {
    3344           0 :       return;
    3345             :     }
    3346             :   }
    3347             : 
    3348           2 :   JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
    3349             : 
    3350           1 :   aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
    3351             :                                                           &transferable);
    3352           1 :   if (NS_WARN_IF(aRv.Failed())) {
    3353           0 :     return;
    3354             :   }
    3355             : 
    3356             :   RefPtr<MessageEventRunnable> runnable =
    3357           2 :     new MessageEventRunnable(ParentAsWorkerPrivate(),
    3358           2 :                              WorkerRunnable::WorkerThreadModifyBusyCount);
    3359             : 
    3360           2 :   UniquePtr<AbstractTimelineMarker> start;
    3361           2 :   UniquePtr<AbstractTimelineMarker> end;
    3362           2 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    3363           1 :   bool isTimelineRecording = timelines && !timelines->IsEmpty();
    3364             : 
    3365           1 :   if (isTimelineRecording) {
    3366           0 :     start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
    3367             :       ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
    3368             :       : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
    3369             :       MarkerTracingType::START);
    3370             :   }
    3371             : 
    3372           1 :   runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv);
    3373             : 
    3374           1 :   if (isTimelineRecording) {
    3375           0 :     end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
    3376             :       ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
    3377             :       : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
    3378             :       MarkerTracingType::END);
    3379           0 :     timelines->AddMarkerForAllObservedDocShells(start);
    3380           0 :     timelines->AddMarkerForAllObservedDocShells(end);
    3381             :   }
    3382             : 
    3383           1 :   if (NS_WARN_IF(aRv.Failed())) {
    3384           0 :     return;
    3385             :   }
    3386             : 
    3387           1 :   if (!runnable->Dispatch()) {
    3388           0 :     aRv.Throw(NS_ERROR_FAILURE);
    3389             :   }
    3390             : }
    3391             : 
    3392             : template <class Derived>
    3393             : void
    3394           1 : WorkerPrivateParent<Derived>::PostMessage(
    3395             :                              JSContext* aCx, JS::Handle<JS::Value> aMessage,
    3396             :                              const Sequence<JSObject*>& aTransferable,
    3397             :                              ErrorResult& aRv)
    3398             : {
    3399           1 :   PostMessageInternal(aCx, aMessage, aTransferable, aRv);
    3400           1 : }
    3401             : 
    3402             : template <class Derived>
    3403             : void
    3404           0 : WorkerPrivateParent<Derived>::UpdateContextOptions(
    3405             :                                     const JS::ContextOptions& aContextOptions)
    3406             : {
    3407           0 :   AssertIsOnParentThread();
    3408             : 
    3409             :   {
    3410           0 :     MutexAutoLock lock(mMutex);
    3411           0 :     mJSSettings.contextOptions = aContextOptions;
    3412             :   }
    3413             : 
    3414             :   RefPtr<UpdateContextOptionsRunnable> runnable =
    3415           0 :     new UpdateContextOptionsRunnable(ParentAsWorkerPrivate(), aContextOptions);
    3416           0 :   if (!runnable->Dispatch()) {
    3417           0 :     NS_WARNING("Failed to update worker context options!");
    3418             :   }
    3419           0 : }
    3420             : 
    3421             : template <class Derived>
    3422             : void
    3423           0 : WorkerPrivateParent<Derived>::UpdatePreference(WorkerPreference aPref, bool aValue)
    3424             : {
    3425           0 :   AssertIsOnParentThread();
    3426           0 :   MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
    3427             : 
    3428             :   RefPtr<UpdatePreferenceRunnable> runnable =
    3429           0 :     new UpdatePreferenceRunnable(ParentAsWorkerPrivate(), aPref, aValue);
    3430           0 :   if (!runnable->Dispatch()) {
    3431           0 :     NS_WARNING("Failed to update worker preferences!");
    3432             :   }
    3433           0 : }
    3434             : 
    3435             : template <class Derived>
    3436             : void
    3437           0 : WorkerPrivateParent<Derived>::UpdateLanguages(const nsTArray<nsString>& aLanguages)
    3438             : {
    3439           0 :   AssertIsOnParentThread();
    3440             : 
    3441             :   RefPtr<UpdateLanguagesRunnable> runnable =
    3442           0 :     new UpdateLanguagesRunnable(ParentAsWorkerPrivate(), aLanguages);
    3443           0 :   if (!runnable->Dispatch()) {
    3444           0 :     NS_WARNING("Failed to update worker languages!");
    3445             :   }
    3446           0 : }
    3447             : 
    3448             : template <class Derived>
    3449             : void
    3450           0 : WorkerPrivateParent<Derived>::UpdateJSWorkerMemoryParameter(JSGCParamKey aKey,
    3451             :                                                             uint32_t aValue)
    3452             : {
    3453           0 :   AssertIsOnParentThread();
    3454             : 
    3455           0 :   bool found = false;
    3456             : 
    3457             :   {
    3458           0 :     MutexAutoLock lock(mMutex);
    3459           0 :     found = mJSSettings.ApplyGCSetting(aKey, aValue);
    3460             :   }
    3461             : 
    3462           0 :   if (found) {
    3463             :     RefPtr<UpdateJSWorkerMemoryParameterRunnable> runnable =
    3464           0 :       new UpdateJSWorkerMemoryParameterRunnable(ParentAsWorkerPrivate(), aKey,
    3465           0 :                                                 aValue);
    3466           0 :     if (!runnable->Dispatch()) {
    3467           0 :       NS_WARNING("Failed to update memory parameter!");
    3468             :     }
    3469             :   }
    3470           0 : }
    3471             : 
    3472             : #ifdef JS_GC_ZEAL
    3473             : template <class Derived>
    3474             : void
    3475           0 : WorkerPrivateParent<Derived>::UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency)
    3476             : {
    3477           0 :   AssertIsOnParentThread();
    3478             : 
    3479             :   {
    3480           0 :     MutexAutoLock lock(mMutex);
    3481           0 :     mJSSettings.gcZeal = aGCZeal;
    3482           0 :     mJSSettings.gcZealFrequency = aFrequency;
    3483             :   }
    3484             : 
    3485             :   RefPtr<UpdateGCZealRunnable> runnable =
    3486           0 :     new UpdateGCZealRunnable(ParentAsWorkerPrivate(), aGCZeal, aFrequency);
    3487           0 :   if (!runnable->Dispatch()) {
    3488           0 :     NS_WARNING("Failed to update worker gczeal!");
    3489             :   }
    3490           0 : }
    3491             : #endif
    3492             : 
    3493             : template <class Derived>
    3494             : void
    3495           0 : WorkerPrivateParent<Derived>::GarbageCollect(bool aShrinking)
    3496             : {
    3497           0 :   AssertIsOnParentThread();
    3498             : 
    3499             :   RefPtr<GarbageCollectRunnable> runnable =
    3500           0 :     new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking,
    3501           0 :                                /* collectChildren = */ true);
    3502           0 :   if (!runnable->Dispatch()) {
    3503           0 :     NS_WARNING("Failed to GC worker!");
    3504             :   }
    3505           0 : }
    3506             : 
    3507             : template <class Derived>
    3508             : void
    3509           0 : WorkerPrivateParent<Derived>::CycleCollect(bool aDummy)
    3510             : {
    3511           0 :   AssertIsOnParentThread();
    3512             : 
    3513             :   RefPtr<CycleCollectRunnable> runnable =
    3514           0 :     new CycleCollectRunnable(ParentAsWorkerPrivate(),
    3515           0 :                              /* collectChildren = */ true);
    3516           0 :   if (!runnable->Dispatch()) {
    3517           0 :     NS_WARNING("Failed to CC worker!");
    3518             :   }
    3519           0 : }
    3520             : 
    3521             : template <class Derived>
    3522             : void
    3523           0 : WorkerPrivateParent<Derived>::OfflineStatusChangeEvent(bool aIsOffline)
    3524             : {
    3525           0 :   AssertIsOnParentThread();
    3526             : 
    3527             :   RefPtr<OfflineStatusChangeRunnable> runnable =
    3528           0 :     new OfflineStatusChangeRunnable(ParentAsWorkerPrivate(), aIsOffline);
    3529           0 :   if (!runnable->Dispatch()) {
    3530           0 :     NS_WARNING("Failed to dispatch offline status change event!");
    3531             :   }
    3532           0 : }
    3533             : 
    3534             : void
    3535           0 : WorkerPrivate::OfflineStatusChangeEventInternal(bool aIsOffline)
    3536             : {
    3537           0 :   AssertIsOnWorkerThread();
    3538             : 
    3539             :   // The worker is already in this state. No need to dispatch an event.
    3540           0 :   if (mOnLine == !aIsOffline) {
    3541           0 :     return;
    3542             :   }
    3543             : 
    3544           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); ++index) {
    3545           0 :     mChildWorkers[index]->OfflineStatusChangeEvent(aIsOffline);
    3546             :   }
    3547             : 
    3548           0 :   mOnLine = !aIsOffline;
    3549           0 :   WorkerGlobalScope* globalScope = GlobalScope();
    3550           0 :   RefPtr<WorkerNavigator> nav = globalScope->GetExistingNavigator();
    3551           0 :   if (nav) {
    3552           0 :     nav->SetOnLine(mOnLine);
    3553             :   }
    3554             : 
    3555           0 :   nsString eventType;
    3556           0 :   if (aIsOffline) {
    3557           0 :     eventType.AssignLiteral("offline");
    3558             :   } else {
    3559           0 :     eventType.AssignLiteral("online");
    3560             :   }
    3561             : 
    3562           0 :   RefPtr<Event> event = NS_NewDOMEvent(globalScope, nullptr, nullptr);
    3563             : 
    3564           0 :   event->InitEvent(eventType, false, false);
    3565           0 :   event->SetTrusted(true);
    3566             : 
    3567           0 :   globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
    3568             : }
    3569             : 
    3570             : template <class Derived>
    3571             : void
    3572           0 : WorkerPrivateParent<Derived>::MemoryPressure(bool aDummy)
    3573             : {
    3574           0 :   AssertIsOnParentThread();
    3575             : 
    3576             :   RefPtr<MemoryPressureRunnable> runnable =
    3577           0 :     new MemoryPressureRunnable(ParentAsWorkerPrivate());
    3578           0 :   Unused << NS_WARN_IF(!runnable->Dispatch());
    3579           0 : }
    3580             : 
    3581             : template <class Derived>
    3582             : bool
    3583           0 : WorkerPrivateParent<Derived>::RegisterSharedWorker(SharedWorker* aSharedWorker,
    3584             :                                                    MessagePort* aPort)
    3585             : {
    3586           0 :   AssertIsOnMainThread();
    3587           0 :   MOZ_ASSERT(aSharedWorker);
    3588           0 :   MOZ_ASSERT(IsSharedWorker());
    3589           0 :   MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
    3590             : 
    3591           0 :   if (IsSharedWorker()) {
    3592             :     RefPtr<MessagePortRunnable> runnable =
    3593           0 :       new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
    3594           0 :     if (!runnable->Dispatch()) {
    3595           0 :       return false;
    3596             :     }
    3597             :   }
    3598             : 
    3599           0 :   mSharedWorkers.AppendElement(aSharedWorker);
    3600             : 
    3601             :   // If there were other SharedWorker objects attached to this worker then they
    3602             :   // may all have been frozen and this worker would need to be thawed.
    3603           0 :   if (mSharedWorkers.Length() > 1 && IsFrozen() && !Thaw(nullptr)) {
    3604           0 :     return false;
    3605             :   }
    3606             : 
    3607           0 :   return true;
    3608             : }
    3609             : 
    3610             : template <class Derived>
    3611             : void
    3612           0 : WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
    3613             :                                                     JSContext* aCx,
    3614             :                                                     const WorkerErrorReport* aReport,
    3615             :                                                     bool aIsErrorEvent)
    3616             : {
    3617           0 :   AssertIsOnMainThread();
    3618             : 
    3619           0 :   if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) {
    3620             :     // Don't fire any events anywhere.  Just log to console.
    3621             :     // XXXbz should we log to all the consoles of all the relevant windows?
    3622           0 :     MOZ_ASSERT(aReport);
    3623           0 :     LogErrorToConsole(*aReport, 0);
    3624           0 :     return;
    3625             :   }
    3626             : 
    3627           0 :   AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
    3628           0 :   GetAllSharedWorkers(sharedWorkers);
    3629             : 
    3630           0 :   if (sharedWorkers.IsEmpty()) {
    3631           0 :     return;
    3632             :   }
    3633             : 
    3634           0 :   AutoTArray<WindowAction, 10> windowActions;
    3635             :   nsresult rv;
    3636             : 
    3637             :   // First fire the error event at all SharedWorker objects. This may include
    3638             :   // multiple objects in a single window as well as objects in different
    3639             :   // windows.
    3640           0 :   for (size_t index = 0; index < sharedWorkers.Length(); index++) {
    3641           0 :     RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
    3642             : 
    3643             :     // May be null.
    3644           0 :     nsPIDOMWindowInner* window = sharedWorker->GetOwner();
    3645             : 
    3646           0 :     RefPtr<Event> event;
    3647             : 
    3648           0 :     if (aIsErrorEvent) {
    3649           0 :       RootedDictionary<ErrorEventInit> errorInit(aCx);
    3650           0 :       errorInit.mBubbles = false;
    3651           0 :       errorInit.mCancelable = true;
    3652           0 :       errorInit.mMessage = aReport->mMessage;
    3653           0 :       errorInit.mFilename = aReport->mFilename;
    3654           0 :       errorInit.mLineno = aReport->mLineNumber;
    3655           0 :       errorInit.mColno = aReport->mColumnNumber;
    3656             : 
    3657           0 :       event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
    3658             :                                       errorInit);
    3659             :     } else {
    3660           0 :       event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
    3661             :                                  EventInit());
    3662             :     }
    3663             : 
    3664           0 :     if (!event) {
    3665           0 :       ThrowAndReport(window, NS_ERROR_UNEXPECTED);
    3666           0 :       continue;
    3667             :     }
    3668             : 
    3669           0 :     event->SetTrusted(true);
    3670             : 
    3671             :     bool defaultActionEnabled;
    3672           0 :     nsresult rv = sharedWorker->DispatchEvent(event, &defaultActionEnabled);
    3673           0 :     if (NS_FAILED(rv)) {
    3674           0 :       ThrowAndReport(window, rv);
    3675           0 :       continue;
    3676             :     }
    3677             : 
    3678           0 :     if (!aIsErrorEvent) {
    3679           0 :       continue;
    3680             :     }
    3681             : 
    3682           0 :     if (defaultActionEnabled) {
    3683             :       // Add the owning window to our list so that we will fire an error event
    3684             :       // at it later.
    3685           0 :       if (!windowActions.Contains(window)) {
    3686           0 :         windowActions.AppendElement(WindowAction(window));
    3687             :       }
    3688             :     } else {
    3689           0 :       size_t actionsIndex = windowActions.LastIndexOf(WindowAction(window));
    3690           0 :       if (actionsIndex != windowActions.NoIndex) {
    3691             :         // Any listener that calls preventDefault() will prevent the window from
    3692             :         // receiving the error event.
    3693           0 :         windowActions[actionsIndex].mDefaultAction = false;
    3694             :       }
    3695             :     }
    3696             :   }
    3697             : 
    3698             :   // If there are no windows to consider further then we're done.
    3699           0 :   if (windowActions.IsEmpty()) {
    3700           0 :     return;
    3701             :   }
    3702             : 
    3703           0 :   bool shouldLogErrorToConsole = true;
    3704             : 
    3705             :   // Now fire error events at all the windows remaining.
    3706           0 :   for (uint32_t index = 0; index < windowActions.Length(); index++) {
    3707           0 :     WindowAction& windowAction = windowActions[index];
    3708             : 
    3709             :     // If there is no window or the script already called preventDefault then
    3710             :     // skip this window.
    3711           0 :     if (!windowAction.mWindow || !windowAction.mDefaultAction) {
    3712           0 :       continue;
    3713             :     }
    3714             : 
    3715             :     nsCOMPtr<nsIScriptGlobalObject> sgo =
    3716           0 :       do_QueryInterface(windowAction.mWindow);
    3717           0 :     MOZ_ASSERT(sgo);
    3718             : 
    3719           0 :     MOZ_ASSERT(NS_IsMainThread());
    3720           0 :     RootedDictionary<ErrorEventInit> init(aCx);
    3721           0 :     init.mLineno = aReport->mLineNumber;
    3722           0 :     init.mFilename = aReport->mFilename;
    3723           0 :     init.mMessage = aReport->mMessage;
    3724           0 :     init.mCancelable = true;
    3725           0 :     init.mBubbles = true;
    3726             : 
    3727           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    3728           0 :     rv = sgo->HandleScriptError(init, &status);
    3729           0 :     if (NS_FAILED(rv)) {
    3730           0 :       ThrowAndReport(windowAction.mWindow, rv);
    3731           0 :       continue;
    3732             :     }
    3733             : 
    3734           0 :     if (status == nsEventStatus_eConsumeNoDefault) {
    3735           0 :       shouldLogErrorToConsole = false;
    3736             :     }
    3737             :   }
    3738             : 
    3739             :   // Finally log a warning in the console if no window tried to prevent it.
    3740           0 :   if (shouldLogErrorToConsole) {
    3741           0 :     MOZ_ASSERT(aReport);
    3742           0 :     LogErrorToConsole(*aReport, 0);
    3743             :   }
    3744             : }
    3745             : 
    3746             : template <class Derived>
    3747             : void
    3748           0 : WorkerPrivateParent<Derived>::GetAllSharedWorkers(
    3749             :                                nsTArray<RefPtr<SharedWorker>>& aSharedWorkers)
    3750             : {
    3751           0 :   AssertIsOnMainThread();
    3752           0 :   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
    3753             : 
    3754           0 :   if (!aSharedWorkers.IsEmpty()) {
    3755           0 :     aSharedWorkers.Clear();
    3756             :   }
    3757             : 
    3758           0 :   for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
    3759           0 :     aSharedWorkers.AppendElement(mSharedWorkers[i]);
    3760             :   }
    3761           0 : }
    3762             : 
    3763             : template <class Derived>
    3764             : void
    3765           0 : WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
    3766             :                                                     nsPIDOMWindowInner* aWindow)
    3767             : {
    3768           0 :   AssertIsOnMainThread();
    3769           0 :   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
    3770           0 :   MOZ_ASSERT(aWindow);
    3771             : 
    3772           0 :   bool someRemoved = false;
    3773             : 
    3774           0 :   for (uint32_t i = 0; i < mSharedWorkers.Length();) {
    3775           0 :     if (mSharedWorkers[i]->GetOwner() == aWindow) {
    3776           0 :       mSharedWorkers[i]->Close();
    3777           0 :       mSharedWorkers.RemoveElementAt(i);
    3778           0 :       someRemoved = true;
    3779             :     } else {
    3780           0 :       MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
    3781             :                                   aWindow));
    3782           0 :       ++i;
    3783             :     }
    3784             :   }
    3785             : 
    3786           0 :   if (!someRemoved) {
    3787           0 :     return;
    3788             :   }
    3789             : 
    3790             :   // If there are still SharedWorker objects attached to this worker then they
    3791             :   // may all be frozen and this worker would need to be frozen. Otherwise,
    3792             :   // if that was the last SharedWorker then it's time to cancel this worker.
    3793             : 
    3794           0 :   if (!mSharedWorkers.IsEmpty()) {
    3795           0 :     Freeze(nullptr);
    3796             :   } else {
    3797           0 :     Cancel();
    3798             :   }
    3799             : }
    3800             : 
    3801             : template <class Derived>
    3802             : void
    3803           0 : WorkerPrivateParent<Derived>::CloseAllSharedWorkers()
    3804             : {
    3805           0 :   AssertIsOnMainThread();
    3806           0 :   MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
    3807             : 
    3808           0 :   for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
    3809           0 :     mSharedWorkers[i]->Close();
    3810             :   }
    3811             : 
    3812           0 :   mSharedWorkers.Clear();
    3813             : 
    3814           0 :   Cancel();
    3815           0 : }
    3816             : 
    3817             : template <class Derived>
    3818             : void
    3819           1 : WorkerPrivateParent<Derived>::WorkerScriptLoaded()
    3820             : {
    3821           1 :   AssertIsOnMainThread();
    3822             : 
    3823           1 :   if (IsSharedWorker() || IsServiceWorker()) {
    3824             :     // No longer need to hold references to the window or document we came from.
    3825           0 :     mLoadInfo.mWindow = nullptr;
    3826           0 :     mLoadInfo.mScriptContext = nullptr;
    3827             :   }
    3828           1 : }
    3829             : 
    3830             : template <class Derived>
    3831             : void
    3832           1 : WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
    3833             : {
    3834           1 :   AssertIsOnMainThread();
    3835             : 
    3836           1 :   if (!mLoadInfo.mBaseURI) {
    3837           0 :     NS_ASSERTION(GetParent(), "Shouldn't happen without a parent!");
    3838           0 :     mLoadInfo.mResolvedScriptURI = aBaseURI;
    3839             :   }
    3840             : 
    3841           1 :   mLoadInfo.mBaseURI = aBaseURI;
    3842             : 
    3843           1 :   if (NS_FAILED(aBaseURI->GetSpec(mLocationInfo.mHref))) {
    3844           0 :     mLocationInfo.mHref.Truncate();
    3845             :   }
    3846             : 
    3847           1 :   mLocationInfo.mHostname.Truncate();
    3848           1 :   nsContentUtils::GetHostOrIPv6WithBrackets(aBaseURI, mLocationInfo.mHostname);
    3849             : 
    3850           2 :   nsCOMPtr<nsIURL> url(do_QueryInterface(aBaseURI));
    3851           1 :   if (!url || NS_FAILED(url->GetFilePath(mLocationInfo.mPathname))) {
    3852           0 :     mLocationInfo.mPathname.Truncate();
    3853             :   }
    3854             : 
    3855           2 :   nsCString temp;
    3856             : 
    3857           1 :   if (url && NS_SUCCEEDED(url->GetQuery(temp)) && !temp.IsEmpty()) {
    3858           0 :     mLocationInfo.mSearch.Assign('?');
    3859           0 :     mLocationInfo.mSearch.Append(temp);
    3860             :   }
    3861             : 
    3862           1 :   if (NS_SUCCEEDED(aBaseURI->GetRef(temp)) && !temp.IsEmpty()) {
    3863           0 :     if (mLocationInfo.mHash.IsEmpty()) {
    3864           0 :       mLocationInfo.mHash.Assign('#');
    3865           0 :       mLocationInfo.mHash.Append(temp);
    3866             :     }
    3867             :   }
    3868             : 
    3869           1 :   if (NS_SUCCEEDED(aBaseURI->GetScheme(mLocationInfo.mProtocol))) {
    3870           1 :     mLocationInfo.mProtocol.Append(':');
    3871             :   }
    3872             :   else {
    3873           0 :     mLocationInfo.mProtocol.Truncate();
    3874             :   }
    3875             : 
    3876             :   int32_t port;
    3877           1 :   if (NS_SUCCEEDED(aBaseURI->GetPort(&port)) && port != -1) {
    3878           0 :     mLocationInfo.mPort.AppendInt(port);
    3879             : 
    3880           0 :     nsAutoCString host(mLocationInfo.mHostname);
    3881           0 :     host.Append(':');
    3882           0 :     host.Append(mLocationInfo.mPort);
    3883             : 
    3884           0 :     mLocationInfo.mHost.Assign(host);
    3885             :   }
    3886             :   else {
    3887           1 :     mLocationInfo.mHost.Assign(mLocationInfo.mHostname);
    3888             :   }
    3889             : 
    3890           1 :   nsContentUtils::GetUTFOrigin(aBaseURI, mLocationInfo.mOrigin);
    3891           1 : }
    3892             : 
    3893             : template <class Derived>
    3894             : nsresult
    3895           0 : WorkerPrivateParent<Derived>::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
    3896             :                                                        nsILoadGroup* aLoadGroup)
    3897             : {
    3898           0 :   return mLoadInfo.SetPrincipalOnMainThread(aPrincipal, aLoadGroup);
    3899             : }
    3900             : 
    3901             : template <class Derived>
    3902             : nsresult
    3903           1 : WorkerPrivateParent<Derived>::SetPrincipalFromChannel(nsIChannel* aChannel)
    3904             : {
    3905           1 :   return mLoadInfo.SetPrincipalFromChannel(aChannel);
    3906             : }
    3907             : 
    3908             : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    3909             : template <class Derived>
    3910             : bool
    3911           1 : WorkerPrivateParent<Derived>::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
    3912             : {
    3913           1 :   return mLoadInfo.FinalChannelPrincipalIsValid(aChannel);
    3914             : }
    3915             : 
    3916             : template <class Derived>
    3917             : bool
    3918           1 : WorkerPrivateParent<Derived>::PrincipalURIMatchesScriptURL()
    3919             : {
    3920           1 :   return mLoadInfo.PrincipalURIMatchesScriptURL();
    3921             : }
    3922             : #endif
    3923             : 
    3924             : template <class Derived>
    3925             : void
    3926           0 : WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
    3927             : {
    3928           0 :   AssertIsOnMainThread();
    3929             : 
    3930             :   // The load group should have been overriden at init time.
    3931           0 :   mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
    3932           0 : }
    3933             : 
    3934             : template <class Derived>
    3935             : void
    3936           0 : WorkerPrivateParent<Derived>::FlushReportsToSharedWorkers(
    3937             :                                            nsIConsoleReportCollector* aReporter)
    3938             : {
    3939           0 :   AssertIsOnMainThread();
    3940             : 
    3941           0 :   AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
    3942           0 :   AutoTArray<WindowAction, 10> windowActions;
    3943           0 :   GetAllSharedWorkers(sharedWorkers);
    3944             : 
    3945             :   // First find out all the shared workers' window.
    3946           0 :   for (size_t index = 0; index < sharedWorkers.Length(); index++) {
    3947           0 :     RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
    3948             : 
    3949             :     // May be null.
    3950           0 :     nsPIDOMWindowInner* window = sharedWorker->GetOwner();
    3951             : 
    3952             :     // Add the owning window to our list so that we will flush the reports later.
    3953           0 :     if (window && !windowActions.Contains(window)) {
    3954           0 :       windowActions.AppendElement(WindowAction(window));
    3955             :     }
    3956             :   }
    3957             : 
    3958           0 :   bool reportErrorToBrowserConsole = true;
    3959             : 
    3960             :   // Flush the reports.
    3961           0 :   for (uint32_t index = 0; index < windowActions.Length(); index++) {
    3962           0 :     WindowAction& windowAction = windowActions[index];
    3963             : 
    3964           0 :     aReporter->FlushReportsToConsole(
    3965           0 :       windowAction.mWindow->WindowID(),
    3966             :       nsIConsoleReportCollector::ReportAction::Save);
    3967           0 :     reportErrorToBrowserConsole = false;
    3968             :   }
    3969             : 
    3970             :   // Finally report to browser console if there is no any window or shared
    3971             :   // worker.
    3972           0 :   if (reportErrorToBrowserConsole) {
    3973           0 :     aReporter->FlushReportsToConsole(0);
    3974           0 :     return;
    3975             :   }
    3976             : 
    3977           0 :   aReporter->ClearConsoleReports();
    3978             : }
    3979             : 
    3980             : template <class Derived>
    3981           6 : NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
    3982             : 
    3983             : template <class Derived>
    3984           4 : NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
    3985             : 
    3986             : template <class Derived>
    3987          37 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WorkerPrivateParent<Derived>)
    3988          20 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
    3989             : 
    3990             : template <class Derived>
    3991           2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
    3992             :                                                   DOMEventTargetHelper)
    3993           2 :   tmp->AssertIsOnParentThread();
    3994             : 
    3995             :   // The WorkerPrivate::mSelfRef has a reference to itself, which is really
    3996             :   // held by the worker thread.  We traverse this reference if and only if our
    3997             :   // busy count is zero and we have not released the main thread reference.
    3998             :   // We do not unlink it.  This allows the CC to break cycles involving the
    3999             :   // WorkerPrivate and begin shutting it down (which does happen in unlink) but
    4000             :   // ensures that the WorkerPrivate won't be deleted before we're done shutting
    4001             :   // down the thread.
    4002             : 
    4003           2 :   if (!tmp->mBusyCount && !tmp->mMainThreadObjectsForgotten) {
    4004           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelfRef)
    4005             :   }
    4006             : 
    4007             :   // The various strong references in LoadInfo are managed manually and cannot
    4008             :   // be cycle collected.
    4009           2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    4010             : 
    4011             : template <class Derived>
    4012           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
    4013             :                                                 DOMEventTargetHelper)
    4014           0 :   tmp->Terminate();
    4015           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    4016             : 
    4017             : template <class Derived>
    4018           5 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
    4019             :                                                DOMEventTargetHelper)
    4020           5 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    4021             : 
    4022             : #ifdef DEBUG
    4023             : 
    4024             : template <class Derived>
    4025             : void
    4026          16 : WorkerPrivateParent<Derived>::AssertIsOnParentThread() const
    4027             : {
    4028          16 :   if (GetParent()) {
    4029           0 :     GetParent()->AssertIsOnWorkerThread();
    4030             :   }
    4031             :   else {
    4032          16 :     AssertIsOnMainThread();
    4033             :   }
    4034          16 : }
    4035             : 
    4036             : template <class Derived>
    4037             : void
    4038           0 : WorkerPrivateParent<Derived>::AssertInnerWindowIsCorrect() const
    4039             : {
    4040           0 :   AssertIsOnParentThread();
    4041             : 
    4042             :   // Only care about top level workers from windows.
    4043           0 :   if (mParent || !mLoadInfo.mWindow) {
    4044           0 :     return;
    4045             :   }
    4046             : 
    4047           0 :   AssertIsOnMainThread();
    4048             : 
    4049           0 :   nsPIDOMWindowOuter* outer = mLoadInfo.mWindow->GetOuterWindow();
    4050           0 :   NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow,
    4051             :                "Inner window no longer correct!");
    4052             : }
    4053             : 
    4054             : #endif
    4055             : 
    4056             : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    4057             : template <class Derived>
    4058             : bool
    4059           1 : WorkerPrivateParent<Derived>::PrincipalIsValid() const
    4060             : {
    4061           1 :   return mLoadInfo.PrincipalIsValid();
    4062             : }
    4063             : #endif
    4064             : 
    4065             : class PostDebuggerMessageRunnable final : public Runnable
    4066             : {
    4067             :   WorkerDebugger *mDebugger;
    4068             :   nsString mMessage;
    4069             : 
    4070             : public:
    4071           0 :   PostDebuggerMessageRunnable(WorkerDebugger* aDebugger,
    4072             :                               const nsAString& aMessage)
    4073           0 :     : mozilla::Runnable("PostDebuggerMessageRunnable")
    4074             :     , mDebugger(aDebugger)
    4075           0 :     , mMessage(aMessage)
    4076             :   {
    4077           0 :   }
    4078             : 
    4079             : private:
    4080           0 :   ~PostDebuggerMessageRunnable()
    4081           0 :   { }
    4082             : 
    4083             :   NS_IMETHOD
    4084           0 :   Run() override
    4085             :   {
    4086           0 :     mDebugger->PostMessageToDebuggerOnMainThread(mMessage);
    4087             : 
    4088           0 :     return NS_OK;
    4089             :   }
    4090             : };
    4091             : 
    4092             : class ReportDebuggerErrorRunnable final : public Runnable
    4093             : {
    4094             :   WorkerDebugger *mDebugger;
    4095             :   nsString mFilename;
    4096             :   uint32_t mLineno;
    4097             :   nsString mMessage;
    4098             : 
    4099             : public:
    4100           0 :   ReportDebuggerErrorRunnable(WorkerDebugger* aDebugger,
    4101             :                               const nsAString& aFilename,
    4102             :                               uint32_t aLineno,
    4103             :                               const nsAString& aMessage)
    4104           0 :     : mozilla::Runnable("ReportDebuggerErrorRunnable")
    4105             :     , mDebugger(aDebugger)
    4106             :     , mFilename(aFilename)
    4107             :     , mLineno(aLineno)
    4108           0 :     , mMessage(aMessage)
    4109             :   {
    4110           0 :   }
    4111             : 
    4112             : private:
    4113           0 :   ~ReportDebuggerErrorRunnable()
    4114           0 :   { }
    4115             : 
    4116             :   NS_IMETHOD
    4117           0 :   Run() override
    4118             :   {
    4119           0 :     mDebugger->ReportErrorToDebuggerOnMainThread(mFilename, mLineno, mMessage);
    4120             : 
    4121           0 :     return NS_OK;
    4122             :   }
    4123             : };
    4124             : 
    4125           1 : WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
    4126             : : mWorkerPrivate(aWorkerPrivate),
    4127           1 :   mIsInitialized(false)
    4128             : {
    4129           1 :   AssertIsOnMainThread();
    4130           1 : }
    4131             : 
    4132           0 : WorkerDebugger::~WorkerDebugger()
    4133             : {
    4134           0 :   MOZ_ASSERT(!mWorkerPrivate);
    4135             : 
    4136           0 :   if (!NS_IsMainThread()) {
    4137           0 :     for (size_t index = 0; index < mListeners.Length(); ++index) {
    4138             :       NS_ReleaseOnMainThread(
    4139           0 :         "WorkerDebugger::mListeners", mListeners[index].forget());
    4140             :     }
    4141             :   }
    4142           0 : }
    4143             : 
    4144           3 : NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger)
    4145             : 
    4146             : NS_IMETHODIMP
    4147           0 : WorkerDebugger::GetIsClosed(bool* aResult)
    4148             : {
    4149           0 :   AssertIsOnMainThread();
    4150             : 
    4151           0 :   *aResult = !mWorkerPrivate;
    4152           0 :   return NS_OK;
    4153             : }
    4154             : 
    4155             : NS_IMETHODIMP
    4156           0 : WorkerDebugger::GetIsChrome(bool* aResult)
    4157             : {
    4158           0 :   AssertIsOnMainThread();
    4159             : 
    4160           0 :   if (!mWorkerPrivate) {
    4161           0 :     return NS_ERROR_UNEXPECTED;
    4162             :   }
    4163             : 
    4164           0 :   *aResult = mWorkerPrivate->IsChromeWorker();
    4165           0 :   return NS_OK;
    4166             : }
    4167             : 
    4168             : NS_IMETHODIMP
    4169           0 : WorkerDebugger::GetIsInitialized(bool* aResult)
    4170             : {
    4171           0 :   AssertIsOnMainThread();
    4172             : 
    4173           0 :   if (!mWorkerPrivate) {
    4174           0 :     return NS_ERROR_UNEXPECTED;
    4175             :   }
    4176             : 
    4177           0 :   *aResult = mIsInitialized;
    4178           0 :   return NS_OK;
    4179             : }
    4180             : 
    4181             : NS_IMETHODIMP
    4182           0 : WorkerDebugger::GetParent(nsIWorkerDebugger** aResult)
    4183             : {
    4184           0 :   AssertIsOnMainThread();
    4185             : 
    4186           0 :   if (!mWorkerPrivate) {
    4187           0 :     return NS_ERROR_UNEXPECTED;
    4188             :   }
    4189             : 
    4190           0 :   WorkerPrivate* parent = mWorkerPrivate->GetParent();
    4191           0 :   if (!parent) {
    4192           0 :     *aResult = nullptr;
    4193           0 :     return NS_OK;
    4194             :   }
    4195             : 
    4196           0 :   MOZ_ASSERT(mWorkerPrivate->IsDedicatedWorker());
    4197             : 
    4198           0 :   nsCOMPtr<nsIWorkerDebugger> debugger = parent->Debugger();
    4199           0 :   debugger.forget(aResult);
    4200           0 :   return NS_OK;
    4201             : }
    4202             : 
    4203             : NS_IMETHODIMP
    4204           0 : WorkerDebugger::GetType(uint32_t* aResult)
    4205             : {
    4206           0 :   AssertIsOnMainThread();
    4207             : 
    4208           0 :   if (!mWorkerPrivate) {
    4209           0 :     return NS_ERROR_UNEXPECTED;
    4210             :   }
    4211             : 
    4212           0 :   *aResult = mWorkerPrivate->Type();
    4213           0 :   return NS_OK;
    4214             : }
    4215             : 
    4216             : NS_IMETHODIMP
    4217           0 : WorkerDebugger::GetUrl(nsAString& aResult)
    4218             : {
    4219           0 :   AssertIsOnMainThread();
    4220             : 
    4221           0 :   if (!mWorkerPrivate) {
    4222           0 :     return NS_ERROR_UNEXPECTED;
    4223             :   }
    4224             : 
    4225           0 :   aResult = mWorkerPrivate->ScriptURL();
    4226           0 :   return NS_OK;
    4227             : }
    4228             : 
    4229             : NS_IMETHODIMP
    4230           0 : WorkerDebugger::GetWindow(mozIDOMWindow** aResult)
    4231             : {
    4232           0 :   AssertIsOnMainThread();
    4233             : 
    4234           0 :   if (!mWorkerPrivate) {
    4235           0 :     return NS_ERROR_UNEXPECTED;
    4236             :   }
    4237             : 
    4238           0 :   if (mWorkerPrivate->GetParent() || !mWorkerPrivate->IsDedicatedWorker()) {
    4239           0 :     *aResult = nullptr;
    4240           0 :     return NS_OK;
    4241             :   }
    4242             : 
    4243           0 :   nsCOMPtr<nsPIDOMWindowInner> window = mWorkerPrivate->GetWindow();
    4244           0 :   window.forget(aResult);
    4245           0 :   return NS_OK;
    4246             : }
    4247             : 
    4248             : NS_IMETHODIMP
    4249           0 : WorkerDebugger::GetPrincipal(nsIPrincipal** aResult)
    4250             : {
    4251           0 :   AssertIsOnMainThread();
    4252           0 :   MOZ_ASSERT(aResult);
    4253             : 
    4254           0 :   if (!mWorkerPrivate) {
    4255           0 :     return NS_ERROR_UNEXPECTED;
    4256             :   }
    4257             : 
    4258           0 :   nsCOMPtr<nsIPrincipal> prin = mWorkerPrivate->GetPrincipal();
    4259           0 :   prin.forget(aResult);
    4260             : 
    4261           0 :   return NS_OK;
    4262             : }
    4263             : 
    4264             : NS_IMETHODIMP
    4265           0 : WorkerDebugger::GetServiceWorkerID(uint32_t* aResult)
    4266             : {
    4267           0 :   AssertIsOnMainThread();
    4268           0 :   MOZ_ASSERT(aResult);
    4269             : 
    4270           0 :   if (!mWorkerPrivate || !mWorkerPrivate->IsServiceWorker()) {
    4271           0 :     return NS_ERROR_UNEXPECTED;
    4272             :   }
    4273             : 
    4274           0 :   *aResult = mWorkerPrivate->ServiceWorkerID();
    4275           0 :   return NS_OK;
    4276             : }
    4277             : 
    4278             : NS_IMETHODIMP
    4279           0 : WorkerDebugger::Initialize(const nsAString& aURL)
    4280             : {
    4281           0 :   AssertIsOnMainThread();
    4282             : 
    4283           0 :   if (!mWorkerPrivate) {
    4284           0 :     return NS_ERROR_UNEXPECTED;
    4285             :   }
    4286             : 
    4287           0 :   if (!mIsInitialized) {
    4288             :     RefPtr<CompileDebuggerScriptRunnable> runnable =
    4289           0 :       new CompileDebuggerScriptRunnable(mWorkerPrivate, aURL);
    4290           0 :     if (!runnable->Dispatch()) {
    4291           0 :       return NS_ERROR_FAILURE;
    4292             :     }
    4293             : 
    4294           0 :     mIsInitialized = true;
    4295             :   }
    4296             : 
    4297           0 :   return NS_OK;
    4298             : }
    4299             : 
    4300             : NS_IMETHODIMP
    4301           0 : WorkerDebugger::PostMessageMoz(const nsAString& aMessage)
    4302             : {
    4303           0 :   AssertIsOnMainThread();
    4304             : 
    4305           0 :   if (!mWorkerPrivate || !mIsInitialized) {
    4306           0 :     return NS_ERROR_UNEXPECTED;
    4307             :   }
    4308             : 
    4309             :   RefPtr<DebuggerMessageEventRunnable> runnable =
    4310           0 :     new DebuggerMessageEventRunnable(mWorkerPrivate, aMessage);
    4311           0 :   if (!runnable->Dispatch()) {
    4312           0 :     return NS_ERROR_FAILURE;
    4313             :   }
    4314             : 
    4315           0 :   return NS_OK;
    4316             : }
    4317             : 
    4318             : NS_IMETHODIMP
    4319           0 : WorkerDebugger::AddListener(nsIWorkerDebuggerListener* aListener)
    4320             : {
    4321           0 :   AssertIsOnMainThread();
    4322             : 
    4323           0 :   if (mListeners.Contains(aListener)) {
    4324           0 :     return NS_ERROR_INVALID_ARG;
    4325             :   }
    4326             : 
    4327           0 :   mListeners.AppendElement(aListener);
    4328           0 :   return NS_OK;
    4329             : }
    4330             : 
    4331             : NS_IMETHODIMP
    4332           0 : WorkerDebugger::RemoveListener(nsIWorkerDebuggerListener* aListener)
    4333             : {
    4334           0 :   AssertIsOnMainThread();
    4335             : 
    4336           0 :   if (!mListeners.Contains(aListener)) {
    4337           0 :     return NS_ERROR_INVALID_ARG;
    4338             :   }
    4339             : 
    4340           0 :   mListeners.RemoveElement(aListener);
    4341           0 :   return NS_OK;
    4342             : }
    4343             : 
    4344             : void
    4345           0 : WorkerDebugger::Close()
    4346             : {
    4347           0 :   MOZ_ASSERT(mWorkerPrivate);
    4348           0 :   mWorkerPrivate = nullptr;
    4349             : 
    4350           0 :   nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners(mListeners);
    4351           0 :   for (size_t index = 0; index < listeners.Length(); ++index) {
    4352           0 :       listeners[index]->OnClose();
    4353             :   }
    4354           0 : }
    4355             : 
    4356             : void
    4357           0 : WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage)
    4358             : {
    4359           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    4360             : 
    4361             :   RefPtr<PostDebuggerMessageRunnable> runnable =
    4362           0 :     new PostDebuggerMessageRunnable(this, aMessage);
    4363           0 :   if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
    4364           0 :     NS_WARNING("Failed to post message to debugger on main thread!");
    4365             :   }
    4366           0 : }
    4367             : 
    4368             : void
    4369           0 : WorkerDebugger::PostMessageToDebuggerOnMainThread(const nsAString& aMessage)
    4370             : {
    4371           0 :   AssertIsOnMainThread();
    4372             : 
    4373           0 :   nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners(mListeners);
    4374           0 :   for (size_t index = 0; index < listeners.Length(); ++index) {
    4375           0 :     listeners[index]->OnMessage(aMessage);
    4376             :   }
    4377           0 : }
    4378             : 
    4379             : void
    4380           0 : WorkerDebugger::ReportErrorToDebugger(const nsAString& aFilename,
    4381             :                                       uint32_t aLineno,
    4382             :                                       const nsAString& aMessage)
    4383             : {
    4384           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
    4385             : 
    4386             :   RefPtr<ReportDebuggerErrorRunnable> runnable =
    4387           0 :     new ReportDebuggerErrorRunnable(this, aFilename, aLineno, aMessage);
    4388           0 :   if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
    4389           0 :     NS_WARNING("Failed to report error to debugger on main thread!");
    4390             :   }
    4391           0 : }
    4392             : 
    4393             : void
    4394           0 : WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
    4395             :                                                   uint32_t aLineno,
    4396             :                                                   const nsAString& aMessage)
    4397             : {
    4398           0 :   AssertIsOnMainThread();
    4399             : 
    4400           0 :   nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners(mListeners);
    4401           0 :   for (size_t index = 0; index < listeners.Length(); ++index) {
    4402           0 :     listeners[index]->OnError(aFilename, aLineno, aMessage);
    4403             :   }
    4404             : 
    4405           0 :   WorkerErrorReport report;
    4406           0 :   report.mMessage = aMessage;
    4407           0 :   report.mFilename = aFilename;
    4408           0 :   LogErrorToConsole(report, 0);
    4409           0 : }
    4410             : 
    4411           1 : WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
    4412             :                              const nsAString& aScriptURL,
    4413             :                              bool aIsChromeWorker, WorkerType aWorkerType,
    4414             :                              const nsAString& aWorkerName,
    4415             :                              const nsACString& aServiceWorkerScope,
    4416           1 :                              WorkerLoadInfo& aLoadInfo)
    4417             :   : WorkerPrivateParent<WorkerPrivate>(aParent, aScriptURL,
    4418             :                                        aIsChromeWorker, aWorkerType,
    4419             :                                        aWorkerName, aServiceWorkerScope,
    4420             :                                        aLoadInfo)
    4421             :   , mDebuggerRegistered(false)
    4422             :   , mDebugger(nullptr)
    4423             :   , mJSContext(nullptr)
    4424             :   , mPRThread(nullptr)
    4425             :   , mNumHoldersPreventingShutdownStart(0)
    4426             :   , mDebuggerEventLoopLevel(0)
    4427             :   , mMainThreadEventTarget(GetMainThreadEventTarget())
    4428           1 :   , mWorkerControlEventTarget(new WorkerControlEventTarget(this))
    4429             :   , mErrorHandlerRecursionCount(0)
    4430             :   , mNextTimeoutId(1)
    4431             :   , mStatus(Pending)
    4432             :   , mFrozen(false)
    4433             :   , mTimerRunning(false)
    4434             :   , mRunningExpiredTimeouts(false)
    4435             :   , mPendingEventQueueClearing(false)
    4436             :   , mCancelAllPendingRunnables(false)
    4437             :   , mPeriodicGCTimerRunning(false)
    4438             :   , mIdleGCTimerRunning(false)
    4439             :   , mWorkerScriptExecutedSuccessfully(false)
    4440             :   , mFetchHandlerWasAdded(false)
    4441           2 :   , mOnLine(false)
    4442             : {
    4443           1 :   if (aParent) {
    4444           0 :     aParent->AssertIsOnWorkerThread();
    4445           0 :     aParent->GetAllPreferences(mPreferences);
    4446           0 :     mOnLine = aParent->OnLine();
    4447             :   }
    4448             :   else {
    4449           1 :     AssertIsOnMainThread();
    4450           1 :     RuntimeService::GetDefaultPreferences(mPreferences);
    4451           1 :     mOnLine = !NS_IsOffline();
    4452             :   }
    4453             : 
    4454           2 :   nsCOMPtr<nsISerialEventTarget> target;
    4455             : 
    4456             :   // A child worker just inherits the parent workers ThrottledEventQueue
    4457             :   // and main thread target for now.  This is mainly due to the restriction
    4458             :   // that ThrottledEventQueue can only be created on the main thread at the
    4459             :   // moment.
    4460           1 :   if (aParent) {
    4461           0 :     mMainThreadThrottledEventQueue = aParent->mMainThreadThrottledEventQueue;
    4462           0 :     mMainThreadEventTarget = aParent->mMainThreadEventTarget;
    4463           0 :     return;
    4464             :   }
    4465             : 
    4466           1 :   MOZ_ASSERT(NS_IsMainThread());
    4467           1 :   target = GetWindow() ? GetWindow()->EventTargetFor(TaskCategory::Worker) : nullptr;
    4468             : 
    4469           1 :   if (!target) {
    4470           1 :     target = GetMainThreadSerialEventTarget();
    4471           1 :     MOZ_DIAGNOSTIC_ASSERT(target);
    4472             :   }
    4473             : 
    4474             :   // Throttle events to the main thread using a ThrottledEventQueue specific to
    4475             :   // this worker thread.  This may return nullptr during shutdown.
    4476           1 :   mMainThreadThrottledEventQueue = ThrottledEventQueue::Create(target);
    4477             : 
    4478             :   // If we were able to creat the throttled event queue, then use it for
    4479             :   // dispatching our main thread runnables.  Otherwise use our underlying
    4480             :   // base target.
    4481           1 :   if (mMainThreadThrottledEventQueue) {
    4482           1 :     mMainThreadEventTarget = mMainThreadThrottledEventQueue;
    4483             :   } else {
    4484           0 :     mMainThreadEventTarget = target.forget();
    4485             :   }
    4486             : }
    4487             : 
    4488           0 : WorkerPrivate::~WorkerPrivate()
    4489             : {
    4490           0 :   mWorkerControlEventTarget->ForgetWorkerPrivate(this);
    4491           0 : }
    4492             : 
    4493             : // static
    4494             : already_AddRefed<WorkerPrivate>
    4495           0 : WorkerPrivate::Constructor(const GlobalObject& aGlobal,
    4496             :                            const nsAString& aScriptURL,
    4497             :                            const WorkerOptions& aOptions,
    4498             :                            ErrorResult& aRv)
    4499             : {
    4500             :   return WorkerPrivate::Constructor(aGlobal, aScriptURL, false,
    4501             :                                     WorkerTypeDedicated,
    4502           0 :                                     aOptions.mName, nullptr, aRv);
    4503             : }
    4504             : 
    4505             : // static
    4506             : bool
    4507           2 : WorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
    4508             : {
    4509             :   // If we're already on a worker workers are clearly enabled.
    4510           2 :   if (!NS_IsMainThread()) {
    4511           1 :     return true;
    4512             :   }
    4513             : 
    4514             :   // If our caller is chrome, workers are always available.
    4515           1 :   if (nsContentUtils::IsSystemCaller(aCx)) {
    4516           1 :     return true;
    4517             :   }
    4518             : 
    4519             :   // Else check the pref.
    4520           0 :   return Preferences::GetBool(PREF_WORKERS_ENABLED);
    4521             : }
    4522             : 
    4523             : // static
    4524             : already_AddRefed<ChromeWorkerPrivate>
    4525           1 : ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal,
    4526             :                                  const nsAString& aScriptURL,
    4527             :                                  ErrorResult& aRv)
    4528             : {
    4529           2 :   return WorkerPrivate::Constructor(aGlobal, aScriptURL, true,
    4530           1 :                                     WorkerTypeDedicated, EmptyString(),
    4531             :                                     nullptr, aRv)
    4532           2 :                                     .downcast<ChromeWorkerPrivate>();
    4533             : }
    4534             : 
    4535             : // static
    4536             : bool
    4537           4 : ChromeWorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
    4538             : {
    4539             :   // Chrome is always allowed to use workers, and content is never
    4540             :   // allowed to use ChromeWorker, so all we have to check is the
    4541             :   // caller.  However, chrome workers apparently might not have a
    4542             :   // system principal, so we have to check for them manually.
    4543           4 :   if (NS_IsMainThread()) {
    4544           3 :     return nsContentUtils::IsSystemCaller(aCx);
    4545             :   }
    4546             : 
    4547           1 :   return GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
    4548             : }
    4549             : 
    4550             : // static
    4551             : already_AddRefed<WorkerPrivate>
    4552           1 : WorkerPrivate::Constructor(const GlobalObject& aGlobal,
    4553             :                            const nsAString& aScriptURL,
    4554             :                            bool aIsChromeWorker, WorkerType aWorkerType,
    4555             :                            const nsAString& aWorkerName,
    4556             :                            WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
    4557             : {
    4558           1 :   JSContext* cx = aGlobal.Context();
    4559             :   return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType,
    4560           1 :                      aWorkerName, NullCString(), aLoadInfo, aRv);
    4561             : }
    4562             : 
    4563             : // static
    4564             : already_AddRefed<WorkerPrivate>
    4565           1 : WorkerPrivate::Constructor(JSContext* aCx,
    4566             :                            const nsAString& aScriptURL,
    4567             :                            bool aIsChromeWorker, WorkerType aWorkerType,
    4568             :                            const nsAString& aWorkerName,
    4569             :                            const nsACString& aServiceWorkerScope,
    4570             :                            WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
    4571             : {
    4572             :   // If this is a sub-worker, we need to keep the parent worker alive until this
    4573             :   // one is registered.
    4574           2 :   UniquePtr<SimpleWorkerHolder> holder;
    4575             : 
    4576           1 :   WorkerPrivate* parent = NS_IsMainThread() ?
    4577             :                           nullptr :
    4578           1 :                           GetCurrentThreadWorkerPrivate();
    4579           1 :   if (parent) {
    4580           0 :     parent->AssertIsOnWorkerThread();
    4581             : 
    4582           0 :     holder.reset(new SimpleWorkerHolder());
    4583           0 :     if (!holder->HoldWorker(parent, Canceling)) {
    4584           0 :       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    4585           0 :       return nullptr;
    4586             :     }
    4587             :   } else {
    4588           1 :     AssertIsOnMainThread();
    4589             :   }
    4590             : 
    4591           2 :   Maybe<WorkerLoadInfo> stackLoadInfo;
    4592           1 :   if (!aLoadInfo) {
    4593           1 :     stackLoadInfo.emplace();
    4594             : 
    4595           1 :     nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
    4596             :                               aIsChromeWorker, InheritLoadGroup,
    4597           1 :                               aWorkerType, stackLoadInfo.ptr());
    4598           1 :     aRv.MightThrowJSException();
    4599           1 :     if (NS_FAILED(rv)) {
    4600           0 :       scriptloader::ReportLoadError(aRv, rv, aScriptURL);
    4601           0 :       return nullptr;
    4602             :     }
    4603             : 
    4604           1 :     aLoadInfo = stackLoadInfo.ptr();
    4605             :   }
    4606             : 
    4607             :   // NB: This has to be done before creating the WorkerPrivate, because it will
    4608             :   // attempt to use static variables that are initialized in the RuntimeService
    4609             :   // constructor.
    4610             :   RuntimeService* runtimeService;
    4611             : 
    4612           1 :   if (!parent) {
    4613           1 :     runtimeService = RuntimeService::GetOrCreateService();
    4614           1 :     if (!runtimeService) {
    4615           0 :       aRv.Throw(NS_ERROR_FAILURE);
    4616           0 :       return nullptr;
    4617             :     }
    4618             :   }
    4619             :   else {
    4620           0 :     runtimeService = RuntimeService::GetService();
    4621             :   }
    4622             : 
    4623           1 :   MOZ_ASSERT(runtimeService);
    4624             : 
    4625             :   RefPtr<WorkerPrivate> worker =
    4626             :     new WorkerPrivate(parent, aScriptURL, aIsChromeWorker,
    4627             :                       aWorkerType, aWorkerName, aServiceWorkerScope,
    4628           2 :                       *aLoadInfo);
    4629             : 
    4630             :   // Gecko contexts always have an explicitly-set default locale (set by
    4631             :   // XPJSRuntime::Initialize for the main thread, set by
    4632             :   // WorkerThreadPrimaryRunnable::Run for workers just before running worker
    4633             :   // code), so this is never SpiderMonkey's builtin default locale.
    4634           2 :   JS::UniqueChars defaultLocale = JS_GetDefaultLocale(aCx);
    4635           1 :   if (NS_WARN_IF(!defaultLocale)) {
    4636           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    4637           0 :     return nullptr;
    4638             :   }
    4639             : 
    4640           1 :   worker->mDefaultLocale = Move(defaultLocale);
    4641             : 
    4642           1 :   if (!runtimeService->RegisterWorker(worker)) {
    4643           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    4644           0 :     return nullptr;
    4645             :   }
    4646             : 
    4647           1 :   worker->EnableDebugger();
    4648             : 
    4649           1 :   MOZ_DIAGNOSTIC_ASSERT(worker->PrincipalIsValid());
    4650             : 
    4651             :   RefPtr<CompileScriptRunnable> compiler =
    4652           3 :     new CompileScriptRunnable(worker, aScriptURL);
    4653           1 :   if (!compiler->Dispatch()) {
    4654           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    4655           0 :     return nullptr;
    4656             :   }
    4657             : 
    4658           1 :   worker->mSelfRef = worker;
    4659             : 
    4660           1 :   return worker.forget();
    4661             : }
    4662             : 
    4663             : // static
    4664             : nsresult
    4665           1 : WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
    4666             :                            WorkerPrivate* aParent, const nsAString& aScriptURL,
    4667             :                            bool aIsChromeWorker,
    4668             :                            LoadGroupBehavior aLoadGroupBehavior,
    4669             :                            WorkerType aWorkerType,
    4670             :                            WorkerLoadInfo* aLoadInfo)
    4671             : {
    4672             :   using namespace mozilla::dom::workers::scriptloader;
    4673             : 
    4674           1 :   MOZ_ASSERT(aCx);
    4675           1 :   MOZ_ASSERT_IF(NS_IsMainThread(), aCx == nsContentUtils::GetCurrentJSContext());
    4676             : 
    4677           1 :   if (aWindow) {
    4678           0 :     AssertIsOnMainThread();
    4679             :   }
    4680             : 
    4681           2 :   WorkerLoadInfo loadInfo;
    4682             :   nsresult rv;
    4683             : 
    4684           1 :   if (aParent) {
    4685           0 :     aParent->AssertIsOnWorkerThread();
    4686             : 
    4687             :     // If the parent is going away give up now.
    4688             :     Status parentStatus;
    4689             :     {
    4690           0 :       MutexAutoLock lock(aParent->mMutex);
    4691           0 :       parentStatus = aParent->mStatus;
    4692             :     }
    4693             : 
    4694           0 :     if (parentStatus > Running) {
    4695           0 :       return NS_ERROR_FAILURE;
    4696             :     }
    4697             : 
    4698             :     // Passing a pointer to our stack loadInfo is safe here because this
    4699             :     // method uses a sync runnable to get the channel from the main thread.
    4700           0 :     rv = ChannelFromScriptURLWorkerThread(aCx, aParent, aScriptURL,
    4701             :                                           loadInfo);
    4702           0 :     if (NS_FAILED(rv)) {
    4703           0 :       MOZ_ALWAYS_TRUE(loadInfo.ProxyReleaseMainThreadObjects(aParent));
    4704           0 :       return rv;
    4705             :     }
    4706             : 
    4707             :     // Now that we've spun the loop there's no guarantee that our parent is
    4708             :     // still alive.  We may have received control messages initiating shutdown.
    4709             :     {
    4710           0 :       MutexAutoLock lock(aParent->mMutex);
    4711           0 :       parentStatus = aParent->mStatus;
    4712             :     }
    4713             : 
    4714           0 :     if (parentStatus > Running) {
    4715           0 :       MOZ_ALWAYS_TRUE(loadInfo.ProxyReleaseMainThreadObjects(aParent));
    4716           0 :       return NS_ERROR_FAILURE;
    4717             :     }
    4718             : 
    4719           0 :     loadInfo.mDomain = aParent->Domain();
    4720           0 :     loadInfo.mFromWindow = aParent->IsFromWindow();
    4721           0 :     loadInfo.mWindowID = aParent->WindowID();
    4722           0 :     loadInfo.mStorageAllowed = aParent->IsStorageAllowed();
    4723           0 :     loadInfo.mOriginAttributes = aParent->GetOriginAttributes();
    4724           0 :     loadInfo.mServiceWorkersTestingInWindow =
    4725           0 :       aParent->ServiceWorkersTestingInWindow();
    4726             :   } else {
    4727           1 :     AssertIsOnMainThread();
    4728             : 
    4729             :     // Make sure that the IndexedDatabaseManager is set up
    4730           1 :     Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
    4731             : 
    4732           1 :     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
    4733           1 :     MOZ_ASSERT(ssm);
    4734             : 
    4735           1 :     bool isChrome = nsContentUtils::IsSystemCaller(aCx);
    4736             : 
    4737             :     // First check to make sure the caller has permission to make a privileged
    4738             :     // worker if they called the ChromeWorker/ChromeSharedWorker constructor.
    4739           1 :     if (aIsChromeWorker && !isChrome) {
    4740           0 :       return NS_ERROR_DOM_SECURITY_ERR;
    4741             :     }
    4742             : 
    4743             :     // Chrome callers (whether creating a ChromeWorker or Worker) always get the
    4744             :     // system principal here as they're allowed to load anything. The script
    4745             :     // loader will refuse to run any script that does not also have the system
    4746             :     // principal.
    4747           1 :     if (isChrome) {
    4748           1 :       rv = ssm->GetSystemPrincipal(getter_AddRefs(loadInfo.mPrincipal));
    4749           1 :       NS_ENSURE_SUCCESS(rv, rv);
    4750             : 
    4751           1 :       loadInfo.mPrincipalIsSystem = true;
    4752             :     }
    4753             : 
    4754             :     // See if we're being called from a window.
    4755           2 :     nsCOMPtr<nsPIDOMWindowInner> globalWindow = aWindow;
    4756           1 :     if (!globalWindow) {
    4757             :       nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
    4758           2 :         nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
    4759           1 :       if (scriptGlobal) {
    4760           0 :         globalWindow = do_QueryInterface(scriptGlobal);
    4761           0 :         MOZ_ASSERT(globalWindow);
    4762             :       }
    4763             :     }
    4764             : 
    4765           2 :     nsCOMPtr<nsIDocument> document;
    4766             : 
    4767           1 :     if (globalWindow) {
    4768             :       // Only use the current inner window, and only use it if the caller can
    4769             :       // access it.
    4770           0 :       if (nsPIDOMWindowOuter* outerWindow = globalWindow->GetOuterWindow()) {
    4771           0 :         loadInfo.mWindow = outerWindow->GetCurrentInnerWindow();
    4772             :         // TODO: fix this for SharedWorkers with multiple documents (bug 1177935)
    4773           0 :         loadInfo.mServiceWorkersTestingInWindow =
    4774           0 :           outerWindow->GetServiceWorkersTestingEnabled();
    4775             :       }
    4776             : 
    4777           0 :       if (!loadInfo.mWindow ||
    4778           0 :           (globalWindow != loadInfo.mWindow &&
    4779           0 :             !nsContentUtils::CanCallerAccess(loadInfo.mWindow))) {
    4780           0 :         return NS_ERROR_DOM_SECURITY_ERR;
    4781             :       }
    4782             : 
    4783           0 :       nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(loadInfo.mWindow);
    4784           0 :       MOZ_ASSERT(sgo);
    4785             : 
    4786           0 :       loadInfo.mScriptContext = sgo->GetContext();
    4787           0 :       NS_ENSURE_TRUE(loadInfo.mScriptContext, NS_ERROR_FAILURE);
    4788             : 
    4789             :       // If we're called from a window then we can dig out the principal and URI
    4790             :       // from the document.
    4791           0 :       document = loadInfo.mWindow->GetExtantDoc();
    4792           0 :       NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
    4793             : 
    4794           0 :       loadInfo.mBaseURI = document->GetDocBaseURI();
    4795           0 :       loadInfo.mLoadGroup = document->GetDocumentLoadGroup();
    4796           0 :       NS_ENSURE_TRUE(loadInfo.mLoadGroup, NS_ERROR_FAILURE);
    4797             : 
    4798             :       // Use the document's NodePrincipal as our principal if we're not being
    4799             :       // called from chrome.
    4800           0 :       if (!loadInfo.mPrincipal) {
    4801           0 :         loadInfo.mPrincipal = document->NodePrincipal();
    4802           0 :         NS_ENSURE_TRUE(loadInfo.mPrincipal, NS_ERROR_FAILURE);
    4803             : 
    4804             :         // We use the document's base domain to limit the number of workers
    4805             :         // each domain can create. For sandboxed documents, we use the domain
    4806             :         // of their first non-sandboxed document, walking up until we find
    4807             :         // one. If we can't find one, we fall back to using the GUID of the
    4808             :         // null principal as the base domain.
    4809           0 :         if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
    4810           0 :           nsCOMPtr<nsIDocument> tmpDoc = document;
    4811           0 :           do {
    4812           0 :             tmpDoc = tmpDoc->GetParentDocument();
    4813           0 :           } while (tmpDoc && tmpDoc->GetSandboxFlags() & SANDBOXED_ORIGIN);
    4814             : 
    4815           0 :           if (tmpDoc) {
    4816             :             // There was an unsandboxed ancestor, yay!
    4817           0 :             nsCOMPtr<nsIPrincipal> tmpPrincipal = tmpDoc->NodePrincipal();
    4818           0 :             rv = tmpPrincipal->GetBaseDomain(loadInfo.mDomain);
    4819           0 :             NS_ENSURE_SUCCESS(rv, rv);
    4820             :           } else {
    4821             :             // No unsandboxed ancestor, use our GUID.
    4822           0 :             rv = loadInfo.mPrincipal->GetBaseDomain(loadInfo.mDomain);
    4823           0 :             NS_ENSURE_SUCCESS(rv, rv);
    4824             :           }
    4825             :         } else {
    4826             :           // Document creating the worker is not sandboxed.
    4827           0 :           rv = loadInfo.mPrincipal->GetBaseDomain(loadInfo.mDomain);
    4828           0 :           NS_ENSURE_SUCCESS(rv, rv);
    4829             :         }
    4830             :       }
    4831             : 
    4832           0 :       NS_ENSURE_TRUE(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
    4833             :                                                   loadInfo.mPrincipal),
    4834             :                      NS_ERROR_FAILURE);
    4835             : 
    4836             :       nsCOMPtr<nsIPermissionManager> permMgr =
    4837           0 :         do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
    4838           0 :       NS_ENSURE_SUCCESS(rv, rv);
    4839             : 
    4840             :       uint32_t perm;
    4841           0 :       rv = permMgr->TestPermissionFromPrincipal(loadInfo.mPrincipal, "systemXHR",
    4842           0 :                                                 &perm);
    4843           0 :       NS_ENSURE_SUCCESS(rv, rv);
    4844             : 
    4845           0 :       loadInfo.mXHRParamsAllowed = perm == nsIPermissionManager::ALLOW_ACTION;
    4846             : 
    4847           0 :       loadInfo.mFromWindow = true;
    4848           0 :       loadInfo.mWindowID = globalWindow->WindowID();
    4849             :       nsContentUtils::StorageAccess access =
    4850           0 :         nsContentUtils::StorageAllowedForWindow(globalWindow);
    4851           0 :       loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
    4852           0 :       loadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(document);
    4853             :     } else {
    4854             :       // Not a window
    4855           1 :       MOZ_ASSERT(isChrome);
    4856             : 
    4857             :       // We're being created outside of a window. Need to figure out the script
    4858             :       // that is creating us in order for us to use relative URIs later on.
    4859           2 :       JS::AutoFilename fileName;
    4860           1 :       if (JS::DescribeScriptedCaller(aCx, &fileName)) {
    4861             :         // In most cases, fileName is URI. In a few other cases
    4862             :         // (e.g. xpcshell), fileName is a file path. Ideally, we would
    4863             :         // prefer testing whether fileName parses as an URI and fallback
    4864             :         // to file path in case of error, but Windows file paths have
    4865             :         // the interesting property that they can be parsed as bogus
    4866             :         // URIs (e.g. C:/Windows/Tmp is interpreted as scheme "C",
    4867             :         // hostname "Windows", path "Tmp"), which defeats this algorithm.
    4868             :         // Therefore, we adopt the opposite convention.
    4869             :         nsCOMPtr<nsIFile> scriptFile =
    4870           2 :           do_CreateInstance("@mozilla.org/file/local;1", &rv);
    4871           1 :         if (NS_FAILED(rv)) {
    4872           0 :           return rv;
    4873             :         }
    4874             : 
    4875           1 :         rv = scriptFile->InitWithPath(NS_ConvertUTF8toUTF16(fileName.get()));
    4876           1 :         if (NS_SUCCEEDED(rv)) {
    4877           0 :           rv = NS_NewFileURI(getter_AddRefs(loadInfo.mBaseURI),
    4878             :                              scriptFile);
    4879             :         }
    4880           1 :         if (NS_FAILED(rv)) {
    4881             :           // As expected, fileName is not a path, so proceed with
    4882             :           // a uri.
    4883           1 :           rv = NS_NewURI(getter_AddRefs(loadInfo.mBaseURI),
    4884             :                          fileName.get());
    4885             :         }
    4886           1 :         if (NS_FAILED(rv)) {
    4887           0 :           return rv;
    4888             :         }
    4889             :       }
    4890           1 :       loadInfo.mXHRParamsAllowed = true;
    4891           1 :       loadInfo.mFromWindow = false;
    4892           1 :       loadInfo.mWindowID = UINT64_MAX;
    4893           1 :       loadInfo.mStorageAllowed = true;
    4894           1 :       loadInfo.mOriginAttributes = OriginAttributes();
    4895             :     }
    4896             : 
    4897           1 :     MOZ_ASSERT(loadInfo.mPrincipal);
    4898           1 :     MOZ_ASSERT(isChrome || !loadInfo.mDomain.IsEmpty());
    4899             : 
    4900           1 :     if (!loadInfo.mLoadGroup || aLoadGroupBehavior == OverrideLoadGroup) {
    4901           1 :       OverrideLoadInfoLoadGroup(loadInfo);
    4902             :     }
    4903           1 :     MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
    4904             :                                             loadInfo.mPrincipal));
    4905             : 
    4906             :     // Top level workers' main script use the document charset for the script
    4907             :     // uri encoding.
    4908           1 :     bool useDefaultEncoding = false;
    4909           1 :     rv = ChannelFromScriptURLMainThread(loadInfo.mPrincipal, loadInfo.mBaseURI,
    4910             :                                         document, loadInfo.mLoadGroup,
    4911             :                                         aScriptURL,
    4912             :                                         ContentPolicyType(aWorkerType),
    4913             :                                         useDefaultEncoding,
    4914           2 :                                         getter_AddRefs(loadInfo.mChannel));
    4915           1 :     NS_ENSURE_SUCCESS(rv, rv);
    4916             : 
    4917           1 :     rv = NS_GetFinalChannelURI(loadInfo.mChannel,
    4918           2 :                                getter_AddRefs(loadInfo.mResolvedScriptURI));
    4919           1 :     NS_ENSURE_SUCCESS(rv, rv);
    4920             : 
    4921           1 :     rv = loadInfo.SetPrincipalFromChannel(loadInfo.mChannel);
    4922           1 :     NS_ENSURE_SUCCESS(rv, rv);
    4923             :   }
    4924             : 
    4925           1 :   MOZ_DIAGNOSTIC_ASSERT(loadInfo.PrincipalIsValid());
    4926             : 
    4927           1 :   aLoadInfo->StealFrom(loadInfo);
    4928           1 :   return NS_OK;
    4929             : }
    4930             : 
    4931             : // static
    4932             : void
    4933           1 : WorkerPrivate::OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo)
    4934             : {
    4935           1 :   MOZ_ASSERT(!aLoadInfo.mInterfaceRequestor);
    4936             : 
    4937             :   aLoadInfo.mInterfaceRequestor =
    4938             :     new WorkerLoadInfo::InterfaceRequestor(aLoadInfo.mPrincipal,
    4939           2 :                                            aLoadInfo.mLoadGroup);
    4940           1 :   aLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aLoadInfo.mLoadGroup);
    4941             : 
    4942             :   // NOTE: this defaults the load context to:
    4943             :   //  - private browsing = false
    4944             :   //  - content = true
    4945             :   //  - use remote tabs = false
    4946             :   nsCOMPtr<nsILoadGroup> loadGroup =
    4947           2 :     do_CreateInstance(NS_LOADGROUP_CONTRACTID);
    4948             : 
    4949             :   nsresult rv =
    4950           1 :     loadGroup->SetNotificationCallbacks(aLoadInfo.mInterfaceRequestor);
    4951           1 :   MOZ_ALWAYS_SUCCEEDS(rv);
    4952             : 
    4953           1 :   aLoadInfo.mLoadGroup = loadGroup.forget();
    4954             : 
    4955           1 :   MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadInfo.mLoadGroup,
    4956             :                                           aLoadInfo.mPrincipal));
    4957           1 : }
    4958             : 
    4959             : void
    4960           1 : WorkerPrivate::DoRunLoop(JSContext* aCx)
    4961             : {
    4962           1 :   AssertIsOnWorkerThread();
    4963           1 :   MOZ_ASSERT(mThread);
    4964             : 
    4965             :   {
    4966           2 :     MutexAutoLock lock(mMutex);
    4967           1 :     mJSContext = aCx;
    4968             : 
    4969           1 :     MOZ_ASSERT(mStatus == Pending);
    4970           1 :     mStatus = Running;
    4971             :   }
    4972             : 
    4973             :   // Now that we've done that, we can go ahead and set up our AutoJSAPI.  We
    4974             :   // can't before this point, because it can't find the right JSContext before
    4975             :   // then, since it gets it from our mJSContext.
    4976           1 :   AutoJSAPI jsapi;
    4977           1 :   jsapi.Init();
    4978           1 :   MOZ_ASSERT(jsapi.cx() == aCx);
    4979             : 
    4980           1 :   EnableMemoryReporter();
    4981             : 
    4982           1 :   InitializeGCTimers();
    4983             : 
    4984           1 :   Maybe<JSAutoCompartment> workerCompartment;
    4985             : 
    4986             :   for (;;) {
    4987             :     Status currentStatus, previousStatus;
    4988           1 :     bool debuggerRunnablesPending = false;
    4989           1 :     bool normalRunnablesPending = false;
    4990             : 
    4991             :     {
    4992           2 :       MutexAutoLock lock(mMutex);
    4993           1 :       previousStatus = mStatus;
    4994             : 
    4995           3 :       while (mControlQueue.IsEmpty() &&
    4996           3 :              !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
    4997           2 :              !(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
    4998           0 :         WaitForWorkerEvents();
    4999             :       }
    5000             : 
    5001           1 :       auto result = ProcessAllControlRunnablesLocked();
    5002           1 :       if (result != ProcessAllControlRunnablesResult::Nothing) {
    5003             :         // NB: There's no JS on the stack here, so Abort vs MayContinue is
    5004             :         // irrelevant
    5005             : 
    5006             :         // The state of the world may have changed, recheck it.
    5007           0 :         normalRunnablesPending = NS_HasPendingEvents(mThread);
    5008             :         // The debugger queue doesn't get cleared, so we can ignore that.
    5009             :       }
    5010             : 
    5011           1 :       currentStatus = mStatus;
    5012             :     }
    5013             : 
    5014             :     // if all holders are done then we can kill this thread.
    5015           1 :     if (currentStatus != Running && !HasActiveHolders()) {
    5016             : 
    5017             :       // If we just changed status, we must schedule the current runnables.
    5018           0 :       if (previousStatus != Running && currentStatus != Killing) {
    5019           0 :         NotifyInternal(aCx, Killing);
    5020           0 :         MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    5021             : 
    5022             : #ifdef DEBUG
    5023             :         {
    5024           0 :           MutexAutoLock lock(mMutex);
    5025           0 :           currentStatus = mStatus;
    5026             :         }
    5027           0 :         MOZ_ASSERT(currentStatus == Killing);
    5028             : #else
    5029             :         currentStatus = Killing;
    5030             : #endif
    5031             :       }
    5032             : 
    5033             :       // If we're supposed to die then we should exit the loop.
    5034           0 :       if (currentStatus == Killing) {
    5035             :         // Flush uncaught rejections immediately, without
    5036             :         // waiting for a next tick.
    5037           0 :         PromiseDebugging::FlushUncaughtRejections();
    5038             : 
    5039           0 :         ShutdownGCTimers();
    5040             : 
    5041           0 :         DisableMemoryReporter();
    5042             : 
    5043             :         {
    5044           0 :           MutexAutoLock lock(mMutex);
    5045             : 
    5046           0 :           mStatus = Dead;
    5047           0 :           mJSContext = nullptr;
    5048             :         }
    5049             : 
    5050             :         // After mStatus is set to Dead there can be no more
    5051             :         // WorkerControlRunnables so no need to lock here.
    5052           0 :         if (!mControlQueue.IsEmpty()) {
    5053             :           WorkerControlRunnable* runnable;
    5054           0 :           while (mControlQueue.Pop(runnable)) {
    5055           0 :             runnable->Cancel();
    5056           0 :             runnable->Release();
    5057             :           }
    5058             :         }
    5059             : 
    5060             :         // Unroot the globals
    5061           0 :         mScope = nullptr;
    5062           0 :         mDebuggerScope = nullptr;
    5063             : 
    5064           0 :         return;
    5065             :       }
    5066             :     }
    5067             : 
    5068           1 :     if (debuggerRunnablesPending || normalRunnablesPending) {
    5069             :       // Start the periodic GC timer if it is not already running.
    5070           1 :       SetGCTimerMode(PeriodicTimer);
    5071             :     }
    5072             : 
    5073           1 :     if (debuggerRunnablesPending) {
    5074             :       WorkerRunnable* runnable;
    5075             : 
    5076             :       {
    5077           0 :         MutexAutoLock lock(mMutex);
    5078             : 
    5079           0 :         mDebuggerQueue.Pop(runnable);
    5080           0 :         debuggerRunnablesPending = !mDebuggerQueue.IsEmpty();
    5081             :       }
    5082             : 
    5083           0 :       MOZ_ASSERT(runnable);
    5084           0 :       static_cast<nsIRunnable*>(runnable)->Run();
    5085           0 :       runnable->Release();
    5086             : 
    5087             :       // Flush the promise queue.
    5088           0 :       Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
    5089             : 
    5090           0 :       if (debuggerRunnablesPending) {
    5091           0 :         WorkerDebuggerGlobalScope* globalScope = DebuggerGlobalScope();
    5092           0 :         MOZ_ASSERT(globalScope);
    5093             : 
    5094             :         // Now *might* be a good time to GC. Let the JS engine make the decision.
    5095           0 :         JSAutoCompartment ac(aCx, globalScope->GetGlobalJSObject());
    5096           0 :         JS_MaybeGC(aCx);
    5097             :       }
    5098           1 :     } else if (normalRunnablesPending) {
    5099             :       // Process a single runnable from the main queue.
    5100           1 :       NS_ProcessNextEvent(mThread, false);
    5101             : 
    5102           0 :       normalRunnablesPending = NS_HasPendingEvents(mThread);
    5103           0 :       if (normalRunnablesPending && GlobalScope()) {
    5104             :         // Now *might* be a good time to GC. Let the JS engine make the decision.
    5105           0 :         JSAutoCompartment ac(aCx, GlobalScope()->GetGlobalJSObject());
    5106           0 :         JS_MaybeGC(aCx);
    5107             :       }
    5108             :     }
    5109             : 
    5110           0 :     if (!debuggerRunnablesPending && !normalRunnablesPending) {
    5111             :       // Both the debugger event queue and the normal event queue has been
    5112             :       // exhausted, cancel the periodic GC timer and schedule the idle GC timer.
    5113           0 :       SetGCTimerMode(IdleTimer);
    5114             :     }
    5115             : 
    5116             :     // If the worker thread is spamming the main thread faster than it can
    5117             :     // process the work, then pause the worker thread until the MT catches
    5118             :     // up.
    5119           0 :     if (mMainThreadThrottledEventQueue &&
    5120           0 :         mMainThreadThrottledEventQueue->Length() > 5000) {
    5121           0 :       mMainThreadThrottledEventQueue->AwaitIdle();
    5122             :     }
    5123           0 :   }
    5124             : 
    5125             :   MOZ_CRASH("Shouldn't get here!");
    5126             : }
    5127             : 
    5128             : void
    5129          35 : WorkerPrivate::OnProcessNextEvent()
    5130             : {
    5131          35 :   AssertIsOnWorkerThread();
    5132             : 
    5133          35 :   uint32_t recursionDepth = CycleCollectedJSContext::Get()->RecursionDepth();
    5134          35 :   MOZ_ASSERT(recursionDepth);
    5135             : 
    5136             :   // Normally we process control runnables in DoRunLoop or RunCurrentSyncLoop.
    5137             :   // However, it's possible that non-worker C++ could spin its own nested event
    5138             :   // loop, and in that case we must ensure that we continue to process control
    5139             :   // runnables here.
    5140          70 :   if (recursionDepth > 1 &&
    5141          35 :       mSyncLoopStack.Length() < recursionDepth - 1) {
    5142          31 :     Unused << ProcessAllControlRunnables();
    5143             :     // There's no running JS, and no state to revalidate, so we can ignore the
    5144             :     // return value.
    5145             :   }
    5146          35 : }
    5147             : 
    5148             : void
    5149          31 : WorkerPrivate::AfterProcessNextEvent()
    5150             : {
    5151          31 :   AssertIsOnWorkerThread();
    5152          31 :   MOZ_ASSERT(CycleCollectedJSContext::Get()->RecursionDepth());
    5153          31 : }
    5154             : 
    5155             : void
    5156           0 : WorkerPrivate::MaybeDispatchLoadFailedRunnable()
    5157             : {
    5158           0 :   AssertIsOnWorkerThread();
    5159             : 
    5160           0 :   nsCOMPtr<nsIRunnable> runnable = StealLoadFailedAsyncRunnable();
    5161           0 :   if (!runnable) {
    5162           0 :     return;
    5163             :   }
    5164             : 
    5165           0 :   MOZ_ALWAYS_SUCCEEDS(DispatchToMainThread(runnable.forget()));
    5166             : }
    5167             : 
    5168             : nsIEventTarget*
    5169           0 : WorkerPrivate::MainThreadEventTarget()
    5170             : {
    5171           0 :   return mMainThreadEventTarget;
    5172             : }
    5173             : 
    5174             : nsresult
    5175          12 : WorkerPrivate::DispatchToMainThread(nsIRunnable* aRunnable, uint32_t aFlags)
    5176             : {
    5177          24 :   nsCOMPtr<nsIRunnable> r = aRunnable;
    5178          24 :   return DispatchToMainThread(r.forget(), aFlags);
    5179             : }
    5180             : 
    5181             : nsresult
    5182          13 : WorkerPrivate::DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
    5183             :                                     uint32_t aFlags)
    5184             : {
    5185          26 :   nsCOMPtr<nsIRunnable> runnable = aRunnable;
    5186          26 :   if (nsCOMPtr<nsINamed> named = do_QueryInterface(runnable)) {
    5187          12 :     named->SetName("WorkerRunnable");
    5188             :   }
    5189          26 :   return mMainThreadEventTarget->Dispatch(runnable.forget(), aFlags);
    5190             : }
    5191             : 
    5192             : nsIEventTarget*
    5193           0 : WorkerPrivate::ControlEventTarget()
    5194             : {
    5195           0 :   return mWorkerControlEventTarget;
    5196             : }
    5197             : 
    5198             : void
    5199           1 : WorkerPrivate::InitializeGCTimers()
    5200             : {
    5201           1 :   AssertIsOnWorkerThread();
    5202             : 
    5203             :   // We need a timer for GC. The basic plan is to run a non-shrinking GC
    5204             :   // periodically (PERIODIC_GC_TIMER_DELAY_SEC) while the worker is running.
    5205             :   // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_SEC) timer to
    5206             :   // run a shrinking GC. If the worker receives more messages then the short
    5207             :   // timer is canceled and the periodic timer resumes.
    5208           1 :   mGCTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    5209           1 :   MOZ_ASSERT(mGCTimer);
    5210             : 
    5211           1 :   mPeriodicGCTimerRunning = false;
    5212           1 :   mIdleGCTimerRunning = false;
    5213           1 : }
    5214             : 
    5215             : void
    5216          61 : WorkerPrivate::SetGCTimerMode(GCTimerMode aMode)
    5217             : {
    5218          61 :   AssertIsOnWorkerThread();
    5219          61 :   MOZ_ASSERT(mGCTimer);
    5220             : 
    5221          61 :   if ((aMode == PeriodicTimer && mPeriodicGCTimerRunning) ||
    5222          26 :       (aMode == IdleTimer && mIdleGCTimerRunning)) {
    5223           9 :     return;
    5224             :   }
    5225             : 
    5226          52 :   MOZ_ALWAYS_SUCCEEDS(mGCTimer->Cancel());
    5227             : 
    5228          52 :   mPeriodicGCTimerRunning = false;
    5229          52 :   mIdleGCTimerRunning = false;
    5230          52 :   LOG(WorkerLog(),
    5231             :       ("Worker %p canceled GC timer because %s\n", this,
    5232             :        aMode == PeriodicTimer ?
    5233             :        "periodic" :
    5234             :        aMode == IdleTimer ? "idle" : "none"));
    5235             : 
    5236          52 :   if (aMode == NoTimer) {
    5237           0 :     return;
    5238             :   }
    5239             : 
    5240          52 :   MOZ_ASSERT(aMode == PeriodicTimer || aMode == IdleTimer);
    5241             : 
    5242          52 :   uint32_t delay = 0;
    5243          52 :   int16_t type = nsITimer::TYPE_ONE_SHOT;
    5244          52 :   nsTimerCallbackFunc callback = nullptr;
    5245          52 :   const char* name = nullptr;
    5246             : 
    5247          52 :   if (aMode == PeriodicTimer) {
    5248          26 :     delay = PERIODIC_GC_TIMER_DELAY_SEC * 1000;
    5249          26 :     type = nsITimer::TYPE_REPEATING_SLACK;
    5250          26 :     callback = PeriodicGCTimerCallback;
    5251          26 :     name = "dom::workers::PeriodicGCTimerCallback";
    5252             :   }
    5253             :   else {
    5254          26 :     delay = IDLE_GC_TIMER_DELAY_SEC * 1000;
    5255          26 :     type = nsITimer::TYPE_ONE_SHOT;
    5256          26 :     callback = IdleGCTimerCallback;
    5257          26 :     name = "dom::workers::IdleGCTimerCallback";
    5258             :   }
    5259             : 
    5260          52 :   MOZ_ALWAYS_SUCCEEDS(mGCTimer->SetTarget(mWorkerControlEventTarget));
    5261          52 :   MOZ_ALWAYS_SUCCEEDS(
    5262             :     mGCTimer->InitWithNamedFuncCallback(callback, this, delay, type, name));
    5263             : 
    5264          52 :   if (aMode == PeriodicTimer) {
    5265          26 :     LOG(WorkerLog(), ("Worker %p scheduled periodic GC timer\n", this));
    5266          26 :     mPeriodicGCTimerRunning = true;
    5267             :   }
    5268             :   else {
    5269          26 :     LOG(WorkerLog(), ("Worker %p scheduled idle GC timer\n", this));
    5270          26 :     mIdleGCTimerRunning = true;
    5271             :   }
    5272             : }
    5273             : 
    5274             : void
    5275           0 : WorkerPrivate::ShutdownGCTimers()
    5276             : {
    5277           0 :   AssertIsOnWorkerThread();
    5278             : 
    5279           0 :   MOZ_ASSERT(mGCTimer);
    5280             : 
    5281             :   // Always make sure the timer is canceled.
    5282           0 :   MOZ_ALWAYS_SUCCEEDS(mGCTimer->Cancel());
    5283             : 
    5284           0 :   LOG(WorkerLog(), ("Worker %p killed the GC timer\n", this));
    5285             : 
    5286           0 :   mGCTimer = nullptr;
    5287           0 :   mPeriodicGCTimerRunning = false;
    5288           0 :   mIdleGCTimerRunning = false;
    5289           0 : }
    5290             : 
    5291             : bool
    5292           0 : WorkerPrivate::InterruptCallback(JSContext* aCx)
    5293             : {
    5294           0 :   AssertIsOnWorkerThread();
    5295             : 
    5296           0 :   MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    5297             : 
    5298           0 :   bool mayContinue = true;
    5299           0 :   bool scheduledIdleGC = false;
    5300             : 
    5301             :   for (;;) {
    5302             :     // Run all control events now.
    5303           0 :     auto result = ProcessAllControlRunnables();
    5304           0 :     if (result == ProcessAllControlRunnablesResult::Abort) {
    5305           0 :       mayContinue = false;
    5306             :     }
    5307             : 
    5308           0 :     bool mayFreeze = mFrozen;
    5309           0 :     if (mayFreeze) {
    5310           0 :       MutexAutoLock lock(mMutex);
    5311           0 :       mayFreeze = mStatus <= Running;
    5312             :     }
    5313             : 
    5314           0 :     if (!mayContinue || !mayFreeze) {
    5315             :       break;
    5316             :     }
    5317             : 
    5318             :     // Cancel the periodic GC timer here before freezing. The idle GC timer
    5319             :     // will clean everything up once it runs.
    5320           0 :     if (!scheduledIdleGC) {
    5321           0 :       SetGCTimerMode(IdleTimer);
    5322           0 :       scheduledIdleGC = true;
    5323             :     }
    5324             : 
    5325           0 :     while ((mayContinue = MayContinueRunning())) {
    5326           0 :       MutexAutoLock lock(mMutex);
    5327           0 :       if (!mControlQueue.IsEmpty()) {
    5328           0 :         break;
    5329             :       }
    5330             : 
    5331           0 :       WaitForWorkerEvents(PR_MillisecondsToInterval(UINT32_MAX));
    5332             :     }
    5333           0 :   }
    5334             : 
    5335           0 :   if (!mayContinue) {
    5336             :     // We want only uncatchable exceptions here.
    5337           0 :     NS_ASSERTION(!JS_IsExceptionPending(aCx),
    5338             :                  "Should not have an exception set here!");
    5339           0 :     return false;
    5340             :   }
    5341             : 
    5342             :   // Make sure the periodic timer gets turned back on here.
    5343           0 :   SetGCTimerMode(PeriodicTimer);
    5344             : 
    5345           0 :   return true;
    5346             : }
    5347             : 
    5348             : bool
    5349           0 : WorkerPrivate::IsOnCurrentThread()
    5350             : {
    5351             :   // May be called on any thread!
    5352             : 
    5353           0 :   MOZ_ASSERT(mPRThread);
    5354           0 :   return PR_GetCurrentThread() == mPRThread;
    5355             : }
    5356             : 
    5357             : void
    5358           0 : WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot)
    5359             : {
    5360           0 :   AssertIsOnWorkerThread();
    5361           0 :   MOZ_ASSERT(mChildWorkers.IsEmpty());
    5362           0 :   MOZ_ASSERT(mSyncLoopStack.IsEmpty());
    5363           0 :   MOZ_ASSERT(!mPendingEventQueueClearing);
    5364             : 
    5365           0 :   ClearMainEventQueue(aRanOrNot);
    5366             : #ifdef DEBUG
    5367           0 :   if (WorkerRan == aRanOrNot) {
    5368           0 :     nsIThread* currentThread = NS_GetCurrentThread();
    5369           0 :     MOZ_ASSERT(currentThread);
    5370           0 :     MOZ_ASSERT(!NS_HasPendingEvents(currentThread));
    5371             :   }
    5372             : #endif
    5373             : 
    5374           0 :   if (WorkerPrivate* parent = GetParent()) {
    5375             :     RefPtr<WorkerFinishedRunnable> runnable =
    5376           0 :       new WorkerFinishedRunnable(parent, this);
    5377           0 :     if (!runnable->Dispatch()) {
    5378           0 :       NS_WARNING("Failed to dispatch runnable!");
    5379             :     }
    5380             :   }
    5381             :   else {
    5382             :     RefPtr<TopLevelWorkerFinishedRunnable> runnable =
    5383           0 :       new TopLevelWorkerFinishedRunnable(this);
    5384           0 :     if (NS_FAILED(DispatchToMainThread(runnable.forget()))) {
    5385           0 :       NS_WARNING("Failed to dispatch runnable!");
    5386             :     }
    5387             :   }
    5388           0 : }
    5389             : 
    5390             : bool
    5391           0 : WorkerPrivate::CollectRuntimeStats(JS::RuntimeStats* aRtStats,
    5392             :                                    bool aAnonymize)
    5393             : {
    5394           0 :   AssertIsOnWorkerThread();
    5395           0 :   NS_ASSERTION(aRtStats, "Null RuntimeStats!");
    5396           0 :   NS_ASSERTION(mJSContext, "This must never be null!");
    5397             : 
    5398           0 :   return JS::CollectRuntimeStats(mJSContext, aRtStats, nullptr, aAnonymize);
    5399             : }
    5400             : 
    5401             : void
    5402           1 : WorkerPrivate::EnableMemoryReporter()
    5403             : {
    5404           1 :   AssertIsOnWorkerThread();
    5405           1 :   MOZ_ASSERT(!mMemoryReporter);
    5406             : 
    5407             :   // No need to lock here since the main thread can't race until we've
    5408             :   // successfully registered the reporter.
    5409           1 :   mMemoryReporter = new MemoryReporter(this);
    5410             : 
    5411           1 :   if (NS_FAILED(RegisterWeakAsyncMemoryReporter(mMemoryReporter))) {
    5412           0 :     NS_WARNING("Failed to register memory reporter!");
    5413             :     // No need to lock here since a failed registration means our memory
    5414             :     // reporter can't start running. Just clean up.
    5415           0 :     mMemoryReporter = nullptr;
    5416             :   }
    5417           1 : }
    5418             : 
    5419             : void
    5420           0 : WorkerPrivate::DisableMemoryReporter()
    5421             : {
    5422           0 :   AssertIsOnWorkerThread();
    5423             : 
    5424           0 :   RefPtr<MemoryReporter> memoryReporter;
    5425             :   {
    5426             :     // Mutex protectes MemoryReporter::mWorkerPrivate which is cleared by
    5427             :     // MemoryReporter::Disable() below.
    5428           0 :     MutexAutoLock lock(mMutex);
    5429             : 
    5430             :     // There is nothing to do here if the memory reporter was never successfully
    5431             :     // registered.
    5432           0 :     if (!mMemoryReporter) {
    5433           0 :       return;
    5434             :     }
    5435             : 
    5436             :     // We don't need this set any longer. Swap it out so that we can unregister
    5437             :     // below.
    5438           0 :     mMemoryReporter.swap(memoryReporter);
    5439             : 
    5440             :     // Next disable the memory reporter so that the main thread stops trying to
    5441             :     // signal us.
    5442           0 :     memoryReporter->Disable();
    5443             :   }
    5444             : 
    5445             :   // Finally unregister the memory reporter.
    5446           0 :   if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) {
    5447           0 :     NS_WARNING("Failed to unregister memory reporter!");
    5448             :   }
    5449             : }
    5450             : 
    5451             : void
    5452          24 : WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval)
    5453             : {
    5454          24 :   AssertIsOnWorkerThread();
    5455          24 :   mMutex.AssertCurrentThreadOwns();
    5456             : 
    5457             :   // Wait for a worker event.
    5458          24 :   mCondVar.Wait(aInterval);
    5459          23 : }
    5460             : 
    5461             : WorkerPrivate::ProcessAllControlRunnablesResult
    5462          66 : WorkerPrivate::ProcessAllControlRunnablesLocked()
    5463             : {
    5464          66 :   AssertIsOnWorkerThread();
    5465          66 :   mMutex.AssertCurrentThreadOwns();
    5466             : 
    5467          66 :   auto result = ProcessAllControlRunnablesResult::Nothing;
    5468             : 
    5469             :   for (;;) {
    5470             :     WorkerControlRunnable* event;
    5471          66 :     if (!mControlQueue.Pop(event)) {
    5472          66 :       break;
    5473             :     }
    5474             : 
    5475           0 :     MutexAutoUnlock unlock(mMutex);
    5476             : 
    5477           0 :     MOZ_ASSERT(event);
    5478           0 :     if (NS_FAILED(static_cast<nsIRunnable*>(event)->Run())) {
    5479           0 :       result = ProcessAllControlRunnablesResult::Abort;
    5480             :     }
    5481             : 
    5482           0 :     if (result == ProcessAllControlRunnablesResult::Nothing) {
    5483             :       // We ran at least one thing.
    5484           0 :       result = ProcessAllControlRunnablesResult::MayContinue;
    5485             :     }
    5486           0 :     event->Release();
    5487           0 :   }
    5488             : 
    5489         132 :   return result;
    5490             : }
    5491             : 
    5492             : void
    5493           0 : WorkerPrivate::ClearMainEventQueue(WorkerRanOrNot aRanOrNot)
    5494             : {
    5495           0 :   AssertIsOnWorkerThread();
    5496             : 
    5497           0 :   MOZ_ASSERT(mSyncLoopStack.IsEmpty());
    5498           0 :   MOZ_ASSERT(!mCancelAllPendingRunnables);
    5499           0 :   mCancelAllPendingRunnables = true;
    5500             : 
    5501           0 :   if (WorkerNeverRan == aRanOrNot) {
    5502           0 :     for (uint32_t count = mPreStartRunnables.Length(), index = 0;
    5503           0 :          index < count;
    5504             :          index++) {
    5505           0 :       RefPtr<WorkerRunnable> runnable = mPreStartRunnables[index].forget();
    5506           0 :       static_cast<nsIRunnable*>(runnable.get())->Run();
    5507             :     }
    5508             :   } else {
    5509           0 :     nsIThread* currentThread = NS_GetCurrentThread();
    5510           0 :     MOZ_ASSERT(currentThread);
    5511             : 
    5512           0 :     NS_ProcessPendingEvents(currentThread);
    5513             :   }
    5514             : 
    5515           0 :   MOZ_ASSERT(mCancelAllPendingRunnables);
    5516           0 :   mCancelAllPendingRunnables = false;
    5517           0 : }
    5518             : 
    5519             : void
    5520           0 : WorkerPrivate::ClearDebuggerEventQueue()
    5521             : {
    5522           0 :   while (!mDebuggerQueue.IsEmpty()) {
    5523             :     WorkerRunnable* runnable;
    5524           0 :     mDebuggerQueue.Pop(runnable);
    5525             :     // It should be ok to simply release the runnable, without running it.
    5526           0 :     runnable->Release();
    5527             :   }
    5528           0 : }
    5529             : 
    5530             : bool
    5531           0 : WorkerPrivate::FreezeInternal()
    5532             : {
    5533           0 :   AssertIsOnWorkerThread();
    5534             : 
    5535           0 :   NS_ASSERTION(!mFrozen, "Already frozen!");
    5536             : 
    5537           0 :   mFrozen = true;
    5538             : 
    5539           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    5540           0 :     mChildWorkers[index]->Freeze(nullptr);
    5541             :   }
    5542             : 
    5543           0 :   return true;
    5544             : }
    5545             : 
    5546             : bool
    5547           0 : WorkerPrivate::ThawInternal()
    5548             : {
    5549           0 :   AssertIsOnWorkerThread();
    5550             : 
    5551           0 :   NS_ASSERTION(mFrozen, "Not yet frozen!");
    5552             : 
    5553           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    5554           0 :     mChildWorkers[index]->Thaw(nullptr);
    5555             :   }
    5556             : 
    5557           0 :   mFrozen = false;
    5558           0 :   return true;
    5559             : }
    5560             : 
    5561             : void
    5562           1 : WorkerPrivate::TraverseTimeouts(nsCycleCollectionTraversalCallback& cb)
    5563             : {
    5564           1 :   for (uint32_t i = 0; i < mTimeouts.Length(); ++i) {
    5565           0 :     TimeoutInfo* tmp = mTimeouts[i];
    5566           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHandler)
    5567             :   }
    5568           1 : }
    5569             : 
    5570             : void
    5571           0 : WorkerPrivate::UnlinkTimeouts()
    5572             : {
    5573           0 :   mTimeouts.Clear();
    5574           0 : }
    5575             : 
    5576             : bool
    5577           1 : WorkerPrivate::ModifyBusyCountFromWorker(bool aIncrease)
    5578             : {
    5579           1 :   AssertIsOnWorkerThread();
    5580             : 
    5581             :   {
    5582           2 :     MutexAutoLock lock(mMutex);
    5583             : 
    5584             :     // If we're in shutdown then the busy count is no longer being considered so
    5585             :     // just return now.
    5586           1 :     if (mStatus >= Killing) {
    5587           0 :       return true;
    5588             :     }
    5589             :   }
    5590             : 
    5591             :   RefPtr<ModifyBusyCountRunnable> runnable =
    5592           2 :     new ModifyBusyCountRunnable(this, aIncrease);
    5593           1 :   return runnable->Dispatch();
    5594             : }
    5595             : 
    5596             : bool
    5597           0 : WorkerPrivate::AddChildWorker(ParentType* aChildWorker)
    5598             : {
    5599           0 :   AssertIsOnWorkerThread();
    5600             : 
    5601             : #ifdef DEBUG
    5602             :   {
    5603             :     Status currentStatus;
    5604             :     {
    5605           0 :       MutexAutoLock lock(mMutex);
    5606           0 :       currentStatus = mStatus;
    5607             :     }
    5608             : 
    5609           0 :     MOZ_ASSERT(currentStatus == Running);
    5610             :   }
    5611             : #endif
    5612             : 
    5613           0 :   NS_ASSERTION(!mChildWorkers.Contains(aChildWorker),
    5614             :                "Already know about this one!");
    5615           0 :   mChildWorkers.AppendElement(aChildWorker);
    5616             : 
    5617           0 :   return mChildWorkers.Length() == 1 ?
    5618             :          ModifyBusyCountFromWorker(true) :
    5619           0 :          true;
    5620             : }
    5621             : 
    5622             : void
    5623           0 : WorkerPrivate::RemoveChildWorker(ParentType* aChildWorker)
    5624             : {
    5625           0 :   AssertIsOnWorkerThread();
    5626             : 
    5627           0 :   NS_ASSERTION(mChildWorkers.Contains(aChildWorker),
    5628             :                "Didn't know about this one!");
    5629           0 :   mChildWorkers.RemoveElement(aChildWorker);
    5630             : 
    5631           0 :   if (mChildWorkers.IsEmpty() && !ModifyBusyCountFromWorker(false)) {
    5632           0 :     NS_WARNING("Failed to modify busy count!");
    5633             :   }
    5634           0 : }
    5635             : 
    5636             : bool
    5637           7 : WorkerPrivate::AddHolder(WorkerHolder* aHolder, Status aFailStatus)
    5638             : {
    5639           7 :   AssertIsOnWorkerThread();
    5640             : 
    5641             :   {
    5642          14 :     MutexAutoLock lock(mMutex);
    5643             : 
    5644           7 :     if (mStatus >= aFailStatus) {
    5645           0 :       return false;
    5646             :     }
    5647             :   }
    5648             : 
    5649           7 :   MOZ_ASSERT(!mHolders.Contains(aHolder), "Already know about this one!");
    5650             : 
    5651           7 :   if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) {
    5652           7 :     if (!mNumHoldersPreventingShutdownStart && !ModifyBusyCountFromWorker(true)) {
    5653           0 :       return false;
    5654             :     }
    5655           7 :     mNumHoldersPreventingShutdownStart += 1;
    5656             :   }
    5657             : 
    5658           7 :   mHolders.AppendElement(aHolder);
    5659           7 :   return true;
    5660             : }
    5661             : 
    5662             : void
    5663           4 : WorkerPrivate::RemoveHolder(WorkerHolder* aHolder)
    5664             : {
    5665           4 :   AssertIsOnWorkerThread();
    5666             : 
    5667           4 :   MOZ_ASSERT(mHolders.Contains(aHolder), "Didn't know about this one!");
    5668           4 :   mHolders.RemoveElement(aHolder);
    5669             : 
    5670           4 :   if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) {
    5671           4 :     mNumHoldersPreventingShutdownStart -= 1;
    5672           4 :     if (!mNumHoldersPreventingShutdownStart && !ModifyBusyCountFromWorker(false)) {
    5673           0 :       NS_WARNING("Failed to modify busy count!");
    5674             :     }
    5675             :   }
    5676           4 : }
    5677             : 
    5678             : void
    5679           0 : WorkerPrivate::NotifyHolders(JSContext* aCx, Status aStatus)
    5680             : {
    5681           0 :   AssertIsOnWorkerThread();
    5682           0 :   MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    5683             : 
    5684           0 :   NS_ASSERTION(aStatus > Running, "Bad status!");
    5685             : 
    5686           0 :   if (aStatus >= Closing) {
    5687           0 :     CancelAllTimeouts();
    5688             :   }
    5689             : 
    5690           0 :   nsTObserverArray<WorkerHolder*>::ForwardIterator iter(mHolders);
    5691           0 :   while (iter.HasMore()) {
    5692           0 :     WorkerHolder* holder = iter.GetNext();
    5693           0 :     if (!holder->Notify(aStatus)) {
    5694           0 :       NS_WARNING("Failed to notify holder!");
    5695             :     }
    5696           0 :     MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    5697             :   }
    5698             : 
    5699           0 :   AutoTArray<ParentType*, 10> children;
    5700           0 :   children.AppendElements(mChildWorkers);
    5701             : 
    5702           0 :   for (uint32_t index = 0; index < children.Length(); index++) {
    5703           0 :     if (!children[index]->Notify(aStatus)) {
    5704           0 :       NS_WARNING("Failed to notify child worker!");
    5705             :     }
    5706             :   }
    5707           0 : }
    5708             : 
    5709             : void
    5710           0 : WorkerPrivate::CancelAllTimeouts()
    5711             : {
    5712           0 :   AssertIsOnWorkerThread();
    5713             : 
    5714           0 :   LOG(TimeoutsLog(), ("Worker %p CancelAllTimeouts.\n", this));
    5715             : 
    5716           0 :   if (mTimerRunning) {
    5717           0 :     NS_ASSERTION(mTimer && mTimerRunnable, "Huh?!");
    5718           0 :     NS_ASSERTION(!mTimeouts.IsEmpty(), "Huh?!");
    5719             : 
    5720           0 :     if (NS_FAILED(mTimer->Cancel())) {
    5721           0 :       NS_WARNING("Failed to cancel timer!");
    5722             :     }
    5723             : 
    5724           0 :     for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
    5725           0 :       mTimeouts[index]->mCanceled = true;
    5726             :     }
    5727             : 
    5728             :     // If mRunningExpiredTimeouts, then the fact that they are all canceled now
    5729             :     // means that the currently executing RunExpiredTimeouts will deal with
    5730             :     // them.  Otherwise, we need to clean them up ourselves.
    5731           0 :     if (!mRunningExpiredTimeouts) {
    5732           0 :       mTimeouts.Clear();
    5733           0 :       ModifyBusyCountFromWorker(false);
    5734             :     }
    5735             : 
    5736             :     // Set mTimerRunning false even if mRunningExpiredTimeouts is true, so that
    5737             :     // if we get reentered under this same RunExpiredTimeouts call we don't
    5738             :     // assert above that !mTimeouts().IsEmpty(), because that's clearly false
    5739             :     // now.
    5740           0 :     mTimerRunning = false;
    5741             :   }
    5742             : #ifdef DEBUG
    5743           0 :   else if (!mRunningExpiredTimeouts) {
    5744           0 :     NS_ASSERTION(mTimeouts.IsEmpty(), "Huh?!");
    5745             :   }
    5746             : #endif
    5747             : 
    5748           0 :   mTimer = nullptr;
    5749           0 :   mTimerRunnable = nullptr;
    5750           0 : }
    5751             : 
    5752             : already_AddRefed<nsIEventTarget>
    5753          17 : WorkerPrivate::CreateNewSyncLoop(Status aFailStatus)
    5754             : {
    5755          17 :   AssertIsOnWorkerThread();
    5756             : 
    5757             :   {
    5758          34 :     MutexAutoLock lock(mMutex);
    5759             : 
    5760          17 :     if (mStatus >= aFailStatus) {
    5761           0 :       return nullptr;
    5762             :     }
    5763             :   }
    5764             : 
    5765          34 :   nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
    5766          17 :   MOZ_ASSERT(thread);
    5767             : 
    5768          34 :   nsCOMPtr<nsIEventTarget> realEventTarget;
    5769          17 :   MOZ_ALWAYS_SUCCEEDS(thread->PushEventQueue(getter_AddRefs(realEventTarget)));
    5770             : 
    5771             :   RefPtr<EventTarget> workerEventTarget =
    5772          51 :     new EventTarget(this, realEventTarget);
    5773             : 
    5774             :   {
    5775             :     // Modifications must be protected by mMutex in DEBUG builds, see comment
    5776             :     // about mSyncLoopStack in WorkerPrivate.h.
    5777             : #ifdef DEBUG
    5778          34 :     MutexAutoLock lock(mMutex);
    5779             : #endif
    5780             : 
    5781          34 :     mSyncLoopStack.AppendElement(new SyncLoopInfo(workerEventTarget));
    5782             :   }
    5783             : 
    5784          17 :   return workerEventTarget.forget();
    5785             : }
    5786             : 
    5787             : bool
    5788          17 : WorkerPrivate::RunCurrentSyncLoop()
    5789             : {
    5790          17 :   AssertIsOnWorkerThread();
    5791             : 
    5792          17 :   JSContext* cx = GetJSContext();
    5793          17 :   MOZ_ASSERT(cx);
    5794             : 
    5795             :   // This should not change between now and the time we finish running this sync
    5796             :   // loop.
    5797          17 :   uint32_t currentLoopIndex = mSyncLoopStack.Length() - 1;
    5798             : 
    5799          17 :   SyncLoopInfo* loopInfo = mSyncLoopStack[currentLoopIndex];
    5800             : 
    5801          17 :   MOZ_ASSERT(loopInfo);
    5802          17 :   MOZ_ASSERT(!loopInfo->mHasRun);
    5803          17 :   MOZ_ASSERT(!loopInfo->mCompleted);
    5804             : 
    5805             : #ifdef DEBUG
    5806          17 :   loopInfo->mHasRun = true;
    5807             : #endif
    5808             : 
    5809          79 :   while (!loopInfo->mCompleted) {
    5810          35 :     bool normalRunnablesPending = false;
    5811             : 
    5812             :     // Don't block with the periodic GC timer running.
    5813          35 :     if (!NS_HasPendingEvents(mThread)) {
    5814          26 :       SetGCTimerMode(IdleTimer);
    5815             :     }
    5816             : 
    5817             :     // Wait for something to do.
    5818             :     {
    5819          69 :       MutexAutoLock lock(mMutex);
    5820             : 
    5821             :       for (;;) {
    5822         197 :         while (mControlQueue.IsEmpty() &&
    5823         174 :                !normalRunnablesPending &&
    5824         116 :                !(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
    5825          24 :           WaitForWorkerEvents();
    5826             :         }
    5827             : 
    5828          34 :         auto result = ProcessAllControlRunnablesLocked();
    5829          34 :         if (result != ProcessAllControlRunnablesResult::Nothing) {
    5830             :           // XXXkhuey how should we handle Abort here? See Bug 1003730.
    5831             : 
    5832             :           // The state of the world may have changed. Recheck it.
    5833           0 :           normalRunnablesPending = NS_HasPendingEvents(mThread);
    5834             : 
    5835             :           // NB: If we processed a NotifyRunnable, we might have run
    5836             :           // non-control runnables, one of which may have shut down the
    5837             :           // sync loop.
    5838           0 :           if (loopInfo->mCompleted) {
    5839           0 :             break;
    5840             :           }
    5841             :         }
    5842             : 
    5843             :         // If we *didn't* run any control runnables, this should be unchanged.
    5844          34 :         MOZ_ASSERT(!loopInfo->mCompleted);
    5845             : 
    5846          34 :         if (normalRunnablesPending) {
    5847          34 :           break;
    5848             :         }
    5849           0 :       }
    5850             :     }
    5851             : 
    5852          34 :     if (normalRunnablesPending) {
    5853             :       // Make sure the periodic timer is running before we continue.
    5854          34 :       SetGCTimerMode(PeriodicTimer);
    5855             : 
    5856          34 :       MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(mThread, false));
    5857             : 
    5858             :       // Now *might* be a good time to GC. Let the JS engine make the decision.
    5859          31 :       if (JS::CurrentGlobalOrNull(cx)) {
    5860          31 :         JS_MaybeGC(cx);
    5861             :       }
    5862             :     }
    5863             :   }
    5864             : 
    5865             :   // Make sure that the stack didn't change underneath us.
    5866          13 :   MOZ_ASSERT(mSyncLoopStack[currentLoopIndex] == loopInfo);
    5867             : 
    5868          13 :   return DestroySyncLoop(currentLoopIndex);
    5869             : }
    5870             : 
    5871             : bool
    5872          13 : WorkerPrivate::DestroySyncLoop(uint32_t aLoopIndex, nsIThreadInternal* aThread)
    5873             : {
    5874          13 :   MOZ_ASSERT(!mSyncLoopStack.IsEmpty());
    5875          13 :   MOZ_ASSERT(mSyncLoopStack.Length() - 1 == aLoopIndex);
    5876             : 
    5877          13 :   if (!aThread) {
    5878          13 :     aThread = mThread;
    5879             :   }
    5880             : 
    5881             :   // We're about to delete the loop, stash its event target and result.
    5882          13 :   SyncLoopInfo* loopInfo = mSyncLoopStack[aLoopIndex];
    5883             :   nsIEventTarget* nestedEventTarget =
    5884          13 :     loopInfo->mEventTarget->GetWeakNestedEventTarget();
    5885          13 :   MOZ_ASSERT(nestedEventTarget);
    5886             : 
    5887          13 :   bool result = loopInfo->mResult;
    5888             : 
    5889             :   {
    5890             :     // Modifications must be protected by mMutex in DEBUG builds, see comment
    5891             :     // about mSyncLoopStack in WorkerPrivate.h.
    5892             : #ifdef DEBUG
    5893          26 :     MutexAutoLock lock(mMutex);
    5894             : #endif
    5895             : 
    5896             :     // This will delete |loopInfo|!
    5897          13 :     mSyncLoopStack.RemoveElementAt(aLoopIndex);
    5898             :   }
    5899             : 
    5900          13 :   MOZ_ALWAYS_SUCCEEDS(aThread->PopEventQueue(nestedEventTarget));
    5901             : 
    5902          13 :   if (mSyncLoopStack.IsEmpty() && mPendingEventQueueClearing) {
    5903           0 :     mPendingEventQueueClearing = false;
    5904           0 :     ClearMainEventQueue(WorkerRan);
    5905             :   }
    5906             : 
    5907          13 :   return result;
    5908             : }
    5909             : 
    5910             : void
    5911          13 : WorkerPrivate::StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult)
    5912             : {
    5913          13 :   AssertIsOnWorkerThread();
    5914          13 :   AssertValidSyncLoop(aSyncLoopTarget);
    5915             : 
    5916          13 :   MOZ_ASSERT(!mSyncLoopStack.IsEmpty());
    5917             : 
    5918          13 :   for (uint32_t index = mSyncLoopStack.Length(); index > 0; index--) {
    5919          13 :     nsAutoPtr<SyncLoopInfo>& loopInfo = mSyncLoopStack[index - 1];
    5920          13 :     MOZ_ASSERT(loopInfo);
    5921          13 :     MOZ_ASSERT(loopInfo->mEventTarget);
    5922             : 
    5923          13 :     if (loopInfo->mEventTarget == aSyncLoopTarget) {
    5924             :       // Can't assert |loop->mHasRun| here because dispatch failures can cause
    5925             :       // us to bail out early.
    5926          13 :       MOZ_ASSERT(!loopInfo->mCompleted);
    5927             : 
    5928          13 :       loopInfo->mResult = aResult;
    5929          13 :       loopInfo->mCompleted = true;
    5930             : 
    5931          13 :       loopInfo->mEventTarget->Disable();
    5932             : 
    5933          13 :       return;
    5934             :     }
    5935             : 
    5936           0 :     MOZ_ASSERT(!SameCOMIdentity(loopInfo->mEventTarget, aSyncLoopTarget));
    5937             :   }
    5938             : 
    5939           0 :   MOZ_CRASH("Unknown sync loop!");
    5940             : }
    5941             : 
    5942             : #ifdef DEBUG
    5943             : void
    5944          58 : WorkerPrivate::AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
    5945             : {
    5946          58 :   MOZ_ASSERT(aSyncLoopTarget);
    5947             : 
    5948             :   EventTarget* workerTarget;
    5949             :   nsresult rv =
    5950         116 :     aSyncLoopTarget->QueryInterface(kDEBUGWorkerEventTargetIID,
    5951         116 :                                     reinterpret_cast<void**>(&workerTarget));
    5952          58 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
    5953          58 :   MOZ_ASSERT(workerTarget);
    5954             : 
    5955          58 :   bool valid = false;
    5956             : 
    5957             :   {
    5958         116 :     MutexAutoLock lock(mMutex);
    5959             : 
    5960         219 :     for (uint32_t index = 0; index < mSyncLoopStack.Length(); index++) {
    5961         219 :       nsAutoPtr<SyncLoopInfo>& loopInfo = mSyncLoopStack[index];
    5962         219 :       MOZ_ASSERT(loopInfo);
    5963         219 :       MOZ_ASSERT(loopInfo->mEventTarget);
    5964             : 
    5965         219 :       if (loopInfo->mEventTarget == aSyncLoopTarget) {
    5966          58 :         valid = true;
    5967          58 :         break;
    5968             :       }
    5969             : 
    5970         161 :       MOZ_ASSERT(!SameCOMIdentity(loopInfo->mEventTarget, aSyncLoopTarget));
    5971             :     }
    5972             :   }
    5973             : 
    5974          58 :   MOZ_ASSERT(valid);
    5975          58 : }
    5976             : #endif
    5977             : 
    5978             : void
    5979           0 : WorkerPrivate::PostMessageToParentInternal(
    5980             :                             JSContext* aCx,
    5981             :                             JS::Handle<JS::Value> aMessage,
    5982             :                             const Sequence<JSObject*>& aTransferable,
    5983             :                             ErrorResult& aRv)
    5984             : {
    5985           0 :   AssertIsOnWorkerThread();
    5986             : 
    5987           0 :   JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
    5988             : 
    5989           0 :   aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
    5990           0 :                                                           &transferable);
    5991           0 :   if (NS_WARN_IF(aRv.Failed())) {
    5992           0 :     return;
    5993             :   }
    5994             : 
    5995             :   RefPtr<MessageEventRunnable> runnable =
    5996             :     new MessageEventRunnable(this,
    5997           0 :                              WorkerRunnable::ParentThreadUnchangedBusyCount);
    5998             : 
    5999           0 :   UniquePtr<AbstractTimelineMarker> start;
    6000           0 :   UniquePtr<AbstractTimelineMarker> end;
    6001           0 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    6002           0 :   bool isTimelineRecording = timelines && !timelines->IsEmpty();
    6003             : 
    6004           0 :   if (isTimelineRecording) {
    6005           0 :     start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
    6006           0 :       ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
    6007             :       : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
    6008           0 :       MarkerTracingType::START);
    6009             :   }
    6010             : 
    6011           0 :   runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv);
    6012             : 
    6013           0 :   if (isTimelineRecording) {
    6014           0 :     end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
    6015           0 :       ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
    6016             :       : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
    6017           0 :       MarkerTracingType::END);
    6018           0 :     timelines->AddMarkerForAllObservedDocShells(start);
    6019           0 :     timelines->AddMarkerForAllObservedDocShells(end);
    6020             :   }
    6021             : 
    6022           0 :   if (NS_WARN_IF(aRv.Failed())) {
    6023           0 :     return;
    6024             :   }
    6025             : 
    6026           0 :   if (!runnable->Dispatch()) {
    6027           0 :     aRv = NS_ERROR_FAILURE;
    6028             :   }
    6029             : }
    6030             : 
    6031             : void
    6032           0 : WorkerPrivate::EnterDebuggerEventLoop()
    6033             : {
    6034           0 :   AssertIsOnWorkerThread();
    6035             : 
    6036           0 :   JSContext* cx = GetJSContext();
    6037           0 :   MOZ_ASSERT(cx);
    6038             : 
    6039           0 :   uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
    6040             : 
    6041           0 :   while (currentEventLoopLevel <= mDebuggerEventLoopLevel) {
    6042           0 :     bool debuggerRunnablesPending = false;
    6043             : 
    6044             :     {
    6045           0 :       MutexAutoLock lock(mMutex);
    6046             : 
    6047           0 :       debuggerRunnablesPending = !mDebuggerQueue.IsEmpty();
    6048             :     }
    6049             : 
    6050             :     // Don't block with the periodic GC timer running.
    6051           0 :     if (!debuggerRunnablesPending) {
    6052           0 :       SetGCTimerMode(IdleTimer);
    6053             :     }
    6054             : 
    6055             :     // Wait for something to do
    6056             :     {
    6057           0 :       MutexAutoLock lock(mMutex);
    6058             : 
    6059           0 :       while (mControlQueue.IsEmpty() &&
    6060           0 :              !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty())) {
    6061           0 :         WaitForWorkerEvents();
    6062             :       }
    6063             : 
    6064           0 :       ProcessAllControlRunnablesLocked();
    6065             : 
    6066             :       // XXXkhuey should we abort JS on the stack here if we got Abort above?
    6067             :     }
    6068             : 
    6069           0 :     if (debuggerRunnablesPending) {
    6070             :       // Start the periodic GC timer if it is not already running.
    6071           0 :       SetGCTimerMode(PeriodicTimer);
    6072             : 
    6073             :       WorkerRunnable* runnable;
    6074             : 
    6075             :       {
    6076           0 :         MutexAutoLock lock(mMutex);
    6077             : 
    6078           0 :         mDebuggerQueue.Pop(runnable);
    6079             :       }
    6080             : 
    6081           0 :       MOZ_ASSERT(runnable);
    6082           0 :       static_cast<nsIRunnable*>(runnable)->Run();
    6083           0 :       runnable->Release();
    6084             : 
    6085             :       // Flush the promise queue.
    6086           0 :       Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
    6087             : 
    6088             :       // Now *might* be a good time to GC. Let the JS engine make the decision.
    6089           0 :       if (JS::CurrentGlobalOrNull(cx)) {
    6090           0 :         JS_MaybeGC(cx);
    6091             :       }
    6092             :     }
    6093             :   }
    6094           0 : }
    6095             : 
    6096             : void
    6097           0 : WorkerPrivate::LeaveDebuggerEventLoop()
    6098             : {
    6099           0 :   AssertIsOnWorkerThread();
    6100             : 
    6101           0 :   MutexAutoLock lock(mMutex);
    6102             : 
    6103           0 :   if (mDebuggerEventLoopLevel > 0) {
    6104           0 :     --mDebuggerEventLoopLevel;
    6105             :   }
    6106           0 : }
    6107             : 
    6108             : void
    6109           0 : WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage)
    6110             : {
    6111           0 :   mDebugger->PostMessageToDebugger(aMessage);
    6112           0 : }
    6113             : 
    6114             : void
    6115           0 : WorkerPrivate::SetDebuggerImmediate(dom::Function& aHandler, ErrorResult& aRv)
    6116             : {
    6117           0 :   AssertIsOnWorkerThread();
    6118             : 
    6119             :   RefPtr<DebuggerImmediateRunnable> runnable =
    6120           0 :     new DebuggerImmediateRunnable(this, aHandler);
    6121           0 :   if (!runnable->Dispatch()) {
    6122           0 :     aRv.Throw(NS_ERROR_FAILURE);
    6123             :   }
    6124           0 : }
    6125             : 
    6126             : void
    6127           0 : WorkerPrivate::ReportErrorToDebugger(const nsAString& aFilename,
    6128             :                                      uint32_t aLineno,
    6129             :                                      const nsAString& aMessage)
    6130             : {
    6131           0 :   mDebugger->ReportErrorToDebugger(aFilename, aLineno, aMessage);
    6132           0 : }
    6133             : 
    6134             : bool
    6135           0 : WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
    6136             : {
    6137           0 :   AssertIsOnWorkerThread();
    6138             : 
    6139           0 :   NS_ASSERTION(aStatus > Running && aStatus < Dead, "Bad status!");
    6140             : 
    6141           0 :   RefPtr<EventTarget> eventTarget;
    6142             : 
    6143             :   // Save the old status and set the new status.
    6144             :   Status previousStatus;
    6145             :   {
    6146           0 :     MutexAutoLock lock(mMutex);
    6147             : 
    6148           0 :     if (mStatus >= aStatus) {
    6149           0 :       return true;
    6150             :     }
    6151             : 
    6152           0 :     previousStatus = mStatus;
    6153           0 :     mStatus = aStatus;
    6154             : 
    6155             :     // Mark parent status as closing immediately to avoid new events being
    6156             :     // dispatched after we clear the queue below.
    6157           0 :     if (aStatus == Closing) {
    6158           0 :       Close();
    6159             :     }
    6160             : 
    6161           0 :     eventTarget = mEventTarget;
    6162             :   }
    6163             : 
    6164             :   // Disable the event target, if it exists.
    6165           0 :   if (eventTarget) {
    6166             :     // Since we'll no longer process events, make sure we no longer allow anyone
    6167             :     // to post them. We have to do this without mMutex held, since our mutex
    6168             :     // must be acquired *after* the WorkerEventTarget's mutex when they're both
    6169             :     // held.
    6170           0 :     eventTarget->Disable();
    6171             :   }
    6172             : 
    6173           0 :   if (mCrossThreadDispatcher) {
    6174             :     // Since we'll no longer process events, make sure we no longer allow
    6175             :     // anyone to post them. We have to do this without mMutex held, since our
    6176             :     // mutex must be acquired *after* mCrossThreadDispatcher's mutex when
    6177             :     // they're both held.
    6178           0 :     mCrossThreadDispatcher->Forget();
    6179           0 :     mCrossThreadDispatcher = nullptr;
    6180             :   }
    6181             : 
    6182           0 :   MOZ_ASSERT(previousStatus != Pending);
    6183             : 
    6184             :   // Let all our holders know the new status.
    6185           0 :   NotifyHolders(aCx, aStatus);
    6186           0 :   MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    6187             : 
    6188             :   // If this is the first time our status has changed then we need to clear the
    6189             :   // main event queue.
    6190           0 :   if (previousStatus == Running) {
    6191             :     // NB: If we're in a sync loop, we can't clear the queue immediately,
    6192             :     // because this is the wrong queue. So we have to defer it until later.
    6193           0 :     if (!mSyncLoopStack.IsEmpty()) {
    6194           0 :       mPendingEventQueueClearing = true;
    6195             :     } else {
    6196           0 :       ClearMainEventQueue(WorkerRan);
    6197             :     }
    6198             :   }
    6199             : 
    6200             :   // If the worker script never ran, or failed to compile, we don't need to do
    6201             :   // anything else.
    6202           0 :   if (!GlobalScope()) {
    6203           0 :     return true;
    6204             :   }
    6205             : 
    6206             :   // Don't abort the script.
    6207           0 :   if (aStatus == Closing) {
    6208           0 :     return true;
    6209             :   }
    6210             : 
    6211           0 :   MOZ_ASSERT(aStatus == Terminating ||
    6212             :              aStatus == Canceling ||
    6213             :              aStatus == Killing);
    6214             : 
    6215             :   // Always abort the script.
    6216           0 :   return false;
    6217             : }
    6218             : 
    6219             : void
    6220           0 : WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport)
    6221             : {
    6222           0 :   mFilename = NS_ConvertUTF8toUTF16(aReport->filename);
    6223           0 :   mLineNumber = aReport->lineno;
    6224           0 :   mColumnNumber = aReport->column;
    6225           0 :   mErrorNumber = aReport->errorNumber;
    6226           0 : }
    6227             : 
    6228             : void
    6229           0 : WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote)
    6230             : {
    6231           0 :   WorkerErrorBase::AssignErrorBase(aNote);
    6232           0 :   xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage);
    6233           0 : }
    6234             : 
    6235             : void
    6236           0 : WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport)
    6237             : {
    6238           0 :   WorkerErrorBase::AssignErrorBase(aReport);
    6239           0 :   xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage);
    6240             : 
    6241           0 :   mLine.Assign(aReport->linebuf(), aReport->linebufLength());
    6242           0 :   mFlags = aReport->flags;
    6243           0 :   MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT);
    6244           0 :   mExnType = JSExnType(aReport->exnType);
    6245           0 :   mMutedError = aReport->isMuted;
    6246             : 
    6247           0 :   if (aReport->notes) {
    6248           0 :     if (!mNotes.SetLength(aReport->notes->length(), fallible)) {
    6249           0 :       return;
    6250             :     }
    6251             : 
    6252           0 :     size_t i = 0;
    6253           0 :     for (auto&& note : *aReport->notes) {
    6254           0 :       mNotes.ElementAt(i).AssignErrorNote(note.get());
    6255           0 :       i++;
    6256             :     }
    6257             :   }
    6258             : }
    6259             : 
    6260             : void
    6261           0 : WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
    6262             :                            JSErrorReport* aReport)
    6263             : {
    6264           0 :   AssertIsOnWorkerThread();
    6265             : 
    6266           0 :   if (!MayContinueRunning() || mErrorHandlerRecursionCount == 2) {
    6267           0 :     return;
    6268             :   }
    6269             : 
    6270           0 :   NS_ASSERTION(mErrorHandlerRecursionCount == 0 ||
    6271             :                mErrorHandlerRecursionCount == 1,
    6272             :                "Bad recursion logic!");
    6273             : 
    6274           0 :   JS::Rooted<JS::Value> exn(aCx);
    6275           0 :   if (!JS_GetPendingException(aCx, &exn)) {
    6276             :     // Probably shouldn't actually happen?  But let's go ahead and just use null
    6277             :     // for lack of anything better.
    6278           0 :     exn.setNull();
    6279             :   }
    6280           0 :   JS_ClearPendingException(aCx);
    6281             : 
    6282           0 :   WorkerErrorReport report;
    6283           0 :   if (aReport) {
    6284           0 :     report.AssignErrorReport(aReport);
    6285             :   }
    6286             :   else {
    6287           0 :     report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
    6288             :   }
    6289             : 
    6290           0 :   if (report.mMessage.IsEmpty() && aToStringResult) {
    6291           0 :     nsDependentCString toStringResult(aToStringResult.c_str());
    6292           0 :     if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) {
    6293             :       // Try again, with only a 1 KB string. Do this infallibly this time.
    6294             :       // If the user doesn't have 1 KB to spare we're done anyways.
    6295           0 :       uint32_t index = std::min(uint32_t(1024), toStringResult.Length());
    6296             : 
    6297             :       // Drop the last code point that may be cropped.
    6298           0 :       index = RewindToPriorUTF8Codepoint(toStringResult.BeginReading(), index);
    6299             : 
    6300             :       nsDependentCString truncatedToStringResult(aToStringResult.c_str(),
    6301           0 :                                                  index);
    6302           0 :       AppendUTF8toUTF16(truncatedToStringResult, report.mMessage);
    6303             :     }
    6304             :   }
    6305             : 
    6306           0 :   mErrorHandlerRecursionCount++;
    6307             : 
    6308             :   // Don't want to run the scope's error handler if this is a recursive error or
    6309             :   // if we ran out of memory.
    6310           0 :   bool fireAtScope = mErrorHandlerRecursionCount == 1 &&
    6311           0 :                      report.mErrorNumber != JSMSG_OUT_OF_MEMORY &&
    6312           0 :                      JS::CurrentGlobalOrNull(aCx);
    6313             : 
    6314           0 :   ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0,
    6315           0 :                                    exn);
    6316             : 
    6317           0 :   mErrorHandlerRecursionCount--;
    6318             : }
    6319             : 
    6320             : // static
    6321             : void
    6322           0 : WorkerPrivate::ReportErrorToConsole(const char* aMessage)
    6323             : {
    6324           0 :   WorkerPrivate* wp = nullptr;
    6325           0 :   if (!NS_IsMainThread()) {
    6326           0 :     wp = GetCurrentThreadWorkerPrivate();
    6327             :   }
    6328             : 
    6329           0 :   ReportErrorToConsoleRunnable::Report(wp, aMessage);
    6330           0 : }
    6331             : 
    6332             : int32_t
    6333           0 : WorkerPrivate::SetTimeout(JSContext* aCx,
    6334             :                           nsIScriptTimeoutHandler* aHandler,
    6335             :                           int32_t aTimeout, bool aIsInterval,
    6336             :                           ErrorResult& aRv)
    6337             : {
    6338           0 :   AssertIsOnWorkerThread();
    6339           0 :   MOZ_ASSERT(aHandler);
    6340             : 
    6341           0 :   const int32_t timerId = mNextTimeoutId++;
    6342             : 
    6343             :   Status currentStatus;
    6344             :   {
    6345           0 :     MutexAutoLock lock(mMutex);
    6346           0 :     currentStatus = mStatus;
    6347             :   }
    6348             : 
    6349             :   // If the worker is trying to call setTimeout/setInterval and the parent
    6350             :   // thread has initiated the close process then just silently fail.
    6351           0 :   if (currentStatus >= Closing) {
    6352           0 :     aRv.Throw(NS_ERROR_FAILURE);
    6353           0 :     return 0;
    6354             :   }
    6355             : 
    6356           0 :   nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
    6357           0 :   newInfo->mIsInterval = aIsInterval;
    6358           0 :   newInfo->mId = timerId;
    6359             : 
    6360           0 :   if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
    6361           0 :     NS_WARNING("Timeout ids overflowed!");
    6362           0 :     mNextTimeoutId = 1;
    6363             :   }
    6364             : 
    6365           0 :   newInfo->mHandler = aHandler;
    6366             : 
    6367             :   // See if any of the optional arguments were passed.
    6368           0 :   aTimeout = std::max(0, aTimeout);
    6369           0 :   newInfo->mInterval = TimeDuration::FromMilliseconds(aTimeout);
    6370             : 
    6371           0 :   newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
    6372             : 
    6373             :   nsAutoPtr<TimeoutInfo>* insertedInfo =
    6374           0 :     mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
    6375             : 
    6376           0 :   LOG(TimeoutsLog(), ("Worker %p has new timeout: delay=%d interval=%s\n",
    6377             :                       this, aTimeout, aIsInterval ? "yes" : "no"));
    6378             : 
    6379             :   // If the timeout we just made is set to fire next then we need to update the
    6380             :   // timer, unless we're currently running timeouts.
    6381           0 :   if (insertedInfo == mTimeouts.Elements() && !mRunningExpiredTimeouts) {
    6382             :     nsresult rv;
    6383             : 
    6384           0 :     if (!mTimer) {
    6385           0 :       mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
    6386           0 :       if (NS_FAILED(rv)) {
    6387           0 :         aRv.Throw(rv);
    6388           0 :         return 0;
    6389             :       }
    6390             : 
    6391           0 :       mTimerRunnable = new TimerRunnable(this);
    6392             :     }
    6393             : 
    6394           0 :     if (!mTimerRunning) {
    6395           0 :       if (!ModifyBusyCountFromWorker(true)) {
    6396           0 :         aRv.Throw(NS_ERROR_FAILURE);
    6397           0 :         return 0;
    6398             :       }
    6399           0 :       mTimerRunning = true;
    6400             :     }
    6401             : 
    6402           0 :     if (!RescheduleTimeoutTimer(aCx)) {
    6403           0 :       aRv.Throw(NS_ERROR_FAILURE);
    6404           0 :       return 0;
    6405             :     }
    6406             :   }
    6407             : 
    6408           0 :   return timerId;
    6409             : }
    6410             : 
    6411             : void
    6412           0 : WorkerPrivate::ClearTimeout(int32_t aId)
    6413             : {
    6414           0 :   AssertIsOnWorkerThread();
    6415             : 
    6416           0 :   if (!mTimeouts.IsEmpty()) {
    6417           0 :     NS_ASSERTION(mTimerRunning, "Huh?!");
    6418             : 
    6419           0 :     for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
    6420           0 :       nsAutoPtr<TimeoutInfo>& info = mTimeouts[index];
    6421           0 :       if (info->mId == aId) {
    6422           0 :         info->mCanceled = true;
    6423           0 :         break;
    6424             :       }
    6425             :     }
    6426             :   }
    6427           0 : }
    6428             : 
    6429             : bool
    6430           0 : WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
    6431             : {
    6432           0 :   AssertIsOnWorkerThread();
    6433             : 
    6434             :   // We may be called recursively (e.g. close() inside a timeout) or we could
    6435             :   // have been canceled while this event was pending, bail out if there is
    6436             :   // nothing to do.
    6437           0 :   if (mRunningExpiredTimeouts || !mTimerRunning) {
    6438           0 :     return true;
    6439             :   }
    6440             : 
    6441           0 :   NS_ASSERTION(mTimer && mTimerRunnable, "Must have a timer!");
    6442           0 :   NS_ASSERTION(!mTimeouts.IsEmpty(), "Should have some work to do!");
    6443             : 
    6444           0 :   bool retval = true;
    6445             : 
    6446           0 :   AutoPtrComparator<TimeoutInfo> comparator = GetAutoPtrComparator(mTimeouts);
    6447           0 :   JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
    6448             : 
    6449             :   // We want to make sure to run *something*, even if the timer fired a little
    6450             :   // early. Fudge the value of now to at least include the first timeout.
    6451           0 :   const TimeStamp actual_now = TimeStamp::Now();
    6452           0 :   const TimeStamp now = std::max(actual_now, mTimeouts[0]->mTargetTime);
    6453             : 
    6454           0 :   if (now != actual_now) {
    6455           0 :     LOG(TimeoutsLog(), ("Worker %p fudged timeout by %f ms.\n", this,
    6456             :                         (now - actual_now).ToMilliseconds()));
    6457             :   }
    6458             : 
    6459           0 :   AutoTArray<TimeoutInfo*, 10> expiredTimeouts;
    6460           0 :   for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
    6461           0 :     nsAutoPtr<TimeoutInfo>& info = mTimeouts[index];
    6462           0 :     if (info->mTargetTime > now) {
    6463           0 :       break;
    6464             :     }
    6465           0 :     expiredTimeouts.AppendElement(info);
    6466             :   }
    6467             : 
    6468             :   // Guard against recursion.
    6469           0 :   mRunningExpiredTimeouts = true;
    6470             : 
    6471             :   // Run expired timeouts.
    6472           0 :   for (uint32_t index = 0; index < expiredTimeouts.Length(); index++) {
    6473           0 :     TimeoutInfo*& info = expiredTimeouts[index];
    6474             : 
    6475           0 :     if (info->mCanceled) {
    6476           0 :       continue;
    6477             :     }
    6478             : 
    6479           0 :     LOG(TimeoutsLog(), ("Worker %p executing timeout with original delay %f ms.\n",
    6480             :                         this, info->mInterval.ToMilliseconds()));
    6481             : 
    6482             :     // Always check JS_IsExceptionPending if something fails, and if
    6483             :     // JS_IsExceptionPending returns false (i.e. uncatchable exception) then
    6484             :     // break out of the loop.
    6485             :     const char *reason;
    6486           0 :     if (info->mIsInterval) {
    6487           0 :       reason = "setInterval handler";
    6488             :     } else {
    6489           0 :       reason = "setTimeout handler";
    6490             :     }
    6491             : 
    6492           0 :     RefPtr<Function> callback = info->mHandler->GetCallback();
    6493           0 :     if (!callback) {
    6494             :       // scope for the AutoEntryScript, so it comes off the stack before we do
    6495             :       // Promise::PerformMicroTaskCheckpoint.
    6496           0 :       AutoEntryScript aes(global, reason, false);
    6497             : 
    6498             :       // Evaluate the timeout expression.
    6499           0 :       const nsAString& script = info->mHandler->GetHandlerText();
    6500             : 
    6501           0 :       const char* filename = nullptr;
    6502           0 :       uint32_t lineNo = 0, dummyColumn = 0;
    6503           0 :       info->mHandler->GetLocation(&filename, &lineNo, &dummyColumn);
    6504             : 
    6505           0 :       JS::CompileOptions options(aes.cx());
    6506           0 :       options.setFileAndLine(filename, lineNo).setNoScriptRval(true);
    6507             : 
    6508           0 :       JS::Rooted<JS::Value> unused(aes.cx());
    6509             : 
    6510           0 :       if (!JS::Evaluate(aes.cx(), options, script.BeginReading(),
    6511           0 :                         script.Length(), &unused) &&
    6512           0 :           !JS_IsExceptionPending(aCx)) {
    6513           0 :         retval = false;
    6514           0 :         break;
    6515             :       }
    6516             :     } else {
    6517           0 :       ErrorResult rv;
    6518           0 :       JS::Rooted<JS::Value> ignoredVal(aCx);
    6519           0 :       callback->Call(GlobalScope(), info->mHandler->GetArgs(), &ignoredVal, rv,
    6520           0 :                      reason);
    6521           0 :       if (rv.IsUncatchableException()) {
    6522           0 :         rv.SuppressException();
    6523           0 :         retval = false;
    6524           0 :         break;
    6525             :       }
    6526             : 
    6527           0 :       rv.SuppressException();
    6528             :     }
    6529             : 
    6530             :     // Since we might be processing more timeouts, go ahead and flush
    6531             :     // the promise queue now before we do that.
    6532           0 :     Promise::PerformWorkerMicroTaskCheckpoint();
    6533             : 
    6534           0 :     NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
    6535             :   }
    6536             : 
    6537             :   // No longer possible to be called recursively.
    6538           0 :   mRunningExpiredTimeouts = false;
    6539             : 
    6540             :   // Now remove canceled and expired timeouts from the main list.
    6541             :   // NB: The timeouts present in expiredTimeouts must have the same order
    6542             :   // with respect to each other in mTimeouts.  That is, mTimeouts is just
    6543             :   // expiredTimeouts with extra elements inserted.  There may be unexpired
    6544             :   // timeouts that have been inserted between the expired timeouts if the
    6545             :   // timeout event handler called setTimeout/setInterval.
    6546           0 :   for (uint32_t index = 0, expiredTimeoutIndex = 0,
    6547           0 :        expiredTimeoutLength = expiredTimeouts.Length();
    6548           0 :        index < mTimeouts.Length(); ) {
    6549           0 :     nsAutoPtr<TimeoutInfo>& info = mTimeouts[index];
    6550           0 :     if ((expiredTimeoutIndex < expiredTimeoutLength &&
    6551           0 :          info == expiredTimeouts[expiredTimeoutIndex] &&
    6552           0 :          ++expiredTimeoutIndex) ||
    6553           0 :         info->mCanceled) {
    6554           0 :       if (info->mIsInterval && !info->mCanceled) {
    6555             :         // Reschedule intervals.
    6556           0 :         info->mTargetTime = info->mTargetTime + info->mInterval;
    6557             :         // Don't resort the list here, we'll do that at the end.
    6558           0 :         ++index;
    6559             :       }
    6560             :       else {
    6561           0 :         mTimeouts.RemoveElement(info);
    6562             :       }
    6563             :     }
    6564             :     else {
    6565             :       // If info did not match the current entry in expiredTimeouts, it
    6566             :       // shouldn't be there at all.
    6567           0 :       NS_ASSERTION(!expiredTimeouts.Contains(info),
    6568             :                    "Our timeouts are out of order!");
    6569           0 :       ++index;
    6570             :     }
    6571             :   }
    6572             : 
    6573           0 :   mTimeouts.Sort(comparator);
    6574             : 
    6575             :   // Either signal the parent that we're no longer using timeouts or reschedule
    6576             :   // the timer.
    6577           0 :   if (mTimeouts.IsEmpty()) {
    6578           0 :     if (!ModifyBusyCountFromWorker(false)) {
    6579           0 :       retval = false;
    6580             :     }
    6581           0 :     mTimerRunning = false;
    6582             :   }
    6583           0 :   else if (retval && !RescheduleTimeoutTimer(aCx)) {
    6584           0 :     retval = false;
    6585             :   }
    6586             : 
    6587           0 :   return retval;
    6588             : }
    6589             : 
    6590             : bool
    6591           0 : WorkerPrivate::RescheduleTimeoutTimer(JSContext* aCx)
    6592             : {
    6593           0 :   AssertIsOnWorkerThread();
    6594           0 :   MOZ_ASSERT(!mRunningExpiredTimeouts);
    6595           0 :   NS_ASSERTION(!mTimeouts.IsEmpty(), "Should have some timeouts!");
    6596           0 :   NS_ASSERTION(mTimer && mTimerRunnable, "Should have a timer!");
    6597             : 
    6598             :   // NB: This is important! The timer may have already fired, e.g. if a timeout
    6599             :   // callback itself calls setTimeout for a short duration and then takes longer
    6600             :   // than that to finish executing. If that has happened, it's very important
    6601             :   // that we don't execute the event that is now pending in our event queue, or
    6602             :   // our code in RunExpiredTimeouts to "fudge" the timeout value will unleash an
    6603             :   // early timeout when we execute the event we're about to queue.
    6604           0 :   mTimer->Cancel();
    6605             : 
    6606             :   double delta =
    6607           0 :     (mTimeouts[0]->mTargetTime - TimeStamp::Now()).ToMilliseconds();
    6608           0 :   uint32_t delay = delta > 0 ? std::min(delta, double(UINT32_MAX)) : 0;
    6609             : 
    6610           0 :   LOG(TimeoutsLog(), ("Worker %p scheduled timer for %d ms, %" PRIuSIZE " pending timeouts\n",
    6611             :                       this, delay, mTimeouts.Length()));
    6612             : 
    6613           0 :   nsresult rv = mTimer->InitWithCallback(mTimerRunnable, delay, nsITimer::TYPE_ONE_SHOT);
    6614           0 :   if (NS_FAILED(rv)) {
    6615           0 :     JS_ReportErrorASCII(aCx, "Failed to start timer!");
    6616           0 :     return false;
    6617             :   }
    6618             : 
    6619           0 :   return true;
    6620             : }
    6621             : 
    6622             : void
    6623           0 : WorkerPrivate::UpdateContextOptionsInternal(
    6624             :                                     JSContext* aCx,
    6625             :                                     const JS::ContextOptions& aContextOptions)
    6626             : {
    6627           0 :   AssertIsOnWorkerThread();
    6628             : 
    6629           0 :   JS::ContextOptionsRef(aCx) = aContextOptions;
    6630             : 
    6631           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6632           0 :     mChildWorkers[index]->UpdateContextOptions(aContextOptions);
    6633             :   }
    6634           0 : }
    6635             : 
    6636             : void
    6637           0 : WorkerPrivate::UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages)
    6638             : {
    6639           0 :   WorkerGlobalScope* globalScope = GlobalScope();
    6640           0 :   if (globalScope) {
    6641           0 :     RefPtr<WorkerNavigator> nav = globalScope->GetExistingNavigator();
    6642           0 :     if (nav) {
    6643           0 :       nav->SetLanguages(aLanguages);
    6644             :     }
    6645             :   }
    6646             : 
    6647           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6648           0 :     mChildWorkers[index]->UpdateLanguages(aLanguages);
    6649             :   }
    6650           0 : }
    6651             : 
    6652             : void
    6653           0 : WorkerPrivate::UpdatePreferenceInternal(WorkerPreference aPref, bool aValue)
    6654             : {
    6655           0 :   AssertIsOnWorkerThread();
    6656           0 :   MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
    6657             : 
    6658           0 :   mPreferences[aPref] = aValue;
    6659             : 
    6660           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6661           0 :     mChildWorkers[index]->UpdatePreference(aPref, aValue);
    6662             :   }
    6663           0 : }
    6664             : 
    6665             : void
    6666           0 : WorkerPrivate::UpdateJSWorkerMemoryParameterInternal(JSContext* aCx,
    6667             :                                                      JSGCParamKey aKey,
    6668             :                                                      uint32_t aValue)
    6669             : {
    6670           0 :   AssertIsOnWorkerThread();
    6671             : 
    6672             :   // XXX aValue might be 0 here (telling us to unset a previous value for child
    6673             :   // workers). Calling JS_SetGCParameter with a value of 0 isn't actually
    6674             :   // supported though. We really need some way to revert to a default value
    6675             :   // here.
    6676           0 :   if (aValue) {
    6677           0 :     JS_SetGCParameter(aCx, aKey, aValue);
    6678             :   }
    6679             : 
    6680           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6681           0 :     mChildWorkers[index]->UpdateJSWorkerMemoryParameter(aKey, aValue);
    6682             :   }
    6683           0 : }
    6684             : 
    6685             : #ifdef JS_GC_ZEAL
    6686             : void
    6687           0 : WorkerPrivate::UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
    6688             :                                     uint32_t aFrequency)
    6689             : {
    6690           0 :   AssertIsOnWorkerThread();
    6691             : 
    6692           0 :   JS_SetGCZeal(aCx, aGCZeal, aFrequency);
    6693             : 
    6694           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6695           0 :     mChildWorkers[index]->UpdateGCZeal(aGCZeal, aFrequency);
    6696             :   }
    6697           0 : }
    6698             : #endif
    6699             : 
    6700             : void
    6701           0 : WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
    6702             :                                       bool aCollectChildren)
    6703             : {
    6704           0 :   AssertIsOnWorkerThread();
    6705             : 
    6706           0 :   if (!GlobalScope()) {
    6707             :     // We haven't compiled anything yet. Just bail out.
    6708           0 :     return;
    6709             :   }
    6710             : 
    6711           0 :   if (aShrinking || aCollectChildren) {
    6712           0 :     JS::PrepareForFullGC(aCx);
    6713             : 
    6714           0 :     if (aShrinking) {
    6715           0 :       JS::GCForReason(aCx, GC_SHRINK, JS::gcreason::DOM_WORKER);
    6716             : 
    6717           0 :       if (!aCollectChildren) {
    6718           0 :         LOG(WorkerLog(), ("Worker %p collected idle garbage\n", this));
    6719             :       }
    6720             :     }
    6721             :     else {
    6722           0 :       JS::GCForReason(aCx, GC_NORMAL, JS::gcreason::DOM_WORKER);
    6723           0 :       LOG(WorkerLog(), ("Worker %p collected garbage\n", this));
    6724             :     }
    6725             :   }
    6726             :   else {
    6727           0 :     JS_MaybeGC(aCx);
    6728           0 :     LOG(WorkerLog(), ("Worker %p collected periodic garbage\n", this));
    6729             :   }
    6730             : 
    6731           0 :   if (aCollectChildren) {
    6732           0 :     for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6733           0 :       mChildWorkers[index]->GarbageCollect(aShrinking);
    6734             :     }
    6735             :   }
    6736             : }
    6737             : 
    6738             : void
    6739           0 : WorkerPrivate::CycleCollectInternal(bool aCollectChildren)
    6740             : {
    6741           0 :   AssertIsOnWorkerThread();
    6742             : 
    6743           0 :   nsCycleCollector_collect(nullptr);
    6744             : 
    6745           0 :   if (aCollectChildren) {
    6746           0 :     for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6747           0 :       mChildWorkers[index]->CycleCollect(/* dummy = */ false);
    6748             :     }
    6749             :   }
    6750           0 : }
    6751             : 
    6752             : void
    6753           0 : WorkerPrivate::MemoryPressureInternal()
    6754             : {
    6755           0 :   AssertIsOnWorkerThread();
    6756             : 
    6757           0 :   RefPtr<Console> console = mScope ? mScope->GetConsoleIfExists() : nullptr;
    6758           0 :   if (console) {
    6759           0 :     console->ClearStorage();
    6760             :   }
    6761             : 
    6762           0 :   console = mDebuggerScope ? mDebuggerScope->GetConsoleIfExists() : nullptr;
    6763           0 :   if (console) {
    6764           0 :     console->ClearStorage();
    6765             :   }
    6766             : 
    6767           0 :   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
    6768           0 :     mChildWorkers[index]->MemoryPressure(false);
    6769             :   }
    6770           0 : }
    6771             : 
    6772             : void
    6773           1 : WorkerPrivate::SetThread(WorkerThread* aThread)
    6774             : {
    6775           1 :   if (aThread) {
    6776             : #ifdef DEBUG
    6777             :     {
    6778             :       bool isOnCurrentThread;
    6779           1 :       MOZ_ASSERT(NS_SUCCEEDED(aThread->IsOnCurrentThread(&isOnCurrentThread)));
    6780           1 :       MOZ_ASSERT(isOnCurrentThread);
    6781             :     }
    6782             : #endif
    6783             : 
    6784           1 :     MOZ_ASSERT(!mPRThread);
    6785           1 :     mPRThread = PRThreadFromThread(aThread);
    6786           1 :     MOZ_ASSERT(mPRThread);
    6787             :   }
    6788             :   else {
    6789           0 :     MOZ_ASSERT(mPRThread);
    6790             :   }
    6791             : 
    6792           2 :   const WorkerThreadFriendKey friendKey;
    6793             : 
    6794           2 :   RefPtr<WorkerThread> doomedThread;
    6795             : 
    6796             :   { // Scope so that |doomedThread| is released without holding the lock.
    6797           2 :     MutexAutoLock lock(mMutex);
    6798             : 
    6799           1 :     if (aThread) {
    6800           1 :       MOZ_ASSERT(!mThread);
    6801           1 :       MOZ_ASSERT(mStatus == Pending);
    6802             : 
    6803           1 :       mThread = aThread;
    6804           1 :       mThread->SetWorker(friendKey, this);
    6805             : 
    6806           1 :       if (!mPreStartRunnables.IsEmpty()) {
    6807           3 :         for (uint32_t index = 0; index < mPreStartRunnables.Length(); index++) {
    6808           2 :           MOZ_ALWAYS_SUCCEEDS(
    6809             :             mThread->DispatchAnyThread(friendKey, mPreStartRunnables[index].forget()));
    6810             :         }
    6811           1 :         mPreStartRunnables.Clear();
    6812             :       }
    6813             :     }
    6814             :     else {
    6815           0 :       MOZ_ASSERT(mThread);
    6816             : 
    6817           0 :       mThread->SetWorker(friendKey, nullptr);
    6818             : 
    6819           0 :       mThread.swap(doomedThread);
    6820             :     }
    6821             :   }
    6822           1 : }
    6823             : 
    6824             : WorkerCrossThreadDispatcher*
    6825           0 : WorkerPrivate::GetCrossThreadDispatcher()
    6826             : {
    6827           0 :   MutexAutoLock lock(mMutex);
    6828             : 
    6829           0 :   if (!mCrossThreadDispatcher && mStatus <= Running) {
    6830           0 :     mCrossThreadDispatcher = new WorkerCrossThreadDispatcher(this);
    6831             :   }
    6832             : 
    6833           0 :   return mCrossThreadDispatcher;
    6834             : }
    6835             : 
    6836             : void
    6837           0 : WorkerPrivate::BeginCTypesCall()
    6838             : {
    6839           0 :   AssertIsOnWorkerThread();
    6840             : 
    6841             :   // Don't try to GC while we're blocked in a ctypes call.
    6842           0 :   SetGCTimerMode(NoTimer);
    6843           0 : }
    6844             : 
    6845             : void
    6846           0 : WorkerPrivate::EndCTypesCall()
    6847             : {
    6848           0 :   AssertIsOnWorkerThread();
    6849             : 
    6850             :   // Make sure the periodic timer is running before we start running JS again.
    6851           0 :   SetGCTimerMode(PeriodicTimer);
    6852           0 : }
    6853             : 
    6854             : bool
    6855           0 : WorkerPrivate::ConnectMessagePort(JSContext* aCx,
    6856             :                                   MessagePortIdentifier& aIdentifier)
    6857             : {
    6858           0 :   AssertIsOnWorkerThread();
    6859             : 
    6860           0 :   WorkerGlobalScope* globalScope = GlobalScope();
    6861             : 
    6862           0 :   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
    6863           0 :   MOZ_ASSERT(jsGlobal);
    6864             : 
    6865             :   // This MessagePortIdentifier is used to create a new port, still connected
    6866             :   // with the other one, but in the worker thread.
    6867           0 :   ErrorResult rv;
    6868           0 :   RefPtr<MessagePort> port = MessagePort::Create(globalScope, aIdentifier, rv);
    6869           0 :   if (NS_WARN_IF(rv.Failed())) {
    6870           0 :     rv.SuppressException();
    6871           0 :     return false;
    6872             :   }
    6873             : 
    6874           0 :   GlobalObject globalObject(aCx, jsGlobal);
    6875           0 :   if (globalObject.Failed()) {
    6876           0 :     return false;
    6877             :   }
    6878             : 
    6879           0 :   RootedDictionary<MessageEventInit> init(aCx);
    6880           0 :   init.mBubbles = false;
    6881           0 :   init.mCancelable = false;
    6882           0 :   init.mSource.SetValue().SetAsMessagePort() = port;
    6883           0 :   if (!init.mPorts.AppendElement(port.forget(), fallible)) {
    6884           0 :     return false;
    6885             :   }
    6886             : 
    6887             :   RefPtr<MessageEvent> event =
    6888           0 :     MessageEvent::Constructor(globalObject,
    6889           0 :                               NS_LITERAL_STRING("connect"), init, rv);
    6890             : 
    6891           0 :   event->SetTrusted(true);
    6892             : 
    6893           0 :   nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
    6894             : 
    6895           0 :   nsEventStatus dummy = nsEventStatus_eIgnore;
    6896           0 :   globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
    6897             : 
    6898           0 :   return true;
    6899             : }
    6900             : 
    6901             : WorkerGlobalScope*
    6902           1 : WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
    6903             : {
    6904           1 :   AssertIsOnWorkerThread();
    6905             : 
    6906           1 :   if (!mScope) {
    6907           2 :     RefPtr<WorkerGlobalScope> globalScope;
    6908           1 :     if (IsSharedWorker()) {
    6909           0 :       globalScope = new SharedWorkerGlobalScope(this, WorkerName());
    6910           1 :     } else if (IsServiceWorker()) {
    6911           0 :       globalScope = new ServiceWorkerGlobalScope(this, ServiceWorkerScope());
    6912             :     } else {
    6913           2 :       globalScope = new DedicatedWorkerGlobalScope(this, WorkerName());
    6914             :     }
    6915             : 
    6916           2 :     JS::Rooted<JSObject*> global(aCx);
    6917           1 :     NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
    6918             : 
    6919           2 :     JSAutoCompartment ac(aCx, global);
    6920             : 
    6921             :     // RegisterBindings() can spin a nested event loop so we have to set mScope
    6922             :     // before calling it, and we have to make sure to unset mScope if it fails.
    6923           1 :     mScope = Move(globalScope);
    6924             : 
    6925           1 :     if (!RegisterBindings(aCx, global)) {
    6926           0 :       mScope = nullptr;
    6927           0 :       return nullptr;
    6928             :     }
    6929             : 
    6930           1 :     JS_FireOnNewGlobalObject(aCx, global);
    6931             :   }
    6932             : 
    6933           1 :   return mScope;
    6934             : }
    6935             : 
    6936             : WorkerDebuggerGlobalScope*
    6937           0 : WorkerPrivate::CreateDebuggerGlobalScope(JSContext* aCx)
    6938             : {
    6939           0 :   AssertIsOnWorkerThread();
    6940             : 
    6941           0 :   MOZ_ASSERT(!mDebuggerScope);
    6942             : 
    6943             :   RefPtr<WorkerDebuggerGlobalScope> globalScope =
    6944           0 :     new WorkerDebuggerGlobalScope(this);
    6945             : 
    6946           0 :   JS::Rooted<JSObject*> global(aCx);
    6947           0 :   NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
    6948             : 
    6949           0 :   JSAutoCompartment ac(aCx, global);
    6950             : 
    6951             :   // RegisterDebuggerBindings() can spin a nested event loop so we have to set
    6952             :   // mDebuggerScope before calling it, and we have to make sure to unset
    6953             :   // mDebuggerScope if it fails.
    6954           0 :   mDebuggerScope = Move(globalScope);
    6955             : 
    6956           0 :   if (!RegisterDebuggerBindings(aCx, global)) {
    6957           0 :     mDebuggerScope = nullptr;
    6958           0 :     return nullptr;
    6959             :   }
    6960             : 
    6961           0 :   JS_FireOnNewGlobalObject(aCx, global);
    6962             : 
    6963           0 :   return mDebuggerScope;
    6964             : }
    6965             : 
    6966             : #ifdef DEBUG
    6967             : 
    6968             : void
    6969         646 : WorkerPrivate::AssertIsOnWorkerThread() const
    6970             : {
    6971             :   // This is much more complicated than it needs to be but we can't use mThread
    6972             :   // because it must be protected by mMutex and sometimes this method is called
    6973             :   // when mMutex is already locked. This method should always work.
    6974         646 :   MOZ_ASSERT(mPRThread,
    6975             :              "AssertIsOnWorkerThread() called before a thread was assigned!");
    6976             : 
    6977        1292 :   nsCOMPtr<nsIThread> thread;
    6978             :   nsresult rv =
    6979        1292 :     nsThreadManager::get().GetThreadFromPRThread(mPRThread,
    6980        1292 :                                                  getter_AddRefs(thread));
    6981         646 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
    6982         646 :   MOZ_ASSERT(thread);
    6983             : 
    6984             :   bool current;
    6985         646 :   rv = thread->IsOnCurrentThread(&current);
    6986         646 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
    6987         646 :   MOZ_ASSERT(current, "Wrong thread!");
    6988         646 : }
    6989             : 
    6990             : #endif // DEBUG
    6991             : 
    6992           0 : NS_IMPL_ISUPPORTS_INHERITED0(ExternalRunnableWrapper, WorkerRunnable)
    6993             : 
    6994             : template <class Derived>
    6995         495 : NS_IMPL_ADDREF(WorkerPrivateParent<Derived>::EventTarget)
    6996             : 
    6997             : template <class Derived>
    6998         486 : NS_IMPL_RELEASE(WorkerPrivateParent<Derived>::EventTarget)
    6999             : 
    7000             : template <class Derived>
    7001         459 : NS_INTERFACE_MAP_BEGIN(WorkerPrivateParent<Derived>::EventTarget)
    7002         459 :   NS_INTERFACE_MAP_ENTRY(nsISerialEventTarget)
    7003         457 :   NS_INTERFACE_MAP_ENTRY(nsIEventTarget)
    7004         380 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    7005             : #ifdef DEBUG
    7006             :   // kDEBUGWorkerEventTargetIID is special in that it does not AddRef its
    7007             :   // result.
    7008          58 :   if (aIID.Equals(kDEBUGWorkerEventTargetIID)) {
    7009          58 :     *aInstancePtr = this;
    7010          58 :     return NS_OK;
    7011             :   }
    7012             :   else
    7013             : #endif
    7014           0 : NS_INTERFACE_MAP_END
    7015             : 
    7016             : template <class Derived>
    7017             : NS_IMETHODIMP
    7018           0 : WorkerPrivateParent<Derived>::
    7019             : EventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
    7020             : {
    7021           0 :   nsCOMPtr<nsIRunnable> event(aRunnable);
    7022           0 :   return Dispatch(event.forget(), aFlags);
    7023             : }
    7024             : 
    7025             : template <class Derived>
    7026             : NS_IMETHODIMP
    7027          36 : WorkerPrivateParent<Derived>::
    7028             : EventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags)
    7029             : {
    7030             :   // May be called on any thread!
    7031          72 :   nsCOMPtr<nsIRunnable> event(aRunnable);
    7032             : 
    7033             :   // Workers only support asynchronous dispatch for now.
    7034          36 :   if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
    7035           0 :     return NS_ERROR_UNEXPECTED;
    7036             :   }
    7037             : 
    7038          72 :   RefPtr<WorkerRunnable> workerRunnable;
    7039             : 
    7040          72 :   MutexAutoLock lock(mMutex);
    7041             : 
    7042          36 :   if (!mWorkerPrivate) {
    7043           0 :     NS_WARNING("A runnable was posted to a worker that is already shutting "
    7044             :                "down!");
    7045           0 :     return NS_ERROR_UNEXPECTED;
    7046             :   }
    7047             : 
    7048          36 :   if (event) {
    7049          36 :     workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(event.forget());
    7050             :   }
    7051             : 
    7052             :   nsresult rv =
    7053          36 :     mWorkerPrivate->DispatchPrivate(workerRunnable.forget(), mNestedEventTarget);
    7054          36 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7055           0 :     return rv;
    7056             :   }
    7057             : 
    7058          36 :   return NS_OK;
    7059             : }
    7060             : 
    7061             : template <class Derived>
    7062             : NS_IMETHODIMP
    7063           0 : WorkerPrivateParent<Derived>::
    7064             : EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
    7065             : {
    7066           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    7067             : }
    7068             : 
    7069             : template <class Derived>
    7070             : NS_IMETHODIMP
    7071           0 : WorkerPrivateParent<Derived>::
    7072             : EventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
    7073             : {
    7074             :   // May be called on any thread!
    7075             : 
    7076           0 :   MOZ_ASSERT(aIsOnCurrentThread);
    7077             : 
    7078           0 :   MutexAutoLock lock(mMutex);
    7079             : 
    7080           0 :   if (!mWorkerPrivate) {
    7081           0 :     NS_WARNING("A worker's event target was used after the worker has !");
    7082           0 :     return NS_ERROR_UNEXPECTED;
    7083             :   }
    7084             : 
    7085           0 :   *aIsOnCurrentThread = mWorkerPrivate->IsOnCurrentThread();
    7086           0 :   return NS_OK;
    7087             : }
    7088             : 
    7089             : template <class Derived>
    7090             : NS_IMETHODIMP_(bool)
    7091           0 : WorkerPrivateParent<Derived>::
    7092             : EventTarget::IsOnCurrentThreadInfallible()
    7093             : {
    7094             :   // May be called on any thread!
    7095             : 
    7096           0 :   MutexAutoLock lock(mMutex);
    7097             : 
    7098           0 :   if (!mWorkerPrivate) {
    7099           0 :     NS_WARNING("A worker's event target was used after the worker has !");
    7100           0 :     return false;
    7101             :   }
    7102             : 
    7103           0 :   return mWorkerPrivate->IsOnCurrentThread();
    7104             : }
    7105             : 
    7106             : BEGIN_WORKERS_NAMESPACE
    7107             : 
    7108             : WorkerCrossThreadDispatcher*
    7109           0 : GetWorkerCrossThreadDispatcher(JSContext* aCx, const JS::Value& aWorker)
    7110             : {
    7111           0 :   if (!aWorker.isObject()) {
    7112           0 :     return nullptr;
    7113             :   }
    7114             : 
    7115           0 :   JS::Rooted<JSObject*> obj(aCx, &aWorker.toObject());
    7116           0 :   WorkerPrivate* w = nullptr;
    7117           0 :   UNWRAP_OBJECT(Worker, &obj, w);
    7118           0 :   MOZ_ASSERT(w);
    7119           0 :   return w->GetCrossThreadDispatcher();
    7120             : }
    7121             : 
    7122             : // Force instantiation.
    7123             : template class WorkerPrivateParent<WorkerPrivate>;
    7124             : 
    7125             : END_WORKERS_NAMESPACE

Generated by: LCOV version 1.13