OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/optimizing-compiler-thread.h" | 5 #include "src/optimizing-compiler-thread.h" |
6 | 6 |
7 #include "src/v8.h" | 7 #include "src/v8.h" |
8 | 8 |
9 #include "src/base/atomicops.h" | 9 #include "src/base/atomicops.h" |
10 #include "src/full-codegen.h" | 10 #include "src/full-codegen.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 } | 36 } |
37 delete info; | 37 delete info; |
38 } | 38 } |
39 | 39 |
40 } // namespace | 40 } // namespace |
41 | 41 |
42 | 42 |
43 class OptimizingCompilerThread::CompileTask : public v8::Task { | 43 class OptimizingCompilerThread::CompileTask : public v8::Task { |
44 public: | 44 public: |
45 explicit CompileTask(Isolate* isolate) : isolate_(isolate) { | 45 explicit CompileTask(Isolate* isolate) : isolate_(isolate) { |
46 base::NoBarrier_AtomicIncrement( | 46 OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread(); |
47 &isolate_->optimizing_compiler_thread()->ref_count_, 1); | 47 base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_); |
| 48 ++thread->ref_count_; |
48 } | 49 } |
49 | 50 |
50 virtual ~CompileTask() {} | 51 virtual ~CompileTask() {} |
51 | 52 |
52 private: | 53 private: |
53 // v8::Task overrides. | 54 // v8::Task overrides. |
54 void Run() OVERRIDE { | 55 void Run() OVERRIDE { |
55 DisallowHeapAllocation no_allocation; | 56 DisallowHeapAllocation no_allocation; |
56 DisallowHandleAllocation no_handles; | 57 DisallowHandleAllocation no_handles; |
57 DisallowHandleDereference no_deref; | 58 DisallowHandleDereference no_deref; |
58 | 59 |
59 OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread(); | 60 OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread(); |
60 StopFlag flag = CONTINUE; | |
61 | |
62 { | 61 { |
63 TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_); | 62 TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_); |
64 | 63 |
65 if (thread->recompilation_delay_ != 0) { | 64 if (thread->recompilation_delay_ != 0) { |
66 base::OS::Sleep(thread->recompilation_delay_); | 65 base::OS::Sleep(thread->recompilation_delay_); |
67 } | 66 } |
68 | 67 |
69 OptimizedCompileJob* job = thread->NextInput(&flag); | 68 thread->CompileNext(thread->NextInput(true)); |
70 | 69 } |
71 switch (flag) { | 70 { |
72 case CONTINUE: | 71 base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_); |
73 thread->CompileNext(job); | 72 if (--thread->ref_count_ == 0) { |
74 break; | 73 thread->ref_count_zero_.NotifyOne(); |
75 | |
76 case STOP: | |
77 case FLUSH: { | |
78 AllowHandleDereference allow_handle_dereference; | |
79 if (!job->info()->is_osr()) { | |
80 DisposeOptimizedCompileJob(job, true); | |
81 } | |
82 break; | |
83 } | |
84 } | 74 } |
85 } | 75 } |
86 if (flag == STOP) { | |
87 base::Release_Store(&thread->stop_thread_, | |
88 static_cast<base::AtomicWord>(CONTINUE)); | |
89 thread->stop_semaphore_.Signal(); | |
90 } | |
91 | |
92 if (base::NoBarrier_AtomicIncrement(&thread->ref_count_, -1) == 0) { | |
93 thread->stop_semaphore_.Signal(); | |
94 } | |
95 } | 76 } |
96 | 77 |
97 Isolate* isolate_; | 78 Isolate* isolate_; |
98 | 79 |
99 DISALLOW_COPY_AND_ASSIGN(CompileTask); | 80 DISALLOW_COPY_AND_ASSIGN(CompileTask); |
100 }; | 81 }; |
101 | 82 |
102 | 83 |
103 OptimizingCompilerThread::~OptimizingCompilerThread() { | 84 OptimizingCompilerThread::~OptimizingCompilerThread() { |
104 if (base::NoBarrier_AtomicIncrement(&ref_count_, -1) > 0) { | 85 #ifdef DEBUG |
105 stop_semaphore_.Wait(); | 86 { |
| 87 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_); |
| 88 DCHECK_EQ(0, ref_count_); |
106 } | 89 } |
| 90 #endif |
107 DCHECK_EQ(0, input_queue_length_); | 91 DCHECK_EQ(0, input_queue_length_); |
108 DeleteArray(input_queue_); | 92 DeleteArray(input_queue_); |
109 if (FLAG_concurrent_osr) { | 93 if (FLAG_concurrent_osr) { |
110 #ifdef DEBUG | 94 #ifdef DEBUG |
111 for (int i = 0; i < osr_buffer_capacity_; i++) { | 95 for (int i = 0; i < osr_buffer_capacity_; i++) { |
112 CHECK_NULL(osr_buffer_[i]); | 96 CHECK_NULL(osr_buffer_[i]); |
113 } | 97 } |
114 #endif | 98 #endif |
115 DeleteArray(osr_buffer_); | 99 DeleteArray(osr_buffer_); |
116 } | 100 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 | 152 |
169 CompileNext(NextInput()); | 153 CompileNext(NextInput()); |
170 | 154 |
171 if (tracing_enabled_) { | 155 if (tracing_enabled_) { |
172 time_spent_compiling_ += compiling_timer.Elapsed(); | 156 time_spent_compiling_ += compiling_timer.Elapsed(); |
173 } | 157 } |
174 } | 158 } |
175 } | 159 } |
176 | 160 |
177 | 161 |
178 OptimizedCompileJob* OptimizingCompilerThread::NextInput(StopFlag* flag) { | 162 OptimizedCompileJob* OptimizingCompilerThread::NextInput( |
| 163 bool check_if_flushing) { |
179 base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_); | 164 base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_); |
180 if (input_queue_length_ == 0) { | 165 if (input_queue_length_ == 0) return NULL; |
181 if (flag) { | |
182 UNREACHABLE(); | |
183 *flag = CONTINUE; | |
184 } | |
185 return NULL; | |
186 } | |
187 OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)]; | 166 OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)]; |
188 DCHECK_NOT_NULL(job); | 167 DCHECK_NOT_NULL(job); |
189 input_queue_shift_ = InputQueueIndex(1); | 168 input_queue_shift_ = InputQueueIndex(1); |
190 input_queue_length_--; | 169 input_queue_length_--; |
191 if (flag) { | 170 if (check_if_flushing) { |
192 switch (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_))) { | 171 if (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_)) != CONTINUE) { |
193 case CONTINUE: | 172 if (!job->info()->is_osr()) DisposeOptimizedCompileJob(job, true); |
194 *flag = CONTINUE; | 173 return NULL; |
195 break; | |
196 | |
197 case FLUSH: | |
198 if (input_queue_length_ == 0) { | |
199 *flag = STOP; | |
200 } else { | |
201 *flag = FLUSH; | |
202 } | |
203 break; | |
204 | |
205 case STOP: | |
206 UNREACHABLE(); | |
207 *flag = CONTINUE; | |
208 break; | |
209 } | 174 } |
210 } | 175 } |
211 return job; | 176 return job; |
212 } | 177 } |
213 | 178 |
214 | 179 |
215 void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) { | 180 void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) { |
216 DCHECK_NOT_NULL(job); | 181 if (!job) return; |
217 | 182 |
218 // The function may have already been optimized by OSR. Simply continue. | 183 // The function may have already been optimized by OSR. Simply continue. |
219 OptimizedCompileJob::Status status = job->OptimizeGraph(); | 184 OptimizedCompileJob::Status status = job->OptimizeGraph(); |
220 USE(status); // Prevent an unused-variable error in release mode. | 185 USE(status); // Prevent an unused-variable error in release mode. |
221 DCHECK(status != OptimizedCompileJob::FAILED); | 186 DCHECK(status != OptimizedCompileJob::FAILED); |
222 | 187 |
223 // The function may have already been optimized by OSR. Simply continue. | 188 // The function may have already been optimized by OSR. Simply continue. |
224 // Use a mutex to make sure that functions marked for install | 189 // Use a mutex to make sure that functions marked for install |
225 // are always also queued. | 190 // are always also queued. |
226 if (job_based_recompilation_) output_queue_mutex_.Lock(); | 191 if (job_based_recompilation_) output_queue_mutex_.Lock(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 if (osr_buffer_[i] != NULL) { | 227 if (osr_buffer_[i] != NULL) { |
263 DisposeOptimizedCompileJob(osr_buffer_[i], restore_function_code); | 228 DisposeOptimizedCompileJob(osr_buffer_[i], restore_function_code); |
264 osr_buffer_[i] = NULL; | 229 osr_buffer_[i] = NULL; |
265 } | 230 } |
266 } | 231 } |
267 } | 232 } |
268 | 233 |
269 | 234 |
270 void OptimizingCompilerThread::Flush() { | 235 void OptimizingCompilerThread::Flush() { |
271 DCHECK(!IsOptimizerThread()); | 236 DCHECK(!IsOptimizerThread()); |
272 bool block = true; | 237 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); |
273 if (job_based_recompilation_) { | 238 if (FLAG_block_concurrent_recompilation) Unblock(); |
274 if (FLAG_block_concurrent_recompilation) Unblock(); | 239 if (!job_based_recompilation_) { |
275 { | 240 input_queue_semaphore_.Signal(); |
276 base::LockGuard<base::Mutex> lock(&input_queue_mutex_); | 241 stop_semaphore_.Wait(); |
277 block = input_queue_length_ > 0; | |
278 if (block) { | |
279 base::Release_Store(&stop_thread_, | |
280 static_cast<base::AtomicWord>(FLUSH)); | |
281 } | |
282 } | |
283 } else { | 242 } else { |
284 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); | 243 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_); |
285 if (FLAG_block_concurrent_recompilation) Unblock(); | 244 while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_); |
| 245 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE)); |
286 } | 246 } |
287 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); | |
288 if (block) stop_semaphore_.Wait(); | |
289 FlushOutputQueue(true); | 247 FlushOutputQueue(true); |
290 if (FLAG_concurrent_osr) FlushOsrBuffer(true); | 248 if (FLAG_concurrent_osr) FlushOsrBuffer(true); |
291 if (tracing_enabled_) { | 249 if (tracing_enabled_) { |
292 PrintF(" ** Flushed concurrent recompilation queues.\n"); | 250 PrintF(" ** Flushed concurrent recompilation queues.\n"); |
293 } | 251 } |
294 } | 252 } |
295 | 253 |
296 | 254 |
297 void OptimizingCompilerThread::Stop() { | 255 void OptimizingCompilerThread::Stop() { |
298 DCHECK(!IsOptimizerThread()); | 256 DCHECK(!IsOptimizerThread()); |
299 bool block = true; | 257 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP)); |
300 if (job_based_recompilation_) { | 258 if (FLAG_block_concurrent_recompilation) Unblock(); |
301 if (FLAG_block_concurrent_recompilation) Unblock(); | 259 if (!job_based_recompilation_) { |
302 { | 260 input_queue_semaphore_.Signal(); |
303 base::LockGuard<base::Mutex> lock(&input_queue_mutex_); | 261 stop_semaphore_.Wait(); |
304 block = input_queue_length_ > 0; | |
305 if (block) { | |
306 base::Release_Store(&stop_thread_, | |
307 static_cast<base::AtomicWord>(FLUSH)); | |
308 } | |
309 } | |
310 } else { | 262 } else { |
311 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP)); | 263 base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_); |
312 if (FLAG_block_concurrent_recompilation) Unblock(); | 264 while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_); |
| 265 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE)); |
313 } | 266 } |
314 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); | |
315 if (block) stop_semaphore_.Wait(); | |
316 | 267 |
317 if (recompilation_delay_ != 0) { | 268 if (recompilation_delay_ != 0) { |
318 // At this point the optimizing compiler thread's event loop has stopped. | 269 // At this point the optimizing compiler thread's event loop has stopped. |
319 // There is no need for a mutex when reading input_queue_length_. | 270 // There is no need for a mutex when reading input_queue_length_. |
320 while (input_queue_length_ > 0) CompileNext(NextInput()); | 271 while (input_queue_length_ > 0) CompileNext(NextInput()); |
321 InstallOptimizedFunctions(); | 272 InstallOptimizedFunctions(); |
322 } else { | 273 } else { |
323 FlushInputQueue(false); | 274 FlushInputQueue(false); |
324 FlushOutputQueue(false); | 275 FlushOutputQueue(false); |
325 } | 276 } |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 | 452 |
502 | 453 |
503 bool OptimizingCompilerThread::IsOptimizerThread() { | 454 bool OptimizingCompilerThread::IsOptimizerThread() { |
504 base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_); | 455 base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_); |
505 return ThreadId::Current().ToInteger() == thread_id_; | 456 return ThreadId::Current().ToInteger() == thread_id_; |
506 } | 457 } |
507 #endif | 458 #endif |
508 | 459 |
509 | 460 |
510 } } // namespace v8::internal | 461 } } // namespace v8::internal |
OLD | NEW |