tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HelperThreads.h (10782B)


      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 * API for managing off-thread work.
      9 */
     10 
     11 #ifndef vm_HelperThreads_h
     12 #define vm_HelperThreads_h
     13 
     14 #include "mozilla/Variant.h"
     15 
     16 #include "js/AllocPolicy.h"
     17 #include "js/HelperThreadAPI.h"
     18 #include "js/shadow/Zone.h"
     19 #include "js/UniquePtr.h"
     20 #include "js/Vector.h"
     21 #include "threading/LockGuard.h"
     22 #include "threading/Mutex.h"
     23 #include "wasm/WasmConstants.h"
     24 
     25 namespace mozilla {
     26 union Utf8Unit;
     27 }
     28 
     29 namespace JS {
     30 class JS_PUBLIC_API ReadOnlyCompileOptions;
     31 class JS_PUBLIC_API ReadOnlyDecodeOptions;
     32 class Zone;
     33 
     34 template <typename UnitT>
     35 class SourceText;
     36 }  // namespace JS
     37 
     38 namespace js {
     39 
     40 class AutoLockHelperThreadState;
     41 struct PromiseHelperTask;
     42 
     43 namespace frontend {
     44 struct InitialStencilAndDelazifications;
     45 }
     46 
     47 namespace gc {
     48 class GCRuntime;
     49 }
     50 
     51 namespace jit {
     52 class BaselineCompileTask;
     53 class IonCompileTask;
     54 class IonFreeTask;
     55 class JitRuntime;
     56 using IonFreeCompileTasks = Vector<IonCompileTask*, 8, SystemAllocPolicy>;
     57 }  // namespace jit
     58 
     59 namespace wasm {
     60 struct CompileTask;
     61 struct CompileTaskState;
     62 struct CompleteTier2GeneratorTask;
     63 using UniqueCompleteTier2GeneratorTask = UniquePtr<CompleteTier2GeneratorTask>;
     64 struct PartialTier2CompileTask;
     65 using UniquePartialTier2CompileTask = UniquePtr<PartialTier2CompileTask>;
     66 }  // namespace wasm
     67 
     68 /*
     69 * Lock protecting all mutable shared state accessed by helper threads, and used
     70 * by all condition variables.
     71 */
     72 extern Mutex gHelperThreadLock MOZ_UNANNOTATED;
     73 
     74 // Set of tasks to dispatch when the helper thread state lock is released.
     75 class AutoHelperTaskQueue {
     76 public:
     77  ~AutoHelperTaskQueue() { dispatchQueuedTasks(); }
     78  bool hasQueuedTasks() const { return !tasksToDispatch.empty(); }
     79  void queueTaskToDispatch(JS::HelperThreadTask* task) const;
     80  void dispatchQueuedTasks();
     81 
     82 private:
     83  // TODO: Convert this to use a linked list.
     84  mutable Vector<JS::HelperThreadTask*, 1, SystemAllocPolicy> tasksToDispatch;
     85 };
     86 
     87 // A lock guard for data protected by the helper thread lock.
     88 //
     89 // This can also queue helper thread tasks to be triggered when the lock is
     90 // released.
     91 class MOZ_RAII AutoLockHelperThreadState
     92    : public AutoHelperTaskQueue,  // Must come before LockGuard.
     93      public LockGuard<Mutex> {
     94 public:
     95  AutoLockHelperThreadState() : LockGuard<Mutex>(gHelperThreadLock) {}
     96  AutoLockHelperThreadState(const AutoLockHelperThreadState&) = delete;
     97 
     98 private:
     99  friend class UnlockGuard<AutoLockHelperThreadState>;
    100  void unlock() {
    101    LockGuard<Mutex>::unlock();
    102    dispatchQueuedTasks();
    103  }
    104 
    105  friend class GlobalHelperThreadState;
    106 };
    107 
    108 using AutoUnlockHelperThreadState = UnlockGuard<AutoLockHelperThreadState>;
    109 
    110 // Create data structures used by helper threads.
    111 bool CreateHelperThreadsState();
    112 
    113 // Destroy data structures used by helper threads.
    114 void DestroyHelperThreadsState();
    115 
    116 // Initialize helper threads unless already initialized.
    117 bool EnsureHelperThreadsInitialized();
    118 
    119 size_t GetHelperThreadCount();
    120 size_t GetHelperThreadCPUCount();
    121 size_t GetMaxWasmCompilationThreads();
    122 
    123 // This allows the JS shell to override GetCPUCount() when passed the
    124 // --thread-count=N option.
    125 bool SetFakeCPUCount(size_t count);
    126 
    127 // Enqueues a wasm compilation task.
    128 bool StartOffThreadWasmCompile(wasm::CompileTask* task,
    129                               wasm::CompileState state);
    130 
    131 // Remove any pending wasm compilation tasks queued with
    132 // StartOffThreadWasmCompile that match the arguments. Return the number
    133 // removed.
    134 size_t RemovePendingWasmCompileTasks(const wasm::CompileTaskState& taskState,
    135                                     wasm::CompileState state,
    136                                     const AutoLockHelperThreadState& lock);
    137 
    138 // Enqueues a wasm Complete Tier-2 compilation task.  This (logically, at
    139 // least) manages a set of sub-tasks that perform compilation of groups of
    140 // functions.
    141 void StartOffThreadWasmCompleteTier2Generator(
    142    wasm::UniqueCompleteTier2GeneratorTask task);
    143 
    144 // Enqueues a wasm Partial Tier-2 compilation task.  This compiles one
    145 // function, doing so itself, without any sub-tasks.
    146 void StartOffThreadWasmPartialTier2Compile(
    147    wasm::UniquePartialTier2CompileTask task);
    148 
    149 // Cancel all background Wasm Complete Tier-2 compilations, both the generator
    150 // task and the individual compilation tasks.
    151 void CancelOffThreadWasmCompleteTier2Generator();
    152 
    153 // Cancel a single background Wasm Partial Tier-2 compilation.
    154 void CancelOffThreadWasmPartialTier2Compile();
    155 
    156 /*
    157 * If helper threads are available, call execute() then dispatchResolve() on the
    158 * given task in a helper thread. If no helper threads are available, the given
    159 * task is executed and resolved synchronously.
    160 *
    161 * This function takes ownership of task unconditionally; if it fails, task is
    162 * deleted.
    163 */
    164 bool StartOffThreadPromiseHelperTask(JSContext* cx,
    165                                     UniquePtr<PromiseHelperTask> task);
    166 
    167 /*
    168 * Like the JSContext-accepting version, but only safe to use when helper
    169 * threads are available, so we can be sure we'll never need to fall back on
    170 * synchronous execution.
    171 *
    172 * This function can be called from any thread, but takes ownership of the task
    173 * only on success. On OOM, it is the caller's responsibility to arrange for the
    174 * task to be cleaned up properly.
    175 */
    176 bool StartOffThreadPromiseHelperTask(PromiseHelperTask* task);
    177 
    178 /*
    179 * Schedule an off-thread Baseline compilation for a script, given a task.
    180 */
    181 bool StartOffThreadBaselineCompile(jit::BaselineCompileTask* task,
    182                                   const AutoLockHelperThreadState& lock);
    183 
    184 void FinishOffThreadBaselineCompile(jit::BaselineCompileTask* task,
    185                                    const AutoLockHelperThreadState& lock);
    186 
    187 /*
    188 * Schedule an off-thread Ion compilation for a script, given a task.
    189 */
    190 bool StartOffThreadIonCompile(jit::IonCompileTask* task,
    191                              const AutoLockHelperThreadState& lock);
    192 
    193 void FinishOffThreadIonCompile(jit::IonCompileTask* task,
    194                               const AutoLockHelperThreadState& lock);
    195 
    196 // RAII class to handle batching compile tasks and starting an IonFreeTask.
    197 class MOZ_RAII AutoStartIonFreeTask {
    198  jit::JitRuntime* jitRuntime_;
    199 
    200  // If true, start an IonFreeTask even if the batch is small.
    201  bool force_;
    202 
    203 public:
    204  explicit AutoStartIonFreeTask(jit::JitRuntime* jitRuntime, bool force = false)
    205      : jitRuntime_(jitRuntime), force_(force) {}
    206  ~AutoStartIonFreeTask();
    207 
    208  [[nodiscard]] bool addIonCompileToFreeTaskBatch(jit::IonCompileTask* task);
    209 };
    210 
    211 struct ZonesInState {
    212  JSRuntime* runtime;
    213  JS::shadow::Zone::GCState state;
    214 };
    215 
    216 using CompilationSelector =
    217    mozilla::Variant<JSScript*, JS::Zone*, ZonesInState, JSRuntime*>;
    218 
    219 /*
    220 * Cancel scheduled or in progress Ion compilations.
    221 */
    222 void CancelOffThreadIonCompile(const CompilationSelector& selector);
    223 
    224 inline void CancelOffThreadIonCompile(JSScript* script) {
    225  CancelOffThreadIonCompile(CompilationSelector(script));
    226 }
    227 
    228 inline void CancelOffThreadIonCompile(JS::Zone* zone) {
    229  CancelOffThreadIonCompile(CompilationSelector(zone));
    230 }
    231 
    232 inline void CancelOffThreadIonCompile(JSRuntime* runtime,
    233                                      JS::shadow::Zone::GCState state) {
    234  CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state}));
    235 }
    236 
    237 inline void CancelOffThreadIonCompile(JSRuntime* runtime) {
    238  CancelOffThreadIonCompile(CompilationSelector(runtime));
    239 }
    240 
    241 #ifdef DEBUG
    242 bool HasOffThreadIonCompile(JS::Zone* zone);
    243 #endif
    244 
    245 /*
    246 * Cancel scheduled or in progress Baseline compilations.
    247 */
    248 void CancelOffThreadBaselineCompile(const CompilationSelector& selector);
    249 
    250 inline void CancelOffThreadBaselineCompile(JSScript* script) {
    251  CancelOffThreadBaselineCompile(CompilationSelector(script));
    252 }
    253 
    254 inline void CancelOffThreadBaselineCompile(JS::Zone* zone) {
    255  CancelOffThreadBaselineCompile(CompilationSelector(zone));
    256 }
    257 
    258 inline void CancelOffThreadBaselineCompile(JSRuntime* runtime,
    259                                           JS::shadow::Zone::GCState state) {
    260  CancelOffThreadBaselineCompile(
    261      CompilationSelector(ZonesInState{runtime, state}));
    262 }
    263 
    264 inline void CancelOffThreadBaselineCompile(JSRuntime* runtime) {
    265  CancelOffThreadBaselineCompile(CompilationSelector(runtime));
    266 }
    267 
    268 /*
    269 * Cancel baseline and Ion compilations.
    270 */
    271 inline void CancelOffThreadCompile(JSRuntime* runtime,
    272                                   JS::shadow::Zone::GCState state) {
    273  CancelOffThreadBaselineCompile(
    274      CompilationSelector(ZonesInState{runtime, state}));
    275  CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state}));
    276 }
    277 
    278 inline void CancelOffThreadCompile(JSRuntime* runtime) {
    279  CancelOffThreadBaselineCompile(runtime);
    280  CancelOffThreadIonCompile(runtime);
    281 }
    282 
    283 /*
    284 * Cancel all scheduled or in progress eager delazification phases for a
    285 * runtime.
    286 */
    287 void CancelOffThreadDelazify(JSRuntime* runtime);
    288 
    289 /*
    290 * Wait for all delazification to complete.
    291 */
    292 void WaitForAllDelazifyTasks(JSRuntime* rt);
    293 
    294 // Start off-thread delazification task, to race the delazification of inner
    295 // functions.
    296 void StartOffThreadDelazification(
    297    JSContext* maybeCx, const JS::ReadOnlyCompileOptions& options,
    298    frontend::InitialStencilAndDelazifications* stencils);
    299 
    300 // Drain the task queues and wait for all helper threads to finish running.
    301 //
    302 // Note that helper threads are shared between runtimes and it's possible that
    303 // another runtime could saturate the helper thread system and cause this to
    304 // never return.
    305 void WaitForAllHelperThreads();
    306 void WaitForAllHelperThreads(AutoLockHelperThreadState& lock);
    307 
    308 // Start handling any compression tasks for this runtime. Called at the start of
    309 // major GC.
    310 void StartOffThreadCompressionsOnGC(JSRuntime* rt, bool isShrinkingGC);
    311 
    312 // Cancel all scheduled, in progress, or finished compression tasks for
    313 // runtime.
    314 void CancelOffThreadCompressions(JSRuntime* runtime);
    315 
    316 void AttachFinishedCompressions(JSRuntime* runtime,
    317                                AutoLockHelperThreadState& lock);
    318 
    319 // Run all pending source compression tasks synchronously, for testing purposes
    320 void RunPendingSourceCompressions(JSRuntime* runtime);
    321 
    322 // False if the off-thread source compression mechanism isn't being used. This
    323 // happens on low core count machines where we are concerned about blocking
    324 // main-thread execution.
    325 bool IsOffThreadSourceCompressionEnabled();
    326 
    327 void AttachFinishedBaselineCompilations(JSContext* cx,
    328                                        AutoLockHelperThreadState& lock);
    329 
    330 }  // namespace js
    331 
    332 #endif /* vm_HelperThreads_h */