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       10698 : void DisposeCompilationJob(CompilationJob* job, bool restore_function_code) {
      22        7400 :   if (restore_function_code) {
      23             :     Handle<JSFunction> function = job->info()->closure();
      24        3298 :     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        7400 :   delete job;
      31        7400 : }
      32             : 
      33             : }  // namespace
      34             : 
      35             : class OptimizingCompileDispatcher::CompileTask : public v8::Task {
      36             :  public:
      37       51659 :   explicit CompileTask(Isolate* isolate,
      38             :                        OptimizingCompileDispatcher* dispatcher)
      39       51659 :       : isolate_(isolate), dispatcher_(dispatcher) {
      40       51659 :     base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
      41       51659 :     ++dispatcher_->ref_count_;
      42       51659 :   }
      43             : 
      44      103318 :   virtual ~CompileTask() {}
      45             : 
      46             :  private:
      47             :   // v8::Task overrides.
      48       51658 :   void Run() override {
      49             :     DisallowHeapAllocation no_allocation;
      50             :     DisallowHandleAllocation no_handles;
      51             :     DisallowHandleDereference no_deref;
      52             : 
      53             :     {
      54       51658 :       TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
      55             : 
      56      154973 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
      57             :                    "V8.RecompileConcurrent");
      58             : 
      59       51657 :       if (dispatcher_->recompilation_delay_ != 0) {
      60             :         base::OS::Sleep(base::TimeDelta::FromMilliseconds(
      61           0 :             dispatcher_->recompilation_delay_));
      62             :       }
      63             : 
      64       51657 :       dispatcher_->CompileNext(dispatcher_->NextInput(true));
      65             :     }
      66             :     {
      67       51659 :       base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
      68       51659 :       if (--dispatcher_->ref_count_ == 0) {
      69       45409 :         dispatcher_->ref_count_zero_.NotifyOne();
      70             :       }
      71             :     }
      72       51659 :   }
      73             : 
      74             :   Isolate* isolate_;
      75             :   OptimizingCompileDispatcher* dispatcher_;
      76             : 
      77             :   DISALLOW_COPY_AND_ASSIGN(CompileTask);
      78             : };
      79             : 
      80      177330 : 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       59110 :   DeleteArray(input_queue_);
      89       59110 : }
      90             : 
      91       51657 : CompilationJob* OptimizingCompileDispatcher::NextInput(bool check_if_flushing) {
      92       51657 :   base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
      93       51659 :   if (input_queue_length_ == 0) return NULL;
      94      103310 :   CompilationJob* job = input_queue_[InputQueueIndex(0)];
      95             :   DCHECK_NOT_NULL(job);
      96       51655 :   input_queue_shift_ = InputQueueIndex(1);
      97       51655 :   input_queue_length_--;
      98       51655 :   if (check_if_flushing) {
      99      103310 :     if (static_cast<ModeFlag>(base::Acquire_Load(&mode_)) == FLUSH) {
     100             :       AllowHandleDereference allow_handle_dereference;
     101          48 :       DisposeCompilationJob(job, true);
     102             :       return NULL;
     103             :     }
     104             :   }
     105       51607 :   return job;
     106             : }
     107             : 
     108       51659 : void OptimizingCompileDispatcher::CompileNext(CompilationJob* job) {
     109      103318 :   if (!job) return;
     110             : 
     111             :   // The function may have already been optimized by OSR.  Simply continue.
     112       51607 :   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       51604 :   base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     119             :   output_queue_.push(job);
     120       51607 :   isolate_->stack_guard()->RequestInstallCode();
     121             : }
     122             : 
     123       83638 : void OptimizingCompileDispatcher::FlushOutputQueue(bool restore_function_code) {
     124             :   for (;;) {
     125             :     CompilationJob* job = NULL;
     126             :     {
     127       87019 :       base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     128      170657 :       if (output_queue_.empty()) return;
     129        3381 :       job = output_queue_.front();
     130             :       output_queue_.pop();
     131             :     }
     132             : 
     133        3381 :     DisposeCompilationJob(job, restore_function_code);
     134        3381 :   }
     135             : }
     136             : 
     137       24529 : void OptimizingCompileDispatcher::Flush(BlockingBehavior blocking_behavior) {
     138       24529 :   if (blocking_behavior == BlockingBehavior::kDontBlock) {
     139       12838 :     if (FLAG_block_concurrent_recompilation) Unblock();
     140       12838 :     base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
     141       12842 :     while (input_queue_length_ > 0) {
     142           8 :       CompilationJob* job = input_queue_[InputQueueIndex(0)];
     143             :       DCHECK_NOT_NULL(job);
     144           4 :       input_queue_shift_ = InputQueueIndex(1);
     145           4 :       input_queue_length_--;
     146           4 :       DisposeCompilationJob(job, true);
     147             :     }
     148       12838 :     FlushOutputQueue(true);
     149       12838 :     if (FLAG_trace_concurrent_recompilation) {
     150           0 :       PrintF("  ** Flushed concurrent recompilation queues (not blocking).\n");
     151             :     }
     152       24529 :     return;
     153             :   }
     154       11691 :   base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
     155       11691 :   if (FLAG_block_concurrent_recompilation) Unblock();
     156             :   {
     157       11691 :     base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
     158          42 :     while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
     159             :     base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
     160             :   }
     161       11691 :   FlushOutputQueue(true);
     162       11691 :   if (FLAG_trace_concurrent_recompilation) {
     163           0 :     PrintF("  ** Flushed concurrent recompilation queues.\n");
     164             :   }
     165             : }
     166             : 
     167       59109 : void OptimizingCompileDispatcher::Stop() {
     168       59109 :   base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
     169       59109 :   if (FLAG_block_concurrent_recompilation) Unblock();
     170             :   {
     171       59109 :     base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
     172          74 :     while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
     173             :     base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
     174             :   }
     175             : 
     176       59109 :   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       59109 :     FlushOutputQueue(false);
     183             :   }
     184       59109 : }
     185             : 
     186       61216 : void OptimizingCompileDispatcher::InstallOptimizedFunctions() {
     187       61216 :   HandleScope handle_scope(isolate_);
     188             : 
     189             :   for (;;) {
     190       48211 :     CompilationJob* job = NULL;
     191             :     {
     192      109427 :       base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
     193      170643 :       if (output_queue_.empty()) return;
     194       48211 :       job = output_queue_.front();
     195             :       output_queue_.pop();
     196             :     }
     197             :     CompilationInfo* info = job->info();
     198             :     Handle<JSFunction> function(*info->closure());
     199       48211 :     if (function->IsOptimized()) {
     200        3967 :       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        3967 :       DisposeCompilationJob(job, false);
     206             :     } else {
     207       44244 :       Compiler::FinalizeCompilationJob(job);
     208             :     }
     209             :   }
     210             : }
     211             : 
     212       51659 : void OptimizingCompileDispatcher::QueueForOptimization(CompilationJob* job) {
     213             :   DCHECK(IsQueueAvailable());
     214             :   {
     215             :     // Add job to the back of the input queue.
     216       51659 :     base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
     217             :     DCHECK_LT(input_queue_length_, input_queue_capacity_);
     218      103318 :     input_queue_[InputQueueIndex(input_queue_length_)] = job;
     219       51659 :     input_queue_length_++;
     220             :   }
     221       51659 :   if (FLAG_block_concurrent_recompilation) {
     222          91 :     blocked_jobs_++;
     223             :   } else {
     224       51568 :     V8::GetCurrentPlatform()->CallOnBackgroundThread(
     225       51568 :         new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
     226             :   }
     227       51659 : }
     228             : 
     229         170 : void OptimizingCompileDispatcher::Unblock() {
     230         431 :   while (blocked_jobs_ > 0) {
     231          91 :     V8::GetCurrentPlatform()->CallOnBackgroundThread(
     232          91 :         new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
     233          91 :     blocked_jobs_--;
     234             :   }
     235         170 : }
     236             : 
     237             : }  // namespace internal
     238             : }  // namespace v8

Generated by: LCOV version 1.10