Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index 38c8d69691d54fe0ff936537f893fe46d289f2a1..25d65040f9a0470c3e594385dc9f30ece9ec4148 100644 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -38,8 +38,6 @@ |
namespace v8 { |
namespace internal { |
- |
- |
// A wrapper around a CompilationInfo that detaches the Handles from |
// the underlying DeferredHandleScope and stores them in info_ on |
// destruction. |
@@ -377,8 +375,7 @@ bool ShouldUseIgnition(CompilationInfo* info) { |
return shared->PassesFilter(FLAG_ignition_filter); |
} |
-CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info, |
- LazyCompilationMode mode) { |
+CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { |
// Function should have been parsed and analyzed before creating a compilation |
// job. |
DCHECK_NOT_NULL(info->literal()); |
@@ -386,9 +383,9 @@ CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info, |
EnsureFeedbackMetadata(info); |
if (ShouldUseIgnition(info)) { |
- return interpreter::Interpreter::NewCompilationJob(info, mode); |
+ return interpreter::Interpreter::NewCompilationJob(info); |
} else { |
- return FullCodeGenerator::NewCompilationJob(info, mode); |
+ return FullCodeGenerator::NewCompilationJob(info); |
} |
} |
@@ -437,6 +434,28 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { |
return status; |
} |
+bool Renumber(ParseInfo* parse_info, |
+ Compiler::EagerInnerFunctionLiterals* eager_literals) { |
+ RuntimeCallTimerScope runtimeTimer(parse_info->isolate(), |
+ &RuntimeCallStats::CompileRenumber); |
+ if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(), |
+ parse_info->literal(), eager_literals)) { |
+ return false; |
+ } |
+ Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); |
+ if (!shared_info.is_null()) { |
+ FunctionLiteral* lit = parse_info->literal(); |
+ shared_info->set_ast_node_count(lit->ast_node_count()); |
+ if (lit->dont_optimize_reason() != kNoReason) { |
+ shared_info->DisableOptimization(lit->dont_optimize_reason()); |
+ } |
+ if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) { |
+ shared_info->set_must_use_ignition_turbo(true); |
+ } |
+ } |
+ return true; |
+} |
+ |
bool GenerateUnoptimizedCode(CompilationInfo* info) { |
if (FLAG_validate_asm && info->scope()->asm_module() && |
!info->shared_info()->is_asm_wasm_broken() && !info->is_debug()) { |
@@ -451,8 +470,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { |
} |
} |
- std::unique_ptr<CompilationJob> job( |
- GetUnoptimizedCompilationJob(info, LazyCompilationMode::kIfRequested)); |
+ std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); |
if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; |
if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; |
if (FinalizeUnoptimizedCompilationJob(job.get()) != |
@@ -462,14 +480,76 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { |
return true; |
} |
+bool CompileUnoptimizedInnerFunctionsRecursively( |
+ ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* literals, |
+ CompilationInfo* outer_info) { |
+ Isolate* isolate = outer_info->isolate(); |
+ Handle<Script> script = outer_info->script(); |
+ RuntimeCallTimerScope runtimeTimer(isolate, |
+ &RuntimeCallStats::CompileInnerFunction); |
+ |
+ for (auto it : *literals) { |
+ FunctionLiteral* literal = it->value(); |
+ |
+ // Find any previously allocated shared function info for the given literal. |
+ Handle<SharedFunctionInfo> shared; |
+ MaybeHandle<SharedFunctionInfo> maybe_existing = |
+ script->FindSharedFunctionInfo(isolate, literal); |
+ if (maybe_existing.ToHandle(&shared)) { |
+ DCHECK(!shared->is_toplevel()); |
+ // If we found an existing shared function info with compiled code, |
+ // we are done. |
+ if (shared->is_compiled()) continue; |
+ } else { |
+ shared = |
+ isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); |
+ shared->set_is_toplevel(false); |
+ } |
+ |
+ Zone zone(isolate->allocator(), ZONE_NAME); |
+ ParseInfo parse_info(&zone, script); |
+ parse_info.set_literal(literal); |
+ parse_info.set_shared_info(shared); |
+ parse_info.set_function_literal_id(shared->function_literal_id()); |
+ parse_info.set_language_mode(literal->scope()->language_mode()); |
+ parse_info.set_ast_value_factory( |
+ outer_info->parse_info()->ast_value_factory()); |
+ parse_info.set_ast_value_factory_owned(false); |
+ |
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null()); |
+ if (outer_info->will_serialize()) info.PrepareForSerializing(); |
+ if (outer_info->is_debug()) info.MarkAsDebug(); |
+ |
+ Compiler::EagerInnerFunctionLiterals inner_literals; |
+ if (!Renumber(&parse_info, &inner_literals) || |
+ !CompileUnoptimizedInnerFunctionsRecursively(&inner_literals, |
+ outer_info) || |
+ !GenerateUnoptimizedCode(&info)) { |
+ if (!isolate->has_pending_exception()) isolate->StackOverflow(); |
+ return false; |
+ } |
+ |
+ DCHECK(!info.code().is_null()); |
+ RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info); |
+ if (literal->should_be_used_once_hint()) { |
+ info.code()->MarkToBeExecutedOnce(isolate); |
+ } |
+ } |
+ return true; |
+} |
+ |
bool CompileUnoptimizedCode(CompilationInfo* info) { |
- DCHECK(AllowCompilation::IsAllowed(info->isolate())); |
- if (!Compiler::Analyze(info->parse_info()) || |
+ Isolate* isolate = info->isolate(); |
+ DCHECK(AllowCompilation::IsAllowed(isolate)); |
+ |
+ Compiler::EagerInnerFunctionLiterals inner_literals; |
+ if (!Compiler::Analyze(info->parse_info(), &inner_literals) || |
+ !CompileUnoptimizedInnerFunctionsRecursively(&inner_literals, info) || |
!GenerateUnoptimizedCode(info)) { |
- Isolate* isolate = info->isolate(); |
if (!isolate->has_pending_exception()) isolate->StackOverflow(); |
return false; |
} |
+ |
return true; |
} |
@@ -552,27 +632,6 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { |
literals, info->osr_ast_id()); |
} |
-bool Renumber(ParseInfo* parse_info) { |
- RuntimeCallTimerScope runtimeTimer(parse_info->isolate(), |
- &RuntimeCallStats::CompileRenumber); |
- if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(), |
- parse_info->literal())) { |
- return false; |
- } |
- Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); |
- if (!shared_info.is_null()) { |
- FunctionLiteral* lit = parse_info->literal(); |
- shared_info->set_ast_node_count(lit->ast_node_count()); |
- if (lit->dont_optimize_reason() != kNoReason) { |
- shared_info->DisableOptimization(lit->dont_optimize_reason()); |
- } |
- if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) { |
- shared_info->set_must_use_ignition_turbo(true); |
- } |
- } |
- return true; |
-} |
- |
bool GetOptimizedCodeNow(CompilationJob* job) { |
CompilationInfo* info = job->info(); |
Isolate* isolate = info->isolate(); |
@@ -1016,8 +1075,6 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { |
EnsureSharedFunctionInfosArrayOnScript(parse_info); |
- FunctionLiteral* lit = parse_info->literal(); |
- |
// Measure how long it takes to do the compilation; only take the |
// rest of the function into account to avoid overlap with the |
// parsing statistics. |
@@ -1029,6 +1086,7 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { |
parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile"); |
// Allocate a shared function info object. |
+ FunctionLiteral* lit = parse_info->literal(); |
DCHECK_EQ(kNoSourcePosition, lit->function_token_position()); |
result = isolate->factory()->NewSharedFunctionInfoForLiteral(lit, script); |
result->set_is_toplevel(true); |
@@ -1064,13 +1122,14 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { |
// ---------------------------------------------------------------------------- |
// Implementation of Compiler |
-bool Compiler::Analyze(ParseInfo* info) { |
+bool Compiler::Analyze(ParseInfo* info, |
+ EagerInnerFunctionLiterals* eager_literals) { |
DCHECK_NOT_NULL(info->literal()); |
RuntimeCallTimerScope runtimeTimer(info->isolate(), |
&RuntimeCallStats::CompileAnalyse); |
if (!Rewriter::Rewrite(info)) return false; |
DeclarationScope::Analyze(info, AnalyzeMode::kRegular); |
- if (!Renumber(info)) return false; |
+ if (!Renumber(info, eager_literals)) return false; |
DCHECK_NOT_NULL(info->scope()); |
return true; |
} |
@@ -1592,7 +1651,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript( |
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( |
FunctionLiteral* literal, Handle<Script> script, |
- CompilationInfo* outer_info, LazyCompilationMode mode) { |
+ CompilationInfo* outer_info) { |
// Precondition: code has been parsed and scopes have been analyzed. |
Isolate* isolate = outer_info->isolate(); |
MaybeHandle<SharedFunctionInfo> maybe_existing; |
@@ -1600,80 +1659,21 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( |
// Find any previously allocated shared function info for the given literal. |
maybe_existing = script->FindSharedFunctionInfo(isolate, literal); |
- // We found an existing shared function info. If it has any sort of code |
- // attached, don't worry about compiling and simply return it. Otherwise, |
- // continue to decide whether to eagerly compile. |
- // Note that we also carry on if we are compiling eager to obtain code for |
- // debugging, unless we already have code with debug break slots. |
+ // If we found an existing shared function info, return it. |
Handle<SharedFunctionInfo> existing; |
if (maybe_existing.ToHandle(&existing)) { |
DCHECK(!existing->is_toplevel()); |
- if (existing->HasBaselineCode() || existing->HasBytecodeArray()) { |
- if (!outer_info->is_debug() || existing->HasDebugCode()) { |
- return existing; |
- } |
- } |
+ return existing; |
} |
- // Allocate a shared function info object. |
- Handle<SharedFunctionInfo> result; |
- if (!maybe_existing.ToHandle(&result)) { |
- result = |
- isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); |
- result->set_is_toplevel(false); |
- } |
- |
- Zone zone(isolate->allocator(), ZONE_NAME); |
- ParseInfo parse_info(&zone, script); |
- CompilationInfo info(&parse_info, Handle<JSFunction>::null()); |
- parse_info.set_literal(literal); |
- parse_info.set_shared_info(result); |
- parse_info.set_function_literal_id(result->function_literal_id()); |
- parse_info.set_language_mode(literal->scope()->language_mode()); |
- parse_info.set_ast_value_factory( |
- outer_info->parse_info()->ast_value_factory()); |
- parse_info.set_ast_value_factory_owned(false); |
- |
- if (outer_info->will_serialize()) info.PrepareForSerializing(); |
- if (outer_info->is_debug()) info.MarkAsDebug(); |
- |
- // If this inner function is already compiled, we don't need to compile |
- // again. When compiling for debug, we are not interested in having debug |
- // break slots in inner functions, neither for setting break points nor |
- // for revealing inner functions. |
- // This is especially important for generators. We must not replace the |
- // code for generators, as there may be suspended generator objects. |
- if (!result->is_compiled()) { |
- if (mode == LazyCompilationMode::kAlways || |
- !literal->ShouldEagerCompile()) { |
- info.SetCode(isolate->builtins()->CompileLazy()); |
- Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); |
- if (outer_scope) { |
- result->set_outer_scope_info(*outer_scope->scope_info()); |
- } |
- } else { |
- // Generate code |
- TimerEventScope<TimerEventCompileCode> timer(isolate); |
- RuntimeCallTimerScope runtimeTimer( |
- isolate, &RuntimeCallStats::CompileInnerFunction); |
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); |
- if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) { |
- // Code generation will ensure that the feedback vector is present and |
- // appropriately sized. |
- DCHECK(!info.code().is_null()); |
- if (literal->should_be_used_once_hint()) { |
- info.code()->MarkToBeExecutedOnce(isolate); |
- } |
- } else { |
- return Handle<SharedFunctionInfo>::null(); |
- } |
- } |
- } |
- |
- if (maybe_existing.is_null()) { |
- RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info); |
+ // Allocate a shared function info object which will be compiled lazily. |
+ Handle<SharedFunctionInfo> result = |
+ isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); |
+ result->set_is_toplevel(false); |
+ Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); |
+ if (outer_scope) { |
+ result->set_outer_scope_info(*outer_scope->scope_info()); |
} |
- |
return result; |
} |
@@ -1718,9 +1718,9 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function, |
} |
CompilationJob* Compiler::PrepareUnoptimizedCompilationJob( |
- CompilationInfo* info, LazyCompilationMode mode) { |
+ CompilationInfo* info) { |
VMState<COMPILER> state(info->isolate()); |
- std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info, mode)); |
+ std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); |
if (job->PrepareJob() != CompilationJob::SUCCEEDED) { |
return nullptr; |
} |