Chromium Code Reviews| 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. |