| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 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/compiler-dispatcher/compiler-dispatcher.h" | 5 #include "src/compiler-dispatcher/compiler-dispatcher.h" |
| 6 | 6 |
| 7 #include "include/v8-platform.h" | 7 #include "include/v8-platform.h" |
| 8 #include "include/v8.h" | 8 #include "include/v8.h" |
| 9 #include "src/base/platform/time.h" | 9 #include "src/base/platform/time.h" |
| 10 #include "src/cancelable-task.h" | 10 #include "src/cancelable-task.h" |
| 11 #include "src/compilation-info.h" | |
| 12 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" | 11 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" |
| 13 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" | 12 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" |
| 14 #include "src/flags.h" | 13 #include "src/flags.h" |
| 15 #include "src/objects-inl.h" | 14 #include "src/objects-inl.h" |
| 16 | 15 |
| 17 namespace v8 { | 16 namespace v8 { |
| 18 namespace internal { | 17 namespace internal { |
| 19 | 18 |
| 20 namespace { | 19 namespace { |
| 21 | 20 |
| 22 enum class ExceptionHandling { kSwallow, kThrow }; | 21 enum class ExceptionHandling { kSwallow, kThrow }; |
| 23 | 22 |
| 24 bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job, | 23 bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job, |
| 25 ExceptionHandling exception_handling) { | 24 ExceptionHandling exception_handling) { |
| 26 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); | 25 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); |
| 27 switch (job->status()) { | 26 switch (job->status()) { |
| 28 case CompileJobStatus::kInitial: | 27 case CompileJobStatus::kInitial: |
| 29 job->PrepareToParseOnMainThread(); | 28 job->PrepareToParseOnMainThread(); |
| 30 break; | 29 break; |
| 31 | 30 |
| 32 case CompileJobStatus::kReadyToParse: | 31 case CompileJobStatus::kReadyToParse: |
| 33 job->Parse(); | 32 job->Parse(); |
| 34 break; | 33 break; |
| 35 | 34 |
| 36 case CompileJobStatus::kParsed: | 35 case CompileJobStatus::kParsed: |
| 37 job->FinalizeParsingOnMainThread(); | 36 job->FinalizeParsingOnMainThread(); |
| 38 break; | 37 break; |
| 39 | 38 |
| 40 case CompileJobStatus::kReadyToAnalyze: | 39 case CompileJobStatus::kReadyToAnalyse: |
| 41 job->AnalyzeOnMainThread(); | |
| 42 break; | |
| 43 | |
| 44 case CompileJobStatus::kAnalyzed: | |
| 45 job->PrepareToCompileOnMainThread(); | 40 job->PrepareToCompileOnMainThread(); |
| 46 break; | 41 break; |
| 47 | 42 |
| 48 case CompileJobStatus::kReadyToCompile: | 43 case CompileJobStatus::kReadyToCompile: |
| 49 job->Compile(); | 44 job->Compile(); |
| 50 break; | 45 break; |
| 51 | 46 |
| 52 case CompileJobStatus::kCompiled: | 47 case CompileJobStatus::kCompiled: |
| 53 job->FinalizeCompilingOnMainThread(); | 48 job->FinalizeCompilingOnMainThread(); |
| 54 break; | 49 break; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 PrintF("CompilerDispatcher: dispatcher is disabled\n"); | 217 PrintF("CompilerDispatcher: dispatcher is disabled\n"); |
| 223 } | 218 } |
| 224 } | 219 } |
| 225 | 220 |
| 226 CompilerDispatcher::~CompilerDispatcher() { | 221 CompilerDispatcher::~CompilerDispatcher() { |
| 227 // To avoid crashing in unit tests due to unfished jobs. | 222 // To avoid crashing in unit tests due to unfished jobs. |
| 228 AbortAll(BlockingBehavior::kBlock); | 223 AbortAll(BlockingBehavior::kBlock); |
| 229 task_manager_->CancelAndWait(); | 224 task_manager_->CancelAndWait(); |
| 230 } | 225 } |
| 231 | 226 |
| 232 bool CompilerDispatcher::CanEnqueue(Handle<SharedFunctionInfo> function) { | 227 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { |
| 233 if (!IsEnabled()) return false; | 228 if (!IsEnabled()) return false; |
| 234 | 229 |
| 235 DCHECK(FLAG_ignition); | 230 DCHECK(FLAG_ignition); |
| 236 | 231 |
| 237 if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) { | 232 if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) { |
| 238 return false; | 233 return false; |
| 239 } | 234 } |
| 240 | 235 |
| 241 { | 236 { |
| 242 base::LockGuard<base::Mutex> lock(&mutex_); | 237 base::LockGuard<base::Mutex> lock(&mutex_); |
| 243 if (abort_) return false; | 238 if (abort_) return false; |
| 244 } | 239 } |
| 245 | 240 |
| 246 // We only handle functions (no eval / top-level code / wasm) that are | 241 // We only handle functions (no eval / top-level code / wasm) that are |
| 247 // attached to a script. | 242 // attached to a script. |
| 248 if (!function->script()->IsScript() || function->is_toplevel() || | 243 if (!function->script()->IsScript() || function->is_toplevel() || |
| 249 function->asm_function() || function->native()) { | 244 function->asm_function() || function->native()) { |
| 250 return false; | 245 return false; |
| 251 } | 246 } |
| 252 | 247 |
| 253 return true; | |
| 254 } | |
| 255 | |
| 256 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { | |
| 257 if (!CanEnqueue(function)) return false; | |
| 258 if (IsEnqueued(function)) return true; | 248 if (IsEnqueued(function)) return true; |
| 259 | 249 |
| 260 if (trace_compiler_dispatcher_) { | 250 if (trace_compiler_dispatcher_) { |
| 261 PrintF("CompilerDispatcher: enqueuing "); | 251 PrintF("CompilerDispatcher: enqueuing "); |
| 262 function->ShortPrint(); | 252 function->ShortPrint(); |
| 263 PrintF(" for parse and compile\n"); | 253 PrintF("\n"); |
| 264 } | 254 } |
| 265 | 255 |
| 266 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( | 256 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( |
| 267 isolate_, tracer_.get(), function, max_stack_size_)); | 257 isolate_, tracer_.get(), function, max_stack_size_)); |
| 268 std::pair<int, int> key(Script::cast(function->script())->id(), | 258 std::pair<int, int> key(Script::cast(function->script())->id(), |
| 269 function->function_literal_id()); | 259 function->function_literal_id()); |
| 270 jobs_.insert(std::make_pair(key, std::move(job))); | 260 jobs_.insert(std::make_pair(key, std::move(job))); |
| 271 ScheduleIdleTaskIfNeeded(); | 261 ScheduleIdleTaskIfNeeded(); |
| 272 return true; | 262 return true; |
| 273 } | 263 } |
| 274 | 264 |
| 275 bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) { | 265 bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) { |
| 276 if (!Enqueue(function)) return false; | 266 if (!Enqueue(function)) return false; |
| 277 | 267 |
| 278 if (trace_compiler_dispatcher_) { | 268 if (trace_compiler_dispatcher_) { |
| 279 PrintF("CompilerDispatcher: stepping "); | 269 PrintF("CompilerDispatcher: stepping "); |
| 280 function->ShortPrint(); | 270 function->ShortPrint(); |
| 281 PrintF("\n"); | 271 PrintF("\n"); |
| 282 } | 272 } |
| 283 JobMap::const_iterator job = GetJobFor(function); | 273 JobMap::const_iterator job = GetJobFor(function); |
| 284 DoNextStepOnMainThread(isolate_, job->second.get(), | 274 DoNextStepOnMainThread(isolate_, job->second.get(), |
| 285 ExceptionHandling::kSwallow); | 275 ExceptionHandling::kSwallow); |
| 286 ConsiderJobForBackgroundProcessing(job->second.get()); | 276 ConsiderJobForBackgroundProcessing(job->second.get()); |
| 287 return true; | 277 return true; |
| 288 } | 278 } |
| 289 | 279 |
| 290 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function, | 280 bool CompilerDispatcher::IsEnabled() const { |
| 291 FunctionLiteral* literal) { | 281 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); |
| 292 if (!CanEnqueue(function)) return false; | 282 return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate); |
| 293 if (IsEnqueued(function)) return true; | |
| 294 | |
| 295 if (trace_compiler_dispatcher_) { | |
| 296 PrintF("CompilerDispatcher: enqueuing "); | |
| 297 function->ShortPrint(); | |
| 298 PrintF(" for compile\n"); | |
| 299 } | |
| 300 | |
| 301 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( | |
| 302 isolate_, tracer_.get(), function, literal, max_stack_size_)); | |
| 303 std::pair<int, int> key(Script::cast(function->script())->id(), | |
| 304 function->function_literal_id()); | |
| 305 jobs_.insert(std::make_pair(key, std::move(job))); | |
| 306 ScheduleIdleTaskIfNeeded(); | |
| 307 return true; | |
| 308 } | 283 } |
| 309 | 284 |
| 310 bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function, | |
| 311 FunctionLiteral* literal) { | |
| 312 if (!Enqueue(function, literal)) return false; | |
| 313 | |
| 314 if (trace_compiler_dispatcher_) { | |
| 315 PrintF("CompilerDispatcher: stepping "); | |
| 316 function->ShortPrint(); | |
| 317 PrintF("\n"); | |
| 318 } | |
| 319 JobMap::const_iterator job = GetJobFor(function); | |
| 320 DoNextStepOnMainThread(isolate_, job->second.get(), | |
| 321 ExceptionHandling::kSwallow); | |
| 322 ConsiderJobForBackgroundProcessing(job->second.get()); | |
| 323 return true; | |
| 324 } | |
| 325 | |
| 326 bool CompilerDispatcher::IsEnabled() const { return FLAG_compiler_dispatcher; } | |
| 327 | |
| 328 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { | 285 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { |
| 329 return GetJobFor(function) != jobs_.end(); | 286 return GetJobFor(function) != jobs_.end(); |
| 330 } | 287 } |
| 331 | 288 |
| 332 void CompilerDispatcher::WaitForJobIfRunningOnBackground( | 289 void CompilerDispatcher::WaitForJobIfRunningOnBackground( |
| 333 CompilerDispatcherJob* job) { | 290 CompilerDispatcherJob* job) { |
| 334 base::LockGuard<base::Mutex> lock(&mutex_); | 291 base::LockGuard<base::Mutex> lock(&mutex_); |
| 335 if (running_background_jobs_.find(job) == running_background_jobs_.end()) { | 292 if (running_background_jobs_.find(job) == running_background_jobs_.end()) { |
| 336 pending_background_jobs_.erase(job); | 293 pending_background_jobs_.erase(job); |
| 337 return; | 294 return; |
| 338 } | 295 } |
| 339 DCHECK_NULL(main_thread_blocking_on_job_); | 296 DCHECK_NULL(main_thread_blocking_on_job_); |
| 340 main_thread_blocking_on_job_ = job; | 297 main_thread_blocking_on_job_ = job; |
| 341 while (main_thread_blocking_on_job_ != nullptr) { | 298 while (main_thread_blocking_on_job_ != nullptr) { |
| 342 main_thread_blocking_signal_.Wait(&mutex_); | 299 main_thread_blocking_signal_.Wait(&mutex_); |
| 343 } | 300 } |
| 344 DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end()); | 301 DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end()); |
| 345 DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end()); | 302 DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end()); |
| 346 } | 303 } |
| 347 | 304 |
| 348 bool CompilerDispatcher::FinishNow(CompilerDispatcherJob* job) { | |
| 349 WaitForJobIfRunningOnBackground(job); | |
| 350 while (!IsFinished(job)) { | |
| 351 DoNextStepOnMainThread(isolate_, job, ExceptionHandling::kThrow); | |
| 352 } | |
| 353 bool result = job->status() != CompileJobStatus::kFailed; | |
| 354 job->ResetOnMainThread(); | |
| 355 return result; | |
| 356 } | |
| 357 | |
| 358 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { | 305 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { |
| 359 JobMap::const_iterator job = GetJobFor(function); | 306 JobMap::const_iterator job = GetJobFor(function); |
| 360 CHECK(job != jobs_.end()); | 307 CHECK(job != jobs_.end()); |
| 361 | 308 |
| 362 if (trace_compiler_dispatcher_) { | 309 if (trace_compiler_dispatcher_) { |
| 363 PrintF("CompilerDispatcher: finishing "); | 310 PrintF("CompilerDispatcher: finishing "); |
| 364 function->ShortPrint(); | 311 function->ShortPrint(); |
| 365 PrintF(" now\n"); | 312 PrintF(" now\n"); |
| 366 } | 313 } |
| 367 | 314 |
| 368 bool result = FinishNow(job->second.get()); | 315 WaitForJobIfRunningOnBackground(job->second.get()); |
| 316 while (!IsFinished(job->second.get())) { |
| 317 DoNextStepOnMainThread(isolate_, job->second.get(), |
| 318 ExceptionHandling::kThrow); |
| 319 } |
| 320 bool result = job->second->status() != CompileJobStatus::kFailed; |
| 369 | 321 |
| 370 if (trace_compiler_dispatcher_) { | 322 if (trace_compiler_dispatcher_) { |
| 371 PrintF("CompilerDispatcher: finished working on "); | 323 PrintF("CompilerDispatcher: finished working on "); |
| 372 function->ShortPrint(); | 324 function->ShortPrint(); |
| 373 PrintF(": %s\n", result ? "success" : "failure"); | 325 PrintF(": %s\n", result ? "success" : "failure"); |
| 374 tracer_->DumpStatistics(); | 326 tracer_->DumpStatistics(); |
| 375 } | 327 } |
| 376 | 328 |
| 329 job->second->ResetOnMainThread(); |
| 377 jobs_.erase(job); | 330 jobs_.erase(job); |
| 378 if (jobs_.empty()) { | 331 if (jobs_.empty()) { |
| 379 base::LockGuard<base::Mutex> lock(&mutex_); | 332 base::LockGuard<base::Mutex> lock(&mutex_); |
| 380 abort_ = false; | 333 abort_ = false; |
| 381 } | 334 } |
| 382 return result; | 335 return result; |
| 383 } | |
| 384 | |
| 385 bool CompilerDispatcher::FinishAllNow() { | |
| 386 if (trace_compiler_dispatcher_) { | |
| 387 PrintF("CompilerDispatcher: finishing all jobs now\n"); | |
| 388 } | |
| 389 | |
| 390 bool result = true; | |
| 391 for (auto& it : jobs_) { | |
| 392 result &= FinishNow(it.second.get()); | |
| 393 } | |
| 394 | |
| 395 if (trace_compiler_dispatcher_) { | |
| 396 PrintF("CompilerDispatcher: finished all jobs\n"); | |
| 397 } | |
| 398 | |
| 399 jobs_.clear(); | |
| 400 { | |
| 401 base::LockGuard<base::Mutex> lock(&mutex_); | |
| 402 DCHECK(pending_background_jobs_.empty()); | |
| 403 DCHECK(running_background_jobs_.empty()); | |
| 404 abort_ = false; | |
| 405 } | |
| 406 return result; | |
| 407 } | 336 } |
| 408 | 337 |
| 409 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { | 338 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { |
| 410 bool background_tasks_running = | 339 bool background_tasks_running = |
| 411 task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning; | 340 task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning; |
| 412 if (!background_tasks_running || blocking == BlockingBehavior::kBlock) { | 341 if (!background_tasks_running || blocking == BlockingBehavior::kBlock) { |
| 413 for (auto& it : jobs_) { | 342 for (auto& it : jobs_) { |
| 414 WaitForJobIfRunningOnBackground(it.second.get()); | 343 WaitForJobIfRunningOnBackground(it.second.get()); |
| 415 if (trace_compiler_dispatcher_) { | 344 if (trace_compiler_dispatcher_) { |
| 416 PrintF("CompilerDispatcher: aborted "); | 345 PrintF("CompilerDispatcher: aborted "); |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 lock.reset(); | 622 lock.reset(); |
| 694 DoNextStepOnMainThread(isolate_, job->second.get(), | 623 DoNextStepOnMainThread(isolate_, job->second.get(), |
| 695 ExceptionHandling::kSwallow); | 624 ExceptionHandling::kSwallow); |
| 696 } | 625 } |
| 697 } | 626 } |
| 698 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); | 627 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); |
| 699 } | 628 } |
| 700 | 629 |
| 701 } // namespace internal | 630 } // namespace internal |
| 702 } // namespace v8 | 631 } // namespace v8 |
| OLD | NEW |