forked from mirrors/gecko-dev
		
	 5f68f357b0
			
		
	
	
		5f68f357b0
		
	
	
	
	
		
			
			Backed out changeset d46945ada9ec (bug 1821250) Backed out changeset 94145877428a (bug 1821250)
		
			
				
	
	
		
			1666 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1666 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifndef mozilla_dom_workers_workerprivate_h__
 | |
| #define mozilla_dom_workers_workerprivate_h__
 | |
| 
 | |
| #include <bitset>
 | |
| #include "MainThreadUtils.h"
 | |
| #include "ScriptLoader.h"
 | |
| #include "js/ContextOptions.h"
 | |
| #include "mozilla/Attributes.h"
 | |
| #include "mozilla/AutoRestore.h"
 | |
| #include "mozilla/BasePrincipal.h"
 | |
| #include "mozilla/CondVar.h"
 | |
| #include "mozilla/DOMEventTargetHelper.h"
 | |
| #include "mozilla/Maybe.h"
 | |
| #include "mozilla/MozPromise.h"
 | |
| #include "mozilla/OriginTrials.h"
 | |
| #include "mozilla/RelativeTimeline.h"
 | |
| #include "mozilla/Result.h"
 | |
| #include "mozilla/StorageAccess.h"
 | |
| #include "mozilla/ThreadBound.h"
 | |
| #include "mozilla/ThreadSafeWeakPtr.h"
 | |
| #include "mozilla/UniquePtr.h"
 | |
| #include "mozilla/UseCounter.h"
 | |
| #include "mozilla/dom/ClientSource.h"
 | |
| #include "mozilla/dom/FlippedOnce.h"
 | |
| #include "mozilla/dom/Timeout.h"
 | |
| #include "mozilla/dom/quota/CheckedUnsafePtr.h"
 | |
| #include "mozilla/dom/Worker.h"
 | |
| #include "mozilla/dom/WorkerBinding.h"
 | |
| #include "mozilla/dom/WorkerCommon.h"
 | |
| #include "mozilla/dom/WorkerLoadInfo.h"
 | |
| #include "mozilla/dom/WorkerStatus.h"
 | |
| #include "mozilla/dom/workerinternals/JSSettings.h"
 | |
| #include "mozilla/dom/workerinternals/Queue.h"
 | |
| #include "mozilla/dom/JSExecutionManager.h"
 | |
| #include "mozilla/net/NeckoChannelParams.h"
 | |
| #include "mozilla/StaticPrefs_extensions.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsIChannel.h"
 | |
| #include "nsIContentSecurityPolicy.h"
 | |
| #include "nsIEventTarget.h"
 | |
| #include "nsILoadInfo.h"
 | |
| #include "nsRFPService.h"
 | |
| #include "nsTObserverArray.h"
 | |
| #include "stdint.h"
 | |
| 
 | |
| class nsIThreadInternal;
 | |
| 
 | |
| namespace JS {
 | |
| struct RuntimeStats;
 | |
| }
 | |
| 
 | |
| namespace mozilla {
 | |
| class ThrottledEventQueue;
 | |
| namespace dom {
 | |
| 
 | |
| class RemoteWorkerChild;
 | |
| 
 | |
| // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
 | |
| // to be updated too. And histograms enum for worker use counters uses the same
 | |
| // order of worker kind. Please also update dom/base/usecounters.py.
 | |
| enum WorkerKind : uint8_t {
 | |
|   WorkerKindDedicated,
 | |
|   WorkerKindShared,
 | |
|   WorkerKindService
 | |
| };
 | |
| 
 | |
| class ClientInfo;
 | |
| class ClientSource;
 | |
| class Function;
 | |
| class JSExecutionManager;
 | |
| class MessagePort;
 | |
| class UniqueMessagePortId;
 | |
| class PerformanceStorage;
 | |
| class TimeoutHandler;
 | |
| class WorkerControlRunnable;
 | |
| class WorkerCSPEventListener;
 | |
| class WorkerDebugger;
 | |
| class WorkerDebuggerGlobalScope;
 | |
| class WorkerErrorReport;
 | |
| class WorkerEventTarget;
 | |
| class WorkerGlobalScope;
 | |
| class WorkerRef;
 | |
| class WorkerRunnable;
 | |
| class WorkerDebuggeeRunnable;
 | |
| class WorkerThread;
 | |
| 
 | |
| // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
 | |
| // object. It exists to avoid changing a lot of code to use Mutex* instead of
 | |
| // Mutex&.
 | |
| class MOZ_CAPABILITY("mutex") SharedMutex {
 | |
|   using Mutex = mozilla::Mutex;
 | |
| 
 | |
|   class MOZ_CAPABILITY("mutex") RefCountedMutex final : public Mutex {
 | |
|    public:
 | |
|     explicit RefCountedMutex(const char* aName) : Mutex(aName) {}
 | |
| 
 | |
|     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex)
 | |
| 
 | |
|    private:
 | |
|     ~RefCountedMutex() = default;
 | |
|   };
 | |
| 
 | |
|   const RefPtr<RefCountedMutex> mMutex;
 | |
| 
 | |
|  public:
 | |
|   explicit SharedMutex(const char* aName)
 | |
|       : mMutex(new RefCountedMutex(aName)) {}
 | |
| 
 | |
|   SharedMutex(const SharedMutex& aOther) = default;
 | |
| 
 | |
|   operator Mutex&() MOZ_RETURN_CAPABILITY(this) { return *mMutex; }
 | |
| 
 | |
|   operator const Mutex&() const MOZ_RETURN_CAPABILITY(this) { return *mMutex; }
 | |
| 
 | |
|   // We need these to make thread-safety analysis work
 | |
|   void Lock() MOZ_CAPABILITY_ACQUIRE() { mMutex->Lock(); }
 | |
|   void Unlock() MOZ_CAPABILITY_RELEASE() { mMutex->Unlock(); }
 | |
| 
 | |
|   // We can assert we own 'this', but we can't assert we hold mMutex
 | |
|   void AssertCurrentThreadOwns() const
 | |
|       MOZ_ASSERT_CAPABILITY(this) MOZ_NO_THREAD_SAFETY_ANALYSIS {
 | |
|     mMutex->AssertCurrentThreadOwns();
 | |
|   }
 | |
| };
 | |
| 
 | |
| nsString ComputeWorkerPrivateId();
 | |
| 
 | |
| class WorkerPrivate final
 | |
|     : public RelativeTimeline,
 | |
|       public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> {
 | |
|  public:
 | |
|   // Callback invoked on the parent thread when the worker's cancellation is
 | |
|   // about to be requested.  This covers both calls to
 | |
|   // WorkerPrivate::Cancel() by the owner as well as self-initiated cancellation
 | |
|   // due to top-level script evaluation failing or close() being invoked on the
 | |
|   // global scope for Dedicated and Shared workers, but not Service Workers as
 | |
|   // they do not expose a close() method.
 | |
|   //
 | |
|   // ### Parent-Initiated Cancellation
 | |
|   //
 | |
|   // When WorkerPrivate::Cancel is invoked on the parent thread (by the binding
 | |
|   // exposed Worker::Terminate), this callback is invoked synchronously inside
 | |
|   // that call.
 | |
|   //
 | |
|   // ### Worker Self-Cancellation
 | |
|   //
 | |
|   // When a worker initiates self-cancellation, the worker's notification to the
 | |
|   // parent thread is a non-blocking, async mechanism triggered by
 | |
|   // `WorkerPrivate::DispatchCancelingRunnable`.
 | |
|   //
 | |
|   // Self-cancellation races a normally scheduled runnable against a timer that
 | |
|   // is scheduled against the parent.  The 2 paths initiated by
 | |
|   // DispatchCancelingRunnable are:
 | |
|   //
 | |
|   // 1. A CancelingRunnable is dispatched at the worker's normal event target to
 | |
|   //    wait for the event loop to be clear of runnables.  When the
 | |
|   //    CancelingRunnable runs it will dispatch a CancelingOnParentRunnable to
 | |
|   //    its parent which is a normal, non-control WorkerDebuggeeRunnable to
 | |
|   //    ensure that any postMessages to the parent or similar events get a
 | |
|   //    chance to be processed prior to cancellation.  The timer scheduled in
 | |
|   //    the next bullet will not be canceled unless
 | |
|   //
 | |
|   // 2. A CancelingWithTimeoutOnParentRunnable control runnable is dispatched
 | |
|   //    to the parent to schedule a timer which will (also) fire on the parent
 | |
|   //    thread.  This handles the case where the worker does not yield
 | |
|   //    control-flow, and so the normal runnable scheduled above does not get to
 | |
|   //    run in a timely fashion.  Because this is a control runnable, if the
 | |
|   //    parent is a worker then the runnable will be processed with urgency.
 | |
|   //    However, if the worker is top-level, then the control-like throttled
 | |
|   //    WorkerPrivate::mMainThreadEventTarget will end up getting used which is
 | |
|   //    nsIRunnablePriority::PRIORITY_MEDIUMHIGH and distinct from the
 | |
|   //    mMainThreadDebuggeeEventTarget which most runnables (like postMessage)
 | |
|   //    use.
 | |
|   //
 | |
|   //    The timer will explicitly use the control event target if the parent is
 | |
|   //    a worker and the implicit event target (via `NS_NewTimer()`) otherwise.
 | |
|   //    The callback is CancelingTimerCallback which just calls
 | |
|   //    WorkerPrivate::Cancel.
 | |
|   using CancellationCallback = std::function<void(bool aEverRan)>;
 | |
| 
 | |
|   // Callback invoked on the parent just prior to dropping the worker thread's
 | |
|   // strong reference that keeps the WorkerPrivate alive while the worker thread
 | |
|   // is running.  This does not provide a guarantee that the underlying thread
 | |
|   // has fully shutdown, just that the worker logic has fully shutdown.
 | |
|   //
 | |
|   // ### Details
 | |
|   //
 | |
|   // The last thing the worker thread's WorkerThreadPrimaryRunnable does before
 | |
|   // initiating the shutdown of the underlying thread is call ScheduleDeletion.
 | |
|   // ScheduleDeletion dispatches a runnable to the parent to notify it that the
 | |
|   // worker has completed its work and will never touch the WorkerPrivate again
 | |
|   // and that the strong self-reference can be dropped.
 | |
|   //
 | |
|   // For parents that are themselves workers, this will be done by
 | |
|   // WorkerFinishedRunnable which is a WorkerControlRunnable, ensuring that this
 | |
|   // is processed in a timely fashion.  For main-thread parents,
 | |
|   // TopLevelWorkerFinishedRunnable will be used and sent via
 | |
|   // mMainThreadEventTargetForMessaging which is a weird ThrottledEventQueue
 | |
|   // which does not provide any ordering guarantees relative to
 | |
|   // mMainThreadDebuggeeEventTarget, so if you want those, you need to enhance
 | |
|   // things.
 | |
|   using TerminationCallback = std::function<void(void)>;
 | |
| 
 | |
|   struct LocationInfo {
 | |
|     nsCString mHref;
 | |
|     nsCString mProtocol;
 | |
|     nsCString mHost;
 | |
|     nsCString mHostname;
 | |
|     nsCString mPort;
 | |
|     nsCString mPathname;
 | |
|     nsCString mSearch;
 | |
|     nsCString mHash;
 | |
|     nsString mOrigin;
 | |
|   };
 | |
| 
 | |
|   NS_INLINE_DECL_REFCOUNTING(WorkerPrivate)
 | |
| 
 | |
|   static already_AddRefed<WorkerPrivate> Constructor(
 | |
|       JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker,
 | |
|       WorkerKind aWorkerKind, RequestCredentials aRequestCredentials,
 | |
|       const WorkerType aWorkerType, const nsAString& aWorkerName,
 | |
|       const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo,
 | |
|       ErrorResult& aRv, nsString aId = u""_ns,
 | |
|       CancellationCallback&& aCancellationCallback = {},
 | |
|       TerminationCallback&& aTerminationCallback = {});
 | |
| 
 | |
|   enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup };
 | |
| 
 | |
|   static nsresult GetLoadInfo(
 | |
|       JSContext* aCx, nsPIDOMWindowInner* aWindow, WorkerPrivate* aParent,
 | |
|       const nsAString& aScriptURL, const enum WorkerType& aWorkerType,
 | |
|       const RequestCredentials& aCredentials, bool aIsChromeWorker,
 | |
|       LoadGroupBehavior aLoadGroupBehavior, WorkerKind aWorkerKind,
 | |
|       WorkerLoadInfo* aLoadInfo);
 | |
| 
 | |
|   void Traverse(nsCycleCollectionTraversalCallback& aCb);
 | |
| 
 | |
|   void ClearSelfAndParentEventTargetRef() {
 | |
|     AssertIsOnParentThread();
 | |
|     MOZ_ASSERT(mSelfRef);
 | |
| 
 | |
|     if (mTerminationCallback) {
 | |
|       mTerminationCallback();
 | |
|       mTerminationCallback = nullptr;
 | |
|     }
 | |
| 
 | |
|     mParentEventTargetRef = nullptr;
 | |
|     mSelfRef = nullptr;
 | |
|   }
 | |
| 
 | |
|   // May be called on any thread...
 | |
|   bool Start();
 | |
| 
 | |
|   // Called on the parent thread.
 | |
|   bool Notify(WorkerStatus aStatus);
 | |
| 
 | |
|   bool Cancel() { return Notify(Canceling); }
 | |
| 
 | |
|   bool Close() MOZ_REQUIRES(mMutex);
 | |
| 
 | |
|   // The passed principal must be the Worker principal in case of a
 | |
|   // ServiceWorker and the loading principal for any other type.
 | |
|   static void OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo,
 | |
|                                         nsIPrincipal* aPrincipal);
 | |
