Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index f93ce6b4fd274c1865feba159b1c44b415432c3a..f56406f025beaed36e35600bd65b85603b917217 100644 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -207,6 +207,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) { |
} |
status = compiler.OptimizeGraph(); |
if (status != OptimizingCompiler::SUCCEEDED) { |
+ status = compiler.AbortOptimization(); |
return status != OptimizingCompiler::FAILED; |
} |
status = compiler.GenerateAndInstallCode(); |
@@ -340,17 +341,20 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { |
} |
OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { |
+ AssertNoAllocation no_gc; |
+ NoHandleAllocation no_handles; |
+ |
ASSERT(last_status() == SUCCEEDED); |
Timer t(this, &time_taken_to_optimize_); |
ASSERT(graph_ != NULL); |
SmartArrayPointer<char> bailout_reason; |
if (!graph_->Optimize(&bailout_reason)) { |
if (!bailout_reason.is_empty()) graph_builder_->Bailout(*bailout_reason); |
- return AbortOptimization(); |
+ return SetLastStatus(BAILED_OUT); |
} else { |
chunk_ = LChunk::NewChunk(graph_); |
if (chunk_ == NULL) { |
- return AbortOptimization(); |
+ return SetLastStatus(BAILED_OUT); |
} |
} |
return SetLastStatus(SUCCEEDED); |
@@ -658,21 +662,91 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, |
} |
-bool Compiler::CompileLazy(CompilationInfo* info) { |
- Isolate* isolate = info->isolate(); |
+static bool InstallFullCode(CompilationInfo* info) { |
+ // Update the shared function info with the compiled code and the |
+ // scope info. Please note, that the order of the shared function |
+ // info initialization is important since set_scope_info might |
+ // trigger a GC, causing the ASSERT below to be invalid if the code |
+ // was flushed. By setting the code object last we avoid this. |
+ Handle<SharedFunctionInfo> shared = info->shared_info(); |
+ Handle<Code> code = info->code(); |
+ Handle<JSFunction> function = info->closure(); |
+ Handle<ScopeInfo> scope_info = |
+ ScopeInfo::Create(info->scope(), info->zone()); |
+ shared->set_scope_info(*scope_info); |
+ shared->set_code(*code); |
+ if (!function.is_null()) { |
+ function->ReplaceCode(*code); |
+ ASSERT(!function->IsOptimized()); |
+ } |
- ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT); |
+ // Set the expected number of properties for instances. |
+ FunctionLiteral* lit = info->function(); |
+ int expected = lit->expected_property_count(); |
+ SetExpectedNofPropertiesFromEstimate(shared, expected); |
- // The VM is in the COMPILER state until exiting this function. |
- VMState state(isolate, COMPILER); |
+ // Set the optimization hints after performing lazy compilation, as |
+ // these are not set when the function is set up as a lazily |
+ // compiled function. |
+ shared->SetThisPropertyAssignmentsInfo( |
+ lit->has_only_simple_this_property_assignments(), |
+ *lit->this_property_assignments()); |
+ |
+ // Check the function has compiled code. |
+ ASSERT(shared->is_compiled()); |
+ shared->set_code_age(0); |
+ shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); |
+ shared->set_dont_inline(lit->flags()->Contains(kDontInline)); |
+ shared->set_ast_node_count(lit->ast_node_count()); |
+ |
+ if (V8::UseCrankshaft()&& |
+ !function.is_null() && |
+ !shared->optimization_disabled()) { |
+ // If we're asked to always optimize, we compile the optimized |
+ // version of the function right away - unless the debugger is |
+ // active as it makes no sense to compile optimized code then. |
+ if (FLAG_always_opt && |
+ !Isolate::Current()->DebuggerHasBreakPoints()) { |
+ CompilationInfoWithZone optimized(function); |
+ optimized.SetOptimizing(AstNode::kNoNumber); |
+ return Compiler::CompileLazy(&optimized); |
+ } |
+ } |
+ return true; |
+} |
- PostponeInterruptsScope postpone(isolate); |
+static void InstallCodeCommon(CompilationInfo* info) { |
Handle<SharedFunctionInfo> shared = info->shared_info(); |
- int compiled_size = shared->end_position() - shared->start_position(); |
- isolate->counters()->total_compile_size()->Increment(compiled_size); |
+ Handle<Code> code = info->code(); |
+ ASSERT(!code.is_null()); |
+ // Set optimizable to false if this is disallowed by the shared |
+ // function info, e.g., we might have flushed the code and must |
+ // reset this bit when lazy compiling the code again. |
+ if (shared->optimization_disabled()) code->set_optimizable(false); |
+ |
+ Handle<JSFunction> function = info->closure(); |
+ Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); |
+} |
+ |
+ |
+static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { |
+ Handle<Code> code = info->code(); |
+ Handle<JSFunction> function = info->closure(); |
+ if (FLAG_cache_optimized_code && code->kind() == Code::OPTIMIZED_FUNCTION) { |
+ Handle<SharedFunctionInfo> shared(function->shared()); |
+ Handle<FixedArray> literals(function->literals()); |
+ Handle<Context> global_context(function->context()->global_context()); |
+ SharedFunctionInfo::AddToOptimizedCodeMap( |
+ shared, global_context, code, literals); |
+ } |
+} |
+ |
+ |
+static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) { |
if (FLAG_cache_optimized_code && info->IsOptimizing()) { |
+ Handle<SharedFunctionInfo> shared = info->shared_info(); |
Handle<JSFunction> function = info->closure(); |
ASSERT(!function.is_null()); |
Handle<Context> global_context(function->context()->global_context()); |
@@ -688,6 +762,25 @@ bool Compiler::CompileLazy(CompilationInfo* info) { |
return true; |
} |
} |
+ return false; |
+} |
+ |
+ |
+bool Compiler::CompileLazy(CompilationInfo* info) { |
+ Isolate* isolate = info->isolate(); |
+ |
+ ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT); |
+ |
+ // The VM is in the COMPILER state until exiting this function. |
+ VMState state(isolate, COMPILER); |
+ |
+ 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); |
+ |
+ if (InstallCodeFromOptimizedCodeMap(info)) return true; |
// Generate the AST for the lazily compiled function. |
if (ParserApi::Parse(info, kNoParsingFlags)) { |
@@ -707,78 +800,17 @@ bool Compiler::CompileLazy(CompilationInfo* info) { |
isolate->StackOverflow(); |
} |
} else { |
- ASSERT(!info->code().is_null()); |
- Handle<Code> code = info->code(); |
- // Set optimizable to false if this is disallowed by the shared |
- // function info, e.g., we might have flushed the code and must |
- // reset this bit when lazy compiling the code again. |
- if (shared->optimization_disabled()) code->set_optimizable(false); |
- |
- Handle<JSFunction> function = info->closure(); |
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); |
+ InstallCodeCommon(info); |
if (info->IsOptimizing()) { |
+ Handle<Code> code = info->code(); |
ASSERT(shared->scope_info() != ScopeInfo::Empty()); |
- function->ReplaceCode(*code); |
- if (FLAG_cache_optimized_code && |
- code->kind() == Code::OPTIMIZED_FUNCTION) { |
- Handle<SharedFunctionInfo> shared(function->shared()); |
- Handle<FixedArray> literals(function->literals()); |
- Handle<Context> global_context(function->context()->global_context()); |
- SharedFunctionInfo::AddToOptimizedCodeMap( |
- shared, global_context, code, literals); |
- } |
+ info->closure()->ReplaceCode(*code); |
+ InsertCodeIntoOptimizedCodeMap(info); |
+ return true; |
} else { |
- // Update the shared function info with the compiled code and the |
- // scope info. Please note, that the order of the shared function |
- // info initialization is important since set_scope_info might |
- // trigger a GC, causing the ASSERT below to be invalid if the code |
- // was flushed. By setting the code object last we avoid this. |
- Handle<ScopeInfo> scope_info = |
- ScopeInfo::Create(info->scope(), info->zone()); |
- shared->set_scope_info(*scope_info); |
- shared->set_code(*code); |
- if (!function.is_null()) { |
- function->ReplaceCode(*code); |
- ASSERT(!function->IsOptimized()); |
- } |
- |
- // Set the expected number of properties for instances. |
- FunctionLiteral* lit = info->function(); |
- int expected = lit->expected_property_count(); |
- SetExpectedNofPropertiesFromEstimate(shared, expected); |
- |
- // Set the optimization hints after performing lazy compilation, as |
- // these are not set when the function is set up as a lazily |
- // compiled function. |
- shared->SetThisPropertyAssignmentsInfo( |
- lit->has_only_simple_this_property_assignments(), |
- *lit->this_property_assignments()); |
- |
- // Check the function has compiled code. |
- ASSERT(shared->is_compiled()); |
- shared->set_code_age(0); |
- shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); |
- shared->set_dont_inline(lit->flags()->Contains(kDontInline)); |
- shared->set_dont_cache(lit->flags()->Contains(kDontCache)); |
- shared->set_ast_node_count(lit->ast_node_count()); |
- |
- if (V8::UseCrankshaft()&& |
- !function.is_null() && |
- !shared->optimization_disabled()) { |
- // If we're asked to always optimize, we compile the optimized |
- // version of the function right away - unless the debugger is |
- // active as it makes no sense to compile optimized code then. |
- if (FLAG_always_opt && |
- !Isolate::Current()->DebuggerHasBreakPoints()) { |
- CompilationInfoWithZone optimized(function); |
- optimized.SetOptimizing(AstNode::kNoNumber); |
- return CompileLazy(&optimized); |
- } |
- } |
+ return InstallFullCode(info); |
} |
- |
- return true; |
} |
} |
@@ -787,6 +819,91 @@ bool Compiler::CompileLazy(CompilationInfo* info) { |
} |
+void Compiler::RecompileParallel(Handle<JSFunction> closure) { |
+ ASSERT(closure->IsMarkedForParallelRecompilation()); |
+ if (closure->IsInRecompileQueue()) return; |
+ |
+ Isolate* isolate = closure->GetIsolate(); |
+ if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { |
+ if (FLAG_trace_parallel_recompilation) { |
+ PrintF(" ** Compilation queue, will retry opting on next run.\n"); |
+ } |
+ return; |
+ } |
+ |
+ SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure)); |
+ VMState state(isolate, PARALLEL_COMPILER_PROLOGUE); |
+ 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(AstNode::kNoNumber); |
+ |
+ { |
+ CompilationHandleScope handle_scope(*info); |
+ |
+ if (InstallCodeFromOptimizedCodeMap(*info)) return; |
+ |
+ if (ParserApi::Parse(*info, kNoParsingFlags)) { |
+ LanguageMode language_mode = info->function()->language_mode(); |
+ info->SetLanguageMode(language_mode); |
+ shared->set_language_mode(language_mode); |
+ info->SaveHandles(); |
+ |
+ if (Rewriter::Rewrite(*info) && Scope::Analyze(*info)) { |
+ OptimizingCompiler* compiler = |
+ new(info->zone()) OptimizingCompiler(*info); |
+ OptimizingCompiler::Status status = compiler->CreateGraph(); |
+ if (status == OptimizingCompiler::SUCCEEDED) { |
+ isolate->optimizing_compiler_thread()->QueueForOptimization(compiler); |
+ shared->code()->set_profiler_ticks(0); |
+ closure->ReplaceCode(isolate->builtins()->builtin( |
+ Builtins::kInRecompileQueue)); |
+ info.Detach(); |
+ } else if (status == OptimizingCompiler::BAILED_OUT) { |
+ isolate->clear_pending_exception(); |
+ InstallFullCode(*info); |
+ } |
+ } |
+ } |
+ } |
+ |
+ if (isolate->has_pending_exception()) { |
+ isolate->clear_pending_exception(); |
+ } |
+} |
+ |
+ |
+void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) { |
+ SmartPointer<CompilationInfo> info(optimizing_compiler->info()); |
+ // If crankshaft succeeded, install the optimized code else install |
+ // the unoptimized code. |
+ OptimizingCompiler::Status status = optimizing_compiler->last_status(); |
+ if (status != OptimizingCompiler::SUCCEEDED) { |
+ status = optimizing_compiler->AbortOptimization(); |
+ } else { |
+ status = optimizing_compiler->GenerateAndInstallCode(); |
+ ASSERT(status == OptimizingCompiler::SUCCEEDED || |
+ status == OptimizingCompiler::BAILED_OUT); |
+ } |
+ |
+ InstallCodeCommon(*info); |
+ if (status == OptimizingCompiler::SUCCEEDED) { |
+ Handle<Code> code = info->code(); |
+ ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty()); |
+ info->closure()->ReplaceCode(*code); |
+ if (info->shared_info()->SearchOptimizedCodeMap( |
+ info->closure()->context()->global_context()) == -1) { |
+ InsertCodeIntoOptimizedCodeMap(*info); |
+ } |
+ } else { |
+ info->SetCode(Handle<Code>(info->shared_info()->code())); |
+ InstallFullCode(*info); |
+ } |
+} |
+ |
+ |
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, |
Handle<Script> script) { |
// Precondition: code has been parsed and scopes have been analyzed. |