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