Commit 58b12f63 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[offthread] Unify compiler.cc finalization logic

This patch unfies the finalization logic between the various unoptimized
compilation paths in compiler.cc, taking the various post-processings and
fixups needed for off-thread finalization and performing them in the same
order for the other finalizations.

It also unifies the general compilation path between streaming script
compilation, main-thread script compilation, and main-thread lazy
compilation, making the main-thread paths both use an iterative execution
and finalization, and making all three use the same job helper methods
and overall finalization helper.

Bug: chromium:1011762
Change-Id: Ibe56f6d2f75a2deffbe9e0b600ded8a02293b722
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2172790
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67609}
parent 65d738d4
...@@ -224,7 +224,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob { ...@@ -224,7 +224,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob {
UnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() { UnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() {
// Step 1: Translate asm.js module to WebAssembly module. // Step 1: Translate asm.js module to WebAssembly module.
Zone* compile_zone = compilation_info()->zone(); Zone* compile_zone = &zone_;
Zone translate_zone(allocator_, ZONE_NAME); Zone translate_zone(allocator_, ZONE_NAME);
Utf16CharacterStream* stream = parse_info()->character_stream(); Utf16CharacterStream* stream = parse_info()->character_stream();
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "src/ast/ast-value-factory.h" #include "src/ast/ast-value-factory.h"
#include "src/base/logging.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/off-thread-isolate.h" #include "src/execution/off-thread-isolate.h"
#include "src/heap/factory-inl.h" #include "src/heap/factory-inl.h"
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <forward_list> #include <forward_list>
#include "src/base/hashmap.h" #include "src/base/hashmap.h"
#include "src/base/logging.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/numbers/conversions.h" #include "src/numbers/conversions.h"
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "src/execution/frames-inl.h" #include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/off-thread-isolate.h"
#include "src/execution/runtime-profiler.h" #include "src/execution/runtime-profiler.h"
#include "src/execution/vm-state-inl.h" #include "src/execution/vm-state-inl.h"
#include "src/handles/maybe-handles.h" #include "src/handles/maybe-handles.h"
...@@ -180,13 +181,15 @@ CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob( ...@@ -180,13 +181,15 @@ CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob(
return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded); return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded);
} }
void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const { namespace {
void RecordUnoptimizedCompilationStats(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info) {
int code_size; int code_size;
if (compilation_info()->has_bytecode_array()) { if (shared_info->HasBytecodeArray()) {
code_size = compilation_info()->bytecode_array()->SizeIncludingMetadata(); code_size = shared_info->GetBytecodeArray().SizeIncludingMetadata();
} else { } else {
DCHECK(compilation_info()->has_asm_wasm_data()); code_size = shared_info->asm_wasm_data().Size();
code_size = compilation_info()->asm_wasm_data()->Size();
} }
Counters* counters = isolate->counters(); Counters* counters = isolate->counters();
...@@ -198,27 +201,30 @@ void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const { ...@@ -198,27 +201,30 @@ void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const {
// Also add total time (there's now already timer_ on the base class). // Also add total time (there's now already timer_ on the base class).
} }
void UnoptimizedCompilationJob::RecordFunctionCompilation( void RecordUnoptimizedFunctionCompilation(
CodeEventListener::LogEventsAndTags tag, Handle<SharedFunctionInfo> shared, Isolate* isolate, CodeEventListener::LogEventsAndTags tag,
Isolate* isolate) const { Handle<SharedFunctionInfo> shared, base::TimeDelta time_taken_to_execute,
base::TimeDelta time_taken_to_finalize) {
Handle<AbstractCode> abstract_code; Handle<AbstractCode> abstract_code;
if (compilation_info()->has_bytecode_array()) { if (shared->HasBytecodeArray()) {
abstract_code = abstract_code =
Handle<AbstractCode>::cast(compilation_info()->bytecode_array()); handle(AbstractCode::cast(shared->GetBytecodeArray()), isolate);
} else { } else {
DCHECK(compilation_info()->has_asm_wasm_data()); DCHECK(shared->HasAsmWasmData());
abstract_code = abstract_code =
Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs)); Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs));
} }
double time_taken_ms = time_taken_to_execute_.InMillisecondsF() + double time_taken_ms = time_taken_to_execute.InMillisecondsF() +
time_taken_to_finalize_.InMillisecondsF(); time_taken_to_finalize.InMillisecondsF();
Handle<Script> script(Script::cast(shared->script()), isolate); Handle<Script> script(Script::cast(shared->script()), isolate);
LogFunctionCompilation(tag, shared, script, abstract_code, false, LogFunctionCompilation(tag, shared, script, abstract_code, false,
time_taken_ms, isolate); time_taken_ms, isolate);
} }
} // namespace
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of OptimizedCompilationJob // Implementation of OptimizedCompilationJob
...@@ -384,13 +390,12 @@ bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) { ...@@ -384,13 +390,12 @@ bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
return literal->scope()->IsAsmModule(); return literal->scope()->IsAsmModule();
} }
void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array, void InstallInterpreterTrampolineCopy(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info) {
ParseInfo* parse_info, Isolate* isolate) { DCHECK(FLAG_interpreted_frames_native_stack);
if (!FLAG_interpreted_frames_native_stack) { DCHECK(shared_info->function_data().IsBytecodeArray());
shared_info->set_bytecode_array(*bytecode_array); Handle<BytecodeArray> bytecode_array(shared_info->GetBytecodeArray(),
return; isolate);
}
Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast( Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
isolate->factory()->interpreter_entry_trampoline_for_profiling())); isolate->factory()->interpreter_entry_trampoline_for_profiling()));
...@@ -420,9 +425,23 @@ void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array, ...@@ -420,9 +425,23 @@ void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array,
script_name, line_num, column_num)); script_name, line_num, column_num));
} }
void InstallCoverageInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared,
Handle<CoverageInfo> coverage_info) {
DCHECK(isolate->is_block_code_coverage());
isolate->debug()->InstallCoverageInfo(shared, coverage_info);
}
void InstallCoverageInfo(OffThreadIsolate* isolate,
Handle<SharedFunctionInfo> shared,
Handle<CoverageInfo> coverage_info) {
// We should only have coverage info when finalizing on the main thread.
UNREACHABLE();
}
template <typename LocalIsolate>
void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info, void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info,
ParseInfo* parse_info, Isolate* isolate) { LocalIsolate* isolate) {
DCHECK_EQ(shared_info->language_mode(), DCHECK_EQ(shared_info->language_mode(),
compilation_info->literal()->language_mode()); compilation_info->literal()->language_mode());
...@@ -441,56 +460,45 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info, ...@@ -441,56 +460,45 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
shared_info->set_is_asm_wasm_broken(true); shared_info->set_is_asm_wasm_broken(true);
} }
InstallBytecodeArray(compilation_info->bytecode_array(), shared_info, shared_info->set_bytecode_array(*compilation_info->bytecode_array());
parse_info, isolate);
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New( Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec()); isolate, compilation_info->feedback_vector_spec());
shared_info->set_feedback_metadata(*feedback_metadata); shared_info->set_feedback_metadata(*feedback_metadata);
} else { } else {
DCHECK(compilation_info->has_asm_wasm_data()); DCHECK(compilation_info->has_asm_wasm_data());
// We should only have asm/wasm data when finalizing on the main thread.
DCHECK((std::is_same<LocalIsolate, Isolate>::value));
shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data()); shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data());
shared_info->set_feedback_metadata( shared_info->set_feedback_metadata(
ReadOnlyRoots(isolate).empty_feedback_metadata()); ReadOnlyRoots(isolate).empty_feedback_metadata());
} }
// Install coverage info on the shared function info.
if (compilation_info->has_coverage_info() && if (compilation_info->has_coverage_info() &&
!shared_info->HasCoverageInfo()) { !shared_info->HasCoverageInfo()) {
DCHECK(isolate->is_block_code_coverage()); InstallCoverageInfo(isolate, shared_info,
isolate->debug()->InstallCoverageInfo(shared_info, compilation_info->coverage_info());
compilation_info->coverage_info());
} }
} }
void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info, void LogUnoptimizedCompilation(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info,
ParseInfo* parse_info, OffThreadIsolate* isolate) { UnoptimizedCompileFlags flags,
DCHECK_EQ(shared_info->language_mode(), base::TimeDelta time_taken_to_execute,
compilation_info->literal()->language_mode()); base::TimeDelta time_taken_to_finalize) {
CodeEventListener::LogEventsAndTags log_tag;
// Update the shared function info with the scope info. if (flags.is_toplevel()) {
Handle<ScopeInfo> scope_info = compilation_info->scope()->scope_info(); log_tag = flags.is_eval() ? CodeEventListener::EVAL_TAG
shared_info->set_scope_info(*scope_info); : CodeEventListener::SCRIPT_TAG;
} else {
DCHECK(compilation_info->has_bytecode_array()); log_tag = flags.is_lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once. : CodeEventListener::FUNCTION_TAG;
DCHECK(!compilation_info->has_asm_wasm_data());
DCHECK(!shared_info->HasFeedbackMetadata());
// If the function failed asm-wasm compilation, mark asm_wasm as broken
// to ensure we don't try to compile as asm-wasm.
if (compilation_info->literal()->scope()->IsAsmModule()) {
shared_info->set_is_asm_wasm_broken(true);
} }
shared_info->set_bytecode_array(*compilation_info->bytecode_array()); RecordUnoptimizedFunctionCompilation(isolate, log_tag, shared_info,
time_taken_to_execute,
Handle<FeedbackMetadata> feedback_metadata = time_taken_to_finalize);
FeedbackMetadata::New(isolate, compilation_info->feedback_vector_spec()); RecordUnoptimizedCompilationStats(isolate, shared_info);
shared_info->set_feedback_metadata(*feedback_metadata);
DCHECK(!compilation_info->has_coverage_info());
} }
template <typename LocalIsolate> template <typename LocalIsolate>
...@@ -525,63 +533,32 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal, ...@@ -525,63 +533,32 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal,
literal->has_static_private_methods_or_accessors()); literal->has_static_private_methods_or_accessors());
} }
CompilationJob::Status FinalizeUnoptimizedCompilationJob( template <typename LocalIsolate>
UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info, CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
Isolate* isolate) {
UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
ParseInfo* parse_info = job->parse_info();
const UnoptimizedCompileFlags flags = parse_info->flags();
SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), *shared_info);
CompilationJob::Status status = job->FinalizeJob(shared_info, isolate);
if (status == CompilationJob::SUCCEEDED) {
InstallUnoptimizedCode(compilation_info, shared_info, parse_info, isolate);
// It's possible that source position collection was enabled after the
// background compile was started in which the compiled bytecode will not be
// missing source positions (for instance by enabling the cpu profiler). So
// force source position collection now in that case.
if (!flags.collect_source_positions() &&
isolate->NeedsDetailedOptimizedCodeLineInfo()) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
}
CodeEventListener::LogEventsAndTags log_tag;
if (flags.is_toplevel()) {
log_tag = flags.is_eval() ? CodeEventListener::EVAL_TAG
: CodeEventListener::SCRIPT_TAG;
} else {
log_tag = flags.is_lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
: CodeEventListener::FUNCTION_TAG;
}
job->RecordFunctionCompilation(log_tag, shared_info, isolate);
job->RecordCompilationStats(isolate);
}
return status;
}
CompilationJob::Status FinalizeUnoptimizedCompilationJob(
UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info, UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
OffThreadIsolate* isolate) { LocalIsolate* isolate,
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) {
UnoptimizedCompilationInfo* compilation_info = job->compilation_info(); UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
ParseInfo* parse_info = job->parse_info();
SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), *shared_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, parse_info, isolate); InstallUnoptimizedCode(compilation_info, shared_info, isolate);
finalize_unoptimized_compilation_data_list->push_back(
// TODO(leszeks): Record the function compilation and compilation stats. FinalizeUnoptimizedCompilationData{
compilation_info->literal()->function_literal_id(),
job->time_taken_to_execute(), job->time_taken_to_finalize()});
} }
return status; return status;
} }
std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs( std::unique_ptr<UnoptimizedCompilationJob>
ExecuteSingleUnoptimizedCompilationJob(
ParseInfo* parse_info, FunctionLiteral* literal, ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator, AccountingAllocator* allocator,
UnoptimizedCompilationJobList* inner_function_jobs) { std::vector<FunctionLiteral*>* eager_inner_literals) {
if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) { if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) {
std::unique_ptr<UnoptimizedCompilationJob> asm_job( std::unique_ptr<UnoptimizedCompilationJob> asm_job(
AsmJs::NewCompilationJob(parse_info, literal, allocator)); AsmJs::NewCompilationJob(parse_info, literal, allocator));
...@@ -594,21 +571,35 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs( ...@@ -594,21 +571,35 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
// with a validation error or another error that could be solve by falling // with a validation error or another error that could be solve by falling
// through to standard unoptimized compile. // through to standard unoptimized compile.
} }
std::vector<FunctionLiteral*> eager_inner_literals;
std::unique_ptr<UnoptimizedCompilationJob> job( std::unique_ptr<UnoptimizedCompilationJob> job(
interpreter::Interpreter::NewCompilationJob( interpreter::Interpreter::NewCompilationJob(
parse_info, literal, allocator, &eager_inner_literals)); parse_info, literal, allocator, eager_inner_literals));
if (job->ExecuteJob() != CompilationJob::SUCCEEDED) { if (job->ExecuteJob() != CompilationJob::SUCCEEDED) {
// Compilation failed, return null. // Compilation failed, return null.
return std::unique_ptr<UnoptimizedCompilationJob>(); return std::unique_ptr<UnoptimizedCompilationJob>();
} }
return job;
}
std::unique_ptr<UnoptimizedCompilationJob>
RecursivelyExecuteUnoptimizedCompilationJobs(
ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator,
UnoptimizedCompilationJobList* inner_function_jobs) {
std::vector<FunctionLiteral*> eager_inner_literals;
std::unique_ptr<UnoptimizedCompilationJob> job =
ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
&eager_inner_literals);
if (!job) return std::unique_ptr<UnoptimizedCompilationJob>();
// 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( std::unique_ptr<UnoptimizedCompilationJob> inner_job(
ExecuteUnoptimizedCompileJobs(parse_info, inner_literal, allocator, RecursivelyExecuteUnoptimizedCompilationJobs(
inner_function_jobs)); parse_info, inner_literal, allocator, inner_function_jobs));
// Compilation failed, return null. // Compilation failed, return null.
if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>(); if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>();
inner_function_jobs->emplace_front(std::move(inner_job)); inner_function_jobs->emplace_front(std::move(inner_job));
...@@ -617,34 +608,14 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs( ...@@ -617,34 +608,14 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
return job; return job;
} }
std::unique_ptr<UnoptimizedCompilationJob> GenerateUnoptimizedCode( bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
ParseInfo* parse_info, AccountingAllocator* allocator, Isolate* isolate, Handle<SharedFunctionInfo> outer_shared_info,
UnoptimizedCompilationJobList* inner_function_jobs) { Handle<Script> script, ParseInfo* parse_info,
DisallowHeapAccess no_heap_access; AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope,
DCHECK(inner_function_jobs->empty()); FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) {
std::unique_ptr<UnoptimizedCompilationJob> job =
ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(),
allocator, inner_function_jobs);
// Character stream shouldn't be used again.
parse_info->ResetCharacterStream();
return job;
}
MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
Isolate* isolate, Handle<Script> script, ParseInfo* parse_info,
AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope) {
EnsureSharedFunctionInfosArrayOnScript(script, parse_info, isolate);
DeclarationScope::AllocateScopeInfos(parse_info, isolate); DeclarationScope::AllocateScopeInfos(parse_info, isolate);
// Prepare and execute compilation of the outer-most function.
// Create the SharedFunctionInfo and add it to the script's list.
Handle<SharedFunctionInfo> top_level =
isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(),
script, true);
std::vector<FunctionLiteral*> functions_to_compile; std::vector<FunctionLiteral*> functions_to_compile;
functions_to_compile.push_back(parse_info->literal()); functions_to_compile.push_back(parse_info->literal());
...@@ -654,57 +625,42 @@ MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel( ...@@ -654,57 +625,42 @@ MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(literal, script, isolate); Compiler::GetSharedFunctionInfo(literal, script, isolate);
if (shared_info->is_compiled()) continue; if (shared_info->is_compiled()) continue;
if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) {
std::unique_ptr<UnoptimizedCompilationJob> asm_job(
AsmJs::NewCompilationJob(parse_info, literal, allocator));
if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED &&
FinalizeUnoptimizedCompilationJob(asm_job.get(), shared_info,
isolate) ==
CompilationJob::SUCCEEDED) {
continue;
}
// asm.js validation failed, fall through to standard unoptimized compile.
// Note: we rely on the fact that AsmJs jobs have done all validation in
// the PrepareJob and ExecuteJob phases and can't fail in FinalizeJob with
// with a validation error or another error that could be solve by falling
// through to standard unoptimized compile.
}
std::unique_ptr<UnoptimizedCompilationJob> job(
interpreter::Interpreter::NewCompilationJob(
parse_info, literal, allocator, &functions_to_compile));
if (job->ExecuteJob() == CompilationJob::FAILED || std::unique_ptr<UnoptimizedCompilationJob> job =
FinalizeUnoptimizedCompilationJob(job.get(), shared_info, isolate) == ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
CompilationJob::FAILED) { &functions_to_compile);
return MaybeHandle<SharedFunctionInfo>(); if (!job) return false;
}
if (FLAG_stress_lazy_source_positions) { if (FinalizeSingleUnoptimizedCompilationJob(
// Collect source positions immediately to try and flush out bytecode job.get(), shared_info, isolate,
// mismatches. finalize_unoptimized_compilation_data_list) !=
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info); CompilationJob::SUCCEEDED) {
return false;
} }
if (shared_info.is_identical_to(top_level)) { if (shared_info.is_identical_to(outer_shared_info)) {
// Ensure that the top level function is retained. // Ensure that the top level function is retained.
*is_compiled_scope = shared_info->is_compiled_scope(); *is_compiled_scope = shared_info->is_compiled_scope();
DCHECK(is_compiled_scope->is_compiled()); DCHECK(is_compiled_scope->is_compiled());
} }
} }
// Character stream shouldn't be used again. // Report any warnings generated during compilation.
parse_info->ResetCharacterStream(); if (parse_info->pending_error_handler()->has_pending_warnings()) {
parse_info->pending_error_handler()->PrepareWarnings(isolate);
}
return top_level; return true;
} }
template <typename LocalIsolate> template <typename LocalIsolate>
bool FinalizeUnoptimizedCode( bool FinalizeAllUnoptimizedCompilationJobs(
ParseInfo* parse_info, LocalIsolate* isolate, ParseInfo* parse_info, LocalIsolate* isolate,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info,
UnoptimizedCompilationJob* outer_function_job, UnoptimizedCompilationJob* outer_function_job,
UnoptimizedCompilationJobList* inner_function_jobs) { UnoptimizedCompilationJobList* inner_function_jobs,
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data_list) {
// TODO(leszeks): Re-enable. // TODO(leszeks): Re-enable.
// DCHECK(AllowCompilation::IsAllowed(isolate)); // DCHECK(AllowCompilation::IsAllowed(isolate));
...@@ -715,8 +671,10 @@ bool FinalizeUnoptimizedCode( ...@@ -715,8 +671,10 @@ bool FinalizeUnoptimizedCode(
DeclarationScope::AllocateScopeInfos(parse_info, isolate); DeclarationScope::AllocateScopeInfos(parse_info, isolate);
// Finalize the outer-most function's compilation job. // Finalize the outer-most function's compilation job.
if (FinalizeUnoptimizedCompilationJob(outer_function_job, shared_info, if (FinalizeSingleUnoptimizedCompilationJob(
isolate) != CompilationJob::SUCCEEDED) { outer_function_job, shared_info, isolate,
finalize_unoptimized_compilation_data_list) !=
CompilationJob::SUCCEEDED) {
return false; return false;
} }
...@@ -730,8 +688,9 @@ bool FinalizeUnoptimizedCode( ...@@ -730,8 +688,9 @@ bool FinalizeUnoptimizedCode(
inner_job->compilation_info()->literal(), script, isolate); 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 (inner_shared_info->is_compiled()) continue;
if (FinalizeUnoptimizedCompilationJob(inner_job.get(), inner_shared_info, if (FinalizeSingleUnoptimizedCompilationJob(
isolate) != inner_job.get(), inner_shared_info, isolate,
finalize_unoptimized_compilation_data_list) !=
CompilationJob::SUCCEEDED) { CompilationJob::SUCCEEDED) {
return false; return false;
} }
...@@ -739,7 +698,7 @@ bool FinalizeUnoptimizedCode( ...@@ -739,7 +698,7 @@ bool FinalizeUnoptimizedCode(
// Report any warnings generated during compilation. // Report any warnings generated during compilation.
if (parse_info->pending_error_handler()->has_pending_warnings()) { if (parse_info->pending_error_handler()->has_pending_warnings()) {
parse_info->pending_error_handler()->ReportWarnings(isolate, script); parse_info->pending_error_handler()->PrepareWarnings(isolate);
} }
return true; return true;
...@@ -991,43 +950,26 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, ...@@ -991,43 +950,26 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
return MaybeHandle<Code>(); return MaybeHandle<Code>();
} }
bool FailWithPendingException(Isolate* isolate, Handle<Script> script, bool FailAndClearPendingException(Isolate* isolate) {
ParseInfo* parse_info, isolate->clear_pending_exception();
Compiler::ClearExceptionFlag flag) {
if (flag == Compiler::CLEAR_EXCEPTION) {
isolate->clear_pending_exception();
} else if (!isolate->has_pending_exception()) {
if (parse_info->pending_error_handler()->has_pending_error()) {
parse_info->pending_error_handler()->ReportErrors(
isolate, script, parse_info->ast_value_factory());
} else {
isolate->StackOverflow();
}
}
return false; return false;
} }
bool FailWithPendingException(OffThreadIsolate* isolate, Handle<Script> script, template <typename LocalIsolate>
ParseInfo* parse_info, bool PreparePendingException(LocalIsolate* isolate, ParseInfo* parse_info) {
Compiler::ClearExceptionFlag flag) {
// Off-thread compilation is a "standard compilation path", on which we don't
// want to override existing Isolate errors (after merging with the main
// thread), so we should expect to always keep the exception.
DCHECK_EQ(flag, Compiler::KEEP_EXCEPTION);
if (parse_info->pending_error_handler()->has_pending_error()) { if (parse_info->pending_error_handler()->has_pending_error()) {
parse_info->pending_error_handler()->PrepareErrorsOffThread( parse_info->pending_error_handler()->PrepareErrors(
isolate, script, parse_info->ast_value_factory()); isolate, parse_info->ast_value_factory());
} }
return false; return false;
} }
bool FailWithPendingExceptionAfterOffThreadFinalization( bool FailWithPreparedPendingException(
Isolate* isolate, Handle<Script> script, Isolate* isolate, Handle<Script> script,
PendingCompilationErrorHandler* pending_error_handler) { const PendingCompilationErrorHandler* pending_error_handler) {
if (!isolate->has_pending_exception()) { if (!isolate->has_pending_exception()) {
if (pending_error_handler->has_pending_error()) { if (pending_error_handler->has_pending_error()) {
pending_error_handler->ReportErrorsAfterOffThreadFinalization(isolate, pending_error_handler->ReportErrors(isolate, script);
script);
} else { } else {
isolate->StackOverflow(); isolate->StackOverflow();
} }
...@@ -1035,17 +977,73 @@ bool FailWithPendingExceptionAfterOffThreadFinalization( ...@@ -1035,17 +977,73 @@ bool FailWithPendingExceptionAfterOffThreadFinalization(
return false; return false;
} }
void FinalizeScriptCompilation( bool FailWithPendingException(Isolate* isolate, Handle<Script> script,
ParseInfo* parse_info,
Compiler::ClearExceptionFlag flag) {
if (flag == Compiler::CLEAR_EXCEPTION) {
return FailAndClearPendingException(isolate);
}
PreparePendingException(isolate, parse_info);
return FailWithPreparedPendingException(isolate, script,
parse_info->pending_error_handler());
}
void FinalizeUnoptimizedCompilation(
Isolate* isolate, Handle<Script> script, Isolate* isolate, Handle<Script> script,
UnoptimizedCompileState::ParallelTasks* parallel_tasks) { const UnoptimizedCompileFlags& flags,
const UnoptimizedCompileState* compile_state,
const FinalizeUnoptimizedCompilationDataList&
finalize_unoptimized_compilation_data_list) {
if (compile_state->pending_error_handler()->has_pending_warnings()) {
compile_state->pending_error_handler()->ReportWarnings(isolate, script);
}
bool need_source_positions = FLAG_stress_lazy_source_positions ||
(!flags.collect_source_positions() &&
isolate->NeedsSourcePositionsForProfiling());
bool need_interpreter_trampoline_copies =
FLAG_interpreted_frames_native_stack;
for (const auto& finalize_data : finalize_unoptimized_compilation_data_list) {
Handle<SharedFunctionInfo> shared_info =
script
->FindSharedFunctionInfo(isolate, finalize_data.function_literal_id)
.ToHandleChecked();
if (need_source_positions) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
}
if (need_interpreter_trampoline_copies) {
InstallInterpreterTrampolineCopy(isolate, shared_info);
}
LogUnoptimizedCompilation(isolate, shared_info, flags,
finalize_data.time_taken_to_execute,
finalize_data.time_taken_to_finalize);
}
}
void FinalizeUnoptimizedScriptCompilation(
Isolate* isolate, Handle<Script> script,
const UnoptimizedCompileFlags& flags,
const UnoptimizedCompileState* compile_state,
const FinalizeUnoptimizedCompilationDataList&
finalize_unoptimized_compilation_data_list) {
FinalizeUnoptimizedCompilation(isolate, script, flags, compile_state,
finalize_unoptimized_compilation_data_list);
script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
UnoptimizedCompileState::ParallelTasks* parallel_tasks =
compile_state->parallel_tasks();
if (parallel_tasks) { if (parallel_tasks) {
CompilerDispatcher* dispatcher = parallel_tasks->dispatcher(); CompilerDispatcher* dispatcher = parallel_tasks->dispatcher();
for (auto& it : *parallel_tasks) { for (auto& it : *parallel_tasks) {
FunctionLiteral* literal = it.first; FunctionLiteral* literal = it.first;
CompilerDispatcher::JobId job_id = it.second; CompilerDispatcher::JobId job_id = it.second;
MaybeHandle<SharedFunctionInfo> maybe_shared_for_task = MaybeHandle<SharedFunctionInfo> maybe_shared_for_task =
script->FindSharedFunctionInfo(isolate, literal); script->FindSharedFunctionInfo(isolate,
literal->function_literal_id());
Handle<SharedFunctionInfo> shared_for_task; Handle<SharedFunctionInfo> shared_for_task;
if (maybe_shared_for_task.ToHandle(&shared_for_task)) { if (maybe_shared_for_task.ToHandle(&shared_for_task)) {
dispatcher->RegisterSharedFunctionInfo(job_id, *shared_for_task); dispatcher->RegisterSharedFunctionInfo(job_id, *shared_for_task);
...@@ -1054,34 +1052,22 @@ void FinalizeScriptCompilation( ...@@ -1054,34 +1052,22 @@ void FinalizeScriptCompilation(
} }
} }
} }
if (isolate->NeedsSourcePositionsForProfiling()) { if (isolate->NeedsSourcePositionsForProfiling()) {
Script::InitLineEnds(isolate, script); Script::InitLineEnds(isolate, script);
} }
} }
// Create shared function info for top level and shared function infos array for
// inner functions.
template <typename LocalIsolate> template <typename LocalIsolate>
MaybeHandle<SharedFunctionInfo> FinalizeTopLevel( Handle<SharedFunctionInfo> CreateTopLevelSharedFunctionInfo(
ParseInfo* parse_info, Handle<Script> script, LocalIsolate* isolate, ParseInfo* parse_info, Handle<Script> script, LocalIsolate* isolate) {
UnoptimizedCompilationJob* outer_function_job,
UnoptimizedCompilationJobList* inner_function_jobs) {
// Internalize ast values onto the heap.
parse_info->ast_value_factory()->Internalize(isolate);
// Create shared function infos for top level and shared function infos array
// for inner functions.
EnsureSharedFunctionInfosArrayOnScript(script, parse_info, isolate); EnsureSharedFunctionInfosArrayOnScript(script, parse_info, isolate);
DCHECK_EQ(kNoSourcePosition, DCHECK_EQ(kNoSourcePosition,
parse_info->literal()->function_token_position()); parse_info->literal()->function_token_position());
Handle<SharedFunctionInfo> shared_info = return isolate->factory()->NewSharedFunctionInfoForLiteral(
isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(), parse_info->literal(), script, true);
script, true);
// Finalize compilation of the unoptimized bytecode or asm-js data.
if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
outer_function_job, inner_function_jobs)) {
return MaybeHandle<SharedFunctionInfo>();
}
return shared_info;
} }
MaybeHandle<SharedFunctionInfo> CompileToplevel( MaybeHandle<SharedFunctionInfo> CompileToplevel(
...@@ -1114,17 +1100,29 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel( ...@@ -1114,17 +1100,29 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
parse_info->flags().is_eval() ? "V8.CompileEval" : "V8.Compile"); parse_info->flags().is_eval() ? "V8.CompileEval" : "V8.Compile");
// Generate the unoptimized bytecode or asm-js data. // Prepare and execute compilation of the outer-most function.
MaybeHandle<SharedFunctionInfo> shared_info =
GenerateUnoptimizedCodeForToplevel( // Create the SharedFunctionInfo and add it to the script's list.
isolate, script, parse_info, isolate->allocator(), is_compiled_scope); Handle<SharedFunctionInfo> shared_info =
if (shared_info.is_null()) { CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
FinalizeUnoptimizedCompilationDataList
finalize_unoptimized_compilation_data_list;
if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
isolate, shared_info, script, parse_info, isolate->allocator(),
is_compiled_scope, &finalize_unoptimized_compilation_data_list)) {
FailWithPendingException(isolate, script, parse_info, FailWithPendingException(isolate, script, parse_info,
Compiler::ClearExceptionFlag::KEEP_EXCEPTION); Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
} }
FinalizeScriptCompilation(isolate, script, parse_info->parallel_tasks()); // Character stream shouldn't be used again.
parse_info->ResetCharacterStream();
FinalizeUnoptimizedScriptCompilation(
isolate, script, parse_info->flags(), parse_info->state(),
finalize_unoptimized_compilation_data_list);
return shared_info; return shared_info;
} }
...@@ -1143,8 +1141,18 @@ std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread( ...@@ -1143,8 +1141,18 @@ std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread(
: RuntimeCallCounterId::kCompileBackgroundFunction); : RuntimeCallCounterId::kCompileBackgroundFunction);
// Generate the unoptimized bytecode or asm-js data. // Generate the unoptimized bytecode or asm-js data.
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( DCHECK(inner_function_jobs->empty());
GenerateUnoptimizedCode(parse_info, allocator, inner_function_jobs));
// TODO(leszeks): Once we can handle asm-js without bailing out of
// off-thread finalization entirely, and the finalization is off-thread by
// default, this can be changed to the iterative version.
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job =
RecursivelyExecuteUnoptimizedCompilationJobs(
parse_info, parse_info->literal(), allocator, inner_function_jobs);
// Character stream shouldn't be used again.
parse_info->ResetCharacterStream();
return outer_function_job; return outer_function_job;
} }
...@@ -1171,8 +1179,7 @@ BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data, ...@@ -1171,8 +1179,7 @@ BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
worker_thread_runtime_call_stats_( worker_thread_runtime_call_stats_(
isolate->counters()->worker_thread_runtime_call_stats()), isolate->counters()->worker_thread_runtime_call_stats()),
timer_(isolate->counters()->compile_script_on_background()), timer_(isolate->counters()->compile_script_on_background()),
language_mode_(info_->language_mode()), language_mode_(info_->language_mode()) {
collected_source_positions_(false) {
VMState<PARSER> state(isolate); VMState<PARSER> state(isolate);
// Prepare the data for the internalization phase and compilation phase, which // Prepare the data for the internalization phase and compilation phase, which
...@@ -1211,7 +1218,6 @@ BackgroundCompileTask::BackgroundCompileTask( ...@@ -1211,7 +1218,6 @@ BackgroundCompileTask::BackgroundCompileTask(
worker_thread_runtime_call_stats_(worker_thread_runtime_stats), worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
timer_(timer), timer_(timer),
language_mode_(info_->language_mode()), language_mode_(info_->language_mode()),
collected_source_positions_(false),
finalize_on_background_thread_(false) { finalize_on_background_thread_(false) {
DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition); DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition);
DCHECK_NULL(outer_parse_info->extension()); DCHECK_NULL(outer_parse_info->extension());
...@@ -1317,7 +1323,6 @@ void BackgroundCompileTask::Run() { ...@@ -1317,7 +1323,6 @@ void BackgroundCompileTask::Run() {
} }
// Save the language mode and record whether we collected source positions. // Save the language mode and record whether we collected source positions.
language_mode_ = info_->language_mode(); language_mode_ = info_->language_mode();
collected_source_positions_ = info_->flags().collect_source_positions();
// We don't currently support off-thread finalization for some jobs (namely, // We don't currently support off-thread finalization for some jobs (namely,
// asm.js), so release the off-thread isolate and fall back to main-thread // asm.js), so release the off-thread isolate and fall back to main-thread
...@@ -1325,7 +1330,7 @@ void BackgroundCompileTask::Run() { ...@@ -1325,7 +1330,7 @@ void BackgroundCompileTask::Run() {
// TODO(leszeks): Still finalize Ignition tasks on the background thread, // TODO(leszeks): Still finalize Ignition tasks on the background thread,
// and fallback to main-thread finalization for asm.js jobs only. // and fallback to main-thread finalization for asm.js jobs only.
finalize_on_background_thread_ = finalize_on_background_thread_ =
finalize_on_background_thread_ && finalize_on_background_thread_ && outer_function_job_ &&
CanOffThreadFinalizeAllJobs(outer_function_job(), *inner_function_jobs()); CanOffThreadFinalizeAllJobs(outer_function_job(), *inner_function_jobs());
if (!finalize_on_background_thread_) { if (!finalize_on_background_thread_) {
...@@ -1348,18 +1353,23 @@ void BackgroundCompileTask::Run() { ...@@ -1348,18 +1353,23 @@ void BackgroundCompileTask::Run() {
OffThreadHandleScope handle_scope(isolate); OffThreadHandleScope handle_scope(isolate);
// We don't have the script source or the script origin yet, so use a few // We don't have the script source, origin, or details yet, so use default
// default values for them. These will be fixed up during the main-thread // values for them. These will be fixed up during the main-thread merge.
// merge. Handle<Script> script =
Handle<Script> script = info_->CreateScript( info_->CreateScript(isolate, isolate->factory()->empty_string(),
isolate, isolate->factory()->empty_string(), kNullMaybeHandle, kNullMaybeHandle, ScriptOriginOptions());
ScriptOriginOptions(), NOT_NATIVES_CODE);
MaybeHandle<SharedFunctionInfo> maybe_result; MaybeHandle<SharedFunctionInfo> maybe_result;
if (info_->literal() != nullptr) { if (info_->literal() != nullptr) {
maybe_result = info_->ast_value_factory()->Internalize(isolate);
FinalizeTopLevel(info_.get(), script, isolate,
outer_function_job_.get(), &inner_function_jobs_); Handle<SharedFunctionInfo> shared_info =
CreateTopLevelSharedFunctionInfo(info_.get(), script, isolate);
if (FinalizeAllUnoptimizedCompilationJobs(
info_.get(), isolate, shared_info, outer_function_job_.get(),
&inner_function_jobs_, &finalize_unoptimized_compilation_data_)) {
maybe_result = shared_info;
}
parser_->HandleSourceURLComments(isolate, script); parser_->HandleSourceURLComments(isolate, script);
} else { } else {
...@@ -1369,8 +1379,7 @@ void BackgroundCompileTask::Run() { ...@@ -1369,8 +1379,7 @@ void BackgroundCompileTask::Run() {
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
if (!maybe_result.ToHandle(&result)) { if (!maybe_result.ToHandle(&result)) {
DCHECK(compile_state_.pending_error_handler()->has_pending_error()); DCHECK(compile_state_.pending_error_handler()->has_pending_error());
FailWithPendingException(isolate, script, info_.get(), PreparePendingException(isolate, info_.get());
Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
} }
outer_function_sfi_ = isolate->TransferHandle(maybe_result); outer_function_sfi_ = isolate->TransferHandle(maybe_result);
...@@ -1447,9 +1456,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate, ...@@ -1447,9 +1456,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
parsing::ReportErrorsAndStatisticsMode::kNo)) { parsing::ReportErrorsAndStatisticsMode::kNo)) {
// Parsing failed probably as a result of stack exhaustion. // Parsing failed probably as a result of stack exhaustion.
bytecode->SetSourcePositionsFailedToCollect(); bytecode->SetSourcePositionsFailedToCollect();
return FailWithPendingException( return FailAndClearPendingException(isolate);
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
} }
// Character stream shouldn't be used again. // Character stream shouldn't be used again.
...@@ -1467,9 +1474,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate, ...@@ -1467,9 +1474,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) { job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) {
// Recompiling failed probably as a result of stack exhaustion. // Recompiling failed probably as a result of stack exhaustion.
bytecode->SetSourcePositionsFailedToCollect(); bytecode->SetSourcePositionsFailedToCollect();
return FailWithPendingException( return FailAndClearPendingException(isolate);
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
} }
} }
...@@ -1510,6 +1515,8 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, ...@@ -1510,6 +1515,8 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy()); AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
Handle<Script> script(Script::cast(shared_info->script()), isolate);
// Set up parse info. // Set up parse info.
UnoptimizedCompileFlags flags = UnoptimizedCompileFlags flags =
UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info); UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
...@@ -1522,9 +1529,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, ...@@ -1522,9 +1529,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (dispatcher->IsEnqueued(shared_info)) { if (dispatcher->IsEnqueued(shared_info)) {
if (!dispatcher->FinishNow(shared_info)) { if (!dispatcher->FinishNow(shared_info)) {
return FailWithPendingException( return FailWithPendingException(isolate, script, &parse_info, flag);
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, flag);
} }
*is_compiled_scope = shared_info->is_compiled_scope(); *is_compiled_scope = shared_info->is_compiled_scope();
DCHECK(is_compiled_scope->is_compiled()); DCHECK(is_compiled_scope->is_compiled());
...@@ -1541,52 +1546,24 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, ...@@ -1541,52 +1546,24 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
// Parse and update ParseInfo with the results. // Parse and update ParseInfo with the results.
if (!parsing::ParseAny(&parse_info, shared_info, isolate)) { if (!parsing::ParseAny(&parse_info, shared_info, isolate)) {
return FailWithPendingException( return FailWithPendingException(isolate, script, &parse_info, flag);
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, flag);
} }
// Generate the unoptimized bytecode or asm-js data. // Generate the unoptimized bytecode or asm-js data.
UnoptimizedCompilationJobList inner_function_jobs; FinalizeUnoptimizedCompilationDataList
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( finalize_unoptimized_compilation_data_list;
GenerateUnoptimizedCode(&parse_info, isolate->allocator(),
&inner_function_jobs));
if (!outer_function_job) {
return FailWithPendingException(
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, flag);
}
// Finalize compilation of the unoptimized bytecode or asm-js data. if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
if (!FinalizeUnoptimizedCode(&parse_info, isolate, shared_info, isolate, shared_info, script, &parse_info, isolate->allocator(),
outer_function_job.get(), is_compiled_scope, &finalize_unoptimized_compilation_data_list)) {
&inner_function_jobs)) { return FailWithPendingException(isolate, script, &parse_info, flag);
return FailWithPendingException(
isolate, handle(Script::cast(shared_info->script()), isolate),
&parse_info, flag);
} }
FinalizeUnoptimizedCompilation(isolate, script, flags, &compile_state,
finalize_unoptimized_compilation_data_list);
DCHECK(!isolate->has_pending_exception()); DCHECK(!isolate->has_pending_exception());
*is_compiled_scope = shared_info->is_compiled_scope();
DCHECK(is_compiled_scope->is_compiled()); DCHECK(is_compiled_scope->is_compiled());
if (FLAG_stress_lazy_source_positions) {
// Collect source positions immediately to try and flush out bytecode
// mismatches.
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
Handle<Script> script(Script::cast(shared_info->script()), isolate);
// Do the same for eagerly compiled inner functions.
for (auto&& inner_job : inner_function_jobs) {
Handle<SharedFunctionInfo> inner_shared_info =
Compiler::GetSharedFunctionInfo(
inner_job->compilation_info()->literal(), script, isolate);
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate,
inner_shared_info);
}
}
return true; return true;
} }
...@@ -1645,6 +1622,8 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag, ...@@ -1645,6 +1622,8 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
bool Compiler::FinalizeBackgroundCompileTask( bool Compiler::FinalizeBackgroundCompileTask(
BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info, BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ClearExceptionFlag flag) { Isolate* isolate, ClearExceptionFlag flag) {
DCHECK(!task->finalize_on_background_thread());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.FinalizeBackgroundCompileTask"); "V8.FinalizeBackgroundCompileTask");
RuntimeCallTimerScope runtimeTimer( RuntimeCallTimerScope runtimeTimer(
...@@ -1667,12 +1646,16 @@ bool Compiler::FinalizeBackgroundCompileTask( ...@@ -1667,12 +1646,16 @@ 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 (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info, if (!FinalizeAllUnoptimizedCompilationJobs(
task->outer_function_job(), parse_info, isolate, shared_info, task->outer_function_job(),
task->inner_function_jobs())) { task->inner_function_jobs(),
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);
} }
FinalizeUnoptimizedCompilation(
isolate, script, parse_info->flags(), parse_info->state(),
*task->finalize_unoptimized_compilation_data());
DCHECK(!isolate->has_pending_exception()); DCHECK(!isolate->has_pending_exception());
DCHECK(shared_info->is_compiled()); DCHECK(shared_info->is_compiled());
...@@ -2221,20 +2204,6 @@ Handle<Script> NewScript( ...@@ -2221,20 +2204,6 @@ Handle<Script> NewScript(
return script; return script;
} }
void FixUpOffThreadAllocatedScript(Isolate* isolate, Handle<Script> script,
Handle<String> source,
Compiler::ScriptDetails script_details,
ScriptOriginOptions origin_options,
NativesFlag natives) {
DisallowHeapAllocation no_gc;
DCHECK_EQ(natives, NOT_NATIVES_CODE);
DCHECK_EQ(script_details.repl_mode, REPLMode::kNo);
script->set_origin_options(origin_options);
script->set_source(*source);
SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
LOG(isolate, ScriptDetails(*script));
}
MaybeHandle<SharedFunctionInfo> CompileScriptOnMainThread( MaybeHandle<SharedFunctionInfo> CompileScriptOnMainThread(
const UnoptimizedCompileFlags flags, Handle<String> source, const UnoptimizedCompileFlags flags, Handle<String> source,
const Compiler::ScriptDetails& script_details, const Compiler::ScriptDetails& script_details,
...@@ -2558,6 +2527,9 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ...@@ -2558,6 +2527,9 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
Isolate* isolate, Handle<String> source, Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, ScriptOriginOptions origin_options, const ScriptDetails& script_details, ScriptOriginOptions origin_options,
ScriptStreamingData* streaming_data) { ScriptStreamingData* streaming_data) {
DCHECK(!origin_options.IsModule());
DCHECK(!origin_options.IsWasm());
ScriptCompileTimerScope compile_timer( ScriptCompileTimerScope compile_timer(
isolate, ScriptCompiler::kNoCacheBecauseStreamingSource); isolate, ScriptCompiler::kNoCacheBecauseStreamingSource);
PostponeInterruptsScope postpone(isolate); PostponeInterruptsScope postpone(isolate);
...@@ -2585,6 +2557,10 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ...@@ -2585,6 +2557,10 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
} }
if (maybe_result.is_null()) { if (maybe_result.is_null()) {
// No cache entry found, finalize compilation of the script and add it to
// the isolate cache.
Handle<Script> script;
if (task->finalize_on_background_thread()) { if (task->finalize_on_background_thread()) {
RuntimeCallTimerScope runtimeTimerScope( RuntimeCallTimerScope runtimeTimerScope(
isolate, RuntimeCallCounterId::kCompilePublishBackgroundFinalization); isolate, RuntimeCallCounterId::kCompilePublishBackgroundFinalization);
...@@ -2594,76 +2570,58 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ...@@ -2594,76 +2570,58 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
task->off_thread_isolate()->Publish(isolate); task->off_thread_isolate()->Publish(isolate);
maybe_result = task->outer_function_sfi(); maybe_result = task->outer_function_sfi();
Handle<Script> script = task->script(); script = task->script();
script->set_source(*source);
FixUpOffThreadAllocatedScript(isolate, script, source, script_details, script->set_origin_options(origin_options);
origin_options, NOT_NATIVES_CODE);
if (maybe_result.is_null()) {
// Off-thread parse, compile or finalization has failed - report error
// messages.
FailWithPendingExceptionAfterOffThreadFinalization(
isolate, script, task->pending_error_handler());
} else {
// Report any warnings generated during compilation.
if (task->pending_error_handler()->has_pending_warnings()) {
task->pending_error_handler()->ReportWarnings(isolate, script);
}
// It's possible that source position collection was enabled after the
// background compile was started (for instance by enabling the cpu
// profiler), and the compiled bytecode is missing source positions. So,
// walk all the SharedFunctionInfos in the script and force source
// position collection.
if (!task->collected_source_positions() &&
isolate->NeedsDetailedOptimizedCodeLineInfo()) {
Handle<WeakFixedArray> shared_function_infos(
script->shared_function_infos(isolate), isolate);
int length = shared_function_infos->length();
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
Object entry = shared_function_infos->Get(isolate, i)
.GetHeapObjectOrSmi(isolate);
if (entry.IsSharedFunctionInfo(isolate)) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate, handle(SharedFunctionInfo::cast(entry), isolate));
}
});
}
FinalizeScriptCompilation(isolate, script, task->parallel_tasks());
}
} else { } else {
ParseInfo* parse_info = task->info(); ParseInfo* parse_info = task->info();
DCHECK(parse_info->flags().is_toplevel()); DCHECK(parse_info->flags().is_toplevel());
// No cache entry found, finalize compilation of the script and add it to script = parse_info->CreateScript(isolate, source, kNullMaybeHandle,
// the isolate cache. origin_options);
Handle<Script> script =
NewScript(isolate, parse_info, source, script_details, origin_options,
NOT_NATIVES_CODE);
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 (parse_info->literal() != nullptr && task->outer_function_job()) {
// Off-thread parse & compile has succeeded - finalize compilation. // Off-thread parse & compile has succeeded - finalize compilation.
maybe_result = FinalizeTopLevel(parse_info, script, isolate, parse_info->ast_value_factory()->Internalize(isolate);
task->outer_function_job(),
task->inner_function_jobs()); Handle<SharedFunctionInfo> shared_info =
CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
if (FinalizeAllUnoptimizedCompilationJobs(
parse_info, isolate, shared_info, task->outer_function_job(),
task->inner_function_jobs(),
task->finalize_unoptimized_compilation_data())) {
maybe_result = shared_info;
}
} }
if (maybe_result.is_null()) { if (maybe_result.is_null()) {
// Compilation failed - throw an exception. // Compilation failed - prepare to throw an exception after script
FailWithPendingException(isolate, script, parse_info, // fields have been set.
Compiler::ClearExceptionFlag::KEEP_EXCEPTION); PreparePendingException(isolate, parse_info);
} else {
FinalizeScriptCompilation(isolate, script,
parse_info->parallel_tasks());
} }
} }
// Add compiled code to the isolate cache. // Set the script fields after finalization, to keep this path the same
// between main-thread and off-thread finalization.
{
DisallowHeapAllocation no_gc;
SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
LOG(isolate, ScriptDetails(*script));
}
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
if (maybe_result.ToHandle(&result)) { if (!maybe_result.ToHandle(&result)) {
FailWithPreparedPendingException(
isolate, script, task->compile_state()->pending_error_handler());
} else {
FinalizeUnoptimizedScriptCompilation(
isolate, script, task->flags(), task->compile_state(),
*task->finalize_unoptimized_compilation_data());
// Add compiled code to the isolate cache.
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.StreamingFinalization.AddToCache"); "V8.StreamingFinalization.AddToCache");
compilation_cache->PutScript(source, isolate->native_context(), compilation_cache->PutScript(source, isolate->native_context(),
...@@ -2684,7 +2642,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( ...@@ -2684,7 +2642,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
MaybeHandle<SharedFunctionInfo> maybe_existing; MaybeHandle<SharedFunctionInfo> maybe_existing;
// Find any previously allocated shared function info for the given literal. // Find any previously allocated shared function info for the given literal.
maybe_existing = script->FindSharedFunctionInfo(isolate, literal); maybe_existing =
script->FindSharedFunctionInfo(isolate, literal->function_literal_id());
// If we found an existing shared function info, return it. // If we found an existing shared function info, return it.
Handle<SharedFunctionInfo> existing; Handle<SharedFunctionInfo> existing;
......
...@@ -276,6 +276,13 @@ class UnoptimizedCompilationJob : public CompilationJob { ...@@ -276,6 +276,13 @@ class UnoptimizedCompilationJob : public CompilationJob {
uintptr_t stack_limit() const { return stack_limit_; } uintptr_t stack_limit() const { return stack_limit_; }
base::TimeDelta time_taken_to_execute() const {
return time_taken_to_execute_;
}
base::TimeDelta time_taken_to_finalize() const {
return time_taken_to_finalize_;
}
bool can_off_thread_finalize() const { return can_off_thread_finalize_; } bool can_off_thread_finalize() const { return can_off_thread_finalize_; }
protected: protected:
...@@ -354,6 +361,15 @@ class OptimizedCompilationJob : public CompilationJob { ...@@ -354,6 +361,15 @@ class OptimizedCompilationJob : public CompilationJob {
const char* compiler_name_; const char* compiler_name_;
}; };
struct FinalizeUnoptimizedCompilationData {
int function_literal_id;
base::TimeDelta time_taken_to_execute;
base::TimeDelta time_taken_to_finalize;
};
using FinalizeUnoptimizedCompilationDataList =
std::vector<FinalizeUnoptimizedCompilationData>;
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
...@@ -386,18 +402,14 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -386,18 +402,14 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
return &inner_function_jobs_; return &inner_function_jobs_;
} }
UnoptimizedCompileFlags flags() const { return flags_; } UnoptimizedCompileFlags flags() const { return flags_; }
const UnoptimizedCompileState* compile_state() const {
return &compile_state_;
}
LanguageMode language_mode() { return language_mode_; } LanguageMode language_mode() { return language_mode_; }
bool collected_source_positions() { return collected_source_positions_; }
bool finalize_on_background_thread() { bool finalize_on_background_thread() {
return finalize_on_background_thread_; return finalize_on_background_thread_;
} }
OffThreadIsolate* off_thread_isolate() { return off_thread_isolate_.get(); } OffThreadIsolate* off_thread_isolate() { return off_thread_isolate_.get(); }
PendingCompilationErrorHandler* pending_error_handler() {
return compile_state_.pending_error_handler();
}
UnoptimizedCompileState::ParallelTasks* parallel_tasks() {
return compile_state_.parallel_tasks();
}
MaybeHandle<SharedFunctionInfo> outer_function_sfi() { MaybeHandle<SharedFunctionInfo> outer_function_sfi() {
DCHECK_NOT_NULL(off_thread_isolate_); DCHECK_NOT_NULL(off_thread_isolate_);
return outer_function_sfi_.ToHandle(); return outer_function_sfi_.ToHandle();
...@@ -406,6 +418,10 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -406,6 +418,10 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
DCHECK_NOT_NULL(off_thread_isolate_); DCHECK_NOT_NULL(off_thread_isolate_);
return script_.ToHandle(); return script_.ToHandle();
} }
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data() {
return &finalize_unoptimized_compilation_data_;
}
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
...@@ -427,6 +443,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -427,6 +443,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
std::unique_ptr<OffThreadIsolate> off_thread_isolate_; std::unique_ptr<OffThreadIsolate> off_thread_isolate_;
OffThreadTransferMaybeHandle<SharedFunctionInfo> outer_function_sfi_; OffThreadTransferMaybeHandle<SharedFunctionInfo> outer_function_sfi_;
OffThreadTransferHandle<Script> script_; OffThreadTransferHandle<Script> script_;
FinalizeUnoptimizedCompilationDataList finalize_unoptimized_compilation_data_;
// Single function data for top-level function compilation. // Single function data for top-level function compilation.
int start_position_; int start_position_;
...@@ -437,7 +454,6 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { ...@@ -437,7 +454,6 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_; WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
TimedHistogram* timer_; TimedHistogram* timer_;
LanguageMode language_mode_; LanguageMode language_mode_;
bool collected_source_positions_;
// True if the background compilation should be finalized on the background // True if the background compilation should be finalized on the background
// thread. When this is true, the ParseInfo, Parser and compilation jobs are // thread. When this is true, the ParseInfo, Parser and compilation jobs are
......
...@@ -18,7 +18,7 @@ namespace internal { ...@@ -18,7 +18,7 @@ namespace internal {
UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone, UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone,
ParseInfo* parse_info, ParseInfo* parse_info,
FunctionLiteral* literal) FunctionLiteral* literal)
: flags_(parse_info->flags()), zone_(zone), feedback_vector_spec_(zone) { : flags_(parse_info->flags()), feedback_vector_spec_(zone) {
// NOTE: The parse_info passed here represents the global information gathered // NOTE: The parse_info passed here represents the global information gathered
// during parsing, but does not represent specific details of the actual // during parsing, but does not represent specific details of the actual
// function literal being compiled for this OptimizedCompilationInfo. As such, // function literal being compiled for this OptimizedCompilationInfo. As such,
......
...@@ -34,8 +34,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final { ...@@ -34,8 +34,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
UnoptimizedCompilationInfo(Zone* zone, ParseInfo* parse_info, UnoptimizedCompilationInfo(Zone* zone, ParseInfo* parse_info,
FunctionLiteral* literal); FunctionLiteral* literal);
Zone* zone() { return zone_; }
const UnoptimizedCompileFlags& flags() const { return flags_; } const UnoptimizedCompileFlags& flags() const { return flags_; }
// Accessors for the input data of the function being compiled. // Accessors for the input data of the function being compiled.
...@@ -87,10 +85,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final { ...@@ -87,10 +85,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
// Compilation flags. // Compilation flags.
const UnoptimizedCompileFlags flags_; const UnoptimizedCompileFlags flags_;
// The zone from which the compilation pipeline working on this
// OptimizedCompilationInfo allocates.
Zone* zone_;
// The root AST node of the function literal being compiled. // The root AST node of the function literal being compiled.
FunctionLiteral* literal_; FunctionLiteral* literal_;
......
...@@ -504,10 +504,14 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, ...@@ -504,10 +504,14 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
i_isolate, true, i::construct_language_mode(i::FLAG_use_strict), i_isolate, true, i::construct_language_mode(i::FLAG_use_strict),
i::REPLMode::kNo); i::REPLMode::kNo);
if (options.compile_options == v8::ScriptCompiler::kEagerCompile) {
flags.set_is_eager(true);
}
i::ParseInfo parse_info(i_isolate, flags, &compile_state); i::ParseInfo parse_info(i_isolate, flags, &compile_state);
i::Handle<i::Script> script = parse_info.CreateScript( i::Handle<i::Script> script = parse_info.CreateScript(
i_isolate, str, i::kNullMaybeHandle, options.compile_options); i_isolate, str, i::kNullMaybeHandle, ScriptOriginOptions());
if (!i::parsing::ParseProgram(&parse_info, script, i_isolate)) { if (!i::parsing::ParseProgram(&parse_info, script, i_isolate)) {
fprintf(stderr, "Failed parsing\n"); fprintf(stderr, "Failed parsing\n");
return false; return false;
......
...@@ -105,6 +105,8 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final ...@@ -105,6 +105,8 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final
// on the main thread. // on the main thread.
void Publish(Isolate* isolate); void Publish(Isolate* isolate);
bool has_pending_exception() const { return false; }
template <typename T> template <typename T>
Handle<T> Throw(Handle<Object> exception) { Handle<T> Throw(Handle<Object> exception) {
UNREACHABLE(); UNREACHABLE();
......
...@@ -1040,10 +1040,10 @@ static bool IsInEagerLiterals( ...@@ -1040,10 +1040,10 @@ static bool IsInEagerLiterals(
#endif // DEBUG #endif // DEBUG
BytecodeGenerator::BytecodeGenerator( BytecodeGenerator::BytecodeGenerator(
UnoptimizedCompilationInfo* info, Zone* compile_zone, UnoptimizedCompilationInfo* info,
const AstStringConstants* ast_string_constants, const AstStringConstants* ast_string_constants,
std::vector<FunctionLiteral*>* eager_inner_literals) std::vector<FunctionLiteral*>* eager_inner_literals)
: zone_(info->zone()), : zone_(compile_zone),
builder_(zone(), info->num_parameters_including_this(), builder_(zone(), info->num_parameters_including_this(),
info->scope()->num_stack_slots(), info->feedback_vector_spec(), info->scope()->num_stack_slots(), info->feedback_vector_spec(),
info->SourcePositionRecordingMode()), info->SourcePositionRecordingMode()),
......
...@@ -32,7 +32,7 @@ class BytecodeJumpTable; ...@@ -32,7 +32,7 @@ class BytecodeJumpTable;
class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
public: public:
explicit BytecodeGenerator( explicit BytecodeGenerator(
UnoptimizedCompilationInfo* info, Zone* zone, UnoptimizedCompilationInfo* info,
const AstStringConstants* ast_string_constants, const AstStringConstants* ast_string_constants,
std::vector<FunctionLiteral*>* eager_inner_literals); std::vector<FunctionLiteral*>* eager_inner_literals);
......
...@@ -152,7 +152,7 @@ InterpreterCompilationJob::InterpreterCompilationJob( ...@@ -152,7 +152,7 @@ InterpreterCompilationJob::InterpreterCompilationJob(
&compilation_info_, CanOffThreadFinalize::kYes), &compilation_info_, CanOffThreadFinalize::kYes),
zone_(allocator, ZONE_NAME), zone_(allocator, ZONE_NAME),
compilation_info_(&zone_, parse_info, literal), compilation_info_(&zone_, parse_info, literal),
generator_(&compilation_info_, parse_info->ast_string_constants(), generator_(&zone_, &compilation_info_, parse_info->ast_string_constants(),
eager_inner_literals) {} eager_inner_literals) {}
InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() { InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
......
...@@ -4907,14 +4907,14 @@ Object Script::GetNameOrSourceURL() { ...@@ -4907,14 +4907,14 @@ Object Script::GetNameOrSourceURL() {
template <typename LocalIsolate> template <typename LocalIsolate>
MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
LocalIsolate* isolate, const FunctionLiteral* fun) { LocalIsolate* isolate, int function_literal_id) {
CHECK_NE(fun->function_literal_id(), kFunctionLiteralIdInvalid); CHECK_NE(function_literal_id, kFunctionLiteralIdInvalid);
// If this check fails, the problem is most probably the function id // If this check fails, the problem is most probably the function id
// renumbering done by AstFunctionLiteralIdReindexer; in particular, that // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
// AstTraversalVisitor doesn't recurse properly in the construct which // AstTraversalVisitor doesn't recurse properly in the construct which
// triggers the mismatch. // triggers the mismatch.
CHECK_LT(fun->function_literal_id(), shared_function_infos().length()); CHECK_LT(function_literal_id, shared_function_infos().length());
MaybeObject shared = shared_function_infos().Get(fun->function_literal_id()); MaybeObject shared = shared_function_infos().Get(function_literal_id);
HeapObject heap_object; HeapObject heap_object;
if (!shared->GetHeapObject(&heap_object) || if (!shared->GetHeapObject(&heap_object) ||
heap_object.IsUndefined(isolate)) { heap_object.IsUndefined(isolate)) {
...@@ -4923,9 +4923,9 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( ...@@ -4923,9 +4923,9 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
return handle(SharedFunctionInfo::cast(heap_object), isolate); return handle(SharedFunctionInfo::cast(heap_object), isolate);
} }
template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
Isolate* isolate, const FunctionLiteral* fun); Isolate* isolate, int function_literal_id);
template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
OffThreadIsolate* isolate, const FunctionLiteral* fun); OffThreadIsolate* isolate, int function_literal_id);
Script::Iterator::Iterator(Isolate* isolate) Script::Iterator::Iterator(Isolate* isolate)
: iterator_(isolate->heap()->script_list()) {} : iterator_(isolate->heap()->script_list()) {}
......
...@@ -201,7 +201,7 @@ class Script : public Struct { ...@@ -201,7 +201,7 @@ class Script : public Struct {
// that matches the function literal. Return empty handle if not found. // that matches the function literal. Return empty handle if not found.
template <typename LocalIsolate> template <typename LocalIsolate>
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo( MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(
LocalIsolate* isolate, const FunctionLiteral* fun); LocalIsolate* isolate, int function_literal_id);
// Iterate over all script objects on the heap. // Iterate over all script objects on the heap.
class V8_EXPORT_PRIVATE Iterator { class V8_EXPORT_PRIVATE Iterator {
......
...@@ -188,6 +188,9 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileState { ...@@ -188,6 +188,9 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileState {
PendingCompilationErrorHandler* pending_error_handler() { PendingCompilationErrorHandler* pending_error_handler() {
return &pending_error_handler_; return &pending_error_handler_;
} }
const PendingCompilationErrorHandler* pending_error_handler() const {
return &pending_error_handler_;
}
ParallelTasks* parallel_tasks() const { return parallel_tasks_.get(); } ParallelTasks* parallel_tasks() const { return parallel_tasks_.get(); }
private: private:
......
...@@ -27,8 +27,9 @@ void MaybeReportErrorsAndStatistics(ParseInfo* info, Handle<Script> script, ...@@ -27,8 +27,9 @@ void MaybeReportErrorsAndStatistics(ParseInfo* info, Handle<Script> script,
ReportErrorsAndStatisticsMode mode) { ReportErrorsAndStatisticsMode mode) {
if (mode == ReportErrorsAndStatisticsMode::kYes) { if (mode == ReportErrorsAndStatisticsMode::kYes) {
if (info->literal() == nullptr) { if (info->literal() == nullptr) {
info->pending_error_handler()->ReportErrors(isolate, script, info->pending_error_handler()->PrepareErrors(isolate,
info->ast_value_factory()); info->ast_value_factory());
info->pending_error_handler()->ReportErrors(isolate, script);
} }
parser->UpdateStatistics(isolate, script); parser->UpdateStatistics(isolate, script);
} }
......
...@@ -9,35 +9,63 @@ ...@@ -9,35 +9,63 @@
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/messages.h" #include "src/execution/messages.h"
#include "src/execution/off-thread-isolate.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/heap/off-thread-factory-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void PendingCompilationErrorHandler::MessageDetails::TransferOffThreadHandle( void PendingCompilationErrorHandler::MessageDetails::SetString(
OffThreadIsolate* isolate) { Handle<String> string, Isolate* isolate) {
DCHECK_NE(type_, kMainThreadHandle); DCHECK_NE(type_, kMainThreadHandle);
if (type_ != kAstRawString) return; DCHECK_NE(type_, kOffThreadTransferHandle);
arg_transfer_handle_ = isolate->TransferHandle(arg_->string()); type_ = kMainThreadHandle;
arg_handle_ = string;
}
void PendingCompilationErrorHandler::MessageDetails::SetString(
Handle<String> string, OffThreadIsolate* isolate) {
DCHECK_NE(type_, kMainThreadHandle);
DCHECK_NE(type_, kOffThreadTransferHandle);
type_ = kOffThreadTransferHandle; type_ = kOffThreadTransferHandle;
arg_transfer_handle_ = isolate->TransferHandle(string);
} }
Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString( template <typename LocalIsolate>
Isolate* isolate) const { void PendingCompilationErrorHandler::MessageDetails::Prepare(
LocalIsolate* isolate) {
switch (type_) { switch (type_) {
case kAstRawString: case kAstRawString:
return arg_->string(); return SetString(arg_->string(), isolate);
case kNone: case kNone:
return isolate->factory()->undefined_string();
case kConstCharString: case kConstCharString:
return isolate->factory() // We can delay allocation until ArgumentString(isolate).
->NewStringFromUtf8(CStrVector(char_arg_)) // TODO(leszeks): We don't actually have to transfer this string, since
.ToHandleChecked(); // it's a root.
return;
case kMainThreadHandle:
case kOffThreadTransferHandle:
UNREACHABLE();
}
}
Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString(
Isolate* isolate) const {
switch (type_) {
case kMainThreadHandle: case kMainThreadHandle:
return arg_handle_; return arg_handle_;
case kOffThreadTransferHandle: case kOffThreadTransferHandle:
return arg_transfer_handle_.ToHandle(); return arg_transfer_handle_.ToHandle();
case kNone:
return isolate->factory()->undefined_string();
case kConstCharString:
return isolate->factory()
->NewStringFromUtf8(CStrVector(char_arg_), AllocationType::kOld)
.ToHandleChecked();
case kAstRawString:
UNREACHABLE();
} }
} }
...@@ -74,8 +102,20 @@ void PendingCompilationErrorHandler::ReportWarningAt(int start_position, ...@@ -74,8 +102,20 @@ void PendingCompilationErrorHandler::ReportWarningAt(int start_position,
MessageDetails(start_position, end_position, message, arg)); MessageDetails(start_position, end_position, message, arg));
} }
void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate, template <typename LocalIsolate>
Handle<Script> script) { void PendingCompilationErrorHandler::PrepareWarnings(LocalIsolate* isolate) {
DCHECK(!has_pending_error());
for (MessageDetails& warning : warning_messages_) {
warning.Prepare(isolate);
}
}
template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate);
template void PendingCompilationErrorHandler::PrepareWarnings(
OffThreadIsolate* isolate);
void PendingCompilationErrorHandler::ReportWarnings(
Isolate* isolate, Handle<Script> script) const {
DCHECK(!has_pending_error()); DCHECK(!has_pending_error());
for (const MessageDetails& warning : warning_messages_) { for (const MessageDetails& warning : warning_messages_) {
...@@ -89,53 +129,33 @@ void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate, ...@@ -89,53 +129,33 @@ void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate,
} }
} }
void PendingCompilationErrorHandler::ReportWarnings(OffThreadIsolate* isolate, template <typename LocalIsolate>
Handle<Script> script) { void PendingCompilationErrorHandler::PrepareErrors(
// Change any AstRawStrings to raw object pointers before the Ast Zone dies, LocalIsolate* isolate, AstValueFactory* ast_value_factory) {
// re-report later on the main thread. if (stack_overflow()) return;
DCHECK(!has_pending_error());
for (MessageDetails& warning : warning_messages_) {
warning.TransferOffThreadHandle(isolate);
}
}
void PendingCompilationErrorHandler::ReportErrors( DCHECK(has_pending_error());
Isolate* isolate, Handle<Script> script, // Internalize ast values for throwing the pending error.
AstValueFactory* ast_value_factory) { ast_value_factory->Internalize(isolate);
if (stack_overflow()) { error_details_.Prepare(isolate);
isolate->StackOverflow();
} else {
DCHECK(has_pending_error());
// Internalize ast values for throwing the pending error.
ast_value_factory->Internalize(isolate);
ThrowPendingError(isolate, script);
}
} }
template void PendingCompilationErrorHandler::PrepareErrors(
Isolate* isolate, AstValueFactory* ast_value_factory);
template void PendingCompilationErrorHandler::PrepareErrors(
OffThreadIsolate* isolate, AstValueFactory* ast_value_factory);
void PendingCompilationErrorHandler::PrepareErrorsOffThread( void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate,
OffThreadIsolate* isolate, Handle<Script> script, Handle<Script> script) const {
AstValueFactory* ast_value_factory) {
if (!stack_overflow()) {
DCHECK(has_pending_error());
// Internalize ast values for later throwing the pending error.
ast_value_factory->Internalize(isolate);
error_details_.TransferOffThreadHandle(isolate);
}
}
void PendingCompilationErrorHandler::ReportErrorsAfterOffThreadFinalization(
Isolate* isolate, Handle<Script> script) {
if (stack_overflow()) { if (stack_overflow()) {
isolate->StackOverflow(); isolate->StackOverflow();
} else { } else {
DCHECK(has_pending_error()); DCHECK(has_pending_error());
// Ast values should already be internalized.
ThrowPendingError(isolate, script); ThrowPendingError(isolate, script);
} }
} }
void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate, void PendingCompilationErrorHandler::ThrowPendingError(
Handle<Script> script) { Isolate* isolate, Handle<Script> script) const {
if (!has_pending_error_) return; if (!has_pending_error_) return;
MessageLocation location = error_details_.GetLocation(script); MessageLocation location = error_details_.GetLocation(script);
...@@ -149,7 +169,8 @@ void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate, ...@@ -149,7 +169,8 @@ void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate,
} }
Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest( Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(
Isolate* isolate) const { Isolate* isolate) {
error_details_.Prepare(isolate);
return MessageFormatter::Format(isolate, error_details_.message(), return MessageFormatter::Format(isolate, error_details_.message(),
error_details_.ArgumentString(isolate)); error_details_.ArgumentString(isolate));
} }
......
...@@ -48,23 +48,16 @@ class PendingCompilationErrorHandler { ...@@ -48,23 +48,16 @@ class PendingCompilationErrorHandler {
bool has_pending_warnings() const { return !warning_messages_.empty(); } bool has_pending_warnings() const { return !warning_messages_.empty(); }
// Handle errors detected during parsing. // Handle errors detected during parsing.
void ReportErrors(Isolate* isolate, Handle<Script> script, template <typename LocalIsolate>
AstValueFactory* ast_value_factory); void PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
// Prepare errors detected during off-thread parsing, to be reported later on void ReportErrors(Isolate* isolate, Handle<Script> script) const;
// the main thread.
void PrepareErrorsOffThread(OffThreadIsolate* isolate, Handle<Script> script,
AstValueFactory* ast_value_factory);
// Report errors detected during off-thread parsing, which were prepared
// off-thread during finalization by the above method.
void ReportErrorsAfterOffThreadFinalization(Isolate* isolate,
Handle<Script> script);
// Handle warnings detected during compilation. // Handle warnings detected during compilation.
void ReportWarnings(Isolate* isolate, Handle<Script> script); template <typename LocalIsolate>
void ReportWarnings(OffThreadIsolate* isolate, Handle<Script> script); void PrepareWarnings(LocalIsolate* isolate);
void ReportWarnings(Isolate* isolate, Handle<Script> script) const;
V8_EXPORT_PRIVATE Handle<String> FormatErrorMessageForTest( V8_EXPORT_PRIVATE Handle<String> FormatErrorMessageForTest(Isolate* isolate);
Isolate* isolate) const;
void set_unidentifiable_error() { void set_unidentifiable_error() {
has_pending_error_ = true; has_pending_error_ = true;
...@@ -106,32 +99,34 @@ class PendingCompilationErrorHandler { ...@@ -106,32 +99,34 @@ class PendingCompilationErrorHandler {
MessageLocation GetLocation(Handle<Script> script) const; MessageLocation GetLocation(Handle<Script> script) const;
MessageTemplate message() const { return message_; } MessageTemplate message() const { return message_; }
// After off-thread finalization, the Ast Zone will be deleted, so before template <typename LocalIsolate>
// that happens we have to transfer any string handles. void Prepare(LocalIsolate* isolate);
void TransferOffThreadHandle(OffThreadIsolate* isolate);
private: private:
enum Type { enum Type {
kNone, kNone,
kAstRawString, kAstRawString,
kConstCharString, kConstCharString,
kOffThreadTransferHandle, kMainThreadHandle,
kMainThreadHandle kOffThreadTransferHandle
}; };
void SetString(Handle<String> string, Isolate* isolate);
void SetString(Handle<String> string, OffThreadIsolate* isolate);
int start_position_; int start_position_;
int end_position_; int end_position_;
MessageTemplate message_; MessageTemplate message_;
union { union {
const AstRawString* arg_; const AstRawString* arg_;
const char* char_arg_; const char* char_arg_;
OffThreadTransferHandle<String> arg_transfer_handle_;
Handle<String> arg_handle_; Handle<String> arg_handle_;
OffThreadTransferHandle<String> arg_transfer_handle_;
}; };
Type type_; Type type_;
}; };
void ThrowPendingError(Isolate* isolate, Handle<Script> script); void ThrowPendingError(Isolate* isolate, Handle<Script> script) const;
bool has_pending_error_; bool has_pending_error_;
bool stack_overflow_; bool stack_overflow_;
......
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