HelperThreadState.h (26558B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 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 of 9 * worklist items and pool of threads. Worklist items are engine internal, and 10 * are distinct from e.g. web workers. 11 */ 12 13 #ifndef vm_HelperThreadState_h 14 #define vm_HelperThreadState_h 15 16 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_CRASH 17 #include "mozilla/Attributes.h" // MOZ_RAII 18 #include "mozilla/EnumeratedArray.h" // mozilla::EnumeratedArray 19 #include "mozilla/LinkedList.h" // mozilla::LinkedList, mozilla::LinkedListElement 20 #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf 21 #include "mozilla/RefPtr.h" // RefPtr 22 #include "mozilla/TimeStamp.h" // mozilla::TimeDuration 23 24 #include <stddef.h> // size_t 25 #include <stdint.h> // uint32_t, uint64_t 26 #include <utility> // std::move 27 28 #include "ds/Fifo.h" // Fifo 29 #include "frontend/CompilationStencil.h" // frontend::InitialStencilAndDelazifications 30 #include "gc/GCRuntime.h" // gc::GCRuntime 31 #include "js/AllocPolicy.h" // SystemAllocPolicy 32 #include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions 33 #include "js/experimental/JSStencil.h" // JS::InstantiationStorage 34 #include "js/HelperThreadAPI.h" // JS::HelperThreadTaskCallback 35 #include "js/MemoryMetrics.h" // JS::GlobalStats 36 #include "js/ProfilingStack.h" // JS::RegisterThreadCallback, JS::UnregisterThreadCallback 37 #include "js/RootingAPI.h" // JS::Handle 38 #include "js/UniquePtr.h" // UniquePtr 39 #include "js/Utility.h" // ThreadType 40 #include "threading/ConditionVariable.h" // ConditionVariable 41 #include "threading/ProtectedData.h" // WriteOnceData 42 #include "vm/ConcurrentDelazification.h" // DelazificationContext 43 #include "vm/HelperThreads.h" // AutoLockHelperThreadState, AutoUnlockHelperThreadState 44 #include "vm/HelperThreadTask.h" // HelperThreadTask 45 #include "vm/JSContext.h" // JSContext 46 #include "vm/JSScript.h" // ScriptSource 47 #include "vm/Runtime.h" // JSRuntime 48 #include "vm/SharedImmutableStringsCache.h" // SharedImmutableString 49 #include "wasm/WasmConstants.h" // wasm::CompileState 50 51 class JSTracer; 52 53 namespace js { 54 55 class Compressor; 56 struct DelazifyTask; 57 struct FreeDelazifyTask; 58 struct PromiseHelperTask; 59 class PromiseObject; 60 61 namespace jit { 62 class BaselineCompileTask; 63 class IonCompileTask; 64 class IonFreeTask; 65 } // namespace jit 66 67 namespace wasm { 68 69 struct CompileTask; 70 using CompileTaskPtrFifo = Fifo<CompileTask*, 0, SystemAllocPolicy>; 71 72 struct CompleteTier2GeneratorTask : public HelperThreadTask { 73 virtual ~CompleteTier2GeneratorTask() = default; 74 virtual void cancel() = 0; 75 const char* getName() override { return "CompleteTier2GeneratorTask"; } 76 }; 77 78 using UniqueCompleteTier2GeneratorTask = UniquePtr<CompleteTier2GeneratorTask>; 79 using CompleteTier2GeneratorTaskPtrVector = 80 Vector<CompleteTier2GeneratorTask*, 0, SystemAllocPolicy>; 81 82 struct PartialTier2CompileTask : public HelperThreadTask { 83 virtual ~PartialTier2CompileTask() = default; 84 virtual void cancel() = 0; 85 const char* getName() override { return "PartialTier2CompileTask"; } 86 }; 87 88 using UniquePartialTier2CompileTask = UniquePtr<PartialTier2CompileTask>; 89 using PartialTier2CompileTaskPtrVector = 90 Vector<PartialTier2CompileTask*, 0, SystemAllocPolicy>; 91 92 } // namespace wasm 93 94 // Per-process state for off thread work items. 95 class GlobalHelperThreadState { 96 public: 97 // A single complete tier-2 ModuleGenerator job spawns many compilation jobs, 98 // and we do not want to allow more than one such ModuleGenerator to run at a 99 // time. 100 static const size_t MaxCompleteTier2GeneratorTasks = 1; 101 102 // The number of partial tier 2 compilation tasks that can run 103 // simultaneously. This constant specifies unfortunately both the default 104 // and the maximum. 105 static const size_t MaxPartialTier2CompileTasks = 1; 106 107 // Number of CPUs to treat this machine as having when creating threads. 108 // May be accessed without locking. 109 size_t cpuCount; 110 111 // Number of threads to create. May be accessed without locking. 112 size_t threadCount; 113 114 // Thread stack quota to use when running tasks. 115 size_t stackQuota; 116 117 bool terminating_ = false; 118 119 using BaselineCompileTaskVector = 120 Vector<jit::BaselineCompileTask*, 1, SystemAllocPolicy>; 121 using IonCompileTaskVector = 122 Vector<jit::IonCompileTask*, 0, SystemAllocPolicy>; 123 using IonFreeTaskVector = 124 Vector<js::UniquePtr<jit::IonFreeTask>, 0, SystemAllocPolicy>; 125 using DelazifyTaskList = mozilla::LinkedList<DelazifyTask>; 126 using FreeDelazifyTaskVector = 127 Vector<js::UniquePtr<FreeDelazifyTask>, 1, SystemAllocPolicy>; 128 using SourceCompressionTaskVector = 129 Vector<UniquePtr<SourceCompressionTask>, 0, SystemAllocPolicy>; 130 using PromiseHelperTaskVector = 131 Vector<PromiseHelperTask*, 0, SystemAllocPolicy>; 132 133 // Count of running task by each threadType. 134 mozilla::EnumeratedArray<ThreadType, size_t, 135 size_t(ThreadType::THREAD_TYPE_MAX)> 136 runningTaskCount; 137 size_t totalCountRunningTasks; 138 139 WriteOnceData<JS::RegisterThreadCallback> registerThread; 140 WriteOnceData<JS::UnregisterThreadCallback> unregisterThread; 141 142 // Count of helper threads 'reserved' for parallel marking. This is used to 143 // prevent too many runtimes trying to mark in parallel at once. Does not stop 144 // threads from being used for other kinds of task, including GC tasks. 145 HelperThreadLockData<size_t> gcParallelMarkingThreads; 146 147 private: 148 // The lists below are all protected by |lock|. 149 150 // Baseline compilation worklist and finished jobs. 151 BaselineCompileTaskVector baselineWorklist_, baselineFinishedList_; 152 153 // Ion compilation worklist and finished jobs. 154 IonCompileTaskVector ionWorklist_, ionFinishedList_; 155 IonFreeTaskVector ionFreeList_; 156 157 // wasm worklists. 158 wasm::CompileTaskPtrFifo wasmWorklist_tier1_; 159 wasm::CompileTaskPtrFifo wasmWorklist_tier2_; 160 wasm::CompleteTier2GeneratorTaskPtrVector wasmCompleteTier2GeneratorWorklist_; 161 wasm::PartialTier2CompileTaskPtrVector wasmPartialTier2CompileWorklist_; 162 163 // Count of finished CompleteTier2Generator tasks. 164 uint32_t wasmCompleteTier2GeneratorsFinished_; 165 166 // Async tasks that, upon completion, are dispatched back to the JSContext's 167 // owner thread via embedding callbacks instead of a finished list. 168 PromiseHelperTaskVector promiseHelperTasks_; 169 170 // Script worklist, which might still have function to delazify. 171 DelazifyTaskList delazifyWorklist_; 172 // Ideally an instance should not have a method to free it-self as, the method 173 // has a this pointer, which aliases the deleted instance, and that the method 174 // might have some of its fields aliased on the stack. 175 // 176 // Delazification task are complex and have a lot of fields. To reduce the 177 // risk of having aliased fields on the stack while deleting instances of a 178 // DelazifyTask, we have FreeDelazifyTask. While FreeDelazifyTask suffer from 179 // the same problem, the limited scope of their actions should mitigate the 180 // risk. 181 FreeDelazifyTaskVector freeDelazifyTaskVector_; 182 183 // Source compression worklist of tasks that can start. 184 SourceCompressionTaskVector compressionWorklist_; 185 186 // Finished source compression tasks. 187 SourceCompressionTaskVector compressionFinishedList_; 188 189 // GC tasks needing to be done in parallel. These are first queued in the 190 // GCRuntime before being dispatched to the helper thread system. 191 GCParallelTaskList gcParallelWorklist_; 192 193 using HelperThreadTaskVector = 194 Vector<HelperThreadTask*, 0, SystemAllocPolicy>; 195 // Vector of running HelperThreadTask. 196 // This is used to get the HelperThreadTask that are currently running. 197 HelperThreadTaskVector helperTasks_; 198 199 // Callback to dispatch a task to a thread pool. Set by 200 // JS::SetHelperThreadTaskCallback. If this is not set the internal thread 201 // pool is used. 202 JS::HelperThreadTaskCallback dispatchTaskCallback = nullptr; 203 friend class AutoHelperTaskQueue; 204 205 // Condition variable for notifiying the main thread that a helper task has 206 // completed some work. 207 js::ConditionVariable consumerWakeup; 208 209 #ifdef DEBUG 210 // The number of tasks dispatched to the thread pool that have not started 211 // running yet. 212 size_t tasksPending_ = 0; 213 #endif 214 215 bool isInitialized_ = false; 216 217 bool useInternalThreadPool_ = true; 218 219 public: 220 void addSizeOfIncludingThis(JS::GlobalStats* stats, 221 const AutoLockHelperThreadState& lock) const; 222 223 size_t maxBaselineCompilationThreads() const; 224 size_t maxIonCompilationThreads() const; 225 size_t maxIonFreeThreads() const; 226 size_t maxWasmCompilationThreads() const; 227 size_t maxWasmCompleteTier2GeneratorThreads() const; 228 size_t maxWasmPartialTier2CompileThreads() const; 229 size_t maxPromiseHelperThreads() const; 230 size_t maxDelazifyThreads() const; 231 size_t maxCompressionThreads() const; 232 size_t maxGCParallelThreads() const; 233 234 GlobalHelperThreadState(); 235 236 bool isInitialized(const AutoLockHelperThreadState& lock) const { 237 return isInitialized_; 238 } 239 240 [[nodiscard]] bool ensureInitialized(); 241 [[nodiscard]] bool ensureThreadCount(size_t count, 242 AutoLockHelperThreadState& lock); 243 void finish(AutoLockHelperThreadState& lock); 244 void finishThreads(AutoLockHelperThreadState& lock); 245 246 void setCpuCount(size_t count); 247 248 void setDispatchTaskCallback(JS::HelperThreadTaskCallback callback, 249 size_t threadCount, size_t stackSize, 250 const AutoLockHelperThreadState& lock); 251 252 void destroyHelperContexts(AutoLockHelperThreadState& lock); 253 254 #ifdef DEBUG 255 void assertIsLockedByCurrentThread() const; 256 #endif 257 258 void wait(AutoLockHelperThreadState& lock, 259 mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever()); 260 void notifyAll(const AutoLockHelperThreadState&); 261 262 bool useInternalThreadPool(const AutoLockHelperThreadState& lock) const { 263 return useInternalThreadPool_; 264 } 265 266 bool isTerminating(const AutoLockHelperThreadState& locked) const { 267 return terminating_; 268 } 269 270 private: 271 void notifyOne(const AutoLockHelperThreadState&); 272 273 public: 274 // Helper method for removing items from the vectors below while iterating 275 // over them. 276 template <typename T> 277 static void remove(T& vector, size_t* index) { 278 // Self-moving is undefined behavior. 279 if (*index != vector.length() - 1) { 280 vector[*index] = std::move(vector.back()); 281 } 282 (*index)--; 283 vector.popBack(); 284 } 285 286 BaselineCompileTaskVector& baselineWorklist( 287 const AutoLockHelperThreadState&) { 288 return baselineWorklist_; 289 } 290 BaselineCompileTaskVector& baselineFinishedList( 291 const AutoLockHelperThreadState&) { 292 return baselineFinishedList_; 293 } 294 IonCompileTaskVector& ionWorklist(const AutoLockHelperThreadState&) { 295 return ionWorklist_; 296 } 297 IonCompileTaskVector& ionFinishedList(const AutoLockHelperThreadState&) { 298 return ionFinishedList_; 299 } 300 IonFreeTaskVector& ionFreeList(const AutoLockHelperThreadState&) { 301 return ionFreeList_; 302 } 303 304 wasm::CompileTaskPtrFifo& wasmWorklist(const AutoLockHelperThreadState&, 305 wasm::CompileState state) { 306 switch (state) { 307 case wasm::CompileState::Once: 308 case wasm::CompileState::EagerTier1: 309 case wasm::CompileState::LazyTier1: 310 return wasmWorklist_tier1_; 311 case wasm::CompileState::EagerTier2: 312 case wasm::CompileState::LazyTier2: 313 return wasmWorklist_tier2_; 314 default: 315 MOZ_CRASH(); 316 } 317 } 318 319 wasm::CompleteTier2GeneratorTaskPtrVector& wasmCompleteTier2GeneratorWorklist( 320 const AutoLockHelperThreadState&) { 321 return wasmCompleteTier2GeneratorWorklist_; 322 } 323 324 wasm::PartialTier2CompileTaskPtrVector& wasmPartialTier2CompileWorklist( 325 const AutoLockHelperThreadState&) { 326 return wasmPartialTier2CompileWorklist_; 327 } 328 329 void incWasmCompleteTier2GeneratorsFinished( 330 const AutoLockHelperThreadState&) { 331 wasmCompleteTier2GeneratorsFinished_++; 332 } 333 334 uint32_t wasmCompleteTier2GeneratorsFinished( 335 const AutoLockHelperThreadState&) const { 336 return wasmCompleteTier2GeneratorsFinished_; 337 } 338 339 PromiseHelperTaskVector& promiseHelperTasks( 340 const AutoLockHelperThreadState&) { 341 return promiseHelperTasks_; 342 } 343 344 DelazifyTaskList& delazifyWorklist(const AutoLockHelperThreadState&) { 345 return delazifyWorklist_; 346 } 347 348 FreeDelazifyTaskVector& freeDelazifyTaskVector( 349 const AutoLockHelperThreadState&) { 350 return freeDelazifyTaskVector_; 351 } 352 353 SourceCompressionTaskVector& compressionWorklist( 354 const AutoLockHelperThreadState&) { 355 return compressionWorklist_; 356 } 357 358 SourceCompressionTaskVector& compressionFinishedList( 359 const AutoLockHelperThreadState&) { 360 return compressionFinishedList_; 361 } 362 363 private: 364 GCParallelTaskList& gcParallelWorklist() { return gcParallelWorklist_; } 365 366 HelperThreadTaskVector& helperTasks(const AutoLockHelperThreadState&) { 367 return helperTasks_; 368 } 369 370 bool canStartWasmCompile(const AutoLockHelperThreadState& lock, 371 wasm::CompileState state); 372 373 bool canStartWasmTier1CompileTask(const AutoLockHelperThreadState& lock); 374 bool canStartWasmTier2CompileTask(const AutoLockHelperThreadState& lock); 375 bool canStartWasmCompleteTier2GeneratorTask( 376 const AutoLockHelperThreadState& lock); 377 bool canStartWasmPartialTier2CompileTask( 378 const AutoLockHelperThreadState& lock); 379 bool canStartPromiseHelperTask(const AutoLockHelperThreadState& lock); 380 bool canStartBaselineCompileTask(const AutoLockHelperThreadState& lock); 381 bool canStartIonCompileTask(const AutoLockHelperThreadState& lock); 382 bool canStartIonFreeTask(const AutoLockHelperThreadState& lock); 383 bool canStartFreeDelazifyTask(const AutoLockHelperThreadState& lock); 384 bool canStartDelazifyTask(const AutoLockHelperThreadState& lock); 385 bool canStartCompressionTask(const AutoLockHelperThreadState& lock); 386 bool canStartGCParallelTask(const AutoLockHelperThreadState& lock); 387 388 HelperThreadTask* maybeGetWasmCompile(const AutoLockHelperThreadState& lock, 389 wasm::CompileState state); 390 391 HelperThreadTask* maybeGetWasmTier1CompileTask( 392 const AutoLockHelperThreadState& lock); 393 HelperThreadTask* maybeGetWasmTier2CompileTask( 394 const AutoLockHelperThreadState& lock); 395 HelperThreadTask* maybeGetWasmCompleteTier2GeneratorTask( 396 const AutoLockHelperThreadState& lock); 397 HelperThreadTask* maybeGetWasmPartialTier2CompileTask( 398 const AutoLockHelperThreadState& lock); 399 HelperThreadTask* maybeGetPromiseHelperTask( 400 const AutoLockHelperThreadState& lock); 401 HelperThreadTask* maybeGetBaselineCompileTask( 402 const AutoLockHelperThreadState& lock); 403 HelperThreadTask* maybeGetIonCompileTask( 404 const AutoLockHelperThreadState& lock); 405 HelperThreadTask* maybeGetLowPrioIonCompileTask( 406 const AutoLockHelperThreadState& lock); 407 HelperThreadTask* maybeGetIonFreeTask(const AutoLockHelperThreadState& lock); 408 HelperThreadTask* maybeGetFreeDelazifyTask( 409 const AutoLockHelperThreadState& lock); 410 HelperThreadTask* maybeGetDelazifyTask(const AutoLockHelperThreadState& lock); 411 HelperThreadTask* maybeGetCompressionTask( 412 const AutoLockHelperThreadState& lock); 413 HelperThreadTask* maybeGetGCParallelTask( 414 const AutoLockHelperThreadState& lock); 415 416 jit::IonCompileTask* highestPriorityPendingIonCompile( 417 const AutoLockHelperThreadState& lock, bool checkExecutionStatus); 418 419 bool checkTaskThreadLimit(ThreadType threadType, size_t maxThreads, 420 bool isMaster, 421 const AutoLockHelperThreadState& lock) const; 422 bool checkTaskThreadLimit(ThreadType threadType, size_t maxThreads, 423 const AutoLockHelperThreadState& lock) const { 424 return checkTaskThreadLimit(threadType, maxThreads, /* isMaster */ false, 425 lock); 426 } 427 428 bool hasActiveThreads(const AutoLockHelperThreadState&); 429 bool canStartTasks(const AutoLockHelperThreadState& locked); 430 431 public: 432 // Used by a major GC to create and enqueue compression tasks. 433 enum class ScheduleCompressionTask { NonShrinkingGC, ShrinkingGC, API }; 434 void createAndSubmitCompressionTasks(ScheduleCompressionTask schedule, 435 JSRuntime* rt); 436 437 void runPendingSourceCompressions(JSRuntime* runtime); 438 439 void trace(JSTracer* trc); 440 441 void waitForAllTasks(); 442 void waitForAllTasksLocked(AutoLockHelperThreadState&); 443 444 #ifdef DEBUG 445 bool hasOffThreadIonCompile(Zone* zone, AutoLockHelperThreadState& lock); 446 #endif 447 448 void cancelOffThreadBaselineCompile(const CompilationSelector& selector); 449 void cancelOffThreadIonCompile(const CompilationSelector& selector); 450 void cancelOffThreadWasmCompleteTier2Generator( 451 AutoLockHelperThreadState& lock); 452 void cancelOffThreadWasmPartialTier2Compile(AutoLockHelperThreadState& lock); 453 454 bool hasAnyDelazifyTask(JSRuntime* rt, AutoLockHelperThreadState& lock); 455 void cancelPendingDelazifyTask(JSRuntime* rt, 456 AutoLockHelperThreadState& lock); 457 void waitUntilCancelledDelazifyTasks(JSRuntime* rt, 458 AutoLockHelperThreadState& lock); 459 void waitUntilEmptyFreeDelazifyTaskVector(AutoLockHelperThreadState& lock); 460 461 void cancelOffThreadCompressions(JSRuntime* runtime, 462 AutoLockHelperThreadState& lock); 463 464 void triggerFreeUnusedMemory(); 465 466 bool submitTask(wasm::UniqueCompleteTier2GeneratorTask task); 467 bool submitTask(wasm::UniquePartialTier2CompileTask task); 468 bool submitTask(wasm::CompileTask* task, wasm::CompileState state); 469 bool submitTask(jit::BaselineCompileTask* task, 470 const AutoLockHelperThreadState& locked); 471 bool submitTask(UniquePtr<jit::IonFreeTask>&& task, 472 const AutoLockHelperThreadState& lock); 473 bool submitTask(jit::IonCompileTask* task, 474 const AutoLockHelperThreadState& locked); 475 bool submitTask(UniquePtr<SourceCompressionTask> task, 476 const AutoLockHelperThreadState& locked); 477 void submitTask(DelazifyTask* task, const AutoLockHelperThreadState& locked); 478 bool submitTask(UniquePtr<FreeDelazifyTask> task, 479 const AutoLockHelperThreadState& locked); 480 bool submitTask(PromiseHelperTask* task); 481 bool submitTask(GCParallelTask* task, 482 const AutoLockHelperThreadState& locked); 483 484 void runOneTask(HelperThreadTask* task, AutoLockHelperThreadState& lock); 485 void dispatch(const AutoLockHelperThreadState& locked); 486 487 private: 488 HelperThreadTask* findHighestPriorityTask( 489 const AutoLockHelperThreadState& locked); 490 491 void runTaskLocked(HelperThreadTask* task, AutoLockHelperThreadState& lock); 492 493 using Selector = HelperThreadTask* ( 494 GlobalHelperThreadState::*)(const AutoLockHelperThreadState&); 495 static const Selector selectors[]; 496 }; 497 498 static inline bool IsHelperThreadStateInitialized() { 499 extern GlobalHelperThreadState* gHelperThreadState; 500 return gHelperThreadState; 501 } 502 503 static inline GlobalHelperThreadState& HelperThreadState() { 504 extern GlobalHelperThreadState* gHelperThreadState; 505 506 MOZ_ASSERT(gHelperThreadState); 507 return *gHelperThreadState; 508 } 509 510 // Eagerly delazify functions, and send the result back to the runtime which 511 // requested the stencil to be parsed, by filling the stencil cache. 512 // 513 // This task is scheduled multiple times, each time it is scheduled, it 514 // delazifies a single function. Once the function is delazified, it schedules 515 // the inner functions of the delazified function for delazification using the 516 // DelazifyStrategy. The DelazifyStrategy is responsible for ordering and 517 // filtering functions to be delazified. 518 // 519 // When no more function have to be delazified, a FreeDelazifyTask is scheduled 520 // to remove the memory held by the DelazifyTask. 521 struct DelazifyTask : public mozilla::LinkedListElement<DelazifyTask>, 522 public HelperThreadTask { 523 // HelperThreads are shared between all runtimes in the process so explicitly 524 // track which one we are associated with. 525 JSRuntime* maybeRuntime = nullptr; 526 527 DelazificationContext delazificationCx; 528 529 // Create a new DelazifyTask and initialize it. 530 // 531 // In case of early failure, no errors are reported, as a DelazifyTask is an 532 // optimization and the VM should remain working even without this 533 // optimization in place. 534 static UniquePtr<DelazifyTask> Create( 535 JSRuntime* maybeRuntime, const JS::ReadOnlyCompileOptions& options, 536 frontend::InitialStencilAndDelazifications* stencils); 537 538 DelazifyTask(JSRuntime* maybeRuntime, 539 const JS::PrefableCompileOptions& initialPrefableOptions); 540 ~DelazifyTask(); 541 542 [[nodiscard]] bool init(const JS::ReadOnlyCompileOptions& options, 543 frontend::InitialStencilAndDelazifications* stencils); 544 545 bool runtimeMatchesOrNoRuntime(JSRuntime* rt) { 546 return !maybeRuntime || maybeRuntime == rt; 547 } 548 549 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 550 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { 551 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); 552 } 553 554 void runHelperThreadTask(AutoLockHelperThreadState& locked) override; 555 [[nodiscard]] bool runTask(); 556 ThreadType threadType() override { return ThreadType::THREAD_TYPE_DELAZIFY; } 557 558 bool done() const; 559 560 const char* getName() override { return "DelazifyTask"; } 561 }; 562 563 // The FreeDelazifyTask exists as this is a bad practice to `js_delete(this)`, 564 // as fields might be aliased across the destructor, such as with RAII guards. 565 // The FreeDelazifyTask limits the risk of adding these kind of issues by 566 // limiting the number of fields to the DelazifyTask pointer, before deleting 567 // it-self. 568 struct FreeDelazifyTask : public HelperThreadTask { 569 DelazifyTask* task; 570 571 explicit FreeDelazifyTask(DelazifyTask* t) : task(t) {} 572 void runHelperThreadTask(AutoLockHelperThreadState& locked) override; 573 ThreadType threadType() override { 574 return ThreadType::THREAD_TYPE_DELAZIFY_FREE; 575 } 576 577 const char* getName() override { return "FreeDelazifyTask"; } 578 }; 579 580 // Entry for a single ScriptSource in a SourceCompressionTask. 581 class SourceCompressionTaskEntry { 582 // The source to be compressed. 583 RefPtr<ScriptSource> source_; 584 585 // The resultant compressed string. If the compressed string is larger 586 // than the original, or we OOM'd during compression, or nothing else 587 // except the task is holding the ScriptSource alive when scheduled to 588 // compress, this will remain None upon completion. 589 SharedImmutableString resultString_; 590 591 public: 592 explicit SourceCompressionTaskEntry(ScriptSource* source) : source_(source) {} 593 594 bool shouldCancel() const { 595 // If the refcount is exactly 1, then nothing else is holding on to the 596 // ScriptSource, so no reason to compress it and we should cancel the task. 597 return source_->refs == 1; 598 } 599 600 // The work algorithm, aware whether it's compressing one-byte UTF-8 source 601 // text or UTF-16, for CharT either Utf8Unit or char16_t. Invoked by 602 // work() after doing a type-test of the ScriptSource*. 603 template <typename CharT> 604 void workEncodingSpecific(Compressor& comp); 605 606 void runTask(Compressor& comp); 607 void complete(); 608 609 struct PerformTaskWork; 610 friend struct PerformTaskWork; 611 }; 612 613 // Off-thread task for compressing one or more script sources. 614 // 615 // Completed tasks are handled during the sweeping phase by 616 // AttachFinishedCompressions, which runs in parallel with other GC sweeping 617 // tasks. 618 class SourceCompressionTask final : public HelperThreadTask { 619 friend class HelperThread; 620 friend class ScriptSource; 621 622 // The runtime that the task is associated with, in the sense that it uses the 623 // runtime's immutable string cache. 624 JSRuntime* runtime_; 625 626 // The script sources to compress. 627 Vector<SourceCompressionTaskEntry, 4, SystemAllocPolicy> entries_; 628 629 public: 630 SourceCompressionTask(JSRuntime* rt, ScriptSource* source) : runtime_(rt) { 631 static_assert(decltype(entries_)::InlineLength >= 1, 632 "Appending one entry should be infallible"); 633 MOZ_ALWAYS_TRUE(entries_.emplaceBack(source)); 634 } 635 virtual ~SourceCompressionTask() = default; 636 637 bool runtimeMatches(JSRuntime* runtime) const { return runtime == runtime_; } 638 639 [[nodiscard]] bool addEntry(ScriptSource* source) { 640 return entries_.emplaceBack(source); 641 } 642 643 void runTask(); 644 void runHelperThreadTask(AutoLockHelperThreadState& locked) override; 645 void complete(); 646 647 ThreadType threadType() override { return ThreadType::THREAD_TYPE_COMPRESS; } 648 649 const char* getName() override { return "SourceCompressionTask"; } 650 }; 651 652 // A PromiseHelperTask is an OffThreadPromiseTask that executes a single job on 653 // a helper thread. Call js::StartOffThreadPromiseHelperTask to submit a 654 // PromiseHelperTask for execution. 655 // 656 // Concrete subclasses must implement execute and OffThreadPromiseTask::resolve. 657 // The helper thread will call execute() to do the main work. Then, the thread 658 // of the JSContext used to create the PromiseHelperTask will call resolve() to 659 // resolve promise according to those results. 660 struct PromiseHelperTask : OffThreadPromiseTask, public HelperThreadTask { 661 PromiseHelperTask(JSContext* cx, JS::Handle<PromiseObject*> promise) 662 : OffThreadPromiseTask(cx, promise) {} 663 664 // To be called on a helper thread and implemented by the derived class. 665 virtual void execute() = 0; 666 667 // May be called in the absence of helper threads or off-thread promise 668 // support to synchronously execute and resolve a PromiseTask. 669 // 670 // Warning: After this function returns, 'this' can be deleted at any time, so 671 // the caller must immediately return from the stream callback. 672 void executeAndResolveAndDestroy(JSContext* cx); 673 674 void runHelperThreadTask(AutoLockHelperThreadState& locked) override; 675 ThreadType threadType() override { return THREAD_TYPE_PROMISE_TASK; } 676 677 const char* getName() override { return "PromiseHelperTask"; } 678 }; 679 680 } /* namespace js */ 681 682 #endif /* vm_HelperThreadState_h */