1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_ 6 #define V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <unordered_set> 11 #include <utility> 12 13 #include "src/base/atomic-utils.h" 14 #include "src/base/macros.h" 15 #include "src/base/platform/condition-variable.h" 16 #include "src/base/platform/mutex.h" 17 #include "src/base/platform/semaphore.h" 18 #include "src/globals.h" 19 #include "testing/gtest/include/gtest/gtest_prod.h" 20 21 namespace v8 { 22 23 class Platform; 24 enum class MemoryPressureLevel; 25 26 namespace internal { 27 28 class CancelableTaskManager; 29 class CompilerDispatcherJob; 30 class CompilerDispatcherTracer; 31 class DeferredHandles; 32 class FunctionLiteral; 33 class Isolate; 34 class SharedFunctionInfo; 35 class Zone; 36 37 template <typename T> 38 class Handle; 39 40 // The CompilerDispatcher uses a combination of idle tasks and background tasks 41 // to parse and compile lazily parsed functions. 42 // 43 // As both parsing and compilation currently requires a preparation and 44 // finalization step that happens on the main thread, every task has to be 45 // advanced during idle time first. Depending on the properties of the task, it 46 // can then be parsed or compiled on either background threads, or during idle 47 // time. Last, it has to be finalized during idle time again. 48 // 49 // CompilerDispatcher::jobs_ maintains the list of all CompilerDispatcherJobs 50 // the CompilerDispatcher knows about. 51 // 52 // CompilerDispatcher::pending_background_jobs_ contains the set of 53 // CompilerDispatcherJobs that can be processed on a background thread. 54 // 55 // CompilerDispatcher::running_background_jobs_ contains the set of 56 // CompilerDispatcherJobs that are currently being processed on a background 57 // thread. 58 // 59 // CompilerDispatcher::DoIdleWork tries to advance as many jobs out of jobs_ as 60 // possible during idle time. If a job can't be advanced, but is suitable for 61 // background processing, it fires off background threads. 62 // 63 // CompilerDispatcher::DoBackgroundWork advances one of the pending jobs, and 64 // then spins of another idle task to potentially do the final step on the main 65 // thread. 66 class V8_EXPORT_PRIVATE CompilerDispatcher { 67 public: 68 enum class BlockingBehavior { kBlock, kDontBlock }; 69 70 CompilerDispatcher(Isolate* isolate, Platform* platform, 71 size_t max_stack_size); 72 ~CompilerDispatcher(); 73 74 // Returns true if the compiler dispatcher is enabled. 75 bool IsEnabled() const; 76 77 // Enqueue a job for parse and compile. Returns true if a job was enqueued. 78 bool Enqueue(Handle<SharedFunctionInfo> function); 79 80 // Like Enqueue, but also advances the job so that it can potentially 81 // continue running on a background thread (if at all possible). Returns 82 // true if the job was enqueued. 83 bool EnqueueAndStep(Handle<SharedFunctionInfo> function); 84 85 // Enqueue a job for compilation. Function must have already been parsed and 86 // analyzed and be ready for compilation. Returns true if a job was enqueued. 87 bool Enqueue(Handle<Script> script, Handle<SharedFunctionInfo> function, 88 FunctionLiteral* literal, std::shared_ptr<Zone> parse_zone, 89 std::shared_ptr<DeferredHandles> parse_handles, 90 std::shared_ptr<DeferredHandles> compile_handles); 91 92 // Like Enqueue, but also advances the job so that it can potentially 93 // continue running on a background thread (if at all possible). Returns 94 // true if the job was enqueued. 95 bool EnqueueAndStep(Handle<Script> script, 96 Handle<SharedFunctionInfo> function, 97 FunctionLiteral* literal, 98 std::shared_ptr<Zone> parse_zone, 99 std::shared_ptr<DeferredHandles> parse_handles, 100 std::shared_ptr<DeferredHandles> compile_handles); 101 102 // Returns true if there is a pending job for the given function. 103 bool IsEnqueued(Handle<SharedFunctionInfo> function) const; 104 105 // Blocks until the given function is compiled (and does so as fast as 106 // possible). Returns true if the compile job was successful. 107 bool FinishNow(Handle<SharedFunctionInfo> function); 108 109 // Aborts a given job. Blocks if requested. 110 void Abort(Handle<SharedFunctionInfo> function, BlockingBehavior blocking); 111 112 // Aborts all jobs. Blocks if requested. 113 void AbortAll(BlockingBehavior blocking); 114 115 // Memory pressure notifications from the embedder. 116 void MemoryPressureNotification(v8::MemoryPressureLevel level, 117 bool is_isolate_locked); 118 119 private: 120 FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStep); 121 FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepTwice); 122 FRIEND_TEST(CompilerDispatcherTest, EnqueueParsed); 123 FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepParsed); 124 FRIEND_TEST(CompilerDispatcherTest, IdleTaskSmallIdleTime); 125 FRIEND_TEST(CompilerDispatcherTest, CompileOnBackgroundThread); 126 FRIEND_TEST(CompilerDispatcherTest, FinishNowWithBackgroundTask); 127 FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask); 128 FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask); 129 FRIEND_TEST(CompilerDispatcherTest, FinishNowDuringAbortAll); 130 131 typedef std::multimap<std::pair<int, int>, 132 std::unique_ptr<CompilerDispatcherJob>> 133 JobMap; 134 class AbortTask; 135 class BackgroundTask; 136 class IdleTask; 137 138 void WaitForJobIfRunningOnBackground(CompilerDispatcherJob* job); 139 void AbortInactiveJobs(); 140 bool CanEnqueue(Handle<SharedFunctionInfo> function); 141 JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const; 142 void ConsiderJobForBackgroundProcessing(CompilerDispatcherJob* job); 143 void ScheduleMoreBackgroundTasksIfNeeded(); 144 void ScheduleIdleTaskFromAnyThread(); 145 void ScheduleIdleTaskIfNeeded(); 146 void ScheduleAbortTask(); 147 void DoBackgroundWork(); 148 void DoIdleWork(double deadline_in_seconds); 149 150 Isolate* isolate_; 151 Platform* platform_; 152 size_t max_stack_size_; 153 154 // Copy of FLAG_trace_compiler_dispatcher to allow for access from any thread. 155 bool trace_compiler_dispatcher_; 156 157 std::unique_ptr<CompilerDispatcherTracer> tracer_; 158 159 std::unique_ptr<CancelableTaskManager> task_manager_; 160 161 // Mapping from (script id, function literal id) to job. We use a multimap, 162 // as script id is not necessarily unique. 163 JobMap jobs_; 164 165 base::AtomicValue<v8::MemoryPressureLevel> memory_pressure_level_; 166 167 // The following members can be accessed from any thread. Methods need to hold 168 // the mutex |mutex_| while accessing them. 169 base::Mutex mutex_; 170 171 // True if the dispatcher is in the process of aborting running tasks. 172 bool abort_; 173 174 bool idle_task_scheduled_; 175 176 // Number of currently scheduled BackgroundTask objects. 177 size_t num_scheduled_background_tasks_; 178 179 // The set of CompilerDispatcherJobs that can be advanced on any thread. 180 std::unordered_set<CompilerDispatcherJob*> pending_background_jobs_; 181 182 // The set of CompilerDispatcherJobs currently processed on background 183 // threads. 184 std::unordered_set<CompilerDispatcherJob*> running_background_jobs_; 185 186 // If not nullptr, then the main thread waits for the task processing 187 // this job, and blocks on the ConditionVariable main_thread_blocking_signal_. 188 CompilerDispatcherJob* main_thread_blocking_on_job_; 189 base::ConditionVariable main_thread_blocking_signal_; 190 191 // Test support. 192 base::AtomicValue<bool> block_for_testing_; 193 base::Semaphore semaphore_for_testing_; 194 195 DISALLOW_COPY_AND_ASSIGN(CompilerDispatcher); 196 }; 197 198 } // namespace internal 199 } // namespace v8 200 201 #endif // V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_ 202