| 
 | |
|   bool IsDebuggerRegistered() MOZ_NO_THREAD_SAFETY_ANALYSIS {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     // No need to lock here since this is only ever modified by the same thread.
 | |
|     return mDebuggerRegistered;  // would give a thread-safety warning
 | |
|   }
 | |
| 
 | |
|   bool ExtensionAPIAllowed() {
 | |
|     return (
 | |
|         StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() &&
 | |
|         mExtensionAPIAllowed);
 | |
|   }
 | |
| 
 | |
|   void SetIsDebuggerRegistered(bool aDebuggerRegistered) {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     MutexAutoLock lock(mMutex);
 | |
| 
 | |
|     MOZ_ASSERT(mDebuggerRegistered != aDebuggerRegistered);
 | |
|     mDebuggerRegistered = aDebuggerRegistered;
 | |
| 
 | |
|     mCondVar.Notify();
 | |
|   }
 | |
| 
 | |
|   void WaitForIsDebuggerRegistered(bool aDebuggerRegistered) {
 | |
|     AssertIsOnParentThread();
 | |
| 
 | |
|     // Yield so that the main thread won't be blocked.
 | |
|     AutoYieldJSThreadExecution yield;
 | |
| 
 | |
|     MOZ_ASSERT(!NS_IsMainThread());
 | |
| 
 | |
|     MutexAutoLock lock(mMutex);
 | |
| 
 | |
|     while (mDebuggerRegistered != aDebuggerRegistered) {
 | |
|       mCondVar.Wait();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsresult SetIsDebuggerReady(bool aReady);
 | |
| 
 | |
|   WorkerDebugger* Debugger() const {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     MOZ_ASSERT(mDebugger);
 | |
|     return mDebugger;
 | |
|   }
 | |
| 
 | |
|   const OriginTrials& Trials() const { return mLoadInfo.mTrials; }
 | |
| 
 | |
|   void SetDebugger(WorkerDebugger* aDebugger) {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     MOZ_ASSERT(mDebugger != aDebugger);
 | |
|     mDebugger = aDebugger;
 | |
|   }
 | |
| 
 | |
|   JS::UniqueChars AdoptDefaultLocale() {
 | |
|     MOZ_ASSERT(mDefaultLocale,
 | |
|                "the default locale must have been successfully set for anyone "
 | |
|                "to be trying to adopt it");
 | |
|     return std::move(mDefaultLocale);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Invoked by WorkerThreadPrimaryRunnable::Run if it already called
 | |
|    * SetWorkerPrivateInWorkerThread but has to bail out on initialization before
 | |
|    * calling DoRunLoop because PBackground failed to initialize or something
 | |
|    * like that.  Note that there's currently no point earlier than this that
 | |
|    * failure can be reported.
 | |
|    *
 | |
|    * When this happens, the worker will need to be deleted, plus the call to
 | |
|    * SetWorkerPrivateInWorkerThread will have scheduled all the
 | |
|    * mPreStartRunnables which need to be cleaned up after, as well as any
 | |
|    * scheduled control runnables.  We're somewhat punting on debugger runnables
 | |
|    * for now, which may leak, but the intent is to moot this whole scenario via
 | |
|    * shutdown blockers, so we don't want the extra complexity right now.
 | |
|    */
 | |
|   void RunLoopNeverRan();
 | |
| 
 | |
|   MOZ_CAN_RUN_SCRIPT
 | |
|   void DoRunLoop(JSContext* aCx);
 | |
| 
 | |
|   void UnrootGlobalScopes();
 | |
| 
 | |
|   bool InterruptCallback(JSContext* aCx);
 | |
| 
 | |
|   bool IsOnCurrentThread();
 | |
| 
 | |
|   void CloseInternal();
 | |
| 
 | |
|   bool FreezeInternal();
 | |
| 
 | |
|   bool ThawInternal();
 | |
| 
 | |
|   void PropagateStorageAccessPermissionGrantedInternal();
 | |
| 
 | |
|   void TraverseTimeouts(nsCycleCollectionTraversalCallback& aCallback);
 | |
| 
 | |
|   void UnlinkTimeouts();
 | |
| 
 | |
|   bool AddChildWorker(WorkerPrivate& aChildWorker);
 | |
| 
 | |
|   void RemoveChildWorker(WorkerPrivate& aChildWorker);
 | |
| 
 | |
|   void PostMessageToParent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
 | |
|                            const Sequence<JSObject*>& aTransferable,
 | |
|                            ErrorResult& aRv);
 | |
| 
 | |
|   void PostMessageToParentMessagePort(JSContext* aCx,
 | |
|                                       JS::Handle<JS::Value> aMessage,
 | |
|                                       const Sequence<JSObject*>& aTransferable,
 | |
|                                       ErrorResult& aRv);
 | |
| 
 | |
|   MOZ_CAN_RUN_SCRIPT void EnterDebuggerEventLoop();
 | |
| 
 | |
|   void LeaveDebuggerEventLoop();
 | |
| 
 | |
|   void PostMessageToDebugger(const nsAString& aMessage);
 | |
| 
 | |
|   void SetDebuggerImmediate(Function& aHandler, ErrorResult& aRv);
 | |
| 
 | |
|   void ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
 | |
|                              const nsAString& aMessage);
 | |
| 
 | |
|   bool NotifyInternal(WorkerStatus aStatus);
 | |
| 
 | |
|   void ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
 | |
|                    JSErrorReport* aReport);
 | |
| 
 | |
