[compiler] Off-thread deserialization ♥️ Isolate cache

Make off-thread deserialization play well with the Isolate compilation
cache, by moving the Finish call into GetSharedFunctionInfoForScript.

This means that

  a) The isolate cache is checked before the Finish, allowing it to be
     hit, and
  b) Results of off-thread deserializations are written into the Isolate
     cache.

Bug: chromium:1075999
Change-Id: I535935180bbe77f3e718253830e649bd62857634
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3094006
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#76341}
This commit is contained in:
Leszek Swirski 2021-08-17 10:52:17 +02:00 committed by V8 LUCI CQ
parent a69080060d
commit df2b169b3f
9 changed files with 148 additions and 60 deletions

View File

@ -2420,42 +2420,45 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
std::unique_ptr<i::AlignedCachedData> cached_data;
if (options == kConsumeCodeCache) {
if (source->consume_cache_task) {
// If there's a cache consume task, finish it
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
source->consume_cache_task->impl_->Finish(isolate, str,
source->resource_options);
i::Handle<i::SharedFunctionInfo> result;
if (maybe_function_info.ToHandle(&result)) {
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
}
// If the above failed, then we must have rejected the cache. Continue
// with normal compilation, disabling the code cache consumption.
source->cached_data->rejected = true;
options = kNoCompileOptions;
} else {
DCHECK(source->cached_data);
// AlignedCachedData takes care of pointer-aligning the data.
cached_data.reset(new i::AlignedCachedData(source->cached_data->data,
source->cached_data->length));
}
}
i::Handle<i::SharedFunctionInfo> result;
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileScript");
i::ScriptDetails script_details = GetScriptDetails(
isolate, source->resource_name, source->resource_line_offset,
source->resource_column_offset, source->source_map_url,
source->host_defined_options, source->resource_options);
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, script_details, nullptr, cached_data.get(), options,
no_cache_reason, i::NOT_NATIVES_CODE);
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info;
if (options == kConsumeCodeCache) {
source->cached_data->rejected = cached_data->rejected();
DCHECK_EQ(no_cache_reason, NoCacheReason::kNoCacheNoReason);
if (source->consume_cache_task) {
// Take ownership of the internal deserialization task and clear it off
// the consume task on the source.
DCHECK_NOT_NULL(source->consume_cache_task->impl_);
std::unique_ptr<i::BackgroundDeserializeTask> deserialize_task =
std::move(source->consume_cache_task->impl_);
maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScriptWithDeserializeTask(
isolate, str, script_details, deserialize_task.get(), options,
no_cache_reason, i::NOT_NATIVES_CODE);
source->cached_data->rejected = deserialize_task->rejected();
} else {
DCHECK(source->cached_data);
// AlignedCachedData takes care of pointer-aligning the data.
auto cached_data = std::make_unique<i::AlignedCachedData>(
source->cached_data->data, source->cached_data->length);
maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScriptWithCachedData(
isolate, str, script_details, cached_data.get(), options,
no_cache_reason, i::NOT_NATIVES_CODE);
source->cached_data->rejected = cached_data->rejected();
}
} else {
// Compile without any cache.
maybe_function_info = i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, script_details, options, no_cache_reason,
i::NOT_NATIVES_CODE);
}
has_pending_exception = !maybe_function_info.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(UnboundScript);
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));

View File

