Chromium Code Reviews| 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" | |
| 11 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" | 12 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" |
| 12 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" | 13 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" |
| 13 #include "src/flags.h" | 14 #include "src/flags.h" |
| 14 #include "src/objects-inl.h" | 15 #include "src/objects-inl.h" |
| 15 | 16 |
| 16 namespace v8 { | 17 namespace v8 { |
| 17 namespace internal { | 18 namespace internal { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 PrintF("CompilerDispatcher: dispatcher is disabled\n"); | 220 PrintF("CompilerDispatcher: dispatcher is disabled\n"); |
| 220 } | 221 } |
| 221 } | 222 } |
| 222 | 223 |
| 223 CompilerDispatcher::~CompilerDispatcher() { | 224 CompilerDispatcher::~CompilerDispatcher() { |
| 224 // To avoid crashing in unit tests due to unfished jobs. | 225 // To avoid crashing in unit tests due to unfished jobs. |
| 225 AbortAll(BlockingBehavior::kBlock); | 226 AbortAll(BlockingBehavior::kBlock); |
| 226 task_manager_->CancelAndWait(); | 227 task_manager_->CancelAndWait(); |
| 227 } | 228 } |
| 228 | 229 |
| 229 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { | 230 bool CompilerDispatcher::CanEnqueueJobs() { |
| 230 if (!IsEnabled()) return false; | 231 if (!IsEnabled()) return false; |
| 231 | 232 |
| 232 if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) { | 233 if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) { |
| 233 return false; | 234 return false; |
| 234 } | 235 } |
| 235 | 236 |
| 236 { | 237 { |
| 237 base::LockGuard<base::Mutex> lock(&mutex_); | 238 base::LockGuard<base::Mutex> lock(&mutex_); |
| 238 if (abort_) return false; | 239 return !abort_; |
| 239 } | 240 } |
| 241 } | |
| 242 | |
| 243 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { | |
| 244 if (!CanEnqueueJobs()) return false; | |
| 240 | 245 |
| 241 // We only handle functions (no eval / top-level code / wasm) that are | 246 // We only handle functions (no eval / top-level code / wasm) that are |
| 242 // attached to a script. | 247 // attached to a script. |
| 243 if (!function->script()->IsScript() || !function->is_function() || | 248 if (!function->script()->IsScript() || !function->is_function() || |
| 244 function->asm_function() || function->native()) { | 249 function->asm_function() || function->native()) { |
| 245 return false; | 250 return false; |
|
marja
2017/01/10 09:58:54
Doesn't this break the "if enqueue fails, it must
rmcilroy
2017/01/12 12:31:55
Yeah, this was part of the WIP stuff I hadn't quit
| |
| 246 } | 251 } |
| 247 | 252 |
| 248 if (IsEnqueued(function)) return true; | 253 if (IsEnqueued(function)) return true; |
| 249 | 254 |
| 250 if (trace_compiler_dispatcher_) { | 255 if (trace_compiler_dispatcher_) { |
| 251 PrintF("CompilerDispatcher: enqueuing "); | 256 PrintF("CompilerDispatcher: enqueuing "); |
| 252 function->ShortPrint(); | 257 function->ShortPrint(); |
| 253 PrintF("\n"); | 258 PrintF(" for parse and compile\n"); |
| 254 } | 259 } |
| 255 | 260 |
| 256 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( | 261 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( |
| 257 isolate_, tracer_.get(), function, max_stack_size_)); | 262 isolate_, tracer_.get(), function, max_stack_size_)); |
| 258 std::pair<int, int> key(Script::cast(function->script())->id(), | 263 std::pair<int, int> key(Script::cast(function->script())->id(), |
| 259 function->function_literal_id()); | 264 function->function_literal_id()); |
| 260 jobs_.insert(std::make_pair(key, std::move(job))); | 265 jobs_.insert(std::make_pair(key, std::move(job))); |
| 261 ScheduleIdleTaskIfNeeded(); | 266 ScheduleIdleTaskIfNeeded(); |
| 262 return true; | 267 return true; |
| 263 } | 268 } |
| 264 | 269 |
| 270 bool CompilerDispatcher::Enqueue(Zone* zone, ParseInfo* parse_info, | |
| 271 CompilationInfo* compile_info, | |
| 272 CompilationJob* compilation_job) { | |
| 273 if (!CanEnqueueJobs()) return false; | |
| 274 | |
| 275 DCHECK(compile_info->has_shared_info()); | |
| 276 Handle<SharedFunctionInfo> function = compile_info->shared_info(); | |
| 277 | |
| 278 if (IsEnqueued(function)) return true; | |
| 279 | |
| 280 if (trace_compiler_dispatcher_) { | |
| 281 PrintF("CompilerDispatcher: enqueuing"); | |
| 282 function->ShortPrint(); | |
| 283 PrintF(" for compile\n"); | |
| 284 } | |
| 285 | |
| 286 CompilerDispatcherJob* job(new CompilerDispatcherJob( | |
| 287 isolate_, tracer_.get(), zone, parse_info, compile_info, compilation_job, | |
| 288 max_stack_size_)); | |
| 289 std::pair<int, int> key(Script::cast(function->script())->id(), | |
| 290 function->function_literal_id()); | |
| 291 jobs_.insert(std::make_pair(key, job)); | |
| 292 ConsiderJobForBackgroundProcessing(job); | |
| 293 ScheduleIdleTaskIfNeeded(); | |
| 294 return true; | |
| 295 } | |
| 296 | |
| 265 bool CompilerDispatcher::IsEnabled() const { | 297 bool CompilerDispatcher::IsEnabled() const { |
| 266 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 298 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); |
| 267 return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate); | 299 return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate); |
| 268 } | 300 } |
| 269 | 301 |
| 270 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { | 302 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { |
| 271 return GetJobFor(function) != jobs_.end(); | 303 return GetJobFor(function) != jobs_.end(); |
| 272 } | 304 } |
| 273 | 305 |
| 274 void CompilerDispatcher::WaitForJobIfRunningOnBackground( | 306 void CompilerDispatcher::WaitForJobIfRunningOnBackground( |
| 275 CompilerDispatcherJob* job) { | 307 CompilerDispatcherJob* job) { |
| 276 base::LockGuard<base::Mutex> lock(&mutex_); | 308 base::LockGuard<base::Mutex> lock(&mutex_); |
| 277 if (running_background_jobs_.find(job) == running_background_jobs_.end()) { | 309 if (running_background_jobs_.find(job) == running_background_jobs_.end()) { |
| 278 pending_background_jobs_.erase(job); | 310 pending_background_jobs_.erase(job); |
| 279 return; | 311 return; |
| 280 } | 312 } |
| 281 DCHECK_NULL(main_thread_blocking_on_job_); | 313 DCHECK_NULL(main_thread_blocking_on_job_); |
| 282 main_thread_blocking_on_job_ = job; | 314 main_thread_blocking_on_job_ = job; |
| 283 while (main_thread_blocking_on_job_ != nullptr) { | 315 while (main_thread_blocking_on_job_ != nullptr) { |
| 284 main_thread_blocking_signal_.Wait(&mutex_); | 316 main_thread_blocking_signal_.Wait(&mutex_); |
| 285 } | 317 } |
| 286 DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end()); | 318 DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end()); |
| 287 DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end()); | 319 DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end()); |
| 288 } | 320 } |
| 289 | 321 |
| 322 bool CompilerDispatcher::FinishNow(CompilerDispatcherJob* job) { | |
| 323 WaitForJobIfRunningOnBackground(job); | |
| 324 while (!IsFinished(job)) { | |
| 325 DoNextStepOnMainThread(isolate_, job, ExceptionHandling::kThrow); | |
| 326 } | |
| 327 bool result = job->status() != CompileJobStatus::kFailed; | |
| 328 job->ResetOnMainThread(); | |
| 329 return result; | |
| 330 } | |
| 331 | |
| 290 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { | 332 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { |
| 291 JobMap::const_iterator job = GetJobFor(function); | 333 JobMap::const_iterator job = GetJobFor(function); |
| 292 CHECK(job != jobs_.end()); | 334 CHECK(job != jobs_.end()); |
| 293 | 335 |
| 294 if (trace_compiler_dispatcher_) { | 336 if (trace_compiler_dispatcher_) { |
| 295 PrintF("CompilerDispatcher: finishing "); | 337 PrintF("CompilerDispatcher: finishing "); |
| 296 function->ShortPrint(); | 338 function->ShortPrint(); |
| 297 PrintF(" now\n"); | 339 PrintF(" now\n"); |
| 298 } | 340 } |
| 299 | 341 |
| 300 WaitForJobIfRunningOnBackground(job->second.get()); | 342 bool result = FinishNow(job->second.get()); |
| 301 while (!IsFinished(job->second.get())) { | |
| 302 DoNextStepOnMainThread(isolate_, job->second.get(), | |
| 303 ExceptionHandling::kThrow); | |
| 304 } | |
| 305 bool result = job->second->status() != CompileJobStatus::kFailed; | |
| 306 | 343 |
| 307 if (trace_compiler_dispatcher_) { | 344 if (trace_compiler_dispatcher_) { |
| 308 PrintF("CompilerDispatcher: finished working on "); | 345 PrintF("CompilerDispatcher: finished working on "); |
| 309 function->ShortPrint(); | 346 function->ShortPrint(); |
| 310 PrintF(": %s\n", result ? "success" : "failure"); | 347 PrintF(": %s\n", result ? "success" : "failure"); |
| 311 tracer_->DumpStatistics(); | 348 tracer_->DumpStatistics(); |
| 312 } | 349 } |
| 313 | 350 |
| 314 job->second->ResetOnMainThread(); | |
| 315 jobs_.erase(job); | 351 jobs_.erase(job); |
| 316 if (jobs_.empty()) { | 352 if (jobs_.empty()) { |
| 317 base::LockGuard<base::Mutex> lock(&mutex_); | 353 base::LockGuard<base::Mutex> lock(&mutex_); |
| 318 abort_ = false; | 354 abort_ = false; |
| 319 } | 355 } |
| 320 return result; | 356 return result; |
| 321 } | 357 } |
| 322 | 358 |
| 359 void CompilerDispatcher::FinishAllNow() { | |
| 360 if (trace_compiler_dispatcher_) { | |
| 361 PrintF("CompilerDispatcher: finishing all jobs now\n"); | |
| 362 } | |
| 363 | |
| 364 for (auto& it : jobs_) { | |
| 365 FinishNow(it.second.get()); | |
| 366 } | |
| 367 | |
| 368 if (trace_compiler_dispatcher_) { | |
| 369 PrintF("CompilerDispatcher: finished all jobs\n"); | |
| 370 } | |
| 371 | |
| 372 jobs_.clear(); | |
| 373 { | |
| 374 base::LockGuard<base::Mutex> lock(&mutex_); | |
| 375 DCHECK(pending_background_jobs_.empty()); | |
| 376 DCHECK(running_background_jobs_.empty()); | |
| 377 abort_ = false; | |
| 378 } | |
| 379 } | |
| 380 | |
| 323 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { | 381 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { |
| 324 bool background_tasks_running = | 382 bool background_tasks_running = |
| 325 task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning; | 383 task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning; |
| 326 if (!background_tasks_running || blocking == BlockingBehavior::kBlock) { | 384 if (!background_tasks_running || blocking == BlockingBehavior::kBlock) { |
| 327 for (auto& it : jobs_) { | 385 for (auto& it : jobs_) { |
| 328 WaitForJobIfRunningOnBackground(it.second.get()); | 386 WaitForJobIfRunningOnBackground(it.second.get()); |
| 329 if (trace_compiler_dispatcher_) { | 387 if (trace_compiler_dispatcher_) { |
| 330 PrintF("CompilerDispatcher: aborted "); | 388 PrintF("CompilerDispatcher: aborted "); |
| 331 it.second->ShortPrint(); | 389 it.second->ShortPrint(); |
| 332 PrintF("\n"); | 390 PrintF("\n"); |
| 333 } | 391 } |
| 334 it.second->ResetOnMainThread(); | 392 it.second->ResetOnMainThread(); |
| 335 } | 393 } |
| 336 jobs_.clear(); | 394 jobs_.clear(); |
| 337 { | 395 { |
| 338 base::LockGuard<base::Mutex> lock(&mutex_); | 396 base::LockGuard<base::Mutex> lock(&mutex_); |
| 339 DCHECK(pending_background_jobs_.empty()); | 397 DCHECK(pending_background_jobs_.empty()); |
| 340 DCHECK(running_background_jobs_.empty()); | 398 DCHECK(running_background_jobs_.empty()); |
| 341 abort_ = false; | 399 abort_ = false; |
| 342 } | 400 } |
| 343 return; | |
|
marja
2017/01/10 09:58:54
Why?
rmcilroy
2017/01/12 12:31:55
Opps not sure how that happened - that explains th
| |
| 344 } | 401 } |
| 345 | 402 |
| 346 { | 403 { |
| 347 base::LockGuard<base::Mutex> lock(&mutex_); | 404 base::LockGuard<base::Mutex> lock(&mutex_); |
| 348 abort_ = true; | 405 abort_ = true; |
| 349 pending_background_jobs_.clear(); | 406 pending_background_jobs_.clear(); |
| 350 } | 407 } |
| 351 AbortInactiveJobs(); | 408 AbortInactiveJobs(); |
| 352 | 409 |
| 353 // All running background jobs might already have scheduled idle tasks instead | 410 // All running background jobs might already have scheduled idle tasks instead |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 lock.reset(); | 664 lock.reset(); |
| 608 DoNextStepOnMainThread(isolate_, job->second.get(), | 665 DoNextStepOnMainThread(isolate_, job->second.get(), |
| 609 ExceptionHandling::kSwallow); | 666 ExceptionHandling::kSwallow); |
| 610 } | 667 } |
| 611 } | 668 } |
| 612 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); | 669 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); |
| 613 } | 670 } |
| 614 | 671 |
| 615 } // namespace internal | 672 } // namespace internal |
| 616 } // namespace v8 | 673 } // namespace v8 |
| OLD | NEW |