Parallel recompilation: fix concurrency issues.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Mar 2013 16:35:32 +0000 (16:35 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Mar 2013 16:35:32 +0000 (16:35 +0000)
BUG=

Review URL: https://chromiumcodereview.appspot.com/12831003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13949 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler.cc
src/optimizing-compiler-thread.cc
src/runtime.cc

index 47ae439..e51fb42 100644 (file)
@@ -946,7 +946,6 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
           // Do a scavenge to put off the next scavenge as far as possible.
           // This may ease the issue that GVN blocks the next scavenge.
           isolate->heap()->CollectGarbage(NEW_SPACE, "parallel recompile");
-          closure->MarkInRecompileQueue();
           shared->code()->set_profiler_ticks(0);
           info.Detach();
           isolate->optimizing_compiler_thread()->QueueForOptimization(compiler);
@@ -978,12 +977,17 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
 
 void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
   SmartPointer<CompilationInfo> info(optimizing_compiler->info());
-  ASSERT(info->closure()->IsMarkedForInstallingRecompiledCode());
-  // While waiting for the optimizer thread, OSR may have already done all
-  // the work and disabled optimization of this function for some reason.
+  // The function may have already been optimized by OSR.  Simply continue.
+  // Except when OSR already disabled optimization for some reason.
   if (info->shared_info()->optimization_disabled()) {
     info->SetCode(Handle<Code>(info->shared_info()->code()));
     InstallFullCode(*info);
+    if (FLAG_trace_parallel_recompilation) {
+      PrintF("  ** aborting optimization for ");
+      info->closure()->PrintName();
+      PrintF(" as it has been disabled.\n");
+    }
+    ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
     return;
   }
 
@@ -1025,6 +1029,7 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
   // Optimized code is finally replacing unoptimized code.  Reset the latter's
   // profiler ticks to prevent too soon re-opt after a deopt.
   info->shared_info()->code()->set_profiler_ticks(0);
+  ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
 }
 
 
index 7952fca..b982b94 100644 (file)
@@ -80,24 +80,16 @@ void OptimizingCompilerThread::CompileNext() {
   input_queue_.Dequeue(&optimizing_compiler);
   Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1));
 
-  ASSERT(optimizing_compiler->info()->closure()->IsInRecompileQueue());
-
+  // The function may have already been optimized by OSR.  Simply continue.
   OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph();
+  USE(status);   // Prevent an unused-variable error in release mode.
   ASSERT(status != OptimizingCompiler::FAILED);
-  // Prevent an unused-variable error in release mode.
-  USE(status);
-
-  output_queue_.Enqueue(optimizing_compiler);
 
-  // The execution thread can call InstallOptimizedFunctions() at any time,
-  // including at this point, after queuing for install and before marking
-  // for install.  To avoid race condition, functions that are queued but not
-  // yet marked for install are not processed by InstallOptimizedFunctions().
-
-  ASSERT(optimizing_compiler->info()->closure()->IsInRecompileQueue());
-  // Mark function to generate and install optimized code.  We assume this
-  // write to be atomic.
+  // The function may have already been optimized by OSR.  Simply continue.
+  // Mark it for installing before queuing so that we can be sure of the write
+  // order: marking first and (after being queued) installing code second.
   optimizing_compiler->info()->closure()->MarkForInstallingRecompiledCode();
+  output_queue_.Enqueue(optimizing_compiler);
 }
 
 
@@ -108,10 +100,6 @@ void OptimizingCompilerThread::Stop() {
   stop_semaphore_->Wait();
 
   if (FLAG_parallel_recompilation_delay != 0) {
-    // Execution ended before we managed to compile and install the remaining
-    // functions in the queue.  We still want to do that for debugging though.
-    // At this point the optimizing thread already stopped, so we finish
-    // processing the queue in the main thread.
     InstallOptimizedFunctions();
     // Barrier when loading queue length is not necessary since the write
     // happens in CompileNext on the same thread.
@@ -135,23 +123,9 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() {
   HandleScope handle_scope(isolate_);
   int functions_installed = 0;
   while (!output_queue_.IsEmpty()) {
-    OptimizingCompiler* compiler = *output_queue_.Peek();
-
-    if (compiler->info()->closure()->IsInRecompileQueue()) {
-      // A function may be queued for install, but not marked as such yet.
-      // We continue with the output queue the next to avoid race condition.
-      break;
-    }
+    OptimizingCompiler* compiler;
     output_queue_.Dequeue(&compiler);
-
-#ifdef DEBUG
-    // Create new closure handle since the deferred handle is about to die.
-    Handle<JSFunction> closure(*compiler->info()->closure());
-#endif  // DEBUG
-
     Compiler::InstallOptimizedCode(compiler);
-    // Assert that the marker builtin has been replaced by actual code.
-    ASSERT(!closure->IsInRecompileQueue());
     functions_installed++;
   }
 }
@@ -162,6 +136,7 @@ void OptimizingCompilerThread::QueueForOptimization(
   ASSERT(IsQueueAvailable());
   ASSERT(!IsOptimizerThread());
   Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
+  optimizing_compiler->info()->closure()->MarkInRecompileQueue();
   input_queue_.Enqueue(optimizing_compiler);
   input_queue_semaphore_->Signal();
 }
index 6c2664b..12777e7 100644 (file)
@@ -7729,7 +7729,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) {
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
   if (!AllowOptimization(isolate, function)) {
     function->ReplaceCode(function->shared()->code());
-    return function->code();
+    return isolate->heap()->undefined_value();
   }
   function->shared()->code()->set_profiler_ticks(0);
   ASSERT(FLAG_parallel_recompilation);
@@ -7742,10 +7742,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) {
   HandleScope handle_scope(isolate);
   ASSERT(args.length() == 1);
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  if (!V8::UseCrankshaft()) return isolate->heap()->undefined_value();
-  ASSERT(FLAG_parallel_recompilation);
+  ASSERT(V8::UseCrankshaft() && FLAG_parallel_recompilation);
   OptimizingCompilerThread* opt_thread = isolate->optimizing_compiler_thread();
-  opt_thread->InstallOptimizedFunctions();
+  do {
+    // The function could have been marked for installing, but not queued just
+    // yet.  In this case, retry until installed.
+    opt_thread->InstallOptimizedFunctions();
+  } while (function->IsMarkedForInstallingRecompiledCode());
   return function->code();
 }