Commit 9a4b334f authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[compiler] Add background compilation mode.

Adds support for compiling top-level code on a background thread behind a flag.
When the flag is enabled, any background-parsing-task will perform compilation
as well as parsing.

BUG=v8:5203
TBR=marja@chromium.org,mstarzinger@chromium.org

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Icf90ac7211298d3555515dafc7c3245618ec1304
Reviewed-on: https://chromium-review.googlesource.com/764048
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49364}
parent adc52af5
...@@ -2613,19 +2613,25 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context, ...@@ -2613,19 +2613,25 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
} }
source->info->set_script(script); source->info->set_script(script);
if (source->info->literal() == nullptr) {
source->info->pending_error_handler()->ReportErrors(
isolate, script, source->info->ast_value_factory());
}
source->parser->UpdateStatistics(isolate, script); source->parser->UpdateStatistics(isolate, script);
source->info->UpdateStatisticsAfterBackgroundParse(isolate); source->info->UpdateStatisticsAfterBackgroundParse(isolate);
source->parser->HandleSourceURLComments(isolate, script); source->parser->HandleSourceURLComments(isolate, script);
i::Handle<i::SharedFunctionInfo> result; i::Handle<i::SharedFunctionInfo> result;
if (source->info->literal() != nullptr) { if (source->info->literal() == nullptr) {
// Parsing has succeeded. // Parsing has failed - report error messages.
result = i::Compiler::GetSharedFunctionInfoForStreamedScript( source->info->pending_error_handler()->ReportErrors(
script, source->info.get(), str->length()); isolate, script, source->info->ast_value_factory());
} else {
// Parsing has succeeded - finalize compile.
if (i::FLAG_background_compile) {
result = i::Compiler::GetSharedFunctionInfoForBackgroundCompile(
script, source->info.get(), str->length(),
source->outer_function_job.get(), &source->inner_function_jobs);
} else {
result = i::Compiler::GetSharedFunctionInfoForStreamedScript(
script, source->info.get(), str->length());
}
} }
has_pending_exception = result.is_null(); has_pending_exception = result.is_null();
if (has_pending_exception) isolate->ReportPendingMessages(); if (has_pending_exception) isolate->ReportPendingMessages();
......
...@@ -188,7 +188,7 @@ class AsmJsCompilationJob final : public CompilationJob { ...@@ -188,7 +188,7 @@ class AsmJsCompilationJob final : public CompilationJob {
explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal, explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
Isolate* isolate) Isolate* isolate)
: CompilationJob(parse_info->stack_limit(), parse_info, : CompilationJob(parse_info->stack_limit(), parse_info,
&compilation_info_, "AsmJs"), &compilation_info_, "AsmJs", State::kReadyToExecute),
zone_(isolate->allocator(), ZONE_NAME), zone_(isolate->allocator(), ZONE_NAME),
compilation_info_(&zone_, isolate, parse_info, literal), compilation_info_(&zone_, isolate, parse_info, literal),
module_(nullptr), module_(nullptr),
...@@ -215,6 +215,7 @@ class AsmJsCompilationJob final : public CompilationJob { ...@@ -215,6 +215,7 @@ class AsmJsCompilationJob final : public CompilationJob {
}; };
CompilationJob::Status AsmJsCompilationJob::PrepareJobImpl() { CompilationJob::Status AsmJsCompilationJob::PrepareJobImpl() {
UNREACHABLE(); // Prepare should always be skipped.
return SUCCEEDED; return SUCCEEDED;
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "src/compiler.h" #include "src/compiler.h"
#include "src/flags.h" #include "src/flags.h"
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/parsing/parse-info.h" #include "src/parsing/parse-info.h"
...@@ -360,8 +361,9 @@ void UnoptimizedCompileJob::PrepareToCompileOnMainThread(Isolate* isolate) { ...@@ -360,8 +361,9 @@ void UnoptimizedCompileJob::PrepareToCompileOnMainThread(Isolate* isolate) {
DCHECK_EQ(status(), Status::kAnalyzed); DCHECK_EQ(status(), Status::kAnalyzed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile); COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
compilation_job_.reset( compilation_job_.reset(interpreter::Interpreter::NewCompilationJob(
Compiler::PrepareUnoptimizedCompilationJob(parse_info_.get(), isolate)); parse_info_.get(), parse_info_->literal(), isolate));
if (!compilation_job_.get()) { if (!compilation_job_.get()) {
if (!isolate->has_pending_exception()) isolate->StackOverflow(); if (!isolate->has_pending_exception()) isolate->StackOverflow();
status_ = Status::kFailed; status_ = Status::kFailed;
......
This diff is collapsed.
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_H_ #ifndef V8_COMPILER_H_
#define V8_COMPILER_H_ #define V8_COMPILER_H_
#include <forward_list>
#include <memory> #include <memory>
#include "src/allocation.h" #include "src/allocation.h"
...@@ -28,6 +29,8 @@ class ThreadedList; ...@@ -28,6 +29,8 @@ class ThreadedList;
template <typename T> template <typename T>
class ThreadedListZoneEntry; class ThreadedListZoneEntry;
typedef std::forward_list<std::unique_ptr<CompilationJob>> CompilationJobList;
// The V8 compiler API. // The V8 compiler API.
// //
// This is the central hub for dispatching to the various compilers within V8. // This is the central hub for dispatching to the various compilers within V8.
...@@ -54,9 +57,11 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -54,9 +57,11 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode); static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script); static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
// Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse. // Compile top level code on a background thread. Should be finalized by
static CompilationJob* PrepareUnoptimizedCompilationJob(ParseInfo* parse_info, // GetSharedFunctionInfoForBackgroundCompile.
Isolate* isolate); static std::unique_ptr<CompilationJob> CompileTopLevelOnBackgroundThread(
ParseInfo* parse_info, Isolate* isolate,
CompilationJobList* inner_function_jobs);
// Generate and install code from previously queued compilation job. // Generate and install code from previously queued compilation job.
static bool FinalizeCompilationJob(CompilationJob* job); static bool FinalizeCompilationJob(CompilationJob* job);
...@@ -128,6 +133,13 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -128,6 +133,13 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
Handle<Script> script, Handle<Script> script,
Isolate* isolate); Isolate* isolate);
// Create a shared function info object for a Script that has already been
// compiled on a background thread.
static Handle<SharedFunctionInfo> GetSharedFunctionInfoForBackgroundCompile(
Handle<Script> script, ParseInfo* parse_info, int source_length,
CompilationJob* outer_function_job,
CompilationJobList* inner_function_jobs);
// Create a shared function info object for a native function literal. // Create a shared function info object for a native function literal.
static Handle<SharedFunctionInfo> GetSharedFunctionInfoForNative( static Handle<SharedFunctionInfo> GetSharedFunctionInfoForNative(
v8::Extension* extension, Handle<String> name); v8::Extension* extension, Handle<String> name);
......
...@@ -785,10 +785,13 @@ class RuntimeCallTimer final { ...@@ -785,10 +785,13 @@ class RuntimeCallTimer final {
V(ArrayLengthSetter) \ V(ArrayLengthSetter) \
V(BoundFunctionNameGetter) \ V(BoundFunctionNameGetter) \
V(BoundFunctionLengthGetter) \ V(BoundFunctionLengthGetter) \
V(CompileBackgroundAnalyse) \
V(CompileBackgroundEval) \
V(CompileBackgroundIgnition) \
V(CompileBackgroundScript) \
V(CompileDeserialize) \ V(CompileDeserialize) \
V(CompileEval) \ V(CompileEval) \
V(CompileAnalyse) \ V(CompileAnalyse) \
V(CompileBackgroundIgnition) \
V(CompileFunction) \ V(CompileFunction) \
V(CompileGetFromOptimizedCodeMap) \ V(CompileGetFromOptimizedCodeMap) \
V(CompileIgnition) \ V(CompileIgnition) \
......
...@@ -889,6 +889,9 @@ DEFINE_BOOL(preparser_scope_analysis, true, ...@@ -889,6 +889,9 @@ DEFINE_BOOL(preparser_scope_analysis, true,
"perform scope analysis for preparsed inner functions") "perform scope analysis for preparsed inner functions")
DEFINE_IMPLICATION(preparser_scope_analysis, aggressive_lazy_inner_functions) DEFINE_IMPLICATION(preparser_scope_analysis, aggressive_lazy_inner_functions)
// compiler.cc
DEFINE_BOOL(background_compile, false, "enable background compilation")
// simulator-arm.cc, simulator-arm64.cc and simulator-mips.cc // simulator-arm.cc, simulator-arm64.cc and simulator-mips.cc
DEFINE_BOOL(trace_sim, false, "Trace simulator execution") DEFINE_BOOL(trace_sim, false, "Trace simulator execution")
DEFINE_BOOL(debug_sim, false, "Enable debugging the simulator") DEFINE_BOOL(debug_sim, false, "Enable debugging the simulator")
......
...@@ -37,41 +37,11 @@ class InterpreterCompilationJob final : public CompilationJob { ...@@ -37,41 +37,11 @@ class InterpreterCompilationJob final : public CompilationJob {
Status FinalizeJobImpl() final; Status FinalizeJobImpl() final;
private: private:
class TimerScope final {
public:
explicit TimerScope(RuntimeCallCounter* counter)
: runtime_stats_enabled_(FLAG_runtime_stats) {
if (V8_UNLIKELY(runtime_stats_enabled_ && counter != nullptr)) {
timer_.Start(counter, nullptr);
}
}
~TimerScope() {
if (V8_UNLIKELY(runtime_stats_enabled_)) {
timer_.Stop();
}
}
private:
RuntimeCallTimer timer_;
bool runtime_stats_enabled_;
DISALLOW_COPY_AND_ASSIGN(TimerScope);
};
bool executed_on_background_thread() {
// TODO(rmcilroy): Fix once we create InterpreterCompilationJob on
// background thread.
return false;
}
BytecodeGenerator* generator() { return &generator_; } BytecodeGenerator* generator() { return &generator_; }
Zone zone_; Zone zone_;
CompilationInfo compilation_info_; CompilationInfo compilation_info_;
BytecodeGenerator generator_; BytecodeGenerator generator_;
RuntimeCallStats* runtime_call_stats_;
RuntimeCallCounter background_execute_counter_;
DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob); DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
}; };
...@@ -195,24 +165,26 @@ InterpreterCompilationJob::InterpreterCompilationJob(ParseInfo* parse_info, ...@@ -195,24 +165,26 @@ InterpreterCompilationJob::InterpreterCompilationJob(ParseInfo* parse_info,
FunctionLiteral* literal, FunctionLiteral* literal,
Isolate* isolate) Isolate* isolate)
: CompilationJob(parse_info->stack_limit(), parse_info, &compilation_info_, : CompilationJob(parse_info->stack_limit(), parse_info, &compilation_info_,
"Ignition"), "Ignition", State::kReadyToExecute),
zone_(isolate->allocator(), ZONE_NAME), zone_(isolate->allocator(), ZONE_NAME),
compilation_info_(&zone_, isolate, parse_info, literal), compilation_info_(&zone_, isolate, parse_info, literal),
generator_(&compilation_info_), generator_(&compilation_info_) {}
runtime_call_stats_(isolate->counters()->runtime_call_stats()),
background_execute_counter_("CompileBackgroundIgnition") {}
InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() { InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
MaybePrintAst(parse_info(), compilation_info()); UNREACHABLE(); // Prepare should always be skipped.
return SUCCEEDED; return SUCCEEDED;
} }
InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() { InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
TimerScope runtimeTimer(
executed_on_background_thread() ? &background_execute_counter_ : nullptr);
RuntimeCallTimerScope runtimeTimerScope( RuntimeCallTimerScope runtimeTimerScope(
!executed_on_background_thread() ? runtime_call_stats_ : nullptr, parse_info()->runtime_call_stats(),
&RuntimeCallStats::CompileIgnition); parse_info()->on_background_thread()
? &RuntimeCallStats::CompileBackgroundIgnition
: &RuntimeCallStats::CompileIgnition);
// Print AST if flag is enabled. Note, if compiling on a background thread
// then ASTs from different functions may be intersperse when printed.
MaybePrintAst(parse_info(), compilation_info());
// TODO(lpy): add support for background compilation RCS trace. // TODO(lpy): add support for background compilation RCS trace.
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
...@@ -226,14 +198,8 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() { ...@@ -226,14 +198,8 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
} }
InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() { InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
// Add background runtime call stats.
if (V8_UNLIKELY(FLAG_runtime_stats && executed_on_background_thread())) {
runtime_call_stats_->CompileBackgroundIgnition.Add(
&background_execute_counter_);
}
RuntimeCallTimerScope runtimeTimerScope( RuntimeCallTimerScope runtimeTimerScope(
!executed_on_background_thread() ? runtime_call_stats_ : nullptr, parse_info()->runtime_call_stats(),
&RuntimeCallStats::CompileIgnitionFinalization); &RuntimeCallStats::CompileIgnitionFinalization);
Handle<BytecodeArray> bytecodes = generator()->FinalizeBytecode( Handle<BytecodeArray> bytecodes = generator()->FinalizeBytecode(
......
...@@ -340,15 +340,16 @@ class Logger : public CodeEventListener { ...@@ -340,15 +340,16 @@ class Logger : public CodeEventListener {
friend class CpuProfiler; friend class CpuProfiler;
}; };
#define TIMER_EVENTS_LIST(V) \ #define TIMER_EVENTS_LIST(V) \
V(RecompileSynchronous, true) \ V(RecompileSynchronous, true) \
V(RecompileConcurrent, true) \ V(RecompileConcurrent, true) \
V(CompileIgnition, true) \ V(CompileIgnition, true) \
V(CompileFullCode, true) \ V(CompileFullCode, true) \
V(OptimizeCode, true) \ V(OptimizeCode, true) \
V(CompileCode, true) \ V(CompileCode, true) \
V(DeoptimizeCode, true) \ V(CompileCodeBackground, true) \
V(Execute, true) \ V(DeoptimizeCode, true) \
V(Execute, true) \
V(External, true) V(External, true)
#define V(TimerName, expose) \ #define V(TimerName, expose) \
......
...@@ -52,8 +52,12 @@ BackgroundParsingTask::BackgroundParsingTask( ...@@ -52,8 +52,12 @@ BackgroundParsingTask::BackgroundParsingTask(
info->AllocateSourceRangeMap(); info->AllocateSourceRangeMap();
} }
info->set_cached_data(&script_data_); info->set_cached_data(&script_data_);
LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
info->set_language_mode(
stricter_language_mode(info->language_mode(), language_mode));
source->info.reset(info); source->info.reset(info);
isolate_ = isolate;
// Parser needs to stay alive for finalizing the parsing on the main // Parser needs to stay alive for finalizing the parsing on the main
// thread. // thread.
...@@ -67,12 +71,21 @@ void BackgroundParsingTask::Run() { ...@@ -67,12 +71,21 @@ void BackgroundParsingTask::Run() {
DisallowHandleAllocation no_handles; DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref; DisallowHandleDereference no_deref;
source_->info->set_on_background_thread(true);
// Reset the stack limit of the parser to reflect correctly that we're on a // Reset the stack limit of the parser to reflect correctly that we're on a
// background thread. // background thread.
uintptr_t old_stack_limit = source_->info->stack_limit();
uintptr_t stack_limit = GetCurrentStackPosition() - stack_size_ * KB; uintptr_t stack_limit = GetCurrentStackPosition() - stack_size_ * KB;
source_->info->set_stack_limit(stack_limit);
source_->parser->set_stack_limit(stack_limit); source_->parser->set_stack_limit(stack_limit);
source_->parser->ParseOnBackground(source_->info.get()); source_->parser->ParseOnBackground(source_->info.get());
if (FLAG_background_compile && source_->info->literal() != nullptr) {
// Parsing has succeeded, compile.
source_->outer_function_job = Compiler::CompileTopLevelOnBackgroundThread(
source_->info.get(), isolate_, &source_->inner_function_jobs);
}
if (script_data_ != nullptr) { if (script_data_ != nullptr) {
source_->cached_data.reset(new ScriptCompiler::CachedData( source_->cached_data.reset(new ScriptCompiler::CachedData(
...@@ -82,6 +95,9 @@ void BackgroundParsingTask::Run() { ...@@ -82,6 +95,9 @@ void BackgroundParsingTask::Run() {
delete script_data_; delete script_data_;
script_data_ = nullptr; script_data_ = nullptr;
} }
source_->info->set_on_background_thread(false);
source_->info->set_stack_limit(old_stack_limit);
} }
} // namespace internal } // namespace internal
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "include/v8.h" #include "include/v8.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/base/platform/semaphore.h" #include "src/base/platform/semaphore.h"
#include "src/compiler.h"
#include "src/parsing/parse-info.h" #include "src/parsing/parse-info.h"
#include "src/unicode-cache.h" #include "src/unicode-cache.h"
...@@ -41,6 +42,10 @@ struct StreamedSource { ...@@ -41,6 +42,10 @@ struct StreamedSource {
std::unique_ptr<ParseInfo> info; std::unique_ptr<ParseInfo> info;
std::unique_ptr<Parser> parser; std::unique_ptr<Parser> parser;
// Data needed for finalizing compilation after background compilation.
std::unique_ptr<CompilationJob> outer_function_job;
CompilationJobList inner_function_jobs;
// Prevent copying. // Prevent copying.
StreamedSource(const StreamedSource&) = delete; StreamedSource(const StreamedSource&) = delete;
StreamedSource& operator=(const StreamedSource&) = delete; StreamedSource& operator=(const StreamedSource&) = delete;
...@@ -58,7 +63,9 @@ class BackgroundParsingTask : public ScriptCompiler::ScriptStreamingTask { ...@@ -58,7 +63,9 @@ class BackgroundParsingTask : public ScriptCompiler::ScriptStreamingTask {
StreamedSource* source_; // Not owned. StreamedSource* source_; // Not owned.
int stack_size_; int stack_size_;
ScriptData* script_data_; ScriptData* script_data_;
Isolate* isolate_;
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -81,6 +81,8 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -81,6 +81,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken) FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken)
FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled, FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled,
set_block_coverage_enabled) set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
set_on_background_thread)
#undef FLAG_ACCESSOR #undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) { void set_parse_restriction(ParseRestriction restriction) {
...@@ -255,6 +257,7 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -255,6 +257,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
kCollectTypeProfile = 1 << 10, kCollectTypeProfile = 1 << 10,
kBlockCoverageEnabled = 1 << 11, kBlockCoverageEnabled = 1 << 11,
kIsAsmWasmBroken = 1 << 12, kIsAsmWasmBroken = 1 << 12,
kOnBackgroundThread = 1 << 14,
}; };
//------------- Inputs to parsing and scope analysis ----------------------- //------------- Inputs to parsing and scope analysis -----------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment