js/src/jsworkers.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     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/. */
     7 /*
     8  * Definitions for managing off-main-thread work using a shared, per runtime
     9  * worklist. Worklist items are engine internal, and are distinct from e.g.
    10  * web workers.
    11  */
    13 #ifndef jsworkers_h
    14 #define jsworkers_h
    16 #include "mozilla/GuardObjects.h"
    17 #include "mozilla/PodOperations.h"
    19 #include "jscntxt.h"
    20 #include "jslock.h"
    22 #include "frontend/TokenStream.h"
    23 #include "jit/Ion.h"
    25 namespace js {
    27 struct WorkerThread;
    28 struct AsmJSParallelTask;
    29 struct ParseTask;
    30 namespace jit {
    31   class IonBuilder;
    32 }
    34 #ifdef JS_THREADSAFE
    36 // Per-process state for off thread work items.
    37 class GlobalWorkerThreadState
    38 {
    39   public:
    40     // Number of CPUs to treat this machine as having when creating threads.
    41     // May be accessed without locking.
    42     size_t cpuCount;
    44     // Number of threads to create. May be accessed without locking.
    45     size_t threadCount;
    47     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
    48     typedef Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> AsmJSParallelTaskVector;
    49     typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
    50     typedef Vector<SourceCompressionTask*, 0, SystemAllocPolicy> SourceCompressionTaskVector;
    52     // List of available threads, or null if the thread state has not been initialized.
    53     WorkerThread *threads;
    55   private:
    56     // The lists below are all protected by |lock|.
    58     // Ion compilation worklist and finished jobs.
    59     IonBuilderVector ionWorklist_, ionFinishedList_;
    61     // AsmJS worklist and finished jobs.
    62     //
    63     // Simultaneous AsmJS compilations all service the same AsmJS module.
    64     // The main thread must pick up finished optimizations and perform codegen.
    65     // |asmJSCompilationInProgress| is used to avoid triggering compilations
    66     // for more than one module at a time.
    67     AsmJSParallelTaskVector asmJSWorklist_, asmJSFinishedList_;
    69   public:
    70     // For now, only allow a single parallel asm.js compilation to happen at a
    71     // time. This avoids race conditions on asmJSWorklist/asmJSFinishedList/etc.
    72     mozilla::Atomic<bool> asmJSCompilationInProgress;
    74   private:
    75     // Script parsing/emitting worklist and finished jobs.
    76     ParseTaskVector parseWorklist_, parseFinishedList_;
    78     // Parse tasks waiting for an atoms-zone GC to complete.
    79     ParseTaskVector parseWaitingOnGC_;
    81     // Source compression worklist.
    82     SourceCompressionTaskVector compressionWorklist_;
    84   public:
    85     GlobalWorkerThreadState();
    87     void ensureInitialized();
    88     void finish();
    90     void lock();
    91     void unlock();
    93 # ifdef DEBUG
    94     bool isLocked();
    95 # endif
    97     enum CondVar {
    98         // For notifying threads waiting for work that they may be able to make progress.
    99         CONSUMER,
   101         // For notifying threads doing work that they may be able to make progress.
   102         PRODUCER
   103     };
   105     void wait(CondVar which, uint32_t timeoutMillis = 0);
   106     void notifyAll(CondVar which);
   107     void notifyOne(CondVar which);
   109     // Helper method for removing items from the vectors below while iterating over them.
   110     template <typename T>
   111     void remove(T &vector, size_t *index)
   112     {
   113         vector[(*index)--] = vector.back();
   114         vector.popBack();
   115     }
   117     IonBuilderVector &ionWorklist() {
   118         JS_ASSERT(isLocked());
   119         return ionWorklist_;
   120     }
   121     IonBuilderVector &ionFinishedList() {
   122         JS_ASSERT(isLocked());
   123         return ionFinishedList_;
   124     }
   126     AsmJSParallelTaskVector &asmJSWorklist() {
   127         JS_ASSERT(isLocked());
   128         return asmJSWorklist_;
   129     }
   130     AsmJSParallelTaskVector &asmJSFinishedList() {
   131         JS_ASSERT(isLocked());
   132         return asmJSFinishedList_;
   133     }
   135     ParseTaskVector &parseWorklist() {
   136         JS_ASSERT(isLocked());
   137         return parseWorklist_;
   138     }
   139     ParseTaskVector &parseFinishedList() {
   140         JS_ASSERT(isLocked());
   141         return parseFinishedList_;
   142     }
   143     ParseTaskVector &parseWaitingOnGC() {
   144         JS_ASSERT(isLocked());
   145         return parseWaitingOnGC_;
   146     }
   148     SourceCompressionTaskVector &compressionWorklist() {
   149         JS_ASSERT(isLocked());
   150         return compressionWorklist_;
   151     }
   153     bool canStartAsmJSCompile();
   154     bool canStartIonCompile();
   155     bool canStartParseTask();
   156     bool canStartCompressionTask();
   158     uint32_t harvestFailedAsmJSJobs() {
   159         JS_ASSERT(isLocked());
   160         uint32_t n = numAsmJSFailedJobs;
   161         numAsmJSFailedJobs = 0;
   162         return n;
   163     }
   164     void noteAsmJSFailure(void *func) {
   165         // Be mindful to signal the main thread after calling this function.
   166         JS_ASSERT(isLocked());
   167         if (!asmJSFailedFunction)
   168             asmJSFailedFunction = func;
   169         numAsmJSFailedJobs++;
   170     }
   171     bool asmJSWorkerFailed() const {
   172         return bool(numAsmJSFailedJobs);
   173     }
   174     void resetAsmJSFailureState() {
   175         numAsmJSFailedJobs = 0;
   176         asmJSFailedFunction = nullptr;
   177     }
   178     void *maybeAsmJSFailedFunction() const {
   179         return asmJSFailedFunction;
   180     }
   182     JSScript *finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token);
   183     bool compressionInProgress(SourceCompressionTask *task);
   184     SourceCompressionTask *compressionTaskForSource(ScriptSource *ss);
   186   private:
   188     /*
   189      * Lock protecting all mutable shared state accessed by helper threads, and
   190      * used by all condition variables.
   191      */
   192     PRLock *workerLock;
   194 # ifdef DEBUG
   195     PRThread *lockOwner;
   196 # endif
   198     /* Condvars for threads waiting/notifying each other. */
   199     PRCondVar *consumerWakeup;
   200     PRCondVar *producerWakeup;
   202     /*
   203      * Number of AsmJS workers that encountered failure for the active module.
   204      * Their parent is logically the main thread, and this number serves for harvesting.
   205      */
   206     uint32_t numAsmJSFailedJobs;
   208     /*
   209      * Function index |i| in |Module.function(i)| of first failed AsmJS function.
   210      * -1 if no function has failed.
   211      */
   212     void *asmJSFailedFunction;
   213 };
   215 static inline GlobalWorkerThreadState &
   216 WorkerThreadState()
   217 {
   218     extern GlobalWorkerThreadState gWorkerThreadState;
   219     return gWorkerThreadState;
   220 }
   222 /* Individual helper thread, one allocated per core. */
   223 struct WorkerThread
   224 {
   225     mozilla::Maybe<PerThreadData> threadData;
   226     PRThread *thread;
   228     /* Indicate to an idle thread that it should finish executing. */
   229     bool terminate;
   231     /* Any builder currently being compiled by Ion on this thread. */
   232     jit::IonBuilder *ionBuilder;
   234     /* Any AsmJS data currently being optimized by Ion on this thread. */
   235     AsmJSParallelTask *asmData;
   237     /* Any source being parsed/emitted on this thread. */
   238     ParseTask *parseTask;
   240     /* Any source being compressed on this thread. */
   241     SourceCompressionTask *compressionTask;
   243     bool idle() const {
   244         return !ionBuilder && !asmData && !parseTask && !compressionTask;
   245     }
   247     void destroy();
   249     void handleAsmJSWorkload();
   250     void handleIonWorkload();
   251     void handleParseWorkload();
   252     void handleCompressionWorkload();
   254     static void ThreadMain(void *arg);
   255     void threadLoop();
   256 };
   258 #endif /* JS_THREADSAFE */
   260 /* Methods for interacting with worker threads. */
   262 // Initialize worker threads unless already initialized.
   263 void
   264 EnsureWorkerThreadsInitialized(ExclusiveContext *cx);
   266 // This allows the JS shell to override GetCPUCount() when passed the
   267 // --thread-count=N option.
   268 void
   269 SetFakeCPUCount(size_t count);
   271 #ifdef JS_ION
   273 /* Perform MIR optimization and LIR generation on a single function. */
   274 bool
   275 StartOffThreadAsmJSCompile(ExclusiveContext *cx, AsmJSParallelTask *asmData);
   277 /*
   278  * Schedule an Ion compilation for a script, given a builder which has been
   279  * generated and read everything needed from the VM state.
   280  */
   281 bool
   282 StartOffThreadIonCompile(JSContext *cx, jit::IonBuilder *builder);
   284 #endif // JS_ION
   286 /*
   287  * Cancel a scheduled or in progress Ion compilation for script. If script is
   288  * nullptr, all compilations for the compartment are cancelled.
   289  */
   290 void
   291 CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script);
   293 /* Cancel all scheduled, in progress or finished parses for runtime. */
   294 void
   295 CancelOffThreadParses(JSRuntime *runtime);
   297 /*
   298  * Start a parse/emit cycle for a stream of source. The characters must stay
   299  * alive until the compilation finishes.
   300  */
   301 bool
   302 StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
   303                           const jschar *chars, size_t length,
   304                           JS::OffThreadCompileCallback callback, void *callbackData);
   306 /*
   307  * Called at the end of GC to enqueue any Parse tasks that were waiting on an
   308  * atoms-zone GC to finish.
   309  */
   310 void
   311 EnqueuePendingParseTasksAfterGC(JSRuntime *rt);
   313 /* Start a compression job for the specified token. */
   314 bool
   315 StartOffThreadCompression(ExclusiveContext *cx, SourceCompressionTask *task);
   317 class AutoLockWorkerThreadState
   318 {
   319     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   321 #ifdef JS_THREADSAFE
   322   public:
   323     AutoLockWorkerThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
   324     {
   325         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   326         WorkerThreadState().lock();
   327     }
   329     ~AutoLockWorkerThreadState() {
   330         WorkerThreadState().unlock();
   331     }
   332 #else
   333   public:
   334     AutoLockWorkerThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
   335     {
   336         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   337     }
   338 #endif
   339 };
   341 class AutoUnlockWorkerThreadState
   342 {
   343     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   345   public:
   347     AutoUnlockWorkerThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
   348     {
   349         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   350 #ifdef JS_THREADSAFE
   351         WorkerThreadState().unlock();
   352 #endif
   353     }
   355     ~AutoUnlockWorkerThreadState()
   356     {
   357 #ifdef JS_THREADSAFE
   358         WorkerThreadState().lock();
   359 #endif
   360     }
   361 };
   363 #ifdef JS_ION
   364 struct AsmJSParallelTask
   365 {
   366     JSRuntime *runtime;     // Associated runtime.
   367     LifoAlloc lifo;         // Provider of all heap memory used for compilation.
   368     void *func;             // Really, a ModuleCompiler::Func*
   369     jit::MIRGenerator *mir; // Passed from main thread to worker.
   370     jit::LIRGraph *lir;     // Passed from worker to main thread.
   371     unsigned compileTime;
   373     AsmJSParallelTask(size_t defaultChunkSize)
   374       : runtime(nullptr), lifo(defaultChunkSize), func(nullptr), mir(nullptr), lir(nullptr), compileTime(0)
   375     { }
   377     void init(JSRuntime *rt, void *func, jit::MIRGenerator *mir) {
   378         this->runtime = rt;
   379         this->func = func;
   380         this->mir = mir;
   381         this->lir = nullptr;
   382     }
   383 };
   384 #endif
   386 struct ParseTask
   387 {
   388     ExclusiveContext *cx;
   389     OwningCompileOptions options;
   390     const jschar *chars;
   391     size_t length;
   392     LifoAlloc alloc;
   394     // Rooted pointer to the global object used by 'cx'.
   395     PersistentRootedObject exclusiveContextGlobal;
   397     // Saved GC-managed CompileOptions fields that will populate slots in
   398     // the ScriptSourceObject. We create the ScriptSourceObject in the
   399     // compilation's temporary compartment, so storing these values there
   400     // at that point would create cross-compartment references. Instead we
   401     // hold them here, and install them after merging the compartments.
   402     PersistentRootedObject optionsElement;
   403     PersistentRootedScript optionsIntroductionScript;
   405     // Callback invoked off the main thread when the parse finishes.
   406     JS::OffThreadCompileCallback callback;
   407     void *callbackData;
   409     // Holds the final script between the invocation of the callback and the
   410     // point where FinishOffThreadScript is called, which will destroy the
   411     // ParseTask.
   412     JSScript *script;
   414     // Any errors or warnings produced during compilation. These are reported
   415     // when finishing the script.
   416     Vector<frontend::CompileError *> errors;
   417     bool overRecursed;
   419     ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal,
   420               JSContext *initCx, const jschar *chars, size_t length,
   421               JS::OffThreadCompileCallback callback, void *callbackData);
   422     bool init(JSContext *cx, const ReadOnlyCompileOptions &options);
   424     void activate(JSRuntime *rt);
   425     void finish();
   427     bool runtimeMatches(JSRuntime *rt) {
   428         return exclusiveContextGlobal->runtimeFromAnyThread() == rt;
   429     }
   431     ~ParseTask();
   432 };
   434 #ifdef JS_THREADSAFE
   435 // Return whether, if a new parse task was started, it would need to wait for
   436 // an in-progress GC to complete before starting.
   437 extern bool
   438 OffThreadParsingMustWaitForGC(JSRuntime *rt);
   439 #endif
   441 // Compression tasks are allocated on the stack by their triggering thread,
   442 // which will block on the compression completing as the task goes out of scope
   443 // to ensure it completes at the required time.
   444 struct SourceCompressionTask
   445 {
   446     friend class ScriptSource;
   448 #ifdef JS_THREADSAFE
   449     // Thread performing the compression.
   450     WorkerThread *workerThread;
   451 #endif
   453   private:
   454     // Context from the triggering thread. Don't use this off thread!
   455     ExclusiveContext *cx;
   457     ScriptSource *ss;
   458     const jschar *chars;
   459     bool oom;
   461     // Atomic flag to indicate to a worker thread that it should abort
   462     // compression on the source.
   463     mozilla::Atomic<bool, mozilla::Relaxed> abort_;
   465   public:
   466     explicit SourceCompressionTask(ExclusiveContext *cx)
   467       : cx(cx), ss(nullptr), chars(nullptr), oom(false), abort_(false)
   468     {
   469 #ifdef JS_THREADSAFE
   470         workerThread = nullptr;
   471 #endif
   472     }
   474     ~SourceCompressionTask()
   475     {
   476         complete();
   477     }
   479     bool work();
   480     bool complete();
   481     void abort() { abort_ = true; }
   482     bool active() const { return !!ss; }
   483     ScriptSource *source() { return ss; }
   484     const jschar *uncompressedChars() { return chars; }
   485     void setOOM() { oom = true; }
   486 };
   488 } /* namespace js */
   490 #endif /* jsworkers_h */

mercurial