LCOV - code coverage report
Current view: top level - js/src/vm - HelperThreads.h (source / functions) Hit Total Coverage
Test: output.info Lines: 36 86 41.9 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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             : /*
       8             :  * Definitions for managing off-thread work using a process wide list
       9             :  * of worklist items and pool of threads. Worklist items are engine internal,
      10             :  * and are distinct from e.g. web workers.
      11             :  */
      12             : 
      13             : #ifndef vm_HelperThreads_h
      14             : #define vm_HelperThreads_h
      15             : 
      16             : #include "mozilla/Attributes.h"
      17             : #include "mozilla/GuardObjects.h"
      18             : #include "mozilla/PodOperations.h"
      19             : #include "mozilla/TimeStamp.h"
      20             : #include "mozilla/TypeTraits.h"
      21             : #include "mozilla/Variant.h"
      22             : 
      23             : #include "jsapi.h"
      24             : 
      25             : #include "ds/Fifo.h"
      26             : #include "jit/Ion.h"
      27             : #include "js/TypeDecls.h"
      28             : #include "threading/ConditionVariable.h"
      29             : #include "vm/JSContext.h"
      30             : #include "vm/MutexIDs.h"
      31             : 
      32             : namespace JS {
      33             : class OffThreadToken {};
      34             : } // namespace JS
      35             : 
      36             : namespace js {
      37             : 
      38             : class AutoLockHelperThreadState;
      39             : class AutoUnlockHelperThreadState;
      40             : class CompileError;
      41             : struct HelperThread;
      42             : struct ParseTask;
      43             : struct PromiseHelperTask;
      44             : namespace jit {
      45             :   class IonBuilder;
      46             : } // namespace jit
      47             : namespace wasm {
      48             :   struct Tier2GeneratorTask;
      49             : } // namespace wasm
      50             : 
      51             : enum class ParseTaskKind
      52             : {
      53             :     Script,
      54             :     Module,
      55             :     ScriptDecode,
      56             :     BinAST,
      57             :     MultiScriptsDecode
      58             : };
      59             : 
      60             : namespace wasm {
      61             : 
      62             : struct CompileTask;
      63             : typedef Fifo<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrFifo;
      64             : 
      65             : struct Tier2GeneratorTask
      66             : {
      67             :     virtual ~Tier2GeneratorTask() = default;
      68             :     virtual void cancel() = 0;
      69             :     virtual void execute() = 0;
      70             : };
      71             : 
      72             : typedef UniquePtr<Tier2GeneratorTask> UniqueTier2GeneratorTask;
      73             : typedef Vector<Tier2GeneratorTask*, 0, SystemAllocPolicy> Tier2GeneratorTaskPtrVector;
      74             : 
      75             : }  // namespace wasm
      76             : 
      77             : // Per-process state for off thread work items.
      78           0 : class GlobalHelperThreadState
      79             : {
      80             :     friend class AutoLockHelperThreadState;
      81             :     friend class AutoUnlockHelperThreadState;
      82             : 
      83             :   public:
      84             :     // A single tier-2 ModuleGenerator job spawns many compilation jobs, and we
      85             :     // do not want to allow more than one such ModuleGenerator to run at a time.
      86             :     static const size_t MaxTier2GeneratorTasks = 1;
      87             : 
      88             :     // Number of CPUs to treat this machine as having when creating threads.
      89             :     // May be accessed without locking.
      90             :     size_t cpuCount;
      91             : 
      92             :     // Number of threads to create. May be accessed without locking.
      93             :     size_t threadCount;
      94             : 
      95             :     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
      96             :     typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
      97             :     typedef mozilla::LinkedList<ParseTask> ParseTaskList;
      98             :     typedef Vector<UniquePtr<SourceCompressionTask>, 0, SystemAllocPolicy> SourceCompressionTaskVector;
      99             :     typedef Vector<GCHelperState*, 0, SystemAllocPolicy> GCHelperStateVector;
     100             :     typedef Vector<GCParallelTask*, 0, SystemAllocPolicy> GCParallelTaskVector;
     101             :     typedef Vector<PromiseHelperTask*, 0, SystemAllocPolicy> PromiseHelperTaskVector;
     102             : 
     103             :     // List of available threads, or null if the thread state has not been initialized.
     104             :     using HelperThreadVector = Vector<HelperThread, 0, SystemAllocPolicy>;
     105             :     UniquePtr<HelperThreadVector> threads;
     106             : 
     107             :     WriteOnceData<JS::RegisterThreadCallback> registerThread;
     108             :     WriteOnceData<JS::UnregisterThreadCallback> unregisterThread;
     109             : 
     110             :   private:
     111             :     // The lists below are all protected by |lock|.
     112             : 
     113             :     // Ion compilation worklist and finished jobs.
     114             :     IonBuilderVector ionWorklist_, ionFinishedList_, ionFreeList_;
     115             : 
     116             :     // wasm worklists.
     117             :     wasm::CompileTaskPtrFifo wasmWorklist_tier1_;
     118             :     wasm::CompileTaskPtrFifo wasmWorklist_tier2_;
     119             :     wasm::Tier2GeneratorTaskPtrVector wasmTier2GeneratorWorklist_;
     120             : 
     121             :     // Count of finished Tier2Generator tasks.
     122             :     uint32_t wasmTier2GeneratorsFinished_;
     123             : 
     124             :     // Async tasks that, upon completion, are dispatched back to the JSContext's
     125             :     // owner thread via embedding callbacks instead of a finished list.
     126             :     PromiseHelperTaskVector promiseHelperTasks_;
     127             : 
     128             :     // Script parsing/emitting worklist and finished jobs.
     129             :     ParseTaskVector parseWorklist_;
     130             :     ParseTaskList parseFinishedList_;
     131             : 
     132             :     // Parse tasks waiting for an atoms-zone GC to complete.
     133             :     ParseTaskVector parseWaitingOnGC_;
     134             : 
     135             :     // Source compression worklist of tasks that we do not yet know can start.
     136             :     SourceCompressionTaskVector compressionPendingList_;
     137             : 
     138             :     // Source compression worklist of tasks that can start.
     139             :     SourceCompressionTaskVector compressionWorklist_;
     140             : 
     141             :     // Finished source compression tasks.
     142             :     SourceCompressionTaskVector compressionFinishedList_;
     143             : 
     144             :     // Runtimes which have sweeping / allocating work to do.
     145             :     GCHelperStateVector gcHelperWorklist_;
     146             : 
     147             :     // GC tasks needing to be done in parallel.
     148             :     GCParallelTaskVector gcParallelWorklist_;
     149             : 
     150             :     ParseTask* removeFinishedParseTask(ParseTaskKind kind, JS::OffThreadToken* token);
     151             : 
     152             :   public:
     153             : 
     154             :     void addSizeOfIncludingThis(JS::GlobalStats* stats,
     155             :                                 AutoLockHelperThreadState& lock) const;
     156             : 
     157             :     size_t maxIonCompilationThreads() const;
     158             :     size_t maxWasmCompilationThreads() const;
     159             :     size_t maxWasmTier2GeneratorThreads() const;
     160             :     size_t maxPromiseHelperThreads() const;
     161             :     size_t maxParseThreads() const;
     162             :     size_t maxCompressionThreads() const;
     163             :     size_t maxGCHelperThreads() const;
     164             :     size_t maxGCParallelThreads() const;
     165             : 
     166             :     GlobalHelperThreadState();
     167             : 
     168             :     bool ensureInitialized();
     169             :     void finish();
     170             :     void finishThreads();
     171             : 
     172             :     void lock();
     173             :     void unlock();
     174             : #ifdef DEBUG
     175             :     bool isLockedByCurrentThread() const;
     176             : #endif
     177             : 
     178             :     enum CondVar {
     179             :         // For notifying threads waiting for work that they may be able to make
     180             :         // progress, ie, a work item has been completed by a helper thread and
     181             :         // the thread that created the work item can now consume it.
     182             :         CONSUMER,
     183             : 
     184             :         // For notifying helper threads doing the work that they may be able to
     185             :         // make progress, ie, a work item has been enqueued and an idle helper
     186             :         // thread may pick up up the work item and perform it.
     187             :         PRODUCER,
     188             :     };
     189             : 
     190             :     void wait(AutoLockHelperThreadState& locked, CondVar which,
     191             :               mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
     192             :     void notifyAll(CondVar which, const AutoLockHelperThreadState&);
     193             :     void notifyOne(CondVar which, const AutoLockHelperThreadState&);
     194             : 
     195             :     // Helper method for removing items from the vectors below while iterating over them.
     196             :     template <typename T>
     197           0 :     void remove(T& vector, size_t* index)
     198             :     {
     199             :         // Self-moving is undefined behavior.
     200           0 :         if (*index != vector.length() - 1)
     201           0 :             vector[*index] = std::move(vector.back());
     202          49 :         (*index)--;
     203          49 :         vector.popBack();
     204           0 :     }
     205             : 
     206             :     IonBuilderVector& ionWorklist(const AutoLockHelperThreadState&) {
     207           0 :         return ionWorklist_;
     208             :     }
     209             :     IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
     210           0 :         return ionFinishedList_;
     211             :     }
     212             :     IonBuilderVector& ionFreeList(const AutoLockHelperThreadState&) {
     213           0 :         return ionFreeList_;
     214             :     }
     215             : 
     216         312 :     wasm::CompileTaskPtrFifo& wasmWorklist(const AutoLockHelperThreadState&, wasm::CompileMode m) {
     217           0 :         switch (m) {
     218             :           case wasm::CompileMode::Once:
     219             :           case wasm::CompileMode::Tier1:
     220         183 :             return wasmWorklist_tier1_;
     221             :           case wasm::CompileMode::Tier2:
     222         129 :             return wasmWorklist_tier2_;
     223             :           default:
     224           0 :             MOZ_CRASH();
     225             :         }
     226             :     }
     227             : 
     228             :     wasm::Tier2GeneratorTaskPtrVector& wasmTier2GeneratorWorklist(const AutoLockHelperThreadState&) {
     229           0 :         return wasmTier2GeneratorWorklist_;
     230             :     }
     231             : 
     232             :     void incWasmTier2GeneratorsFinished(const AutoLockHelperThreadState&) {
     233           0 :         wasmTier2GeneratorsFinished_++;
     234             :     }
     235             : 
     236             :     uint32_t wasmTier2GeneratorsFinished(const AutoLockHelperThreadState&) const {
     237             :         return wasmTier2GeneratorsFinished_;
     238             :     }
     239             : 
     240             :     PromiseHelperTaskVector& promiseHelperTasks(const AutoLockHelperThreadState&) {
     241           0 :         return promiseHelperTasks_;
     242             :     }
     243             : 
     244             :     ParseTaskVector& parseWorklist(const AutoLockHelperThreadState&) {
     245           0 :         return parseWorklist_;
     246             :     }
     247             :     ParseTaskList& parseFinishedList(const AutoLockHelperThreadState&) {
     248           0 :         return parseFinishedList_;
     249             :     }
     250             :     ParseTaskVector& parseWaitingOnGC(const AutoLockHelperThreadState&) {
     251           0 :         return parseWaitingOnGC_;
     252             :     }
     253             : 
     254             :     SourceCompressionTaskVector& compressionPendingList(const AutoLockHelperThreadState&) {
     255         416 :         return compressionPendingList_;
     256             :     }
     257             : 
     258             :     SourceCompressionTaskVector& compressionWorklist(const AutoLockHelperThreadState&) {
     259           0 :         return compressionWorklist_;
     260             :     }
     261             : 
     262             :     SourceCompressionTaskVector& compressionFinishedList(const AutoLockHelperThreadState&) {
     263           0 :         return compressionFinishedList_;
     264             :     }
     265             : 
     266             :     GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
     267           0 :         return gcHelperWorklist_;
     268             :     }
     269             : 
     270             :     GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
     271          42 :         return gcParallelWorklist_;
     272             :     }
     273             : 
     274             :     bool canStartWasmCompile(const AutoLockHelperThreadState& lock, wasm::CompileMode mode);
     275             : 
     276             :     bool canStartWasmTier1Compile(const AutoLockHelperThreadState& lock);
     277             :     bool canStartWasmTier2Compile(const AutoLockHelperThreadState& lock);
     278             :     bool canStartWasmTier2Generator(const AutoLockHelperThreadState& lock);
     279             :     bool canStartPromiseHelperTask(const AutoLockHelperThreadState& lock);
     280             :     bool canStartIonCompile(const AutoLockHelperThreadState& lock);
     281             :     bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
     282             :     bool canStartParseTask(const AutoLockHelperThreadState& lock);
     283             :     bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
     284             :     bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
     285             :     bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
     286             : 
     287             :     // Used by a major GC to signal processing enqueued compression tasks.
     288             :     void startHandlingCompressionTasks(const AutoLockHelperThreadState&);
     289             : 
     290             :   private:
     291             :     void scheduleCompressionTasks(const AutoLockHelperThreadState&);
     292             : 
     293             :   public:
     294             :     jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock);
     295             : 
     296             :     template <
     297             :         typename F,
     298             :         typename = typename mozilla::EnableIf<
     299             :             // Matches when the type is a function or lambda with the signature `bool(ParseTask*)`
     300             :             mozilla::IsSame<bool, decltype((*(F*)nullptr)((ParseTask*)nullptr))>::value
     301             :         >::Type
     302             :     >
     303             :     bool finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token, F&& finishCallback);
     304             : 
     305             :     JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token);
     306             : 
     307             :     bool finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token, MutableHandle<ScriptVector> scripts);
     308             : 
     309             :     void cancelParseTask(JSRuntime* rt, ParseTaskKind kind, JS::OffThreadToken* token);
     310             :     void destroyParseTask(JSRuntime* rt, ParseTask* parseTask);
     311             : 
     312             :     void mergeParseTaskRealm(JSContext* cx, ParseTask* parseTask, JS::Realm* dest);
     313             : 
     314             :     void trace(JSTracer* trc, js::gc::AutoTraceSession& session);
     315             : 
     316             :     JSScript* finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token);
     317             :     JSScript* finishScriptDecodeTask(JSContext* cx, JS::OffThreadToken* token);
     318             :     bool finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token, MutableHandle<ScriptVector> scripts);
     319             :     JSObject* finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token);
     320             : 
     321             : #if defined(JS_BUILD_BINAST)
     322             :     JSScript* finishBinASTDecodeTask(JSContext* cx, JS::OffThreadToken* token);
     323             : #endif
     324             : 
     325             :     bool hasActiveThreads(const AutoLockHelperThreadState&);
     326             :     void waitForAllThreads();
     327             :     void waitForAllThreadsLocked(AutoLockHelperThreadState&);
     328             : 
     329             :     template <typename T>
     330             :     bool checkTaskThreadLimit(size_t maxThreads, bool isMaster = false) const;
     331             : 
     332             :   private:
     333             :     /*
     334             :      * Lock protecting all mutable shared state accessed by helper threads, and
     335             :      * used by all condition variables.
     336             :      */
     337             :     js::Mutex helperLock;
     338             : 
     339             :     /* Condvars for threads waiting/notifying each other. */
     340             :     js::ConditionVariable consumerWakeup;
     341             :     js::ConditionVariable producerWakeup;
     342             : 
     343           0 :     js::ConditionVariable& whichWakeup(CondVar which) {
     344           1 :         switch (which) {
     345          78 :           case CONSUMER: return consumerWakeup;
     346         254 :           case PRODUCER: return producerWakeup;
     347           0 :           default: MOZ_CRASH("Invalid CondVar in |whichWakeup|");
     348             :         }
     349             :     }
     350             : };
     351             : 
     352             : static inline GlobalHelperThreadState&
     353        7851 : HelperThreadState()
     354             : {
     355             :     extern GlobalHelperThreadState* gHelperThreadState;
     356             : 
     357        7851 :     MOZ_ASSERT(gHelperThreadState);
     358        7851 :     return *gHelperThreadState;
     359             : }
     360             : 
     361             : typedef mozilla::Variant<jit::IonBuilder*,
     362             :                          wasm::CompileTask*,
     363             :                          wasm::Tier2GeneratorTask*,
     364             :                          PromiseHelperTask*,
     365             :                          ParseTask*,
     366             :                          SourceCompressionTask*,
     367             :                          GCHelperState*,
     368             :                          GCParallelTask*> HelperTaskUnion;
     369             : 
     370             : /* Individual helper thread, one allocated per core. */
     371          12 : struct HelperThread
     372             : {
     373             :     mozilla::Maybe<Thread> thread;
     374             : 
     375             :     /*
     376             :      * Indicate to a thread that it should terminate itself. This is only read
     377             :      * or written with the helper thread state lock held.
     378             :      */
     379             :     bool terminate;
     380             : 
     381             :     /*
     382             :      * Indicate that this thread has been registered and needs to be
     383             :      * unregistered at shutdown.
     384             :      */
     385             :     bool registered;
     386             : 
     387             :     /* The current task being executed by this thread, if any. */
     388             :     mozilla::Maybe<HelperTaskUnion> currentTask;
     389             : 
     390             :     bool idle() const {
     391         379 :         return currentTask.isNothing();
     392             :     }
     393             : 
     394             :     /* Any builder currently being compiled by Ion on this thread. */
     395             :     jit::IonBuilder* ionBuilder() {
     396           0 :         return maybeCurrentTaskAs<jit::IonBuilder*>();
     397             :     }
     398             : 
     399             :     /* Any wasm data currently being optimized on this thread. */
     400             :     wasm::CompileTask* wasmTask() {
     401           0 :         return maybeCurrentTaskAs<wasm::CompileTask*>();
     402             :     }
     403             : 
     404             :     wasm::Tier2GeneratorTask* wasmTier2GeneratorTask() {
     405           0 :         return maybeCurrentTaskAs<wasm::Tier2GeneratorTask*>();
     406             :     }
     407             : 
     408             :     /* Any source being parsed/emitted on this thread. */
     409             :     ParseTask* parseTask() {
     410        1451 :         return maybeCurrentTaskAs<ParseTask*>();
     411             :     }
     412             : 
     413             :     /* Any source being compressed on this thread. */
     414             :     SourceCompressionTask* compressionTask() {
     415           0 :         return maybeCurrentTaskAs<SourceCompressionTask*>();
     416             :     }
     417             : 
     418             :     /* Any GC state for background sweeping or allocating being performed. */
     419             :     GCHelperState* gcHelperTask() {
     420           0 :         return maybeCurrentTaskAs<GCHelperState*>();
     421             :     }
     422             : 
     423             :     /* State required to perform a GC parallel task. */
     424             :     GCParallelTask* gcParallelTask() {
     425          21 :         return maybeCurrentTaskAs<GCParallelTask*>();
     426             :     }
     427             : 
     428             :     void destroy();
     429             : 
     430             :     static void ThreadMain(void* arg);
     431             :     void threadLoop();
     432             : 
     433             :     void ensureRegisteredWithProfiler();
     434             :     void unregisterWithProfilerIfNeeded();
     435             : 
     436             :   private:
     437             :     struct TaskSpec
     438             :     {
     439             :         using Selector = bool(GlobalHelperThreadState::*)(const AutoLockHelperThreadState&);
     440             :         using Handler = void(HelperThread::*)(AutoLockHelperThreadState&);
     441             : 
     442             :         js::ThreadType type;
     443             :         Selector canStart;
     444             :         Handler handleWorkload;
     445             :     };
     446             : 
     447             :     static const TaskSpec taskSpecs[];
     448             : 
     449             :     const TaskSpec* findHighestPriorityTask(const AutoLockHelperThreadState& locked);
     450             : 
     451             :     template <typename T>
     452        3162 :     T maybeCurrentTaskAs() {
     453        3162 :         if (currentTask.isSome() && currentTask->is<T>())
     454        1738 :             return currentTask->as<T>();
     455             : 
     456             :         return nullptr;
     457             :     }
     458             : 
     459             :     void handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::CompileMode mode);
     460             : 
     461             :     void handleWasmTier1Workload(AutoLockHelperThreadState& locked);
     462             :     void handleWasmTier2Workload(AutoLockHelperThreadState& locked);
     463             :     void handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked);
     464             :     void handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked);
     465             :     void handleIonWorkload(AutoLockHelperThreadState& locked);
     466             :     void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
     467             :     void handleParseWorkload(AutoLockHelperThreadState& locked);
     468             :     void handleCompressionWorkload(AutoLockHelperThreadState& locked);
     469             :     void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
     470             :     void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
     471             : };
     472             : 
     473             : /* Methods for interacting with helper threads. */
     474             : 
     475             : // Create data structures used by helper threads.
     476             : bool
     477             : CreateHelperThreadsState();
     478             : 
     479             : // Destroy data structures used by helper threads.
     480             : void
     481             : DestroyHelperThreadsState();
     482             : 
     483             : // Initialize helper threads unless already initialized.
     484             : bool
     485             : EnsureHelperThreadsInitialized();
     486             : 
     487             : // This allows the JS shell to override GetCPUCount() when passed the
     488             : // --thread-count=N option.
     489             : void
     490             : SetFakeCPUCount(size_t count);
     491             : 
     492             : // Get the current helper thread, or null.
     493             : HelperThread*
     494             : CurrentHelperThread();
     495             : 
     496             : // Enqueues a wasm compilation task.
     497             : bool
     498             : StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode);
     499             : 
     500             : namespace wasm {
     501             : 
     502             : // Called on a helper thread after StartOffThreadWasmCompile.
     503             : void
     504             : ExecuteCompileTaskFromHelperThread(CompileTask* task);
     505             : 
     506             : }
     507             : 
     508             : // Enqueues a wasm compilation task.
     509             : void
     510             : StartOffThreadWasmTier2Generator(wasm::UniqueTier2GeneratorTask task);
     511             : 
     512             : // Cancel all background Wasm Tier-2 compilations.
     513             : void
     514             : CancelOffThreadWasmTier2Generator();
     515             : 
     516             : /*
     517             :  * If helper threads are available, call execute() then dispatchResolve() on the
     518             :  * given task in a helper thread. If no helper threads are available, the given
     519             :  * task is executed and resolved synchronously.
     520             :  */
     521             : bool
     522             : StartOffThreadPromiseHelperTask(JSContext* cx, UniquePtr<PromiseHelperTask> task);
     523             : 
     524             : bool
     525             : StartOffThreadPromiseHelperTask(PromiseHelperTask* task);
     526             : 
     527             : /*
     528             :  * Schedule an Ion compilation for a script, given a builder which has been
     529             :  * generated and read everything needed from the VM state.
     530             :  */
     531             : bool
     532             : StartOffThreadIonCompile(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock);
     533             : 
     534             : /*
     535             :  * Schedule deletion of Ion compilation data.
     536             :  */
     537             : bool
     538             : StartOffThreadIonFree(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock);
     539             : 
     540             : struct AllCompilations {};
     541             : struct ZonesInState { JSRuntime* runtime; JS::Zone::GCState state; };
     542             : struct CompilationsUsingNursery { JSRuntime* runtime; };
     543             : 
     544             : using CompilationSelector = mozilla::Variant<JSScript*,
     545             :                                              JS::Realm*,
     546             :                                              Zone*,
     547             :                                              ZonesInState,
     548             :                                              JSRuntime*,
     549             :                                              CompilationsUsingNursery,
     550             :                                              AllCompilations>;
     551             : 
     552             : /*
     553             :  * Cancel scheduled or in progress Ion compilations.
     554             :  */
     555             : void
     556             : CancelOffThreadIonCompile(const CompilationSelector& selector, bool discardLazyLinkList);
     557             : 
     558             : inline void
     559           1 : CancelOffThreadIonCompile(JSScript* script)
     560             : {
     561           1 :     CancelOffThreadIonCompile(CompilationSelector(script), true);
     562           1 : }
     563             : 
     564             : inline void
     565           0 : CancelOffThreadIonCompile(JS::Realm* realm)
     566             : {
     567           0 :     CancelOffThreadIonCompile(CompilationSelector(realm), true);
     568           0 : }
     569             : 
     570             : inline void
     571           0 : CancelOffThreadIonCompile(Zone* zone)
     572             : {
     573           0 :     CancelOffThreadIonCompile(CompilationSelector(zone), true);
     574           0 : }
     575             : 
     576             : inline void
     577           0 : CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state)
     578             : {
     579           0 :     CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state}), true);
     580           0 : }
     581             : 
     582             : inline void
     583           0 : CancelOffThreadIonCompile(JSRuntime* runtime)
     584             : {
     585           0 :     CancelOffThreadIonCompile(CompilationSelector(runtime), true);
     586           0 : }
     587             : 
     588             : inline void
     589           3 : CancelOffThreadIonCompilesUsingNurseryPointers(JSRuntime* runtime)
     590             : {
     591           9 :     CancelOffThreadIonCompile(CompilationSelector(CompilationsUsingNursery{runtime}), true);
     592           3 : }
     593             : 
     594             : #ifdef DEBUG
     595             : bool
     596             : HasOffThreadIonCompile(JS::Realm* realm);
     597             : #endif
     598             : 
     599             : /* Cancel all scheduled, in progress or finished parses for runtime. */
     600             : void
     601             : CancelOffThreadParses(JSRuntime* runtime);
     602             : 
     603             : /*
     604             :  * Start a parse/emit cycle for a stream of source. The characters must stay
     605             :  * alive until the compilation finishes.
     606             :  */
     607             : bool
     608             : StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
     609             :                           const char16_t* chars, size_t length,
     610             :                           JS::OffThreadCompileCallback callback, void* callbackData);
     611             : 
     612             : bool
     613             : StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
     614             :                           const char16_t* chars, size_t length,
     615             :                           JS::OffThreadCompileCallback callback, void* callbackData);
     616             : 
     617             : bool
     618             : StartOffThreadDecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
     619             :                            const JS::TranscodeRange& range,
     620             :                            JS::OffThreadCompileCallback callback, void* callbackData);
     621             : 
     622             : #if defined(JS_BUILD_BINAST)
     623             : 
     624             : bool
     625             : StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
     626             :                            const uint8_t* buf, size_t length,
     627             :                            JS::OffThreadCompileCallback callback, void* callbackData);
     628             : 
     629             : #endif /* JS_BUILD_BINAST */
     630             : 
     631             : bool
     632             : StartOffThreadDecodeMultiScripts(JSContext* cx, const ReadOnlyCompileOptions& options,
     633             :                                  JS::TranscodeSources& sources,
     634             :                                  JS::OffThreadCompileCallback callback, void* callbackData);
     635             : 
     636             : /*
     637             :  * Called at the end of GC to enqueue any Parse tasks that were waiting on an
     638             :  * atoms-zone GC to finish.
     639             :  */
     640             : void
     641             : EnqueuePendingParseTasksAfterGC(JSRuntime* rt);
     642             : 
     643             : struct AutoEnqueuePendingParseTasksAfterGC {
     644             :     const gc::GCRuntime& gc_;
     645           0 :     explicit AutoEnqueuePendingParseTasksAfterGC(const gc::GCRuntime& gc) : gc_(gc) {}
     646             :     ~AutoEnqueuePendingParseTasksAfterGC();
     647             : };
     648             : 
     649             : // Enqueue a compression job to be processed if there's a major GC.
     650             : bool
     651             : EnqueueOffThreadCompression(JSContext* cx, UniquePtr<SourceCompressionTask> task);
     652             : 
     653             : // Cancel all scheduled, in progress, or finished compression tasks for
     654             : // runtime.
     655             : void
     656             : CancelOffThreadCompressions(JSRuntime* runtime);
     657             : 
     658        2050 : class MOZ_RAII AutoLockHelperThreadState : public LockGuard<Mutex>
     659             : {
     660             :     using Base = LockGuard<Mutex>;
     661             : 
     662             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     663             : 
     664             :   public:
     665             :     explicit AutoLockHelperThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
     666        3087 :       : Base(HelperThreadState().helperLock)
     667             :     {
     668        2058 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     669             :     }
     670             : };
     671             : 
     672           0 : class MOZ_RAII AutoUnlockHelperThreadState : public UnlockGuard<Mutex>
     673             : {
     674             :     using Base = UnlockGuard<Mutex>;
     675             : 
     676             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     677             : 
     678             :   public:
     679             : 
     680             :     explicit AutoUnlockHelperThreadState(AutoLockHelperThreadState& locked
     681             :                                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     682         375 :       : Base(locked)
     683             :     {
     684         250 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     685             :     }
     686             : };
     687             : 
     688             : struct ParseTask : public mozilla::LinkedListElement<ParseTask>, public JS::OffThreadToken
     689             : {
     690             :     ParseTaskKind kind;
     691             :     OwningCompileOptions options;
     692             : 
     693             :     LifoAlloc alloc;
     694             : 
     695             :     // The global object to use while parsing.
     696             :     JSObject* parseGlobal;
     697             : 
     698             :     // Callback invoked off thread when the parse finishes.
     699             :     JS::OffThreadCompileCallback callback;
     700             :     void* callbackData;
     701             : 
     702             :     // Holds the final scripts between the invocation of the callback and the
     703             :     // point where FinishOffThreadScript is called, which will destroy the
     704             :     // ParseTask.
     705             :     GCVector<JSScript*, 1> scripts;
     706             : 
     707             :     // Holds the ScriptSourceObjects generated for the script compilation.
     708             :     GCVector<ScriptSourceObject*, 1> sourceObjects;
     709             : 
     710             :     // Any errors or warnings produced during compilation. These are reported
     711             :     // when finishing the script.
     712             :     Vector<CompileError*, 0, SystemAllocPolicy> errors;
     713             :     bool overRecursed;
     714             :     bool outOfMemory;
     715             : 
     716             :     ParseTask(ParseTaskKind kind, JSContext* cx,
     717             :               JS::OffThreadCompileCallback callback, void* callbackData);
     718             :     virtual ~ParseTask();
     719             : 
     720             :     bool init(JSContext* cx, const ReadOnlyCompileOptions& options, JSObject* global);
     721             : 
     722             :     void activate(JSRuntime* rt);
     723             :     virtual void parse(JSContext* cx) = 0;
     724             :     bool finish(JSContext* cx);
     725             : 
     726             :     bool runtimeMatches(JSRuntime* rt) {
     727           0 :         return parseGlobal->runtimeFromAnyThread() == rt;
     728             :     }
     729             : 
     730             :     void trace(JSTracer* trc);
     731             : 
     732             :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     733             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     734           0 :         return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
     735             :     }
     736             : };
     737             : 
     738           5 : struct ScriptParseTask : public ParseTask
     739             : {
     740             :     JS::TwoByteChars data;
     741             : 
     742             :     ScriptParseTask(JSContext* cx, const char16_t* chars, size_t length,
     743             :                     JS::OffThreadCompileCallback callback, void* callbackData);
     744             :     void parse(JSContext* cx) override;
     745             : };
     746             : 
     747           0 : struct ModuleParseTask : public ParseTask
     748             : {
     749             :     JS::TwoByteChars data;
     750             : 
     751             :     ModuleParseTask(JSContext* cx, const char16_t* chars, size_t length,
     752             :                     JS::OffThreadCompileCallback callback, void* callbackData);
     753             :     void parse(JSContext* cx) override;
     754             : };
     755             : 
     756           0 : struct ScriptDecodeTask : public ParseTask
     757             : {
     758             :     const JS::TranscodeRange range;
     759             : 
     760             :     ScriptDecodeTask(JSContext* cx, const JS::TranscodeRange& range,
     761             :                      JS::OffThreadCompileCallback callback, void* callbackData);
     762             :     void parse(JSContext* cx) override;
     763             : };
     764             : 
     765             : #if defined(JS_BUILD_BINAST)
     766             : 
     767           0 : struct BinASTDecodeTask : public ParseTask
     768             : {
     769             :     mozilla::Range<const uint8_t> data;
     770             : 
     771             :     BinASTDecodeTask(JSContext* cx, const uint8_t* buf, size_t length,
     772             :                      JS::OffThreadCompileCallback callback, void* callbackData);
     773             :     void parse(JSContext* cx) override;
     774             : };
     775             : 
     776             : #endif /* JS_BUILD_BINAST */
     777             : 
     778           0 : struct MultiScriptsDecodeTask : public ParseTask
     779             : {
     780             :     JS::TranscodeSources* sources;
     781             : 
     782             :     MultiScriptsDecodeTask(JSContext* cx, JS::TranscodeSources& sources,
     783             :                            JS::OffThreadCompileCallback callback, void* callbackData);
     784             :     void parse(JSContext* cx) override;
     785             : };
     786             : 
     787             : // Return whether, if a new parse task was started, it would need to wait for
     788             : // an in-progress GC to complete before starting.
     789             : extern bool
     790             : OffThreadParsingMustWaitForGC(JSRuntime* rt);
     791             : 
     792             : // It is not desirable to eagerly compress: if lazy functions that are tied to
     793             : // the ScriptSource were to be executed relatively soon after parsing, they
     794             : // would need to block on decompression, which hurts responsiveness.
     795             : //
     796             : // To this end, compression tasks are heap allocated and enqueued in a pending
     797             : // list by ScriptSource::setSourceCopy. When a major GC occurs, we schedule
     798             : // pending compression tasks and move the ones that are ready to be compressed
     799             : // to the worklist. Currently, a compression task is considered ready 2 major
     800             : // GCs after being enqueued. Completed tasks are handled during the sweeping
     801             : // phase by AttachCompressedSourcesTask, which runs in parallel with other GC
     802             : // sweeping tasks.
     803           0 : class SourceCompressionTask
     804             : {
     805             :     friend struct HelperThread;
     806             :     friend class ScriptSource;
     807             : 
     808             :     // The runtime that the ScriptSource is associated with, in the sense that
     809             :     // it uses the runtime's immutable string cache.
     810             :     JSRuntime* runtime_;
     811             : 
     812             :     // The major GC number of the runtime when the task was enqueued.
     813             :     uint64_t majorGCNumber_;
     814             : 
     815             :     // The source to be compressed.
     816             :     ScriptSourceHolder sourceHolder_;
     817             : 
     818             :     // The resultant compressed string. If the compressed string is larger
     819             :     // than the original, or we OOM'd during compression, or nothing else
     820             :     // except the task is holding the ScriptSource alive when scheduled to
     821             :     // compress, this will remain None upon completion.
     822             :     mozilla::Maybe<SharedImmutableString> resultString_;
     823             : 
     824             :   public:
     825             :     // The majorGCNumber is used for scheduling tasks.
     826           0 :     SourceCompressionTask(JSRuntime* rt, ScriptSource* source)
     827         416 :       : runtime_(rt),
     828         832 :         majorGCNumber_(rt->gc.majorGCCount()),
     829        1664 :         sourceHolder_(source)
     830         416 :     { }
     831             : 
     832             :     bool runtimeMatches(JSRuntime* runtime) const {
     833             :         return runtime == runtime_;
     834             :     }
     835             :     bool shouldStart() const {
     836             :         // We wait 2 major GCs to start compressing, in order to avoid
     837             :         // immediate compression.
     838           0 :         return runtime_->gc.majorGCCount() > majorGCNumber_ + 1;
     839             :     }
     840             : 
     841             :     bool shouldCancel() const {
     842             :         // If the refcount is exactly 1, then nothing else is holding on to the
     843             :         // ScriptSource, so no reason to compress it and we should cancel the task.
     844           0 :         return sourceHolder_.get()->refs == 1;
     845             :     }
     846             : 
     847             :     void work();
     848             :     void complete();
     849             : };
     850             : 
     851             : // A PromiseHelperTask is an OffThreadPromiseTask that executes a single job on
     852             : // a helper thread. Derived classes do their helper-thread work by implementing
     853             : // execute().
     854             : struct PromiseHelperTask : OffThreadPromiseTask
     855             : {
     856             :     PromiseHelperTask(JSContext* cx, Handle<PromiseObject*> promise)
     857             :       : OffThreadPromiseTask(cx, promise)
     858             :     {}
     859             : 
     860             :     // To be called on a helper thread and implemented by the derived class.
     861             :     virtual void execute() = 0;
     862             : 
     863             :     // May be called in the absence of helper threads or off-thread promise
     864             :     // support to synchronously execute and resolve a PromiseTask.
     865             :     //
     866             :     // Warning: After this function returns, 'this' can be deleted at any time, so the
     867             :     // caller must immediately return from the stream callback.
     868             :     void executeAndResolveAndDestroy(JSContext* cx);
     869             : };
     870             : 
     871             : } /* namespace js */
     872             : 
     873             : #endif /* vm_HelperThreads_h */

Generated by: LCOV version 1.13-14-ga5dd952