|   static void ReportErrorToConsole(const char* aMessage);
 | |
| 
 | |
|   static void ReportErrorToConsole(const char* aMessage,
 | |
|                                    const nsTArray<nsString>& aParams);
 | |
| 
 | |
|   int32_t SetTimeout(JSContext* aCx, TimeoutHandler* aHandler, int32_t aTimeout,
 | |
|                      bool aIsInterval, Timeout::Reason aReason,
 | |
|                      ErrorResult& aRv);
 | |
| 
 | |
|   void ClearTimeout(int32_t aId, Timeout::Reason aReason);
 | |
| 
 | |
|   MOZ_CAN_RUN_SCRIPT bool RunExpiredTimeouts(JSContext* aCx);
 | |
| 
 | |
|   bool RescheduleTimeoutTimer(JSContext* aCx);
 | |
| 
 | |
|   void UpdateContextOptionsInternal(JSContext* aCx,
 | |
|                                     const JS::ContextOptions& aContextOptions);
 | |
| 
 | |
|   void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
 | |
| 
 | |
|   void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key,
 | |
|                                              Maybe<uint32_t> aValue);
 | |
| 
 | |
|   enum WorkerRanOrNot { WorkerNeverRan = 0, WorkerRan };
 | |
| 
 | |
|   void ScheduleDeletion(WorkerRanOrNot aRanOrNot);
 | |
| 
 | |
|   bool CollectRuntimeStats(JS::RuntimeStats* aRtStats, bool aAnonymize);
 | |
| 
 | |
| #ifdef JS_GC_ZEAL
 | |
|   void UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
 | |
|                             uint32_t aFrequency);
 | |
| #endif
 | |
| 
 | |
|   void SetLowMemoryStateInternal(JSContext* aCx, bool aState);
 | |
| 
 | |
|   void GarbageCollectInternal(JSContext* aCx, bool aShrinking,
 | |
|                               bool aCollectChildren);
 | |
| 
 | |
|   void CycleCollectInternal(bool aCollectChildren);
 | |
| 
 | |
|   void OfflineStatusChangeEventInternal(bool aIsOffline);
 | |
| 
 | |
|   void MemoryPressureInternal();
 | |
| 
 | |
|   typedef MozPromise<uint64_t, nsresult, true> JSMemoryUsagePromise;
 | |
|   RefPtr<JSMemoryUsagePromise> GetJSMemoryUsage();
 | |
| 
 | |
|   void SetFetchHandlerWasAdded() {
 | |
|     MOZ_ASSERT(IsServiceWorker());
 | |
|     AssertIsOnWorkerThread();
 | |
|     mFetchHandlerWasAdded = true;
 | |
|   }
 | |
| 
 | |
|   bool FetchHandlerWasAdded() const {
 | |
|     MOZ_ASSERT(IsServiceWorker());
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mFetchHandlerWasAdded;
 | |
|   }
 | |
| 
 | |
|   JSContext* GetJSContext() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
 | |
|     // mJSContext is only modified on the worker thread, so workerthread code
 | |
|     // can safely read it without a lock
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mJSContext;
 | |
|   }
 | |
| 
 | |
|   WorkerGlobalScope* GlobalScope() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mScope;
 | |
|   }
 | |
| 
 | |
|   WorkerDebuggerGlobalScope* DebuggerGlobalScope() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mDebuggerScope;
 | |
|   }
 | |
| 
 | |
|   // Get the global associated with the current nested event loop.  Will return
 | |
|   // null if we're not in a nested event loop or that nested event loop does not
 | |
|   // have an associated global.
 | |
|   nsIGlobalObject* GetCurrentEventLoopGlobal() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mCurrentEventLoopGlobal;
 | |
|   }
 | |
| 
 | |
|   nsICSPEventListener* CSPEventListener() const;
 | |
| 
 | |
|   void SetThread(WorkerThread* aThread);
 | |
| 
 | |
|   void SetWorkerPrivateInWorkerThread(WorkerThread* aThread);
 | |
| 
 | |
|   void ResetWorkerPrivateInWorkerThread();
 | |
| 
 | |
|   bool IsOnWorkerThread() const;
 | |
| 
 | |
|   void AssertIsOnWorkerThread() const
 | |
| #ifdef DEBUG
 | |
|       ;
 | |
| #else
 | |
|   {
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   // This may block!
 | |
|   void BeginCTypesCall();
 | |
| 
 | |
|   // This may block!
 | |
|   void EndCTypesCall();
 | |
| 
 | |
|   void BeginCTypesCallback();
 | |
| 
 | |
|   void EndCTypesCallback();
 | |
| 
 | |
|   bool ConnectMessagePort(JSContext* aCx, UniqueMessagePortId& aIdentifier);
 | |
| 
 | |
|   WorkerGlobalScope* GetOrCreateGlobalScope(JSContext* aCx);
 | |
| 
 | |
|   WorkerDebuggerGlobalScope* CreateDebuggerGlobalScope(JSContext* aCx);
 | |
| 
 | |
|   bool RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 | |
| 
 | |
|   bool RegisterDebuggerBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 | |
| 
 | |
|   bool OnLine() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mOnLine;
 | |
|   }
 | |
| 
 | |
|   void StopSyncLoop(nsIEventTarget* aSyncLoopTarget, nsresult aResult);
 | |
| 
 | |
|   bool MaybeStopSyncLoop(nsIEventTarget* aSyncLoopTarget, nsresult aResult);
 | |
| 
 | |
|   void ShutdownModuleLoader();
 | |
| 
 | |
|   void ClearPreStartRunnables();
 | |
| 
 | |
|   void ClearDebuggerEventQueue();
 | |
| 
 | |
|   void OnProcessNextEvent();
 | |
| 
 | |
|   void AfterProcessNextEvent();
 | |
| 
 | |
|   void AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
 | |
| #ifdef DEBUG
 | |
|       ;
 | |
| #else
 | |
|   {
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   void AssertIsNotPotentiallyLastGCCCRunning() {
 | |
| #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     MOZ_DIAGNOSTIC_ASSERT(!data->mIsPotentiallyLastGCCCRunning);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   void SetWorkerScriptExecutedSuccessfully() {
 | |
|     AssertIsOnWorkerThread();
 | |
|     // Should only be called once!
 | |
|     MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully);
 | |
|     mWorkerScriptExecutedSuccessfully = true;
 | |
|   }
 | |
| 
 | |
|   // Only valid after CompileScriptRunnable has finished running!
 | |
|   bool WorkerScriptExecutedSuccessfully() const {
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mWorkerScriptExecutedSuccessfully;
 | |
|   }
 | |
| 
 | |
|   // Get the event target to use when dispatching to the main thread
 | |
|   // from this Worker thread.  This may be the main thread itself or
 | |
|   // a ThrottledEventQueue to the main thread.
 | |
|   nsISerialEventTarget* MainThreadEventTargetForMessaging();
 | |
| 
 | |
|   nsresult DispatchToMainThreadForMessaging(
 | |
|       nsIRunnable* aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL);
 | |
| 
 | |
|   nsresult DispatchToMainThreadForMessaging(
 | |
|       already_AddRefed<nsIRunnable> aRunnable,
 | |
|       uint32_t aFlags = NS_DISPATCH_NORMAL);
 | |
| 
 | |
|   nsISerialEventTarget* MainThreadEventTarget();
 | |
| 
 | |
|   nsresult DispatchToMainThread(nsIRunnable* aRunnable,
 | |
|                                 uint32_t aFlags = NS_DISPATCH_NORMAL);
 | |
| 
 | |
|   nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
 | |
|                                 uint32_t aFlags = NS_DISPATCH_NORMAL);
 | |
| 
 | |
|   nsresult DispatchDebuggeeToMainThread(
 | |
|       already_AddRefed<WorkerDebuggeeRunnable> aRunnable,
 | |
|       uint32_t aFlags = NS_DISPATCH_NORMAL);
 | |
| 
 | |
|   // Get an event target that will dispatch runnables as control runnables on
 | |
|   // the worker thread.  Implement nsICancelableRunnable if you wish to take
 | |
|   // action on cancelation.
 | |
|   nsISerialEventTarget* ControlEventTarget();
 | |
| 
 | |
|   // Get an event target that will attempt to dispatch a normal WorkerRunnable,
 | |
|   // but if that fails will then fall back to a control runnable.
 | |
|   nsISerialEventTarget* HybridEventTarget();
 | |
| 
 | |
|   void DumpCrashInformation(nsACString& aString);
 | |
| 
 | |
|   ClientType GetClientType() const;
 | |
| 
 | |
|   bool EnsureCSPEventListener();
 | |
| 
 | |
|   void EnsurePerformanceStorage();
 | |
| 
 | |
|   bool GetExecutionGranted() const;
 | |
|   void SetExecutionGranted(bool aGranted);
 | |
| 
 | |
|   void ScheduleTimeSliceExpiration(uint32_t aDelay);
 | |
|   void CancelTimeSliceExpiration();
 | |
| 
 | |
|   JSExecutionManager* GetExecutionManager() const;
 | |
|   void SetExecutionManager(JSExecutionManager* aManager);
 | |
| 
 | |
|   void ExecutionReady();
 | |
| 
 | |
|   PerformanceStorage* GetPerformanceStorage();
 | |
| 
 | |
|   bool IsAcceptingEvents() MOZ_EXCLUDES(mMutex) {
 | |
|     AssertIsOnParentThread();
 | |
| 
 | |
|     MutexAutoLock lock(mMutex);
 | |
|     return mParentStatus < Canceling;
 | |
|   }
 | |
| 
 | |
