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 #ifndef mozilla_dom_workers_workerprivate_h__
8 #define mozilla_dom_workers_workerprivate_h__
9 
10 #include <bitset>
11 #include "MainThreadUtils.h"
12 #include "ScriptLoader.h"
13 #include "js/ContextOptions.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/AutoRestore.h"
16 #include "mozilla/CondVar.h"
17 #include "mozilla/DOMEventTargetHelper.h"
18 #include "mozilla/Maybe.h"
19 #include "mozilla/MozPromise.h"
20 #include "mozilla/PerformanceCounter.h"
21 #include "mozilla/RelativeTimeline.h"
22 #include "mozilla/Result.h"
23 #include "mozilla/StorageAccess.h"
24 #include "mozilla/ThreadBound.h"
25 #include "mozilla/ThreadSafeWeakPtr.h"
26 #include "mozilla/UniquePtr.h"
27 #include "mozilla/UseCounter.h"
28 #include "mozilla/dom/ClientSource.h"
29 #include "mozilla/dom/FlippedOnce.h"
30 #include "mozilla/dom/RemoteWorkerChild.h"
31 #include "mozilla/dom/quota/CheckedUnsafePtr.h"
32 #include "mozilla/dom/Worker.h"
33 #include "mozilla/dom/WorkerCommon.h"
34 #include "mozilla/dom/WorkerLoadInfo.h"
35 #include "mozilla/dom/WorkerStatus.h"
36 #include "mozilla/dom/workerinternals/JSSettings.h"
37 #include "mozilla/dom/workerinternals/Queue.h"
38 #include "mozilla/StaticPrefs_extensions.h"
39 #include "nsContentUtils.h"
40 #include "nsIChannel.h"
41 #include "nsIContentSecurityPolicy.h"
42 #include "nsIEventTarget.h"
43 #include "nsILoadInfo.h"
44 #include "nsTObserverArray.h"
45 
46 class nsIThreadInternal;
47 
48 namespace mozilla {
49 class ThrottledEventQueue;
50 namespace dom {
51 
52 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
53 // to be updated too. And histograms enum for worker use counters uses the same
54 // order of worker kind. Please also update dom/base/usecounters.py.
55 enum WorkerKind { WorkerKindDedicated, WorkerKindShared, WorkerKindService };
56 
57 class ClientInfo;
58 class ClientSource;
59 class Function;
60 class JSExecutionManager;
61 class MessagePort;
62 class UniqueMessagePortId;
63 class PerformanceStorage;
64 class TimeoutHandler;
65 class WorkerControlRunnable;
66 class WorkerCSPEventListener;
67 class WorkerDebugger;
68 class WorkerDebuggerGlobalScope;
69 class WorkerErrorReport;
70 class WorkerEventTarget;
71 class WorkerGlobalScope;
72 class WorkerRef;
73 class WorkerRunnable;
74 class WorkerDebuggeeRunnable;
75 class WorkerThread;
76 
77 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
78 // object. It exists to avoid changing a lot of code to use Mutex* instead of
79 // Mutex&.
80 class SharedMutex {
81   using Mutex = mozilla::Mutex;
82 
83   class RefCountedMutex final : public Mutex {
84    public:
RefCountedMutex(const char * aName)85     explicit RefCountedMutex(const char* aName) : Mutex(aName) {}
86 
87     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex)
88 
89    private:
90     ~RefCountedMutex() = default;
91   };
92 
93   const RefPtr<RefCountedMutex> mMutex;
94 
95  public:
SharedMutex(const char * aName)96   explicit SharedMutex(const char* aName)
97       : mMutex(new RefCountedMutex(aName)) {}
98 
99   SharedMutex(const SharedMutex& aOther) = default;
100 
101   operator Mutex&() { return *mMutex; }
102 
103   operator const Mutex&() const { return *mMutex; }
104 
AssertCurrentThreadOwns()105   void AssertCurrentThreadOwns() const { mMutex->AssertCurrentThreadOwns(); }
106 };
107 
108 nsString ComputeWorkerPrivateId();
109 
110 class WorkerPrivate final
111     : public RelativeTimeline,
112       public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> {
113  public:
114   struct LocationInfo {
115     nsCString mHref;
116     nsCString mProtocol;
117     nsCString mHost;
118     nsCString mHostname;
119     nsCString mPort;
120     nsCString mPathname;
121     nsCString mSearch;
122     nsCString mHash;
123     nsString mOrigin;
124   };
125 
126   NS_INLINE_DECL_REFCOUNTING(WorkerPrivate)
127 
128   static already_AddRefed<WorkerPrivate> Constructor(
129       JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker,
130       WorkerKind aWorkerKind, const nsAString& aWorkerName,
131       const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo,
132       ErrorResult& aRv, nsString aId = u""_ns);
133 
134   enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup };
135 
136   static nsresult GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
137                               WorkerPrivate* aParent,
138                               const nsAString& aScriptURL, bool aIsChromeWorker,
139                               LoadGroupBehavior aLoadGroupBehavior,
140                               WorkerKind aWorkerKind,
141                               WorkerLoadInfo* aLoadInfo);
142 
143   void Traverse(nsCycleCollectionTraversalCallback& aCb);
144 
ClearSelfAndParentEventTargetRef()145   void ClearSelfAndParentEventTargetRef() {
146     AssertIsOnParentThread();
147     MOZ_ASSERT(mSelfRef);
148     mParentEventTargetRef = nullptr;
149     mSelfRef = nullptr;
150   }
151 
152   // May be called on any thread...
153   bool Start();
154 
155   // Called on the parent thread.
156   bool Notify(WorkerStatus aStatus);
157 
Cancel()158   bool Cancel() { return Notify(Canceling); }
159 
160   bool Close();
161 
162   // The passed principal must be the Worker principal in case of a
163   // ServiceWorker and the loading principal for any other type.
164   static void OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo,
165                                         nsIPrincipal* aPrincipal);
166 
IsDebuggerRegistered()167   bool IsDebuggerRegistered() {
168     AssertIsOnMainThread();
169 
170     // No need to lock here since this is only ever modified by the same thread.
171     return mDebuggerRegistered;
172   }
173 
ExtensionAPIAllowed()174   bool ExtensionAPIAllowed() {
175     return (
176         StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() &&
177         mExtensionAPIAllowed);
178   }
179 
SetIsDebuggerRegistered(bool aDebuggerRegistered)180   void SetIsDebuggerRegistered(bool aDebuggerRegistered) {
181     AssertIsOnMainThread();
182 
183     MutexAutoLock lock(mMutex);
184 
185     MOZ_ASSERT(mDebuggerRegistered != aDebuggerRegistered);
186     mDebuggerRegistered = aDebuggerRegistered;
187 
188     mCondVar.Notify();
189   }
190 
WaitForIsDebuggerRegistered(bool aDebuggerRegistered)191   void WaitForIsDebuggerRegistered(bool aDebuggerRegistered) {
192     AssertIsOnParentThread();
193 
194     // Yield so that the main thread won't be blocked.
195     AutoYieldJSThreadExecution yield;
196 
197     MOZ_ASSERT(!NS_IsMainThread());
198 
199     MutexAutoLock lock(mMutex);
200 
201     while (mDebuggerRegistered != aDebuggerRegistered) {
202       mCondVar.Wait();
203     }
204   }
205 
206   nsresult SetIsDebuggerReady(bool aReady);
207 
Debugger()208   WorkerDebugger* Debugger() const {
209     AssertIsOnMainThread();
210 
211     MOZ_ASSERT(mDebugger);
212     return mDebugger;
213   }
214 
SetDebugger(WorkerDebugger * aDebugger)215   void SetDebugger(WorkerDebugger* aDebugger) {
216     AssertIsOnMainThread();
217 
218     MOZ_ASSERT(mDebugger != aDebugger);
219     mDebugger = aDebugger;
220   }
221 
AdoptDefaultLocale()222   JS::UniqueChars AdoptDefaultLocale() {
223     MOZ_ASSERT(mDefaultLocale,
224                "the default locale must have been successfully set for anyone "
225                "to be trying to adopt it");
226     return std::move(mDefaultLocale);
227   }
228 
229   /**
230    * Invoked by WorkerThreadPrimaryRunnable::Run if it already called
231    * SetWorkerPrivateInWorkerThread but has to bail out on initialization before
232    * calling DoRunLoop because PBackground failed to initialize or something
233    * like that.  Note that there's currently no point earlier than this that
234    * failure can be reported.
235    *
236    * When this happens, the worker will need to be deleted, plus the call to
237    * SetWorkerPrivateInWorkerThread will have scheduled all the
238    * mPreStartRunnables which need to be cleaned up after, as well as any
239    * scheduled control runnables.  We're somewhat punting on debugger runnables
240    * for now, which may leak, but the intent is to moot this whole scenario via
241    * shutdown blockers, so we don't want the extra complexity right now.
242    */
243   void RunLoopNeverRan();
244 
245   MOZ_CAN_RUN_SCRIPT
246   void DoRunLoop(JSContext* aCx);
247 
248   bool InterruptCallback(JSContext* aCx);
249 
250   bool IsOnCurrentThread();
251 
252   void CloseInternal();
253 
254   bool FreezeInternal();
255 
256   bool ThawInternal();
257 
258   void PropagateStorageAccessPermissionGrantedInternal();
259 
260   void TraverseTimeouts(nsCycleCollectionTraversalCallback& aCallback);
261 
262   void UnlinkTimeouts();
263 
264   bool ModifyBusyCountFromWorker(bool aIncrease);
265 
266   bool AddChildWorker(WorkerPrivate& aChildWorker);
267 
268   void RemoveChildWorker(WorkerPrivate& aChildWorker);
269 
270   void PostMessageToParent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
271                            const Sequence<JSObject*>& aTransferable,
272                            ErrorResult& aRv);
273 
274   void PostMessageToParentMessagePort(JSContext* aCx,
275                                       JS::Handle<JS::Value> aMessage,
276                                       const Sequence<JSObject*>& aTransferable,
277                                       ErrorResult& aRv);
278 
279   MOZ_CAN_RUN_SCRIPT void EnterDebuggerEventLoop();
280 
281   void LeaveDebuggerEventLoop();
282 
283   void PostMessageToDebugger(const nsAString& aMessage);
284 
285   void SetDebuggerImmediate(Function& aHandler, ErrorResult& aRv);
286 
287   void ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
288                              const nsAString& aMessage);
289 
290   bool NotifyInternal(WorkerStatus aStatus);
291 
292   void ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
293                    JSErrorReport* aReport);
294 
295   static void ReportErrorToConsole(const char* aMessage);
296 
297   static void ReportErrorToConsole(const char* aMessage,
298                                    const nsTArray<nsString>& aParams);
299 
300   int32_t SetTimeout(JSContext* aCx, TimeoutHandler* aHandler, int32_t aTimeout,
301                      bool aIsInterval, ErrorResult& aRv);
302 
303   void ClearTimeout(int32_t aId);
304 
305   MOZ_CAN_RUN_SCRIPT bool RunExpiredTimeouts(JSContext* aCx);
306 
307   bool RescheduleTimeoutTimer(JSContext* aCx);
308 
309   void UpdateContextOptionsInternal(JSContext* aCx,
310                                     const JS::ContextOptions& aContextOptions);
311 
312   void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
313 
314   void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key,
315                                              Maybe<uint32_t> aValue);
316 
317   enum WorkerRanOrNot { WorkerNeverRan = 0, WorkerRan };
318 
319   void ScheduleDeletion(WorkerRanOrNot aRanOrNot);
320 
321   bool CollectRuntimeStats(JS::RuntimeStats* aRtStats, bool aAnonymize);
322 
323 #ifdef JS_GC_ZEAL
324   void UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
325                             uint32_t aFrequency);
326 #endif
327 
328   void SetLowMemoryStateInternal(JSContext* aCx, bool aState);
329 
330   void GarbageCollectInternal(JSContext* aCx, bool aShrinking,
331                               bool aCollectChildren);
332 
333   void CycleCollectInternal(bool aCollectChildren);
334 
335   void OfflineStatusChangeEventInternal(bool aIsOffline);
336 
337   void MemoryPressureInternal();
338 
SetFetchHandlerWasAdded()339   void SetFetchHandlerWasAdded() {
340     MOZ_ASSERT(IsServiceWorker());
341     AssertIsOnWorkerThread();
342     mFetchHandlerWasAdded = true;
343   }
344 
FetchHandlerWasAdded()345   bool FetchHandlerWasAdded() const {
346     MOZ_ASSERT(IsServiceWorker());
347     AssertIsOnWorkerThread();
348     return mFetchHandlerWasAdded;
349   }
350 
GetJSContext()351   JSContext* GetJSContext() const {
352     // mJSContext is only modified on the worker thread, so workerthread code
353     // can safely read it without a lock
354     AssertIsOnWorkerThread();
355     return mJSContext;
356   }
357 
GlobalScope()358   WorkerGlobalScope* GlobalScope() const {
359     auto data = mWorkerThreadAccessible.Access();
360     return data->mScope;
361   }
362 
DebuggerGlobalScope()363   WorkerDebuggerGlobalScope* DebuggerGlobalScope() const {
364     auto data = mWorkerThreadAccessible.Access();
365     return data->mDebuggerScope;
366   }
367 
368   // Get the global associated with the current nested event loop.  Will return
369   // null if we're not in a nested event loop or that nested event loop does not
370   // have an associated global.
GetCurrentEventLoopGlobal()371   nsIGlobalObject* GetCurrentEventLoopGlobal() const {
372     auto data = mWorkerThreadAccessible.Access();
373     return data->mCurrentEventLoopGlobal;
374   }
375 
376   nsICSPEventListener* CSPEventListener() const;
377 
378   void SetThread(WorkerThread* aThread);
379 
380   void SetWorkerPrivateInWorkerThread(WorkerThread* aThread);
381 
382   void ResetWorkerPrivateInWorkerThread();
383 
384   bool IsOnWorkerThread() const;
385 
386   void AssertIsOnWorkerThread() const
387 #ifdef DEBUG
388       ;
389 #else
390   {
391   }
392 #endif
393 
394   // This may block!
395   void BeginCTypesCall();
396 
397   // This may block!
398   void EndCTypesCall();
399 
400   void BeginCTypesCallback();
401 
402   void EndCTypesCallback();
403 
404   bool ConnectMessagePort(JSContext* aCx, UniqueMessagePortId& aIdentifier);
405 
406   WorkerGlobalScope* GetOrCreateGlobalScope(JSContext* aCx);
407 
408   WorkerDebuggerGlobalScope* CreateDebuggerGlobalScope(JSContext* aCx);
409 
410   bool RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
411 
412   bool RegisterDebuggerBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
413 
OnLine()414   bool OnLine() const {
415     auto data = mWorkerThreadAccessible.Access();
416     return data->mOnLine;
417   }
418 
419   void StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult);
420 
AllPendingRunnablesShouldBeCanceled()421   bool AllPendingRunnablesShouldBeCanceled() const {
422     return mCancelAllPendingRunnables;
423   }
424 
425   void ClearMainEventQueue(WorkerRanOrNot aRanOrNot);
426 
427   void ClearDebuggerEventQueue();
428 
429   void OnProcessNextEvent();
430 
431   void AfterProcessNextEvent();
432 
433   void AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
434 #ifdef DEBUG
435       ;
436 #else
437   {
438   }
439 #endif
440 
SetWorkerScriptExecutedSuccessfully()441   void SetWorkerScriptExecutedSuccessfully() {
442     AssertIsOnWorkerThread();
443     // Should only be called once!
444     MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully);
445     mWorkerScriptExecutedSuccessfully = true;
446   }
447 
448   // Only valid after CompileScriptRunnable has finished running!
WorkerScriptExecutedSuccessfully()449   bool WorkerScriptExecutedSuccessfully() const {
450     AssertIsOnWorkerThread();
451     return mWorkerScriptExecutedSuccessfully;
452   }
453 
454   // Get the event target to use when dispatching to the main thread
455   // from this Worker thread.  This may be the main thread itself or
456   // a ThrottledEventQueue to the main thread.
457   nsIEventTarget* MainThreadEventTargetForMessaging();
458 
459   nsresult DispatchToMainThreadForMessaging(
460       nsIRunnable* aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL);
461 
462   nsresult DispatchToMainThreadForMessaging(
463       already_AddRefed<nsIRunnable> aRunnable,
464       uint32_t aFlags = NS_DISPATCH_NORMAL);
465 
466   nsIEventTarget* MainThreadEventTarget();
467 
468   nsresult DispatchToMainThread(nsIRunnable* aRunnable,
469                                 uint32_t aFlags = NS_DISPATCH_NORMAL);
470 
471   nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
472                                 uint32_t aFlags = NS_DISPATCH_NORMAL);
473 
474   nsresult DispatchDebuggeeToMainThread(
475       already_AddRefed<WorkerDebuggeeRunnable> aRunnable,
476       uint32_t aFlags = NS_DISPATCH_NORMAL);
477 
478   // Get an event target that will dispatch runnables as control runnables on
479   // the worker thread.  Implement nsICancelableRunnable if you wish to take
480   // action on cancelation.
481   nsISerialEventTarget* ControlEventTarget();
482 
483   // Get an event target that will attempt to dispatch a normal WorkerRunnable,
484   // but if that fails will then fall back to a control runnable.
485   nsISerialEventTarget* HybridEventTarget();
486 
487   void DumpCrashInformation(nsACString& aString);
488 
489   ClientType GetClientType() const;
490 
491   bool EnsureCSPEventListener();
492 
493   void EnsurePerformanceStorage();
494 
495   bool GetExecutionGranted() const;
496   void SetExecutionGranted(bool aGranted);
497 
498   void ScheduleTimeSliceExpiration(uint32_t aDelay);
499   void CancelTimeSliceExpiration();
500 
501   JSExecutionManager* GetExecutionManager() const;
502   void SetExecutionManager(JSExecutionManager* aManager);
503 
504   void ExecutionReady();
505 
506   PerformanceStorage* GetPerformanceStorage();
507 
MutablePerformanceCounterRef()508   PerformanceCounter& MutablePerformanceCounterRef() const {
509     return *mPerformanceCounter;
510   }
511 
PerformanceCounterRef()512   const PerformanceCounter& PerformanceCounterRef() const {
513     return MutablePerformanceCounterRef();
514   }
515 
IsAcceptingEvents()516   bool IsAcceptingEvents() {
517     AssertIsOnParentThread();
518 
519     MutexAutoLock lock(mMutex);
520     return mParentStatus < Canceling;
521   }
522 
ParentStatusProtected()523   WorkerStatus ParentStatusProtected() {
524     AssertIsOnParentThread();
525     MutexAutoLock lock(mMutex);
526     return mParentStatus;
527   }
528 
ParentStatus()529   WorkerStatus ParentStatus() const {
530     mMutex.AssertCurrentThreadOwns();
531     return mParentStatus;
532   }
533 
ParentEventTargetRef()534   Worker* ParentEventTargetRef() const {
535     MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef);
536     return mParentEventTargetRef;
537   }
538 
SetParentEventTargetRef(Worker * aParentEventTargetRef)539   void SetParentEventTargetRef(Worker* aParentEventTargetRef) {
540     MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef);
541     MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef);
542     mParentEventTargetRef = aParentEventTargetRef;
543   }
544 
545   bool ModifyBusyCount(bool aIncrease);
546 
547   // This method is used by RuntimeService to know what is going wrong the
548   // shutting down.
BusyCount()549   uint32_t BusyCount() { return mBusyCount; }
550 
551   // Check whether this worker is a secure context.  For use from the parent
552   // thread only; the canonical "is secure context" boolean is stored on the
553   // compartment of the worker global.  The only reason we don't
554   // AssertIsOnParentThread() here is so we can assert that this value matches
555   // the one on the compartment, which has to be done from the worker thread.
IsSecureContext()556   bool IsSecureContext() const { return mIsSecureContext; }
557 
558   // Check whether we're running in automation.
IsInAutomation()559   bool IsInAutomation() const { return mIsInAutomation; }
560 
IsPrivilegedAddonGlobal()561   bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal; }
562 
CreationTimeStamp()563   TimeStamp CreationTimeStamp() const { return mCreationTimeStamp; }
564 
CreationTime()565   DOMHighResTimeStamp CreationTime() const { return mCreationTimeHighRes; }
566 
TimeStampToDOMHighRes(const TimeStamp & aTimeStamp)567   DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const {
568     MOZ_ASSERT(!aTimeStamp.IsNull());
569     TimeDuration duration = aTimeStamp - mCreationTimeStamp;
570     return duration.ToMilliseconds();
571   }
572 
GetLocationInfo()573   LocationInfo& GetLocationInfo() { return mLocationInfo; }
574 
CopyJSSettings(workerinternals::JSSettings & aSettings)575   void CopyJSSettings(workerinternals::JSSettings& aSettings) {
576     mozilla::MutexAutoLock lock(mMutex);
577     aSettings = mJSSettings;
578   }
579 
CopyJSRealmOptions(JS::RealmOptions & aOptions)580   void CopyJSRealmOptions(JS::RealmOptions& aOptions) {
581     mozilla::MutexAutoLock lock(mMutex);
582     aOptions = IsChromeWorker() ? mJSSettings.chromeRealmOptions
583                                 : mJSSettings.contentRealmOptions;
584   }
585 
586   // The ability to be a chrome worker is orthogonal to the type of
587   // worker [Dedicated|Shared|Service].
IsChromeWorker()588   bool IsChromeWorker() const { return mIsChromeWorker; }
589 
590   // TODO: Invariants require that the parent worker out-live any child
591   // worker, so WorkerPrivate* should be safe in the moment of calling.
592   // We would like to have stronger type-system annotated/enforced handling.
GetParent()593   WorkerPrivate* GetParent() const { return mParent; }
594 
IsFrozen()595   bool IsFrozen() const {
596     AssertIsOnParentThread();
597     return mParentFrozen;
598   }
599 
IsParentWindowPaused()600   bool IsParentWindowPaused() const {
601     AssertIsOnParentThread();
602     return mParentWindowPaused;
603   }
604 
605   // When we debug a worker, we want to disconnect the window and the worker
606   // communication. This happens calling this method.
607   // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
608   void ParentWindowPaused();
609 
610   void ParentWindowResumed();
611 
ScriptURL()612   const nsString& ScriptURL() const { return mScriptURL; }
613 
WorkerName()614   const nsString& WorkerName() const { return mWorkerName; }
615 
Kind()616   WorkerKind Kind() const { return mWorkerKind; }
617 
IsDedicatedWorker()618   bool IsDedicatedWorker() const { return mWorkerKind == WorkerKindDedicated; }
619 
IsSharedWorker()620   bool IsSharedWorker() const { return mWorkerKind == WorkerKindShared; }
621 
IsServiceWorker()622   bool IsServiceWorker() const { return mWorkerKind == WorkerKindService; }
623 
ContentPolicyType()624   nsContentPolicyType ContentPolicyType() const {
625     return ContentPolicyType(mWorkerKind);
626   }
627 
ContentPolicyType(WorkerKind aWorkerKind)628   static nsContentPolicyType ContentPolicyType(WorkerKind aWorkerKind) {
629     switch (aWorkerKind) {
630       case WorkerKindDedicated:
631         return nsIContentPolicy::TYPE_INTERNAL_WORKER;
632       case WorkerKindShared:
633         return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
634       case WorkerKindService:
635         return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;
636       default:
637         MOZ_ASSERT_UNREACHABLE("Invalid worker type");
638         return nsIContentPolicy::TYPE_INVALID;
639     }
640   }
641 
GetScriptContext()642   nsIScriptContext* GetScriptContext() const {
643     AssertIsOnMainThread();
644     return mLoadInfo.mScriptContext;
645   }
646 
Domain()647   const nsCString& Domain() const { return mLoadInfo.mDomain; }
648 
IsFromWindow()649   bool IsFromWindow() const { return mLoadInfo.mFromWindow; }
650 
GetLoadFlags()651   nsLoadFlags GetLoadFlags() const { return mLoadInfo.mLoadFlags; }
652 
WindowID()653   uint64_t WindowID() const { return mLoadInfo.mWindowID; }
654 
ServiceWorkerID()655   uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
656 
ServiceWorkerScope()657   const nsCString& ServiceWorkerScope() const {
658     return GetServiceWorkerDescriptor().Scope();
659   }
660 
661   // This value should never change after the script load completes. Before
662   // then, it may only be called on the main thread.
GetBaseURI()663   nsIURI* GetBaseURI() const { return mLoadInfo.mBaseURI; }
664 
665   void SetBaseURI(nsIURI* aBaseURI);
666 
GetResolvedScriptURI()667   nsIURI* GetResolvedScriptURI() const { return mLoadInfo.mResolvedScriptURI; }
668 
ServiceWorkerCacheName()669   const nsString& ServiceWorkerCacheName() const {
670     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
671     AssertIsOnMainThread();
672     return mLoadInfo.mServiceWorkerCacheName;
673   }
674 
GetServiceWorkerDescriptor()675   const ServiceWorkerDescriptor& GetServiceWorkerDescriptor() const {
676     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
677     MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome());
678     return mLoadInfo.mServiceWorkerDescriptor.ref();
679   }
680 
681   const ServiceWorkerRegistrationDescriptor&
GetServiceWorkerRegistrationDescriptor()682   GetServiceWorkerRegistrationDescriptor() const {
683     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
684     MOZ_DIAGNOSTIC_ASSERT(
685         mLoadInfo.mServiceWorkerRegistrationDescriptor.isSome());
686     return mLoadInfo.mServiceWorkerRegistrationDescriptor.ref();
687   }
688 
UpdateServiceWorkerState(ServiceWorkerState aState)689   void UpdateServiceWorkerState(ServiceWorkerState aState) {
690     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
691     MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome());
692     return mLoadInfo.mServiceWorkerDescriptor.ref().SetState(aState);
693   }
694 
GetParentController()695   const Maybe<ServiceWorkerDescriptor>& GetParentController() const {
696     return mLoadInfo.mParentController;
697   }
698 
GetChannelInfo()699   const ChannelInfo& GetChannelInfo() const { return mLoadInfo.mChannelInfo; }
700 
SetChannelInfo(const ChannelInfo & aChannelInfo)701   void SetChannelInfo(const ChannelInfo& aChannelInfo) {
702     AssertIsOnMainThread();
703     MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized());
704     MOZ_ASSERT(aChannelInfo.IsInitialized());
705     mLoadInfo.mChannelInfo = aChannelInfo;
706   }
707 
InitChannelInfo(nsIChannel * aChannel)708   void InitChannelInfo(nsIChannel* aChannel) {
709     mLoadInfo.mChannelInfo.InitFromChannel(aChannel);
710   }
711 
InitChannelInfo(const ChannelInfo & aChannelInfo)712   void InitChannelInfo(const ChannelInfo& aChannelInfo) {
713     mLoadInfo.mChannelInfo = aChannelInfo;
714   }
715 
GetPrincipal()716   nsIPrincipal* GetPrincipal() const {
717     AssertIsOnMainThread();
718     return mLoadInfo.mPrincipal;
719   }
720 
GetLoadingPrincipal()721   nsIPrincipal* GetLoadingPrincipal() const {
722     AssertIsOnMainThread();
723     return mLoadInfo.mLoadingPrincipal;
724   }
725 
GetPartitionedPrincipal()726   nsIPrincipal* GetPartitionedPrincipal() const {
727     AssertIsOnMainThread();
728     return mLoadInfo.mPartitionedPrincipal;
729   }
730 
OriginNoSuffix()731   const nsAString& OriginNoSuffix() const { return mLoadInfo.mOriginNoSuffix; }
732 
Origin()733   const nsACString& Origin() const { return mLoadInfo.mOrigin; }
734 
735   const nsACString& EffectiveStoragePrincipalOrigin() const;
736 
GetLoadGroup()737   nsILoadGroup* GetLoadGroup() const {
738     AssertIsOnMainThread();
739     return mLoadInfo.mLoadGroup;
740   }
741 
UsesSystemPrincipal()742   bool UsesSystemPrincipal() const { return mLoadInfo.mPrincipalIsSystem; }
UsesAddonOrExpandedAddonPrincipal()743   bool UsesAddonOrExpandedAddonPrincipal() const {
744     return mLoadInfo.mPrincipalIsAddonOrExpandedAddon;
745   }
746 
GetPrincipalInfo()747   const mozilla::ipc::PrincipalInfo& GetPrincipalInfo() const {
748     return *mLoadInfo.mPrincipalInfo;
749   }
750 
GetPartitionedPrincipalInfo()751   const mozilla::ipc::PrincipalInfo& GetPartitionedPrincipalInfo() const {
752     return *mLoadInfo.mPartitionedPrincipalInfo;
753   }
754 
GetPrincipalHashValue()755   uint32_t GetPrincipalHashValue() const {
756     return mLoadInfo.mPrincipalHashValue;
757   }
758 
759   const mozilla::ipc::PrincipalInfo& GetEffectiveStoragePrincipalInfo() const;
760 
ForgetWorkerChannel()761   already_AddRefed<nsIChannel> ForgetWorkerChannel() {
762     AssertIsOnMainThread();
763     return mLoadInfo.mChannel.forget();
764   }
765 
GetWindow()766   nsPIDOMWindowInner* GetWindow() const {
767     AssertIsOnMainThread();
768     return mLoadInfo.mWindow;
769   }
770 
771   nsPIDOMWindowInner* GetAncestorWindow() const;
772 
GetCSP()773   nsIContentSecurityPolicy* GetCSP() const {
774     AssertIsOnMainThread();
775     return mLoadInfo.mCSP;
776   }
777 
778   void SetCSP(nsIContentSecurityPolicy* aCSP);
779 
780   nsresult SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
781                                   const nsACString& aCSPReportOnlyHeaderValue);
782 
783   void StoreCSPOnClient();
784 
GetCSPInfo()785   const mozilla::ipc::CSPInfo& GetCSPInfo() const {
786     return *mLoadInfo.mCSPInfo;
787   }
788 
789   void UpdateReferrerInfoFromHeader(
790       const nsACString& aReferrerPolicyHeaderValue);
791 
GetReferrerInfo()792   nsIReferrerInfo* GetReferrerInfo() const { return mLoadInfo.mReferrerInfo; }
793 
GetReferrerPolicy()794   ReferrerPolicy GetReferrerPolicy() const {
795     return mLoadInfo.mReferrerInfo->ReferrerPolicy();
796   }
797 
SetReferrerInfo(nsIReferrerInfo * aReferrerInfo)798   void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
799     mLoadInfo.mReferrerInfo = aReferrerInfo;
800   }
801 
IsEvalAllowed()802   bool IsEvalAllowed() const { return mLoadInfo.mEvalAllowed; }
803 
SetEvalAllowed(bool aEvalAllowed)804   void SetEvalAllowed(bool aEvalAllowed) {
805     mLoadInfo.mEvalAllowed = aEvalAllowed;
806   }
807 
GetReportCSPViolations()808   bool GetReportCSPViolations() const { return mLoadInfo.mReportCSPViolations; }
809 
SetReportCSPViolations(bool aReport)810   void SetReportCSPViolations(bool aReport) {
811     mLoadInfo.mReportCSPViolations = aReport;
812   }
813 
XHRParamsAllowed()814   bool XHRParamsAllowed() const { return mLoadInfo.mXHRParamsAllowed; }
815 
SetXHRParamsAllowed(bool aAllowed)816   void SetXHRParamsAllowed(bool aAllowed) {
817     mLoadInfo.mXHRParamsAllowed = aAllowed;
818   }
819 
StorageAccess()820   mozilla::StorageAccess StorageAccess() const {
821     AssertIsOnWorkerThread();
822     if (mLoadInfo.mHasStorageAccessPermissionGranted) {
823       return mozilla::StorageAccess::eAllow;
824     }
825 
826     return mLoadInfo.mStorageAccess;
827   }
828 
UseRegularPrincipal()829   bool UseRegularPrincipal() const {
830     AssertIsOnWorkerThread();
831     return mLoadInfo.mUseRegularPrincipal;
832   }
833 
HasStorageAccessPermissionGranted()834   bool HasStorageAccessPermissionGranted() const {
835     AssertIsOnWorkerThread();
836     return mLoadInfo.mHasStorageAccessPermissionGranted;
837   }
838 
CookieJarSettings()839   nsICookieJarSettings* CookieJarSettings() const {
840     // Any thread.
841     MOZ_ASSERT(mLoadInfo.mCookieJarSettings);
842     return mLoadInfo.mCookieJarSettings;
843   }
844 
GetOriginAttributes()845   const OriginAttributes& GetOriginAttributes() const {
846     return mLoadInfo.mOriginAttributes;
847   }
848 
849   // Determine if the SW testing per-window flag is set by devtools
ServiceWorkersTestingInWindow()850   bool ServiceWorkersTestingInWindow() const {
851     return mLoadInfo.mServiceWorkersTestingInWindow;
852   }
853 
ShouldResistFingerprinting()854   bool ShouldResistFingerprinting() const {
855     return mLoadInfo.mShouldResistFingerprinting;
856   }
857 
858   // Determin if the worker was created under a third-party context.
IsThirdPartyContextToTopWindow()859   bool IsThirdPartyContextToTopWindow() const {
860     return mLoadInfo.mIsThirdPartyContextToTopWindow;
861   }
862 
IsWatchedByDevTools()863   bool IsWatchedByDevTools() const { return mLoadInfo.mWatchedByDevTools; }
864 
865   // Determine if the worker is currently loading its top level script.
IsLoadingWorkerScript()866   bool IsLoadingWorkerScript() const { return mLoadingWorkerScript; }
867 
868   // Called by ScriptLoader to track when this worker is loading its
869   // top level script.
SetLoadingWorkerScript(bool aLoadingWorkerScript)870   void SetLoadingWorkerScript(bool aLoadingWorkerScript) {
871     // any thread
872     mLoadingWorkerScript = aLoadingWorkerScript;
873   }
874 
875   RemoteWorkerChild* GetRemoteWorkerController();
876 
877   void SetRemoteWorkerController(RemoteWorkerChild* aController);
878 
879   void SetRemoteWorkerControllerWeakRef(
880       ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef);
881 
882   ThreadSafeWeakPtr<RemoteWorkerChild> GetRemoteWorkerControllerWeakRef();
883 
884   RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag();
885 
886   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
887   // as these are only used for globals going in and out of the bfcache.
888   bool Freeze(const nsPIDOMWindowInner* aWindow);
889 
890   bool Thaw(const nsPIDOMWindowInner* aWindow);
891 
892   void PropagateStorageAccessPermissionGranted();
893 
894   void EnableDebugger();
895 
896   void DisableDebugger();
897 
898   already_AddRefed<WorkerRunnable> MaybeWrapAsWorkerRunnable(
899       already_AddRefed<nsIRunnable> aRunnable);
900 
901   bool ProxyReleaseMainThreadObjects();
902 
903   void SetLowMemoryState(bool aState);
904 
905   void GarbageCollect(bool aShrinking);
906 
907   void CycleCollect();
908 
909   nsresult SetPrincipalsAndCSPOnMainThread(nsIPrincipal* aPrincipal,
910                                            nsIPrincipal* aPartitionedPrincipal,
911                                            nsILoadGroup* aLoadGroup,
912                                            nsIContentSecurityPolicy* aCsp);
913 
914   nsresult SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel);
915 
916   bool FinalChannelPrincipalIsValid(nsIChannel* aChannel);
917 
918 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
919   bool PrincipalURIMatchesScriptURL();
920 #endif
921 
922   void UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
923 
924   void WorkerScriptLoaded();
925 
926   Document* GetDocument() const;
927 
928   void MemoryPressure();
929 
930   void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
931 
932   void UpdateLanguages(const nsTArray<nsString>& aLanguages);
933 
934   void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
935 
936 #ifdef JS_GC_ZEAL
937   void UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency);
938 #endif
939 
940   void OfflineStatusChangeEvent(bool aIsOffline);
941 
942   nsresult Dispatch(already_AddRefed<WorkerRunnable> aRunnable,
943                     nsIEventTarget* aSyncLoopTarget = nullptr);
944 
945   nsresult DispatchControlRunnable(
946       already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable);
947 
948   nsresult DispatchDebuggerRunnable(
949       already_AddRefed<WorkerRunnable> aDebuggerRunnable);
950 
951 #ifdef DEBUG
952   void AssertIsOnParentThread() const;
953 
954   void AssertInnerWindowIsCorrect() const;
955 #else
AssertIsOnParentThread()956   void AssertIsOnParentThread() const {}
957 
AssertInnerWindowIsCorrect()958   void AssertInnerWindowIsCorrect() const {}
959 #endif
960 
961 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
962   bool PrincipalIsValid() const;
963 #endif
964 
965   void StartCancelingTimer();
966 
967   const nsAString& Id();
968 
AgentClusterId()969   const nsID& AgentClusterId() const { return mAgentClusterId; }
970 
971   bool IsSharedMemoryAllowed() const;
972 
973   // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
974   bool CrossOriginIsolated() const;
975 
SetUseCounter(UseCounterWorker aUseCounter)976   void SetUseCounter(UseCounterWorker aUseCounter) {
977     MOZ_ASSERT(!mReportedUseCounters);
978     MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown);
979     AssertIsOnWorkerThread();
980     mUseCounters[static_cast<size_t>(aUseCounter)] = true;
981   }
982 
983   /**
984    * COEP Methods
985    *
986    * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods
987    * will, depending on the return type, return a value that will avoid
988    * assertion failures or a value that won't block loads.
989    */
990   nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const;
991 
992   // Fails if a policy has already been set or if `aPolicy` violates the owner's
993   // policy, if an owner exists.
994   mozilla::Result<Ok, nsresult> SetEmbedderPolicy(
995       nsILoadInfo::CrossOriginEmbedderPolicy aPolicy);
996 
997   // `aRequest` is the request loading the worker and must be QI-able to
998   // `nsIChannel*`. It's used to verify that the worker can indeed inherit its
999   // owner's COEP (when an owner exists).
1000   //
1001   // TODO: remove `aRequest`; currently, it's required because instances may not
1002   // always know its final, resolved script URL or have access internally to
1003   // `aRequest`.
1004   void InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest);
1005 
1006   // Requires a policy to already have been set.
1007   bool MatchEmbedderPolicy(
1008       nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const;
1009 
1010   nsILoadInfo::CrossOriginEmbedderPolicy GetOwnerEmbedderPolicy() const;
1011 
1012   void SetCCCollectedAnything(bool collectedAnything);
1013 
GetCurrentTimerNestingLevel()1014   uint32_t GetCurrentTimerNestingLevel() const {
1015     auto data = mWorkerThreadAccessible.Access();
1016     return data->mCurrentTimerNestingLevel;
1017   }
1018 
IncreaseTopLevelWorkerFinishedRunnableCount()1019   void IncreaseTopLevelWorkerFinishedRunnableCount() {
1020     ++mTopLevelWorkerFinishedRunnableCount;
1021   }
DecreaseTopLevelWorkerFinishedRunnableCount()1022   void DecreaseTopLevelWorkerFinishedRunnableCount() {
1023     --mTopLevelWorkerFinishedRunnableCount;
1024   }
IncreaseWorkerFinishedRunnableCount()1025   void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount; }
DecreaseWorkerFinishedRunnableCount()1026   void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount; }
1027 
1028  private:
1029   WorkerPrivate(
1030       WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
1031       WorkerKind aWorkerKind, const nsAString& aWorkerName,
1032       const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo,
1033       nsString&& aId, const nsID& aAgentClusterId,
1034       const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy);
1035 
1036   ~WorkerPrivate();
1037 
1038   struct AgentClusterIdAndCoop {
1039     nsID mId;
1040     nsILoadInfo::CrossOriginOpenerPolicy mCoop;
1041   };
1042 
1043   static AgentClusterIdAndCoop ComputeAgentClusterIdAndCoop(
1044       WorkerPrivate* aParent, WorkerKind aWorkerKind,
1045       WorkerLoadInfo* aLoadInfo);
1046 
MayContinueRunning()1047   bool MayContinueRunning() {
1048     AssertIsOnWorkerThread();
1049 
1050     WorkerStatus status;
1051     {
1052       MutexAutoLock lock(mMutex);
1053       status = mStatus;
1054     }
1055 
1056     if (status < Canceling) {
1057       return true;
1058     }
1059 
1060     return false;
1061   }
1062 
1063   void CancelAllTimeouts();
1064 
1065   enum class ProcessAllControlRunnablesResult {
1066     // We did not process anything.
1067     Nothing,
1068     // We did process something, states may have changed, but we can keep
1069     // executing script.
1070     MayContinue,
1071     // We did process something, and should not continue executing script.
1072     Abort
1073   };
1074 
ProcessAllControlRunnables()1075   ProcessAllControlRunnablesResult ProcessAllControlRunnables() {
1076     MutexAutoLock lock(mMutex);
1077     return ProcessAllControlRunnablesLocked();
1078   }
1079 
1080   ProcessAllControlRunnablesResult ProcessAllControlRunnablesLocked();
1081 
1082   void EnableMemoryReporter();
1083 
1084   void DisableMemoryReporter();
1085 
1086   void WaitForWorkerEvents();
1087 
1088   // If the worker shutdown status is equal or greater then aFailStatus, this
1089   // operation will fail and nullptr will be returned. See WorkerStatus.h for
1090   // more information about the correct value to use.
1091   already_AddRefed<nsIEventTarget> CreateNewSyncLoop(WorkerStatus aFailStatus);
1092 
1093   bool RunCurrentSyncLoop();
1094 
1095   bool DestroySyncLoop(uint32_t aLoopIndex);
1096 
1097   void InitializeGCTimers();
1098 
1099   enum GCTimerMode { PeriodicTimer = 0, IdleTimer, NoTimer };
1100 
1101   void SetGCTimerMode(GCTimerMode aMode);
1102 
1103   void ShutdownGCTimers();
1104 
1105   friend class WorkerRef;
1106 
1107   bool AddWorkerRef(WorkerRef* aWorkerRefer, WorkerStatus aFailStatus);
1108 
1109   void RemoveWorkerRef(WorkerRef* aWorkerRef);
1110 
1111   void NotifyWorkerRefs(WorkerStatus aStatus);
1112 
HasActiveWorkerRefs()1113   bool HasActiveWorkerRefs() {
1114     auto data = mWorkerThreadAccessible.Access();
1115     return !(data->mChildWorkers.IsEmpty() && data->mTimeouts.IsEmpty() &&
1116              data->mWorkerRefs.IsEmpty());
1117   }
1118 
1119   // Internal logic to dispatch a runnable. This is separate from Dispatch()
1120   // to allow runnables to be atomically dispatched in bulk.
1121   nsresult DispatchLockHeld(already_AddRefed<WorkerRunnable> aRunnable,
1122                             nsIEventTarget* aSyncLoopTarget,
1123                             const MutexAutoLock& aProofOfLock);
1124 
1125   // This method dispatches a simple runnable that starts the shutdown procedure
1126   // after a self.close(). This method is called after a ClearMainEventQueue()
1127   // to be sure that the canceling runnable is the only one in the queue.  We
1128   // need this async operation to be sure that all the current JS code is
1129   // executed.
1130   void DispatchCancelingRunnable();
1131 
GetUseCounter(UseCounterWorker aUseCounter)1132   bool GetUseCounter(UseCounterWorker aUseCounter) {
1133     MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown);
1134     AssertIsOnWorkerThread();
1135     return mUseCounters[static_cast<size_t>(aUseCounter)];
1136   }
1137 
1138   void ReportUseCounters();
1139 
1140   UniquePtr<ClientSource> CreateClientSource();
1141 
1142   // This method is called when corresponding script loader processes the COEP
1143   // header for the worker.
1144   // This method should be called only once in the main thread.
1145   // After this method is called the COEP value owner(window/parent worker) is
1146   // cached in mOwnerEmbedderPolicy such that it can be accessed in other
1147   // threads, i.e. WorkerThread.
1148   void EnsureOwnerEmbedderPolicy();
1149 
1150   class EventTarget;
1151   friend class EventTarget;
1152   friend class AutoSyncLoopHolder;
1153 
1154   struct TimeoutInfo;
1155 
1156   class MemoryReporter;
1157   friend class MemoryReporter;
1158 
1159   friend class mozilla::dom::WorkerThread;
1160 
1161   SharedMutex mMutex;
1162   mozilla::CondVar mCondVar;
1163 
1164   // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1165   // our static assert
1166   MOZ_NON_OWNING_REF WorkerPrivate* const mParent;
1167 
1168   const nsString mScriptURL;
1169 
1170   // This is the worker name for shared workers and dedicated workers.
1171   const nsString mWorkerName;
1172 
1173   const WorkerKind mWorkerKind;
1174 
1175   // The worker is owned by its thread, which is represented here.  This is set
1176   // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
1177   // traversed by the cycle collector if the busy count is zero.
1178   //
1179   // There are 4 ways a worker can be terminated:
1180   // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
1181   //    traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
1182   //    Worker webidl object. Doing this, CC will be able to detect a cycle and
1183   //    Unlink is called. In Unlink, Worker calls Cancel().
1184   // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
1185   // 3. WorkerScope::Close() is called - Similar to point 2.
1186   // 4. xpcom-shutdown notification - We call Kill().
1187   RefPtr<Worker> mParentEventTargetRef;
1188   RefPtr<WorkerPrivate> mSelfRef;
1189 
1190   // The lifetime of these objects within LoadInfo is managed explicitly;
1191   // they do not need to be cycle collected.
1192   WorkerLoadInfo mLoadInfo;
1193   LocationInfo mLocationInfo;
1194 
1195   // Protected by mMutex.
1196   workerinternals::JSSettings mJSSettings;
1197 
1198   WorkerDebugger* mDebugger;
1199 
1200   workerinternals::Queue<WorkerControlRunnable*, 4> mControlQueue;
1201   workerinternals::Queue<WorkerRunnable*, 4> mDebuggerQueue;
1202 
1203   JSContext* mJSContext;
1204   RefPtr<WorkerThread> mThread;
1205   // Touched on multiple threads, protected with mMutex. Only modified on the
1206   // worker thread
1207   // mThread is only modified on the Worker thread, before calling DoRunLoop
1208   // mPRThread is only modified on another thread in ScheduleWorker(), and is
1209   // constant for the duration of DoRunLoop.  Static mutex analysis doesn't help
1210   // here
1211   PRThread* mPRThread;
1212 
1213   // Accessed from main thread
1214   RefPtr<ThrottledEventQueue> mMainThreadEventTargetForMessaging;
1215   RefPtr<ThrottledEventQueue> mMainThreadEventTarget;
1216 
1217   // Accessed from worker thread and destructing thread
1218   RefPtr<WorkerEventTarget> mWorkerControlEventTarget;
1219   RefPtr<WorkerEventTarget> mWorkerHybridEventTarget;
1220 
1221   // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
1222   // See WorkerDebuggeeRunnable for details.
1223   RefPtr<ThrottledEventQueue> mMainThreadDebuggeeEventTarget;
1224 
1225   struct SyncLoopInfo {
1226     explicit SyncLoopInfo(EventTarget* aEventTarget);
1227 
1228     RefPtr<EventTarget> mEventTarget;
1229     bool mCompleted;
1230     bool mResult;
1231 #ifdef DEBUG
1232     bool mHasRun;
1233 #endif
1234   };
1235 
1236   // This is only modified on the worker thread, but in DEBUG builds
1237   // AssertValidSyncLoop function iterates it on other threads. Therefore
1238   // modifications are done with mMutex held *only* in DEBUG builds.
1239   nsTArray<UniquePtr<SyncLoopInfo>> mSyncLoopStack;
1240 
1241   nsCOMPtr<nsITimer> mCancelingTimer;
1242 
1243   // fired on the main thread if the worker script fails to load
1244   nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
1245 
1246   RefPtr<PerformanceStorage> mPerformanceStorage;
1247 
1248   RefPtr<WorkerCSPEventListener> mCSPEventListener;
1249 
1250   // Protected by mMutex.
1251   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
1252 
1253   // Only touched on the parent thread. This is set only if IsSharedWorker().
1254   RefPtr<RemoteWorkerChild> mRemoteWorkerController;
1255 
1256   // This is set only if IsServiceWorker().
1257   ThreadSafeWeakPtr<RemoteWorkerChild> mRemoteWorkerControllerWeakRef;
1258 
1259   JS::UniqueChars mDefaultLocale;  // nulled during worker JSContext init
1260   TimeStamp mKillTime;
1261   WorkerStatus mParentStatus;
1262   WorkerStatus mStatus;
1263 
1264   // This is touched on parent thread only, but it can be read on a different
1265   // thread before crashing because hanging.
1266   Atomic<uint64_t> mBusyCount;
1267 
1268   Atomic<bool> mLoadingWorkerScript;
1269 
1270   TimeStamp mCreationTimeStamp;
1271   DOMHighResTimeStamp mCreationTimeHighRes;
1272 
1273   // Flags for use counters used directly by this worker.
1274   static_assert(sizeof(UseCounterWorker) <= sizeof(size_t),
1275                 "UseCounterWorker is too big");
1276   static_assert(UseCounterWorker::Count >= static_cast<UseCounterWorker>(0),
1277                 "Should be non-negative value and safe to cast to unsigned");
1278   std::bitset<static_cast<size_t>(UseCounterWorker::Count)> mUseCounters;
1279   bool mReportedUseCounters;
1280 
1281   // This is created while creating the WorkerPrivate, so it's safe to be
1282   // touched on any thread.
1283   const nsID mAgentClusterId;
1284 
1285   // Things touched on worker thread only.
1286   struct WorkerThreadAccessible {
1287     explicit WorkerThreadAccessible(WorkerPrivate* aParent);
1288 
1289     RefPtr<WorkerGlobalScope> mScope;
1290     RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
1291     // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1292     // our static assert
1293     nsTArray<WorkerPrivate*> mChildWorkers;
1294     nsTObserverArray<WorkerRef*> mWorkerRefs;
1295     nsTArray<UniquePtr<TimeoutInfo>> mTimeouts;
1296 
1297     nsCOMPtr<nsITimer> mTimer;
1298     nsCOMPtr<nsITimerCallback> mTimerRunnable;
1299 
1300     nsCOMPtr<nsITimer> mGCTimer;
1301 
1302     RefPtr<MemoryReporter> mMemoryReporter;
1303 
1304     // While running a nested event loop, whether a sync loop or a debugger
1305     // event loop we want to keep track of which global is running it, if any,
1306     // so runnables that run off that event loop can get at that information. In
1307     // practice this only matters for various worker debugger runnables running
1308     // against sandboxes, because all other runnables know which globals they
1309     // belong to already.  We could also address this by threading the relevant
1310     // global through the chains of runnables involved, but we'd need to thread
1311     // it through some runnables that run on the main thread, and that would
1312     // require some care to make sure things get released on the correct thread,
1313     // which we'd rather avoid.  This member is only accessed on the worker
1314     // thread.
1315     nsCOMPtr<nsIGlobalObject> mCurrentEventLoopGlobal;
1316 
1317     // Timer that triggers an interrupt on expiration of the current time slice
1318     nsCOMPtr<nsITimer> mTSTimer;
1319 
1320     // Execution manager used to regulate execution for this worker.
1321     RefPtr<JSExecutionManager> mExecutionManager;
1322 
1323     // Used to relinguish clearance for CTypes Callbacks.
1324     nsTArray<AutoYieldJSThreadExecution> mYieldJSThreadExecution;
1325 
1326     uint32_t mNumWorkerRefsPreventingShutdownStart;
1327     uint32_t mDebuggerEventLoopLevel;
1328 
1329     uint32_t mErrorHandlerRecursionCount;
1330     int32_t mNextTimeoutId;
1331 
1332     // Tracks the current setTimeout/setInterval nesting level.
1333     // When there isn't a TimeoutHandler on the stack, this will be 0.
1334     // Whenever setTimeout/setInterval are called, a new TimeoutInfo will be
1335     // created with a nesting level one more than the current nesting level,
1336     // saturating at the kClampTimeoutNestingLevel.
1337     //
1338     // When RunExpiredTimeouts is run, it sets this value to the
1339     // TimeoutInfo::mNestingLevel for the duration of
1340     // the WorkerScriptTimeoutHandler::Call which will explicitly trigger a
1341     // microtask checkpoint so that any immediately-resolved promises will
1342     // still see the nesting level.
1343     uint32_t mCurrentTimerNestingLevel;
1344 
1345     bool mFrozen;
1346     bool mTimerRunning;
1347     bool mRunningExpiredTimeouts;
1348     bool mPeriodicGCTimerRunning;
1349     bool mIdleGCTimerRunning;
1350     bool mOnLine;
1351     bool mJSThreadExecutionGranted;
1352     bool mCCCollectedAnything;
1353     FlippedOnce<false> mDeletionScheduled;
1354   };
1355   ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
1356 
1357   class MOZ_RAII AutoPushEventLoopGlobal {
1358    public:
1359     AutoPushEventLoopGlobal(WorkerPrivate* aWorkerPrivate, JSContext* aCx);
1360     ~AutoPushEventLoopGlobal();
1361 
1362    private:
1363     // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1364     // our static assert
1365     MOZ_NON_OWNING_REF WorkerPrivate* mWorkerPrivate;
1366     nsCOMPtr<nsIGlobalObject> mOldEventLoopGlobal;
1367   };
1368   friend class AutoPushEventLoopGlobal;
1369 
1370   uint32_t mPostSyncLoopOperations;
1371 
1372   // List of operations to do at the end of the last sync event loop.
1373   enum {
1374     ePendingEventQueueClearing = 0x01,
1375     eDispatchCancelingRunnable = 0x02,
1376   };
1377 
1378   bool mParentWindowPaused;
1379 
1380   bool mCancelAllPendingRunnables;
1381   bool mWorkerScriptExecutedSuccessfully;
1382   bool mFetchHandlerWasAdded;
1383   bool mMainThreadObjectsForgotten;
1384   bool mIsChromeWorker;
1385   bool mParentFrozen;
1386 
1387   // mIsSecureContext is set once in our constructor; after that it can be read
1388   // from various threads.
1389   //
1390   // It's a bit unfortunate that we have to have an out-of-band boolean for
1391   // this, but we need access to this state from the parent thread, and we can't
1392   // use our global object's secure state there.
1393   const bool mIsSecureContext;
1394 
1395   bool mDebuggerRegistered;
1396 
1397   // During registration, this worker may be marked as not being ready to
1398   // execute debuggee runnables or content.
1399   //
1400   // Protected by mMutex.
1401   bool mDebuggerReady;
1402   nsTArray<RefPtr<WorkerRunnable>> mDelayedDebuggeeRunnables;
1403 
1404   // Whether this worker should have access to the WebExtension API bindings
1405   // (currently only the Extension Background ServiceWorker declared in the
1406   // extension manifest is allowed to access any WebExtension API bindings).
1407   // This default to false, and it is eventually set to true by
1408   // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions
1409   // are met.
1410   bool mExtensionAPIAllowed;
1411 
1412   // mIsInAutomation is true when we're running in test automation.
1413   // We expose some extra testing functions in that case.
1414   bool mIsInAutomation;
1415 
1416   const RefPtr<mozilla::PerformanceCounter> mPerformanceCounter =
1417       MakeRefPtr<mozilla::PerformanceCounter>(nsPrintfCString(
1418           "Worker:%s", NS_ConvertUTF16toUTF8(mWorkerName).get()));
1419 
1420   nsString mId;
1421 
1422   // This is used to check if it's allowed to share the memory across the agent
1423   // cluster.
1424   const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy;
1425 
1426   // Member variable of this class rather than the worker global scope because
1427   // it's received on the main thread, but the global scope is thread-bound
1428   // to the worker thread, so storing the value in the global scope would
1429   // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and
1430   // there isn't a strong reason to store it on the global scope other than
1431   // better consistency with the COEP spec.
1432   Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy;
1433   Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mOwnerEmbedderPolicy;
1434 
1435   /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal
1436    * on the main thread when constructing a top-level worker. The flag is
1437    * propagated to nested workers. The flag is only allowed to take effect in
1438    * extension processes and is forbidden in content scripts in content
1439    * processes. The flag may be read on either the parent/owner thread as well
1440    * as on the worker thread itself. When bug 1443925 is fixed allowing
1441    * nsIPrincipal to be used OMT, it may be possible to remove this flag. */
1442   bool mIsPrivilegedAddonGlobal;
1443 
1444   Atomic<uint32_t> mTopLevelWorkerFinishedRunnableCount;
1445   Atomic<uint32_t> mWorkerFinishedRunnableCount;
1446 };
1447 
1448 class AutoSyncLoopHolder {
1449   CheckedUnsafePtr<WorkerPrivate> mWorkerPrivate;
1450   nsCOMPtr<nsIEventTarget> mTarget;
1451   uint32_t mIndex;
1452 
1453  public:
1454   // See CreateNewSyncLoop() for more information about the correct value to use
1455   // for aFailStatus.
AutoSyncLoopHolder(WorkerPrivate * aWorkerPrivate,WorkerStatus aFailStatus)1456   AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus)
1457       : mWorkerPrivate(aWorkerPrivate),
1458         mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus)),
1459         mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1) {
1460     aWorkerPrivate->AssertIsOnWorkerThread();
1461   }
1462 
~AutoSyncLoopHolder()1463   ~AutoSyncLoopHolder() {
1464     if (mWorkerPrivate && mTarget) {
1465       mWorkerPrivate->AssertIsOnWorkerThread();
1466       mWorkerPrivate->StopSyncLoop(mTarget, false);
1467       mWorkerPrivate->DestroySyncLoop(mIndex);
1468     }
1469   }
1470 
Run()1471   bool Run() {
1472     CheckedUnsafePtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
1473     mWorkerPrivate = nullptr;
1474 
1475     workerPrivate->AssertIsOnWorkerThread();
1476 
1477     return workerPrivate->RunCurrentSyncLoop();
1478   }
1479 
GetEventTarget()1480   nsIEventTarget* GetEventTarget() const {
1481     // This can be null if CreateNewSyncLoop() fails.
1482     return mTarget;
1483   }
1484 };
1485 
1486 }  // namespace dom
1487 }  // namespace mozilla
1488 
1489 #endif /* mozilla_dom_workers_workerprivate_h__ */
1490