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/platform/condition-variable.h"
17 #include "src/base/platform/mutex.h"
18 #include "src/base/platform/semaphore.h"
19 #include "src/globals.h"
20 #include "src/identity-map.h"
21 #include "testing/gtest/include/gtest/gtest_prod.h"  // nogncheck
22 
23 namespace v8 {
24 
25 class Platform;
26 enum class MemoryPressureLevel;
27 
28 namespace internal {
29 
30 class AstValueFactory;
31 class CancelableTaskManager;
32 class CompilerDispatcherJob;
33 class UnoptimizedCompileJob;
34 class CompilerDispatcherTracer;
35 class DeferredHandles;
36 class FunctionLiteral;
37 class Isolate;
38 class ParseInfo;
39 class SharedFunctionInfo;
40 class Zone;
41 
42 template <typename T>
43 class Handle;
44 
45 // The CompilerDispatcher uses a combination of idle tasks and background tasks
46 // to parse and compile lazily parsed functions.
47 //
48 // As both parsing and compilation currently requires a preparation and
49 // finalization step that happens on the main thread, every task has to be
50 // advanced during idle time first. Depending on the properties of the task, it
51 // can then be parsed or compiled on either background threads, or during idle
52 // time. Last, it has to be finalized during idle time again.
53 //
54 // CompilerDispatcher::jobs_ maintains the list of all CompilerDispatcherJobs
55 // the CompilerDispatcher knows about.
56 //
57 // CompilerDispatcher::pending_background_jobs_ contains the set of
58 // CompilerDispatcherJobs that can be processed on a background thread.
59 //
60 // CompilerDispatcher::running_background_jobs_ contains the set of
61 // CompilerDispatcherJobs that are currently being processed on a background
62 // thread.
63 //
64 // CompilerDispatcher::DoIdleWork tries to advance as many jobs out of jobs_ as
65 // possible during idle time. If a job can't be advanced, but is suitable for
66 // background processing, it fires off background threads.
67 //
68 // CompilerDispatcher::DoBackgroundWork advances one of the pending jobs, and
69 // then spins of another idle task to potentially do the final step on the main
70 // thread.
71 class V8_EXPORT_PRIVATE CompilerDispatcher {
72  public:
73   typedef uintptr_t JobId;
74 
75   CompilerDispatcher(Isolate* isolate, Platform* platform,
76                      size_t max_stack_size);
77   ~CompilerDispatcher();
78 
79   // Returns true if the compiler dispatcher is enabled.
80   bool IsEnabled() const;
81 
82   // Enqueue a job for parse and compile. Returns true if a job was enqueued.
83   bool Enqueue(Handle<SharedFunctionInfo> function);
84 
85   // Like Enqueue, but also advances the job so that it can potentially
86   // continue running on a background thread (if at all possible). Returns
87   // true if the job was enqueued.
88   bool EnqueueAndStep(Handle<SharedFunctionInfo> function);
89 
90   // Returns true if there is a pending job for the given function.
91   bool IsEnqueued(Handle<SharedFunctionInfo> function) const;
92 
93   // Blocks until the given function is compiled (and does so as fast as
94   // possible). Returns true if the compile job was successful.
95   bool FinishNow(Handle<SharedFunctionInfo> function);
96 
97   // Blocks until all jobs are finished.
98   void FinishAllNow();
99 
100   // Aborts a given job. Blocks if requested.
101   void Abort(Handle<SharedFunctionInfo> function, BlockingBehavior blocking);
102 
103   // Aborts all jobs. Blocks if requested.
104   void AbortAll(BlockingBehavior blocking);
105 
106   // Memory pressure notifications from the embedder.
107   void MemoryPressureNotification(v8::MemoryPressureLevel level,
108                                   bool is_isolate_locked);
109 
110  private:
111   FRIEND_TEST(CompilerDispatcherTest, EnqueueJob);
112   FRIEND_TEST(CompilerDispatcherTest, EnqueueWithoutSFI);
113   FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStep);
114   FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepWithoutSFI);
115   FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepTwice);
116   FRIEND_TEST(CompilerDispatcherTest, EnqueueParsed);
117   FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepParsed);
118   FRIEND_TEST(CompilerDispatcherTest, IdleTaskSmallIdleTime);
119   FRIEND_TEST(CompilerDispatcherTest, CompileOnBackgroundThread);
120   FRIEND_TEST(CompilerDispatcherTest, FinishNowWithWorkerTask);
121   FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllPendingWorkerTask);
122   FRIEND_TEST(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask);
123   FRIEND_TEST(CompilerDispatcherTest, FinishNowDuringAbortAll);
124   FRIEND_TEST(CompilerDispatcherTest, CompileMultipleOnBackgroundThread);
125 
126   typedef std::map<JobId, std::unique_ptr<CompilerDispatcherJob>> JobMap;
127   typedef IdentityMap<JobId, FreeStoreAllocationPolicy> SharedToJobIdMap;
128   class AbortTask;
129   class WorkerTask;
130   class IdleTask;
131 
132   void WaitForJobIfRunningOnBackground(CompilerDispatcherJob* job);
133   void AbortInactiveJobs();
134   bool CanEnqueue();
135   bool CanEnqueue(Handle<SharedFunctionInfo> function);
136   JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const;
137   void ConsiderJobForBackgroundProcessing(CompilerDispatcherJob* job);
138   void ScheduleMoreWorkerTasksIfNeeded();
139   void ScheduleIdleTaskFromAnyThread();
140   void ScheduleIdleTaskIfNeeded();
141   void ScheduleAbortTask();
142   void DoBackgroundWork();
143   void DoIdleWork(double deadline_in_seconds);
144   JobId Enqueue(std::unique_ptr<CompilerDispatcherJob> job);
145   JobId EnqueueAndStep(std::unique_ptr<CompilerDispatcherJob> job);
146   // Returns job if not removed otherwise iterator following the removed job.
147   JobMap::const_iterator RemoveIfFinished(JobMap::const_iterator job);
148   // Returns iterator to the inserted job.
149   JobMap::const_iterator InsertJob(std::unique_ptr<CompilerDispatcherJob> job);
150   // Returns iterator following the removed job.
151   JobMap::const_iterator RemoveJob(JobMap::const_iterator job);
152   bool FinishNow(CompilerDispatcherJob* job);
153 
154   Isolate* isolate_;
155   Platform* platform_;
156   size_t max_stack_size_;
157 
158   // Copy of FLAG_trace_compiler_dispatcher to allow for access from any thread.
159   bool trace_compiler_dispatcher_;
160 
161   std::unique_ptr<CompilerDispatcherTracer> tracer_;
162 
163   std::unique_ptr<CancelableTaskManager> task_manager_;
164 
165   // Id for next job to be added
166   JobId next_job_id_;
167 
168   // Mapping from job_id to job.
169   JobMap jobs_;
170 
171   // Mapping from SharedFunctionInfo to the corresponding unoptimized
172   // compilation's JobId;
173   SharedToJobIdMap shared_to_unoptimized_job_id_;
174 
175   base::AtomicValue<v8::MemoryPressureLevel> memory_pressure_level_;
176 
177   // The following members can be accessed from any thread. Methods need to hold
178   // the mutex |mutex_| while accessing them.
179   base::Mutex mutex_;
180 
181   // True if the dispatcher is in the process of aborting running tasks.
182   bool abort_;
183 
184   bool idle_task_scheduled_;
185 
186   // Number of scheduled or running WorkerTask objects.
187   int num_worker_tasks_;
188 
189   // The set of CompilerDispatcherJobs that can be advanced on any thread.
190   std::unordered_set<CompilerDispatcherJob*> pending_background_jobs_;
191 
192   // The set of CompilerDispatcherJobs currently processed on background
193   // threads.
194   std::unordered_set<CompilerDispatcherJob*> running_background_jobs_;
195 
196   // If not nullptr, then the main thread waits for the task processing
197   // this job, and blocks on the ConditionVariable main_thread_blocking_signal_.
198   CompilerDispatcherJob* main_thread_blocking_on_job_;
199   base::ConditionVariable main_thread_blocking_signal_;
200 
201   // Test support.
202   base::AtomicValue<bool> block_for_testing_;
203   base::Semaphore semaphore_for_testing_;
204 
205   DISALLOW_COPY_AND_ASSIGN(CompilerDispatcher);
206 };
207 
208 }  // namespace internal
209 }  // namespace v8
210 
211 #endif  // V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_
212