Revert of Reland "Remove support for thread-based recompilation" (patchset #1 id...
authorjochen <jochen@chromium.org>
Tue, 14 Apr 2015 12:29:27 +0000 (05:29 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Apr 2015 12:29:26 +0000 (12:29 +0000)
Reason for revert:
still times out

Original issue's description:
> Reland "Remove support for thread-based recompilation"
>
> Original issue's description:
> > Remove support for thread-based recompilation
> >
> > BUG=v8:3608
> > R=yangguo@chromium.org
> > LOG=y
> >
> > Committed: https://crrev.com/ed5db223a19dfe126af012e894582251aa3635d7
> > Cr-Commit-Position: refs/heads/master@{#27619}
>
> BUG=v8:3608
> R=yangguo@chromium.org
> LOG=y
>
> Committed: https://crrev.com/f1ceccb8b8b352a91e6366e3e3103f1db0df6afb
> Cr-Commit-Position: refs/heads/master@{#27813}

TBR=yangguo@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:3608

Review URL: https://codereview.chromium.org/1082183003

Cr-Commit-Position: refs/heads/master@{#27816}

19 files changed:
BUILD.gn
src/compiler.cc
src/compiler.h
src/cpu-profiler.h
src/debug.cc
src/execution.cc
src/flag-definitions.h
src/heap/heap.cc
src/hydrogen.cc
src/isolate.cc
src/isolate.h
src/objects.cc
src/optimizing-compile-dispatcher.cc [deleted file]
src/optimizing-compile-dispatcher.h [deleted file]
src/optimizing-compiler-thread.cc [new file with mode: 0644]
src/optimizing-compiler-thread.h [new file with mode: 0644]
src/runtime/runtime-compiler.cc
src/runtime/runtime-test.cc
tools/gyp/v8.gyp

index 3eebcfe8ceb49252a070acb4228c7e92c9eeeb27..4d0e3385557c3c8f8c74025cb08c6013f029ae88 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -893,8 +893,8 @@ source_set("v8_base") {
     "src/objects-printer.cc",
     "src/objects.cc",
     "src/objects.h",
-    "src/optimizing-compile-dispatcher.cc",
-    "src/optimizing-compile-dispatcher.h",
+    "src/optimizing-compiler-thread.cc",
+    "src/optimizing-compiler-thread.h",
     "src/ostreams.cc",
     "src/ostreams.h",
     "src/parser.cc",
index 9502311960a74cbd08e4a9a25e9f093901fccf66..00a228238f98574a0949ba396a29ac32c3d2d220 100644 (file)
@@ -819,7 +819,7 @@ static bool GetOptimizedCodeNow(CompilationInfo* info) {
 
 static bool GetOptimizedCodeLater(CompilationInfo* info) {
   Isolate* isolate = info->isolate();
-  if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
+  if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
     if (FLAG_trace_concurrent_recompilation) {
       PrintF("  ** Compilation queue full, will retry optimizing ");
       info->closure()->ShortPrint();
@@ -840,7 +840,7 @@ static bool GetOptimizedCodeLater(CompilationInfo* info) {
   OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info);
   OptimizedCompileJob::Status status = job->CreateGraph();
   if (status != OptimizedCompileJob::SUCCEEDED) return false;
-  isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
+  isolate->optimizing_compiler_thread()->QueueForOptimization(job);
 
   if (FLAG_trace_concurrent_recompilation) {
     PrintF("  ** Queued ");
index f9acb66c089b38d86bb1f15e753edb03a4a98fdc..fb91a9e2f5e1383927814c4c0b1e1273417d2934 100644 (file)
@@ -372,10 +372,12 @@ class CompilationInfo {
   }
 
   void AbortDueToDependencyChange() {
+    DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
     aborted_due_to_dependency_change_ = true;
   }
 
   bool HasAbortedDueToDependencyChange() const {
+    DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
     return aborted_due_to_dependency_change_;
   }
 
index 7d8669bf61f3778d340d8ee3ecb7397e69c50bda..26ec7f900a4cc120996ca12b9edcd6bc4083f550 100644 (file)
@@ -11,7 +11,7 @@
 #include "src/circular-queue.h"
 #include "src/compiler.h"
 #include "src/sampler.h"
-#include "src/unbound-queue-inl.h"
+#include "src/unbound-queue.h"
 
 namespace v8 {
 namespace internal {
index 25407a746fc5a61b6e58e7e2fd1367427bb160f3..854b507c47339fd21a9d61eb58ed6ebf3e32f4b5 100644 (file)
@@ -1843,7 +1843,7 @@ void Debug::PrepareForBreakPoints() {
   // functions as debugging does not work with optimized code.
   if (!has_break_points_) {
     if (isolate_->concurrent_recompilation_enabled()) {
-      isolate_->optimizing_compile_dispatcher()->Flush();
+      isolate_->optimizing_compiler_thread()->Flush();
     }
 
     Deoptimizer::DeoptimizeAll(isolate_);
index e281bac5fa25e778bc0e9ddecd60565af3d2d796..7ae67410e45790653c33d8f578abf79f8c38ec18 100644 (file)
@@ -677,7 +677,7 @@ Object* StackGuard::HandleInterrupts() {
 
   if (CheckAndClearInterrupt(INSTALL_CODE)) {
     DCHECK(isolate_->concurrent_recompilation_enabled());
-    isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
+    isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
   }
 
   if (CheckAndClearInterrupt(API_INTERRUPT)) {
index def2dec73ef6bd637bdf781df9f4a3f729cefce9..e48dd9f788507f08861d91aef2c04217106feb47 100644 (file)
@@ -364,6 +364,9 @@ DEFINE_BOOL(optimize_for_in, true, "optimize functions containing for-in loops")
 
 DEFINE_BOOL(concurrent_recompilation, true,
             "optimizing hot functions asynchronously on a separate thread")
+DEFINE_BOOL(job_based_recompilation, true,
+            "post tasks to v8::Platform instead of using a thread for "
+            "concurrent recompilation")
 DEFINE_BOOL(trace_concurrent_recompilation, false,
             "track concurrent recompilation")
 DEFINE_INT(concurrent_recompilation_queue_length, 8,
index 0a458d7acfde0e45136c37e87141a0c1950771b3..274d9ef0c22e83a5cc1f92ad8a03da6e7b9c6244 100644 (file)
@@ -430,7 +430,7 @@ void Heap::GarbageCollectionPrologue() {
   store_buffer()->GCPrologue();
 
   if (isolate()->concurrent_osr_enabled()) {
-    isolate()->optimizing_compile_dispatcher()->AgeBufferedOsrJobs();
+    isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs();
   }
 
   if (new_space_.IsAtMaximumCapacity()) {
@@ -767,7 +767,7 @@ void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
   if (isolate()->concurrent_recompilation_enabled()) {
     // The optimizing compiler may be unnecessarily holding on to memory.
     DisallowHeapAllocation no_recursive_gc;
-    isolate()->optimizing_compile_dispatcher()->Flush();
+    isolate()->optimizing_compiler_thread()->Flush();
   }
   isolate()->ClearSerializerData();
   mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
@@ -885,7 +885,7 @@ int Heap::NotifyContextDisposed(bool dependant_context) {
   }
   if (isolate()->concurrent_recompilation_enabled()) {
     // Flush the queued recompilation tasks.
-    isolate()->optimizing_compile_dispatcher()->Flush();
+    isolate()->optimizing_compiler_thread()->Flush();
   }
   AgeInlineCaches();
   set_retained_maps(ArrayList::cast(empty_fixed_array()));
index 0ea1bd59bd42890451fd6de40e34dbe43335e9c9..7649dae047dc43dbb6a7dfff333c021182cb7883 100644 (file)
@@ -3475,6 +3475,7 @@ HBasicBlock* HGraph::CreateBasicBlock() {
 
 void HGraph::FinalizeUniqueness() {
   DisallowHeapAllocation no_gc;
+  DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
   for (int i = 0; i < blocks()->length(); ++i) {
     for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
       it.Current()->FinalizeUniqueness();
index 9a9403a79f660441347df4f2349e2bfa59827551..927972d8225dcd0b2fcfdd7fec1493bcfa897a89 100644 (file)
@@ -1736,7 +1736,7 @@ Isolate::Isolate(bool enable_serializer)
       heap_profiler_(NULL),
       function_entry_hook_(NULL),
       deferred_handles_head_(NULL),
-      optimizing_compile_dispatcher_(NULL),
+      optimizing_compiler_thread_(NULL),
       stress_deopt_count_(0),
       next_optimization_id_(0),
 #if TRACE_MAPS
@@ -1833,9 +1833,9 @@ void Isolate::Deinit() {
   FreeThreadResources();
 
   if (concurrent_recompilation_enabled()) {
-    optimizing_compile_dispatcher_->Stop();
-    delete optimizing_compile_dispatcher_;
-    optimizing_compile_dispatcher_ = NULL;
+    optimizing_compiler_thread_->Stop();
+    delete optimizing_compiler_thread_;
+    optimizing_compiler_thread_ = NULL;
   }
 
   if (heap_.mark_compact_collector()->sweeping_in_progress()) {
@@ -2133,8 +2133,9 @@ bool Isolate::Init(Deserializer* des) {
 
   if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) {
     PrintF("Concurrent recompilation has been disabled for tracing.\n");
-  } else if (OptimizingCompileDispatcher::Enabled(max_available_threads_)) {
-    optimizing_compile_dispatcher_ = new OptimizingCompileDispatcher(this);
+  } else if (OptimizingCompilerThread::Enabled(max_available_threads_)) {
+    optimizing_compiler_thread_ = new OptimizingCompilerThread(this);
+    optimizing_compiler_thread_->Start();
   }
 
   // Initialize runtime profiler before deserialization, because collections may
index 85d25ed93e782894abb701a9b6f2bd367c07ee01..e8576f5940d599b30617984b46342c1cffbc1dc7 100644 (file)
@@ -19,7 +19,7 @@
 #include "src/handles.h"
 #include "src/hashmap.h"
 #include "src/heap/heap.h"
-#include "src/optimizing-compile-dispatcher.h"
+#include "src/optimizing-compiler-thread.h"
 #include "src/regexp-stack.h"
 #include "src/runtime/runtime.h"
 #include "src/runtime-profiler.h"
@@ -1028,20 +1028,20 @@ class Isolate {
 
   bool concurrent_recompilation_enabled() {
     // Thread is only available with flag enabled.
-    DCHECK(optimizing_compile_dispatcher_ == NULL ||
+    DCHECK(optimizing_compiler_thread_ == NULL ||
            FLAG_concurrent_recompilation);
-    return optimizing_compile_dispatcher_ != NULL;
+    return optimizing_compiler_thread_ != NULL;
   }
 
   bool concurrent_osr_enabled() const {
     // Thread is only available with flag enabled.
-    DCHECK(optimizing_compile_dispatcher_ == NULL ||
+    DCHECK(optimizing_compiler_thread_ == NULL ||
            FLAG_concurrent_recompilation);
-    return optimizing_compile_dispatcher_ != NULL && FLAG_concurrent_osr;
+    return optimizing_compiler_thread_ != NULL && FLAG_concurrent_osr;
   }
 
-  OptimizingCompileDispatcher* optimizing_compile_dispatcher() {
-    return optimizing_compile_dispatcher_;
+  OptimizingCompilerThread* optimizing_compiler_thread() {
+    return optimizing_compiler_thread_;
   }
 
   int id() const { return static_cast<int>(id_); }
@@ -1329,7 +1329,7 @@ class Isolate {
 #endif
 
   DeferredHandles* deferred_handles_head_;
-  OptimizingCompileDispatcher* optimizing_compile_dispatcher_;
+  OptimizingCompilerThread* optimizing_compiler_thread_;
 
   // Counts deopt points if deopt_every_n_times is enabled.
   unsigned int stress_deopt_count_;
@@ -1350,7 +1350,7 @@ class Isolate {
 
   friend class ExecutionAccess;
   friend class HandleScopeImplementer;
-  friend class OptimizingCompileDispatcher;
+  friend class OptimizingCompilerThread;
   friend class SweeperThread;
   friend class ThreadManager;
   friend class Simulator;
index bb10a9b1c203b08793c58c5a0c2c936c0a8b9599..20d7f9029b29e98bd7f5c21674087287be8f8216 100644 (file)
@@ -9708,7 +9708,7 @@ void JSFunction::AttemptConcurrentOptimization() {
     return;
   }
   if (isolate->concurrent_osr_enabled() &&
-      isolate->optimizing_compile_dispatcher()->IsQueuedForOSR(this)) {
+      isolate->optimizing_compiler_thread()->IsQueuedForOSR(this)) {
     // Do not attempt regular recompilation if we already queued this for OSR.
     // TODO(yangguo): This is necessary so that we don't install optimized
     // code on a function that is already optimized, since OSR and regular
diff --git a/src/optimizing-compile-dispatcher.cc b/src/optimizing-compile-dispatcher.cc
deleted file mode 100644 (file)
index 8445dc1..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/optimizing-compile-dispatcher.h"
-
-#include "src/v8.h"
-
-#include "src/base/atomicops.h"
-#include "src/full-codegen.h"
-#include "src/hydrogen.h"
-#include "src/isolate.h"
-
-namespace v8 {
-namespace internal {
-
-namespace {
-
-void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
-                                bool restore_function_code) {
-  // The recompile job is allocated in the CompilationInfo's zone.
-  CompilationInfo* info = job->info();
-  if (restore_function_code) {
-    if (info->is_osr()) {
-      if (!job->IsWaitingForInstall()) {
-        // Remove stack check that guards OSR entry on original code.
-        Handle<Code> code = info->unoptimized_code();
-        uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
-        BackEdgeTable::RemoveStackCheck(code, offset);
-      }
-    } else {
-      Handle<JSFunction> function = info->closure();
-      function->ReplaceCode(function->shared()->code());
-    }
-  }
-  delete info;
-}
-
-}  // namespace
-
-
-class OptimizingCompileDispatcher::CompileTask : public v8::Task {
- public:
-  explicit CompileTask(Isolate* isolate) : isolate_(isolate) {
-    OptimizingCompileDispatcher* dispatcher =
-        isolate_->optimizing_compile_dispatcher();
-    base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
-    ++dispatcher->ref_count_;
-  }
-
-  virtual ~CompileTask() {}
-
- private:
-  // v8::Task overrides.
-  void Run() OVERRIDE {
-    DisallowHeapAllocation no_allocation;
-    DisallowHandleAllocation no_handles;
-    DisallowHandleDereference no_deref;
-
-    OptimizingCompileDispatcher* dispatcher =
-        isolate_->optimizing_compile_dispatcher();
-    {
-      TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
-
-      if (dispatcher->recompilation_delay_ != 0) {
-        base::OS::Sleep(dispatcher->recompilation_delay_);
-      }
-
-      dispatcher->CompileNext(dispatcher->NextInput(true));
-    }
-    {
-      base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
-      if (--dispatcher->ref_count_ == 0) {
-        dispatcher->ref_count_zero_.NotifyOne();
-      }
-    }
-  }
-
-  Isolate* isolate_;
-
-  DISALLOW_COPY_AND_ASSIGN(CompileTask);
-};
-
-
-OptimizingCompileDispatcher::~OptimizingCompileDispatcher() {
-#ifdef DEBUG
-  {
-    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
-    DCHECK_EQ(0, ref_count_);
-  }
-#endif
-  DCHECK_EQ(0, input_queue_length_);
-  DeleteArray(input_queue_);
-  if (FLAG_concurrent_osr) {
-#ifdef DEBUG
-    for (int i = 0; i < osr_buffer_capacity_; i++) {
-      CHECK_NULL(osr_buffer_[i]);
-    }
-#endif
-    DeleteArray(osr_buffer_);
-  }
-}
-
-
-OptimizedCompileJob* OptimizingCompileDispatcher::NextInput(
-    bool check_if_flushing) {
-  base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
-  if (input_queue_length_ == 0) return NULL;
-  OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)];
-  DCHECK_NOT_NULL(job);
-  input_queue_shift_ = InputQueueIndex(1);
-  input_queue_length_--;
-  if (check_if_flushing) {
-    if (static_cast<ModeFlag>(base::Acquire_Load(&mode_)) == FLUSH) {
-      if (!job->info()->is_osr()) {
-        AllowHandleDereference allow_handle_dereference;
-        DisposeOptimizedCompileJob(job, true);
-      }
-      return NULL;
-    }
-  }
-  return job;
-}
-
-
-void OptimizingCompileDispatcher::CompileNext(OptimizedCompileJob* job) {
-  if (!job) return;
-
-  // The function may have already been optimized by OSR.  Simply continue.
-  OptimizedCompileJob::Status status = job->OptimizeGraph();
-  USE(status);  // Prevent an unused-variable error in release mode.
-  DCHECK(status != OptimizedCompileJob::FAILED);
-
-  // The function may have already been optimized by OSR.  Simply continue.
-  // Use a mutex to make sure that functions marked for install
-  // are always also queued.
-  base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
-  output_queue_.push(job);
-  isolate_->stack_guard()->RequestInstallCode();
-}
-
-
-void OptimizingCompileDispatcher::FlushOutputQueue(bool restore_function_code) {
-  base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
-  while (!output_queue_.empty()) {
-    OptimizedCompileJob* job = output_queue_.front();
-    output_queue_.pop();
-
-    // OSR jobs are dealt with separately.
-    if (!job->info()->is_osr()) {
-      DisposeOptimizedCompileJob(job, restore_function_code);
-    }
-  }
-}
-
-
-void OptimizingCompileDispatcher::FlushOsrBuffer(bool restore_function_code) {
-  for (int i = 0; i < osr_buffer_capacity_; i++) {
-    if (osr_buffer_[i] != NULL) {
-      DisposeOptimizedCompileJob(osr_buffer_[i], restore_function_code);
-      osr_buffer_[i] = NULL;
-    }
-  }
-}
-
-
-void OptimizingCompileDispatcher::Flush() {
-  base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
-  if (FLAG_block_concurrent_recompilation) Unblock();
-  {
-    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
-    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
-    base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
-  }
-  FlushOutputQueue(true);
-  if (FLAG_concurrent_osr) FlushOsrBuffer(true);
-  if (FLAG_trace_concurrent_recompilation) {
-    PrintF("  ** Flushed concurrent recompilation queues.\n");
-  }
-}
-
-
-void OptimizingCompileDispatcher::Stop() {
-  base::Release_Store(&mode_, static_cast<base::AtomicWord>(FLUSH));
-  if (FLAG_block_concurrent_recompilation) Unblock();
-  {
-    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
-    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
-    base::Release_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
-  }
-
-  if (recompilation_delay_ != 0) {
-    // At this point the optimizing compiler thread's event loop has stopped.
-    // There is no need for a mutex when reading input_queue_length_.
-    while (input_queue_length_ > 0) CompileNext(NextInput());
-    InstallOptimizedFunctions();
-  } else {
-    FlushOutputQueue(false);
-  }
-
-  if (FLAG_concurrent_osr) FlushOsrBuffer(false);
-
-  if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) &&
-      FLAG_concurrent_osr) {
-    PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
-  }
-}
-
-
-void OptimizingCompileDispatcher::InstallOptimizedFunctions() {
-  HandleScope handle_scope(isolate_);
-
-  base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
-  while (!output_queue_.empty()) {
-    OptimizedCompileJob* job = output_queue_.front();
-    output_queue_.pop();
-    CompilationInfo* info = job->info();
-    Handle<JSFunction> function(*info->closure());
-    if (info->is_osr()) {
-      if (FLAG_trace_osr) {
-        PrintF("[COSR - ");
-        function->ShortPrint();
-        PrintF(" is ready for install and entry at AST id %d]\n",
-               info->osr_ast_id().ToInt());
-      }
-      job->WaitForInstall();
-      // Remove stack check that guards OSR entry on original code.
-      Handle<Code> code = info->unoptimized_code();
-      uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
-      BackEdgeTable::RemoveStackCheck(code, offset);
-    } else {
-      if (function->IsOptimized()) {
-        if (FLAG_trace_concurrent_recompilation) {
-          PrintF("  ** Aborting compilation for ");
-          function->ShortPrint();
-          PrintF(" as it has already been optimized.\n");
-        }
-        DisposeOptimizedCompileJob(job, false);
-      } else {
-        Handle<Code> code = Compiler::GetConcurrentlyOptimizedCode(job);
-        function->ReplaceCode(code.is_null() ? function->shared()->code()
-                                             : *code);
-      }
-    }
-  }
-}
-
-
-void OptimizingCompileDispatcher::QueueForOptimization(
-    OptimizedCompileJob* job) {
-  DCHECK(IsQueueAvailable());
-  CompilationInfo* info = job->info();
-  if (info->is_osr()) {
-    osr_attempts_++;
-    AddToOsrBuffer(job);
-    // Add job to the front of the input queue.
-    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
-    DCHECK_LT(input_queue_length_, input_queue_capacity_);
-    // Move shift_ back by one.
-    input_queue_shift_ = InputQueueIndex(input_queue_capacity_ - 1);
-    input_queue_[InputQueueIndex(0)] = job;
-    input_queue_length_++;
-  } else {
-    // Add job to the back of the input queue.
-    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
-    DCHECK_LT(input_queue_length_, input_queue_capacity_);
-    input_queue_[InputQueueIndex(input_queue_length_)] = job;
-    input_queue_length_++;
-  }
-  if (FLAG_block_concurrent_recompilation) {
-    blocked_jobs_++;
-  } else {
-    V8::GetCurrentPlatform()->CallOnBackgroundThread(
-        new CompileTask(isolate_), v8::Platform::kShortRunningTask);
-  }
-}
-
-
-void OptimizingCompileDispatcher::Unblock() {
-  while (blocked_jobs_ > 0) {
-    V8::GetCurrentPlatform()->CallOnBackgroundThread(
-        new CompileTask(isolate_), v8::Platform::kShortRunningTask);
-    blocked_jobs_--;
-  }
-}
-
-
-OptimizedCompileJob* OptimizingCompileDispatcher::FindReadyOSRCandidate(
-    Handle<JSFunction> function, BailoutId osr_ast_id) {
-  for (int i = 0; i < osr_buffer_capacity_; i++) {
-    OptimizedCompileJob* current = osr_buffer_[i];
-    if (current != NULL && current->IsWaitingForInstall() &&
-        current->info()->HasSameOsrEntry(function, osr_ast_id)) {
-      osr_hits_++;
-      osr_buffer_[i] = NULL;
-      return current;
-    }
-  }
-  return NULL;
-}
-
-
-bool OptimizingCompileDispatcher::IsQueuedForOSR(Handle<JSFunction> function,
-                                                 BailoutId osr_ast_id) {
-  for (int i = 0; i < osr_buffer_capacity_; i++) {
-    OptimizedCompileJob* current = osr_buffer_[i];
-    if (current != NULL &&
-        current->info()->HasSameOsrEntry(function, osr_ast_id)) {
-      return !current->IsWaitingForInstall();
-    }
-  }
-  return false;
-}
-
-
-bool OptimizingCompileDispatcher::IsQueuedForOSR(JSFunction* function) {
-  for (int i = 0; i < osr_buffer_capacity_; i++) {
-    OptimizedCompileJob* current = osr_buffer_[i];
-    if (current != NULL && *current->info()->closure() == function) {
-      return !current->IsWaitingForInstall();
-    }
-  }
-  return false;
-}
-
-
-void OptimizingCompileDispatcher::AddToOsrBuffer(OptimizedCompileJob* job) {
-  // Find the next slot that is empty or has a stale job.
-  OptimizedCompileJob* stale = NULL;
-  while (true) {
-    stale = osr_buffer_[osr_buffer_cursor_];
-    if (stale == NULL || stale->IsWaitingForInstall()) break;
-    osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
-  }
-
-  // Add to found slot and dispose the evicted job.
-  if (stale != NULL) {
-    DCHECK(stale->IsWaitingForInstall());
-    CompilationInfo* info = stale->info();
-    if (FLAG_trace_osr) {
-      PrintF("[COSR - Discarded ");
-      info->closure()->PrintName();
-      PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
-    }
-    DisposeOptimizedCompileJob(stale, false);
-  }
-  osr_buffer_[osr_buffer_cursor_] = job;
-  osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
-}
-}
-}  // namespace v8::internal
diff --git a/src/optimizing-compile-dispatcher.h b/src/optimizing-compile-dispatcher.h
deleted file mode 100644 (file)
index 822bb40..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_OPTIMIZING_COMPILE_DISPATCHER_H_
-#define V8_OPTIMIZING_COMPILE_DISPATCHER_H_
-
-#include <queue>
-
-#include "src/base/atomicops.h"
-#include "src/base/platform/condition-variable.h"
-#include "src/base/platform/mutex.h"
-#include "src/base/platform/platform.h"
-#include "src/flags.h"
-#include "src/list.h"
-
-namespace v8 {
-namespace internal {
-
-class HOptimizedGraphBuilder;
-class OptimizedCompileJob;
-class SharedFunctionInfo;
-
-class OptimizingCompileDispatcher {
- public:
-  explicit OptimizingCompileDispatcher(Isolate* isolate)
-      : isolate_(isolate),
-        input_queue_capacity_(FLAG_concurrent_recompilation_queue_length),
-        input_queue_length_(0),
-        input_queue_shift_(0),
-        osr_buffer_capacity_(FLAG_concurrent_recompilation_queue_length + 4),
-        osr_buffer_cursor_(0),
-        osr_hits_(0),
-        osr_attempts_(0),
-        blocked_jobs_(0),
-        ref_count_(0),
-        recompilation_delay_(FLAG_concurrent_recompilation_delay) {
-    base::NoBarrier_Store(&mode_, static_cast<base::AtomicWord>(COMPILE));
-    input_queue_ = NewArray<OptimizedCompileJob*>(input_queue_capacity_);
-    if (FLAG_concurrent_osr) {
-      // Allocate and mark OSR buffer slots as empty.
-      osr_buffer_ = NewArray<OptimizedCompileJob*>(osr_buffer_capacity_);
-      for (int i = 0; i < osr_buffer_capacity_; i++) osr_buffer_[i] = NULL;
-    }
-  }
-
-  ~OptimizingCompileDispatcher();
-
-  void Run();
-  void Stop();
-  void Flush();
-  void QueueForOptimization(OptimizedCompileJob* optimizing_compiler);
-  void Unblock();
-  void InstallOptimizedFunctions();
-  OptimizedCompileJob* FindReadyOSRCandidate(Handle<JSFunction> function,
-                                             BailoutId osr_ast_id);
-  bool IsQueuedForOSR(Handle<JSFunction> function, BailoutId osr_ast_id);
-
-  bool IsQueuedForOSR(JSFunction* function);
-
-  inline bool IsQueueAvailable() {
-    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
-    return input_queue_length_ < input_queue_capacity_;
-  }
-
-  inline void AgeBufferedOsrJobs() {
-    // Advance cursor of the cyclic buffer to next empty slot or stale OSR job.
-    // Dispose said OSR job in the latter case.  Calling this on every GC
-    // should make sure that we do not hold onto stale jobs indefinitely.
-    AddToOsrBuffer(NULL);
-  }
-
-  static bool Enabled(int max_available) {
-    return (FLAG_concurrent_recompilation && max_available > 1);
-  }
-
- private:
-  class CompileTask;
-
-  enum ModeFlag { COMPILE, FLUSH };
-
-  void FlushOutputQueue(bool restore_function_code);
-  void FlushOsrBuffer(bool restore_function_code);
-  void CompileNext(OptimizedCompileJob* job);
-  OptimizedCompileJob* NextInput(bool check_if_flushing = false);
-
-  // Add a recompilation task for OSR to the cyclic buffer, awaiting OSR entry.
-  // Tasks evicted from the cyclic buffer are discarded.
-  void AddToOsrBuffer(OptimizedCompileJob* compiler);
-
-  inline int InputQueueIndex(int i) {
-    int result = (i + input_queue_shift_) % input_queue_capacity_;
-    DCHECK_LE(0, result);
-    DCHECK_LT(result, input_queue_capacity_);
-    return result;
-  }
-
-  Isolate* isolate_;
-
-  // Circular queue of incoming recompilation tasks (including OSR).
-  OptimizedCompileJob** input_queue_;
-  int input_queue_capacity_;
-  int input_queue_length_;
-  int input_queue_shift_;
-  base::Mutex input_queue_mutex_;
-
-  // Queue of recompilation tasks ready to be installed (excluding OSR).
-  std::queue<OptimizedCompileJob*> output_queue_;
-  // Used for job based recompilation which has multiple producers on
-  // different threads.
-  base::Mutex output_queue_mutex_;
-
-  // Cyclic buffer of recompilation tasks for OSR.
-  OptimizedCompileJob** osr_buffer_;
-  int osr_buffer_capacity_;
-  int osr_buffer_cursor_;
-
-  volatile base::AtomicWord mode_;
-
-  int osr_hits_;
-  int osr_attempts_;
-
-  int blocked_jobs_;
-
-  int ref_count_;
-  base::Mutex ref_count_mutex_;
-  base::ConditionVariable ref_count_zero_;
-
-  // Copy of FLAG_concurrent_recompilation_delay that will be used from the
-  // background thread.
-  //
-  // Since flags might get modified while the background thread is running, it
-  // is not safe to access them directly.
-  int recompilation_delay_;
-};
-}
-}  // namespace v8::internal
-
-#endif  // V8_OPTIMIZING_COMPILE_DISPATCHER_H_
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
new file mode 100644 (file)
index 0000000..eda4f5c
--- /dev/null
@@ -0,0 +1,463 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/optimizing-compiler-thread.h"
+
+#include "src/v8.h"
+
+#include "src/base/atomicops.h"
+#include "src/full-codegen.h"
+#include "src/hydrogen.h"
+#include "src/isolate.h"
+#include "src/v8threads.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
+                                bool restore_function_code) {
+  // The recompile job is allocated in the CompilationInfo's zone.
+  CompilationInfo* info = job->info();
+  if (restore_function_code) {
+    if (info->is_osr()) {
+      if (!job->IsWaitingForInstall()) {
+        // Remove stack check that guards OSR entry on original code.
+        Handle<Code> code = info->unoptimized_code();
+        uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
+        BackEdgeTable::RemoveStackCheck(code, offset);
+      }
+    } else {
+      Handle<JSFunction> function = info->closure();
+      function->ReplaceCode(function->shared()->code());
+    }
+  }
+  delete info;
+}
+
+}  // namespace
+
+
+class OptimizingCompilerThread::CompileTask : public v8::Task {
+ public:
+  explicit CompileTask(Isolate* isolate) : isolate_(isolate) {
+    OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread();
+    base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_);
+    ++thread->ref_count_;
+  }
+
+  virtual ~CompileTask() {}
+
+ private:
+  // v8::Task overrides.
+  void Run() OVERRIDE {
+    DisallowHeapAllocation no_allocation;
+    DisallowHandleAllocation no_handles;
+    DisallowHandleDereference no_deref;
+
+    OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread();
+    {
+      TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
+
+      if (thread->recompilation_delay_ != 0) {
+        base::OS::Sleep(thread->recompilation_delay_);
+      }
+
+      thread->CompileNext(thread->NextInput(true));
+    }
+    {
+      base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_);
+      if (--thread->ref_count_ == 0) {
+        thread->ref_count_zero_.NotifyOne();
+      }
+    }
+  }
+
+  Isolate* isolate_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompileTask);
+};
+
+
+OptimizingCompilerThread::~OptimizingCompilerThread() {
+#ifdef DEBUG
+  {
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    DCHECK_EQ(0, ref_count_);
+  }
+#endif
+  DCHECK_EQ(0, input_queue_length_);
+  DeleteArray(input_queue_);
+  if (FLAG_concurrent_osr) {
+#ifdef DEBUG
+    for (int i = 0; i < osr_buffer_capacity_; i++) {
+      CHECK_NULL(osr_buffer_[i]);
+    }
+#endif
+    DeleteArray(osr_buffer_);
+  }
+}
+
+
+void OptimizingCompilerThread::Run() {
+#ifdef DEBUG
+  { base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_);
+    thread_id_ = ThreadId::Current().ToInteger();
+  }
+#endif
+  DisallowHeapAllocation no_allocation;
+  DisallowHandleAllocation no_handles;
+  DisallowHandleDereference no_deref;
+
+  if (job_based_recompilation_) {
+    return;
+  }
+
+  base::ElapsedTimer total_timer;
+  if (tracing_enabled_) total_timer.Start();
+
+  while (true) {
+    input_queue_semaphore_.Wait();
+    TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
+
+    if (recompilation_delay_ != 0) {
+      base::OS::Sleep(recompilation_delay_);
+    }
+
+    switch (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_))) {
+      case CONTINUE:
+        break;
+      case STOP:
+        if (tracing_enabled_) {
+          time_spent_total_ = total_timer.Elapsed();
+        }
+        stop_semaphore_.Signal();
+        return;
+      case FLUSH:
+        // The main thread is blocked, waiting for the stop semaphore.
+        { AllowHandleDereference allow_handle_dereference;
+          FlushInputQueue(true);
+        }
+        base::Release_Store(&stop_thread_,
+                            static_cast<base::AtomicWord>(CONTINUE));
+        stop_semaphore_.Signal();
+        // Return to start of consumer loop.
+        continue;
+    }
+
+    base::ElapsedTimer compiling_timer;
+    if (tracing_enabled_) compiling_timer.Start();
+
+    CompileNext(NextInput());
+
+    if (tracing_enabled_) {
+      time_spent_compiling_ += compiling_timer.Elapsed();
+    }
+  }
+}
+
+
+OptimizedCompileJob* OptimizingCompilerThread::NextInput(
+    bool check_if_flushing) {
+  base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
+  if (input_queue_length_ == 0) return NULL;
+  OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)];
+  DCHECK_NOT_NULL(job);
+  input_queue_shift_ = InputQueueIndex(1);
+  input_queue_length_--;
+  if (check_if_flushing) {
+    if (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_)) != CONTINUE) {
+      if (!job->info()->is_osr()) {
+        AllowHandleDereference allow_handle_dereference;
+        DisposeOptimizedCompileJob(job, true);
+      }
+      return NULL;
+    }
+  }
+  return job;
+}
+
+
+void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) {
+  if (!job) return;
+
+  // The function may have already been optimized by OSR.  Simply continue.
+  OptimizedCompileJob::Status status = job->OptimizeGraph();
+  USE(status);   // Prevent an unused-variable error in release mode.
+  DCHECK(status != OptimizedCompileJob::FAILED);
+
+  // The function may have already been optimized by OSR.  Simply continue.
+  // Use a mutex to make sure that functions marked for install
+  // are always also queued.
+  if (job_based_recompilation_) output_queue_mutex_.Lock();
+  output_queue_.Enqueue(job);
+  if (job_based_recompilation_) output_queue_mutex_.Unlock();
+  isolate_->stack_guard()->RequestInstallCode();
+}
+
+
+void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
+  OptimizedCompileJob* job;
+  while ((job = NextInput())) {
+    DCHECK(!job_based_recompilation_);
+    // This should not block, since we have one signal on the input queue
+    // semaphore corresponding to each element in the input queue.
+    input_queue_semaphore_.Wait();
+    // OSR jobs are dealt with separately.
+    if (!job->info()->is_osr()) {
+      DisposeOptimizedCompileJob(job, restore_function_code);
+    }
+  }
+}
+
+
+void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
+  OptimizedCompileJob* job;
+  while (output_queue_.Dequeue(&job)) {
+    // OSR jobs are dealt with separately.
+    if (!job->info()->is_osr()) {
+      DisposeOptimizedCompileJob(job, restore_function_code);
+    }
+  }
+}
+
+
+void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) {
+  for (int i = 0; i < osr_buffer_capacity_; i++) {
+    if (osr_buffer_[i] != NULL) {
+      DisposeOptimizedCompileJob(osr_buffer_[i], restore_function_code);
+      osr_buffer_[i] = NULL;
+    }
+  }
+}
+
+
+void OptimizingCompilerThread::Flush() {
+  DCHECK(!IsOptimizerThread());
+  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
+  if (FLAG_block_concurrent_recompilation) Unblock();
+  if (!job_based_recompilation_) {
+    input_queue_semaphore_.Signal();
+    stop_semaphore_.Wait();
+  } else {
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE));
+  }
+  FlushOutputQueue(true);
+  if (FLAG_concurrent_osr) FlushOsrBuffer(true);
+  if (tracing_enabled_) {
+    PrintF("  ** Flushed concurrent recompilation queues.\n");
+  }
+}
+
+
+void OptimizingCompilerThread::Stop() {
+  DCHECK(!IsOptimizerThread());
+  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP));
+  if (FLAG_block_concurrent_recompilation) Unblock();
+  if (!job_based_recompilation_) {
+    input_queue_semaphore_.Signal();
+    stop_semaphore_.Wait();
+  } else {
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE));
+  }
+
+  if (recompilation_delay_ != 0) {
+    // At this point the optimizing compiler thread's event loop has stopped.
+    // There is no need for a mutex when reading input_queue_length_.
+    while (input_queue_length_ > 0) CompileNext(NextInput());
+    InstallOptimizedFunctions();
+  } else {
+    FlushInputQueue(false);
+    FlushOutputQueue(false);
+  }
+
+  if (FLAG_concurrent_osr) FlushOsrBuffer(false);
+
+  if (tracing_enabled_) {
+    double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
+    if (job_based_recompilation_) percentage = 100.0;
+    PrintF("  ** Compiler thread did %.2f%% useful work\n", percentage);
+  }
+
+  if ((FLAG_trace_osr || tracing_enabled_) && FLAG_concurrent_osr) {
+    PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
+  }
+
+  Join();
+}
+
+
+void OptimizingCompilerThread::InstallOptimizedFunctions() {
+  DCHECK(!IsOptimizerThread());
+  HandleScope handle_scope(isolate_);
+
+  OptimizedCompileJob* job;
+  while (output_queue_.Dequeue(&job)) {
+    CompilationInfo* info = job->info();
+    Handle<JSFunction> function(*info->closure());
+    if (info->is_osr()) {
+      if (FLAG_trace_osr) {
+        PrintF("[COSR - ");
+        function->ShortPrint();
+        PrintF(" is ready for install and entry at AST id %d]\n",
+               info->osr_ast_id().ToInt());
+      }
+      job->WaitForInstall();
+      // Remove stack check that guards OSR entry on original code.
+      Handle<Code> code = info->unoptimized_code();
+      uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
+      BackEdgeTable::RemoveStackCheck(code, offset);
+    } else {
+      if (function->IsOptimized()) {
+        if (tracing_enabled_) {
+          PrintF("  ** Aborting compilation for ");
+          function->ShortPrint();
+          PrintF(" as it has already been optimized.\n");
+        }
+        DisposeOptimizedCompileJob(job, false);
+      } else {
+        Handle<Code> code = Compiler::GetConcurrentlyOptimizedCode(job);
+        function->ReplaceCode(
+            code.is_null() ? function->shared()->code() : *code);
+      }
+    }
+  }
+}
+
+
+void OptimizingCompilerThread::QueueForOptimization(OptimizedCompileJob* job) {
+  DCHECK(IsQueueAvailable());
+  DCHECK(!IsOptimizerThread());
+  CompilationInfo* info = job->info();
+  if (info->is_osr()) {
+    osr_attempts_++;
+    AddToOsrBuffer(job);
+    // Add job to the front of the input queue.
+    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
+    DCHECK_LT(input_queue_length_, input_queue_capacity_);
+    // Move shift_ back by one.
+    input_queue_shift_ = InputQueueIndex(input_queue_capacity_ - 1);
+    input_queue_[InputQueueIndex(0)] = job;
+    input_queue_length_++;
+  } else {
+    // Add job to the back of the input queue.
+    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
+    DCHECK_LT(input_queue_length_, input_queue_capacity_);
+    input_queue_[InputQueueIndex(input_queue_length_)] = job;
+    input_queue_length_++;
+  }
+  if (FLAG_block_concurrent_recompilation) {
+    blocked_jobs_++;
+  } else if (job_based_recompilation_) {
+    V8::GetCurrentPlatform()->CallOnBackgroundThread(
+        new CompileTask(isolate_), v8::Platform::kShortRunningTask);
+  } else {
+    input_queue_semaphore_.Signal();
+  }
+}
+
+
+void OptimizingCompilerThread::Unblock() {
+  DCHECK(!IsOptimizerThread());
+  while (blocked_jobs_ > 0) {
+    if (job_based_recompilation_) {
+      V8::GetCurrentPlatform()->CallOnBackgroundThread(
+          new CompileTask(isolate_), v8::Platform::kShortRunningTask);
+    } else {
+      input_queue_semaphore_.Signal();
+    }
+    blocked_jobs_--;
+  }
+}
+
+
+OptimizedCompileJob* OptimizingCompilerThread::FindReadyOSRCandidate(
+    Handle<JSFunction> function, BailoutId osr_ast_id) {
+  DCHECK(!IsOptimizerThread());
+  for (int i = 0; i < osr_buffer_capacity_; i++) {
+    OptimizedCompileJob* current = osr_buffer_[i];
+    if (current != NULL &&
+        current->IsWaitingForInstall() &&
+        current->info()->HasSameOsrEntry(function, osr_ast_id)) {
+      osr_hits_++;
+      osr_buffer_[i] = NULL;
+      return current;
+    }
+  }
+  return NULL;
+}
+
+
+bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function,
+                                              BailoutId osr_ast_id) {
+  DCHECK(!IsOptimizerThread());
+  for (int i = 0; i < osr_buffer_capacity_; i++) {
+    OptimizedCompileJob* current = osr_buffer_[i];
+    if (current != NULL &&
+        current->info()->HasSameOsrEntry(function, osr_ast_id)) {
+      return !current->IsWaitingForInstall();
+    }
+  }
+  return false;
+}
+
+
+bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) {
+  DCHECK(!IsOptimizerThread());
+  for (int i = 0; i < osr_buffer_capacity_; i++) {
+    OptimizedCompileJob* current = osr_buffer_[i];
+    if (current != NULL && *current->info()->closure() == function) {
+      return !current->IsWaitingForInstall();
+    }
+  }
+  return false;
+}
+
+
+void OptimizingCompilerThread::AddToOsrBuffer(OptimizedCompileJob* job) {
+  DCHECK(!IsOptimizerThread());
+  // Find the next slot that is empty or has a stale job.
+  OptimizedCompileJob* stale = NULL;
+  while (true) {
+    stale = osr_buffer_[osr_buffer_cursor_];
+    if (stale == NULL || stale->IsWaitingForInstall()) break;
+    osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
+  }
+
+  // Add to found slot and dispose the evicted job.
+  if (stale != NULL) {
+    DCHECK(stale->IsWaitingForInstall());
+    CompilationInfo* info = stale->info();
+    if (FLAG_trace_osr) {
+      PrintF("[COSR - Discarded ");
+      info->closure()->PrintName();
+      PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
+    }
+    DisposeOptimizedCompileJob(stale, false);
+  }
+  osr_buffer_[osr_buffer_cursor_] = job;
+  osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
+}
+
+
+#ifdef DEBUG
+bool OptimizingCompilerThread::IsOptimizerThread(Isolate* isolate) {
+  return isolate->concurrent_recompilation_enabled() &&
+         isolate->optimizing_compiler_thread()->IsOptimizerThread();
+}
+
+
+bool OptimizingCompilerThread::IsOptimizerThread() {
+  base::LockGuard<base::Mutex> lock_guard(&thread_id_mutex_);
+  return ThreadId::Current().ToInteger() == thread_id_;
+}
+#endif
+
+
+} }  // namespace v8::internal
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
new file mode 100644 (file)
index 0000000..7d60d9b
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_OPTIMIZING_COMPILER_THREAD_H_
+#define V8_OPTIMIZING_COMPILER_THREAD_H_
+
+#include "src/base/atomicops.h"
+#include "src/base/platform/condition-variable.h"
+#include "src/base/platform/mutex.h"
+#include "src/base/platform/platform.h"
+#include "src/base/platform/time.h"
+#include "src/flags.h"
+#include "src/list.h"
+#include "src/unbound-queue-inl.h"
+
+namespace v8 {
+namespace internal {
+
+class HOptimizedGraphBuilder;
+class OptimizedCompileJob;
+class SharedFunctionInfo;
+
+class OptimizingCompilerThread : public base::Thread {
+ public:
+  explicit OptimizingCompilerThread(Isolate* isolate)
+      : Thread(Options("OptimizingCompilerThread")),
+#ifdef DEBUG
+        thread_id_(0),
+#endif
+        isolate_(isolate),
+        stop_semaphore_(0),
+        input_queue_semaphore_(0),
+        input_queue_capacity_(FLAG_concurrent_recompilation_queue_length),
+        input_queue_length_(0),
+        input_queue_shift_(0),
+        osr_buffer_capacity_(FLAG_concurrent_recompilation_queue_length + 4),
+        osr_buffer_cursor_(0),
+        osr_hits_(0),
+        osr_attempts_(0),
+        blocked_jobs_(0),
+        ref_count_(0),
+        tracing_enabled_(FLAG_trace_concurrent_recompilation),
+        job_based_recompilation_(FLAG_job_based_recompilation),
+        recompilation_delay_(FLAG_concurrent_recompilation_delay) {
+    base::NoBarrier_Store(&stop_thread_,
+                          static_cast<base::AtomicWord>(CONTINUE));
+    input_queue_ = NewArray<OptimizedCompileJob*>(input_queue_capacity_);
+    if (FLAG_concurrent_osr) {
+      // Allocate and mark OSR buffer slots as empty.
+      osr_buffer_ = NewArray<OptimizedCompileJob*>(osr_buffer_capacity_);
+      for (int i = 0; i < osr_buffer_capacity_; i++) osr_buffer_[i] = NULL;
+    }
+  }
+
+  ~OptimizingCompilerThread();
+
+  void Run();
+  void Stop();
+  void Flush();
+  void QueueForOptimization(OptimizedCompileJob* optimizing_compiler);
+  void Unblock();
+  void InstallOptimizedFunctions();
+  OptimizedCompileJob* FindReadyOSRCandidate(Handle<JSFunction> function,
+                                             BailoutId osr_ast_id);
+  bool IsQueuedForOSR(Handle<JSFunction> function, BailoutId osr_ast_id);
+
+  bool IsQueuedForOSR(JSFunction* function);
+
+  inline bool IsQueueAvailable() {
+    base::LockGuard<base::Mutex> access_input_queue(&input_queue_mutex_);
+    return input_queue_length_ < input_queue_capacity_;
+  }
+
+  inline void AgeBufferedOsrJobs() {
+    // Advance cursor of the cyclic buffer to next empty slot or stale OSR job.
+    // Dispose said OSR job in the latter case.  Calling this on every GC
+    // should make sure that we do not hold onto stale jobs indefinitely.
+    AddToOsrBuffer(NULL);
+  }
+
+  static bool Enabled(int max_available) {
+    return (FLAG_concurrent_recompilation && max_available > 1);
+  }
+
+#ifdef DEBUG
+  static bool IsOptimizerThread(Isolate* isolate);
+  bool IsOptimizerThread();
+#endif
+
+ private:
+  class CompileTask;
+
+  enum StopFlag { CONTINUE, STOP, FLUSH };
+
+  void FlushInputQueue(bool restore_function_code);
+  void FlushOutputQueue(bool restore_function_code);
+  void FlushOsrBuffer(bool restore_function_code);
+  void CompileNext(OptimizedCompileJob* job);
+  OptimizedCompileJob* NextInput(bool check_if_flushing = false);
+
+  // Add a recompilation task for OSR to the cyclic buffer, awaiting OSR entry.
+  // Tasks evicted from the cyclic buffer are discarded.
+  void AddToOsrBuffer(OptimizedCompileJob* compiler);
+
+  inline int InputQueueIndex(int i) {
+    int result = (i + input_queue_shift_) % input_queue_capacity_;
+    DCHECK_LE(0, result);
+    DCHECK_LT(result, input_queue_capacity_);
+    return result;
+  }
+
+#ifdef DEBUG
+  int thread_id_;
+  base::Mutex thread_id_mutex_;
+#endif
+
+  Isolate* isolate_;
+  base::Semaphore stop_semaphore_;
+  base::Semaphore input_queue_semaphore_;
+
+  // Circular queue of incoming recompilation tasks (including OSR).
+  OptimizedCompileJob** input_queue_;
+  int input_queue_capacity_;
+  int input_queue_length_;
+  int input_queue_shift_;
+  base::Mutex input_queue_mutex_;
+
+  // Queue of recompilation tasks ready to be installed (excluding OSR).
+  UnboundQueue<OptimizedCompileJob*> output_queue_;
+  // Used for job based recompilation which has multiple producers on
+  // different threads.
+  base::Mutex output_queue_mutex_;
+
+  // Cyclic buffer of recompilation tasks for OSR.
+  OptimizedCompileJob** osr_buffer_;
+  int osr_buffer_capacity_;
+  int osr_buffer_cursor_;
+
+  volatile base::AtomicWord stop_thread_;
+  base::TimeDelta time_spent_compiling_;
+  base::TimeDelta time_spent_total_;
+
+  int osr_hits_;
+  int osr_attempts_;
+
+  int blocked_jobs_;
+
+  int ref_count_;
+  base::Mutex ref_count_mutex_;
+  base::ConditionVariable ref_count_zero_;
+
+  // Copies of FLAG_trace_concurrent_recompilation,
+  // FLAG_concurrent_recompilation_delay and
+  // FLAG_job_based_recompilation that will be used from the background thread.
+  //
+  // Since flags might get modified while the background thread is running, it
+  // is not safe to access them directly.
+  bool tracing_enabled_;
+  bool job_based_recompilation_;
+  int recompilation_delay_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_OPTIMIZING_COMPILER_THREAD_H_
index 16175803f05a76d91b2ccdb9515b2ba0c39d26f3..d8512fdfb540b546badd2fe7e72303fd629ce27f 100644 (file)
@@ -232,9 +232,8 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
     // Gate the OSR entry with a stack check.
     BackEdgeTable::AddStackCheck(caller_code, pc_offset);
     // Poll already queued compilation jobs.
-    OptimizingCompileDispatcher* dispatcher =
-        isolate->optimizing_compile_dispatcher();
-    if (dispatcher->IsQueuedForOSR(function, ast_id)) {
+    OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
+    if (thread->IsQueuedForOSR(function, ast_id)) {
       if (FLAG_trace_osr) {
         PrintF("[OSR - Still waiting for queued: ");
         function->PrintName();
@@ -243,7 +242,7 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
       return NULL;
     }
 
-    job = dispatcher->FindReadyOSRCandidate(function, ast_id);
+    job = thread->FindReadyOSRCandidate(function, ast_id);
   }
 
   if (job != NULL) {
@@ -325,7 +324,7 @@ RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
     return isolate->StackOverflow();
   }
 
-  isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
+  isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
   return (function->IsOptimized()) ? function->code()
                                    : function->shared()->code();
 }
index 9a59d9c436c0ea4b6e011c99e958c683caf42847..6a812da8227e91b9e648e34703baee0c5ae166ff 100644 (file)
@@ -175,7 +175,7 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
   if (isolate->concurrent_recompilation_enabled() &&
       sync_with_compiler_thread) {
     while (function->IsInOptimizationQueue()) {
-      isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
+      isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
       base::OS::Sleep(50);
     }
   }
@@ -200,7 +200,7 @@ RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
   DCHECK(args.length() == 0);
   RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
   RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
-  isolate->optimizing_compile_dispatcher()->Unblock();
+  isolate->optimizing_compiler_thread()->Unblock();
   return isolate->heap()->undefined_value();
 }
 
index c3a1c611d69fc280e53ec940863bd9562453d201..31890fa713137e216dfb61edfb7c84bea259d7fe 100644 (file)
         '../../src/objects-printer.cc',
         '../../src/objects.cc',
         '../../src/objects.h',
-        '../../src/optimizing-compile-dispatcher.cc',
-        '../../src/optimizing-compile-dispatcher.h',
+        '../../src/optimizing-compiler-thread.cc',
+        '../../src/optimizing-compiler-thread.h',
         '../../src/ostreams.cc',
         '../../src/ostreams.h',
         '../../src/parser.cc',