blob: 707733947ba6ac5c8eaa66e325ca6a17d0c82163 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 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#include "src/optimizing-compile-dispatcher.h"
6
7#include "src/base/atomicops.h"
8#include "src/full-codegen/full-codegen.h"
9#include "src/isolate.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010010#include "src/tracing/trace-event.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/v8.h"
12
13namespace v8 {
14namespace internal {
15
16namespace {
17
Ben Murdochc5610432016-08-08 18:44:38 +010018void DisposeCompilationJob(CompilationJob* job, bool restore_function_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019 if (restore_function_code) {
Ben Murdochc5610432016-08-08 18:44:38 +010020 Handle<JSFunction> function = job->info()->closure();
Ben Murdochda12d292016-06-02 14:46:10 +010021 function->ReplaceCode(function->shared()->code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 }
Ben Murdochc5610432016-08-08 18:44:38 +010023 delete job;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024}
25
26} // namespace
27
28
29class OptimizingCompileDispatcher::CompileTask : public v8::Task {
30 public:
31 explicit CompileTask(Isolate* isolate) : isolate_(isolate) {
32 OptimizingCompileDispatcher* dispatcher =
33 isolate_->optimizing_compile_dispatcher();
34 base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
35 ++dispatcher->ref_count_;
36 }
37
38 virtual ~CompileTask() {}
39
40 private:
41 // v8::Task overrides.
42 void Run() override {
43 DisallowHeapAllocation no_allocation;
44 DisallowHandleAllocation no_handles;
45 DisallowHandleDereference no_deref;
46
47 OptimizingCompileDispatcher* dispatcher =
48 isolate_->optimizing_compile_dispatcher();
49 {
50 TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
Ben Murdoch097c5b22016-05-18 11:27:45 +010051 TRACE_EVENT0("v8", "V8.RecompileConcurrent");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052
53 if (dispatcher->recompilation_delay_ != 0) {
54 base::OS::Sleep(base::TimeDelta::FromMilliseconds(
55 dispatcher->recompilation_delay_));
56 }
57
58 dispatcher->CompileNext(dispatcher->NextInput(true));
59 }
60 {
61 base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
62 if (--dispatcher->ref_count_ == 0) {
63 dispatcher->ref_count_zero_.NotifyOne();
64 }
65 }
66 }
67
68 Isolate* isolate_;
69
70 DISALLOW_COPY_AND_ASSIGN(CompileTask);
71};
72
73
74OptimizingCompileDispatcher::~OptimizingCompileDispatcher() {
75#ifdef DEBUG
76 {
77 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
78 DCHECK_EQ(0, ref_count_);
79 }
80#endif
81 DCHECK_EQ(0, input_queue_length_);
82 DeleteArray(input_queue_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083}
84
Ben Murdochc5610432016-08-08 18:44:38 +010085CompilationJob* OptimizingCompileDispatcher::NextInput(bool check_if_flushing) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
87 if (input_queue_length_ == 0) return NULL;
Ben Murdochc5610432016-08-08 18:44:38 +010088 CompilationJob* job = input_queue_[InputQueueIndex(0)];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 DCHECK_NOT_NULL(job);
90 input_queue_shift_ = InputQueueIndex(1);
91 input_queue_length_--;
92 if (check_if_flushing) {
93 if (static_cast<ModeFlag>(base::Acquire_Load(&mode_)) == FLUSH) {
Ben Murdochc5610432016-08-08 18:44:38 +010094 AllowHandleDereference allow_handle_dereference;
95 DisposeCompilationJob(job, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 return NULL;
97 }
98 }
99 return job;
100}
101
Ben Murdochc5610432016-08-08 18:44:38 +0100102void OptimizingCompileDispatcher::CompileNext(CompilationJob* job) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 if (!job) return;
104
105 // The function may have already been optimized by OSR. Simply continue.
Ben Murdochc5610432016-08-08 18:44:38 +0100106 CompilationJob::Status status = job->OptimizeGraph();
107 USE(status); // Prevent an unused-variable error.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108
109 // The function may have already been optimized by OSR. Simply continue.
110 // Use a mutex to make sure that functions marked for install
111 // are always also queued.
112 base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
113 output_queue_.push(job);
114 isolate_->stack_guard()->RequestInstallCode();
115}
116
117
118void OptimizingCompileDispatcher::FlushOutputQueue(bool restore_function_code) {
119 for (;;) {
Ben Murdochc5610432016-08-08 18:44:38 +0100120 CompilationJob* job = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 {
122 base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
123 if (output_queue_.empty()) return;
124 job = output_queue_.front();
125 output_queue_.pop();
126 }
127
Ben Murdochc5610432016-08-08 18:44:38 +0100128 DisposeCompilationJob(job, restore_function_code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 }
130}
131
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133void OptimizingCompileDispatcher::Flush() {
134 base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
135 if (FLAG_block_concurrent_recompilation) Unblock();
136 {
137 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
138 while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
139 base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
140 }
141 FlushOutputQueue(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 if (FLAG_trace_concurrent_recompilation) {
143 PrintF(" ** Flushed concurrent recompilation queues.\n");
144 }
145}
146
147
148void OptimizingCompileDispatcher::Stop() {
149 base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
150 if (FLAG_block_concurrent_recompilation) Unblock();
151 {
152 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
153 while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
154 base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
155 }
156
157 if (recompilation_delay_ != 0) {
158 // At this point the optimizing compiler thread's event loop has stopped.
159 // There is no need for a mutex when reading input_queue_length_.
160 while (input_queue_length_ > 0) CompileNext(NextInput());
161 InstallOptimizedFunctions();
162 } else {
163 FlushOutputQueue(false);
164 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165}
166
167
168void OptimizingCompileDispatcher::InstallOptimizedFunctions() {
169 HandleScope handle_scope(isolate_);
170
171 for (;;) {
Ben Murdochc5610432016-08-08 18:44:38 +0100172 CompilationJob* job = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 {
174 base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
175 if (output_queue_.empty()) return;
176 job = output_queue_.front();
177 output_queue_.pop();
178 }
179 CompilationInfo* info = job->info();
180 Handle<JSFunction> function(*info->closure());
Ben Murdochda12d292016-06-02 14:46:10 +0100181 if (function->IsOptimized()) {
182 if (FLAG_trace_concurrent_recompilation) {
183 PrintF(" ** Aborting compilation for ");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 function->ShortPrint();
Ben Murdochda12d292016-06-02 14:46:10 +0100185 PrintF(" as it has already been optimized.\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 }
Ben Murdochc5610432016-08-08 18:44:38 +0100187 DisposeCompilationJob(job, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100189 Compiler::FinalizeCompilationJob(job);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 }
191 }
192}
193
Ben Murdochc5610432016-08-08 18:44:38 +0100194void OptimizingCompileDispatcher::QueueForOptimization(CompilationJob* job) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 DCHECK(IsQueueAvailable());
Ben Murdochda12d292016-06-02 14:46:10 +0100196 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 // Add job to the back of the input queue.
198 base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
199 DCHECK_LT(input_queue_length_, input_queue_capacity_);
200 input_queue_[InputQueueIndex(input_queue_length_)] = job;
201 input_queue_length_++;
202 }
203 if (FLAG_block_concurrent_recompilation) {
204 blocked_jobs_++;
205 } else {
206 V8::GetCurrentPlatform()->CallOnBackgroundThread(
207 new CompileTask(isolate_), v8::Platform::kShortRunningTask);
208 }
209}
210
211
212void OptimizingCompileDispatcher::Unblock() {
213 while (blocked_jobs_ > 0) {
214 V8::GetCurrentPlatform()->CallOnBackgroundThread(
215 new CompileTask(isolate_), v8::Platform::kShortRunningTask);
216 blocked_jobs_--;
217 }
218}
219
220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221} // namespace internal
222} // namespace v8