Chromium Code Reviews| 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) { |