|   WorkerStatus ParentStatusProtected() {
 | |
|     AssertIsOnParentThread();
 | |
|     MutexAutoLock lock(mMutex);
 | |
|     return mParentStatus;
 | |
|   }
 | |
| 
 | |
|   WorkerStatus ParentStatus() const MOZ_REQUIRES(mMutex) {
 | |
|     mMutex.AssertCurrentThreadOwns();
 | |
|     return mParentStatus;
 | |
|   }
 | |
| 
 | |
|   Worker* ParentEventTargetRef() const {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef);
 | |
|     return mParentEventTargetRef;
 | |
|   }
 | |
| 
 | |
|   void SetParentEventTargetRef(Worker* aParentEventTargetRef) {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef);
 | |
|     MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef);
 | |
|     mParentEventTargetRef = aParentEventTargetRef;
 | |
|   }
 | |
| 
 | |
|   // Check whether this worker is a secure context.  For use from the parent
 | |
|   // thread only; the canonical "is secure context" boolean is stored on the
 | |
|   // compartment of the worker global.  The only reason we don't
 | |
|   // AssertIsOnParentThread() here is so we can assert that this value matches
 | |
|   // the one on the compartment, which has to be done from the worker thread.
 | |
|   bool IsSecureContext() const { return mIsSecureContext; }
 | |
| 
 | |
|   // Check whether we're running in automation.
 | |
|   bool IsInAutomation() const { return mIsInAutomation; }
 | |
| 
 | |
|   bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal; }
 | |
| 
 | |
|   TimeStamp CreationTimeStamp() const { return mCreationTimeStamp; }
 | |
| 
 | |
|   DOMHighResTimeStamp CreationTime() const { return mCreationTimeHighRes; }
 | |
| 
 | |
|   DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const {
 | |
|     MOZ_ASSERT(!aTimeStamp.IsNull());
 | |
|     TimeDuration duration = aTimeStamp - mCreationTimeStamp;
 | |
|     return duration.ToMilliseconds();
 | |
|   }
 | |
| 
 | |
|   LocationInfo& GetLocationInfo() { return mLocationInfo; }
 | |
| 
 | |
|   void CopyJSSettings(workerinternals::JSSettings& aSettings) {
 | |
|     mozilla::MutexAutoLock lock(mMutex);
 | |
|     aSettings = mJSSettings;
 | |
|   }
 | |
| 
 | |
|   void CopyJSRealmOptions(JS::RealmOptions& aOptions) {
 | |
|     mozilla::MutexAutoLock lock(mMutex);
 | |
|     aOptions = IsChromeWorker() ? mJSSettings.chromeRealmOptions
 | |
|                                 : mJSSettings.contentRealmOptions;
 | |
|   }
 | |
| 
 | |
|   // The ability to be a chrome worker is orthogonal to the type of
 | |
|   // worker [Dedicated|Shared|Service].
 | |
|   bool IsChromeWorker() const { return mIsChromeWorker; }
 | |
| 
 | |
|   // TODO: Invariants require that the parent worker out-live any child
 | |
|   // worker, so WorkerPrivate* should be safe in the moment of calling.
 | |
|   // We would like to have stronger type-system annotated/enforced handling.
 | |
|   WorkerPrivate* GetParent() const { return mParent; }
 | |
| 
 | |
|   bool IsFrozen() const {
 | |
|     AssertIsOnParentThread();
 | |
|     return mParentFrozen;
 | |
|   }
 | |
| 
 | |
|   bool IsParentWindowPaused() const {
 | |
|     AssertIsOnParentThread();
 | |
|     return mParentWindowPaused;
 | |
|   }
 | |
| 
 | |
|   // When we debug a worker, we want to disconnect the window and the worker
 | |
|   // communication. This happens calling this method.
 | |
|   // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
 | |
|   void ParentWindowPaused();
 | |
| 
 | |
|   void ParentWindowResumed();
 | |
| 
 | |
|   const nsString& ScriptURL() const { return mScriptURL; }
 | |
| 
 | |
|   const nsString& WorkerName() const { return mWorkerName; }
 | |
|   RequestCredentials WorkerCredentials() const { return mCredentialsMode; }
 | |
|   enum WorkerType WorkerType() const { return mWorkerType; }
 | |
| 
 | |
|   WorkerKind Kind() const { return mWorkerKind; }
 | |
| 
 | |
|   bool IsDedicatedWorker() const { return mWorkerKind == WorkerKindDedicated; }
 | |
| 
 | |
|   bool IsSharedWorker() const { return mWorkerKind == WorkerKindShared; }
 | |
| 
 | |
|   bool IsServiceWorker() const { return mWorkerKind == WorkerKindService; }
 | |
| 
 | |
|   nsContentPolicyType ContentPolicyType() const {
 | |
|     return ContentPolicyType(mWorkerKind);
 | |
|   }
 | |
| 
 | |
|   static nsContentPolicyType ContentPolicyType(WorkerKind aWorkerKind) {
 | |
|     switch (aWorkerKind) {
 | |
|       case WorkerKindDedicated:
 | |
|         return nsIContentPolicy::TYPE_INTERNAL_WORKER;
 | |
|       case WorkerKindShared:
 | |
|         return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
 | |
|       case WorkerKindService:
 | |
|         return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;
 | |
|       default:
 | |
|         MOZ_ASSERT_UNREACHABLE("Invalid worker type");
 | |
|         return nsIContentPolicy::TYPE_INVALID;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsIScriptContext* GetScriptContext() const {
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mScriptContext;
 | |
|   }
 | |
| 
 | |
|   const nsCString& Domain() const { return mLoadInfo.mDomain; }
 | |
| 
 | |
|   bool IsFromWindow() const { return mLoadInfo.mFromWindow; }
 | |
| 
 | |
|   nsLoadFlags GetLoadFlags() const { return mLoadInfo.mLoadFlags; }
 | |
| 
 | |
|   uint64_t WindowID() const { return mLoadInfo.mWindowID; }
 | |
| 
 | |
|   uint64_t AssociatedBrowsingContextID() const {
 | |
|     return mLoadInfo.mAssociatedBrowsingContextID;
 | |
|   }
 | |
| 
 | |
|   uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
 | |
| 
 | |
|   const nsCString& ServiceWorkerScope() const {
 | |
|     return GetServiceWorkerDescriptor().Scope();
 | |
|   }
 | |
| 
 | |
|   // This value should never change after the script load completes. Before
 | |
|   // then, it may only be called on the main thread.
 | |
|   nsIURI* GetBaseURI() const { return mLoadInfo.mBaseURI; }
 | |
| 
 | |
|   void SetBaseURI(nsIURI* aBaseURI);
 | |
| 
 | |
|   nsIURI* GetResolvedScriptURI() const { return mLoadInfo.mResolvedScriptURI; }
 | |
| 
 | |
|   const nsString& ServiceWorkerCacheName() const {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mServiceWorkerCacheName;
 | |
|   }
 | |
| 
 | |
|   const ServiceWorkerDescriptor& GetServiceWorkerDescriptor() const {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
 | |
|     MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome());
 | |
|     return mLoadInfo.mServiceWorkerDescriptor.ref();
 | |
|   }
 | |
| 
 | |
|   const ServiceWorkerRegistrationDescriptor&
 | |
|   GetServiceWorkerRegistrationDescriptor() const {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
 | |
|     MOZ_DIAGNOSTIC_ASSERT(
 | |
|         mLoadInfo.mServiceWorkerRegistrationDescriptor.isSome());
 | |
|     return mLoadInfo.mServiceWorkerRegistrationDescriptor.ref();
 | |
|   }
 | |
| 
 | |
|   void UpdateServiceWorkerState(ServiceWorkerState aState) {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
 | |
|     MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome());
 | |
|     return mLoadInfo.mServiceWorkerDescriptor.ref().SetState(aState);
 | |
|   }
 | |
| 
 | |
|   const Maybe<ServiceWorkerDescriptor>& GetParentController() const {
 | |
|     return mLoadInfo.mParentController;
 | |
|   }
 | |
| 
 | |
|   const ChannelInfo& GetChannelInfo() const { return mLoadInfo.mChannelInfo; }
 | |
| 
 | |
|   void SetChannelInfo(const ChannelInfo& aChannelInfo) {
 | |
|     AssertIsOnMainThread();
 | |
|     MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized());
 | |
|     MOZ_ASSERT(aChannelInfo.IsInitialized());
 | |
|     mLoadInfo.mChannelInfo = aChannelInfo;
 | |
|   }
 | |
| 
 | |
|   void InitChannelInfo(nsIChannel* aChannel) {
 | |
|     mLoadInfo.mChannelInfo.InitFromChannel(aChannel);
 | |
|   }
 | |
| 
 | |
|   void InitChannelInfo(const ChannelInfo& aChannelInfo) {
 | |
|     mLoadInfo.mChannelInfo = aChannelInfo;
 | |
|   }
 | |
| 
 | |
|   nsIPrincipal* GetPrincipal() const { return mLoadInfo.mPrincipal; }
 | |
| 
 | |
|   nsIPrincipal* GetLoadingPrincipal() const {
 | |
|     return mLoadInfo.mLoadingPrincipal;
 | |
|   }
 | |
| 
 | |
|   nsIPrincipal* GetPartitionedPrincipal() const {
 | |
|     return mLoadInfo.mPartitionedPrincipal;
 | |
|   }
 | |
| 
 | |
|   nsIPrincipal* GetEffectiveStoragePrincipal() const;
 | |
| 
 | |
|   nsILoadGroup* GetLoadGroup() const {
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mLoadGroup;
 | |
|   }
 | |
| 
 | |