@ -2830,13 +2830,10 @@ MaybeHandle<SharedFunctionInfo> CompileScriptOnBothBackgroundAndMainThread(
return maybe_result;
}
} // namespace
// static
MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, v8::Extension* extension,
AlignedCachedData* cached_data,
AlignedCachedData* cached_data, BackgroundDeserializeTask* deserialize_task,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
@ -2844,9 +2841,12 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
if (compile_options == ScriptCompiler::kNoCompileOptions ||
compile_options == ScriptCompiler::kEagerCompile) {
DCHECK_NULL(cached_data);
DCHECK_NULL(deserialize_task);
} else {
DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
DCHECK(cached_data);
DCHECK_EQ(compile_options, ScriptCompiler::kConsumeCodeCache);
// Have to have exactly one of cached_data or deserialize_task.
DCHECK(cached_data || deserialize_task);
DCHECK(!(cached_data && deserialize_task));
DCHECK_NULL(extension);
}
int source_length = source->length();
@ -2882,17 +2882,26 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileDeserialize);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileDeserialize");
Handle<SharedFunctionInfo> inner_result;
if (CodeSerializer::Deserialize(isolate, cached_data, source,
script_details.origin_options)
.ToHandle(&inner_result) &&
inner_result->is_compiled()) {
// Promote to per-isolate compilation cache.
is_compiled_scope = inner_result->is_compiled_scope(isolate);
DCHECK(is_compiled_scope.is_compiled());
compilation_cache->PutScript(source, language_mode, inner_result);
maybe_result = inner_result;
if (deserialize_task) {
// If there's a cache consume task, finish it.
maybe_result = deserialize_task->Finish(isolate, source,
script_details.origin_options);
} else {
maybe_result = CodeSerializer::Deserialize(
isolate, cached_data, source, script_details.origin_options);
}
bool consuming_code_cache_succeeded = false;
Handle<SharedFunctionInfo> result;
if (maybe_result.ToHandle(&result)) {
is_compiled_scope = result->is_compiled_scope(isolate);
if (is_compiled_scope.is_compiled()) {
consuming_code_cache_succeeded = true;
// Promote to per-isolate compilation cache.
compilation_cache->PutScript(source, language_mode, result);
}
}
if (!consuming_code_cache_succeeded) {
// Deserializer failed. Fall through to compile.
compile_timer.set_consuming_code_cache_failed();
}
@ -2937,6 +2946,51 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
return maybe_result;
}
} // namespace
MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
return GetSharedFunctionInfoForScriptImpl(
isolate, source, script_details, nullptr, nullptr, nullptr,
compile_options, no_cache_reason, natives);
}
MaybeHandle<SharedFunctionInfo>
Compiler::GetSharedFunctionInfoForScriptWithExtension(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, v8::Extension* extension,
ScriptCompiler::CompileOptions compile_options, NativesFlag natives) {
return GetSharedFunctionInfoForScriptImpl(
isolate, source, script_details, extension, nullptr, nullptr,
compile_options, ScriptCompiler::kNoCacheBecauseV8Extension, natives);
}
MaybeHandle<SharedFunctionInfo>
Compiler::GetSharedFunctionInfoForScriptWithCachedData(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, AlignedCachedData* cached_data,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
return GetSharedFunctionInfoForScriptImpl(
isolate, source, script_details, nullptr, cached_data, nullptr,
compile_options, no_cache_reason, natives);
}
MaybeHandle<SharedFunctionInfo>
Compiler::GetSharedFunctionInfoForScriptWithDeserializeTask(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details,
BackgroundDeserializeTask* deserialize_task,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
return GetSharedFunctionInfoForScriptImpl(
isolate, source, script_details, nullptr, nullptr, deserialize_task,
compile_options, no_cache_reason, natives);
}
// static
MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
Handle<String> source, Handle<FixedArray> arguments,

View File

@ -160,9 +160,40 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
// Create a shared function info object for a String source.
static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason,
NativesFlag is_natives_code);
// Create a shared function info object for a String source.
static MaybeHandle<SharedFunctionInfo>
GetSharedFunctionInfoForScriptWithExtension(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, v8::Extension* extension,
AlignedCachedData* cached_data,
ScriptCompiler::CompileOptions compile_options,
NativesFlag is_natives_code);
// Create a shared function info object for a String source and serialized
// cached data. The cached data may be rejected, in which case this function
// will set cached_data->rejected() to true.
static MaybeHandle<SharedFunctionInfo>
GetSharedFunctionInfoForScriptWithCachedData(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, AlignedCachedData* cached_data,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason,
NativesFlag is_natives_code);
// Create a shared function info object for a String source and a task that
// has deserialized cached data on a background thread. The cached data from
// the task may be rejected, in which case this function will set
// deserialize_task->rejected() to true.
static MaybeHandle<SharedFunctionInfo>
GetSharedFunctionInfoForScriptWithDeserializeTask(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details,
BackgroundDeserializeTask* deserialize_task,
ScriptCompiler::CompileOptions compile_options,
ScriptCompiler::NoCacheReason no_cache_reason,
NativesFlag is_natives_code);
@ -571,6 +602,8 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask {
Handle<String> source,
ScriptOriginOptions origin_options);
bool rejected() const { return cached_data_.rejected(); }
private:
Isolate* isolate_for_local_isolate_;
AlignedCachedData cached_data_;

