Commit 1fc93f2e authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Compiler] Enable use of seperate zones for parsing and compiling.

In order to allow parallel compilation of eager inner functions, we need to
seperate the zone used for parsing (which will be shared between all the
parallel compile jobs) and the zone used for compilation. This CL changes
CompilationInfo to require a zone (which can be different from the zone in
ParseInfo). We then seal the ParseInfo zone after parsing and analysis is done
to prevent any further allocation in that zone, so that it can be shared
(read-only) with the parallel compile jobs.

BUG=v8:5203

Review-Url: https://codereview.chromium.org/2645403002
Cr-Commit-Position: refs/heads/master@{#43089}
parent 7ef8cb56
......@@ -53,10 +53,10 @@ bool CompilationInfo::has_shared_info() const {
return parse_info_ && !parse_info_->shared_info().is_null();
}
CompilationInfo::CompilationInfo(ParseInfo* parse_info,
CompilationInfo::CompilationInfo(Zone* zone, ParseInfo* parse_info,
Handle<JSFunction> closure)
: CompilationInfo(parse_info, {}, Code::ComputeFlags(Code::FUNCTION), BASE,
parse_info->isolate(), parse_info->zone()) {
parse_info->isolate(), zone) {
closure_ = closure;
// Compiling for the snapshot typically results in different code than
......
......@@ -53,7 +53,8 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
kLoopPeelingEnabled = 1 << 16,
};
CompilationInfo(ParseInfo* parse_info, Handle<JSFunction> closure);
CompilationInfo(Zone* zone, ParseInfo* parse_info,
Handle<JSFunction> closure);
CompilationInfo(Vector<const char> debug_name, Isolate* isolate, Zone* zone,
Code::Flags code_flags);
~CompilationInfo();
......
......@@ -97,8 +97,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
max_stack_size_(max_stack_size),
parse_info_(
new ParseInfo(Handle<Script>(Script::cast(shared->script())))),
compile_info_(
new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())),
compile_info_(new CompilationInfo(parse_info_->zone(), parse_info_.get(),
Handle<JSFunction>::null())),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
parse_info_->set_literal(literal);
parse_info_->set_shared_info(shared);
......@@ -318,8 +318,8 @@ bool CompilerDispatcherJob::AnalyzeOnMainThread() {
PrintF("CompilerDispatcherJob[%p]: Analyzing\n", static_cast<void*>(this));
}
compile_info_.reset(
new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null()));
compile_info_.reset(new CompilationInfo(
parse_info_->zone(), parse_info_.get(), Handle<JSFunction>::null()));
DeferredHandleScope scope(isolate_);
{
......
......@@ -28,7 +28,6 @@ class SharedFunctionInfo;
class String;
class UnicodeCache;
class Utf16CharacterStream;
class Zone;
enum class CompileJobStatus {
kInitial,
......
......@@ -383,12 +383,14 @@ bool UseAsmWasm(DeclarationScope* scope, Handle<SharedFunctionInfo> shared_info,
!shared_info->is_asm_wasm_broken() && !is_debug;
}
bool UseCompilerDispatcher(CompilerDispatcher* dispatcher,
bool UseCompilerDispatcher(Compiler::ConcurrencyMode inner_function_mode,
CompilerDispatcher* dispatcher,
DeclarationScope* scope,
Handle<SharedFunctionInfo> shared_info,
bool is_debug, bool will_serialize) {
return FLAG_compiler_dispatcher_eager_inner && dispatcher->IsEnabled() &&
!is_debug && !will_serialize &&
return FLAG_compiler_dispatcher_eager_inner &&
inner_function_mode == Compiler::CONCURRENT &&
dispatcher->IsEnabled() && !is_debug && !will_serialize &&
!UseAsmWasm(scope, shared_info, is_debug);
}
......@@ -509,6 +511,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
bool CompileUnoptimizedInnerFunctions(
Compiler::EagerInnerFunctionLiterals* literals,
Compiler::ConcurrencyMode inner_function_mode,
CompilationInfo* outer_info) {
Isolate* isolate = outer_info->isolate();
Handle<Script> script = outer_info->script();
......@@ -529,8 +532,8 @@ bool CompileUnoptimizedInnerFunctions(
// Try to enqueue the eager function on the compiler dispatcher.
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (UseCompilerDispatcher(dispatcher, literal->scope(), shared, is_debug,
will_serialize) &&
if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(),
shared, is_debug, will_serialize) &&
dispatcher->EnqueueAndStep(shared, literal)) {
// If we have successfully queued up the function for compilation on the
// compiler dispatcher then we are done.
......@@ -538,7 +541,8 @@ bool CompileUnoptimizedInnerFunctions(
} else {
// Otherwise generate unoptimized code now.
ParseInfo parse_info(script);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
CompilationInfo info(parse_info.zone(), &parse_info,
Handle<JSFunction>::null());
parse_info.set_literal(literal);
parse_info.set_shared_info(shared);
......@@ -560,13 +564,43 @@ bool CompileUnoptimizedInnerFunctions(
return true;
}
bool CompileUnoptimizedCode(CompilationInfo* info) {
bool InnerFunctionIsAsmModule(
ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* literals) {
for (auto it : *literals) {
FunctionLiteral* literal = it->value();
if (literal->scope()->IsAsmModule()) return true;
}
return false;
}
bool CompileUnoptimizedCode(CompilationInfo* info,
Compiler::ConcurrencyMode inner_function_mode) {
Isolate* isolate = info->isolate();
DCHECK(AllowCompilation::IsAllowed(isolate));
Compiler::EagerInnerFunctionLiterals inner_literals;
if (!Compiler::Analyze(info->parse_info(), &inner_literals) ||
!CompileUnoptimizedInnerFunctions(&inner_literals, info) ||
if (!Compiler::Analyze(info->parse_info(), &inner_literals)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
}
// Disable concurrent inner compilation for asm-wasm code.
// TODO(rmcilroy,bradnelson): Remove this AsmWasm check once the asm-wasm
// builder doesn't do parsing when visiting function declarations.
if (info->scope()->IsAsmModule() ||
InnerFunctionIsAsmModule(&inner_literals)) {
inner_function_mode = Compiler::NOT_CONCURRENT;
}
if (inner_function_mode == Compiler::CONCURRENT) {
// Seal the parse zone so that it can be shared by parallel inner function
// compilation jobs.
DCHECK_NE(info->parse_info()->zone(), info->zone());
info->parse_info()->zone()->Seal();
}
if (!CompileUnoptimizedInnerFunctions(&inner_literals, inner_function_mode,
info) ||
!GenerateUnoptimizedCode(info)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
......@@ -600,7 +634,8 @@ void EnsureSharedFunctionInfosArrayOnScript(ParseInfo* info) {
info->script()->set_shared_function_infos(*infos);
}
MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(
CompilationInfo* info, Compiler::ConcurrencyMode inner_function_mode) {
RuntimeCallTimerScope runtimeTimer(
info->isolate(), &RuntimeCallStats::CompileGetUnoptimizedCode);
VMState<COMPILER> state(info->isolate());
......@@ -615,7 +650,9 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
info->literal()->language_mode());
// Compile either unoptimized code or bytecode for the interpreter.
if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
if (!CompileUnoptimizedCode(info, inner_function_mode)) {
return MaybeHandle<Code>();
}
// Record the function compilation event.
RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info);
......@@ -925,7 +962,7 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) {
VMState<COMPILER> state(isolate);
PostponeInterruptsScope postpone(isolate);
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
DCHECK(function->shared()->is_compiled());
......@@ -1058,9 +1095,11 @@ MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
}
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
Zone compile_zone(isolate->allocator(), ZONE_NAME);
CompilationInfo info(&compile_zone, &parse_info, function);
Handle<Code> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCode(&info), Code);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, GetUnoptimizedCode(&info, Compiler::CONCURRENT), Code);
if (FLAG_always_opt && !info.shared_info()->HasAsmWasmData()) {
Handle<Code> opt_code;
......@@ -1121,7 +1160,7 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
parse_info->set_function_literal_id(result->function_literal_id());
// Compile the code.
if (!CompileUnoptimizedCode(info)) {
if (!CompileUnoptimizedCode(info, Compiler::CONCURRENT)) {
return Handle<SharedFunctionInfo>::null();
}
......@@ -1230,20 +1269,11 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function,
// Start a compilation.
Handle<Code> code;
if (!GetOptimizedCode(function, mode).ToHandle(&code)) {
// Optimization failed, get unoptimized code.
// Optimization failed, get unoptimized code. Unoptimized code must exist
// already if we are optimizing.
DCHECK(!isolate->has_pending_exception());
if (function->shared()->is_compiled()) {
code = handle(function->shared()->code(), isolate);
} else if (function->shared()->HasBytecodeArray()) {
code = isolate->builtins()->InterpreterEntryTrampoline();
function->shared()->ReplaceCode(*code);
} else {
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
if (!GetUnoptimizedCode(&info).ToHandle(&code)) {
return false;
}
}
DCHECK(function->shared()->is_compiled());
code = handle(function->shared()->code(), isolate);
}
// Install code on closure.
......@@ -1263,9 +1293,10 @@ bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
// Start a compilation.
ParseInfo parse_info(shared);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
CompilationInfo info(parse_info.zone(), &parse_info,
Handle<JSFunction>::null());
info.MarkAsDebug();
if (GetUnoptimizedCode(&info).is_null()) {
if (GetUnoptimizedCode(&info, Compiler::NOT_CONCURRENT).is_null()) {
isolate->clear_pending_exception();
return false;
}
......@@ -1290,7 +1321,8 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
// Start a compilation.
ParseInfo parse_info(script);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
Zone compile_zone(isolate->allocator(), ZONE_NAME);
CompilationInfo info(&compile_zone, &parse_info, Handle<JSFunction>::null());
info.MarkAsDebug();
// TODO(635): support extensions.
......@@ -1313,7 +1345,9 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
bool Compiler::EnsureBytecode(CompilationInfo* info) {
if (!info->shared_info()->is_compiled()) {
if (GetUnoptimizedCode(info).is_null()) return false;
if (GetUnoptimizedCode(info, Compiler::NOT_CONCURRENT).is_null()) {
return false;
}
}
DCHECK(info->shared_info()->is_compiled());
......@@ -1330,8 +1364,9 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
DCHECK_NOT_NULL(info->scope());
Handle<SharedFunctionInfo> shared = info->shared_info();
if (!shared->has_deoptimization_support()) {
Zone zone(info->isolate()->allocator(), ZONE_NAME);
CompilationInfo unoptimized(info->parse_info(), info->closure());
Zone compile_zone(info->isolate()->allocator(), ZONE_NAME);
CompilationInfo unoptimized(&compile_zone, info->parse_info(),
info->closure());
unoptimized.EnableDeoptimizationSupport();
// Don't generate full-codegen code for functions it can't support.
......@@ -1431,7 +1466,9 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
Script::SetEvalOrigin(script, outer_info, eval_position);
ParseInfo parse_info(script);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
Zone compile_zone(isolate->allocator(), ZONE_NAME);
CompilationInfo info(&compile_zone, &parse_info,
Handle<JSFunction>::null());
parse_info.set_eval();
parse_info.set_language_mode(language_mode);
parse_info.set_parse_restriction(restriction);
......@@ -1639,7 +1676,9 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
// Compile the function and add it to the cache.
ParseInfo parse_info(script);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
Zone compile_zone(isolate->allocator(), ZONE_NAME);
CompilationInfo info(&compile_zone, &parse_info,
Handle<JSFunction>::null());
if (resource_options.IsModule()) parse_info.set_module();
if (compile_options != ScriptCompiler::kNoCompileOptions) {
parse_info.set_cached_data(cached_data);
......@@ -1706,7 +1745,9 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript(
parse_info->set_language_mode(
static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
CompilationInfo compile_info(parse_info, Handle<JSFunction>::null());
Zone compile_zone(isolate->allocator(), ZONE_NAME);
CompilationInfo compile_info(&compile_zone, parse_info,
Handle<JSFunction>::null());
// The source was parsed lazily, so compiling for debugging is not possible.
DCHECK(!compile_info.is_debug());
......
......@@ -550,7 +550,8 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
}
ParseInfo parse_info(shared_info);
CompilationInfo info(&parse_info, Handle<JSFunction>::null());
CompilationInfo info(parse_info.zone(), &parse_info,
Handle<JSFunction>::null());
if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
info.MarkAsOptimizeFromBytecode();
......
......@@ -551,7 +551,7 @@ class PipelineCompilationJob final : public CompilationJob {
: CompilationJob(isolate, &info_, "TurboFan"),
parse_info_(handle(function->shared())),
zone_stats_(isolate->allocator()),
info_(&parse_info_, function),
info_(parse_info_.zone(), &parse_info_, function),
pipeline_statistics_(CreatePipelineStatistics(info(), &zone_stats_)),
data_(&zone_stats_, info(), pipeline_statistics_.get()),
pipeline_(&data_),
......
......@@ -8043,7 +8043,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
top_info()->parse_info()->ast_value_factory());
parse_info.set_ast_value_factory_owned(false);
CompilationInfo target_info(&parse_info, target);
CompilationInfo target_info(parse_info.zone(), &parse_info, target);
if (inlining_kind != CONSTRUCT_CALL_RETURN &&
IsClassConstructor(target_shared->kind())) {
......
......@@ -39,7 +39,7 @@ class HCompilationJob final : public CompilationJob {
explicit HCompilationJob(Handle<JSFunction> function)
: CompilationJob(function->GetIsolate(), &info_, "Crankshaft"),
parse_info_(handle(function->shared())),
info_(&parse_info_, function),
info_(parse_info_.zone(), &parse_info_, function),
graph_(nullptr),
chunk_(nullptr) {}
......
......@@ -49,7 +49,8 @@ Zone::Zone(AccountingAllocator* allocator, const char* name)
limit_(0),
allocator_(allocator),
segment_head_(nullptr),
name_(name) {
name_(name),
sealed_(false) {
allocator_->ZoneCreation(this);
}
......@@ -62,6 +63,8 @@ Zone::~Zone() {
}
void* Zone::New(size_t size) {
CHECK(!sealed_);
// Round up the requested size to fit the alignment.
size = RoundUp(size, kAlignmentInBytes);
......
......@@ -50,6 +50,9 @@ class V8_EXPORT_PRIVATE Zone final {
return static_cast<T*>(New(length * sizeof(T)));
}
// Seals the zone to prevent any further allocation.
void Seal() { sealed_ = true; }
// Returns true if more memory has been allocated in zones than
// the limit allows.
bool excess_allocation() const {
......@@ -106,6 +109,7 @@ class V8_EXPORT_PRIVATE Zone final {
Segment* segment_head_;
const char* name_;
bool sealed_;
};
// ZoneObject is an abstraction that helps define classes of objects
......
......@@ -156,7 +156,7 @@ Handle<JSFunction> FunctionTester::ForMachineGraph(Graph* graph,
Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
info.SetOptimizing();
info.MarkAsDeoptimizationEnabled();
......@@ -185,7 +185,7 @@ Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
// and replace the JSFunction's code with the result.
Handle<JSFunction> FunctionTester::CompileGraph(Graph* graph) {
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
CHECK(parsing::ParseFunction(info.parse_info()));
info.SetOptimizing();
......
......@@ -44,7 +44,7 @@ TEST(TestLinkageCreate) {
HandleAndZoneScope handles;
Handle<JSFunction> function = Compile("a + b");
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info);
CHECK(descriptor);
}
......@@ -60,7 +60,7 @@ TEST(TestLinkageJSFunctionIncoming) {
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(sources[i]))));
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info);
CHECK(descriptor);
......@@ -76,7 +76,7 @@ TEST(TestLinkageJSCall) {
HandleAndZoneScope handles;
Handle<JSFunction> function = Compile("a + c");
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
for (int i = 0; i < 32; i++) {
CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(
......
......@@ -34,7 +34,7 @@ struct TestHelper : public HandleAndZoneScope {
void CheckLoopAssignedCount(int expected, const char* var_name) {
// TODO(titzer): don't scope analyze every single time.
ParseInfo parse_info(handle(function->shared()));
CompilationInfo info(&parse_info, function);
CompilationInfo info(parse_info.zone(), &parse_info, function);
CHECK(parsing::ParseFunction(&parse_info));
CHECK(Rewriter::Rewrite(&parse_info));
......
......@@ -124,7 +124,7 @@ class BytecodeGraphTester {
// having to instantiate a ParseInfo first. Fix this!
ParseInfo parse_info(handle(function->shared()));
CompilationInfo compilation_info(&parse_info, function);
CompilationInfo compilation_info(parse_info.zone(), &parse_info, function);
compilation_info.SetOptimizing();
compilation_info.MarkAsDeoptimizationEnabled();
compilation_info.MarkAsOptimizeFromBytecode();
......
......@@ -29,7 +29,7 @@ class BlockingCompilationJob : public CompilationJob {
: CompilationJob(isolate, &info_, "BlockingCompilationJob",
State::kReadyToExecute),
parse_info_(handle(function->shared())),
info_(&parse_info_, function),
info_(parse_info_.zone(), &parse_info_, function),
blocking_(false),
semaphore_(0) {}
~BlockingCompilationJob() override = default;
......
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