• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cstdint>
9 #include <map>
10 #include <memory>
11 #include <unordered_set>
12 #include <utility>
13 
14 #include "src/base/atomic-utils.h"
15 #include "src/base/macros.h"
16 #include "src/base/optional.h"
17 #include "src/base/platform/condition-variable.h"
18 #include "src/base/platform/mutex.h"
19 #include "src/base/platform/semaphore.h"
20 #include "src/common/globals.h"
21 #include "src/handles/maybe-handles.h"
22 #include "src/utils/identity-map.h"
23 #include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck
24 
25 namespace v8 {
26 
27 class Platform;
28 enum class MemoryPressureLevel;
29 
30 namespace internal {
31 
32 class AstRawString;
33 class AstValueFactory;
34 class BackgroundCompileTask;
35 class CancelableTaskManager;
36 class UnoptimizedCompileJob;
37 class CompilerDispatcherTracer;
38 class FunctionLiteral;
39 class Isolate;
40 class ParseInfo;
41 class SharedFunctionInfo;
42 class TimedHistogram;
43 class WorkerThreadRuntimeCallStats;
44 class Zone;
45 
46 template <typename T>
47 class Handle;
48 
49 // The CompilerDispatcher uses a combination of idle tasks and background tasks
50 // to parse and compile lazily parsed functions.
51 //
52 // As both parsing and compilation currently requires a preparation and
53 // finalization step that happens on the main thread, every task has to be
54 // advanced during idle time first. Depending on the properties of the task, it
55 // can then be parsed or compiled on either background threads, or during idle
56 // time. Last, it has to be finalized during idle time again.
57 //
58 // CompilerDispatcher::jobs_ maintains the list of all CompilerDispatcherJobs
59 // the CompilerDispatcher knows about.
60 //
61 // CompilerDispatcher::pending_background_jobs_ contains the set of
62 // CompilerDispatcherJobs that can be processed on a background thread.
63 //
64 // CompilerDispatcher::running_background_jobs_ contains the set of
65 // CompilerDispatcherJobs that are currently being processed on a background
66 // thread.
67 //
68 // CompilerDispatcher::DoIdleWork tries to advance as many jobs out of jobs_ as
69 // possible during idle time. If a job can't be advanced, but is suitable for
70 // background processing, it fires off background threads.
71 //
72 // CompilerDispatcher::DoBackgroundWork advances one of the pending jobs, and
73 // then spins of another idle task to potentially do the final step on the main
74 // thread.
75 class V8_EXPORT_PRIVATE CompilerDispatcher {
76  public:
77   using JobId = uintptr_t;
78 
79   CompilerDispatcher(Isolate* isolate, Platform* platform,
80                      size_t max_stack_size);
81   ~CompilerDispatcher();
82 
83   // Returns true if the compiler dispatcher is enabled.
84   bool IsEnabled() const;
85 
86   base::Optional<JobId> Enqueue(const ParseInfo* outer_parse_info,
87                                 const AstRawString* function_name,
88                                 const FunctionLiteral* function_literal);
89 
90   // Registers the given |function| with the compilation job |job_id|.
91   void RegisterSharedFunctionInfo(JobId job_id, SharedFunctionInfo function);
92 
93   // Returns true if there is a pending job with the given id.
94   bool IsEnqueued(JobId job_id) const;
95 
96   // Returns true if there is a pending job registered for the given function.
97   bool IsEnqueued(Handle<SharedFunctionInfo> function) const;
98 
99   // Blocks until the given function is compiled (and does so as fast as
100   // possible). Returns true if the compile job was successful.
101   bool FinishNow(Handle<SharedFunctionInfo> function);
102 
103   // Aborts compilation job |job_id|.
104   void AbortJob(JobId job_id);
105 
106   // Aborts all jobs, blocking until all jobs are aborted.
107   void AbortAll();
108 
109  private:
110   FRIEND_TEST(CompilerDispatcherTest, IdleTaskNoIdleTime);
111   FRIEND_TEST(CompilerDispatcherTest, IdleTaskSmallIdleTime);
112   FRIEND_TEST(CompilerDispatcherTest, FinishNowWithWorkerTask);
113   FRIEND_TEST(CompilerDispatcherTest, AbortJobNotStarted);
114   FRIEND_TEST(CompilerDispatcherTest, AbortJobAlreadyStarted);
115   FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllPendingWorkerTask);
116   FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask);
117   FRIEND_TEST(CompilerDispatcherTest, CompileMultipleOnBackgroundThread);
118 
119   struct Job {
120     explicit Job(BackgroundCompileTask* task_arg);
121     ~Job();
122 
IsReadyToFinalizeJob123     bool IsReadyToFinalize(const base::MutexGuard&) {
124       return has_run && (!function.is_null() || aborted);
125     }
126 
IsReadyToFinalizeJob127     bool IsReadyToFinalize(base::Mutex* mutex) {
128       base::MutexGuard lock(mutex);
129       return IsReadyToFinalize(lock);
130     }
131 
132     std::unique_ptr<BackgroundCompileTask> task;
133     MaybeHandle<SharedFunctionInfo> function;
134     bool has_run;
135     bool aborted;
136   };
137 
138   using JobMap = std::map<JobId, std::unique_ptr<Job>>;
139   using SharedToJobIdMap = IdentityMap<JobId, FreeStoreAllocationPolicy>;
140 
141   void WaitForJobIfRunningOnBackground(Job* job);
142   JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const;
143   void ScheduleMoreWorkerTasksIfNeeded();
144   void ScheduleIdleTaskFromAnyThread(const base::MutexGuard&);
145   void DoBackgroundWork();
146   void DoIdleWork(double deadline_in_seconds);
147   // Returns iterator to the inserted job.
148   JobMap::const_iterator InsertJob(std::unique_ptr<Job> job);
149   // Returns iterator following the removed job.
150   JobMap::const_iterator RemoveJob(JobMap::const_iterator job);
151 
152   Isolate* isolate_;
153   WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
154   TimedHistogram* background_compile_timer_;
155   std::shared_ptr<v8::TaskRunner> taskrunner_;
156   Platform* platform_;
157   size_t max_stack_size_;
158 
159   // Copy of FLAG_trace_compiler_dispatcher to allow for access from any thread.
160   bool trace_compiler_dispatcher_;
161 
162   std::unique_ptr<CancelableTaskManager> task_manager_;
163 
164   // Id for next job to be added
165   JobId next_job_id_;
166 
167   // Mapping from job_id to job.
168   JobMap jobs_;
169 
170   // Mapping from SharedFunctionInfo to the corresponding unoptimized
171   // compilation's JobId;
172   SharedToJobIdMap shared_to_unoptimized_job_id_;
173 
174   // The following members can be accessed from any thread. Methods need to hold
175   // the mutex |mutex_| while accessing them.
176   base::Mutex mutex_;
177 
178   // True if an idle task is scheduled to be run.
179   bool idle_task_scheduled_;
180 
181   // Number of scheduled or running WorkerTask objects.
182   int num_worker_tasks_;
183 
184   // The set of jobs that can be run on a background thread.
185   std::unordered_set<Job*> pending_background_jobs_;
186 
187   // The set of jobs currently being run on background threads.
188   std::unordered_set<Job*> running_background_jobs_;
189 
190   // If not nullptr, then the main thread waits for the task processing
191   // this job, and blocks on the ConditionVariable main_thread_blocking_signal_.
192   Job* main_thread_blocking_on_job_;
193   base::ConditionVariable main_thread_blocking_signal_;
194 
195   // Test support.
196   base::AtomicValue<bool> block_for_testing_;
197   base::Semaphore semaphore_for_testing_;
198 
199   DISALLOW_COPY_AND_ASSIGN(CompilerDispatcher);
200 };
201 
202 }  // namespace internal
203 }  // namespace v8
204 
205 #endif  // V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_
206