View File

@ -34,9 +34,8 @@ static MaybeHandle<SharedFunctionInfo> GetFunctionInfo(Isolate* isolate,
ScriptOriginOptions(false, true));
script_details.repl_mode = repl_mode;
return Compiler::GetSharedFunctionInfoForScript(
isolate, source, script_details, nullptr, nullptr,
ScriptCompiler::kNoCompileOptions, ScriptCompiler::kNoCacheNoReason,
NOT_NATIVES_CODE);
isolate, source, script_details, ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE);
}
} // namespace

View File

@ -760,8 +760,8 @@ MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* v8_isolate,
{
i::AlignedCachedData* cached_data = nullptr;
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, i::ScriptDetails(), nullptr, cached_data,
i::Compiler::GetSharedFunctionInfoForScriptWithCachedData(
isolate, str, i::ScriptDetails(), cached_data,
ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheBecauseInspector,
i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE

View File

@ -4129,10 +4129,9 @@ bool Genesis::CompileExtension(Isolate* isolate, v8::Extension* extension) {
Handle<String> script_name =
factory->NewStringFromUtf8(name).ToHandleChecked();
MaybeHandle<SharedFunctionInfo> maybe_function_info =
Compiler::GetSharedFunctionInfoForScript(
isolate, source, ScriptDetails(script_name), extension, nullptr,
ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheBecauseV8Extension, EXTENSION_CODE);
Compiler::GetSharedFunctionInfoForScriptWithExtension(
isolate, source, ScriptDetails(script_name), extension,
ScriptCompiler::kNoCompileOptions, EXTENSION_CODE);
if (!maybe_function_info.ToHandle(&function_info)) return false;
cache->Add(isolate, name, function_info);
}

View File

@ -35,7 +35,7 @@ static Handle<JSFunction> Compile(const char* source) {
.ToHandleChecked();
Handle<SharedFunctionInfo> shared =
Compiler::GetSharedFunctionInfoForScript(
isolate, source_code, ScriptDetails(), nullptr, nullptr,
isolate, source_code, ScriptDetails(),
v8::ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
.ToHandleChecked();

View File

@ -73,7 +73,7 @@ static Handle<JSFunction> Compile(const char* source) {
.ToHandleChecked();
Handle<SharedFunctionInfo> shared =
Compiler::GetSharedFunctionInfoForScript(
isolate, source_code, ScriptDetails(), nullptr, nullptr,
isolate, source_code, ScriptDetails(),
v8::ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
.ToHandleChecked();

View File

@ -1574,8 +1574,8 @@ static Handle<SharedFunctionInfo> CompileScript(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, AlignedCachedData* cached_data,
v8::ScriptCompiler::CompileOptions options) {
return Compiler::GetSharedFunctionInfoForScript(
isolate, source, script_details, nullptr, cached_data, options,
return Compiler::GetSharedFunctionInfoForScriptWithCachedData(
isolate, source, script_details, cached_data, options,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
.ToHandleChecked();
}
@ -1586,7 +1586,7 @@ static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
v8::ScriptCompiler::CompileOptions options) {
Handle<SharedFunctionInfo> sfi =
Compiler::GetSharedFunctionInfoForScript(
isolate, source, script_details, nullptr, nullptr, options,
isolate, source, script_details, options,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE)
.ToHandleChecked();
std::unique_ptr<ScriptCompiler::CachedData> cached_data(