LCOV - code coverage report
Current view: top level - js/src/vm - HelperThreads.h (source / functions) Hit Total Coverage
Test: output.info Lines: 77 119 64.7 %
Date: 2017-07-14 16:53:18 Functions: 34 63 54.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             : #include "jscntxt.h"
      25             : 
      26             : #include "jit/Ion.h"
      27             : #include "threading/ConditionVariable.h"
      28             : #include "vm/MutexIDs.h"
      29             : 
      30             : namespace JS {
      31             : struct Zone;
      32             : } // namespace JS
      33             : 
      34             : namespace js {
      35             : 
      36             : class AutoLockHelperThreadState;
      37             : class AutoUnlockHelperThreadState;
      38             : class CompileError;
      39             : class PromiseTask;
      40             : struct HelperThread;
      41             : struct ParseTask;
      42             : namespace jit {
      43             :   class IonBuilder;
      44             : } // namespace jit
      45             : namespace wasm {
      46             :   class FuncIR;
      47             :   class FunctionCompileResults;
      48             :   class CompileTask;
      49             :   typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
      50             : } // namespace wasm
      51             : 
      52             : enum class ParseTaskKind
      53             : {
      54             :     Script,
      55             :     Module,
      56             :     ScriptDecode,
      57             :     MultiScriptsDecode
      58             : };
      59             : 
      60             : // Per-process state for off thread work items.
      61           0 : class GlobalHelperThreadState
      62             : {
      63             :     friend class AutoLockHelperThreadState;
      64             :     friend class AutoUnlockHelperThreadState;
      65             : 
      66             :   public:
      67             :     // Number of CPUs to treat this machine as having when creating threads.
      68             :     // May be accessed without locking.
      69             :     size_t cpuCount;
      70             : 
      71             :     // Number of threads to create. May be accessed without locking.
      72             :     size_t threadCount;
      73             : 
      74             :     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
      75             :     typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
      76             :     typedef Vector<UniquePtr<SourceCompressionTask>, 0, SystemAllocPolicy> SourceCompressionTaskVector;
      77             :     typedef Vector<GCHelperState*, 0, SystemAllocPolicy> GCHelperStateVector;
      78             :     typedef Vector<GCParallelTask*, 0, SystemAllocPolicy> GCParallelTaskVector;
      79             :     typedef Vector<PromiseTask*, 0, SystemAllocPolicy> PromiseTaskVector;
      80             : 
      81             :     // List of available threads, or null if the thread state has not been initialized.
      82             :     using HelperThreadVector = Vector<HelperThread, 0, SystemAllocPolicy>;
      83             :     UniquePtr<HelperThreadVector> threads;
      84             : 
      85             :   private:
      86             :     // The lists below are all protected by |lock|.
      87             : 
      88             :     // Ion compilation worklist and finished jobs.
      89             :     IonBuilderVector ionWorklist_, ionFinishedList_, ionFreeList_;
      90             : 
      91             :     // wasm worklist and finished jobs.
      92             :     wasm::CompileTaskPtrVector wasmWorklist_, wasmFinishedList_;
      93             : 
      94             :   public:
      95             :     // For now, only allow a single parallel wasm compilation to happen at a
      96             :     // time. This avoids race conditions on wasmWorklist/wasmFinishedList/etc.
      97             :     mozilla::Atomic<bool> wasmCompilationInProgress;
      98             : 
      99             :   private:
     100             :     // Async tasks that, upon completion, are dispatched back to the JSContext's
     101             :     // owner thread via embedding callbacks instead of a finished list.
     102             :     PromiseTaskVector promiseTasks_;
     103             : 
     104             :     // Script parsing/emitting worklist and finished jobs.
     105             :     ParseTaskVector parseWorklist_, parseFinishedList_;
     106             : 
     107             :     // Parse tasks waiting for an atoms-zone GC to complete.
     108             :     ParseTaskVector parseWaitingOnGC_;
     109             : 
     110             :     // Source compression worklist of tasks that we do not yet know can start.
     111             :     SourceCompressionTaskVector compressionPendingList_;
     112             : 
     113             :     // Source compression worklist of tasks that can start.
     114             :     SourceCompressionTaskVector compressionWorklist_;
     115             : 
     116             :     // Finished source compression tasks.
     117             :     SourceCompressionTaskVector compressionFinishedList_;
     118             : 
     119             :     // Runtimes which have sweeping / allocating work to do.
     120             :     GCHelperStateVector gcHelperWorklist_;
     121             : 
     122             :     // GC tasks needing to be done in parallel.
     123             :     GCParallelTaskVector gcParallelWorklist_;
     124             : 
     125             :     ParseTask* removeFinishedParseTask(ParseTaskKind kind, void* token);
     126             : 
     127             :   public:
     128             :     size_t maxIonCompilationThreads() const;
     129             :     size_t maxUnpausedIonCompilationThreads() const;
     130             :     size_t maxWasmCompilationThreads() const;
     131             :     size_t maxParseThreads() const;
     132             :     size_t maxCompressionThreads() const;
     133             :     size_t maxGCHelperThreads() const;
     134             :     size_t maxGCParallelThreads() const;
     135             : 
     136             :     GlobalHelperThreadState();
     137             : 
     138             :     bool ensureInitialized();
     139             :     void finish();
     140             :     void finishThreads();
     141             : 
     142             :     void lock();
     143             :     void unlock();
     144             : #ifdef DEBUG
     145             :     bool isLockedByCurrentThread();
     146             : #endif
     147             : 
     148             :     enum CondVar {
     149             :         // For notifying threads waiting for work that they may be able to make progress.
     150             :         CONSUMER,
     151             : 
     152             :         // For notifying threads doing work that they may be able to make progress.
     153             :         PRODUCER,
     154             : 
     155             :         // For notifying threads doing work which are paused that they may be
     156             :         // able to resume making progress.
     157             :         PAUSE
     158             :     };
     159             : 
     160             :     void wait(AutoLockHelperThreadState& locked, CondVar which,
     161             :               mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
     162             :     void notifyAll(CondVar which, const AutoLockHelperThreadState&);
     163             :     void notifyOne(CondVar which, const AutoLockHelperThreadState&);
     164             : 
     165             :     // Helper method for removing items from the vectors below while iterating over them.
     166             :     template <typename T>
     167          23 :     void remove(T& vector, size_t* index)
     168             :     {
     169             :         // Self-moving is undefined behavior.
     170          23 :         if (*index != vector.length() - 1)
     171           1 :             vector[*index] = mozilla::Move(vector.back());
     172          23 :         (*index)--;
     173          23 :         vector.popBack();
     174          23 :     }
     175             : 
     176         413 :     IonBuilderVector& ionWorklist(const AutoLockHelperThreadState&) {
     177         413 :         return ionWorklist_;
     178             :     }
     179         258 :     IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
     180         258 :         return ionFinishedList_;
     181             :     }
     182         130 :     IonBuilderVector& ionFreeList(const AutoLockHelperThreadState&) {
     183         130 :         return ionFreeList_;
     184             :     }
     185             : 
     186         161 :     wasm::CompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&) {
     187         161 :         return wasmWorklist_;
     188             :     }
     189           0 :     wasm::CompileTaskPtrVector& wasmFinishedList(const AutoLockHelperThreadState&) {
     190           0 :         return wasmFinishedList_;
     191             :     }
     192             : 
     193         161 :     PromiseTaskVector& promiseTasks(const AutoLockHelperThreadState&) {
     194         161 :         return promiseTasks_;
     195             :     }
     196             : 
     197         209 :     ParseTaskVector& parseWorklist(const AutoLockHelperThreadState&) {
     198         209 :         return parseWorklist_;
     199             :     }
     200          30 :     ParseTaskVector& parseFinishedList(const AutoLockHelperThreadState&) {
     201          30 :         return parseFinishedList_;
     202             :     }
     203           0 :     ParseTaskVector& parseWaitingOnGC(const AutoLockHelperThreadState&) {
     204           0 :         return parseWaitingOnGC_;
     205             :     }
     206             : 
     207         156 :     SourceCompressionTaskVector& compressionPendingList(const AutoLockHelperThreadState&) {
     208         156 :         return compressionPendingList_;
     209             :     }
     210             : 
     211         131 :     SourceCompressionTaskVector& compressionWorklist(const AutoLockHelperThreadState&) {
     212         131 :         return compressionWorklist_;
     213             :     }
     214             : 
     215           0 :     SourceCompressionTaskVector& compressionFinishedList(const AutoLockHelperThreadState&) {
     216           0 :         return compressionFinishedList_;
     217             :     }
     218             : 
     219         153 :     GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
     220         153 :         return gcHelperWorklist_;
     221             :     }
     222             : 
     223         245 :     GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
     224         245 :         return gcParallelWorklist_;
     225             :     }
     226             : 
     227             :     bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
     228             :     bool canStartPromiseTask(const AutoLockHelperThreadState& lock);
     229             :     bool canStartIonCompile(const AutoLockHelperThreadState& lock);
     230             :     bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
     231             :     bool canStartParseTask(const AutoLockHelperThreadState& lock);
     232             :     bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
     233             :     bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
     234             :     bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
     235             : 
     236             :     // Used by a major GC to signal processing enqueued compression tasks.
     237             :     void startHandlingCompressionTasks(const AutoLockHelperThreadState&);
     238             :     void scheduleCompressionTasks(const AutoLockHelperThreadState&);
     239             : 
     240             :     // Unlike the methods above, the value returned by this method can change
     241             :     // over time, even if the helper thread state lock is held throughout.
     242             :     bool pendingIonCompileHasSufficientPriority(const AutoLockHelperThreadState& lock);
     243             : 
     244             :     jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
     245             :                                                       bool remove = false);
     246             :     HelperThread* lowestPriorityUnpausedIonCompileAtThreshold(
     247             :         const AutoLockHelperThreadState& lock);
     248             :     HelperThread* highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock);
     249             : 
     250           0 :     uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&) {
     251           0 :         uint32_t n = numWasmFailedJobs;
     252           0 :         numWasmFailedJobs = 0;
     253           0 :         return n;
     254             :     }
     255           0 :     UniqueChars harvestWasmError(const AutoLockHelperThreadState&) {
     256           0 :         return Move(firstWasmError);
     257             :     }
     258           0 :     void noteWasmFailure(const AutoLockHelperThreadState&) {
     259             :         // Be mindful to signal the active thread after calling this function.
     260           0 :         numWasmFailedJobs++;
     261           0 :     }
     262           0 :     void setWasmError(const AutoLockHelperThreadState&, UniqueChars error) {
     263           0 :         if (!firstWasmError)
     264           0 :             firstWasmError = Move(error);
     265           0 :     }
     266           0 :     bool wasmFailed(const AutoLockHelperThreadState&) {
     267           0 :         return bool(numWasmFailedJobs);
     268             :     }
     269             : 
     270             :     template <
     271             :         typename F,
     272             :         typename = typename mozilla::EnableIf<
     273             :             // Matches when the type is a function or lambda with the signature `bool(ParseTask*)`
     274             :             mozilla::IsSame<bool, decltype((*(F*)nullptr)((ParseTask*)nullptr))>::value
     275             :         >::Type
     276             :     >
     277             :     bool finishParseTask(JSContext* cx, ParseTaskKind kind, void* token, F&& finishCallback);
     278             : 
     279             :     JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, void* token);
     280             : 
     281             :     bool finishParseTask(JSContext* cx, ParseTaskKind kind, void* token, MutableHandle<ScriptVector> scripts);
     282             : 
     283             :     void cancelParseTask(JSRuntime* rt, ParseTaskKind kind, void* token);
     284             : 
     285             :     void mergeParseTaskCompartment(JSContext* cx, ParseTask* parseTask,
     286             :                                    Handle<GlobalObject*> global,
     287             :                                    JSCompartment* dest);
     288             : 
     289             :     void trace(JSTracer* trc);
     290             : 
     291             :   private:
     292             :     /*
     293             :      * Number of wasm jobs that encountered failure for the active module.
     294             :      * Their parent is logically the active thread, and this number serves for harvesting.
     295             :      */
     296             :     uint32_t numWasmFailedJobs;
     297             :     /*
     298             :      * Error string from wasm validation. Arbitrarily choose to keep the first one that gets
     299             :      * reported. Nondeterministic if multiple threads have errors.
     300             :      */
     301             :     UniqueChars firstWasmError;
     302             : 
     303             :   public:
     304             :     JSScript* finishScriptParseTask(JSContext* cx, void* token);
     305             :     JSScript* finishScriptDecodeTask(JSContext* cx, void* token);
     306             :     bool finishMultiScriptsDecodeTask(JSContext* cx, void* token, MutableHandle<ScriptVector> scripts);
     307             :     JSObject* finishModuleParseTask(JSContext* cx, void* token);
     308             : 
     309             :     bool hasActiveThreads(const AutoLockHelperThreadState&);
     310             :     void waitForAllThreads();
     311             : 
     312             :     template <typename T>
     313             :     bool checkTaskThreadLimit(size_t maxThreads) const;
     314             : 
     315             :   private:
     316             : 
     317             :     /*
     318             :      * Lock protecting all mutable shared state accessed by helper threads, and
     319             :      * used by all condition variables.
     320             :      */
     321             :     js::Mutex helperLock;
     322             : 
     323             :     /* Condvars for threads waiting/notifying each other. */
     324             :     js::ConditionVariable consumerWakeup;
     325             :     js::ConditionVariable producerWakeup;
     326             :     js::ConditionVariable pauseWakeup;
     327             : 
     328         216 :     js::ConditionVariable& whichWakeup(CondVar which) {
     329         216 :         switch (which) {
     330          69 :           case CONSUMER: return consumerWakeup;
     331         145 :           case PRODUCER: return producerWakeup;
     332           2 :           case PAUSE: return pauseWakeup;
     333           0 :           default: MOZ_CRASH("Invalid CondVar in |whichWakeup|");
     334             :         }
     335             :     }
     336             : };
     337             : 
     338             : static inline GlobalHelperThreadState&
     339        4631 : HelperThreadState()
     340             : {
     341             :     extern GlobalHelperThreadState* gHelperThreadState;
     342             : 
     343        4631 :     MOZ_ASSERT(gHelperThreadState);
     344        4631 :     return *gHelperThreadState;
     345             : }
     346             : 
     347             : typedef mozilla::Variant<jit::IonBuilder*,
     348             :                          wasm::CompileTask*,
     349             :                          PromiseTask*,
     350             :                          ParseTask*,
     351             :                          SourceCompressionTask*,
     352             :                          GCHelperState*,
     353             :                          GCParallelTask*> HelperTaskUnion;
     354             : 
     355             : /* Individual helper thread, one allocated per core. */
     356          36 : struct HelperThread
     357             : {
     358             :     mozilla::Maybe<Thread> thread;
     359             : 
     360             :     /*
     361             :      * Indicate to a thread that it should terminate itself. This is only read
     362             :      * or written with the helper thread state lock held.
     363             :      */
     364             :     bool terminate;
     365             : 
     366             :     /*
     367             :      * Indicate to a thread that it should pause execution. This is only
     368             :      * written with the helper thread state lock held, but may be read from
     369             :      * without the lock held.
     370             :      */
     371             :     mozilla::Atomic<bool, mozilla::Relaxed> pause;
     372             : 
     373             :     /* The current task being executed by this thread, if any. */
     374             :     mozilla::Maybe<HelperTaskUnion> currentTask;
     375             : 
     376         145 :     bool idle() const {
     377         145 :         return currentTask.isNothing();
     378             :     }
     379             : 
     380             :     /* Any builder currently being compiled by Ion on this thread. */
     381        3100 :     jit::IonBuilder* ionBuilder() {
     382        3100 :         return maybeCurrentTaskAs<jit::IonBuilder*>();
     383             :     }
     384             : 
     385             :     /* Any wasm data currently being optimized on this thread. */
     386           0 :     wasm::CompileTask* wasmTask() {
     387           0 :         return maybeCurrentTaskAs<wasm::CompileTask*>();
     388             :     }
     389             : 
     390             :     /* Any source being parsed/emitted on this thread. */
     391          16 :     ParseTask* parseTask() {
     392          16 :         return maybeCurrentTaskAs<ParseTask*>();
     393             :     }
     394             : 
     395             :     /* Any source being compressed on this thread. */
     396           0 :     SourceCompressionTask* compressionTask() {
     397           0 :         return maybeCurrentTaskAs<SourceCompressionTask*>();
     398             :     }
     399             : 
     400             :     /* Any GC state for background sweeping or allocating being performed. */
     401           0 :     GCHelperState* gcHelperTask() {
     402           0 :         return maybeCurrentTaskAs<GCHelperState*>();
     403             :     }
     404             : 
     405             :     /* State required to perform a GC parallel task. */
     406          23 :     GCParallelTask* gcParallelTask() {
     407          23 :         return maybeCurrentTaskAs<GCParallelTask*>();
     408             :     }
     409             : 
     410             :     void destroy();
     411             : 
     412             :     static void ThreadMain(void* arg);
     413             :     void threadLoop();
     414             : 
     415             :   private:
     416             :     template <typename T>
     417        3139 :     T maybeCurrentTaskAs() {
     418        3139 :         if (currentTask.isSome() && currentTask->is<T>())
     419          45 :             return currentTask->as<T>();
     420             : 
     421        3094 :         return nullptr;
     422             :     }
     423             : 
     424             :     void handleWasmWorkload(AutoLockHelperThreadState& locked);
     425             :     void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked);
     426             :     void handleIonWorkload(AutoLockHelperThreadState& locked);
     427             :     void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
     428             :     void handleParseWorkload(AutoLockHelperThreadState& locked);
     429             :     void handleCompressionWorkload(AutoLockHelperThreadState& locked);
     430             :     void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
     431             :     void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
     432             : };
     433             : 
     434             : /* Methods for interacting with helper threads. */
     435             : 
     436             : // Create data structures used by helper threads.
     437             : bool
     438             : CreateHelperThreadsState();
     439             : 
     440             : // Destroy data structures used by helper threads.
     441             : void
     442             : DestroyHelperThreadsState();
     443             : 
     444             : // Initialize helper threads unless already initialized.
     445             : bool
     446             : EnsureHelperThreadsInitialized();
     447             : 
     448             : // This allows the JS shell to override GetCPUCount() when passed the
     449             : // --thread-count=N option.
     450             : void
     451             : SetFakeCPUCount(size_t count);
     452             : 
     453             : // Get the current helper thread, or null.
     454             : HelperThread*
     455             : CurrentHelperThread();
     456             : 
     457             : // Pause the current thread until it's pause flag is unset.
     458             : void
     459             : PauseCurrentHelperThread();
     460             : 
     461             : // Enqueues a wasm compilation task.
     462             : bool
     463             : StartOffThreadWasmCompile(wasm::CompileTask* task);
     464             : 
     465             : namespace wasm {
     466             : 
     467             : // Performs MIR optimization and LIR generation on one or several functions.
     468             : MOZ_MUST_USE bool
     469             : CompileFunction(CompileTask* task, UniqueChars* error);
     470             : 
     471             : }
     472             : 
     473             : /*
     474             :  * If helper threads are available, start executing the given PromiseTask on a
     475             :  * helper thread, finishing back on the originating JSContext's owner thread. If
     476             :  * no helper threads are available, the PromiseTask is synchronously executed
     477             :  * and finished.
     478             :  */
     479             : bool
     480             : StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task);
     481             : 
     482             : /*
     483             :  * Schedule an Ion compilation for a script, given a builder which has been
     484             :  * generated and read everything needed from the VM state.
     485             :  */
     486             : bool
     487             : StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder);
     488             : 
     489             : /*
     490             :  * Schedule deletion of Ion compilation data.
     491             :  */
     492             : bool
     493             : StartOffThreadIonFree(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock);
     494             : 
     495             : struct AllCompilations {};
     496             : struct ZonesInState { JSRuntime* runtime; JS::Zone::GCState state; };
     497             : 
     498             : using CompilationSelector = mozilla::Variant<JSScript*,
     499             :                                              JSCompartment*,
     500             :                                              ZonesInState,
     501             :                                              JSRuntime*,
     502             :                                              AllCompilations>;
     503             : 
     504             : /*
     505             :  * Cancel scheduled or in progress Ion compilations.
     506             :  */
     507             : void
     508             : CancelOffThreadIonCompile(const CompilationSelector& selector, bool discardLazyLinkList);
     509             : 
     510             : inline void
     511           6 : CancelOffThreadIonCompile(JSScript* script)
     512             : {
     513           6 :     CancelOffThreadIonCompile(CompilationSelector(script), true);
     514           6 : }
     515             : 
     516             : inline void
     517             : CancelOffThreadIonCompile(JSCompartment* comp)
     518             : {
     519             :     CancelOffThreadIonCompile(CompilationSelector(comp), true);
     520             : }
     521             : 
     522             : inline void
     523           1 : CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state)
     524             : {
     525           1 :     CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state}), true);
     526           1 : }
     527             : 
     528             : inline void
     529           4 : CancelOffThreadIonCompile(JSRuntime* runtime)
     530             : {
     531           4 :     CancelOffThreadIonCompile(CompilationSelector(runtime), true);
     532           4 : }
     533             : 
     534             : inline void
     535           0 : CancelOffThreadIonCompile()
     536             : {
     537           0 :     CancelOffThreadIonCompile(CompilationSelector(AllCompilations()), false);
     538           0 : }
     539             : 
     540             : #ifdef DEBUG
     541             : bool
     542             : HasOffThreadIonCompile(JSCompartment* comp);
     543             : #endif
     544             : 
     545             : /* Cancel all scheduled, in progress or finished parses for runtime. */
     546             : void
     547             : CancelOffThreadParses(JSRuntime* runtime);
     548             : 
     549             : /*
     550             :  * Start a parse/emit cycle for a stream of source. The characters must stay
     551             :  * alive until the compilation finishes.
     552             :  */
     553             : bool
     554             : StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
     555             :                           const char16_t* chars, size_t length,
     556             :                           JS::OffThreadCompileCallback callback, void* callbackData);
     557             : 
     558             : bool
     559             : StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
     560             :                           const char16_t* chars, size_t length,
     561             :                           JS::OffThreadCompileCallback callback, void* callbackData);
     562             : 
     563             : bool
     564             : StartOffThreadDecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
     565             :                            const JS::TranscodeRange& range,
     566             :                            JS::OffThreadCompileCallback callback, void* callbackData);
     567             : 
     568             : bool
     569             : StartOffThreadDecodeMultiScripts(JSContext* cx, const ReadOnlyCompileOptions& options,
     570             :                                  JS::TranscodeSources& sources,
     571             :                                  JS::OffThreadCompileCallback callback, void* callbackData);
     572             : 
     573             : /*
     574             :  * Called at the end of GC to enqueue any Parse tasks that were waiting on an
     575             :  * atoms-zone GC to finish.
     576             :  */
     577             : void
     578             : EnqueuePendingParseTasksAfterGC(JSRuntime* rt);
     579             : 
     580             : struct AutoEnqueuePendingParseTasksAfterGC {
     581             :     const gc::GCRuntime& gc_;
     582           3 :     explicit AutoEnqueuePendingParseTasksAfterGC(const gc::GCRuntime& gc) : gc_(gc) {}
     583             :     ~AutoEnqueuePendingParseTasksAfterGC();
     584             : };
     585             : 
     586             : // Enqueue a compression job to be processed if there's a major GC.
     587             : bool
     588             : EnqueueOffThreadCompression(JSContext* cx, UniquePtr<SourceCompressionTask> task);
     589             : 
     590             : // Cancel all scheduled, in progress, or finished compression tasks for
     591             : // runtime.
     592             : void
     593             : CancelOffThreadCompressions(JSRuntime* runtime);
     594             : 
     595         491 : class MOZ_RAII AutoLockHelperThreadState : public LockGuard<Mutex>
     596             : {
     597             :     using Base = LockGuard<Mutex>;
     598             : 
     599             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     600             : 
     601             :   public:
     602         527 :     explicit AutoLockHelperThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
     603         527 :       : Base(HelperThreadState().helperLock)
     604             :     {
     605         527 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     606         527 :     }
     607             : };
     608             : 
     609          55 : class MOZ_RAII AutoUnlockHelperThreadState : public UnlockGuard<Mutex>
     610             : {
     611             :     using Base = UnlockGuard<Mutex>;
     612             : 
     613             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     614             : 
     615             :   public:
     616             : 
     617          56 :     explicit AutoUnlockHelperThreadState(AutoLockHelperThreadState& locked
     618             :                                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     619          56 :       : Base(locked)
     620             :     {
     621          56 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     622          56 :     }
     623             : };
     624             : 
     625             : struct ParseTask
     626             : {
     627             :     ParseTaskKind kind;
     628             :     OwningCompileOptions options;
     629             : 
     630             :     mozilla::Variant<const JS::TranscodeRange,
     631             :                      JS::TwoByteChars,
     632             :                      JS::TranscodeSources*> data;
     633             : 
     634             :     LifoAlloc alloc;
     635             : 
     636             :     // Rooted pointer to the global object to use while parsing.
     637             :     JSObject* parseGlobal;
     638             : 
     639             :     // Callback invoked off thread when the parse finishes.
     640             :     JS::OffThreadCompileCallback callback;
     641             :     void* callbackData;
     642             : 
     643             :     // Holds the final scripts between the invocation of the callback and the
     644             :     // point where FinishOffThreadScript is called, which will destroy the
     645             :     // ParseTask.
     646             :     GCVector<JSScript*, 1> scripts;
     647             : 
     648             :     // Holds the ScriptSourceObjects generated for the script compilation.
     649             :     GCVector<ScriptSourceObject*, 1> sourceObjects;
     650             : 
     651             :     // Any errors or warnings produced during compilation. These are reported
     652             :     // when finishing the script.
     653             :     Vector<CompileError*, 0, SystemAllocPolicy> errors;
     654             :     bool overRecursed;
     655             :     bool outOfMemory;
     656             : 
     657             :     ParseTask(ParseTaskKind kind, JSContext* cx, JSObject* parseGlobal,
     658             :               const char16_t* chars, size_t length,
     659             :               JS::OffThreadCompileCallback callback, void* callbackData);
     660             :     ParseTask(ParseTaskKind kind, JSContext* cx, JSObject* parseGlobal,
     661             :               const JS::TranscodeRange& range,
     662             :               JS::OffThreadCompileCallback callback, void* callbackData);
     663             :     ParseTask(ParseTaskKind kind, JSContext* cx, JSObject* parseGlobal,
     664             :               JS::TranscodeSources& sources,
     665             :               JS::OffThreadCompileCallback callback, void* callbackData);
     666             :     bool init(JSContext* cx, const ReadOnlyCompileOptions& options);
     667             : 
     668             :     void activate(JSRuntime* rt);
     669             :     virtual void parse(JSContext* cx) = 0;
     670             :     bool finish(JSContext* cx);
     671             : 
     672           0 :     bool runtimeMatches(JSRuntime* rt) {
     673           0 :         return parseGlobal->runtimeFromAnyThread() == rt;
     674             :     }
     675             : 
     676             :     virtual ~ParseTask();
     677             : 
     678             :     void trace(JSTracer* trc);
     679             : };
     680             : 
     681           0 : struct ScriptParseTask : public ParseTask
     682             : {
     683             :     ScriptParseTask(JSContext* cx, JSObject* parseGlobal,
     684             :                     const char16_t* chars, size_t length,
     685             :                     JS::OffThreadCompileCallback callback, void* callbackData);
     686             :     void parse(JSContext* cx) override;
     687             : };
     688             : 
     689           0 : struct ModuleParseTask : public ParseTask
     690             : {
     691             :     ModuleParseTask(JSContext* cx, JSObject* parseGlobal,
     692             :                     const char16_t* chars, size_t length,
     693             :                     JS::OffThreadCompileCallback callback, void* callbackData);
     694             :     void parse(JSContext* cx) override;
     695             : };
     696             : 
     697           0 : struct ScriptDecodeTask : public ParseTask
     698             : {
     699             :     ScriptDecodeTask(JSContext* cx, JSObject* parseGlobal,
     700             :                      const JS::TranscodeRange& range,
     701             :                      JS::OffThreadCompileCallback callback, void* callbackData);
     702             :     void parse(JSContext* cx) override;
     703             : };
     704             : 
     705          15 : struct MultiScriptsDecodeTask : public ParseTask
     706             : {
     707             :     MultiScriptsDecodeTask(JSContext* cx, JSObject* parseGlobal,
     708             :                            JS::TranscodeSources& sources,
     709             :                            JS::OffThreadCompileCallback callback, void* callbackData);
     710             :     void parse(JSContext* cx) override;
     711             : };
     712             : 
     713             : // Return whether, if a new parse task was started, it would need to wait for
     714             : // an in-progress GC to complete before starting.
     715             : extern bool
     716             : OffThreadParsingMustWaitForGC(JSRuntime* rt);
     717             : 
     718             : // It is not desirable to eagerly compress: if lazy functions that are tied to
     719             : // the ScriptSource were to be executed relatively soon after parsing, they
     720             : // would need to block on decompression, which hurts responsiveness.
     721             : //
     722             : // To this end, compression tasks are heap allocated and enqueued in a pending
     723             : // list by ScriptSource::setSourceCopy. When a major GC occurs, we schedule
     724             : // pending compression tasks and move the ones that are ready to be compressed
     725             : // to the worklist. Currently, a compression task is considered ready 2 major
     726             : // GCs after being enqueued. Completed tasks are handled during the sweeping
     727             : // phase by AttachCompressedSourcesTask, which runs in parallel with other GC
     728             : // sweeping tasks.
     729           0 : class SourceCompressionTask
     730             : {
     731             :     friend struct HelperThread;
     732             :     friend class ScriptSource;
     733             : 
     734             :     // The runtime that the ScriptSource is associated with, in the sense that
     735             :     // it uses the runtime's immutable string cache.
     736             :     JSRuntime* runtime_;
     737             : 
     738             :     // The major GC number of the runtime when the task was enqueued.
     739             :     uint64_t majorGCNumber_;
     740             : 
     741             :     // The source to be compressed.
     742             :     ScriptSourceHolder sourceHolder_;
     743             : 
     744             :     // The resultant compressed string. If the compressed string is larger
     745             :     // than the original, or we OOM'd during compression, or nothing else
     746             :     // except the task is holding the ScriptSource alive when scheduled to
     747             :     // compress, this will remain None upon completion.
     748             :     mozilla::Maybe<SharedImmutableString> resultString_;
     749             : 
     750             :   public:
     751             :     // The majorGCNumber is used for scheduling tasks.
     752         155 :     SourceCompressionTask(JSRuntime* rt, ScriptSource* source)
     753         155 :       : runtime_(rt),
     754         155 :         majorGCNumber_(rt->gc.majorGCCount()),
     755         310 :         sourceHolder_(source)
     756         155 :     { }
     757             : 
     758           0 :     bool runtimeMatches(JSRuntime* runtime) const {
     759           0 :         return runtime == runtime_;
     760             :     }
     761          49 :     bool shouldStart() const {
     762             :         // We wait 2 major GCs to start compressing, in order to avoid
     763             :         // immediate compression.
     764          49 :         return runtime_->gc.majorGCCount() > majorGCNumber_ + 1;
     765             :     }
     766             : 
     767           0 :     bool shouldCancel() const {
     768             :         // If the refcount is exactly 1, then nothing else is holding on to the
     769             :         // ScriptSource, so no reason to compress it and we should cancel the task.
     770           0 :         return sourceHolder_.get()->refs == 1;
     771             :     }
     772             : 
     773             :     void work();
     774             :     void complete();
     775             : };
     776             : 
     777             : } /* namespace js */
     778             : 
     779             : #endif /* vm_HelperThreads_h */

Generated by: LCOV version 1.13