Chromium Code Reviews| Index: src/runtime.cc |
| diff --git a/src/runtime.cc b/src/runtime.cc |
| index e763d435cc985e80a21f0fe43b4e11439c534e6b..f959846c7a34525ea39965f428c9712829d060e3 100644 |
| --- a/src/runtime.cc |
| +++ b/src/runtime.cc |
| @@ -2957,7 +2957,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { |
| Handle<SharedFunctionInfo> target_shared(target->shared()); |
| Handle<SharedFunctionInfo> source_shared(source->shared()); |
| - if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) { |
| + if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) { |
| return Failure::Exception(); |
| } |
| @@ -8265,7 +8265,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { |
| // The function should be compiled for the optimization hints to be |
| // available. |
| - JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION); |
| + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); |
| Handle<SharedFunctionInfo> shared(function->shared(), isolate); |
| if (!function->has_initial_map() && |
| @@ -8297,7 +8297,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { |
| } |
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { |
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileUnoptimized) { |
| HandleScope scope(isolate); |
| ASSERT(args.length() == 1); |
| @@ -8312,27 +8312,35 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { |
| // Compile the target function. |
| ASSERT(!function->is_compiled()); |
|
titzer
2013/12/09 14:49:28
Why?
Yang
2013/12/10 11:22:04
I guess we would guard that this is only called fr
titzer
2013/12/17 15:27:55
In general, I think neither CompileOptimized nor C
Yang
2013/12/17 16:31:33
Added asserts at the end guarding those exit invar
|
| - if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) { |
| - return Failure::Exception(); |
| - } |
| + ASSERT(function->shared()->allows_lazy_compilation()); |
| + |
| + Handle<Code> code = Compiler::GetUnoptimizedCode(function); |
| + RETURN_IF_EMPTY_HANDLE(isolate, code); |
| + function->ReplaceCode(*code); |
| // All done. Return the compiled code. |
| ASSERT(function->is_compiled()); |
| - return function->code(); |
| + return *code; |
| } |
| -bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { |
| - // If the function is not compiled ignore the lazy |
| - // recompilation. This can happen if the debugger is activated and |
| - // the function is returned to the not compiled state. |
| - if (!function->shared()->is_compiled()) return false; |
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileOptimized) { |
| + HandleScope scope(isolate); |
| + ASSERT(args.length() == 2); |
| + Handle<JSFunction> function = args.at<JSFunction>(0); |
| + CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1); |
| - // If the function is not optimizable or debugger is active continue using the |
| - // code from the full compiler. |
| - if (!isolate->use_crankshaft() || |
| - function->shared()->optimization_disabled() || |
| - isolate->DebuggerHasBreakPoints()) { |
| + Handle<Code> unoptimized(function->shared()->code()); |
| + if (!function->shared()->is_compiled()) { |
|
titzer
2013/12/09 14:49:28
I don't think we want this check. IIRC that forces
Yang
2013/12/10 11:22:04
I think that is intentional. I merely inlined Allo
titzer
2013/12/17 15:27:55
Add a TODO. I still think it's an unnecessary rest
Yang
2013/12/17 16:31:33
Done.
|
| + // If the function is not compiled ignore the lazy |
| + // recompilation. This can happen if the debugger is activated and |
| + // the function is returned to the not compiled state. |
| + function->ReplaceCode(function->shared()->code()); |
| + } else if (!isolate->use_crankshaft() || |
| + function->shared()->optimization_disabled() || |
| + isolate->DebuggerHasBreakPoints()) { |
| + // If the function is not optimizable or debugger is active continue |
| + // using the code from the full compiler. |
| if (FLAG_trace_opt) { |
| PrintF("[failed to optimize "); |
| function->PrintName(); |
| @@ -8340,53 +8348,19 @@ bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { |
| function->shared()->optimization_disabled() ? "F" : "T", |
| isolate->DebuggerHasBreakPoints() ? "T" : "F"); |
| } |
| - return false; |
| + function->ReplaceCode(*unoptimized); |
| + } else { |
| + Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT |
| + : Compiler::NOT_CONCURRENT; |
| + Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, mode); |
| + if (code.is_null()) code = isolate->builtins()->InOptimizationQueue(); |
|
titzer
2013/12/09 14:49:28
I totally don't understand this. What if the optim
Yang
2013/12/10 11:22:04
You are right. Currently GetOptimizedCode would re
|
| + function->ReplaceCode(*code); |
| } |
| - return true; |
| -} |
| - |
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { |
| - HandleScope scope(isolate); |
| - ASSERT(args.length() == 1); |
| - Handle<JSFunction> function = args.at<JSFunction>(0); |
| - |
| - if (!AllowOptimization(isolate, function)) { |
| - function->ReplaceCode(function->shared()->code()); |
| - return function->code(); |
| - } |
| - function->shared()->code()->set_profiler_ticks(0); |
| - if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) { |
| - return function->code(); |
| - } |
| - if (FLAG_trace_opt) { |
| - PrintF("[failed to optimize "); |
| - function->PrintName(); |
| - PrintF(": optimized compilation failed]\n"); |
| - } |
| - function->ReplaceCode(function->shared()->code()); |
| return function->code(); |
| } |
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_ConcurrentRecompile) { |
| - HandleScope handle_scope(isolate); |
| - ASSERT(args.length() == 1); |
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| - if (!AllowOptimization(isolate, function)) { |
| - function->ReplaceCode(function->shared()->code()); |
| - return isolate->heap()->undefined_value(); |
| - } |
| - Handle<Code> shared_code(function->shared()->code()); |
| - shared_code->set_profiler_ticks(0); |
| - ASSERT(isolate->concurrent_recompilation_enabled()); |
| - if (!Compiler::RecompileConcurrent(function, shared_code)) { |
| - function->ReplaceCode(*shared_code); |
| - } |
| - return isolate->heap()->undefined_value(); |
| -} |
| - |
| - |
| class ActivationsFinder : public ThreadVisitor { |
| public: |
| Code* code_; |
| @@ -8527,7 +8501,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); |
| - function->MarkForLazyRecompilation(); |
| + function->MarkForCompileOptimized(); |
| Code* unoptimized = function->shared()->code(); |
| if (args.length() == 2 && |
| @@ -8542,7 +8516,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { |
| isolate->runtime_profiler()->AttemptOnStackReplacement(*function); |
| } |
| } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) { |
| - function->MarkForConcurrentRecompilation(); |
| + function->MarkForCompileOptimizedConcurrent(); |
| } |
| } |
| @@ -8576,7 +8550,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| if (isolate->concurrent_recompilation_enabled() && |
| sync_with_compiler_thread) { |
| - while (function->IsInRecompileQueue()) { |
| + while (function->IsInOptimizationQueue()) { |
| isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); |
| OS::Sleep(50); |
| } |
| @@ -8612,9 +8586,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { |
| static bool IsSuitableForOnStackReplacement(Isolate* isolate, |
| Handle<JSFunction> function, |
| - Handle<Code> unoptimized) { |
| + Handle<Code> current_code) { |
| // Keep track of whether we've succeeded in optimizing. |
| - if (!isolate->use_crankshaft() || !unoptimized->optimizable()) return false; |
| + if (!isolate->use_crankshaft() || !current_code->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 |
| @@ -8633,79 +8607,75 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { |
| HandleScope scope(isolate); |
| ASSERT(args.length() == 1); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| - Handle<Code> unoptimized(function->shared()->code(), isolate); |
| + Handle<Code> current_code(function->shared()->code()); |
|
titzer
2013/12/09 14:49:28
Let's call this caller_code?
Yang
2013/12/10 11:22:04
Done.
|
| + |
| + // We're not prepared to handle a function with arguments object. |
| + ASSERT(!function->shared()->uses_arguments()); |
| // Passing the PC in the javascript frame from the caller directly is |
| // not GC safe, so we walk the stack to get it. |
| JavaScriptFrameIterator it(isolate); |
| JavaScriptFrame* frame = it.frame(); |
| - if (!unoptimized->contains(frame->pc())) { |
| + if (!current_code->contains(frame->pc())) { |
| // Code on the stack may not be the code object referenced by the shared |
| // function info. It may have been replaced to include deoptimization data. |
| - unoptimized = Handle<Code>(frame->LookupCode()); |
| + current_code = Handle<Code>(frame->LookupCode()); |
| } |
| - uint32_t pc_offset = static_cast<uint32_t>(frame->pc() - |
| - unoptimized->instruction_start()); |
| + uint32_t pc_offset = static_cast<uint32_t>( |
| + frame->pc() - current_code->instruction_start()); |
| #ifdef DEBUG |
| ASSERT_EQ(frame->function(), *function); |
| - ASSERT_EQ(frame->LookupCode(), *unoptimized); |
| - ASSERT(unoptimized->contains(frame->pc())); |
| + ASSERT_EQ(frame->LookupCode(), *current_code); |
| + ASSERT(current_code->contains(frame->pc())); |
| #endif // DEBUG |
| - // We're not prepared to handle a function with arguments object. |
| - ASSERT(!function->shared()->uses_arguments()); |
| + BailoutId ast_id = current_code->TranslatePcOffsetToAstId(pc_offset); |
| + ASSERT(!ast_id.IsNone()); |
| + |
| + Compiler::ConcurrencyMode mode = isolate->concurrent_osr_enabled() |
| + ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT; |
| Handle<Code> result = Handle<Code>::null(); |
| - BailoutId ast_id = BailoutId::None(); |
| - if (isolate->concurrent_osr_enabled()) { |
| - if (isolate->optimizing_compiler_thread()-> |
| - IsQueuedForOSR(function, pc_offset)) { |
| - // Still waiting for the optimizing compiler thread to finish. Carry on. |
| + if (mode == Compiler::CONCURRENT) { |
| + // Gate the OSR entry with a stack check. |
| + BackEdgeTable::AddStackCheck(*current_code, pc_offset); |
| + // Poll already queued compilation jobs. |
| + OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread(); |
| + if (thread->IsQueuedForOSR(function, ast_id)) { |
| if (FLAG_trace_osr) { |
| - PrintF("[COSR - polling recompile tasks for "); |
| + PrintF("[OSR - Still waiting for queued: "); |
| function->PrintName(); |
| - PrintF("]\n"); |
| + PrintF(" at AST id %d]\n", ast_id.ToInt()); |
| } |
| return NULL; |
| } |
| - RecompileJob* job = isolate->optimizing_compiler_thread()-> |
| - FindReadyOSRCandidate(function, pc_offset); |
| - |
| - if (job == NULL) { |
| - if (IsSuitableForOnStackReplacement(isolate, function, unoptimized) && |
| - Compiler::RecompileConcurrent(function, unoptimized, pc_offset)) { |
| - if (function->IsMarkedForLazyRecompilation() || |
| - function->IsMarkedForConcurrentRecompilation()) { |
| - // Prevent regular recompilation if we queue this for OSR. |
| - // TODO(yangguo): remove this as soon as OSR becomes one-shot. |
| - function->ReplaceCode(function->shared()->code()); |
| - } |
| - return NULL; |
| + RecompileJob* job = thread->FindReadyOSRCandidate(function, ast_id); |
| + if (job != NULL) { |
| + if (FLAG_trace_osr) { |
| + PrintF("[OSR - Found ready: "); |
| + function->PrintName(); |
| + PrintF(" at AST id %d]\n", ast_id.ToInt()); |
| } |
| - // Fall through to the end in case of failure. |
| - } else { |
| - // TODO(titzer): don't install the OSR code into the function. |
| - ast_id = job->info()->osr_ast_id(); |
| - result = Compiler::InstallOptimizedCode(job); |
| + result = Compiler::GetConcurrentlyOptimizedCode(job); |
| } |
| - } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) { |
| - ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset); |
| - ASSERT(!ast_id.IsNone()); |
| + } |
| + |
| + if (result.is_null() && |
| + IsSuitableForOnStackReplacement(isolate, function, current_code)) { |
| if (FLAG_trace_osr) { |
| - PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt()); |
| + PrintF("[OSR - Compiling: "); |
| function->PrintName(); |
| - PrintF("]\n"); |
| + PrintF(" at AST id %d]\n", ast_id.ToInt()); |
| } |
| - // Attempt OSR compilation. |
| - result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION); |
| + result = Compiler::GetOptimizedCode(function, current_code, mode, ast_id); |
| } |
| // Revert the patched back edge table, regardless of whether OSR succeeds. |
| - BackEdgeTable::Revert(isolate, *unoptimized); |
| + BackEdgeTable::Revert(isolate, *current_code); |
| // Check whether we ended up with usable optimized code. |
| if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) { |
| @@ -8715,26 +8685,27 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { |
| if (data->OsrPcOffset()->value() >= 0) { |
| ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id); |
| if (FLAG_trace_osr) { |
| - PrintF("[OSR - entry at AST id %d, offset %d in optimized code]\n", |
| + PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n", |
| ast_id.ToInt(), data->OsrPcOffset()->value()); |
| } |
| // TODO(titzer): this is a massive hack to make the deopt counts |
| // match. Fix heuristics for reenabling optimizations! |
| function->shared()->increment_deopt_count(); |
| + |
| + // TODO(titzer): Do not install code into the function. |
| + function->ReplaceCode(*result); |
| return *result; |
| } |
| } |
| + // Failed. |
| if (FLAG_trace_osr) { |
| - PrintF("[OSR - optimization failed for "); |
| + PrintF("[OSR - Failed: "); |
| function->PrintName(); |
| - PrintF("]\n"); |
| + PrintF(" at AST id %d]\n", ast_id.ToInt()); |
| } |
| - if (function->IsMarkedForLazyRecompilation() || |
| - function->IsMarkedForConcurrentRecompilation()) { |
| - function->ReplaceCode(function->shared()->code()); |
| - } |
| + function->ReplaceCode(function->shared()->code()); |
| return NULL; |
| } |
| @@ -9436,7 +9407,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { |
| } |
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) { |
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallOptimizedCode) { |
| HandleScope scope(isolate); |
| ASSERT(args.length() == 1); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| @@ -9685,13 +9656,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { |
| // Compile source string in the native context. |
| ParseRestriction restriction = function_literal_only |
| ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; |
| - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( |
| - source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); |
| - RETURN_IF_EMPTY_HANDLE(isolate, shared); |
| - Handle<JSFunction> fun = |
| - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, |
| - context, |
| - NOT_TENURED); |
| + Handle<JSFunction> fun = Compiler::GetFunctionFromEval( |
| + source, context, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); |
| + RETURN_IF_EMPTY_HANDLE(isolate, fun); |
| return *fun; |
| } |
| @@ -9717,18 +9684,11 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, |
| // Deal with a normal eval call with a string argument. Compile it |
| // and return the compiled function bound in the local context. |
| - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( |
| - source, |
| - context, |
| - context->IsNativeContext(), |
| - language_mode, |
| - NO_PARSE_RESTRICTION, |
| - scope_position); |
| - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared, |
| + static const ParseRestriction restriction = NO_PARSE_RESTRICTION; |
| + Handle<JSFunction> compiled = Compiler::GetFunctionFromEval( |
| + source, context, language_mode, restriction, scope_position); |
| + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, compiled, |
| MakePair(Failure::Exception(), NULL)); |
| - Handle<JSFunction> compiled = |
| - isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| - shared, context, NOT_TENURED); |
| return MakePair(*compiled, *receiver); |
| } |
| @@ -12563,7 +12523,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { |
| if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, |
| &source_position, |
| alignment)) { |
| - return isolate->heap()->undefined_value(); |
| + return isolate->heap()->undefined_value(); |
| } |
| return Smi::FromInt(source_position); |
| @@ -12723,18 +12683,11 @@ static MaybeObject* DebugEvaluate(Isolate* isolate, |
| context = isolate->factory()->NewWithContext(closure, context, extension); |
| } |
| - Handle<SharedFunctionInfo> shared = Compiler::CompileEval( |
| - source, |
| - context, |
| - context->IsNativeContext(), |
| - CLASSIC_MODE, |
| - NO_PARSE_RESTRICTION, |
| - RelocInfo::kNoPosition); |
| - RETURN_IF_EMPTY_HANDLE(isolate, shared); |
| + static const ParseRestriction restriction = NO_PARSE_RESTRICTION; |
|
titzer
2013/12/09 14:49:28
Why the extra local here?
Yang
2013/12/10 11:22:04
Removed.
|
| + Handle<JSFunction> eval_fun = Compiler::GetFunctionFromEval( |
| + source, context, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); |
| + RETURN_IF_EMPTY_HANDLE(isolate, eval_fun); |
| - Handle<JSFunction> eval_fun = |
| - isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| - shared, context, NOT_TENURED); |
| bool pending_exception; |
| Handle<Object> result = Execution::Call( |
| isolate, eval_fun, receiver, 0, NULL, &pending_exception); |
| @@ -13150,7 +13103,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { |
| ASSERT(args.length() == 1); |
| // Get the function and make sure it is compiled. |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); |
| - if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { |
| + if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { |
| return Failure::Exception(); |
| } |
| func->code()->PrintLn(); |
| @@ -13165,7 +13118,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { |
| ASSERT(args.length() == 1); |
| // Get the function and make sure it is compiled. |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); |
| - if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { |
| + if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { |
| return Failure::Exception(); |
| } |
| func->shared()->construct_stub()->PrintLn(); |