Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index cf556f237babe4642cd2d837aa75a99ce73b0e78..31e0fc5110dc054d91089821e7ff7e212177956a 100644 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -10,6 +10,7 @@ |
#include "src/asmjs/asm-js.h" |
#include "src/asmjs/asm-typer.h" |
#include "src/ast/ast-numbering.h" |
+#include "src/ast/collect-eager-literals.h" |
#include "src/ast/prettyprinter.h" |
#include "src/ast/scopes.h" |
#include "src/bootstrapper.h" |
@@ -71,6 +72,15 @@ struct ScopedTimer { |
// ---------------------------------------------------------------------------- |
// Implementation of CompilationJob |
+CompilationJob::CompilationJob(Isolate* isolate, CompilationInfo* info, |
+ const char* compiler_name, State initial_state) |
+ : info_(info), |
+ compiler_name_(compiler_name), |
+ state_(initial_state), |
+ stack_limit_(isolate->stack_guard()->real_climit()) {} |
+ |
+CompilationJob::~CompilationJob() {} |
+ |
CompilationJob::Status CompilationJob::PrepareJob() { |
DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); |
DisallowJavascriptExecution no_js(isolate()); |
@@ -188,6 +198,13 @@ void CompilationJob::RecordOptimizedCompilationStats() const { |
Isolate* CompilationJob::isolate() const { return info()->isolate(); } |
+void CompilationJob::TakeOwnershipOfCompilationInfo() { |
+ DCHECK_NULL(compilation_info_.get()); |
+ compilation_info_.reset(info_); |
+ parse_info_.reset(info_->parse_info()); |
+ zone_.reset(info_->parse_info()->zone()); |
+} |
+ |
namespace { |
void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, |
@@ -346,17 +363,99 @@ bool ShouldUseIgnition(CompilationInfo* info) { |
return info->shared_info()->PassesFilter(FLAG_ignition_filter); |
} |
-CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { |
+bool Renumber(ParseInfo* parse_info) { |
+ // Create a canonical handle scope if compiling ignition bytecode. This is |
+ // required by the constant array builder to de-duplicate objects without |
+ // dereferencing handles. |
+ std::unique_ptr<CanonicalHandleScope> canonical; |
+ if (FLAG_ignition) { |
+ canonical.reset(new CanonicalHandleScope(parse_info->isolate())); |
+ } |
+ |
+ 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::kDontCrankshaft) { |
+ shared_info->set_dont_crankshaft(true); |
+ } |
+ } |
+ return true; |
+} |
+ |
+std::vector<std::unique_ptr<CompilationJob>> GetUnoptimizedCompilationJobs( |
+ CompilationInfo* info) { |
// Function should have been parsed and analyzed before creating a compilation |
// job. |
DCHECK_NOT_NULL(info->literal()); |
DCHECK_NOT_NULL(info->scope()); |
EnsureFeedbackMetadata(info); |
+ |
+ std::vector<std::unique_ptr<CompilationJob>> result; |
+ |
if (ShouldUseIgnition(info)) { |
- return interpreter::Interpreter::NewCompilationJob(info); |
+ // When compiling eagerly, the majority of work might happen in the |
+ // finalization phase, when we get the SharedFunctionInfos for all the |
+ // functions referenced from the function we actually want to compile. |
+ // |
+ // This is undesirable when we want to schedule the compilation work (which |
+ // is only the case for ignition at this point). To avoid this compilation |
+ // during finalization, walk the AST and create separate compilation jobs |
+ // for each eager function literal we encounter. |
+ // |
+ // This doesn't work for debug code, as GetSharedFunctionInfo only caches |
+ // the SharedFunctionInfos with non-debug code. |
+ ShouldCompile should_compile = |
+ (FLAG_ignition_split_jobs && !info->is_debug()) |
+ ? ShouldCompile::kNever |
+ : ShouldCompile::kIfNecessary; |
+ result.push_back(std::unique_ptr<CompilationJob>( |
+ interpreter::Interpreter::NewCompilationJob(info, should_compile))); |
+ |
+ if (should_compile == ShouldCompile::kNever) { |
+ CollectEagerLiterals collector(info); |
+ collector.Run(); |
+ |
+ for (auto fun : collector.eager_literals()) { |
+ Handle<SharedFunctionInfo> sfi = Compiler::GetSharedFunctionInfo( |
+ fun, info->script(), info, ShouldCompile::kNever); |
+ |
+ std::unique_ptr<ParseInfo> parse_info(new ParseInfo( |
+ new Zone(info->isolate()->allocator()), info->script())); |
+ parse_info->set_literal(fun); |
+ parse_info->set_shared_info(sfi); |
+ parse_info->set_language_mode(fun->scope()->language_mode()); |
+ |
+ std::unique_ptr<CompilationInfo> compilation_info(new CompilationInfo( |
+ parse_info.release(), Handle<JSFunction>::null())); |
+ if (info->will_serialize()) compilation_info->PrepareForSerializing(); |
+ DCHECK(!info->is_debug()); |
+ |
+ Renumber(compilation_info->parse_info()); |
+ EnsureFeedbackMetadata(compilation_info.get()); |
+ DCHECK(ShouldUseIgnition(compilation_info.get())); |
+ std::unique_ptr<CompilationJob> job( |
+ interpreter::Interpreter::NewCompilationJob( |
+ compilation_info.release(), ShouldCompile::kNever)); |
+ job->TakeOwnershipOfCompilationInfo(); |
+ result.push_back(std::move(job)); |
+ } |
+ } |
+ |
+ return result; |
} else { |
- return FullCodeGenerator::NewCompilationJob(info); |
+ std::unique_ptr<CompilationJob> job( |
+ FullCodeGenerator::NewCompilationJob(info)); |
+ result.push_back(std::move(job)); |
+ return result; |
} |
} |
@@ -419,12 +518,16 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { |
} |
} |
- 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()) != |
- CompilationJob::SUCCEEDED) { |
- return false; |
+ std::vector<std::unique_ptr<CompilationJob>> jobs( |
+ GetUnoptimizedCompilationJobs(info)); |
+ for (auto& job : jobs) { |
+ if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; |
+ if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; |
+ if (FinalizeUnoptimizedCompilationJob(job.get()) != |
+ CompilationJob::SUCCEEDED) { |
+ return false; |
+ } |
+ job.reset(); |
} |
return true; |
} |
@@ -497,33 +600,6 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { |
literals, info->osr_ast_id()); |
} |
-bool Renumber(ParseInfo* parse_info) { |
- // Create a canonical handle scope if compiling ignition bytecode. This is |
- // required by the constant array builder to de-duplicate objects without |
- // dereferencing handles. |
- std::unique_ptr<CanonicalHandleScope> canonical; |
- if (FLAG_ignition) { |
- canonical.reset(new CanonicalHandleScope(parse_info->isolate())); |
- } |
- |
- 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::kDontCrankshaft) { |
- shared_info->set_dont_crankshaft(true); |
- } |
- } |
- return true; |
-} |
- |
bool UseTurboFan(Handle<SharedFunctionInfo> shared) { |
bool optimization_disabled = shared->optimization_disabled(); |
bool dont_crankshaft = shared->dont_crankshaft(); |
@@ -1694,16 +1770,16 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript( |
return result; |
} |
- |
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( |
FunctionLiteral* literal, Handle<Script> script, |
- CompilationInfo* outer_info) { |
+ CompilationInfo* outer_info, ShouldCompile should_compile) { |
// Precondition: code has been parsed and scopes have been analyzed. |
Isolate* isolate = outer_info->isolate(); |
MaybeHandle<SharedFunctionInfo> maybe_existing; |
// Find any previously allocated shared function info for the given literal. |
- if (outer_info->shared_info()->never_compiled()) { |
+ if (outer_info->shared_info()->never_compiled() && |
+ should_compile == ShouldCompile::kIfNecessary) { |
// On the first compile, there are no existing shared function info for |
// inner functions yet, so do not try to find them. All bets are off for |
// live edit though. |
@@ -1725,6 +1801,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( |
if (!outer_info->is_debug() || existing->HasDebugCode()) { |
return existing; |
} |
+ } else if (should_compile == ShouldCompile::kNever) { |
+ return existing; |
Michael Starzinger
2016/10/17 13:16:03
nit: Please add a DCHECK(!outer_info->is_debug())
|
} |
} |
@@ -1754,7 +1832,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( |
RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::CompileCode); |
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); |
- if (!literal->ShouldEagerCompile()) { |
+ if (!literal->ShouldEagerCompile() || |
+ should_compile == ShouldCompile::kNever) { |
info.SetCode(isolate->builtins()->CompileLazy()); |
Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); |
if (outer_scope) { |
@@ -1818,14 +1897,18 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function, |
return GetOptimizedCode(function, NOT_CONCURRENT, osr_ast_id, osr_frame); |
} |
-CompilationJob* Compiler::PrepareUnoptimizedCompilationJob( |
- CompilationInfo* info) { |
+std::vector<std::unique_ptr<CompilationJob>> |
+Compiler::PrepareUnoptimizedCompilationJobs(CompilationInfo* info) { |
VMState<COMPILER> state(info->isolate()); |
- std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); |
- if (job->PrepareJob() != CompilationJob::SUCCEEDED) { |
- return nullptr; |
+ std::vector<std::unique_ptr<CompilationJob>> jobs( |
+ GetUnoptimizedCompilationJobs(info)); |
+ for (auto& job : jobs) { |
+ if (job->PrepareJob() != CompilationJob::SUCCEEDED) { |
+ std::vector<std::unique_ptr<CompilationJob>> result; |
+ return result; |
+ } |
} |
- return job.release(); |
+ return jobs; |
} |
bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) { |