| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| /* |
| * Definitions for managing off-main-thread work using a shared, per runtime |
| * worklist. Worklist items are engine internal, and are distinct from e.g. |
| * web workers. |
| */ |
| |
| #ifndef jsworkers_h |
| #define jsworkers_h |
| |
| #include "mozilla/GuardObjects.h" |
| #include "mozilla/PodOperations.h" |
| |
| #include "jscntxt.h" |
| #include "jslock.h" |
| |
| #include "jit/Ion.h" |
| |
| namespace js { |
| |
| struct AsmJSParallelTask; |
| |
| namespace jit { |
| class IonBuilder; |
| } |
| |
| #if defined(JS_THREADSAFE) && defined(JS_ION) |
| # define JS_PARALLEL_COMPILATION |
| |
| struct WorkerThread; |
| struct AsmJSParallelTask; |
| |
| /* Per-runtime state for off thread work items. */ |
| class WorkerThreadState |
| { |
| public: |
| /* Available threads. */ |
| WorkerThread *threads; |
| size_t numThreads; |
| |
| enum CondVar { |
| MAIN, |
| WORKER |
| }; |
| |
| /* Shared worklist for Ion worker threads. */ |
| js::Vector<jit::IonBuilder*, 0, SystemAllocPolicy> ionWorklist; |
| |
| /* Worklist for AsmJS worker threads. */ |
| js::Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> asmJSWorklist; |
| |
| /* |
| * Finished list for AsmJS worker threads. |
| * Simultaneous AsmJS compilations all service the same AsmJS module. |
| * The main thread must pick up finished optimizations and perform codegen. |
| */ |
| js::Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> asmJSFinishedList; |
| |
| WorkerThreadState() { mozilla::PodZero(this); } |
| ~WorkerThreadState(); |
| |
| bool init(JSRuntime *rt); |
| |
| void lock(); |
| void unlock(); |
| |
| # ifdef DEBUG |
| bool isLocked(); |
| # endif |
| |
| void wait(CondVar which, uint32_t timeoutMillis = 0); |
| void notify(CondVar which); |
| void notifyAll(CondVar which); |
| |
| bool canStartAsmJSCompile(); |
| bool canStartIonCompile(); |
| |
| uint32_t harvestFailedAsmJSJobs() { |
| JS_ASSERT(isLocked()); |
| uint32_t n = numAsmJSFailedJobs; |
| numAsmJSFailedJobs = 0; |
| return n; |
| } |
| void noteAsmJSFailure(int32_t func) { |
| // Be mindful to signal the main thread after calling this function. |
| JS_ASSERT(isLocked()); |
| if (asmJSFailedFunctionIndex < 0) |
| asmJSFailedFunctionIndex = func; |
| numAsmJSFailedJobs++; |
| } |
| bool asmJSWorkerFailed() const { |
| return bool(numAsmJSFailedJobs); |
| } |
| void resetAsmJSFailureState() { |
| numAsmJSFailedJobs = 0; |
| asmJSFailedFunctionIndex = -1; |
| } |
| int32_t maybeGetAsmJSFailedFunctionIndex() const { |
| return asmJSFailedFunctionIndex; |
| } |
| |
| private: |
| |
| /* |
| * Lock protecting all mutable shared state accessed by helper threads, and |
| * used by all condition variables. |
| */ |
| PRLock *workerLock; |
| |
| # ifdef DEBUG |
| PRThread *lockOwner; |
| # endif |
| |
| /* Condvar to notify the main thread that work has been completed. */ |
| PRCondVar *mainWakeup; |
| |
| /* Condvar to notify helper threads that they may be able to make progress. */ |
| PRCondVar *helperWakeup; |
| |
| /* |
| * Number of AsmJS workers that encountered failure for the active module. |
| * Their parent is logically the main thread, and this number serves for harvesting. |
| */ |
| uint32_t numAsmJSFailedJobs; |
| |
| /* |
| * Function index |i| in |Module.function(i)| of first failed AsmJS function. |
| * -1 if no function has failed. |
| */ |
| int32_t asmJSFailedFunctionIndex; |
| }; |
| |
| /* Individual helper thread, one allocated per core. */ |
| struct WorkerThread |
| { |
| JSRuntime *runtime; |
| |
| mozilla::Maybe<PerThreadData> threadData; |
| PRThread *thread; |
| |
| /* Indicate to an idle thread that it should finish executing. */ |
| bool terminate; |
| |
| /* Any builder currently being compiled by Ion on this thread. */ |
| jit::IonBuilder *ionBuilder; |
| |
| /* Any AsmJS data currently being optimized by Ion on this thread. */ |
| AsmJSParallelTask *asmData; |
| |
| void destroy(); |
| |
| void handleAsmJSWorkload(WorkerThreadState &state); |
| void handleIonWorkload(WorkerThreadState &state); |
| |
| static void ThreadMain(void *arg); |
| void threadLoop(); |
| }; |
| |
| #endif /* JS_THREADSAFE && JS_ION */ |
| |
| inline bool |
| OffThreadCompilationEnabled(JSContext *cx) |
| { |
| #ifdef JS_PARALLEL_COMPILATION |
| return jit::js_IonOptions.parallelCompilation |
| && cx->runtime()->useHelperThreads() |
| && cx->runtime()->helperThreadCount() != 0; |
| #else |
| return false; |
| #endif |
| } |
| |
| /* Methods for interacting with worker threads. */ |
| |
| /* Initialize worker threads unless already initialized. */ |
| bool |
| EnsureParallelCompilationInitialized(JSRuntime *rt); |
| |
| /* Perform MIR optimization and LIR generation on a single function. */ |
| bool |
| StartOffThreadAsmJSCompile(JSContext *cx, AsmJSParallelTask *asmData); |
| |
| /* |
| * Schedule an Ion compilation for a script, given a builder which has been |
| * generated and read everything needed from the VM state. |
| */ |
| bool |
| StartOffThreadIonCompile(JSContext *cx, jit::IonBuilder *builder); |
| |
| /* |
| * Cancel a scheduled or in progress Ion compilation for script. If script is |
| * NULL, all compilations for the compartment are cancelled. |
| */ |
| void |
| CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script); |
| |
| class AutoLockWorkerThreadState |
| { |
| JSRuntime *rt; |
| MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
| |
| public: |
| |
| AutoLockWorkerThreadState(JSRuntime *rt |
| MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
| : rt(rt) |
| { |
| MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
| #ifdef JS_PARALLEL_COMPILATION |
| JS_ASSERT(rt->workerThreadState); |
| rt->workerThreadState->lock(); |
| #else |
| (void)this->rt; |
| #endif |
| } |
| |
| ~AutoLockWorkerThreadState() |
| { |
| #ifdef JS_PARALLEL_COMPILATION |
| rt->workerThreadState->unlock(); |
| #endif |
| } |
| }; |
| |
| class AutoUnlockWorkerThreadState |
| { |
| JSRuntime *rt; |
| MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
| |
| public: |
| |
| AutoUnlockWorkerThreadState(JSRuntime *rt |
| MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
| : rt(rt) |
| { |
| MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
| #ifdef JS_PARALLEL_COMPILATION |
| JS_ASSERT(rt->workerThreadState); |
| rt->workerThreadState->unlock(); |
| #else |
| (void)this->rt; |
| #endif |
| } |
| |
| ~AutoUnlockWorkerThreadState() |
| { |
| #ifdef JS_PARALLEL_COMPILATION |
| rt->workerThreadState->lock(); |
| #endif |
| } |
| }; |
| |
| } /* namespace js */ |
| |
| #endif /* jsworkers_h */ |