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