| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index e763d435cc985e80a21f0fe43b4e11439c534e6b..f60520d8ea050486e7521d1ddd6f2b010bb96c78 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,42 +8297,53 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
|
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileUnoptimized) {
|
| HandleScope scope(isolate);
|
| ASSERT(args.length() == 1);
|
|
|
| Handle<JSFunction> function = args.at<JSFunction>(0);
|
| #ifdef DEBUG
|
| if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
|
| - PrintF("[lazy: ");
|
| + PrintF("[unoptimized: ");
|
| function->PrintName();
|
| PrintF("]\n");
|
| }
|
| #endif
|
|
|
| // Compile the target function.
|
| - ASSERT(!function->is_compiled());
|
| - 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();
|
| + ASSERT(function->code()->kind() == Code::FUNCTION ||
|
| + (FLAG_always_opt &&
|
| + function->code()->kind() == Code::OPTIMIZED_FUNCTION));
|
| + 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;
|
| -
|
| - // 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()) {
|
| +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);
|
| +
|
| + Handle<Code> unoptimized(function->shared()->code());
|
| + if (!function->shared()->is_compiled()) {
|
| + // If the function is not compiled, do not optimize.
|
| + // This can happen if the debugger is activated and
|
| + // the function is returned to the not compiled state.
|
| + // TODO(yangguo): reconsider this.
|
| + 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 +8351,21 @@ 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);
|
| + function->ReplaceCode(code.is_null() ? *unoptimized : *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());
|
| + ASSERT(function->code()->kind() == Code::FUNCTION ||
|
| + function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
|
| + function->IsInOptimizationQueue());
|
| 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 +8506,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
|
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
|
|
| if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
|
| - function->MarkForLazyRecompilation();
|
| + function->MarkForOptimization();
|
|
|
| Code* unoptimized = function->shared()->code();
|
| if (args.length() == 2 &&
|
| @@ -8542,7 +8521,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
|
| isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
|
| }
|
| } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) {
|
| - function->MarkForConcurrentRecompilation();
|
| + function->MarkForConcurrentOptimization();
|
| }
|
| }
|
|
|
| @@ -8576,7 +8555,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 +8591,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 +8612,79 @@ 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> caller_code(function->shared()->code());
|
| +
|
| + // 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 (!caller_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());
|
| + caller_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() - caller_code->instruction_start());
|
|
|
| #ifdef DEBUG
|
| ASSERT_EQ(frame->function(), *function);
|
| - ASSERT_EQ(frame->LookupCode(), *unoptimized);
|
| - ASSERT(unoptimized->contains(frame->pc()));
|
| + ASSERT_EQ(frame->LookupCode(), *caller_code);
|
| + ASSERT(caller_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 = caller_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.
|
| + OptimizedCompileJob* job = NULL;
|
| + if (mode == Compiler::CONCURRENT) {
|
| + // 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)) {
|
| 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);
|
| + job = thread->FindReadyOSRCandidate(function, ast_id);
|
| + }
|
|
|
| - 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;
|
| - }
|
| - // 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);
|
| + if (job != NULL) {
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[OSR - Found ready: ");
|
| + function->PrintName();
|
| + PrintF(" at AST id %d]\n", ast_id.ToInt());
|
| }
|
| - } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
|
| - ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
|
| - ASSERT(!ast_id.IsNone());
|
| + result = Compiler::GetConcurrentlyOptimizedCode(job);
|
| + } else if (result.is_null() &&
|
| + IsSuitableForOnStackReplacement(isolate, function, caller_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());
|
| + }
|
| + result = Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
|
| + if (result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
|
| + // Optimization is queued. Return to check later.
|
| + return NULL;
|
| }
|
| - // Attempt OSR compilation.
|
| - result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION);
|
| }
|
|
|
| // Revert the patched back edge table, regardless of whether OSR succeeds.
|
| - BackEdgeTable::Revert(isolate, *unoptimized);
|
| + BackEdgeTable::Revert(isolate, *caller_code);
|
|
|
| // Check whether we ended up with usable optimized code.
|
| if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
|
| @@ -8715,26 +8694,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 +9416,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 +9665,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 +9693,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 +12532,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 +12692,14 @@ 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);
|
| -
|
| Handle<JSFunction> eval_fun =
|
| - isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
| - shared, context, NOT_TENURED);
|
| + Compiler::GetFunctionFromEval(source,
|
| + context,
|
| + CLASSIC_MODE,
|
| + NO_PARSE_RESTRICTION,
|
| + RelocInfo::kNoPosition);
|
| + RETURN_IF_EMPTY_HANDLE(isolate, eval_fun);
|
| +
|
| bool pending_exception;
|
| Handle<Object> result = Execution::Call(
|
| isolate, eval_fun, receiver, 0, NULL, &pending_exception);
|
| @@ -13150,7 +13115,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 +13130,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();
|
|
|