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 24 matching lines...) Expand all Loading... |
35 } | 35 } |
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( |
| 47 &isolate_->optimizing_compiler_thread()->ref_count_, 1); |
| 48 } |
46 | 49 |
47 virtual ~CompileTask() {} | 50 virtual ~CompileTask() {} |
48 | 51 |
49 private: | 52 private: |
50 // v8::Task overrides. | 53 // v8::Task overrides. |
51 void Run() OVERRIDE { | 54 void Run() OVERRIDE { |
52 DisallowHeapAllocation no_allocation; | 55 DisallowHeapAllocation no_allocation; |
53 DisallowHandleAllocation no_handles; | 56 DisallowHandleAllocation no_handles; |
54 DisallowHandleDereference no_deref; | 57 DisallowHandleDereference no_deref; |
55 | 58 |
56 OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread(); | 59 OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread(); |
| 60 StopFlag flag = CONTINUE; |
57 | 61 |
58 { | 62 { |
59 TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_); | 63 TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_); |
60 | 64 |
61 if (thread->recompilation_delay_ != 0) { | 65 if (thread->recompilation_delay_ != 0) { |
62 base::OS::Sleep(thread->recompilation_delay_); | 66 base::OS::Sleep(thread->recompilation_delay_); |
63 } | 67 } |
64 | 68 |
65 StopFlag flag; | |
66 OptimizedCompileJob* job = thread->NextInput(&flag); | 69 OptimizedCompileJob* job = thread->NextInput(&flag); |
67 | 70 |
68 if (flag == CONTINUE) { | 71 switch (flag) { |
69 thread->CompileNext(job); | 72 case CONTINUE: |
70 } else { | 73 thread->CompileNext(job); |
71 AllowHandleDereference allow_handle_dereference; | 74 break; |
72 if (!job->info()->is_osr()) { | 75 |
73 DisposeOptimizedCompileJob(job, true); | 76 case STOP: |
| 77 case FLUSH: { |
| 78 AllowHandleDereference allow_handle_dereference; |
| 79 if (!job->info()->is_osr()) { |
| 80 DisposeOptimizedCompileJob(job, true); |
| 81 } |
| 82 break; |
74 } | 83 } |
75 } | 84 } |
76 } | 85 } |
| 86 if (flag == STOP) { |
| 87 base::Release_Store(&thread->stop_thread_, |
| 88 static_cast<base::AtomicWord>(CONTINUE)); |
| 89 thread->stop_semaphore_.Signal(); |
| 90 } |
77 | 91 |
78 bool signal = false; | 92 if (base::NoBarrier_AtomicIncrement(&thread->ref_count_, -1) == 0) { |
79 { | 93 thread->stop_semaphore_.Signal(); |
80 base::LockGuard<base::RecursiveMutex> lock(&thread->task_count_mutex_); | |
81 if (--thread->task_count_ == 0) { | |
82 if (static_cast<StopFlag>(base::Acquire_Load(&thread->stop_thread_)) == | |
83 FLUSH) { | |
84 base::Release_Store(&thread->stop_thread_, | |
85 static_cast<base::AtomicWord>(CONTINUE)); | |
86 signal = true; | |
87 } | |
88 } | |
89 } | 94 } |
90 if (signal) thread->stop_semaphore_.Signal(); | |
91 } | 95 } |
92 | 96 |
93 Isolate* isolate_; | 97 Isolate* isolate_; |
94 | 98 |
95 DISALLOW_COPY_AND_ASSIGN(CompileTask); | 99 DISALLOW_COPY_AND_ASSIGN(CompileTask); |
96 }; | 100 }; |
97 | 101 |
98 | 102 |
99 OptimizingCompilerThread::~OptimizingCompilerThread() { | 103 OptimizingCompilerThread::~OptimizingCompilerThread() { |
| 104 if (base::NoBarrier_AtomicIncrement(&ref_count_, -1) > 0) { |
| 105 stop_semaphore_.Wait(); |
| 106 } |
100 DCHECK_EQ(0, input_queue_length_); | 107 DCHECK_EQ(0, input_queue_length_); |
101 DeleteArray(input_queue_); | 108 DeleteArray(input_queue_); |
102 if (FLAG_concurrent_osr) { | 109 if (FLAG_concurrent_osr) { |
103 #ifdef DEBUG | 110 #ifdef DEBUG |
104 for (int i = 0; i < osr_buffer_capacity_; i++) { | 111 for (int i = 0; i < osr_buffer_capacity_; i++) { |
105 CHECK_NULL(osr_buffer_[i]); | 112 CHECK_NULL(osr_buffer_[i]); |
106 } | 113 } |
107 #endif | 114 #endif |
108 DeleteArray(osr_buffer_); | 115 DeleteArray(osr_buffer_); |
109 } | 116 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 UNREACHABLE(); | 182 UNREACHABLE(); |
176 *flag = CONTINUE; | 183 *flag = CONTINUE; |
177 } | 184 } |
178 return NULL; | 185 return NULL; |
179 } | 186 } |
180 OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)]; | 187 OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)]; |
181 DCHECK_NOT_NULL(job); | 188 DCHECK_NOT_NULL(job); |
182 input_queue_shift_ = InputQueueIndex(1); | 189 input_queue_shift_ = InputQueueIndex(1); |
183 input_queue_length_--; | 190 input_queue_length_--; |
184 if (flag) { | 191 if (flag) { |
185 *flag = static_cast<StopFlag>(base::Acquire_Load(&stop_thread_)); | 192 switch (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_))) { |
| 193 case CONTINUE: |
| 194 *flag = CONTINUE; |
| 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 } |
186 } | 210 } |
187 return job; | 211 return job; |
188 } | 212 } |
189 | 213 |
190 | 214 |
191 void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) { | 215 void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) { |
192 DCHECK_NOT_NULL(job); | 216 DCHECK_NOT_NULL(job); |
193 | 217 |
194 // The function may have already been optimized by OSR. Simply continue. | 218 // The function may have already been optimized by OSR. Simply continue. |
195 OptimizedCompileJob::Status status = job->OptimizeGraph(); | 219 OptimizedCompileJob::Status status = job->OptimizeGraph(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 osr_buffer_[i] = NULL; | 264 osr_buffer_[i] = NULL; |
241 } | 265 } |
242 } | 266 } |
243 } | 267 } |
244 | 268 |
245 | 269 |
246 void OptimizingCompilerThread::Flush() { | 270 void OptimizingCompilerThread::Flush() { |
247 DCHECK(!IsOptimizerThread()); | 271 DCHECK(!IsOptimizerThread()); |
248 bool block = true; | 272 bool block = true; |
249 if (job_based_recompilation_) { | 273 if (job_based_recompilation_) { |
250 base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_); | 274 if (FLAG_block_concurrent_recompilation) Unblock(); |
251 block = task_count_ > 0 || blocked_jobs_ > 0; | 275 { |
252 if (block) { | 276 base::LockGuard<base::Mutex> lock(&input_queue_mutex_); |
253 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); | 277 block = input_queue_length_ > 0; |
| 278 if (block) { |
| 279 base::Release_Store(&stop_thread_, |
| 280 static_cast<base::AtomicWord>(FLUSH)); |
| 281 } |
254 } | 282 } |
255 if (FLAG_block_concurrent_recompilation) Unblock(); | |
256 } else { | 283 } else { |
257 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); | 284 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); |
258 if (FLAG_block_concurrent_recompilation) Unblock(); | 285 if (FLAG_block_concurrent_recompilation) Unblock(); |
259 } | 286 } |
260 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); | 287 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); |
261 if (block) stop_semaphore_.Wait(); | 288 if (block) stop_semaphore_.Wait(); |
262 FlushOutputQueue(true); | 289 FlushOutputQueue(true); |
263 if (FLAG_concurrent_osr) FlushOsrBuffer(true); | 290 if (FLAG_concurrent_osr) FlushOsrBuffer(true); |
264 if (tracing_enabled_) { | 291 if (tracing_enabled_) { |
265 PrintF(" ** Flushed concurrent recompilation queues.\n"); | 292 PrintF(" ** Flushed concurrent recompilation queues.\n"); |
266 } | 293 } |
267 } | 294 } |
268 | 295 |
269 | 296 |
270 void OptimizingCompilerThread::Stop() { | 297 void OptimizingCompilerThread::Stop() { |
271 DCHECK(!IsOptimizerThread()); | 298 DCHECK(!IsOptimizerThread()); |
272 bool block = true; | 299 bool block = true; |
273 if (job_based_recompilation_) { | 300 if (job_based_recompilation_) { |
274 base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_); | 301 if (FLAG_block_concurrent_recompilation) Unblock(); |
275 block = task_count_ > 0 || blocked_jobs_ > 0; | 302 { |
276 if (block) { | 303 base::LockGuard<base::Mutex> lock(&input_queue_mutex_); |
277 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH)); | 304 block = input_queue_length_ > 0; |
| 305 if (block) { |
| 306 base::Release_Store(&stop_thread_, |
| 307 static_cast<base::AtomicWord>(FLUSH)); |
| 308 } |
278 } | 309 } |
279 if (FLAG_block_concurrent_recompilation) Unblock(); | |
280 } else { | 310 } else { |
281 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP)); | 311 base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP)); |
282 if (FLAG_block_concurrent_recompilation) Unblock(); | 312 if (FLAG_block_concurrent_recompilation) Unblock(); |
283 } | 313 } |
284 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); | 314 if (!job_based_recompilation_) input_queue_semaphore_.Signal(); |
285 if (block) stop_semaphore_.Wait(); | 315 if (block) stop_semaphore_.Wait(); |
286 | 316 |
287 if (recompilation_delay_ != 0) { | 317 if (recompilation_delay_ != 0) { |
288 // At this point the optimizing compiler thread's event loop has stopped. | 318 // At this point the optimizing compiler thread's event loop has stopped. |
289 // There is no need for a mutex when reading input_queue_length_. | 319 // There is no need for a mutex when reading input_queue_length_. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 } else { | 395 } else { |
366 // Add job to the back of the input queue. | 396 // Add job to the back of the input queue. |
367 base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_); | 397 base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_); |
368 DCHECK_LT(input_queue_length_, input_queue_capacity_); | 398 DCHECK_LT(input_queue_length_, input_queue_capacity_); |
369 input_queue_[InputQueueIndex(input_queue_length_)] = job; | 399 input_queue_[InputQueueIndex(input_queue_length_)] = job; |
370 input_queue_length_++; | 400 input_queue_length_++; |
371 } | 401 } |
372 if (FLAG_block_concurrent_recompilation) { | 402 if (FLAG_block_concurrent_recompilation) { |
373 blocked_jobs_++; | 403 blocked_jobs_++; |
374 } else if (job_based_recompilation_) { | 404 } else if (job_based_recompilation_) { |
375 base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_); | |
376 ++task_count_; | |
377 V8::GetCurrentPlatform()->CallOnBackgroundThread( | 405 V8::GetCurrentPlatform()->CallOnBackgroundThread( |
378 new CompileTask(isolate_), v8::Platform::kShortRunningTask); | 406 new CompileTask(isolate_), v8::Platform::kShortRunningTask); |
379 } else { | 407 } else { |
380 input_queue_semaphore_.Signal(); | 408 input_queue_semaphore_.Signal(); |
381 } | 409 } |
382 } | 410 } |
383 | 411 |
384 | 412 |
385 void OptimizingCompilerThread::Unblock() { | 413 void OptimizingCompilerThread::Unblock() { |
386 DCHECK(!IsOptimizerThread()); | 414 DCHECK(!IsOptimizerThread()); |
387 { | |
388 base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_); | |
389 task_count_ += blocked_jobs_; | |
390 } | |
391 while (blocked_jobs_ > 0) { | 415 while (blocked_jobs_ > 0) { |
392 if (job_based_recompilation_) { | 416 if (job_based_recompilation_) { |
393 V8::GetCurrentPlatform()->CallOnBackgroundThread( | 417 V8::GetCurrentPlatform()->CallOnBackgroundThread( |
394 new CompileTask(isolate_), v8::Platform::kShortRunningTask); | 418 new CompileTask(isolate_), v8::Platform::kShortRunningTask); |
395 } else { | 419 } else { |
396 input_queue_semaphore_.Signal(); | 420 input_queue_semaphore_.Signal(); |
397 } | 421 } |
398 blocked_jobs_--; | 422 blocked_jobs_--; |
399 } | 423 } |
400 } | 424 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 | 501 |
478 | 502 |
479 bool OptimizingCompilerThread::IsOptimizerThread() { | 503 bool OptimizingCompilerThread::IsOptimizerThread() { |
480 base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_); | 504 base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_); |
481 return ThreadId::Current().ToInteger() == thread_id_; | 505 return ThreadId::Current().ToInteger() == thread_id_; |
482 } | 506 } |
483 #endif | 507 #endif |
484 | 508 |
485 | 509 |
486 } } // namespace v8::internal | 510 } } // namespace v8::internal |
OLD | NEW |