|   bool UsesSystemPrincipal() const {
 | |
|     return GetPrincipal()->IsSystemPrincipal();
 | |
|   }
 | |
|   bool UsesAddonOrExpandedAddonPrincipal() const {
 | |
|     return GetPrincipal()->GetIsAddonOrExpandedAddonPrincipal();
 | |
|   }
 | |
| 
 | |
|   const mozilla::ipc::PrincipalInfo& GetPrincipalInfo() const {
 | |
|     return *mLoadInfo.mPrincipalInfo;
 | |
|   }
 | |
| 
 | |
|   const mozilla::ipc::PrincipalInfo& GetPartitionedPrincipalInfo() const {
 | |
|     return *mLoadInfo.mPartitionedPrincipalInfo;
 | |
|   }
 | |
| 
 | |
|   const mozilla::ipc::PrincipalInfo& GetEffectiveStoragePrincipalInfo() const;
 | |
| 
 | |
|   already_AddRefed<nsIChannel> ForgetWorkerChannel() {
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mChannel.forget();
 | |
|   }
 | |
| 
 | |
|   nsPIDOMWindowInner* GetWindow() const {
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mWindow;
 | |
|   }
 | |
| 
 | |
|   nsPIDOMWindowInner* GetAncestorWindow() const;
 | |
| 
 | |
|   void EvictFromBFCache();
 | |
| 
 | |
|   nsIContentSecurityPolicy* GetCsp() const {
 | |
|     AssertIsOnMainThread();
 | |
|     return mLoadInfo.mCSP;
 | |
|   }
 | |
| 
 | |
|   void SetCsp(nsIContentSecurityPolicy* aCSP);
 | |
| 
 | |
|   nsresult SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
 | |
|                                   const nsACString& aCSPReportOnlyHeaderValue);
 | |
| 
 | |
|   void StoreCSPOnClient();
 | |
| 
 | |
|   const mozilla::ipc::CSPInfo& GetCSPInfo() const {
 | |
|     return *mLoadInfo.mCSPInfo;
 | |
|   }
 | |
| 
 | |
|   void UpdateReferrerInfoFromHeader(
 | |
|       const nsACString& aReferrerPolicyHeaderValue);
 | |
| 
 | |
|   nsIReferrerInfo* GetReferrerInfo() const { return mLoadInfo.mReferrerInfo; }
 | |
| 
 | |
|   ReferrerPolicy GetReferrerPolicy() const {
 | |
|     return mLoadInfo.mReferrerInfo->ReferrerPolicy();
 | |
|   }
 | |
| 
 | |
|   void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
 | |
|     mLoadInfo.mReferrerInfo = aReferrerInfo;
 | |
|   }
 | |
| 
 | |
|   bool IsEvalAllowed() const { return mLoadInfo.mEvalAllowed; }
 | |
| 
 | |
|   void SetEvalAllowed(bool aAllowed) { mLoadInfo.mEvalAllowed = aAllowed; }
 | |
| 
 | |
|   bool GetReportEvalCSPViolations() const {
 | |
|     return mLoadInfo.mReportEvalCSPViolations;
 | |
|   }
 | |
| 
 | |
|   void SetReportEvalCSPViolations(bool aReport) {
 | |
|     mLoadInfo.mReportEvalCSPViolations = aReport;
 | |
|   }
 | |
| 
 | |
|   bool IsWasmEvalAllowed() const { return mLoadInfo.mWasmEvalAllowed; }
 | |
| 
 | |
|   void SetWasmEvalAllowed(bool aAllowed) {
 | |
|     mLoadInfo.mWasmEvalAllowed = aAllowed;
 | |
|   }
 | |
| 
 | |
|   bool GetReportWasmEvalCSPViolations() const {
 | |
|     return mLoadInfo.mReportWasmEvalCSPViolations;
 | |
|   }
 | |
| 
 | |
|   void SetReportWasmEvalCSPViolations(bool aReport) {
 | |
|     mLoadInfo.mReportWasmEvalCSPViolations = aReport;
 | |
|   }
 | |
| 
 | |
|   bool XHRParamsAllowed() const { return mLoadInfo.mXHRParamsAllowed; }
 | |
| 
 | |
|   void SetXHRParamsAllowed(bool aAllowed) {
 | |
|     mLoadInfo.mXHRParamsAllowed = aAllowed;
 | |
|   }
 | |
| 
 | |
|   mozilla::StorageAccess StorageAccess() const {
 | |
|     AssertIsOnWorkerThread();
 | |
|     if (mLoadInfo.mUsingStorageAccess) {
 | |
|       return mozilla::StorageAccess::eAllow;
 | |
|     }
 | |
| 
 | |
|     return mLoadInfo.mStorageAccess;
 | |
|   }
 | |
| 
 | |
|   bool UseRegularPrincipal() const {
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mLoadInfo.mUseRegularPrincipal;
 | |
|   }
 | |
| 
 | |
|   bool UsingStorageAccess() const {
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mLoadInfo.mUsingStorageAccess;
 | |
|   }
 | |
| 
 | |
|   nsICookieJarSettings* CookieJarSettings() const {
 | |
|     // Any thread.
 | |
|     MOZ_ASSERT(mLoadInfo.mCookieJarSettings);
 | |
|     return mLoadInfo.mCookieJarSettings;
 | |
|   }
 | |
| 
 | |
|   const net::CookieJarSettingsArgs& CookieJarSettingsArgs() const {
 | |
|     MOZ_ASSERT(mLoadInfo.mCookieJarSettings);
 | |
|     return mLoadInfo.mCookieJarSettingsArgs;
 | |
|   }
 | |
| 
 | |
|   const OriginAttributes& GetOriginAttributes() const {
 | |
|     return mLoadInfo.mOriginAttributes;
 | |
|   }
 | |
| 
 | |
|   // Determine if the SW testing per-window flag is set by devtools
 | |
|   bool ServiceWorkersTestingInWindow() const {
 | |
|     return mLoadInfo.mServiceWorkersTestingInWindow;
 | |
|   }
 | |
| 
 | |
|   // Determine if the worker was created under a third-party context.
 | |
|   bool IsThirdPartyContextToTopWindow() const {
 | |
|     return mLoadInfo.mIsThirdPartyContextToTopWindow;
 | |
|   }
 | |
| 
 | |
|   bool IsWatchedByDevTools() const { return mLoadInfo.mWatchedByDevTools; }
 | |
| 
 | |
|   bool ShouldResistFingerprinting(RFPTarget aTarget) const;
 | |
| 
 | |
|   const Maybe<RFPTarget>& GetOverriddenFingerprintingSettings() const {
 | |
|     return mLoadInfo.mOverriddenFingerprintingSettings;
 | |
|   }
 | |
| 
 | |
|   RemoteWorkerChild* GetRemoteWorkerController();
 | |
| 
 | |
|   void SetRemoteWorkerController(RemoteWorkerChild* aController);
 | |
| 
 | |
|   RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag();
 | |
| 
 | |
|   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
 | |
|   // as these are only used for globals going in and out of the bfcache.
 | |
|   bool Freeze(const nsPIDOMWindowInner* aWindow);
 | |
| 
 | |
|   bool Thaw(const nsPIDOMWindowInner* aWindow);
 | |
| 
 | |
|   void PropagateStorageAccessPermissionGranted();
 | |
| 
 | |
|   void EnableDebugger();
 | |
| 
 | |
|   void DisableDebugger();
 | |
| 
 | |
|   already_AddRefed<WorkerRunnable> MaybeWrapAsWorkerRunnable(
 | |
|       already_AddRefed<nsIRunnable> aRunnable);
 | |
| 
 | |
|   bool ProxyReleaseMainThreadObjects();
 | |
| 
 | |
|   void SetLowMemoryState(bool aState);
 | |
| 
 | |
|   void GarbageCollect(bool aShrinking);
 | |
| 
 | |
|   void CycleCollect();
 | |
| 
 | |
|   nsresult SetPrincipalsAndCSPOnMainThread(nsIPrincipal* aPrincipal,
 | |
|                                            nsIPrincipal* aPartitionedPrincipal,
 | |
|                                            nsILoadGroup* aLoadGroup,
 | |
|                                            nsIContentSecurityPolicy* aCsp);
 | |
| 
 | |
|   nsresult SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel);
 | |
| 
 | |
|   bool FinalChannelPrincipalIsValid(nsIChannel* aChannel);
 | |
| 
 | |
| #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|   bool PrincipalURIMatchesScriptURL();
 | |
| #endif
 | |
| 
 | |
|   void UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
 | |
| 
 | |
|   void WorkerScriptLoaded();
 | |
| 
 | |
|   Document* GetDocument() const;
 | |
| 
 | |
|   void MemoryPressure();
 | |
| 
 | |
|   void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
 | |
| 
 | |
|   void UpdateLanguages(const nsTArray<nsString>& aLanguages);
 | |
| 
 | |
|   void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
 | |
| 
 | |
| #ifdef JS_GC_ZEAL
 | |
|   void UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency);
 | |
| #endif
 | |
| 
 | |
|   void OfflineStatusChangeEvent(bool aIsOffline);
 | |
| 
 | |
|   nsresult Dispatch(already_AddRefed<WorkerRunnable> aRunnable,
 | |
|                     nsIEventTarget* aSyncLoopTarget = nullptr);
 | |
| 
 | |
|   nsresult DispatchControlRunnable(
 | |
|       already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable);
 | |
| 
 | |
|   nsresult DispatchDebuggerRunnable(
 | |
|       already_AddRefed<WorkerRunnable> aDebuggerRunnable);
 | |
| 
 | |
|   bool IsOnParentThread() const;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   void AssertIsOnParentThread() const;
 | |
| 
 | |
