Reland "Remove support for thread-based recompilation"
authorjochen <jochen@chromium.org>
Tue, 14 Apr 2015 13:57:35 +0000 (06:57 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Apr 2015 13:57:29 +0000 (13:57 +0000)
Original issue's description:
> Remove support for thread-based recompilation
>
> BUG=v8:3608
> R=yangguo@chromium.org
> LOG=y
>
> Committed: https://crrev.com/ed5db223a19dfe126af01
> Cr-Commit-Position: refs/heads/master@{#27619}

BUG=v8:3608
R=yangguo@chromium.org
LOG=y

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

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

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 [new file with mode: 0644]
src/optimizing-compile-dispatcher.h [new file with mode: 0644]
src/optimizing-compiler-thread.cc [deleted file]
src/optimizing-compiler-thread.h [deleted file]
src/runtime/runtime-compiler.cc
src/runtime/runtime-test.cc
tools/gyp/v8.gyp

index 4d0e3385557c3c8f8c74025cb08c6013f029ae88..3eebcfe8ceb49252a070acb4228c7e92c9eeeb27 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-compiler-thread.cc",
-    "src/optimizing-compiler-thread.h",
+    "src/optimizing-compile-dispatcher.cc",
+    "src/optimizing-compile-dispatcher.h",
     "src/ostreams.cc",
     "src/ostreams.h",
     "src/parser.cc",
index f2a3a3243f10f2a23fcfa97c51f048f978cd44a8..4553f2e1075b86c4de3a0717222306949323015b 100644 (file)
@@ -820,7 +820,7 @@ static bool GetOptimizedCodeNow(CompilationInfo* info) {
 
 static bool GetOptimizedCodeLater(CompilationInfo* info) {
   Isolate* isolate = info->isolate();
-  if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
+  if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
     if (FLAG_trace_concurrent_recompilation) {
       PrintF("  ** Compilation queue full, will retry optimizing ");
       info->closure()->ShortPrint();
@@ -841,7 +841,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_compiler_thread()->QueueForOptimization(job);
+  isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
 
   if (FLAG_trace_concurrent_recompilation) {
     PrintF("  ** Queued ");
index fb91a9e2f5e1383927814c4c0b1e1273417d2934..f9acb66c089b38d86bb1f15e753edb03a4a98fdc 100644 (file)
@@ -372,12 +372,10 @@ 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 26ec7f900a4cc120996ca12b9edcd6bc4083f550..7d8669bf61f3778d340d8ee3ecb7397e69c50bda 100644 (file)
@@ -11,7 +11,7 @@
 #include "src/circular-queue.h"
 #include "src/compiler.h"
 #include "src/sampler.h"
-#include "src/unbound-queue.h"
+#include "src/unbound-queue-inl.h"
 
 namespace v8 {
 namespace internal {
index 854b507c47339fd21a9d61eb58ed6ebf3e32f4b5..25407a746fc5a61b6e58e7e2fd1367427bb160f3 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_compiler_thread()->Flush();
+      isolate_->optimizing_compile_dispatcher()->Flush();
     }
 
     Deoptimizer::DeoptimizeAll(isolate_);
index 7ae67410e45790653c33d8f578abf79f8c38ec18..e281bac5fa25e778bc0e9ddecd60565af3d2d796 100644 (file)
@@ -677,7 +677,7 @@ Object* StackGuard::HandleInterrupts() {
 
   if (CheckAndClearInterrupt(INSTALL_CODE)) {
     DCHECK(isolate_->concurrent_recompilation_enabled());
-    isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
+    isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
   }
 
   if (CheckAndClearInterrupt(API_INTERRUPT)) {
index e48dd9f788507f08861d91aef2c04217106feb47..def2dec73ef6bd637bdf781df9f4a3f729cefce9 100644 (file)
@@ -364,9 +364,6 @@ 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 9aef842684ed248f5544121b02aa1566a998078e..797d1e0683cc0f324231f78a2f7600c61f49d1f0 100644 (file)
@@ -430,7 +430,7 @@ void Heap::GarbageCollectionPrologue() {
   store_buffer()->GCPrologue();
 
   if (isolate()->concurrent_osr_enabled()) {
-    isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs();
+    isolate()->optimizing_compile_dispatcher()->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_compiler_thread()->Flush();
+    isolate()->optimizing_compile_dispatcher()->Flush();
   }
   isolate()->ClearSerializerData();
   mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
@@ -889,7 +889,7 @@ int Heap::NotifyContextDisposed(bool dependant_context) {
   }
   if (isolate()->concurrent_recompilation_enabled()) {
     // Flush the queued recompilation tasks.
-    isolate()->optimizing_compiler_thread()->Flush();
+    isolate()->optimizing_compile_dispatcher()->Flush();
   }
   AgeInlineCaches();
   set_retained_maps(ArrayList::cast(empty_fixed_array()));
index 7649dae047dc43dbb6a7dfff333c021182cb7883..0ea1bd59bd42890451fd6de40e34dbe43335e9c9 100644 (file)
@@ -3475,7 +3475,6 @@ 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 927972d8225dcd0b2fcfdd7fec1493bcfa897a89..9a9403a79f660441347df4f2349e2bfa59827551 100644 (file)
@@ -1736,7 +1736,7 @@ Isolate::Isolate(bool enable_serializer)
       heap_profiler_(NULL),
       function_entry_hook_(NULL),
       deferred_handles_head_(NULL),
-      optimizing_compiler_thread_(NULL),
+      optimizing_compile_dispatcher_(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_compiler_thread_->Stop();
-    delete optimizing_compiler_thread_;
-    optimizing_compiler_thread_ = NULL;
+    optimizing_compile_dispatcher_->Stop();
+    delete optimizing_compile_dispatcher_;
+    optimizing_compile_dispatcher_ = NULL;
   }
 
   if (heap_.mark_compact_collector()->sweeping_in_progress()) {
@@ -2133,9 +2133,8 @@ bool Isolate::Init(Deserializer* des) {
 
   if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) {
     PrintF("Concurrent recompilation has been disabled for tracing.\n");
-  } else if (OptimizingCompilerThread::Enabled(max_available_threads_)) {
-    optimizing_compiler_thread_ = new OptimizingCompilerThread(this);
-    optimizing_compiler_thread_->Start();
+  } else if (OptimizingCompileDispatcher::Enabled(max_available_threads_)) {
+    optimizing_compile_dispatcher_ = new OptimizingCompileDispatcher(this);
   }
 
   // Initialize runtime profiler before deserialization, because collections may
index e8576f5940d599b30617984b46342c1cffbc1dc7..85d25ed93e782894abb701a9b6f2bd367c07ee01 100644 (file)
@@ -19,7 +19,7 @@
 #include "src/handles.h"
 #include "src/hashmap.h"
 #include "src/heap/heap.h"
-#include "src/optimizing-compiler-thread.h"
+#include "src/optimizing-compile-dispatcher.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_compiler_thread_ == NULL ||
+    DCHECK(optimizing_compile_dispatcher_ == NULL ||
            FLAG_concurrent_recompilation);
-    return optimizing_compiler_thread_ != NULL;
+    return optimizing_compile_dispatcher_ != NULL;
   }
 
   bool concurrent_osr_enabled() const {
     // Thread is only available with flag enabled.
-    DCHECK(optimizing_compiler_thread_ == NULL ||
+    DCHECK(optimizing_compile_dispatcher_ == NULL ||
            FLAG_concurrent_recompilation);
-    return optimizing_compiler_thread_ != NULL && FLAG_concurrent_osr;
+    return optimizing_compile_dispatcher_ != NULL && FLAG_concurrent_osr;
   }
 
-  OptimizingCompilerThread* optimizing_compiler_thread() {
-    return optimizing_compiler_thread_;
+  OptimizingCompileDispatcher* optimizing_compile_dispatcher() {
+    return optimizing_compile_dispatcher_;
   }
 
   int id() const { return static_cast<int>(id_); }
@@ -1329,7 +1329,7 @@ class Isolate {
 #endif
 
   DeferredHandles* deferred_handles_head_;
-  OptimizingCompilerThread* optimizing_compiler_thread_;
+  OptimizingCompileDispatcher* optimizing_compile_dispatcher_;
 
   // 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 OptimizingCompilerThread;
+  friend class OptimizingCompileDispatcher;
   friend class SweeperThread;
   friend class ThreadManager;
   friend class Simulator;
index 20d7f9029b29e98bd7f5c21674087287be8f8216..bb10a9b1c203b08793c58c5a0c2c936c0a8b9599 100644 (file)
@@ -9708,7 +9708,7 @@ void JSFunction::AttemptConcurrentOptimization() {
     return;
   }
   if (isolate->concurrent_osr_enabled() &&
-      isolate->optimizing_compiler_thread()->IsQueuedForOSR(this)) {
+      isolate->optimizing_compile_dispatcher()->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
new file mode 100644 (file)
index 0000000..e422913
--- /dev/null
@@ -0,0 +1,359 @@
+// 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) {
+  for (;;) {
+    OptimizedCompileJob* job = NULL;
+    {
+      base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
+      if (output_queue_.empty()) return;
+      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_);
+
+  for (;;) {
+    OptimizedCompileJob* job = NULL;
+    {
+      base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
+      if (output_queue_.empty()) return;
+      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
new file mode 100644 (file)
index 0000000..822bb40
--- /dev/null
@@ -0,0 +1,139 @@
+// 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
deleted file mode 100644 (file)
index eda4f5c..0000000
+++ /dev/null
@@ -1,463 +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-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
deleted file mode 100644 (file)
index 7d60d9b..0000000
+++ /dev/null
@@ -1,166 +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_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 d8512fdfb540b546badd2fe7e72303fd629ce27f..16175803f05a76d91b2ccdb9515b2ba0c39d26f3 100644 (file)
@@ -232,8 +232,9 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
     // Gate the OSR entry with a stack check.
     BackEdgeTable::AddStackCheck(caller_code, pc_offset);
     // Poll already queued compilation jobs.
-    OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
-    if (thread->IsQueuedForOSR(function, ast_id)) {
+    OptimizingCompileDispatcher* dispatcher =
+        isolate->optimizing_compile_dispatcher();
+    if (dispatcher->IsQueuedForOSR(function, ast_id)) {
       if (FLAG_trace_osr) {
         PrintF("[OSR - Still waiting for queued: ");
         function->PrintName();
@@ -242,7 +243,7 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
       return NULL;
     }
 
-    job = thread->FindReadyOSRCandidate(function, ast_id);
+    job = dispatcher->FindReadyOSRCandidate(function, ast_id);
   }
 
   if (job != NULL) {
@@ -324,7 +325,7 @@ RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
     return isolate->StackOverflow();
   }
 
-  isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+  isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
   return (function->IsOptimized()) ? function->code()
                                    : function->shared()->code();
 }
index 6a812da8227e91b9e648e34703baee0c5ae166ff..9a59d9c436c0ea4b6e011c99e958c683caf42847 100644 (file)
@@ -175,7 +175,7 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
   if (isolate->concurrent_recompilation_enabled() &&
       sync_with_compiler_thread) {
     while (function->IsInOptimizationQueue()) {
-      isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+      isolate->optimizing_compile_dispatcher()->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_compiler_thread()->Unblock();
+  isolate->optimizing_compile_dispatcher()->Unblock();
   return isolate->heap()->undefined_value();
 }
 
index 31890fa713137e216dfb61edfb7c84bea259d7fe..c3a1c611d69fc280e53ec940863bd9562453d201 100644 (file)
         '../../src/objects-printer.cc',
         '../../src/objects.cc',
         '../../src/objects.h',
-        '../../src/optimizing-compiler-thread.cc',
-        '../../src/optimizing-compiler-thread.h',
+        '../../src/optimizing-compile-dispatcher.cc',
+        '../../src/optimizing-compile-dispatcher.h',
         '../../src/ostreams.cc',
         '../../src/ostreams.h',
         '../../src/parser.cc',