Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index 1fba20fa5b923790d9ac720a69f68f2da952157c..3ec2f5bf80b1981aca56cabaf542d06e229b1839 100644 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -58,7 +58,8 @@ CompilationInfo::CompilationInfo(Handle<Script> script, |
Zone* zone) |
: flags_(LanguageModeField::encode(CLASSIC_MODE)), |
script_(script), |
- osr_ast_id_(BailoutId::None()) { |
+ osr_ast_id_(BailoutId::None()), |
+ osr_pc_offset_(0) { |
Initialize(script->GetIsolate(), BASE, zone); |
} |
@@ -68,7 +69,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, |
: flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), |
shared_info_(shared_info), |
script_(Handle<Script>(Script::cast(shared_info->script()))), |
- osr_ast_id_(BailoutId::None()) { |
+ osr_ast_id_(BailoutId::None()), |
+ osr_pc_offset_(0) { |
Initialize(script_->GetIsolate(), BASE, zone); |
} |
@@ -80,7 +82,8 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure, |
shared_info_(Handle<SharedFunctionInfo>(closure->shared())), |
script_(Handle<Script>(Script::cast(shared_info_->script()))), |
context_(closure->context()), |
- osr_ast_id_(BailoutId::None()) { |
+ osr_ast_id_(BailoutId::None()), |
+ osr_pc_offset_(0) { |
Initialize(script_->GetIsolate(), BASE, zone); |
} |
@@ -90,7 +93,8 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub, |
Zone* zone) |
: flags_(LanguageModeField::encode(CLASSIC_MODE) | |
IsLazy::encode(true)), |
- osr_ast_id_(BailoutId::None()) { |
+ osr_ast_id_(BailoutId::None()), |
+ osr_pc_offset_(0) { |
Initialize(isolate, STUB, zone); |
code_stub_ = stub; |
} |
@@ -963,8 +967,9 @@ bool Compiler::CompileLazy(CompilationInfo* info) { |
} |
-void Compiler::RecompileConcurrent(Handle<JSFunction> closure) { |
- ASSERT(closure->IsMarkedForConcurrentRecompilation()); |
+void Compiler::RecompileConcurrent(Handle<JSFunction> closure, |
+ uint32_t osr_pc_offset) { |
+ ASSERT(osr_pc_offset != 0 || closure->IsMarkedForConcurrentRecompilation()); |
titzer
2013/09/03 14:05:36
Not sure what you are trying to assert here.
Yang
2013/09/03 14:49:44
Asserting that if we are not recompiling for OSR,
|
Isolate* isolate = closure->GetIsolate(); |
// Here we prepare compile data for the concurrent recompilation thread, but |
@@ -982,13 +987,31 @@ void Compiler::RecompileConcurrent(Handle<JSFunction> closure) { |
} |
SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure)); |
+ Handle<SharedFunctionInfo> shared = info->shared_info(); |
+ |
+ if (osr_pc_offset != 0) { |
+ int loop_depth; |
+ BailoutId osr_ast_id = shared->code()->TranslatePcOffsetToAstId( |
titzer
2013/09/03 14:05:36
Are you calling this method in another place? Othe
Yang
2013/09/03 14:49:44
Done.
|
+ osr_pc_offset, &loop_depth); |
+ ASSERT(!osr_ast_id.IsNone()); |
+ info->SetOptimizing(osr_ast_id); |
+ info->set_osr_pc_offset(osr_pc_offset); |
+ |
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - attempt to queue "); |
+ closure->PrintName(); |
+ PrintF(" for concurrent compilation at AST id %d, loop depth %d]\n", |
+ osr_ast_id.ToInt(), loop_depth); |
+ } |
+ } else { |
+ info->SetOptimizing(BailoutId::None()); |
+ } |
+ |
VMState<COMPILER> state(isolate); |
PostponeInterruptsScope postpone(isolate); |
- Handle<SharedFunctionInfo> shared = info->shared_info(); |
int compiled_size = shared->end_position() - shared->start_position(); |
isolate->counters()->total_compile_size()->Increment(compiled_size); |
- info->SetOptimizing(BailoutId::None()); |
{ |
CompilationHandleScope handle_scope(*info); |
@@ -1019,11 +1042,10 @@ void Compiler::RecompileConcurrent(Handle<JSFunction> closure) { |
} |
} |
- if (shared->code()->back_edges_patched_for_osr()) { |
- // At this point we either put the function on recompilation queue or |
- // aborted optimization. In either case we want to continue executing |
- // the unoptimized code without running into OSR. If the unoptimized |
- // code has been patched for OSR, unpatch it. |
+ // If we don't compile for on-stack replacement in the background thread, |
+ // reset the OSR attempt to avoid recompilation being preempted by OSR. |
+ if (!FLAG_speculative_concurrent_osr && |
+ shared->code()->back_edges_patched_for_osr()) { |
Deoptimizer::RevertInterruptCode(isolate, shared->code()); |
} |
@@ -1094,6 +1116,170 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) { |
} |
+static uint32_t CurrentPcOffset(Isolate* isolate, |
+ Handle<JSFunction> function, |
+ Handle<Code> unoptimized) { |
titzer
2013/09/03 14:05:36
Please put the mechanism for finding the osr_pc_of
Yang
2013/09/03 14:49:44
I got a CL in queue that removes this completely.
|
+ JavaScriptFrameIterator it(isolate); |
+ JavaScriptFrame* frame = it.frame(); |
+ ASSERT(frame->function() == *function); |
+ ASSERT(frame->LookupCode() == *unoptimized); |
+ ASSERT(unoptimized->contains(frame->pc())); |
+ |
+ // Use linear search of the unoptimized code's back edge table to find |
+ // the AST id matching the PC. |
+ return static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start()); |
+} |
+ |
+ |
+static bool IsSuitableForOnStackReplacement(Isolate* isolate, |
+ Handle<JSFunction> function, |
+ Handle<Code> unoptimized) { |
+ // Keep track of whether we've succeeded in optimizing. |
+ if (!unoptimized->optimizable()) return false; |
+ // If we are trying to do OSR when there are already optimized |
+ // activations of the function, it means (a) the function is directly or |
+ // indirectly recursive and (b) an optimized invocation has been |
+ // deoptimized so that we are currently in an unoptimized activation. |
+ // Check for optimized activations of this function. |
+ for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { |
+ JavaScriptFrame* frame = it.frame(); |
+ if (frame->is_optimized() && frame->function() == *function) return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+ |
+bool Compiler::CompileForOnStackReplacement(Handle<JSFunction> function, |
+ BailoutId* ast_id) { |
titzer
2013/09/03 14:05:36
This should take the osr_pc_offset as a parameter.
Yang
2013/09/03 14:49:44
Ditto. CL queued up doing exactly that.
|
+ Isolate* isolate = function->GetIsolate(); |
+ // We have hit a back edge in an unoptimized frame for a function that was |
+ // selected for on-stack replacement. Find the unoptimized code object. |
+ Handle<Code> unoptimized(function->shared()->code(), isolate); |
+ |
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized); |
+ if (FLAG_trace_osr) { |
+ PrintF("[OSR - restored original interrupt calls in "); |
+ function->PrintName(); |
+ PrintF("]\n"); |
+ } |
+ |
+ if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) { |
+ return false; |
+ } |
+ |
+ uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized); |
+ |
+ int loop_depth; |
+ *ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset, &loop_depth); |
titzer
2013/09/03 14:05:36
If you move this code back to the runtime, you don
Yang
2013/09/03 14:49:44
I changed this so that we return the AST id direct
|
+ ASSERT(!ast_id->IsNone()); |
+ if (FLAG_trace_osr) { |
+ PrintF("[OSR - replacing at AST id %d, loop depth %d in ", |
+ ast_id->ToInt(), loop_depth); |
+ function->PrintName(); |
+ PrintF("]\n"); |
+ } |
+ |
+ // Try to compile the optimized code. A true return value from |
+ // CompileOptimized means that compilation succeeded, not necessarily |
+ // that optimization succeeded. |
+ if (JSFunction::CompileOptimized(function, *ast_id, CLEAR_EXCEPTION) && |
+ function->IsOptimized()) { |
+ DeoptimizationInputData* data = DeoptimizationInputData::cast( |
+ function->code()->deoptimization_data()); |
+ if (data->OsrPcOffset()->value() >= 0) { |
+ if (FLAG_trace_osr) { |
+ PrintF("[OSR - entry, offset %d in optimized code]\n", |
+ data->OsrPcOffset()->value()); |
+ } |
+ ASSERT(BailoutId(data->OsrAstId()->value()) == *ast_id); |
+ return true; |
+ } |
+ } else { |
+ if (FLAG_trace_osr) { |
+ PrintF("[OSR - optimization failed for "); |
+ function->PrintName(); |
+ PrintF("]\n"); |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
+bool Compiler::CompileForConcurrentOSR(Handle<JSFunction> function, |
+ BailoutId* ast_id) { |
+ ASSERT(FLAG_concurrent_recompilation && FLAG_speculative_concurrent_osr); |
+ |
+ Isolate* isolate = function->GetIsolate(); |
+ Handle<Code> unoptimized(function->shared()->code(), isolate); |
+ |
+ uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized); |
+ |
+ if (isolate->optimizing_compiler_thread()-> |
+ IsQueuedForOSR(function, pc_offset)) { |
+ // Still waiting for the optimizing compiler thread to finish. Carry on. |
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - polling recompile tasks for "); |
+ function->PrintName(); |
+ PrintF("]\n"); |
+ } |
+ return false; |
+ } |
+ |
+ OptimizingCompiler* compiler = isolate->optimizing_compiler_thread()-> |
+ FindReadyOSRCandidate(function, pc_offset); |
+ |
+ if (compiler != NULL) { |
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - optimization complete for "); |
+ function->PrintName(); |
+ PrintF(", restoring interrupt calls]\n"); |
+ } |
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized); |
+ |
+ *ast_id = compiler->info()->osr_ast_id(); |
+ |
+ InstallOptimizedCode(compiler); |
+ isolate->optimizing_compiler_thread()->RemoveStaleOSRCandidates(); |
+ |
+ if (!function->IsOptimized()) { |
titzer
2013/09/03 14:05:36
You shouldn't check function->IsOptimized, but loo
Yang
2013/09/03 14:49:44
Done.
|
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - optimization failed for "); |
+ function->PrintName(); |
+ PrintF("]\n"); |
+ } |
+ return false; |
+ } |
+ |
+ DeoptimizationInputData* data = DeoptimizationInputData::cast( |
+ function->code()->deoptimization_data()); |
+ |
+ if (data->OsrPcOffset()->value() >= 0) { |
+ ASSERT(BailoutId(data->OsrAstId()->value()) == *ast_id); |
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - entry at AST id %d, offset %d in optimized code]\n", |
+ ast_id->ToInt(), data->OsrPcOffset()->value()); |
+ } |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) { |
+ if (FLAG_trace_osr) { |
+ PrintF("[COSR - "); |
+ function->PrintName(); |
+ PrintF(" is unsuitable, restoring interrupt calls]\n"); |
+ } |
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized); |
+ return false; |
+ } |
+ |
+ RecompileConcurrent(function, pc_offset); |
+ return false; |
+} |
+ |
+ |
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, |
Handle<Script> script) { |
// Precondition: code has been parsed and scopes have been analyzed. |