|   void AssertInnerWindowIsCorrect() const;
 | |
| #else
 | |
|   void AssertIsOnParentThread() const {}
 | |
| 
 | |
|   void AssertInnerWindowIsCorrect() const {}
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|   bool PrincipalIsValid() const;
 | |
| #endif
 | |
| 
 | |
|   void StartCancelingTimer();
 | |
| 
 | |
|   const nsAString& Id();
 | |
| 
 | |
|   const nsID& AgentClusterId() const { return mAgentClusterId; }
 | |
| 
 | |
|   bool IsSharedMemoryAllowed() const;
 | |
| 
 | |
|   // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
 | |
|   bool CrossOriginIsolated() const;
 | |
| 
 | |
|   void SetUseCounter(UseCounterWorker aUseCounter) {
 | |
|     MOZ_ASSERT(!mReportedUseCounters);
 | |
|     MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown);
 | |
|     AssertIsOnWorkerThread();
 | |
|     mUseCounters[static_cast<size_t>(aUseCounter)] = true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * COEP Methods
 | |
|    *
 | |
|    * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods
 | |
|    * will, depending on the return type, return a value that will avoid
 | |
|    * assertion failures or a value that won't block loads.
 | |
|    */
 | |
|   nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const;
 | |
| 
 | |
|   // Fails if a policy has already been set or if `aPolicy` violates the owner's
 | |
|   // policy, if an owner exists.
 | |
|   mozilla::Result<Ok, nsresult> SetEmbedderPolicy(
 | |
|       nsILoadInfo::CrossOriginEmbedderPolicy aPolicy);
 | |
| 
 | |
|   // `aRequest` is the request loading the worker and must be QI-able to
 | |
|   // `nsIChannel*`. It's used to verify that the worker can indeed inherit its
 | |
|   // owner's COEP (when an owner exists).
 | |
|   //
 | |
|   // TODO: remove `aRequest`; currently, it's required because instances may not
 | |
|   // always know its final, resolved script URL or have access internally to
 | |
|   // `aRequest`.
 | |
|   void InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest);
 | |
| 
 | |
|   // Requires a policy to already have been set.
 | |
|   bool MatchEmbedderPolicy(
 | |
|       nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const;
 | |
| 
 | |
|   nsILoadInfo::CrossOriginEmbedderPolicy GetOwnerEmbedderPolicy() const;
 | |
| 
 | |
|   void SetCCCollectedAnything(bool collectedAnything);
 | |
|   bool isLastCCCollectedAnything();
 | |
| 
 | |
|   uint32_t GetCurrentTimerNestingLevel() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mCurrentTimerNestingLevel;
 | |
|   }
 | |
| 
 | |
|   void IncreaseTopLevelWorkerFinishedRunnableCount() {
 | |
|     ++mTopLevelWorkerFinishedRunnableCount;
 | |
|   }
 | |
|   void DecreaseTopLevelWorkerFinishedRunnableCount() {
 | |
|     --mTopLevelWorkerFinishedRunnableCount;
 | |
|   }
 | |
|   void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount; }
 | |
|   void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount; }
 | |
| 
 | |
|   void RunShutdownTasks();
 | |
| 
 | |
|   bool CancelBeforeWorkerScopeConstructed() const {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return data->mCancelBeforeWorkerScopeConstructed;
 | |
|   }
 | |
| 
 | |
|   enum class CCFlag : uint8_t {
 | |
|     EligibleForWorkerRef,
 | |
|     IneligibleForWorkerRef,
 | |
|     EligibleForChildWorker,
 | |
|     IneligibleForChildWorker,
 | |
|     EligibleForTimeout,
 | |
|     IneligibleForTimeout,
 | |
|     CheckBackgroundActors,
 | |
|   };
 | |
| 
 | |
|   // When create/release a StrongWorkerRef, child worker, and timeout, this
 | |
|   // method is used to setup if mParentEventTargetRef can get into
 | |
|   // cycle-collection.
 | |
|   // When this method is called, it will also checks if any background actor
 | |
|   // should block the mParentEventTargetRef cycle-collection when there is no
 | |
|   // StrongWorkerRef/ChildWorker/Timeout.
 | |
|   // Worker thread only.
 | |
|   void UpdateCCFlag(const CCFlag);
 | |
| 
 | |
|   // This is used in WorkerPrivate::Traverse() to checking if
 | |
|   // mParentEventTargetRef should get into cycle-collection.
 | |
|   // Parent thread only method.
 | |
|   bool IsEligibleForCC();
 | |
| 
 | |
|   // A method which adjusts the count of background actors which should not
 | |
|   // block WorkerPrivate::mParentEventTargetRef cycle-collection.
 | |
|   // Worker thread only.
 | |
|   void AdjustNonblockingCCBackgroundActorCount(int32_t aCount);
 | |
| 
 | |
|  private:
 | |
|   WorkerPrivate(
 | |
|       WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
 | |
|       WorkerKind aWorkerKind, RequestCredentials aRequestCredentials,
 | |
|       enum WorkerType aWorkerType, const nsAString& aWorkerName,
 | |
|       const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo,
 | |
|       nsString&& aId, const nsID& aAgentClusterId,
 | |
|       const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy,
 | |
|       CancellationCallback&& aCancellationCallback,
 | |
|       TerminationCallback&& aTerminationCallback);
 | |
| 
 | |
|   ~WorkerPrivate();
 | |
| 
 | |
|   struct AgentClusterIdAndCoop {
 | |
|     nsID mId;
 | |
|     nsILoadInfo::CrossOriginOpenerPolicy mCoop;
 | |
|   };
 | |
| 
 | |
|   static AgentClusterIdAndCoop ComputeAgentClusterIdAndCoop(
 | |
|       WorkerPrivate* aParent, WorkerKind aWorkerKind,
 | |
|       WorkerLoadInfo* aLoadInfo);
 | |
| 
 | |
