| 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 |