LCOV - code coverage report
Current view: top level - src/compiler-dispatcher - optimizing-compile-dispatcher.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 95 103 92.2 %
Date: 2017-04-26 Functions: 13 14 92.9 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
       6             : 
       7             : #include "src/base/atomicops.h"
       8             : #include "src/compilation-info.h"
       9             : #include "src/compiler.h"
      10             : #include "src/full-codegen/full-codegen.h"
      11             : #include "src/isolate.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/tracing/trace-event.h"
      14             : #include "src/v8.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : namespace {
      20             : 
      21       11391 : void DisposeCompilationJob(CompilationJob* job, bool restore_function_code) {
      22        8094 :   if (restore_function_code) {
      23             :     Handle<JSFunction> function = job->info()->closure();
      24        3297 :     function->ReplaceCode(function->shared()->code());
      25             :     // TODO(mvstanton): We can't call ensureliterals here due to allocation,
      26             :     // but we probably shouldn't call ReplaceCode either, as this
      27             :     // sometimes runs on the worker thread!
      28             :     // JSFunction::EnsureLiterals(function);
      29             :   }
      30        8094 :   delete job;
      31        8094 : }
      32             : 
      33             : }  // namespace
      34             : 
      35             : class OptimizingCompileDispatcher::CompileTask : public v8::Task {
      36             :  public:
      37       51653 :   explicit CompileTask(Isolate* isolate,
      38             :                        OptimizingCompileDispatcher* dispatcher)
      39       51653 :       : isolate_(isolate), dispatcher_(dispatcher) {
      40       51653 :     base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
      41       51653 :     ++dispatcher_->ref_count_;
      42       51653 :   }
      43             : 
      44      103306 :   virtual ~CompileTask() {}
      45             : 
      46             :  private:
      47             :   // v8::Task overrides.
      48       51653 :   void Run() override {
      49             :     DisallowHeapAllocation no_allocation;
      50             :     DisallowHandleAllocation no_handles;
      51             :     DisallowHandleDereference no_deref;
      52             : 
      53             :     {
      54       51653 :       TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
      55             : 
      56      154959 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
      57             :                    "V8.RecompileConcurrent");
      58             : 
      59       51653 :       if (dispatcher_->recompilation_delay_ != 0) {
      60             :         base::OS::Sleep(base::TimeDelta::FromMilliseconds(
      61           0 :             dispatcher_->recompilation_delay_));
      62             :       }
      63             : 
      64       51653 :       dispatcher_->CompileNext(dispatcher_->NextInput(true));
      65             :     }
      66             :     {
      67       51653 :       base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
      68       51653 :       if (--dispatcher_->ref_count_ == 0) {
      69       45671 :         dispatcher_->ref_count_zero_.NotifyOne();
      70             :       }
      71             :     }
      72       51653 :   }
      73             : 
      74             :   Isolate* isolate_;
      75             :   OptimizingCompileDispatcher* dispatcher_;
      76             : 
      77             :   DISALLOW_COPY_AND_ASSIGN(CompileTask);
      78             : };
      79             : 
      80      177407 : OptimizingCompileDispatcher::~OptimizingCompileDispatcher() {
      81             : #ifdef DEBUG
      82             :   {
      83             :     base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
      84             :     DCHECK_EQ(0, ref_count_);
      85             :   }
      86             : #endif
      87             :   DCHECK_EQ(0, input_queue_length_);
      88       59135 :   DeleteArray(input_queue_);
      89       59136 : }
      90             : 
      91       51653 : CompilationJob* OptimizingCompileDispatcher::NextInput(bool check_if_flushing) {
      92       51653 :   base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
      93       51653 :   if (input_queue_length_ == 0) return NULL;
      94      103282 :   CompilationJob* job = input_queue_[InputQueueIndex(0)];
      95             :   DCHECK_NOT_NULL(job);
      96       51641 :   input_queue_shift_ = InputQueueIndex(1);
      97       51641 :   input_queue_length_--;
      98       51641 :   if (check_if_flushing) {
      99      103282 :     if (static_cast<ModeFlag>(base::Acquire_Load(&mode_)) == FLUSH) {
     100             :       AllowHandleDereference allow_handle_dereference;
     101          44 :       DisposeCompilationJob(job, true);
     102             :       return NULL;
     103             :     }
     104             :   }
     105       51597 :   return job;
     106             : }
     107             : 
     108       51653 : void OptimizingCompileDispatcher::CompileNext(CompilationJob* job) {
     109      103306 :   if (!job) return;
     110             : 
     111             :   // The function may have already been optimized by OSR.  Simply continue.
     112       51597 :   CompilationJob::Status status = job->ExecuteJob();
     113             :   USE(status);  // Prevent an unused-variable error.
     114             : 
     115             :   // The function may have already been optimized by OSR.  Simply continue.
     116             :   // Use a mutex to make sure that functions marked for install
     117             :   // are always also queued.
     118       51588 :   base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     119             :   output_queue_.push(job);
     120       51597 :   isolate_->stack_guard()->RequestInstallCode();
     121             : }
     122             : 
     123       83701 : void OptimizingCompileDispatcher::FlushOutputQueue(bool restore_function_code) {
     124             :   for (;;) {
     125             :     CompilationJob* job = NULL;
     126             :     {
     127       87066 :       base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     128      170769 :       if (output_queue_.empty()) return;
     129        3365 :       job = output_queue_.front();
     130             :       output_queue_.pop();
     131             :     }
     132             : 
     133        3365 :     DisposeCompilationJob(job, restore_function_code);
     134        3365 :   }
     135             : }
     136             : 
     137       24567 : void OptimizingCompileDispatcher::Flush(BlockingBehavior blocking_behavior) {
     138       24567 :   if (blocking_behavior == BlockingBehavior::kDontBlock) {
     139       12852 :     if (FLAG_block_concurrent_recompilation) Unblock();
     140       12852 :     base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
     141       12864 :     while (input_queue_length_ > 0) {
     142          24 :       CompilationJob* job = input_queue_[InputQueueIndex(0)];
     143             :       DCHECK_NOT_NULL(job);
     144          12 :       input_queue_shift_ = InputQueueIndex(1);
     145          12 :       input_queue_length_--;
     146          12 :       DisposeCompilationJob(job, true);
     147             :     }
     148       12852 :     FlushOutputQueue(true);
     149       12852 :     if (FLAG_trace_concurrent_recompilation) {
     150           0 :       PrintF("  ** Flushed concurrent recompilation queues (not blocking).\n");
     151             :     }
     152       24567 :     return;
     153             :   }
     154       11715 :   base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
     155       11715 :   if (FLAG_block_concurrent_recompilation) Unblock();
     156             :   {
     157       11715 :     base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
     158          23 :     while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
     159             :     base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
     160             :   }
     161       11715 :   FlushOutputQueue(true);
     162       11715 :   if (FLAG_trace_concurrent_recompilation) {
     163           0 :     PrintF("  ** Flushed concurrent recompilation queues.\n");
     164             :   }
     165             : }
     166             : 
     167       59135 : void OptimizingCompileDispatcher::Stop() {
     168       59135 :   base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
     169       59135 :   if (FLAG_block_concurrent_recompilation) Unblock();
     170             :   {
     171       59135 :     base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
     172          60 :     while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
     173             :     base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
     174             :   }
     175             : 
     176       59134 :   if (recompilation_delay_ != 0) {
     177             :     // At this point the optimizing compiler thread's event loop has stopped.
     178             :     // There is no need for a mutex when reading input_queue_length_.
     179           0 :     while (input_queue_length_ > 0) CompileNext(NextInput());
     180           0 :     InstallOptimizedFunctions();
     181             :   } else {
     182       59134 :     FlushOutputQueue(false);
     183             :   }
     184       59135 : }
     185             : 
     186       63646 : void OptimizingCompileDispatcher::InstallOptimizedFunctions() {
     187       63646 :   HandleScope handle_scope(isolate_);
     188             : 
     189             :   for (;;) {
     190       48218 :     CompilationJob* job = NULL;
     191             :     {
     192      111864 :       base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     193      175510 :       if (output_queue_.empty()) return;
     194       48218 :       job = output_queue_.front();
     195             :       output_queue_.pop();
     196             :     }
     197             :     CompilationInfo* info = job->info();
     198             :     Handle<JSFunction> function(*info->closure());
     199       48218 :     if (function->IsOptimized()) {
     200        4673 :       if (FLAG_trace_concurrent_recompilation) {
     201           0 :         PrintF("  ** Aborting compilation for ");
     202           0 :         function->ShortPrint();
     203           0 :         PrintF(" as it has already been optimized.\n");
     204             :       }
     205        4673 :       DisposeCompilationJob(job, false);
     206             :     } else {
     207       43545 :       Compiler::FinalizeCompilationJob(job);
     208             :     }
     209             :   }
     210             : }
     211             : 
     212       51653 : void OptimizingCompileDispatcher::QueueForOptimization(CompilationJob* job) {
     213             :   DCHECK(IsQueueAvailable());
     214             :   {
     215             :     // Add job to the back of the input queue.
     216       51653 :     base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
     217             :     DCHECK_LT(input_queue_length_, input_queue_capacity_);
     218      103306 :     input_queue_[InputQueueIndex(input_queue_length_)] = job;
     219       51653 :     input_queue_length_++;
     220             :   }
     221       51653 :   if (FLAG_block_concurrent_recompilation) {
     222          92 :     blocked_jobs_++;
     223             :   } else {
     224       51561 :     V8::GetCurrentPlatform()->CallOnBackgroundThread(
     225       51561 :         new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
     226             :   }
     227       51653 : }
     228             : 
     229         170 : void OptimizingCompileDispatcher::Unblock() {
     230         432 :   while (blocked_jobs_ > 0) {
     231          92 :     V8::GetCurrentPlatform()->CallOnBackgroundThread(
     232          92 :         new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
     233          92 :     blocked_jobs_--;
     234             :   }
     235         170 : }
     236             : 
     237             : }  // namespace internal
     238             : }  // namespace v8

Generated by: LCOV version 1.10