|   bool MayContinueRunning() {
 | |
|     AssertIsOnWorkerThread();
 | |
| 
 | |
|     WorkerStatus status;
 | |
|     {
 | |
|       MutexAutoLock lock(mMutex);
 | |
|       status = mStatus;
 | |
|     }
 | |
| 
 | |
|     if (status < Canceling) {
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   void CancelAllTimeouts();
 | |
| 
 | |
|   enum class ProcessAllControlRunnablesResult {
 | |
|     // We did not process anything.
 | |
|     Nothing,
 | |
|     // We did process something, states may have changed, but we can keep
 | |
|     // executing script.
 | |
|     MayContinue,
 | |
|     // We did process something, and should not continue executing script.
 | |
|     Abort
 | |
|   };
 | |
| 
 | |
|   ProcessAllControlRunnablesResult ProcessAllControlRunnables() {
 | |
|     MutexAutoLock lock(mMutex);
 | |
|     return ProcessAllControlRunnablesLocked();
 | |
|   }
 | |
| 
 | |
|   ProcessAllControlRunnablesResult ProcessAllControlRunnablesLocked()
 | |
|       MOZ_REQUIRES(mMutex);
 | |
| 
 | |
|   void EnableMemoryReporter();
 | |
| 
 | |
|   void DisableMemoryReporter();
 | |
| 
 | |
|   void WaitForWorkerEvents() MOZ_REQUIRES(mMutex);
 | |
| 
 | |
|   // If the worker shutdown status is equal or greater then aFailStatus, this
 | |
|   // operation will fail and nullptr will be returned. See WorkerStatus.h for
 | |
|   // more information about the correct value to use.
 | |
|   already_AddRefed<nsISerialEventTarget> CreateNewSyncLoop(
 | |
|       WorkerStatus aFailStatus);
 | |
| 
 | |
|   nsresult RunCurrentSyncLoop();
 | |
| 
 | |
|   nsresult DestroySyncLoop(uint32_t aLoopIndex);
 | |
| 
 | |
|   void InitializeGCTimers();
 | |
| 
 | |
|   enum GCTimerMode { PeriodicTimer = 0, IdleTimer, NoTimer };
 | |
| 
 | |
|   void SetGCTimerMode(GCTimerMode aMode);
 | |
| 
 | |
|  public:
 | |
|   void CancelGCTimers() { SetGCTimerMode(NoTimer); }
 | |
| 
 | |
|  private:
 | |
|   void ShutdownGCTimers();
 | |
| 
 | |
|   friend class WorkerRef;
 | |
| 
 | |
|   bool AddWorkerRef(WorkerRef* aWorkerRefer, WorkerStatus aFailStatus);
 | |
| 
 | |
|   void RemoveWorkerRef(WorkerRef* aWorkerRef);
 | |
| 
 | |
|   void NotifyWorkerRefs(WorkerStatus aStatus);
 | |
| 
 | |
|   bool HasActiveWorkerRefs() {
 | |
|     auto data = mWorkerThreadAccessible.Access();
 | |
|     return !(data->mChildWorkers.IsEmpty() && data->mTimeouts.IsEmpty() &&
 | |
|              data->mWorkerRefs.IsEmpty());
 | |
|   }
 | |
| 
 | |
|   friend class WorkerEventTarget;
 | |
| 
 | |
|   nsresult RegisterShutdownTask(nsITargetShutdownTask* aTask);
 | |
| 
 | |
|   nsresult UnregisterShutdownTask(nsITargetShutdownTask* aTask);
 | |
| 
 | |
|   // Internal logic to dispatch a runnable. This is separate from Dispatch()
 | |
|   // to allow runnables to be atomically dispatched in bulk.
 | |
|   nsresult DispatchLockHeld(already_AddRefed<WorkerRunnable> aRunnable,
 | |
|                             nsIEventTarget* aSyncLoopTarget,
 | |
|                             const MutexAutoLock& aProofOfLock)
 | |
|       MOZ_REQUIRES(mMutex);
 | |
| 
 | |
|   // This method dispatches a simple runnable that starts the shutdown procedure
 | |
|   // after a self.close(). This method is called after a ClearMainEventQueue()
 | |
|   // to be sure that the canceling runnable is the only one in the queue.  We
 | |
|   // need this async operation to be sure that all the current JS code is
 | |
|   // executed.
 | |
|   void DispatchCancelingRunnable();
 | |
| 
 | |
|   bool GetUseCounter(UseCounterWorker aUseCounter) {
 | |
|     MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown);
 | |
|     AssertIsOnWorkerThread();
 | |
|     return mUseCounters[static_cast<size_t>(aUseCounter)];
 | |
|   }
 | |
| 
 | |
|   void ReportUseCounters();
 | |
| 
 | |
|   UniquePtr<ClientSource> CreateClientSource();
 | |
| 
 | |
|   // This method is called when corresponding script loader processes the COEP
 | |
|   // header for the worker.
 | |
|   // This method should be called only once in the main thread.
 | |
|   // After this method is called the COEP value owner(window/parent worker) is
 | |
|   // cached in mOwnerEmbedderPolicy such that it can be accessed in other
 | |
|   // threads, i.e. WorkerThread.
 | |
|   void EnsureOwnerEmbedderPolicy();
 | |
| 
 | |
|   class EventTarget;
 | |
|   friend class EventTarget;
 | |
|   friend class AutoSyncLoopHolder;
 | |
| 
 | |
|   struct TimeoutInfo;
 | |
| 
 | |
|   class MemoryReporter;
 | |
|   friend class MemoryReporter;
 | |
| 
 | |
|   friend class mozilla::dom::WorkerThread;
 | |
| 
 | |
|   SharedMutex mMutex;
 | |
|   mozilla::CondVar mCondVar MOZ_GUARDED_BY(mMutex);
 | |
| 
 | |
|   // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
 | |
|   // our static assert
 | |
|   MOZ_NON_OWNING_REF WorkerPrivate* const mParent;
 | |
| 
 | |
|   const nsString mScriptURL;
 | |
| 
 | |
|   // This is the worker name for shared workers and dedicated workers.
 | |
|   const nsString mWorkerName;
 | |
|   const RequestCredentials mCredentialsMode;
 | |
|   enum WorkerType mWorkerType;
 | |
| 
 | |
|   const WorkerKind mWorkerKind;
 | |
| 
 | |
|   // The worker is owned by its thread, which is represented here.  This is set
 | |
|   // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
 | |
|   // traversed by the cycle collector if no other things preventing shutdown.
 | |
|   //
 | |
|   // There are 4 ways a worker can be terminated:
 | |
|   // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
 | |
|   //    traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
 | |
|   //    Worker webidl object. Doing this, CC will be able to detect a cycle and
 | |
|   //    Unlink is called. In Unlink, Worker calls Cancel().
 | |
|   // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
 | |
|   // 3. WorkerScope::Close() is called - Similar to point 2.
 | |
|   // 4. xpcom-shutdown notification - We call Kill().
 | |
|   RefPtr<Worker> mParentEventTargetRef;
 | |
|   RefPtr<WorkerPrivate> mSelfRef;
 | |
| 
 | |
|   CancellationCallback mCancellationCallback;
 | |
| 
 | |
|   // The termination callback is passed into the constructor on the parent
 | |
|   // thread and invoked by `ClearSelfAndParentEventTargetRef` just before it
 | |
|   // drops its self-ref.
 | |
|   TerminationCallback mTerminationCallback;
 | |
| 
 | |
|   // The lifetime of these objects within LoadInfo is managed explicitly;
 | |
|   // they do not need to be cycle collected.
 | |
|   WorkerLoadInfo mLoadInfo;
 | |
|   LocationInfo mLocationInfo;
 | |
| 
 | |
|   // Protected by mMutex.
 | |
|   workerinternals::JSSettings mJSSettings MOZ_GUARDED_BY(mMutex);
 | |
| 
 | |
|   WorkerDebugger* mDebugger;
 | |
| 
 | |
|   workerinternals::Queue<WorkerControlRunnable*, 4> mControlQueue;
 | |
|   workerinternals::Queue<WorkerRunnable*, 4> mDebuggerQueue;
 | |
| 
 | |
|   // Touched on multiple threads, protected with mMutex. Only modified on the
 | |
|   // worker thread
 | |
|   JSContext* mJSContext MOZ_GUARDED_BY(mMutex);
 | |
|   // mThread is only modified on the Worker thread, before calling DoRunLoop
 | |
|   RefPtr<WorkerThread> mThread MOZ_GUARDED_BY(mMutex);
 | |
|   // mPRThread is only modified on another thread in ScheduleWorker(), and is
 | |
|   // constant for the duration of DoRunLoop.  Static mutex analysis doesn't help
 | |
|   // here
 | |
|   PRThread* mPRThread;
 | |
| 
 | |
|   // Accessed from main thread
 | |
|   RefPtr<ThrottledEventQueue> mMainThreadEventTargetForMessaging;
 | |
|   RefPtr<ThrottledEventQueue> mMainThreadEventTarget;
 | |
| 
 | |
|   // Accessed from worker thread and destructing thread
 | |
|   RefPtr<WorkerEventTarget> mWorkerControlEventTarget;
 | |
|   RefPtr<WorkerEventTarget> mWorkerHybridEventTarget;
 | |
| 
 | |
|   // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
 | |
|   // See WorkerDebuggeeRunnable for details.
 | |
|   RefPtr<ThrottledEventQueue> mMainThreadDebuggeeEventTarget;
 | |
| 
 | |
|   struct SyncLoopInfo {
 | |
|     explicit SyncLoopInfo(EventTarget* aEventTarget);
 | |
| 
 | |
|     RefPtr<EventTarget> mEventTarget;
 | |
|     nsresult mResult;
 | |
|     bool mCompleted;
 | |
| #ifdef DEBUG
 | |
|     bool mHasRun;
 | |
| #endif
 | |
|   };
 | |
| 
 | |
|   // This is only modified on the worker thread, but in DEBUG builds
 | |
|   // AssertValidSyncLoop function iterates it on other threads. Therefore
 | |
|   // modifications are done with mMutex held *only* in DEBUG builds.
 | |
|   nsTArray<UniquePtr<SyncLoopInfo>> mSyncLoopStack;
 | |
| 
 | |
|   nsCOMPtr<nsITimer> mCancelingTimer;
 | |
| 
 | |
|   // fired on the main thread if the worker script fails to load
 | |
|   nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
 | |
| 
 | |
|   RefPtr<PerformanceStorage> mPerformanceStorage;
 | |
| 
 | |
|   RefPtr<WorkerCSPEventListener> mCSPEventListener;
 | |
| 
 | |
|   // Protected by mMutex.
 | |
|   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables MOZ_GUARDED_BY(mMutex);
 | |
| 
 | |
|   // Only touched on the parent thread.  Used for both SharedWorker and
 | |
|   // ServiceWorker RemoteWorkers.
 | |
|   RefPtr<RemoteWorkerChild> mRemoteWorkerController;
 | |
| 
 | |
|   JS::UniqueChars mDefaultLocale;  // nulled during worker JSContext init
 | |
|   TimeStamp mKillTime;
 | |
|   WorkerStatus mParentStatus MOZ_GUARDED_BY(mMutex);
 | |
|   WorkerStatus mStatus MOZ_GUARDED_BY(mMutex);
 | |
| 
 | |
|   TimeStamp mCreationTimeStamp;
 | |
|   DOMHighResTimeStamp mCreationTimeHighRes;
 | |
| 
 | |
|   // Flags for use counters used directly by this worker.
 | |
|   static_assert(sizeof(UseCounterWorker) <= sizeof(size_t),
 | |
|                 "UseCounterWorker is too big");
 | |
|   static_assert(UseCounterWorker::Count >= static_cast<UseCounterWorker>(0),
 | |
|                 "Should be non-negative value and safe to cast to unsigned");
 | |
|   std::bitset<static_cast<size_t>(UseCounterWorker::Count)> mUseCounters;
 | |
|   bool mReportedUseCounters;
 | |
| 
 | |
|   // This is created while creating the WorkerPrivate, so it's safe to be
 | |
|   // touched on any thread.
 | |
|   const nsID mAgentClusterId;
 | |
| 
 | |
|   // Things touched on worker thread only.
 | |
|   struct WorkerThreadAccessible {
 | |
|     explicit WorkerThreadAccessible(WorkerPrivate* aParent);
 | |
| 
 | |
|     RefPtr<WorkerGlobalScope> mScope;
 | |
|     RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
 | |
|     // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
 | |
|     // our static assert
 | |
|     nsTArray<WorkerPrivate*> mChildWorkers;
 | |
|     nsTObserverArray<WorkerRef*> mWorkerRefs;
 | |
|     nsTArray<UniquePtr<TimeoutInfo>> mTimeouts;
 | |
| 
 | |
|     nsCOMPtr<nsITimer> mTimer;
 | |
|     nsCOMPtr<nsITimerCallback> mTimerRunnable;
 | |
| 
 | |
|     nsCOMPtr<nsITimer> mPeriodicGCTimer;
 | |
|     nsCOMPtr<nsITimer> mIdleGCTimer;
 | |
| 
 | |
|     RefPtr<MemoryReporter> mMemoryReporter;
 | |
| 
 | |
|     // While running a nested event loop, whether a sync loop or a debugger
 | |
|     // event loop we want to keep track of which global is running it, if any,
 | |
|     // so runnables that run off that event loop can get at that information. In
 | |
|     // practice this only matters for various worker debugger runnables running
 | |
|     // against sandboxes, because all other runnables know which globals they
 | |
|     // belong to already.  We could also address this by threading the relevant
 | |
|     // global through the chains of runnables involved, but we'd need to thread
 | |
|     // it through some runnables that run on the main thread, and that would
 | |
|     // require some care to make sure things get released on the correct thread,
 | |
|     // which we'd rather avoid.  This member is only accessed on the worker
 | |
|     // thread.
 | |
|     nsCOMPtr<nsIGlobalObject> mCurrentEventLoopGlobal;
 | |
| 
 | |
|     // Timer that triggers an interrupt on expiration of the current time slice
 | |
|     nsCOMPtr<nsITimer> mTSTimer;
 | |
| 
 | |
|     // Execution manager used to regulate execution for this worker.
 | |
|     RefPtr<JSExecutionManager> mExecutionManager;
 | |
| 
 | |
|     // Used to relinguish clearance for CTypes Callbacks.
 | |
|     nsTArray<AutoYieldJSThreadExecution> mYieldJSThreadExecution;
 | |
| 
 | |
|     uint32_t mNumWorkerRefsPreventingShutdownStart;
 | |
|     uint32_t mDebuggerEventLoopLevel;
 | |
| 
 | |
|     // This is the count of background actors that binding with IPCWorkerRefs.
 | |
|     // This count would be used in WorkerPrivate::UpdateCCFlag for checking if
 | |
|     // CC should be blocked by background actors.
 | |
|     uint32_t mNonblockingCCBackgroundActorCount;
 | |
| 
 | |
|     uint32_t mErrorHandlerRecursionCount;
 | |
|     int32_t mNextTimeoutId;
 | |
| 
 | |
|     // Tracks the current setTimeout/setInterval nesting level.
 | |
|     // When there isn't a TimeoutHandler on the stack, this will be 0.
 | |
|     // Whenever setTimeout/setInterval are called, a new TimeoutInfo will be
 | |
|     // created with a nesting level one more than the current nesting level,
 | |
|     // saturating at the kClampTimeoutNestingLevel.
 | |
|     //
 | |
|     // When RunExpiredTimeouts is run, it sets this value to the
 | |
|     // TimeoutInfo::mNestingLevel for the duration of
 | |
|     // the WorkerScriptTimeoutHandler::Call which will explicitly trigger a
 | |
|     // microtask checkpoint so that any immediately-resolved promises will
 | |
|     // still see the nesting level.
 | |
|     uint32_t mCurrentTimerNestingLevel;
 | |
| 
 | |
|     bool mFrozen;
 | |
|     bool mTimerRunning;
 | |
|     bool mRunningExpiredTimeouts;
 | |
|     bool mPeriodicGCTimerRunning;
 | |
|     bool mIdleGCTimerRunning;
 | |
|     bool mOnLine;
 | |
|     bool mJSThreadExecutionGranted;
 | |
|     bool mCCCollectedAnything;
 | |
|     FlippedOnce<false> mDeletionScheduled;
 | |
|     FlippedOnce<false> mCancelBeforeWorkerScopeConstructed;
 | |
|     FlippedOnce<false> mPerformedShutdownAfterLastContentTaskExecuted;
 | |
| #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|     bool mIsPotentiallyLastGCCCRunning = false;
 | |
| #endif
 | |
|   };
 | |
|   ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
 | |
| 
 | |
|   class MOZ_RAII AutoPushEventLoopGlobal {
 | |
|    public:
 | |
|     AutoPushEventLoopGlobal(WorkerPrivate* aWorkerPrivate, JSContext* aCx);
 | |
|     ~AutoPushEventLoopGlobal();
 | |
| 
 | |
|    private:
 | |
|     // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
 | |
|     // our static assert
 | |
|     MOZ_NON_OWNING_REF WorkerPrivate* mWorkerPrivate;
 | |
|     nsCOMPtr<nsIGlobalObject> mOldEventLoopGlobal;
 | |
|   };
 | |
|   friend class AutoPushEventLoopGlobal;
 | |
| 
 | |
|   uint32_t mPostSyncLoopOperations;
 | |
| 
 | |
|   // List of operations to do at the end of the last sync event loop.
 | |
|   enum {
 | |
|     eDispatchCancelingRunnable = 0x02,
 | |
|   };
 | |
| 
 | |
|   bool mParentWindowPaused;
 | |
| 
 | |
|   bool mWorkerScriptExecutedSuccessfully;
 | |
|   bool mFetchHandlerWasAdded;
 | |
|   bool mMainThreadObjectsForgotten;
 | |
|   bool mIsChromeWorker;
 | |
|   bool mParentFrozen;
 | |
| 
 | |
|   // mIsSecureContext is set once in our constructor; after that it can be read
 | |
|   // from various threads.
 | |
|   //
 | |
|   // It's a bit unfortunate that we have to have an out-of-band boolean for
 | |
|   // this, but we need access to this state from the parent thread, and we can't
 | |
|   // use our global object's secure state there.
 | |
|   const bool mIsSecureContext;
 | |
| 
 | |
|   bool mDebuggerRegistered MOZ_GUARDED_BY(mMutex);
 | |
| 
 | |
|   // During registration, this worker may be marked as not being ready to
 | |
|   // execute debuggee runnables or content.
 | |
|   //
 | |
|   // Protected by mMutex.
 | |
|   bool mDebuggerReady;
 | |
|   nsTArray<RefPtr<WorkerRunnable>> mDelayedDebuggeeRunnables;
 | |
| 
 | |
|   // Whether this worker should have access to the WebExtension API bindings
 | |
|   // (currently only the Extension Background ServiceWorker declared in the
 | |
|   // extension manifest is allowed to access any WebExtension API bindings).
 | |
|   // This default to false, and it is eventually set to true by
 | |
|   // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions
 | |
|   // are met.
 | |
|   bool mExtensionAPIAllowed;
 | |
| 
 | |
|   // mIsInAutomation is true when we're running in test automation.
 | |
|   // We expose some extra testing functions in that case.
 | |
|   bool mIsInAutomation;
 | |
| 
 | |
|   nsString mId;
 | |
| 
 | |
|   // This is used to check if it's allowed to share the memory across the agent
 | |
|   // cluster.
 | |
|   const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy;
 | |
| 
 | |
|   // Member variable of this class rather than the worker global scope because
 | |
|   // it's received on the main thread, but the global scope is thread-bound
 | |
|   // to the worker thread, so storing the value in the global scope would
 | |
|   // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and
 | |
|   // there isn't a strong reason to store it on the global scope other than
 | |
|   // better consistency with the COEP spec.
 | |
|   Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy;
 | |
|   Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mOwnerEmbedderPolicy;
 | |
| 
 | |
|   /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal
 | |
|    * on the main thread when constructing a top-level worker. The flag is
 | |
|    * propagated to nested workers. The flag is only allowed to take effect in
 | |
|    * extension processes and is forbidden in content scripts in content
 | |
|    * processes. The flag may be read on either the parent/owner thread as well
 | |
|    * as on the worker thread itself. When bug 1443925 is fixed allowing
 | |
|    * nsIPrincipal to be used OMT, it may be possible to remove this flag. */
 | |
|   bool mIsPrivilegedAddonGlobal;
 | |
| 
 | |
|   Atomic<uint32_t> mTopLevelWorkerFinishedRunnableCount;
 | |
|   Atomic<uint32_t> mWorkerFinishedRunnableCount;
 | |
| 
 | |
|   nsTArray<nsCOMPtr<nsITargetShutdownTask>> mShutdownTasks
 | |
|       MOZ_GUARDED_BY(mMutex);
 | |
|   bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false;
 | |
| 
 | |
|   bool mCCFlagSaysEligible MOZ_GUARDED_BY(mMutex){true};
 | |
| 
 | |
|   // The flag indicates if the worke is idle for events in the main event loop.
 | |
|   bool mWorkerLoopIsIdle MOZ_GUARDED_BY(mMutex){false};
 | |
| };
 | |
