Commit 198deea2 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[compiler] Off-thread finalize each function immediately

Allow "iterative" finalization when off-thread finalization is enabled,
meaning that each compiled function is finalized immediately after
compilation, rather than all functions being first compiled and then
finalized.

This is what we do on the main thread, and it reduces peak Zone memory
usage by being able to discard empty compilation Zones earlier.

One necessary functionality for this was being able to defer the
finalization of asm.js functions until the main thread pause, since
they can't be finalized off-thread -- previously we would just bail
out of doing the off-thread finalization if any inner function was
asm.js.

Bug: chromium:1011762
Change-Id: I21ff69d62eaa93b5ff908624b7115601e36f70f1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2282536Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69032}
parent fddd23c0
...@@ -187,8 +187,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob { ...@@ -187,8 +187,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob {
explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal, explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator) AccountingAllocator* allocator)
: UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info, : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
&compilation_info_, &compilation_info_),
CanOffThreadFinalize::kNo),
allocator_(allocator), allocator_(allocator),
zone_(allocator, ZONE_NAME), zone_(allocator, ZONE_NAME),
compilation_info_(&zone_, parse_info, literal), compilation_info_(&zone_, parse_info, literal),
...@@ -203,7 +202,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob { ...@@ -203,7 +202,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob {
Isolate* isolate) final; Isolate* isolate) final;
Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info, Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
OffThreadIsolate* isolate) final { OffThreadIsolate* isolate) final {
UNREACHABLE(); return CompilationJob::RETRY_ON_MAIN_THREAD;
} }
private: private:
...@@ -278,8 +277,8 @@ UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl( ...@@ -278,8 +277,8 @@ UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl(
RecordHistograms(isolate); RecordHistograms(isolate);
ReportCompilationSuccess(handle(Script::cast(shared_info->script()), isolate), ReportCompilationSuccess(handle(Script::cast(shared_info->script()), isolate),
compilation_info()->literal()->position(), shared_info->StartPosition(), compile_time_,
compile_time_, module_->size()); module_->size());
return SUCCEEDED; return SUCCEEDED;
} }
......
...@@ -548,13 +548,6 @@ template <typename LocalIsolate> ...@@ -548,13 +548,6 @@ template <typename LocalIsolate>
void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info, void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info,
LocalIsolate* isolate) { LocalIsolate* isolate) {
DCHECK_EQ(shared_info->language_mode(),
compilation_info->literal()->language_mode());
// Update the shared function info with the scope info.
Handle<ScopeInfo> scope_info = compilation_info->scope()->scope_info();
shared_info->set_scope_info(*scope_info);
if (compilation_info->has_bytecode_array()) { if (compilation_info->has_bytecode_array()) {
DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once. DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once.
DCHECK(!compilation_info->has_asm_wasm_data()); DCHECK(!compilation_info->has_asm_wasm_data());
...@@ -622,8 +615,10 @@ void EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script, ...@@ -622,8 +615,10 @@ void EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script,
script->set_shared_function_infos(*infos); script->set_shared_function_infos(*infos);
} }
void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal, void UpdateSharedFunctionFlagsAfterCompilation(FunctionLiteral* literal,
SharedFunctionInfo shared_info) { SharedFunctionInfo shared_info) {
DCHECK_EQ(shared_info.language_mode(), literal->language_mode());
shared_info.set_has_duplicate_parameters(literal->has_duplicate_parameters()); shared_info.set_has_duplicate_parameters(literal->has_duplicate_parameters());
shared_info.set_is_oneshot_iife(literal->is_oneshot_iife()); shared_info.set_is_oneshot_iife(literal->is_oneshot_iife());
shared_info.UpdateAndFinalizeExpectedNofPropertiesFromEstimate(literal); shared_info.UpdateAndFinalizeExpectedNofPropertiesFromEstimate(literal);
...@@ -637,8 +632,13 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal, ...@@ -637,8 +632,13 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal,
literal->SafeToSkipArgumentsAdaptor()); literal->SafeToSkipArgumentsAdaptor());
shared_info.set_has_static_private_methods_or_accessors( shared_info.set_has_static_private_methods_or_accessors(
literal->has_static_private_methods_or_accessors()); literal->has_static_private_methods_or_accessors());
shared_info.set_scope_info(*literal->scope()->scope_info());
} }
// Finalize a single compilation job. This function can return
// RETRY_ON_MAIN_THREAD if the job cannot be finalized off-thread, in which case
// it should be safe to call it again on the main thread with the same job.
template <typename LocalIsolate> template <typename LocalIsolate>
CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob( CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info, UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
...@@ -647,8 +647,6 @@ CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob( ...@@ -647,8 +647,6 @@ CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
finalize_unoptimized_compilation_data_list) { finalize_unoptimized_compilation_data_list) {
UnoptimizedCompilationInfo* compilation_info = job->compilation_info(); UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), *shared_info);
CompilationJob::Status status = job->FinalizeJob(shared_info, isolate); CompilationJob::Status status = job->FinalizeJob(shared_info, isolate);
if (status == CompilationJob::SUCCEEDED) { if (status == CompilationJob::SUCCEEDED) {
InstallUnoptimizedCode(compilation_info, shared_info, isolate); InstallUnoptimizedCode(compilation_info, shared_info, isolate);
...@@ -656,6 +654,8 @@ CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob( ...@@ -656,6 +654,8 @@ CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
isolate, shared_info, job->time_taken_to_execute(), isolate, shared_info, job->time_taken_to_execute(),
job->time_taken_to_finalize()); job->time_taken_to_finalize());
} }
DCHECK_IMPLIES(status == CompilationJob::RETRY_ON_MAIN_THREAD,
(std::is_same<LocalIsolate, OffThreadIsolate>::value));
return status; return status;
} }
...@@ -688,37 +688,38 @@ ExecuteSingleUnoptimizedCompilationJob( ...@@ -688,37 +688,38 @@ ExecuteSingleUnoptimizedCompilationJob(
return job; return job;
} }
std::unique_ptr<UnoptimizedCompilationJob> bool RecursivelyExecuteUnoptimizedCompilationJobs(
RecursivelyExecuteUnoptimizedCompilationJobs(
ParseInfo* parse_info, FunctionLiteral* literal, ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator, AccountingAllocator* allocator,
UnoptimizedCompilationJobList* inner_function_jobs) { UnoptimizedCompilationJobList* function_jobs) {
std::vector<FunctionLiteral*> eager_inner_literals; std::vector<FunctionLiteral*> eager_inner_literals;
std::unique_ptr<UnoptimizedCompilationJob> job = std::unique_ptr<UnoptimizedCompilationJob> job =
ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator, ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
&eager_inner_literals); &eager_inner_literals);
if (!job) return std::unique_ptr<UnoptimizedCompilationJob>(); if (!job) return false;
// Recursively compile eager inner literals. // Recursively compile eager inner literals.
for (FunctionLiteral* inner_literal : eager_inner_literals) { for (FunctionLiteral* inner_literal : eager_inner_literals) {
std::unique_ptr<UnoptimizedCompilationJob> inner_job( if (!RecursivelyExecuteUnoptimizedCompilationJobs(
RecursivelyExecuteUnoptimizedCompilationJobs( parse_info, inner_literal, allocator, function_jobs)) {
parse_info, inner_literal, allocator, inner_function_jobs)); return false;
// Compilation failed, return null. }
if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>();
inner_function_jobs->emplace_front(std::move(inner_job));
} }
return job; function_jobs->emplace_front(std::move(job));
return true;
} }
template <typename LocalIsolate>
bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs( bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
Isolate* isolate, Handle<SharedFunctionInfo> outer_shared_info, LocalIsolate* isolate, Handle<SharedFunctionInfo> outer_shared_info,
Handle<Script> script, ParseInfo* parse_info, Handle<Script> script, ParseInfo* parse_info,
AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope, AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope,
FinalizeUnoptimizedCompilationDataList* FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) { finalize_unoptimized_compilation_data_list,
DeferredFinalizationJobDataList*
jobs_to_retry_finalization_on_main_thread) {
DeclarationScope::AllocateScopeInfos(parse_info, isolate); DeclarationScope::AllocateScopeInfos(parse_info, isolate);
std::vector<FunctionLiteral*> functions_to_compile; std::vector<FunctionLiteral*> functions_to_compile;
...@@ -736,17 +737,36 @@ bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs( ...@@ -736,17 +737,36 @@ bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
&functions_to_compile); &functions_to_compile);
if (!job) return false; if (!job) return false;
if (FinalizeSingleUnoptimizedCompilationJob( UpdateSharedFunctionFlagsAfterCompilation(literal, *shared_info);
job.get(), shared_info, isolate,
finalize_unoptimized_compilation_data_list) != auto finalization_status = FinalizeSingleUnoptimizedCompilationJob(
CompilationJob::SUCCEEDED) { job.get(), shared_info, isolate,
return false; finalize_unoptimized_compilation_data_list);
}
switch (finalization_status) {
case CompilationJob::SUCCEEDED:
if (shared_info.is_identical_to(outer_shared_info)) {
// Ensure that the top level function is retained.
*is_compiled_scope = shared_info->is_compiled_scope(isolate);
DCHECK(is_compiled_scope->is_compiled());
}
break;
case CompilationJob::FAILED:
return false;
case CompilationJob::RETRY_ON_MAIN_THREAD:
// This should not happen on the main thread.
DCHECK((!std::is_same<LocalIsolate, Isolate>::value));
DCHECK_NOT_NULL(jobs_to_retry_finalization_on_main_thread);
if (shared_info.is_identical_to(outer_shared_info)) { // Clear the literal and ParseInfo to prevent further attempts to access
// Ensure that the top level function is retained. // them.
*is_compiled_scope = shared_info->is_compiled_scope(isolate); job->compilation_info()->ClearLiteral();
DCHECK(is_compiled_scope->is_compiled()); job->ClearParseInfo();
jobs_to_retry_finalization_on_main_thread->emplace_back(
isolate, shared_info, std::move(job));
break;
} }
} }
...@@ -758,16 +778,13 @@ bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs( ...@@ -758,16 +778,13 @@ bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
return true; return true;
} }
template <typename LocalIsolate>
bool FinalizeAllUnoptimizedCompilationJobs( bool FinalizeAllUnoptimizedCompilationJobs(
ParseInfo* parse_info, LocalIsolate* isolate, ParseInfo* parse_info, Isolate* isolate, Handle<Script> script,
Handle<SharedFunctionInfo> shared_info, UnoptimizedCompilationJobList* compilation_jobs,
UnoptimizedCompilationJob* outer_function_job,
UnoptimizedCompilationJobList* inner_function_jobs,
FinalizeUnoptimizedCompilationDataList* FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) { finalize_unoptimized_compilation_data_list) {
// TODO(leszeks): Re-enable. DCHECK(AllowCompilation::IsAllowed(isolate));
// DCHECK(AllowCompilation::IsAllowed(isolate)); DCHECK(!compilation_jobs->empty());
// TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't // TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't
// rely on accessing native context during finalization. // rely on accessing native context during finalization.
...@@ -775,26 +792,16 @@ bool FinalizeAllUnoptimizedCompilationJobs( ...@@ -775,26 +792,16 @@ bool FinalizeAllUnoptimizedCompilationJobs(
// Allocate scope infos for the literal. // Allocate scope infos for the literal.
DeclarationScope::AllocateScopeInfos(parse_info, isolate); DeclarationScope::AllocateScopeInfos(parse_info, isolate);
// Finalize the outer-most function's compilation job. // Finalize the functions' compilation jobs.
if (FinalizeSingleUnoptimizedCompilationJob( for (auto&& job : *compilation_jobs) {
outer_function_job, shared_info, isolate, FunctionLiteral* literal = job->compilation_info()->literal();
finalize_unoptimized_compilation_data_list) != Handle<SharedFunctionInfo> shared_info =
CompilationJob::SUCCEEDED) { Compiler::GetSharedFunctionInfo(literal, script, isolate);
return false;
}
Handle<Script> script(Script::cast(shared_info->script()), isolate);
parse_info->CheckFlagsForFunctionFromScript(*script);
// Finalize the inner functions' compilation jobs.
for (auto&& inner_job : *inner_function_jobs) {
Handle<SharedFunctionInfo> inner_shared_info =
Compiler::GetSharedFunctionInfo(
inner_job->compilation_info()->literal(), script, isolate);
// The inner function might be compiled already if compiling for debug. // The inner function might be compiled already if compiling for debug.
if (inner_shared_info->is_compiled()) continue; if (shared_info->is_compiled()) continue;
UpdateSharedFunctionFlagsAfterCompilation(literal, *shared_info);
if (FinalizeSingleUnoptimizedCompilationJob( if (FinalizeSingleUnoptimizedCompilationJob(
inner_job.get(), inner_shared_info, isolate, job.get(), shared_info, isolate,
finalize_unoptimized_compilation_data_list) != finalize_unoptimized_compilation_data_list) !=
CompilationJob::SUCCEEDED) { CompilationJob::SUCCEEDED) {
return false; return false;
...@@ -809,6 +816,38 @@ bool FinalizeAllUnoptimizedCompilationJobs( ...@@ -809,6 +816,38 @@ bool FinalizeAllUnoptimizedCompilationJobs(
return true; return true;
} }
bool FinalizeDeferredUnoptimizedCompilationJobs(
Isolate* isolate, Handle<Script> script,
DeferredFinalizationJobDataList* deferred_jobs,
PendingCompilationErrorHandler* pending_error_handler,
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) {
DCHECK(AllowCompilation::IsAllowed(isolate));
if (deferred_jobs->empty()) return true;
// TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't
// rely on accessing native context during finalization.
// Finalize the deferred compilation jobs.
for (auto&& job : *deferred_jobs) {
Handle<SharedFunctionInfo> shared_info = job.function_handle();
if (FinalizeSingleUnoptimizedCompilationJob(
job.job(), shared_info, isolate,
finalize_unoptimized_compilation_data_list) !=
CompilationJob::SUCCEEDED) {
return false;
}
}
// Report any warnings generated during deferred finalization.
if (pending_error_handler->has_pending_warnings()) {
pending_error_handler->PrepareWarnings(isolate);
}
return true;
}
V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache( V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache(
Handle<JSFunction> function, BailoutId osr_offset) { Handle<JSFunction> function, BailoutId osr_offset) {
RuntimeCallTimerScope runtimeTimer( RuntimeCallTimerScope runtimeTimer(
...@@ -1243,7 +1282,8 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel( ...@@ -1243,7 +1282,8 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs( if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
isolate, shared_info, script, parse_info, isolate->allocator(), isolate, shared_info, script, parse_info, isolate->allocator(),
is_compiled_scope, &finalize_unoptimized_compilation_data_list)) { is_compiled_scope, &finalize_unoptimized_compilation_data_list,
nullptr)) {
FailWithPendingException(isolate, script, parse_info, FailWithPendingException(isolate, script, parse_info,
Compiler::ClearExceptionFlag::KEEP_EXCEPTION); Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
...@@ -1258,34 +1298,73 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel( ...@@ -1258,34 +1298,73 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
return shared_info; return shared_info;
} }
std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread( RuntimeCallCounterId RuntimeCallCounterIdForCompileBackground(
ParseInfo* parse_info) {
if (parse_info->flags().is_toplevel()) {
if (parse_info->flags().is_eval()) {
return RuntimeCallCounterId::kCompileBackgroundEval;
}
return RuntimeCallCounterId::kCompileBackgroundScript;
}
return RuntimeCallCounterId::kCompileBackgroundFunction;
}
MaybeHandle<SharedFunctionInfo> CompileAndFinalizeOnBackgroundThread(
ParseInfo* parse_info, AccountingAllocator* allocator, ParseInfo* parse_info, AccountingAllocator* allocator,
UnoptimizedCompilationJobList* inner_function_jobs) { Handle<Script> script, OffThreadIsolate* isolate,
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list,
DeferredFinalizationJobDataList*
jobs_to_retry_finalization_on_main_thread) {
DisallowHeapAccess no_heap_access; DisallowHeapAccess no_heap_access;
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileCodeBackground"); "V8.CompileCodeBackground");
RuntimeCallTimerScope runtimeTimer( RuntimeCallTimerScope runtimeTimer(
parse_info->runtime_call_stats(), parse_info->runtime_call_stats(),
parse_info->flags().is_toplevel() RuntimeCallCounterIdForCompileBackground(parse_info));
? parse_info->flags().is_eval()
? RuntimeCallCounterId::kCompileBackgroundEval
: RuntimeCallCounterId::kCompileBackgroundScript
: RuntimeCallCounterId::kCompileBackgroundFunction);
// Generate the unoptimized bytecode or asm-js data. Handle<SharedFunctionInfo> shared_info =
DCHECK(inner_function_jobs->empty()); CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
// TODO(leszeks): Consider persisting the is_compiled_scope across the
// off-thread publish.
IsCompiledScope is_compiled_scope;
// TODO(leszeks): Once we can handle asm-js without bailing out of if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
// off-thread finalization entirely, and the finalization is off-thread by isolate, shared_info, script, parse_info, allocator,
// default, this can be changed to the iterative version. &is_compiled_scope, finalize_unoptimized_compilation_data_list,
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job = jobs_to_retry_finalization_on_main_thread)) {
RecursivelyExecuteUnoptimizedCompilationJobs( return kNullMaybeHandle;
parse_info, parse_info->literal(), allocator, inner_function_jobs); }
// Character stream shouldn't be used again. // Character stream shouldn't be used again.
parse_info->ResetCharacterStream(); parse_info->ResetCharacterStream();
return outer_function_job; return shared_info;
}
// TODO(leszeks): Remove this once off-thread finalization is always on.
void CompileOnBackgroundThread(ParseInfo* parse_info,
AccountingAllocator* allocator,
UnoptimizedCompilationJobList* jobs) {
DisallowHeapAccess no_heap_access;
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileCodeBackground");
RuntimeCallTimerScope runtimeTimer(
parse_info->runtime_call_stats(),
RuntimeCallCounterIdForCompileBackground(parse_info));
// Generate the unoptimized bytecode or asm-js data.
DCHECK(jobs->empty());
bool success = RecursivelyExecuteUnoptimizedCompilationJobs(
parse_info, parse_info->literal(), allocator, jobs);
USE(success);
DCHECK_EQ(success, !jobs->empty());
// Character stream shouldn't be used again.
parse_info->ResetCharacterStream();
} }
MaybeHandle<SharedFunctionInfo> CompileToplevel( MaybeHandle<SharedFunctionInfo> CompileToplevel(
...@@ -1406,20 +1485,6 @@ class OffThreadParseInfoScope { ...@@ -1406,20 +1485,6 @@ class OffThreadParseInfoScope {
DISALLOW_COPY_AND_ASSIGN(OffThreadParseInfoScope); DISALLOW_COPY_AND_ASSIGN(OffThreadParseInfoScope);
}; };
bool CanOffThreadFinalizeAllJobs(
UnoptimizedCompilationJob* outer_job,
const UnoptimizedCompilationJobList& inner_function_jobs) {
if (!outer_job->can_off_thread_finalize()) return false;
for (auto& job : inner_function_jobs) {
if (!job->can_off_thread_finalize()) {
return false;
}
}
return true;
}
} // namespace } // namespace
void BackgroundCompileTask::Run() { void BackgroundCompileTask::Run() {
...@@ -1448,87 +1513,62 @@ void BackgroundCompileTask::Run() { ...@@ -1448,87 +1513,62 @@ void BackgroundCompileTask::Run() {
parser_->ParseOnBackground(info_.get(), start_position_, end_position_, parser_->ParseOnBackground(info_.get(), start_position_, end_position_,
function_literal_id_); function_literal_id_);
if (info_->literal() != nullptr) {
// Parsing has succeeded, compile.
outer_function_job_ = CompileOnBackgroundThread(
info_.get(), compile_state_.allocator(), &inner_function_jobs_);
}
// Save the language mode and record whether we collected source positions.
language_mode_ = info_->language_mode();
// We don't currently support off-thread finalization for some jobs (namely, // Save the language mode.
// asm.js), so release the off-thread isolate and fall back to main-thread language_mode_ = info_->language_mode();
// finalization.
// TODO(leszeks): Still finalize Ignition tasks on the background thread,
// and fallback to main-thread finalization for asm.js jobs only.
finalize_on_background_thread_ =
finalize_on_background_thread_ && outer_function_job_ &&
CanOffThreadFinalizeAllJobs(outer_function_job(), *inner_function_jobs());
if (!finalize_on_background_thread_) { if (!finalize_on_background_thread_) {
off_thread_isolate_.reset(); if (info_->literal() != nullptr) {
return; CompileOnBackgroundThread(info_.get(), compile_state_.allocator(),
} &compilation_jobs_);
}
// --- } else {
// At this point, off-thread compilation has completed and we are off-thread DCHECK(info_->flags().is_toplevel());
// finalizing.
// ---
DCHECK(info_->flags().is_toplevel());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.FinalizeCodeBackground");
OffThreadIsolate* isolate = off_thread_isolate();
isolate->PinToCurrentThread();
OffThreadHandleScope handle_scope(isolate); OffThreadIsolate* isolate = off_thread_isolate();
isolate->PinToCurrentThread();
// We don't have the script source, origin, or details yet, so use default OffThreadHandleScope handle_scope(isolate);
// values for them. These will be fixed up during the main-thread merge.
Handle<Script> script =
info_->CreateScript(isolate, isolate->factory()->empty_string(),
kNullMaybeHandle, ScriptOriginOptions());
MaybeHandle<SharedFunctionInfo> maybe_result;
if (info_->literal() != nullptr) {
info_->ast_value_factory()->Internalize(isolate); info_->ast_value_factory()->Internalize(isolate);
Handle<SharedFunctionInfo> shared_info = // We don't have the script source, origin, or details yet, so use default
CreateTopLevelSharedFunctionInfo(info_.get(), script, isolate); // values for them. These will be fixed up during the main-thread merge.
if (FinalizeAllUnoptimizedCompilationJobs( Handle<Script> script =
info_.get(), isolate, shared_info, outer_function_job_.get(), info_->CreateScript(isolate, isolate->factory()->empty_string(),
&inner_function_jobs_, &finalize_unoptimized_compilation_data_)) { kNullMaybeHandle, ScriptOriginOptions());
maybe_result = shared_info;
}
parser_->HandleSourceURLComments(isolate, script); parser_->HandleSourceURLComments(isolate, script);
} else {
DCHECK(!outer_function_job_);
}
Handle<SharedFunctionInfo> result; MaybeHandle<SharedFunctionInfo> maybe_result;
if (!maybe_result.ToHandle(&result)) { if (info_->literal() != nullptr) {
DCHECK(compile_state_.pending_error_handler()->has_pending_error()); maybe_result = CompileAndFinalizeOnBackgroundThread(
PreparePendingException(isolate, info_.get()); info_.get(), compile_state_.allocator(), script, isolate,
} &finalize_unoptimized_compilation_data_,
&jobs_to_retry_finalization_on_main_thread_);
} else {
DCHECK(compile_state_.pending_error_handler()->has_pending_error());
PreparePendingException(isolate, info_.get());
}
outer_function_sfi_ = isolate->TransferHandle(maybe_result); outer_function_sfi_ = isolate->TransferHandle(maybe_result);
script_ = isolate->TransferHandle(script); script_ = isolate->TransferHandle(script);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), {
"V8.FinalizeCodeBackground.Finish"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
isolate->FinishOffThread(); "V8.FinalizeCodeBackground.Finish");
isolate->FinishOffThread();
}
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), {
"V8.FinalizeCodeBackground.ReleaseParser"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
DCHECK_EQ(language_mode_, info_->language_mode()); "V8.FinalizeCodeBackground.ReleaseParser");
off_thread_scope.reset(); DCHECK_EQ(language_mode_, info_->language_mode());
parser_.reset(); off_thread_scope.reset();
info_.reset(); parser_.reset();
outer_function_job_.reset(); info_.reset();
inner_function_jobs_.clear(); }
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -1689,7 +1729,8 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, ...@@ -1689,7 +1729,8 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs( if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
isolate, shared_info, script, &parse_info, isolate->allocator(), isolate, shared_info, script, &parse_info, isolate->allocator(),
is_compiled_scope, &finalize_unoptimized_compilation_data_list)) { is_compiled_scope, &finalize_unoptimized_compilation_data_list,
nullptr)) {
return FailWithPendingException(isolate, script, &parse_info, flag); return FailWithPendingException(isolate, script, &parse_info, flag);
} }
...@@ -1772,7 +1813,7 @@ bool Compiler::FinalizeBackgroundCompileTask( ...@@ -1772,7 +1813,7 @@ bool Compiler::FinalizeBackgroundCompileTask(
task->parser()->UpdateStatistics(isolate, script); task->parser()->UpdateStatistics(isolate, script);
task->parser()->HandleSourceURLComments(isolate, script); task->parser()->HandleSourceURLComments(isolate, script);
if (parse_info->literal() == nullptr || !task->outer_function_job()) { if (task->compilation_jobs()->empty()) {
// Parsing or compile failed on background thread - report error messages. // Parsing or compile failed on background thread - report error messages.
return FailWithPendingException(isolate, script, parse_info, flag); return FailWithPendingException(isolate, script, parse_info, flag);
} }
...@@ -1780,8 +1821,7 @@ bool Compiler::FinalizeBackgroundCompileTask( ...@@ -1780,8 +1821,7 @@ bool Compiler::FinalizeBackgroundCompileTask(
// Parsing has succeeded - finalize compilation. // Parsing has succeeded - finalize compilation.
parse_info->ast_value_factory()->Internalize(isolate); parse_info->ast_value_factory()->Internalize(isolate);
if (!FinalizeAllUnoptimizedCompilationJobs( if (!FinalizeAllUnoptimizedCompilationJobs(
parse_info, isolate, shared_info, task->outer_function_job(), parse_info, isolate, script, task->compilation_jobs(),
task->inner_function_jobs(),
task->finalize_unoptimized_compilation_data())) { task->finalize_unoptimized_compilation_data())) {
// Finalization failed - throw an exception. // Finalization failed - throw an exception.
return FailWithPendingException(isolate, script, parse_info, flag); return FailWithPendingException(isolate, script, parse_info, flag);
...@@ -2711,8 +2751,18 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ...@@ -2711,8 +2751,18 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
task->off_thread_isolate()->Publish(isolate); task->off_thread_isolate()->Publish(isolate);
maybe_result = task->outer_function_sfi();
script = task->script(); script = task->script();
// We might not have been able to finalize all jobs on the background
// thread (e.g. asm.js jobs), so finalize those deferred jobs now.
if (FinalizeDeferredUnoptimizedCompilationJobs(
isolate, script,
task->jobs_to_retry_finalization_on_main_thread(),
task->compile_state()->pending_error_handler(),
task->finalize_unoptimized_compilation_data())) {
maybe_result = task->outer_function_sfi();
}
script->set_source(*source); script->set_source(*source);
script->set_origin_options(origin_options); script->set_origin_options(origin_options);
} else { } else {
...@@ -2725,15 +2775,16 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ...@@ -2725,15 +2775,16 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
task->parser()->UpdateStatistics(isolate, script); task->parser()->UpdateStatistics(isolate, script);
task->parser()->HandleSourceURLComments(isolate, script); task->parser()->HandleSourceURLComments(isolate, script);
if (parse_info->literal() != nullptr && task->outer_function_job()) { if (!task->compilation_jobs()->empty()) {
// Off-thread parse & compile has succeeded - finalize compilation. // Off-thread parse & compile has succeeded - finalize compilation.
DCHECK_NOT_NULL(parse_info->literal());
parse_info->ast_value_factory()->Internalize(isolate); parse_info->ast_value_factory()->Internalize(isolate);
Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo> shared_info =
CreateTopLevelSharedFunctionInfo(parse_info, script, isolate); CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
if (FinalizeAllUnoptimizedCompilationJobs( if (FinalizeAllUnoptimizedCompilationJobs(
parse_info, isolate, shared_info, task->outer_function_job(), parse_info, isolate, script, task->compilation_jobs(),
task->inner_function_jobs(),
task->finalize_unoptimized_compilation_data())) { task->finalize_unoptimized_compilation_data())) {
maybe_result = shared_info; maybe_result = shared_info;
} }
......
...@@ -212,7 +212,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ...@@ -212,7 +212,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
// thread. The current state of the job can be checked using {state()}. // thread. The current state of the job can be checked using {state()}.
class V8_EXPORT_PRIVATE CompilationJob { class V8_EXPORT_PRIVATE CompilationJob {
public: public:
enum Status { SUCCEEDED, FAILED }; enum Status { SUCCEEDED, FAILED, RETRY_ON_MAIN_THREAD };
enum class State { enum class State {
kReadyToPrepare, kReadyToPrepare,
kReadyToExecute, kReadyToExecute,
...@@ -234,10 +234,16 @@ class V8_EXPORT_PRIVATE CompilationJob { ...@@ -234,10 +234,16 @@ class V8_EXPORT_PRIVATE CompilationJob {
} }
V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) { V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) {
if (status == SUCCEEDED) { switch (status) {
state_ = next_state; case SUCCEEDED:
} else { state_ = next_state;
state_ = State::kFailed; break;
case FAILED:
state_ = State::kFailed;
break;
case RETRY_ON_MAIN_THREAD:
// Don't change the state, we'll re-try on the main thread.
break;
} }
return status; return status;
} }
...@@ -257,17 +263,12 @@ class V8_EXPORT_PRIVATE CompilationJob { ...@@ -257,17 +263,12 @@ class V8_EXPORT_PRIVATE CompilationJob {
// Either of phases can either fail or succeed. // Either of phases can either fail or succeed.
class UnoptimizedCompilationJob : public CompilationJob { class UnoptimizedCompilationJob : public CompilationJob {
public: public:
enum class CanOffThreadFinalize : bool { kYes = true, kNo = false };
UnoptimizedCompilationJob(uintptr_t stack_limit, ParseInfo* parse_info, UnoptimizedCompilationJob(uintptr_t stack_limit, ParseInfo* parse_info,
UnoptimizedCompilationInfo* compilation_info, UnoptimizedCompilationInfo* compilation_info)
CanOffThreadFinalize can_off_thread_finalize)
: CompilationJob(State::kReadyToExecute), : CompilationJob(State::kReadyToExecute),
stack_limit_(stack_limit), stack_limit_(stack_limit),
parse_info_(parse_info), parse_info_(parse_info),
compilation_info_(compilation_info), compilation_info_(compilation_info) {}
can_off_thread_finalize_(can_off_thread_finalize ==
CanOffThreadFinalize::kYes) {}
// Executes the compile job. Can be called on a background thread. // Executes the compile job. Can be called on a background thread.
V8_WARN_UNUSED_RESULT Status ExecuteJob(); V8_WARN_UNUSED_RESULT Status ExecuteJob();
...@@ -276,7 +277,9 @@ class UnoptimizedCompilationJob : public CompilationJob { ...@@ -276,7 +277,9 @@ class UnoptimizedCompilationJob : public CompilationJob {
V8_WARN_UNUSED_RESULT Status V8_WARN_UNUSED_RESULT Status
FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate); FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate);
// Finalizes the compile job. Can be called on a background thread. // Finalizes the compile job. Can be called on a background thread, and might
// return RETRY_ON_MAIN_THREAD if the finalization can't be run on the
// background thread, and should instead be retried on the foreground thread.
V8_WARN_UNUSED_RESULT Status FinalizeJob( V8_WARN_UNUSED_RESULT Status FinalizeJob(
Handle<SharedFunctionInfo> shared_info, OffThreadIsolate* isolate); Handle<SharedFunctionInfo> shared_info, OffThreadIsolate* isolate);
...@@ -285,7 +288,10 @@ class UnoptimizedCompilationJob : public CompilationJob { ...@@ -285,7 +288,10 @@ class UnoptimizedCompilationJob : public CompilationJob {
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
Isolate* isolate) const; Isolate* isolate) const;
ParseInfo* parse_info() const { return parse_info_; } ParseInfo* parse_info() const {
DCHECK_NOT_NULL(parse_info_);
return parse_info_;
}
UnoptimizedCompilationInfo* compilation_info() const { UnoptimizedCompilationInfo* compilation_info() const {
return compilation_info_; return compilation_info_;
} }
...@@ -299,7 +305,7 @@ class UnoptimizedCompilationJob : public CompilationJob { ...@@ -299,7 +305,7 @@ class UnoptimizedCompilationJob : public CompilationJob {
return time_taken_to_finalize_; return time_taken_to_finalize_;
} }
bool can_off_thread_finalize() const { return can_off_thread_finalize_; } void ClearParseInfo() { parse_info_ = nullptr; }
protected: protected:
// Overridden by the actual implementation. // Overridden by the actual implementation.
...@@ -315,7 +321,6 @@ class UnoptimizedCompilationJob : public CompilationJob { ...@@ -315,7 +321,6 @@ class UnoptimizedCompilationJob : public CompilationJob {
UnoptimizedCompilationInfo* compilation_info_; UnoptimizedCompilationInfo* compilation_info_;
base::TimeDelta time_taken_to_execute_; base::TimeDelta time_taken_to_execute_;
base::TimeDelta time_taken_to_finalize_; base::TimeDelta time_taken_to_finalize_;
bool can_off_thread_finalize_;
}; };
// A base class for optimized compilation jobs. // A base class for optimized compilation jobs.
...@@ -426,6 +431,33 @@ class FinalizeUnoptimizedCompilationData { ...@@ -426,6 +431,33 @@ class FinalizeUnoptimizedCompilationData {
using FinalizeUnoptimizedCompilationDataList = using FinalizeUnoptimizedCompilationDataList =
std::vector<FinalizeUnoptimizedCompilationData>; std::vector<FinalizeUnoptimizedCompilationData>;
class DeferredFinalizationJobData {
public:
DeferredFinalizationJobData(Isolate* isolate,
Handle<SharedFunctionInfo> function_handle,
std::unique_ptr<UnoptimizedCompilationJob> job) {
UNREACHABLE();
}
DeferredFinalizationJobData(OffThreadIsolate* isolate,
Handle<SharedFunctionInfo> function_handle,
std::unique_ptr<UnoptimizedCompilationJob> job)
: function_transfer_handle_(isolate->TransferHandle(function_handle)),
job_(std::move(job)) {}
Handle<SharedFunctionInfo> function_handle() const {
return function_transfer_handle_.ToHandle();
}
UnoptimizedCompilationJob* job() const { return job_.get(); }
private:
OffThreadTransferHandle<SharedFunctionInfo> function_transfer_handle_;
std::unique_ptr<UnoptimizedCompilationJob> job_;
};
using DeferredFinalizationJobDataList =
std::vector<DeferredFinalizationJobData>;
class V8_EXPORT_PRIVATE BackgroundCompileTask { class V8_EXPORT_PRIVATE BackgroundCompileTask {
public: public:
// Creates a new task that when run will parse and compile the streamed // Creates a new task that when run will parse and compile the streamed
...@@ -451,16 +483,11 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -451,16 +483,11 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
return info_.get(); return info_.get();
} }
Parser* parser() { return parser_.get(); } Parser* parser() { return parser_.get(); }
UnoptimizedCompilationJob* outer_function_job() { UnoptimizedCompilationJobList* compilation_jobs() {
return outer_function_job_.get(); return &compilation_jobs_;
}
UnoptimizedCompilationJobList* inner_function_jobs() {
return &inner_function_jobs_;
} }
UnoptimizedCompileFlags flags() const { return flags_; } UnoptimizedCompileFlags flags() const { return flags_; }
const UnoptimizedCompileState* compile_state() const { UnoptimizedCompileState* compile_state() { return &compile_state_; }
return &compile_state_;
}
LanguageMode language_mode() { return language_mode_; } LanguageMode language_mode() { return language_mode_; }
bool finalize_on_background_thread() { bool finalize_on_background_thread() {
return finalize_on_background_thread_; return finalize_on_background_thread_;
...@@ -479,6 +506,12 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -479,6 +506,12 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
return &finalize_unoptimized_compilation_data_; return &finalize_unoptimized_compilation_data_;
} }
// Jobs which could not be finalized in the background task, and need to be
// finalized on the main thread.
DeferredFinalizationJobDataList* jobs_to_retry_finalization_on_main_thread() {
return &jobs_to_retry_finalization_on_main_thread_;
}
private: private:
// Data needed for parsing, and data needed to to be passed between thread // Data needed for parsing, and data needed to to be passed between thread
// between parsing and compilation. These need to be initialized before the // between parsing and compilation. These need to be initialized before the
...@@ -489,8 +522,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -489,8 +522,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
std::unique_ptr<Parser> parser_; std::unique_ptr<Parser> parser_;
// Data needed for finalizing compilation after background compilation. // Data needed for finalizing compilation after background compilation.
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job_; UnoptimizedCompilationJobList compilation_jobs_;
UnoptimizedCompilationJobList inner_function_jobs_;
// Data needed for merging onto the main thread after background finalization. // Data needed for merging onto the main thread after background finalization.
// TODO(leszeks): When these are available, the above fields are not. We // TODO(leszeks): When these are available, the above fields are not. We
...@@ -500,6 +532,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -500,6 +532,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
OffThreadTransferMaybeHandle<SharedFunctionInfo> outer_function_sfi_; OffThreadTransferMaybeHandle<SharedFunctionInfo> outer_function_sfi_;
OffThreadTransferHandle<Script> script_; OffThreadTransferHandle<Script> script_;
FinalizeUnoptimizedCompilationDataList finalize_unoptimized_compilation_data_; FinalizeUnoptimizedCompilationDataList finalize_unoptimized_compilation_data_;
DeferredFinalizationJobDataList jobs_to_retry_finalization_on_main_thread_;
// Single function data for top-level function compilation. // Single function data for top-level function compilation.
int start_position_; int start_position_;
......
...@@ -43,6 +43,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final { ...@@ -43,6 +43,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
DCHECK_NOT_NULL(literal); DCHECK_NOT_NULL(literal);
literal_ = literal; literal_ = literal;
} }
void ClearLiteral() { literal_ = nullptr; }
DeclarationScope* scope() const; DeclarationScope* scope() const;
......
...@@ -149,7 +149,7 @@ InterpreterCompilationJob::InterpreterCompilationJob( ...@@ -149,7 +149,7 @@ InterpreterCompilationJob::InterpreterCompilationJob(
AccountingAllocator* allocator, AccountingAllocator* allocator,
std::vector<FunctionLiteral*>* eager_inner_literals) std::vector<FunctionLiteral*>* eager_inner_literals)
: UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info, : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
&compilation_info_, CanOffThreadFinalize::kYes), &compilation_info_),
zone_(allocator, ZONE_NAME), zone_(allocator, ZONE_NAME),
compilation_info_(&zone_, parse_info, literal), compilation_info_(&zone_, parse_info, literal),
generator_(&zone_, &compilation_info_, parse_info->ast_string_constants(), generator_(&zone_, &compilation_info_, parse_info->ast_string_constants(),
......
...@@ -417,12 +417,15 @@ bool SharedFunctionInfo::is_compiled() const { ...@@ -417,12 +417,15 @@ bool SharedFunctionInfo::is_compiled() const {
!data.IsUncompiledData(); !data.IsUncompiledData();
} }
IsCompiledScope SharedFunctionInfo::is_compiled_scope(Isolate* isolate) const { template <typename LocalIsolate>
IsCompiledScope SharedFunctionInfo::is_compiled_scope(
LocalIsolate* isolate) const {
return IsCompiledScope(*this, isolate); return IsCompiledScope(*this, isolate);
} }
template <typename LocalIsolate>
IsCompiledScope::IsCompiledScope(const SharedFunctionInfo shared, IsCompiledScope::IsCompiledScope(const SharedFunctionInfo shared,
Isolate* isolate) LocalIsolate* isolate)
: retain_bytecode_(shared.HasBytecodeArray() : retain_bytecode_(shared.HasBytecodeArray()
? handle(shared.GetBytecodeArray(), isolate) ? handle(shared.GetBytecodeArray(), isolate)
: MaybeHandle<BytecodeArray>()), : MaybeHandle<BytecodeArray>()),
......
...@@ -260,7 +260,8 @@ class SharedFunctionInfo : public HeapObject { ...@@ -260,7 +260,8 @@ class SharedFunctionInfo : public HeapObject {
// Returns an IsCompiledScope which reports whether the function is compiled, // Returns an IsCompiledScope which reports whether the function is compiled,
// and if compiled, will avoid the function becoming uncompiled while it is // and if compiled, will avoid the function becoming uncompiled while it is
// held. // held.
inline IsCompiledScope is_compiled_scope(Isolate* isolate) const; template <typename LocalIsolate>
inline IsCompiledScope is_compiled_scope(LocalIsolate* isolate) const;
// [length]: The function length - usually the number of declared parameters. // [length]: The function length - usually the number of declared parameters.
// Use up to 2^16-2 parameters (16 bits of values, where one is reserved for // Use up to 2^16-2 parameters (16 bits of values, where one is reserved for
...@@ -700,7 +701,9 @@ struct SourceCodeOf { ...@@ -700,7 +701,9 @@ struct SourceCodeOf {
// the scope is retained. // the scope is retained.
class IsCompiledScope { class IsCompiledScope {
public: public:
inline IsCompiledScope(const SharedFunctionInfo shared, Isolate* isolate); template <typename LocalIsolate>
inline IsCompiledScope(const SharedFunctionInfo shared,
LocalIsolate* isolate);
inline IsCompiledScope() : retain_bytecode_(), is_compiled_(false) {} inline IsCompiledScope() : retain_bytecode_(), is_compiled_(false) {}
inline bool is_compiled() const { return is_compiled_; } inline bool is_compiled() const { return is_compiled_; }
......
...@@ -40,15 +40,19 @@ void PendingCompilationErrorHandler::MessageDetails::Prepare( ...@@ -40,15 +40,19 @@ void PendingCompilationErrorHandler::MessageDetails::Prepare(
switch (type_) { switch (type_) {
case kAstRawString: case kAstRawString:
return SetString(arg_->string(), isolate); return SetString(arg_->string(), isolate);
case kNone: case kNone:
case kConstCharString: case kConstCharString:
// We can delay allocation until ArgumentString(isolate). // We can delay allocation until ArgumentString(isolate).
// TODO(leszeks): We don't actually have to transfer this string, since // TODO(leszeks): We don't actually have to transfer this string, since
// it's a root. // it's a root.
return; return;
case kMainThreadHandle: case kMainThreadHandle:
case kOffThreadTransferHandle: case kOffThreadTransferHandle:
UNREACHABLE(); // The message details might already be prepared, so skip them if this is
// the case.
return;
} }
} }
......
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