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

Generated by: LCOV version 1.10