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 {
UnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() {
// 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);
Utf16CharacterStream* stream = parse_info()->character_stream();
......
......@@ -27,6 +27,7 @@
#include "src/ast/ast-value-factory.h"
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/execution/off-thread-isolate.h"
#include "src/heap/factory-inl.h"
......
......@@ -31,6 +31,7 @@
#include <forward_list>
#include "src/base/hashmap.h"
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/heap/factory.h"
#include "src/numbers/conversions.h"
......
......@@ -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"
......@@ -180,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();
......@@ -198,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
......@@ -384,13 +390,12 @@ 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);
return;
}
void InstallInterpreterTrampolineCopy(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info) {
DCHECK(FLAG_interpreted_frames_native_stack);
DCHECK(shared_info->function_data().IsBytecodeArray());
Handle<BytecodeArray> bytecode_array(shared_info->GetBytecodeArray(),
isolate);
Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
isolate->factory()->interpreter_entry_trampoline_for_profiling()));
......@@ -420,9 +425,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());
......@@ -441,56 +460,45 @@ 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,
InstallCoverageInfo(isolate, shared_info,
compilation_info->coverage_info());
}
}
void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
void LogUnoptimizedCompilation(Isolate* isolate,
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);
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>
......@@ -525,63 +533,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();
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(
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->push_back(
FinalizeUnoptimizedCompilationData{
compilation_info->literal()->function_literal_id(),
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) {
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));
......@@ -594,21 +571,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));
......@@ -617,34 +608,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 =
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);
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());
......@@ -654,57 +625,42 @@ MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(literal, script, isolate);
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 ||
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));
......@@ -715,8 +671,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;
}
......@@ -730,8 +688,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;
}
......@@ -739,7 +698,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;
......@@ -991,43 +950,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) {
bool FailAndClearPendingException(Isolate* isolate) {
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;
}
bool FailWithPendingException(OffThreadIsolate* isolate, Handle<Script> script,
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);
template <typename LocalIsolate>
bool PreparePendingException(LocalIsolate* isolate, ParseInfo* parse_info) {
if (parse_info->pending_error_handler()->has_pending_error()) {
parse_info->pending_error_handler()->PrepareErrorsOffThread(
isolate, script, parse_info->ast_value_factory());
parse_info->pending_error_handler()->PrepareErrors(
isolate, parse_info->ast_value_factory());
}
return false;
}
bool FailWithPendingExceptionAfterOffThreadFinalization(
bool FailWithPreparedPendingException(
Isolate* isolate, Handle<Script> script,
PendingCompilationErrorHandler* pending_error_handler) {
const PendingCompilationErrorHandler* pending_error_handler) {
if (!isolate->has_pending_exception()) {
if (pending_error_handler->has_pending_error()) {
pending_error_handler->ReportErrorsAfterOffThreadFinalization(isolate,
script);
pending_error_handler->ReportErrors(isolate, script);
} else {
isolate->StackOverflow();
}
......@@ -1035,17 +977,73 @@ bool FailWithPendingExceptionAfterOffThreadFinalization(
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,
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);
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);
......@@ -1054,34 +1052,22 @@ void FinalizeScriptCompilation(
}
}
}
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)) {
return MaybeHandle<SharedFunctionInfo>();
}
return shared_info;
return isolate->factory()->NewSharedFunctionInfoForLiteral(
parse_info->literal(), script, true);
}
MaybeHandle<SharedFunctionInfo> CompileToplevel(
......@@ -1114,17 +1100,29 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("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->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;
}
......@@ -1143,8 +1141,18 @@ std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread(
: 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;
}
......@@ -1171,8 +1179,7 @@ BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
worker_thread_runtime_call_stats_(
isolate->counters()->worker_thread_runtime_call_stats()),
timer_(isolate->counters()->compile_script_on_background()),
language_mode_(info_->language_mode()),
collected_source_positions_(false) {
language_mode_(info_->language_mode()) {
VMState<PARSER> state(isolate);
// Prepare the data for the internalization phase and compilation phase, which
......@@ -1211,7 +1218,6 @@ BackgroundCompileTask::BackgroundCompileTask(
worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
timer_(timer),
language_mode_(info_->language_mode()),
collected_source_positions_(false),
finalize_on_background_thread_(false) {
DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition);
DCHECK_NULL(outer_parse_info->extension());
......@@ -1317,7 +1323,6 @@ void BackgroundCompileTask::Run() {
}
// Save the language mode and record whether we collected source positions.
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,
// asm.js), so release the off-thread isolate and fall back to main-thread
......@@ -1325,7 +1330,7 @@ void BackgroundCompileTask::Run() {
// 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_ &&
finalize_on_background_thread_ && outer_function_job_ &&
CanOffThreadFinalizeAllJobs(outer_function_job(), *inner_function_jobs());
if (!finalize_on_background_thread_) {
......@@ -1348,18 +1353,23 @@ void BackgroundCompileTask::Run() {
OffThreadHandleScope handle_scope(isolate);
// 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(
isolate, isolate->factory()->empty_string(), kNullMaybeHandle,
ScriptOriginOptions(), NOT_NATIVES_CODE);
// 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());
MaybeHandle<SharedFunctionInfo> maybe_result;
if (info_->literal() != nullptr) {
maybe_result =
FinalizeTopLevel(info_.get(), script, isolate,
outer_function_job_.get(), &inner_function_jobs_);
info_->ast_value_factory()->Internalize(isolate);
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 {
......@@ -1369,8 +1379,7 @@ void BackgroundCompileTask::Run() {
Handle<SharedFunctionInfo> result;
if (!maybe_result.ToHandle(&result)) {
DCHECK(compile_state_.pending_error_handler()->has_pending_error());
FailWithPendingException(isolate, script, info_.get(),
Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
PreparePendingException(isolate, info_.get());
}
outer_function_sfi_ = isolate->TransferHandle(maybe_result);
......@@ -1447,9 +1456,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.
......@@ -1467,9 +1474,7 @@ 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);
}
}
......@@ -1510,6 +1515,8 @@ 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.
UnoptimizedCompileFlags flags =
UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
......@@ -1522,9 +1529,7 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
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());
......@@ -1541,52 +1546,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);
}
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;
}
......@@ -1645,6 +1622,8 @@ 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(
......@@ -1667,12 +1646,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());
......@@ -2221,20 +2204,6 @@ Handle<Script> NewScript(
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(
const UnoptimizedCompileFlags flags, Handle<String> source,
const Compiler::ScriptDetails& script_details,
......@@ -2558,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);
......@@ -2585,6 +2557,10 @@ 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);
......@@ -2594,76 +2570,58 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
task->off_thread_isolate()->Publish(isolate);
maybe_result = task->outer_function_sfi();
Handle<Script> script = task->script();
FixUpOffThreadAllocatedScript(isolate, script, source, script_details,
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());
}
script = task->script();
script->set_source(*source);
script->set_origin_options(origin_options);
} else {
ParseInfo* parse_info = task->info();
DCHECK(parse_info->flags().is_toplevel());
// 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);
script = parse_info->CreateScript(isolate, source, kNullMaybeHandle,
origin_options);
task->parser()->UpdateStatistics(isolate, script);
task->parser()->HandleSourceURLComments(isolate, script);
if (parse_info->literal() != nullptr && task->outer_function_job()) {
// Off-thread parse & compile has succeeded - finalize compilation.
maybe_result = FinalizeTopLevel(parse_info, script, isolate,
task->outer_function_job(),
task->inner_function_jobs());
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 - throw an exception.
FailWithPendingException(isolate, script, parse_info,
Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
} else {
FinalizeScriptCompilation(isolate, script,
parse_info->parallel_tasks());
// Compilation failed - prepare to throw an exception after script
// fields have been set.
PreparePendingException(isolate, parse_info);
}
}
// 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;
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(),
......@@ -2684,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;
......
......@@ -276,6 +276,13 @@ class UnoptimizedCompilationJob : public CompilationJob {
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_; }
protected:
......@@ -354,6 +361,15 @@ class OptimizedCompilationJob : public CompilationJob {
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 {
public:
// Creates a new task that when run will parse and compile the streamed
......@@ -386,18 +402,14 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
return &inner_function_jobs_;
}
UnoptimizedCompileFlags flags() const { return flags_; }
const UnoptimizedCompileState* compile_state() const {
return &compile_state_;
}
LanguageMode language_mode() { return language_mode_; }
bool collected_source_positions() { return collected_source_positions_; }
bool finalize_on_background_thread() {
return finalize_on_background_thread_;
}
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() {
DCHECK_NOT_NULL(off_thread_isolate_);
return outer_function_sfi_.ToHandle();
......@@ -406,6 +418,10 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
DCHECK_NOT_NULL(off_thread_isolate_);
return script_.ToHandle();
}
FinalizeUnoptimizedCompilationDataList*
finalize_unoptimized_compilation_data() {
return &finalize_unoptimized_compilation_data_;
}
private:
// Data needed for parsing, and data needed to to be passed between thread
......@@ -427,6 +443,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
std::unique_ptr<OffThreadIsolate> off_thread_isolate_;
OffThreadTransferMaybeHandle<SharedFunctionInfo> outer_function_sfi_;
OffThreadTransferHandle<Script> script_;
FinalizeUnoptimizedCompilationDataList finalize_unoptimized_compilation_data_;
// Single function data for top-level function compilation.
int start_position_;
......@@ -437,7 +454,6 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
TimedHistogram* timer_;
LanguageMode language_mode_;
bool collected_source_positions_;
// True if the background compilation should be finalized on the background
// thread. When this is true, the ParseInfo, Parser and compilation jobs are
......
......@@ -18,7 +18,7 @@ namespace internal {
UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone,
ParseInfo* parse_info,
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
// during parsing, but does not represent specific details of the actual
// function literal being compiled for this OptimizedCompilationInfo. As such,
......
......@@ -34,8 +34,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
UnoptimizedCompilationInfo(Zone* zone, ParseInfo* parse_info,
FunctionLiteral* literal);
Zone* zone() { return zone_; }
const UnoptimizedCompileFlags& flags() const { return flags_; }
// Accessors for the input data of the function being compiled.
......@@ -87,10 +85,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
// Compilation 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.
FunctionLiteral* literal_;
......
......@@ -504,10 +504,14 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
i_isolate, true, i::construct_language_mode(i::FLAG_use_strict),
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::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)) {
fprintf(stderr, "Failed parsing\n");
return false;
......
......@@ -105,6 +105,8 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final
// on the main thread.
void Publish(Isolate* isolate);
bool has_pending_exception() const { return false; }
template <typename T>
Handle<T> Throw(Handle<Object> exception) {
UNREACHABLE();
......
......@@ -1040,10 +1040,10 @@ static bool IsInEagerLiterals(
#endif // DEBUG
BytecodeGenerator::BytecodeGenerator(
UnoptimizedCompilationInfo* info,
Zone* compile_zone, UnoptimizedCompilationInfo* info,
const AstStringConstants* ast_string_constants,
std::vector<FunctionLiteral*>* eager_inner_literals)
: zone_(info->zone()),
: zone_(compile_zone),
builder_(zone(), info->num_parameters_including_this(),
info->scope()->num_stack_slots(), info->feedback_vector_spec(),
info->SourcePositionRecordingMode()),
......
......@@ -32,7 +32,7 @@ class BytecodeJumpTable;
class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
public:
explicit BytecodeGenerator(
UnoptimizedCompilationInfo* info,
Zone* zone, UnoptimizedCompilationInfo* info,
const AstStringConstants* ast_string_constants,
std::vector<FunctionLiteral*>* eager_inner_literals);
......
......@@ -152,7 +152,7 @@ InterpreterCompilationJob::InterpreterCompilationJob(
&compilation_info_, CanOffThreadFinalize::kYes),
zone_(allocator, ZONE_NAME),
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) {}
InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
......
......@@ -4907,14 +4907,14 @@ Object Script::GetNameOrSourceURL() {
template <typename LocalIsolate>
MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
LocalIsolate* isolate, const FunctionLiteral* fun) {
CHECK_NE(fun->function_literal_id(), kFunctionLiteralIdInvalid);
LocalIsolate* isolate, int function_literal_id) {
CHECK_NE(function_literal_id, kFunctionLiteralIdInvalid);
// If this check fails, the problem is most probably the function id
// renumbering done by AstFunctionLiteralIdReindexer; in particular, that
// AstTraversalVisitor doesn't recurse properly in the construct which
// triggers the mismatch.
CHECK_LT(fun->function_literal_id(), shared_function_infos().length());
MaybeObject shared = shared_function_infos().Get(fun->function_literal_id());
CHECK_LT(function_literal_id, shared_function_infos().length());
MaybeObject shared = shared_function_infos().Get(function_literal_id);
HeapObject heap_object;
if (!shared->GetHeapObject(&heap_object) ||
heap_object.IsUndefined(isolate)) {
......@@ -4923,9 +4923,9 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
return handle(SharedFunctionInfo::cast(heap_object), isolate);
}
template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
Isolate* isolate, const FunctionLiteral* fun);
Isolate* isolate, int function_literal_id);
template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
OffThreadIsolate* isolate, const FunctionLiteral* fun);
OffThreadIsolate* isolate, int function_literal_id);
Script::Iterator::Iterator(Isolate* isolate)
: iterator_(isolate->heap()->script_list()) {}
......
......@@ -201,7 +201,7 @@ class Script : public Struct {
// that matches the function literal. Return empty handle if not found.
template <typename LocalIsolate>
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(
LocalIsolate* isolate, const FunctionLiteral* fun);
LocalIsolate* isolate, int function_literal_id);
// Iterate over all script objects on the heap.
class V8_EXPORT_PRIVATE Iterator {
......
......@@ -188,6 +188,9 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileState {
PendingCompilationErrorHandler* 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(); }
private:
......
......@@ -27,8 +27,9 @@ void MaybeReportErrorsAndStatistics(ParseInfo* info, Handle<Script> script,
ReportErrorsAndStatisticsMode mode) {
if (mode == ReportErrorsAndStatisticsMode::kYes) {
if (info->literal() == nullptr) {
info->pending_error_handler()->ReportErrors(isolate, script,
info->pending_error_handler()->PrepareErrors(isolate,
info->ast_value_factory());
info->pending_error_handler()->ReportErrors(isolate, script);
}
parser->UpdateStatistics(isolate, script);
}
......
......@@ -9,35 +9,63 @@
#include "src/debug/debug.h"
#include "src/execution/isolate.h"
#include "src/execution/messages.h"
#include "src/execution/off-thread-isolate.h"
#include "src/handles/handles.h"
#include "src/heap/off-thread-factory-inl.h"
#include "src/objects/objects-inl.h"
namespace v8 {
namespace internal {
void PendingCompilationErrorHandler::MessageDetails::TransferOffThreadHandle(
OffThreadIsolate* isolate) {
void PendingCompilationErrorHandler::MessageDetails::SetString(
Handle<String> string, Isolate* isolate) {
DCHECK_NE(type_, kMainThreadHandle);
if (type_ != kAstRawString) return;
arg_transfer_handle_ = isolate->TransferHandle(arg_->string());
DCHECK_NE(type_, kOffThreadTransferHandle);
type_ = kMainThreadHandle;
arg_handle_ = string;
}
void PendingCompilationErrorHandler::MessageDetails::SetString(
Handle<String> string, OffThreadIsolate* isolate) {
DCHECK_NE(type_, kMainThreadHandle);
DCHECK_NE(type_, kOffThreadTransferHandle);
type_ = kOffThreadTransferHandle;
arg_transfer_handle_ = isolate->TransferHandle(string);
}
Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString(
Isolate* isolate) const {
template <typename LocalIsolate>
void PendingCompilationErrorHandler::MessageDetails::Prepare(
LocalIsolate* isolate) {
switch (type_) {
case kAstRawString:
return arg_->string();
return SetString(arg_->string(), isolate);
case kNone:
return isolate->factory()->undefined_string();
case kConstCharString:
return isolate->factory()
->NewStringFromUtf8(CStrVector(char_arg_))
.ToHandleChecked();
// We can delay allocation until ArgumentString(isolate).
// TODO(leszeks): We don't actually have to transfer this string, since
// it's a root.
return;
case kMainThreadHandle:
case kOffThreadTransferHandle:
UNREACHABLE();
}
}
Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString(
Isolate* isolate) const {
switch (type_) {
case kMainThreadHandle:
return arg_handle_;
case kOffThreadTransferHandle:
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,
MessageDetails(start_position, end_position, message, arg));
}
void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate,
Handle<Script> script) {
template <typename LocalIsolate>
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());
for (const MessageDetails& warning : warning_messages_) {
......@@ -89,53 +129,33 @@ void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate,
}
}
void PendingCompilationErrorHandler::ReportWarnings(OffThreadIsolate* isolate,
Handle<Script> script) {
// Change any AstRawStrings to raw object pointers before the Ast Zone dies,
// re-report later on the main thread.
DCHECK(!has_pending_error());
for (MessageDetails& warning : warning_messages_) {
warning.TransferOffThreadHandle(isolate);
}
}
template <typename LocalIsolate>
void PendingCompilationErrorHandler::PrepareErrors(
LocalIsolate* isolate, AstValueFactory* ast_value_factory) {
if (stack_overflow()) return;
void PendingCompilationErrorHandler::ReportErrors(
Isolate* isolate, Handle<Script> script,
AstValueFactory* ast_value_factory) {
if (stack_overflow()) {
isolate->StackOverflow();
} else {
DCHECK(has_pending_error());
// Internalize ast values for throwing the pending error.
ast_value_factory->Internalize(isolate);
ThrowPendingError(isolate, script);
}
error_details_.Prepare(isolate);
}
template void PendingCompilationErrorHandler::PrepareErrors(
Isolate* isolate, AstValueFactory* ast_value_factory);
template void PendingCompilationErrorHandler::PrepareErrors(
OffThreadIsolate* isolate, AstValueFactory* ast_value_factory);
void PendingCompilationErrorHandler::PrepareErrorsOffThread(
OffThreadIsolate* isolate, Handle<Script> script,
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) {
void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate,
Handle<Script> script) const {
if (stack_overflow()) {
isolate->StackOverflow();
} else {
DCHECK(has_pending_error());
// Ast values should already be internalized.
ThrowPendingError(isolate, script);
}
}
void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate,
Handle<Script> script) {
void PendingCompilationErrorHandler::ThrowPendingError(
Isolate* isolate, Handle<Script> script) const {
if (!has_pending_error_) return;
MessageLocation location = error_details_.GetLocation(script);
......@@ -149,7 +169,8 @@ void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate,
}
Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(
Isolate* isolate) const {
Isolate* isolate) {
error_details_.Prepare(isolate);
return MessageFormatter::Format(isolate, error_details_.message(),
error_details_.ArgumentString(isolate));
}
......
......@@ -48,23 +48,16 @@ class PendingCompilationErrorHandler {
bool has_pending_warnings() const { return !warning_messages_.empty(); }
// Handle errors detected during parsing.
void ReportErrors(Isolate* isolate, Handle<Script> script,
AstValueFactory* ast_value_factory);
// Prepare errors detected during off-thread parsing, to be reported later on
// 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);
template <typename LocalIsolate>
void PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
void ReportErrors(Isolate* isolate, Handle<Script> script) const;
// Handle warnings detected during compilation.
void ReportWarnings(Isolate* isolate, Handle<Script> script);
void ReportWarnings(OffThreadIsolate* isolate, Handle<Script> script);
template <typename LocalIsolate>
void PrepareWarnings(LocalIsolate* isolate);
void ReportWarnings(Isolate* isolate, Handle<Script> script) const;
V8_EXPORT_PRIVATE Handle<String> FormatErrorMessageForTest(
Isolate* isolate) const;
V8_EXPORT_PRIVATE Handle<String> FormatErrorMessageForTest(Isolate* isolate);
void set_unidentifiable_error() {
has_pending_error_ = true;
......@@ -106,32 +99,34 @@ class PendingCompilationErrorHandler {
MessageLocation GetLocation(Handle<Script> script) const;
MessageTemplate message() const { return message_; }
// After off-thread finalization, the Ast Zone will be deleted, so before
// that happens we have to transfer any string handles.
void TransferOffThreadHandle(OffThreadIsolate* isolate);
template <typename LocalIsolate>
void Prepare(LocalIsolate* isolate);
private:
enum Type {
kNone,
kAstRawString,
kConstCharString,
kOffThreadTransferHandle,
kMainThreadHandle
kMainThreadHandle,
kOffThreadTransferHandle
};
void SetString(Handle<String> string, Isolate* isolate);
void SetString(Handle<String> string, OffThreadIsolate* isolate);
int start_position_;
int end_position_;
MessageTemplate message_;
union {
const AstRawString* arg_;
const char* char_arg_;
OffThreadTransferHandle<String> arg_transfer_handle_;
Handle<String> arg_handle_;
OffThreadTransferHandle<String> arg_transfer_handle_;
};
Type type_;
};
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
void ThrowPendingError(Isolate* isolate, Handle<Script> script) const;
bool has_pending_error_;
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