Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/codegen/compiler.cc')
-rw-r--r--deps/v8/src/codegen/compiler.cc1142
1 files changed, 644 insertions, 498 deletions
diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc
index 595e59f5514..c436c57407c 100644
--- a/deps/v8/src/codegen/compiler.cc
+++ b/deps/v8/src/codegen/compiler.cc
@@ -30,6 +30,7 @@
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/isolate.h"
+#include "src/execution/off-thread-isolate.h"
#include "src/execution/runtime-profiler.h"
#include "src/execution/vm-state-inl.h"
#include "src/handles/maybe-handles.h"
@@ -42,10 +43,11 @@
#include "src/objects/map.h"
#include "src/objects/object-list-macros.h"
#include "src/objects/shared-function-info.h"
+#include "src/objects/string.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
-#include "src/parsing/rewriter.h"
+#include "src/parsing/pending-compilation-error-handler.h"
#include "src/parsing/scanner-character-streams.h"
#include "src/snapshot/code-serializer.h"
#include "src/utils/ostreams.h"
@@ -179,13 +181,15 @@ CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob(
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;
- if (compilation_info()->has_bytecode_array()) {
- code_size = compilation_info()->bytecode_array()->SizeIncludingMetadata();
+ if (shared_info->HasBytecodeArray()) {
+ code_size = shared_info->GetBytecodeArray().SizeIncludingMetadata();
} else {
- DCHECK(compilation_info()->has_asm_wasm_data());
- code_size = compilation_info()->asm_wasm_data()->Size();
+ code_size = shared_info->asm_wasm_data().Size();
}
Counters* counters = isolate->counters();
@@ -197,27 +201,30 @@ void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const {
// Also add total time (there's now already timer_ on the base class).
}
-void UnoptimizedCompilationJob::RecordFunctionCompilation(
- CodeEventListener::LogEventsAndTags tag, Handle<SharedFunctionInfo> shared,
- Isolate* isolate) const {
+void RecordUnoptimizedFunctionCompilation(
+ Isolate* isolate, CodeEventListener::LogEventsAndTags tag,
+ Handle<SharedFunctionInfo> shared, base::TimeDelta time_taken_to_execute,
+ base::TimeDelta time_taken_to_finalize) {
Handle<AbstractCode> abstract_code;
- if (compilation_info()->has_bytecode_array()) {
+ if (shared->HasBytecodeArray()) {
abstract_code =
- Handle<AbstractCode>::cast(compilation_info()->bytecode_array());
+ handle(AbstractCode::cast(shared->GetBytecodeArray()), isolate);
} else {
- DCHECK(compilation_info()->has_asm_wasm_data());
+ DCHECK(shared->HasAsmWasmData());
abstract_code =
Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs));
}
- double time_taken_ms = time_taken_to_execute_.InMillisecondsF() +
- time_taken_to_finalize_.InMillisecondsF();
+ double time_taken_ms = time_taken_to_execute.InMillisecondsF() +
+ time_taken_to_finalize.InMillisecondsF();
Handle<Script> script(Script::cast(shared->script()), isolate);
LogFunctionCompilation(tag, shared, script, abstract_code, false,
time_taken_ms, isolate);
}
+} // namespace
+
// ----------------------------------------------------------------------------
// Implementation of OptimizedCompilationJob
@@ -383,13 +390,15 @@ bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
return literal->scope()->IsAsmModule();
}
-void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array,
- Handle<SharedFunctionInfo> shared_info,
- ParseInfo* parse_info, Isolate* isolate) {
- if (!FLAG_interpreted_frames_native_stack) {
- shared_info->set_bytecode_array(*bytecode_array);
+void InstallInterpreterTrampolineCopy(Isolate* isolate,
+ Handle<SharedFunctionInfo> shared_info) {
+ DCHECK(FLAG_interpreted_frames_native_stack);
+ if (!shared_info->function_data().IsBytecodeArray()) {
+ DCHECK(!shared_info->HasBytecodeArray());
return;
}
+ Handle<BytecodeArray> bytecode_array(shared_info->GetBytecodeArray(),
+ isolate);
Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
isolate->factory()->interpreter_entry_trampoline_for_profiling()));
@@ -419,9 +428,23 @@ void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array,
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,
Handle<SharedFunctionInfo> shared_info,
- ParseInfo* parse_info, Isolate* isolate) {
+ LocalIsolate* isolate) {
DCHECK_EQ(shared_info->language_mode(),
compilation_info->literal()->language_mode());
@@ -440,63 +463,52 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
shared_info->set_is_asm_wasm_broken(true);
}
- InstallBytecodeArray(compilation_info->bytecode_array(), shared_info,
- parse_info, isolate);
+ shared_info->set_bytecode_array(*compilation_info->bytecode_array());
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
shared_info->set_feedback_metadata(*feedback_metadata);
} else {
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_feedback_metadata(
ReadOnlyRoots(isolate).empty_feedback_metadata());
}
- // Install coverage info on the shared function info.
if (compilation_info->has_coverage_info() &&
!shared_info->HasCoverageInfo()) {
- DCHECK(isolate->is_block_code_coverage());
- isolate->debug()->InstallCoverageInfo(shared_info,
- compilation_info->coverage_info());
+ InstallCoverageInfo(isolate, shared_info,
+ compilation_info->coverage_info());
}
}
-void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
- Handle<SharedFunctionInfo> shared_info,
- ParseInfo* parse_info, OffThreadIsolate* 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);
-
- DCHECK(compilation_info->has_bytecode_array());
- DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once.
- 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);
+void LogUnoptimizedCompilation(Isolate* isolate,
+ Handle<SharedFunctionInfo> shared_info,
+ UnoptimizedCompileFlags flags,
+ base::TimeDelta time_taken_to_execute,
+ base::TimeDelta time_taken_to_finalize) {
+ 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;
}
- shared_info->set_bytecode_array(*compilation_info->bytecode_array());
-
- Handle<FeedbackMetadata> feedback_metadata =
- FeedbackMetadata::New(isolate, compilation_info->feedback_vector_spec());
- shared_info->set_feedback_metadata(*feedback_metadata);
-
- DCHECK(!compilation_info->has_coverage_info());
+ RecordUnoptimizedFunctionCompilation(isolate, log_tag, shared_info,
+ time_taken_to_execute,
+ time_taken_to_finalize);
+ RecordUnoptimizedCompilationStats(isolate, shared_info);
}
template <typename LocalIsolate>
void EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script,
ParseInfo* parse_info,
LocalIsolate* isolate) {
- DCHECK(parse_info->is_toplevel());
+ DCHECK(parse_info->flags().is_toplevel());
if (script->shared_function_infos().length() > 0) {
DCHECK_EQ(script->shared_function_infos().length(),
parse_info->max_function_literal_id() + 1);
@@ -524,63 +536,32 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal,
literal->has_static_private_methods_or_accessors());
}
-CompilationJob::Status FinalizeUnoptimizedCompilationJob(
- UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate) {
- UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
- ParseInfo* parse_info = job->parse_info();
-
- 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 (!parse_info->collect_source_positions() &&
- isolate->NeedsDetailedOptimizedCodeLineInfo()) {
- SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
- }
-
- CodeEventListener::LogEventsAndTags log_tag;
- if (parse_info->is_toplevel()) {
- log_tag = compilation_info->is_eval() ? CodeEventListener::EVAL_TAG
- : CodeEventListener::SCRIPT_TAG;
- } else {
- log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
- : CodeEventListener::FUNCTION_TAG;
- }
- job->RecordFunctionCompilation(log_tag, shared_info, isolate);
- job->RecordCompilationStats(isolate);
- }
- return status;
-}
-
-CompilationJob::Status FinalizeUnoptimizedCompilationJob(
+template <typename LocalIsolate>
+CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
- OffThreadIsolate* isolate) {
+ LocalIsolate* isolate,
+ FinalizeUnoptimizedCompilationDataList*
+ finalize_unoptimized_compilation_data_list) {
UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
- ParseInfo* parse_info = job->parse_info();
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);
-
- // TODO(leszeks): Record the function compilation and compilation stats.
+ InstallUnoptimizedCode(compilation_info, shared_info, isolate);
+ finalize_unoptimized_compilation_data_list->emplace_back(
+ isolate, shared_info, job->time_taken_to_execute(),
+ job->time_taken_to_finalize());
}
return status;
}
-std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
+std::unique_ptr<UnoptimizedCompilationJob>
+ExecuteSingleUnoptimizedCompilationJob(
ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator,
- UnoptimizedCompilationJobList* inner_function_jobs) {
- if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
+ std::vector<FunctionLiteral*>* eager_inner_literals) {
+ 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) {
@@ -592,21 +573,35 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
// with a validation error or another error that could be solve by falling
// through to standard unoptimized compile.
}
- std::vector<FunctionLiteral*> eager_inner_literals;
std::unique_ptr<UnoptimizedCompilationJob> job(
interpreter::Interpreter::NewCompilationJob(
- parse_info, literal, allocator, &eager_inner_literals));
+ parse_info, literal, allocator, eager_inner_literals));
if (job->ExecuteJob() != CompilationJob::SUCCEEDED) {
// Compilation failed, return null.
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.
for (FunctionLiteral* inner_literal : eager_inner_literals) {
std::unique_ptr<UnoptimizedCompilationJob> inner_job(
- ExecuteUnoptimizedCompileJobs(parse_info, inner_literal, allocator,
- inner_function_jobs));
+ RecursivelyExecuteUnoptimizedCompilationJobs(
+ parse_info, inner_literal, allocator, inner_function_jobs));
// Compilation failed, return null.
if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>();
inner_function_jobs->emplace_front(std::move(inner_job));
@@ -615,39 +610,14 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
return job;
}
-std::unique_ptr<UnoptimizedCompilationJob> GenerateUnoptimizedCode(
- ParseInfo* parse_info, AccountingAllocator* allocator,
- UnoptimizedCompilationJobList* inner_function_jobs) {
- DisallowHeapAccess no_heap_access;
- DCHECK(inner_function_jobs->empty());
-
- std::unique_ptr<UnoptimizedCompilationJob> job;
- if (Compiler::Analyze(parse_info)) {
- 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);
- parse_info->ast_value_factory()->Internalize(isolate);
-
- if (!Compiler::Analyze(parse_info)) return MaybeHandle<SharedFunctionInfo>();
+bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
+ Isolate* isolate, Handle<SharedFunctionInfo> outer_shared_info,
+ Handle<Script> script, ParseInfo* parse_info,
+ AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope,
+ FinalizeUnoptimizedCompilationDataList*
+ finalize_unoptimized_compilation_data_list) {
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;
functions_to_compile.push_back(parse_info->literal());
@@ -657,57 +627,42 @@ MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(literal, script, isolate);
if (shared_info->is_compiled()) continue;
- if (UseAsmWasm(literal, parse_info->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 ||
- FinalizeUnoptimizedCompilationJob(job.get(), shared_info, isolate) ==
- CompilationJob::FAILED) {
- return MaybeHandle<SharedFunctionInfo>();
- }
+ std::unique_ptr<UnoptimizedCompilationJob> job =
+ ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
+ &functions_to_compile);
+ if (!job) return false;
- if (FLAG_stress_lazy_source_positions) {
- // Collect source positions immediately to try and flush out bytecode
- // mismatches.
- SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
+ if (FinalizeSingleUnoptimizedCompilationJob(
+ job.get(), shared_info, isolate,
+ finalize_unoptimized_compilation_data_list) !=
+ 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.
*is_compiled_scope = shared_info->is_compiled_scope();
DCHECK(is_compiled_scope->is_compiled());
}
}
- // Character stream shouldn't be used again.
- parse_info->ResetCharacterStream();
+ // Report any warnings generated during compilation.
+ if (parse_info->pending_error_handler()->has_pending_warnings()) {
+ parse_info->pending_error_handler()->PrepareWarnings(isolate);
+ }
- return top_level;
+ return true;
}
template <typename LocalIsolate>
-bool FinalizeUnoptimizedCode(
+bool FinalizeAllUnoptimizedCompilationJobs(
ParseInfo* parse_info, LocalIsolate* isolate,
Handle<SharedFunctionInfo> shared_info,
UnoptimizedCompilationJob* outer_function_job,
- UnoptimizedCompilationJobList* inner_function_jobs) {
+ UnoptimizedCompilationJobList* inner_function_jobs,
+ FinalizeUnoptimizedCompilationDataList*
+ finalize_unoptimized_compilation_data_list) {
// TODO(leszeks): Re-enable.
// DCHECK(AllowCompilation::IsAllowed(isolate));
@@ -718,8 +673,10 @@ bool FinalizeUnoptimizedCode(
DeclarationScope::AllocateScopeInfos(parse_info, isolate);
// Finalize the outer-most function's compilation job.
- if (FinalizeUnoptimizedCompilationJob(outer_function_job, shared_info,
- isolate) != CompilationJob::SUCCEEDED) {
+ if (FinalizeSingleUnoptimizedCompilationJob(
+ outer_function_job, shared_info, isolate,
+ finalize_unoptimized_compilation_data_list) !=
+ CompilationJob::SUCCEEDED) {
return false;
}
@@ -733,8 +690,9 @@ bool FinalizeUnoptimizedCode(
inner_job->compilation_info()->literal(), script, isolate);
// The inner function might be compiled already if compiling for debug.
if (inner_shared_info->is_compiled()) continue;
- if (FinalizeUnoptimizedCompilationJob(inner_job.get(), inner_shared_info,
- isolate) !=
+ if (FinalizeSingleUnoptimizedCompilationJob(
+ inner_job.get(), inner_shared_info, isolate,
+ finalize_unoptimized_compilation_data_list) !=
CompilationJob::SUCCEEDED) {
return false;
}
@@ -742,7 +700,7 @@ bool FinalizeUnoptimizedCode(
// Report any warnings generated during compilation.
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;
@@ -994,15 +952,26 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
return MaybeHandle<Code>();
}
-bool FailWithPendingException(Isolate* isolate, Handle<Script> script,
- ParseInfo* parse_info,
- 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());
+bool FailAndClearPendingException(Isolate* isolate) {
+ isolate->clear_pending_exception();
+ return false;
+}
+
+template <typename LocalIsolate>
+bool PreparePendingException(LocalIsolate* isolate, ParseInfo* parse_info) {
+ if (parse_info->pending_error_handler()->has_pending_error()) {
+ parse_info->pending_error_handler()->PrepareErrors(
+ isolate, parse_info->ast_value_factory());
+ }
+ return false;
+}
+
+bool FailWithPreparedPendingException(
+ Isolate* isolate, Handle<Script> script,
+ const PendingCompilationErrorHandler* pending_error_handler) {
+ if (!isolate->has_pending_exception()) {
+ if (pending_error_handler->has_pending_error()) {
+ pending_error_handler->ReportErrors(isolate, script);
} else {
isolate->StackOverflow();
}
@@ -1010,25 +979,74 @@ bool FailWithPendingException(Isolate* isolate, Handle<Script> script,
return false;
}
-bool FailWithPendingException(OffThreadIsolate* isolate, Handle<Script> script,
+bool FailWithPendingException(Isolate* isolate, Handle<Script> script,
ParseInfo* parse_info,
Compiler::ClearExceptionFlag flag) {
- // TODO(leszeks): Implement.
- UNREACHABLE();
+ 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,
+ 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());
+
+ for (const auto& finalize_data : finalize_unoptimized_compilation_data_list) {
+ Handle<SharedFunctionInfo> shared_info = finalize_data.function_handle();
+ // It's unlikely, but possible, that the bytecode was flushed between being
+ // allocated and now, so guard against that case, and against it being
+ // flushed in the middle of this loop.
+ IsCompiledScope is_compiled_scope(*shared_info, isolate);
+ if (!is_compiled_scope.is_compiled()) continue;
+
+ if (need_source_positions) {
+ SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
+ }
+ if (FLAG_interpreted_frames_native_stack) {
+ InstallInterpreterTrampolineCopy(isolate, shared_info);
+ }
+
+ LogUnoptimizedCompilation(isolate, shared_info, flags,
+ finalize_data.time_taken_to_execute(),
+ finalize_data.time_taken_to_finalize());
+ }
}
-void FinalizeScriptCompilation(Isolate* isolate, Handle<Script> script,
- ParseInfo* parse_info) {
+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);
- // Register any pending parallel tasks with the associated SFI.
- if (parse_info->parallel_tasks()) {
- CompilerDispatcher* dispatcher = parse_info->parallel_tasks()->dispatcher();
- for (auto& it : *parse_info->parallel_tasks()) {
+ UnoptimizedCompileState::ParallelTasks* parallel_tasks =
+ compile_state->parallel_tasks();
+ if (parallel_tasks) {
+ CompilerDispatcher* dispatcher = parallel_tasks->dispatcher();
+ for (auto& it : *parallel_tasks) {
FunctionLiteral* literal = it.first;
CompilerDispatcher::JobId job_id = it.second;
MaybeHandle<SharedFunctionInfo> maybe_shared_for_task =
- script->FindSharedFunctionInfo(isolate, literal);
+ script->FindSharedFunctionInfo(isolate,
+ literal->function_literal_id());
Handle<SharedFunctionInfo> shared_for_task;
if (maybe_shared_for_task.ToHandle(&shared_for_task)) {
dispatcher->RegisterSharedFunctionInfo(job_id, *shared_for_task);
@@ -1037,42 +1055,22 @@ void FinalizeScriptCompilation(Isolate* isolate, Handle<Script> script,
}
}
}
-}
-void FinalizeScriptCompilation(OffThreadIsolate* isolate, Handle<Script> script,
- ParseInfo* parse_info) {
- script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
- DCHECK(!parse_info->parallel_tasks());
+ if (isolate->NeedsSourcePositionsForProfiling()) {
+ Script::InitLineEnds(isolate, script);
+ }
}
+// Create shared function info for top level and shared function infos array for
+// inner functions.
template <typename LocalIsolate>
-MaybeHandle<SharedFunctionInfo> FinalizeTopLevel(
- 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.
+Handle<SharedFunctionInfo> CreateTopLevelSharedFunctionInfo(
+ ParseInfo* parse_info, Handle<Script> script, LocalIsolate* isolate) {
EnsureSharedFunctionInfosArrayOnScript(script, parse_info, isolate);
DCHECK_EQ(kNoSourcePosition,
parse_info->literal()->function_token_position());
- Handle<SharedFunctionInfo> shared_info =
- isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(),
- 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)) {
- FailWithPendingException(isolate, script, parse_info,
- Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
- return MaybeHandle<SharedFunctionInfo>();
- }
-
- FinalizeScriptCompilation(isolate, script, parse_info);
-
- return shared_info;
+ return isolate->factory()->NewSharedFunctionInfoForLiteral(
+ parse_info->literal(), script, true);
}
MaybeHandle<SharedFunctionInfo> CompileToplevel(
@@ -1086,8 +1084,9 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
PostponeInterruptsScope postpone(isolate);
DCHECK(!isolate->native_context().is_null());
RuntimeCallTimerScope runtimeTimer(
- isolate, parse_info->is_eval() ? RuntimeCallCounterId::kCompileEval
- : RuntimeCallCounterId::kCompileScript);
+ isolate, parse_info->flags().is_eval()
+ ? RuntimeCallCounterId::kCompileEval
+ : RuntimeCallCounterId::kCompileScript);
VMState<BYTECODE_COMPILER> state(isolate);
if (parse_info->literal() == nullptr &&
!parsing::ParseProgram(parse_info, script, maybe_outer_scope_info,
@@ -1097,24 +1096,36 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
// parsing statistics.
- HistogramTimer* rate = parse_info->is_eval()
+ HistogramTimer* rate = parse_info->flags().is_eval()
? isolate->counters()->compile_eval()
: isolate->counters()->compile();
HistogramTimerScope timer(rate);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
- parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
+ parse_info->flags().is_eval() ? "V8.CompileEval" : "V8.Compile");
- // Generate the unoptimized bytecode or asm-js data.
- MaybeHandle<SharedFunctionInfo> shared_info =
- GenerateUnoptimizedCodeForToplevel(
- isolate, script, parse_info, isolate->allocator(), is_compiled_scope);
- if (shared_info.is_null()) {
+ // Prepare and execute compilation of the outer-most function.
+
+ // Create the SharedFunctionInfo and add it to the script's list.
+ Handle<SharedFunctionInfo> shared_info =
+ 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,
Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
return MaybeHandle<SharedFunctionInfo>();
}
- FinalizeScriptCompilation(isolate, script, parse_info);
+ // 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;
}
@@ -1126,15 +1137,25 @@ std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread(
"V8.CompileCodeBackground");
RuntimeCallTimerScope runtimeTimer(
parse_info->runtime_call_stats(),
- parse_info->is_toplevel()
- ? parse_info->is_eval()
+ parse_info->flags().is_toplevel()
+ ? parse_info->flags().is_eval()
? RuntimeCallCounterId::kCompileBackgroundEval
: RuntimeCallCounterId::kCompileBackgroundScript
: RuntimeCallCounterId::kCompileBackgroundFunction);
// Generate the unoptimized bytecode or asm-js data.
- std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
- GenerateUnoptimizedCode(parse_info, allocator, inner_function_jobs));
+ DCHECK(inner_function_jobs->empty());
+
+ // 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;
}
@@ -1149,55 +1170,67 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
Isolate* isolate)
- : info_(new ParseInfo(isolate)),
- off_thread_isolate_(FLAG_finalize_streaming_on_background
- ? new OffThreadIsolate(isolate, info_->zone())
- : nullptr),
+ : flags_(UnoptimizedCompileFlags::ForToplevelCompile(
+ isolate, true, construct_language_mode(FLAG_use_strict),
+ REPLMode::kNo)),
+ compile_state_(isolate),
+ info_(std::make_unique<ParseInfo>(isolate, flags_, &compile_state_)),
+ start_position_(0),
+ end_position_(0),
+ function_literal_id_(kFunctionLiteralIdTopLevel),
stack_size_(i::FLAG_stack_size),
worker_thread_runtime_call_stats_(
isolate->counters()->worker_thread_runtime_call_stats()),
- allocator_(isolate->allocator()),
timer_(isolate->counters()->compile_script_on_background()),
- collected_source_positions_(false) {
+ language_mode_(info_->language_mode()) {
VMState<PARSER> state(isolate);
// Prepare the data for the internalization phase and compilation phase, which
// will happen in the main thread after parsing.
+
LOG(isolate, ScriptEvent(Logger::ScriptEventType::kStreamingCompile,
- info_->script_id()));
- info_->SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(), true,
- construct_language_mode(FLAG_use_strict),
- REPLMode::kNo);
- language_mode_ = info_->language_mode();
+ info_->flags().script_id()));
std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(
streamed_data->source_stream.get(), streamed_data->encoding));
info_->set_character_stream(std::move(stream));
- finalize_on_background_thread_ = FLAG_finalize_streaming_on_background;
+ // TODO(leszeks): Add block coverage support to off-thread finalization.
+ finalize_on_background_thread_ =
+ FLAG_finalize_streaming_on_background && !flags_.block_coverage_enabled();
+ if (finalize_on_background_thread()) {
+ off_thread_isolate_ =
+ std::make_unique<OffThreadIsolate>(isolate, info_->zone());
+ }
}
BackgroundCompileTask::BackgroundCompileTask(
- AccountingAllocator* allocator, const ParseInfo* outer_parse_info,
- const AstRawString* function_name, const FunctionLiteral* function_literal,
+ const ParseInfo* outer_parse_info, const AstRawString* function_name,
+ const FunctionLiteral* function_literal,
WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
TimedHistogram* timer, int max_stack_size)
- : info_(ParseInfo::FromParent(outer_parse_info, allocator, function_literal,
- function_name)),
+ : flags_(UnoptimizedCompileFlags::ForToplevelFunction(
+ outer_parse_info->flags(), function_literal)),
+ compile_state_(*outer_parse_info->state()),
+ info_(ParseInfo::ForToplevelFunction(flags_, &compile_state_,
+ function_literal, function_name)),
+ start_position_(function_literal->start_position()),
+ end_position_(function_literal->end_position()),
+ function_literal_id_(function_literal->function_literal_id()),
stack_size_(max_stack_size),
worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
- allocator_(allocator),
timer_(timer),
language_mode_(info_->language_mode()),
- collected_source_positions_(false),
finalize_on_background_thread_(false) {
- DCHECK(outer_parse_info->is_toplevel());
+ DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition);
+ DCHECK_NULL(outer_parse_info->extension());
+
DCHECK(!function_literal->is_toplevel());
// Clone the character stream so both can be accessed independently.
std::unique_ptr<Utf16CharacterStream> character_stream =
outer_parse_info->character_stream()->Clone();
- character_stream->Seek(function_literal->start_position());
+ character_stream->Seek(start_position_);
info_->set_character_stream(std::move(character_stream));
// Get preparsed scope data from the function literal.
@@ -1225,14 +1258,14 @@ class OffThreadParseInfoScope {
original_runtime_call_stats_(parse_info_->runtime_call_stats()),
original_stack_limit_(parse_info_->stack_limit()),
worker_thread_scope_(worker_thread_runtime_stats) {
- parse_info_->set_runtime_call_stats(worker_thread_scope_.Get());
- parse_info_->set_stack_limit(GetCurrentStackPosition() - stack_size * KB);
+ parse_info_->SetPerThreadState(GetCurrentStackPosition() - stack_size * KB,
+ worker_thread_scope_.Get());
}
~OffThreadParseInfoScope() {
DCHECK_NOT_NULL(parse_info_);
- parse_info_->set_stack_limit(original_stack_limit_);
- parse_info_->set_runtime_call_stats(original_runtime_call_stats_);
+ parse_info_->SetPerThreadState(original_stack_limit_,
+ original_runtime_call_stats_);
}
private:
@@ -1244,6 +1277,20 @@ class 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
void BackgroundCompileTask::Run() {
@@ -1270,82 +1317,94 @@ void BackgroundCompileTask::Run() {
parser_.reset(new Parser(info_.get()));
parser_->InitializeEmptyScopeChain(info_.get());
- parser_->ParseOnBackground(info_.get());
+ parser_->ParseOnBackground(info_.get(), start_position_, end_position_,
+ function_literal_id_);
if (info_->literal() != nullptr) {
// Parsing has succeeded, compile.
- outer_function_job_ = CompileOnBackgroundThread(info_.get(), allocator_,
- &inner_function_jobs_);
- // Save the language mode and record whether we collected source positions.
- language_mode_ = info_->language_mode();
- collected_source_positions_ = info_->collect_source_positions();
-
- if (finalize_on_background_thread_) {
- DCHECK(info_->is_toplevel());
+ 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();
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
- "V8.FinalizeCodeBackground");
+ // 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
+ // 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_) {
+ off_thread_isolate_.reset();
+ return;
+ }
- off_thread_isolate_->PinToCurrentThread();
+ // ---
+ // At this point, off-thread compilation has completed and we are off-thread
+ // finalizing.
+ // ---
- OffThreadHandleScope handle_scope(off_thread_isolate_.get());
+ DCHECK(info_->flags().is_toplevel());
- // We don't have the script source or the script origin yet, so use a few
- // default values for them. These will be fixed up during the main-thread
- // merge.
- Handle<Script> script =
- info_->CreateScript(off_thread_isolate_.get(),
- off_thread_isolate_->factory()->empty_string(),
- ScriptOriginOptions(), NOT_NATIVES_CODE);
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
+ "V8.FinalizeCodeBackground");
- Handle<SharedFunctionInfo> outer_function_sfi =
- FinalizeTopLevel(info_.get(), script, off_thread_isolate_.get(),
- outer_function_job_.get(), &inner_function_jobs_)
- .ToHandleChecked();
+ OffThreadIsolate* isolate = off_thread_isolate();
+ isolate->PinToCurrentThread();
- parser_->HandleSourceURLComments(off_thread_isolate_.get(), script);
+ OffThreadHandleScope handle_scope(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
- "V8.FinalizeCodeBackground.Finish");
- off_thread_isolate_->FinishOffThread();
+ // We don't have the script source, origin, or details yet, so use default
+ // 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());
- // Off-thread handles will become invalid after the handle scope closes,
- // so save the raw object here.
- outer_function_sfi_ = *outer_function_sfi;
+ MaybeHandle<SharedFunctionInfo> maybe_result;
+ if (info_->literal() != nullptr) {
+ info_->ast_value_factory()->Internalize(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
- "V8.FinalizeCodeBackground.ReleaseParser");
- DCHECK_EQ(language_mode_, info_->language_mode());
- off_thread_scope.reset();
- parser_.reset();
- info_.reset();
- outer_function_job_.reset();
- inner_function_jobs_.clear();
+ 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);
+ } else {
+ DCHECK(!outer_function_job_);
}
-}
-// ----------------------------------------------------------------------------
-// Implementation of Compiler
+ Handle<SharedFunctionInfo> result;
+ if (!maybe_result.ToHandle(&result)) {
+ DCHECK(compile_state_.pending_error_handler()->has_pending_error());
+ PreparePendingException(isolate, info_.get());
+ }
-bool Compiler::Analyze(ParseInfo* parse_info) {
- DCHECK_NOT_NULL(parse_info->literal());
- RuntimeCallTimerScope runtimeTimer(parse_info->runtime_call_stats(),
- RuntimeCallCounterId::kCompileAnalyse,
- RuntimeCallStats::kThreadSpecific);
- if (!Rewriter::Rewrite(parse_info)) return false;
- if (!DeclarationScope::Analyze(parse_info)) return false;
- return true;
-}
+ outer_function_sfi_ = isolate->TransferHandle(maybe_result);
+ script_ = isolate->TransferHandle(script);
-bool Compiler::ParseAndAnalyze(ParseInfo* parse_info,
- Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate) {
- if (!parsing::ParseAny(parse_info, shared_info, isolate)) {
- return false;
- }
- return Compiler::Analyze(parse_info);
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
+ "V8.FinalizeCodeBackground.Finish");
+ isolate->FinishOffThread();
+
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
+ "V8.FinalizeCodeBackground.ReleaseParser");
+ DCHECK_EQ(language_mode_, info_->language_mode());
+ off_thread_scope.reset();
+ parser_.reset();
+ info_.reset();
+ outer_function_job_.reset();
+ inner_function_jobs_.clear();
}
+// ----------------------------------------------------------------------------
+// Implementation of Compiler
+
// static
bool Compiler::CollectSourcePositions(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info) {
@@ -1385,10 +1444,14 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
HistogramTimerScope timer(isolate->counters()->collect_source_positions());
// Set up parse info.
- ParseInfo parse_info(isolate, *shared_info);
- parse_info.set_lazy_compile();
- parse_info.set_collect_source_positions();
- if (FLAG_allow_natives_syntax) parse_info.set_allow_natives_syntax();
+ UnoptimizedCompileFlags flags =
+ UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
+ flags.set_is_lazy_compile(true);
+ flags.set_collect_source_positions(true);
+ flags.set_allow_natives_syntax(FLAG_allow_natives_syntax);
+
+ UnoptimizedCompileState compile_state(isolate);
+ ParseInfo parse_info(isolate, flags, &compile_state);
// Parse and update ParseInfo with the results. Don't update parsing
// statistics since we've already parsed the code before.
@@ -1396,9 +1459,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
parsing::ReportErrorsAndStatisticsMode::kNo)) {
// Parsing failed probably as a result of stack exhaustion.
bytecode->SetSourcePositionsFailedToCollect();
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
+ return FailAndClearPendingException(isolate);
}
// Character stream shouldn't be used again.
@@ -1409,14 +1470,6 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
// wasting time fully parsing them when they won't ever be used.
std::unique_ptr<UnoptimizedCompilationJob> job;
{
- if (!Compiler::Analyze(&parse_info)) {
- // Recompiling failed probably as a result of stack exhaustion.
- bytecode->SetSourcePositionsFailedToCollect();
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
- }
-
job = interpreter::Interpreter::NewSourcePositionCollectionJob(
&parse_info, parse_info.literal(), bytecode, isolate->allocator());
@@ -1424,13 +1477,11 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) {
// Recompiling failed probably as a result of stack exhaustion.
bytecode->SetSourcePositionsFailedToCollect();
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
+ return FailAndClearPendingException(isolate);
}
}
- DCHECK(job->compilation_info()->collect_source_positions());
+ DCHECK(job->compilation_info()->flags().collect_source_positions());
// If debugging, make sure that instrumented bytecode has the source position
// table set on it as well.
@@ -1467,17 +1518,21 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
+ Handle<Script> script(Script::cast(shared_info->script()), isolate);
+
// Set up parse info.
- ParseInfo parse_info(isolate, *shared_info);
- parse_info.set_lazy_compile();
+ UnoptimizedCompileFlags flags =
+ UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
+ flags.set_is_lazy_compile(true);
+
+ UnoptimizedCompileState compile_state(isolate);
+ ParseInfo parse_info(isolate, flags, &compile_state);
// Check if the compiler dispatcher has shared_info enqueued for compile.
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (dispatcher->IsEnqueued(shared_info)) {
if (!dispatcher->FinishNow(shared_info)) {
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, flag);
+ return FailWithPendingException(isolate, script, &parse_info, flag);
}
*is_compiled_scope = shared_info->is_compiled_scope();
DCHECK(is_compiled_scope->is_compiled());
@@ -1494,55 +1549,24 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
// Parse and update ParseInfo with the results.
if (!parsing::ParseAny(&parse_info, shared_info, isolate)) {
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, flag);
+ return FailWithPendingException(isolate, script, &parse_info, flag);
}
// Generate the unoptimized bytecode or asm-js data.
- UnoptimizedCompilationJobList inner_function_jobs;
- std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
- 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);
- }
-
- // Internalize ast values onto the heap.
- parse_info.ast_value_factory()->Internalize(isolate);
+ FinalizeUnoptimizedCompilationDataList
+ finalize_unoptimized_compilation_data_list;
- // Finalize compilation of the unoptimized bytecode or asm-js data.
- if (!FinalizeUnoptimizedCode(&parse_info, isolate, shared_info,
- outer_function_job.get(),
- &inner_function_jobs)) {
- return FailWithPendingException(
- isolate, handle(Script::cast(shared_info->script()), isolate),
- &parse_info, flag);
+ if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
+ isolate, shared_info, script, &parse_info, isolate->allocator(),
+ is_compiled_scope, &finalize_unoptimized_compilation_data_list)) {
+ return FailWithPendingException(isolate, script, &parse_info, flag);
}
+ FinalizeUnoptimizedCompilation(isolate, script, flags, &compile_state,
+ finalize_unoptimized_compilation_data_list);
+
DCHECK(!isolate->has_pending_exception());
- *is_compiled_scope = shared_info->is_compiled_scope();
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;
}
@@ -1601,13 +1625,15 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
bool Compiler::FinalizeBackgroundCompileTask(
BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ClearExceptionFlag flag) {
+ DCHECK(!task->finalize_on_background_thread());
+
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.FinalizeBackgroundCompileTask");
RuntimeCallTimerScope runtimeTimer(
isolate, RuntimeCallCounterId::kCompileFinalizeBackgroundCompileTask);
HandleScope scope(isolate);
ParseInfo* parse_info = task->info();
- DCHECK(!parse_info->is_toplevel());
+ DCHECK(!parse_info->flags().is_toplevel());
DCHECK(!shared_info->is_compiled());
Handle<Script> script(Script::cast(shared_info->script()), isolate);
@@ -1623,12 +1649,16 @@ bool Compiler::FinalizeBackgroundCompileTask(
// Parsing has succeeded - finalize compilation.
parse_info->ast_value_factory()->Internalize(isolate);
- if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
- task->outer_function_job(),
- task->inner_function_jobs())) {
+ if (!FinalizeAllUnoptimizedCompilationJobs(
+ parse_info, isolate, shared_info, task->outer_function_job(),
+ task->inner_function_jobs(),
+ task->finalize_unoptimized_compilation_data())) {
// Finalization failed - throw an exception.
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(shared_info->is_compiled());
@@ -1717,22 +1747,23 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
is_compiled_scope = shared_info->is_compiled_scope();
allow_eval_cache = true;
} else {
- ParseInfo parse_info(isolate);
- parse_info.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
- true, language_mode, REPLMode::kNo);
+ UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
+ isolate, true, language_mode, REPLMode::kNo);
+ flags.set_is_eval(true);
+ flags.set_parse_restriction(restriction);
- parse_info.set_eval();
- parse_info.set_parse_restriction(restriction);
+ UnoptimizedCompileState compile_state(isolate);
+ ParseInfo parse_info(isolate, flags, &compile_state);
parse_info.set_parameters_end_pos(parameters_end_pos);
- DCHECK(!parse_info.is_module());
+ DCHECK(!parse_info.flags().is_module());
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
if (!context->IsNativeContext()) {
maybe_outer_scope_info = handle(context->scope_info(), isolate);
}
-
- script = parse_info.CreateScript(
- isolate, source, OriginOptionsForEval(outer_info->script()));
+ script =
+ parse_info.CreateScript(isolate, source, kNullMaybeHandle,
+ OriginOptionsForEval(outer_info->script()));
script->set_eval_from_shared(*outer_info);
if (eval_position == kNoSourcePosition) {
// If the position is missing, attempt to get the code offset by
@@ -1817,7 +1848,6 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate, Handle<Context> context,
// (via v8::Isolate::SetModifyCodeGenerationFromStringsCallback)
bool ModifyCodeGenerationFromStrings(Isolate* isolate, Handle<Context> context,
Handle<i::Object>* source) {
- DCHECK(context->allow_code_gen_from_strings().IsFalse(isolate));
DCHECK(isolate->modify_code_gen_callback());
DCHECK(source);
@@ -1858,10 +1888,8 @@ std::pair<MaybeHandle<String>, bool> Compiler::ValidateDynamicCompilationSource(
// allow_code_gen_from_strings can be many things, so we'll always check
// against the 'false' literal, so that e.g. undefined and 'true' are treated
// the same.
- if (!context->allow_code_gen_from_strings().IsFalse(isolate)) {
- if (!original_source->IsString()) {
- return {MaybeHandle<String>(), true};
- }
+ if (!context->allow_code_gen_from_strings().IsFalse(isolate) &&
+ original_source->IsString()) {
return {Handle<String>::cast(original_source), false};
}
@@ -2138,16 +2166,22 @@ struct ScriptCompileTimerScope {
}
};
-void SetScriptFieldsFromDetails(Script script,
- Compiler::ScriptDetails script_details) {
+void SetScriptFieldsFromDetails(Isolate* isolate, Script script,
+ Compiler::ScriptDetails script_details,
+ DisallowHeapAllocation* no_gc) {
Handle<Object> script_name;
if (script_details.name_obj.ToHandle(&script_name)) {
script.set_name(*script_name);
script.set_line_offset(script_details.line_offset);
script.set_column_offset(script_details.column_offset);
}
+ // The API can provide a source map URL, but a source map URL could also have
+ // been inferred by the parser from a magic comment. The latter takes
+ // preference over the former, so we don't want to override the source mapping
+ // URL if it already exists.
Handle<Object> source_map_url;
- if (script_details.source_map_url.ToHandle(&source_map_url)) {
+ if (script_details.source_map_url.ToHandle(&source_map_url) &&
+ script.source_mapping_url(isolate).IsUndefined(isolate)) {
script.set_source_mapping_url(*source_map_url);
}
Handle<FixedArray> host_defined_options;
@@ -2156,31 +2190,139 @@ void SetScriptFieldsFromDetails(Script script,
}
}
-Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
- Handle<String> source,
- Compiler::ScriptDetails script_details,
- ScriptOriginOptions origin_options,
- NativesFlag natives) {
+Handle<Script> NewScript(
+ Isolate* isolate, ParseInfo* parse_info, Handle<String> source,
+ Compiler::ScriptDetails script_details, ScriptOriginOptions origin_options,
+ NativesFlag natives,
+ MaybeHandle<FixedArray> maybe_wrapped_arguments = kNullMaybeHandle) {
// Create a script object describing the script to be compiled.
- Handle<Script> script =
- parse_info->CreateScript(isolate, source, origin_options, natives);
- SetScriptFieldsFromDetails(*script, script_details);
+ Handle<Script> script = parse_info->CreateScript(
+ isolate, source, maybe_wrapped_arguments, origin_options, natives);
+ DisallowHeapAllocation no_gc;
+ SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
LOG(isolate, ScriptDetails(*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(*script, script_details);
- LOG(isolate, ScriptDetails(*script));
+MaybeHandle<SharedFunctionInfo> CompileScriptOnMainThread(
+ const UnoptimizedCompileFlags flags, Handle<String> source,
+ const Compiler::ScriptDetails& script_details,
+ ScriptOriginOptions origin_options, NativesFlag natives,
+ v8::Extension* extension, Isolate* isolate,
+ IsCompiledScope* is_compiled_scope) {
+ UnoptimizedCompileState compile_state(isolate);
+ ParseInfo parse_info(isolate, flags, &compile_state);
+ parse_info.set_extension(extension);
+
+ Handle<Script> script = NewScript(isolate, &parse_info, source,
+ script_details, origin_options, natives);
+ DCHECK_IMPLIES(parse_info.flags().collect_type_profile(),
+ script->IsUserJavaScript());
+ DCHECK_EQ(parse_info.flags().is_repl_mode(), script->is_repl_mode());
+
+ return CompileToplevel(&parse_info, script, isolate, is_compiled_scope);
+}
+
+class StressBackgroundCompileThread : public base::Thread {
+ public:
+ StressBackgroundCompileThread(Isolate* isolate, Handle<String> source)
+ : base::Thread(
+ base::Thread::Options("StressBackgroundCompileThread", 2 * i::MB)),
+ source_(source),
+ streamed_source_(std::make_unique<SourceStream>(source, isolate),
+ v8::ScriptCompiler::StreamedSource::UTF8) {
+ data()->task = std::make_unique<i::BackgroundCompileTask>(data(), isolate);
+ }
+
+ void Run() override { data()->task->Run(); }
+
+ ScriptStreamingData* data() { return streamed_source_.impl(); }
+
+ private:
+ // Dummy external source stream which returns the whole source in one go.
+ // TODO(leszeks): Also test chunking the data.
+ class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
+ public:
+ SourceStream(Handle<String> source, Isolate* isolate) : done_(false) {
+ source_buffer_ = source->ToCString(ALLOW_NULLS, FAST_STRING_TRAVERSAL,
+ &source_length_);
+ }
+
+ size_t GetMoreData(const uint8_t** src) override {
+ if (done_) {
+ return 0;
+ }
+ *src = reinterpret_cast<uint8_t*>(source_buffer_.release());
+ done_ = true;
+
+ return source_length_;
+ }
+
+ private:
+ int source_length_;
+ std::unique_ptr<char[]> source_buffer_;
+ bool done_;
+ };
+
+ Handle<String> source_;
+ v8::ScriptCompiler::StreamedSource streamed_source_;
+};
+
+bool CanBackgroundCompile(const Compiler::ScriptDetails& script_details,
+ ScriptOriginOptions origin_options,
+ v8::Extension* extension,
+ ScriptCompiler::CompileOptions compile_options,
+ NativesFlag natives) {
+ // TODO(leszeks): Remove the module check once background compilation of
+ // modules is supported.
+ return !origin_options.IsModule() && !extension &&
+ script_details.repl_mode == REPLMode::kNo &&
+ compile_options == ScriptCompiler::kNoCompileOptions &&
+ natives == NOT_NATIVES_CODE;
+}
+
+MaybeHandle<SharedFunctionInfo> CompileScriptOnBothBackgroundAndMainThread(
+ Handle<String> source, const Compiler::ScriptDetails& script_details,
+ ScriptOriginOptions origin_options, Isolate* isolate,
+ IsCompiledScope* is_compiled_scope) {
+ // Start a background thread compiling the script.
+ StressBackgroundCompileThread background_compile_thread(isolate, source);
+
+ UnoptimizedCompileFlags flags_copy =
+ background_compile_thread.data()->task->flags();
+
+ CHECK(background_compile_thread.Start());
+ MaybeHandle<SharedFunctionInfo> main_thread_maybe_result;
+ // In parallel, compile on the main thread to flush out any data races.
+ {
+ IsCompiledScope inner_is_compiled_scope;
+ // The background thread should also create any relevant exceptions, so we
+ // can ignore the main-thread created ones.
+ // TODO(leszeks): Maybe verify that any thrown (or unthrown) exceptions are
+ // equivalent.
+ TryCatch ignore_try_catch(reinterpret_cast<v8::Isolate*>(isolate));
+ flags_copy.set_script_id(Script::kTemporaryScriptId);
+ main_thread_maybe_result = CompileScriptOnMainThread(
+ flags_copy, source, script_details, origin_options, NOT_NATIVES_CODE,
+ nullptr, isolate, &inner_is_compiled_scope);
+ }
+ // Join with background thread and finalize compilation.
+ background_compile_thread.Join();
+ MaybeHandle<SharedFunctionInfo> maybe_result =
+ Compiler::GetSharedFunctionInfoForStreamedScript(
+ isolate, source, script_details, origin_options,
+ background_compile_thread.data());
+
+ // Either both compiles should succeed, or both should fail.
+ // TODO(leszeks): Compare the contents of the results of the two compiles.
+ CHECK_EQ(maybe_result.is_null(), main_thread_maybe_result.is_null());
+
+ Handle<SharedFunctionInfo> result;
+ if (maybe_result.ToHandle(&result)) {
+ *is_compiled_scope = result->is_compiled_scope();
+ }
+
+ return maybe_result;
}
} // namespace
@@ -2254,25 +2396,28 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
if (maybe_result.is_null()) {
// No cache entry found compile the script.
- ParseInfo parse_info(isolate);
-
- parse_info.SetFlagsForToplevelCompile(
- isolate->is_collecting_type_profile(), natives == NOT_NATIVES_CODE,
- language_mode, script_details.repl_mode);
+ if (FLAG_stress_background_compile &&
+ CanBackgroundCompile(script_details, origin_options, extension,
+ compile_options, natives)) {
+ // If the --stress-background-compile flag is set, do the actual
+ // compilation on a background thread, and wait for its result.
+ maybe_result = CompileScriptOnBothBackgroundAndMainThread(
+ source, script_details, origin_options, isolate, &is_compiled_scope);
+ } else {
+ UnoptimizedCompileFlags flags =
+ UnoptimizedCompileFlags::ForToplevelCompile(
+ isolate, natives == NOT_NATIVES_CODE, language_mode,
+ script_details.repl_mode);
- parse_info.set_module(origin_options.IsModule());
- parse_info.set_extension(extension);
- parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
+ flags.set_is_eager(compile_options == ScriptCompiler::kEagerCompile);
+ flags.set_is_module(origin_options.IsModule());
- Handle<Script> script = NewScript(isolate, &parse_info, source,
- script_details, origin_options, natives);
- DCHECK_IMPLIES(parse_info.collect_type_profile(),
- script->IsUserJavaScript());
- DCHECK_EQ(parse_info.is_repl_mode(), script->is_repl_mode());
+ maybe_result = CompileScriptOnMainThread(
+ flags, source, script_details, origin_options, natives, extension,
+ isolate, &is_compiled_scope);
+ }
- // Compile the function and add it to the isolate cache.
- maybe_result =
- CompileToplevel(&parse_info, script, isolate, &is_compiled_scope);
+ // Add the result to the isolate cache.
Handle<SharedFunctionInfo> result;
if (extension == nullptr && maybe_result.ToHandle(&result)) {
DCHECK(is_compiled_scope.is_compiled());
@@ -2331,18 +2476,18 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
Handle<Script> script;
IsCompiledScope is_compiled_scope;
if (!maybe_result.ToHandle(&wrapped)) {
- ParseInfo parse_info(isolate);
- parse_info.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
- true, language_mode,
- script_details.repl_mode);
-
- parse_info.set_eval(); // Use an eval scope as declaration scope.
- parse_info.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
+ UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
+ isolate, true, language_mode, script_details.repl_mode);
+ flags.set_is_eval(true); // Use an eval scope as declaration scope.
+ flags.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
// TODO(delphick): Remove this and instead make the wrapped and wrapper
// functions fully non-lazy instead thus preventing source positions from
// being omitted.
- parse_info.set_collect_source_positions(true);
- // parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
+ flags.set_collect_source_positions(true);
+ // flags.set_eager(compile_options == ScriptCompiler::kEagerCompile);
+
+ UnoptimizedCompileState compile_state(isolate);
+ ParseInfo parse_info(isolate, flags, &compile_state);
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
if (!context->IsNativeContext()) {
@@ -2350,8 +2495,7 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
}
script = NewScript(isolate, &parse_info, source, script_details,
- origin_options, NOT_NATIVES_CODE);
- script->set_wrapped_arguments(*arguments);
+ origin_options, NOT_NATIVES_CODE, arguments);
Handle<SharedFunctionInfo> top_level;
maybe_result = CompileToplevel(&parse_info, script, maybe_outer_scope_info,
@@ -2383,6 +2527,9 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, ScriptOriginOptions origin_options,
ScriptStreamingData* streaming_data) {
+ DCHECK(!origin_options.IsModule());
+ DCHECK(!origin_options.IsWasm());
+
ScriptCompileTimerScope compile_timer(
isolate, ScriptCompiler::kNoCacheBecauseStreamingSource);
PostponeInterruptsScope postpone(isolate);
@@ -2410,73 +2557,71 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
}
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()) {
RuntimeCallTimerScope runtimeTimerScope(
isolate, RuntimeCallCounterId::kCompilePublishBackgroundFinalization);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.OffThreadFinalization.Publish");
- Handle<SharedFunctionInfo> sfi(task->outer_function_sfi(), isolate);
- Handle<Script> script(Script::cast(sfi->script()), isolate);
- task->off_thread_isolate()->factory()->Publish(isolate);
-
- FixUpOffThreadAllocatedScript(isolate, script, source, script_details,
- origin_options, NOT_NATIVES_CODE);
-
- // 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));
- }
- });
- }
+ task->off_thread_isolate()->Publish(isolate);
- maybe_result = sfi;
+ maybe_result = task->outer_function_sfi();
+ script = task->script();
+ script->set_source(*source);
+ script->set_origin_options(origin_options);
} else {
ParseInfo* parse_info = task->info();
- DCHECK(parse_info->is_toplevel());
+ DCHECK(parse_info->flags().is_toplevel());
+
+ script = parse_info->CreateScript(isolate, source, kNullMaybeHandle,
+ origin_options);
- // No cache entry found, finalize compilation of the script and add it to
- // the isolate cache.
- Handle<Script> script =
- NewScript(isolate, parse_info, source, script_details, origin_options,
- NOT_NATIVES_CODE);
task->parser()->UpdateStatistics(isolate, script);
task->parser()->HandleSourceURLComments(isolate, script);
- if (parse_info->literal() == nullptr || !task->outer_function_job()) {
- // Parsing has failed - report error messages.
- FailWithPendingException(isolate, script, parse_info,
- Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
- } else {
- // Parsing has succeeded - finalize compilation.
- maybe_result = FinalizeTopLevel(parse_info, script, isolate,
- task->outer_function_job(),
- task->inner_function_jobs());
- if (maybe_result.is_null()) {
- // Finalization failed - throw an exception.
- FailWithPendingException(
- isolate, script, parse_info,
- Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
+ if (parse_info->literal() != nullptr && task->outer_function_job()) {
+ // Off-thread parse & compile has succeeded - finalize compilation.
+ parse_info->ast_value_factory()->Internalize(isolate);
+
+ 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()) {
+ // Compilation failed - prepare to throw an exception after script
+ // fields have been set.
+ PreparePendingException(isolate, parse_info);
+ }
+ }
+
+ // 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));
}
- // Add compiled code to the isolate cache.
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"),
"V8.StreamingFinalization.AddToCache");
compilation_cache->PutScript(source, isolate->native_context(),
@@ -2497,7 +2642,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
MaybeHandle<SharedFunctionInfo> maybe_existing;
// 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.
Handle<SharedFunctionInfo> existing;