| 
 | |
| class AutoSyncLoopHolder {
 | |
|   CheckedUnsafePtr<WorkerPrivate> mWorkerPrivate;
 | |
|   nsCOMPtr<nsISerialEventTarget> mTarget;
 | |
|   uint32_t mIndex;
 | |
| 
 | |
|  public:
 | |
|   // See CreateNewSyncLoop() for more information about the correct value to use
 | |
|   // for aFailStatus.
 | |
|   AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus)
 | |
|       : mWorkerPrivate(aWorkerPrivate),
 | |
|         mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus)),
 | |
|         mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1) {
 | |
|     aWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   }
 | |
| 
 | |
|   ~AutoSyncLoopHolder() {
 | |
|     if (mWorkerPrivate && mTarget) {
 | |
|       mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|       mWorkerPrivate->StopSyncLoop(mTarget, NS_ERROR_FAILURE);
 | |
|       mWorkerPrivate->DestroySyncLoop(mIndex);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsresult Run() {
 | |
|     CheckedUnsafePtr<WorkerPrivate> workerPrivate = mWorkerPrivate;
 | |
|     mWorkerPrivate = nullptr;
 | |
| 
 | |
|     workerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|     return workerPrivate->RunCurrentSyncLoop();
 | |
|   }
 | |
| 
 | |
|   nsISerialEventTarget* GetSerialEventTarget() const {
 | |
|     // This can be null if CreateNewSyncLoop() fails.
 | |
|     return mTarget;
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 | |
| 
 | |
| #endif /* mozilla_dom_workers_workerprivate_h__ */
 |