Commit 26609973 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[codegen] Assert that deserialized SFIs have correct origins

Re-use the same check we already have in place for the
compilation cache for when we use CodeSerializer::Deserialize.

- Move HasOrigin to SharedFunctionInfo::HasMatchingOrigin
- HasMatchingOrigin no longer allocates
- Pass ScriptDetails in more places

Bug: v8:10284
Change-Id: I6e074bd1e7db9a35fdf7123d04a65841d9813e02
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3090968
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76451}
parent 1c4ae62d
...@@ -105,41 +105,6 @@ void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) { ...@@ -105,41 +105,6 @@ void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
CompilationCacheScript::CompilationCacheScript(Isolate* isolate) CompilationCacheScript::CompilationCacheScript(Isolate* isolate)
: CompilationSubCache(isolate, 1) {} : CompilationSubCache(isolate, 1) {}
namespace {
// We only re-use a cached function for some script source code if the
// script originates from the same place. This is to avoid issues
// when reporting errors, etc.
bool HasOrigin(Isolate* isolate, Handle<SharedFunctionInfo> function_info,
const ScriptDetails& script_details) {
Handle<Script> script =
Handle<Script>(Script::cast(function_info->script()), isolate);
// If the script name isn't set, the boilerplate script should have
// an undefined name to have the same origin.
Handle<Object> name;
if (!script_details.name_obj.ToHandle(&name)) {
return script->name().IsUndefined(isolate);
}
// Do the fast bailout checks first.
if (script_details.line_offset != script->line_offset()) return false;
if (script_details.column_offset != script->column_offset()) return false;
// Check that both names are strings. If not, no match.
if (!name->IsString() || !script->name().IsString()) return false;
// Are the origin_options same?
if (script_details.origin_options.Flags() !=
script->origin_options().Flags()) {
return false;
}
// Compare the two name strings for equality.
if (!String::Equals(isolate, Handle<String>::cast(name),
Handle<String>(String::cast(script->name()), isolate))) {
return false;
}
// TODO(10284): Enable host-defined options check again
return true;
}
} // namespace
// TODO(245): Need to allow identical code from different contexts to // TODO(245): Need to allow identical code from different contexts to
// be cached in the same script generation. Currently the first use // be cached in the same script generation. Currently the first use
// will be cached, but subsequent code from different source / line // will be cached, but subsequent code from different source / line
...@@ -162,7 +127,7 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup( ...@@ -162,7 +127,7 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup(
if (probe.ToHandle(&function_info)) { if (probe.ToHandle(&function_info)) {
// Break when we've found a suitable shared function info that // Break when we've found a suitable shared function info that
// matches the origin. // matches the origin.
if (HasOrigin(isolate(), function_info, script_details)) { if (function_info->HasMatchingOrigin(isolate(), script_details)) {
result = scope.CloseAndEscape(function_info); result = scope.CloseAndEscape(function_info);
} }
} }
...@@ -173,9 +138,7 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup( ...@@ -173,9 +138,7 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup(
// handle created in the caller's handle scope. // handle created in the caller's handle scope.
Handle<SharedFunctionInfo> function_info; Handle<SharedFunctionInfo> function_info;
if (result.ToHandle(&function_info)) { if (result.ToHandle(&function_info)) {
// Since HasOrigin can allocate, we need to protect the SharedFunctionInfo DCHECK(function_info->HasMatchingOrigin(isolate(), script_details));
// with handles during the call.
DCHECK(HasOrigin(isolate(), function_info, script_details));
isolate()->counters()->compilation_cache_hits()->Increment(); isolate()->counters()->compilation_cache_hits()->Increment();
LOG(isolate(), CompilationCacheEvent("hit", "script", *function_info)); LOG(isolate(), CompilationCacheEvent("hit", "script", *function_info));
} else { } else {
......
...@@ -1706,10 +1706,10 @@ void BackgroundDeserializeTask::Run() { ...@@ -1706,10 +1706,10 @@ void BackgroundDeserializeTask::Run() {
MaybeHandle<SharedFunctionInfo> BackgroundDeserializeTask::Finish( MaybeHandle<SharedFunctionInfo> BackgroundDeserializeTask::Finish(
Isolate* isolate, Handle<String> source, Isolate* isolate, Handle<String> source,
ScriptOriginOptions origin_options) { const ScriptDetails& script_details) {
return CodeSerializer::FinishOffThreadDeserialize( return CodeSerializer::FinishOffThreadDeserialize(
isolate, std::move(off_thread_data_), &cached_data_, source, isolate, std::move(off_thread_data_), &cached_data_, source,
origin_options); script_details);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -2884,11 +2884,11 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( ...@@ -2884,11 +2884,11 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
"V8.CompileDeserialize"); "V8.CompileDeserialize");
if (deserialize_task) { if (deserialize_task) {
// If there's a cache consume task, finish it. // If there's a cache consume task, finish it.
maybe_result = deserialize_task->Finish(isolate, source, maybe_result =
script_details.origin_options); deserialize_task->Finish(isolate, source, script_details);
} else { } else {
maybe_result = CodeSerializer::Deserialize( maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
isolate, cached_data, source, script_details.origin_options); script_details);
} }
bool consuming_code_cache_succeeded = false; bool consuming_code_cache_succeeded = false;
...@@ -2906,6 +2906,11 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( ...@@ -2906,6 +2906,11 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
compile_timer.set_consuming_code_cache_failed(); compile_timer.set_consuming_code_cache_failed();
} }
} }
if (!maybe_result.is_null()) {
// Assert we end up with compatible SFIs.
DCHECK(maybe_result.ToHandleChecked()->HasMatchingOrigin(isolate,
script_details));
}
} }
if (maybe_result.is_null()) { if (maybe_result.is_null()) {
...@@ -3025,7 +3030,7 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction( ...@@ -3025,7 +3030,7 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileDeserialize"); "V8.CompileDeserialize");
maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source, maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
script_details.origin_options); script_details);
if (maybe_result.is_null()) { if (maybe_result.is_null()) {
// Deserializer failed. Fall through to compile. // Deserializer failed. Fall through to compile.
compile_timer.set_consuming_code_cache_failed(); compile_timer.set_consuming_code_cache_failed();
......
...@@ -600,7 +600,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask { ...@@ -600,7 +600,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask {
MaybeHandle<SharedFunctionInfo> Finish(Isolate* isolate, MaybeHandle<SharedFunctionInfo> Finish(Isolate* isolate,
Handle<String> source, Handle<String> source,
ScriptOriginOptions origin_options); const ScriptDetails& script_details);
bool rejected() const { return cached_data_.rejected(); } bool rejected() const { return cached_data_.rejected(); }
......
...@@ -15,6 +15,8 @@ namespace internal { ...@@ -15,6 +15,8 @@ namespace internal {
struct ScriptDetails { struct ScriptDetails {
ScriptDetails() ScriptDetails()
: line_offset(0), column_offset(0), repl_mode(REPLMode::kNo) {} : line_offset(0), column_offset(0), repl_mode(REPLMode::kNo) {}
explicit ScriptDetails(ScriptOriginOptions origin_options)
: ScriptDetails(Handle<Object>(), origin_options) {}
explicit ScriptDetails( explicit ScriptDetails(
Handle<Object> script_name, Handle<Object> script_name,
ScriptOriginOptions origin_options = v8::ScriptOriginOptions()) ScriptOriginOptions origin_options = v8::ScriptOriginOptions())
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
#include "src/codegen/compilation-cache.h" #include "src/codegen/compilation-cache.h"
#include "src/codegen/compiler.h" #include "src/codegen/compiler.h"
#include "src/codegen/script-details.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/diagnostics/code-tracer.h" #include "src/diagnostics/code-tracer.h"
#include "src/objects/shared-function-info-inl.h" #include "src/objects/shared-function-info-inl.h"
...@@ -713,5 +714,62 @@ void SharedFunctionInfo::UninstallDebugBytecode(SharedFunctionInfo shared, ...@@ -713,5 +714,62 @@ void SharedFunctionInfo::UninstallDebugBytecode(SharedFunctionInfo shared,
kReleaseStore); kReleaseStore);
} }
// static
// We only re-use a cached function for some script source code if the
// script originates from the same place. This is to avoid issues
// when reporting errors, etc.
bool SharedFunctionInfo::HasMatchingOrigin(
Isolate* isolate, const ScriptDetails& script_details) const {
DisallowGarbageCollection no_gc;
Script script = Script::cast(this->script());
// If the script name isn't set, the boilerplate script should have
// an undefined name to have the same origin.
Object name_obj;
{
Handle<Object> tmp_handle;
if (script_details.name_obj.ToHandle(&tmp_handle)) {
name_obj = *tmp_handle;
} else {
return script.name().IsUndefined(isolate);
}
}
// Do the fast bailout checks first.
if (script_details.line_offset != script.line_offset()) return false;
if (script_details.column_offset != script.column_offset()) return false;
// Check that both names are strings. If not, no match.
if (!name_obj.IsString() || !script.name().IsString()) return false;
// Are the origin_options same?
if (script_details.origin_options.Flags() !=
script.origin_options().Flags()) {
return false;
}
if (!String::cast(name_obj).Equals(String::cast(script.name()))) return false;
// TODO(10284): Enable strict checks again.
// FixedArray host_defined_options;
// {
// Handle<FixedArray> tmp_handle;
// if (script_details.host_defined_options.ToHandle(&tmp_handle)) {
// host_defined_options = *tmp_handle;
// } else {
// host_defined_options = ReadOnlyRoots(isolate).empty_fixed_array();
// }
// }
// FixedArray script_options = script.host_defined_options();
// if (host_defined_options == script_options) return true;
// int length = host_defined_options.length();
// if (length != script_options.length()) return false;
// for (int i = 0; i < length; i++) {
// // host-defined options is a v8::PrimitiveArray.
// DCHECK(host_defined_options.get(i).IsPrimitive());
// DCHECK(script_options.get(i).IsPrimitive());
// if (!host_defined_options.get(i).StrictEquals(script_options.get(i))) {
// return false;
// }
// }
return true;
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -38,6 +38,7 @@ class DebugInfo; ...@@ -38,6 +38,7 @@ class DebugInfo;
class IsCompiledScope; class IsCompiledScope;
template <typename> template <typename>
class Signature; class Signature;
struct ScriptDetails;
class WasmCapiFunctionData; class WasmCapiFunctionData;
class WasmExportedFunctionData; class WasmExportedFunctionData;
class WasmJSFunctionData; class WasmJSFunctionData;
...@@ -207,6 +208,9 @@ class SharedFunctionInfo ...@@ -207,6 +208,9 @@ class SharedFunctionInfo
int function_literal_id, int function_literal_id,
bool reset_preparsed_scope_data = true); bool reset_preparsed_scope_data = true);
bool HasMatchingOrigin(Isolate* isolate,
const ScriptDetails& script_details) const;
// Layout description of the optimized code map. // Layout description of the optimized code map.
static const int kEntriesStart = 0; static const int kEntriesStart = 0;
static const int kContextOffset = 0; static const int kContextOffset = 0;
...@@ -240,8 +244,9 @@ class SharedFunctionInfo ...@@ -240,8 +244,9 @@ class SharedFunctionInfo
// Updates the scope info if available. // Updates the scope info if available.
V8_EXPORT_PRIVATE void SetPosition(int start_position, int end_position); V8_EXPORT_PRIVATE void SetPosition(int start_position, int end_position);
// [outer scope info | feedback metadata] Shared storage for outer scope info // [outer scope info | feedback metadata] Shared storage for outer scope
// (on uncompiled functions) and feedback metadata (on compiled functions). // info (on uncompiled functions) and feedback metadata (on compiled
// functions).
DECL_ACCESSORS(raw_outer_scope_info_or_feedback_metadata, HeapObject) DECL_ACCESSORS(raw_outer_scope_info_or_feedback_metadata, HeapObject)
DECL_ACQUIRE_GETTER(raw_outer_scope_info_or_feedback_metadata, HeapObject) DECL_ACQUIRE_GETTER(raw_outer_scope_info_or_feedback_metadata, HeapObject)
private: private:
...@@ -255,8 +260,8 @@ class SharedFunctionInfo ...@@ -255,8 +260,8 @@ class SharedFunctionInfo
inline bool HasOuterScopeInfo() const; inline bool HasOuterScopeInfo() const;
inline ScopeInfo GetOuterScopeInfo() const; inline ScopeInfo GetOuterScopeInfo() const;
// [feedback metadata] Metadata template for feedback vectors of instances of // [feedback metadata] Metadata template for feedback vectors of instances
// this function. // of this function.
inline bool HasFeedbackMetadata() const; inline bool HasFeedbackMetadata() const;
inline bool HasFeedbackMetadata(AcquireLoadTag tag) const; inline bool HasFeedbackMetadata(AcquireLoadTag tag) const;
inline FeedbackMetadata feedback_metadata() const; inline FeedbackMetadata feedback_metadata() const;
...@@ -268,9 +273,9 @@ class SharedFunctionInfo ...@@ -268,9 +273,9 @@ class SharedFunctionInfo
// for some period of time, use IsCompiledScope instead. // for some period of time, use IsCompiledScope instead.
inline bool is_compiled() const; inline bool is_compiled() const;
// Returns an IsCompiledScope which reports whether the function is compiled, // Returns an IsCompiledScope which reports whether the function is
// and if compiled, will avoid the function becoming uncompiled while it is // compiled, and if compiled, will avoid the function becoming uncompiled
// held. // while it is held.
template <typename IsolateT> template <typename IsolateT>
inline IsCompiledScope is_compiled_scope(IsolateT* isolate) const; inline IsCompiledScope is_compiled_scope(IsolateT* isolate) const;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/base/platform/elapsed-timer.h" #include "src/base/platform/elapsed-timer.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/codegen/macro-assembler.h" #include "src/codegen/macro-assembler.h"
#include "src/codegen/script-details.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/handles/maybe-handles.h" #include "src/handles/maybe-handles.h"
...@@ -74,8 +75,10 @@ ScriptCompiler::CachedData* CodeSerializer::Serialize( ...@@ -74,8 +75,10 @@ ScriptCompiler::CachedData* CodeSerializer::Serialize(
// Serialize code object. // Serialize code object.
Handle<String> source(String::cast(script->source()), isolate); Handle<String> source(String::cast(script->source()), isolate);
HandleScope scope(isolate); HandleScope scope(isolate);
CodeSerializer cs(isolate, SerializedCodeData::SourceHash( ScriptDetails script_details(handle(script->name(), isolate),
source, script->origin_options())); script->origin_options());
CodeSerializer cs(isolate,
SerializedCodeData::SourceHash(source, script_details));
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
cs.reference_map()->AddAttachedReference(*source); cs.reference_map()->AddAttachedReference(*source);
AlignedCachedData* cached_data = cs.SerializeSharedFunctionInfo(info); AlignedCachedData* cached_data = cs.SerializeSharedFunctionInfo(info);
...@@ -291,12 +294,12 @@ class StressOffThreadDeserializeThread final : public base::Thread { ...@@ -291,12 +294,12 @@ class StressOffThreadDeserializeThread final : public base::Thread {
CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_); CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_);
} }
MaybeHandle<SharedFunctionInfo> Finalize(Isolate* isolate, MaybeHandle<SharedFunctionInfo> Finalize(
Handle<String> source, Isolate* isolate, Handle<String> source,
ScriptOriginOptions origin_options) { const ScriptDetails& script_details) {
return CodeSerializer::FinishOffThreadDeserialize( return CodeSerializer::FinishOffThreadDeserialize(
isolate, std::move(off_thread_data_), cached_data_, source, isolate, std::move(off_thread_data_), cached_data_, source,
origin_options); script_details);
} }
private: private:
...@@ -369,19 +372,72 @@ void FinalizeDeserialization(Isolate* isolate, ...@@ -369,19 +372,72 @@ void FinalizeDeserialization(Isolate* isolate,
} }
} }
void CompareSFIs(Handle<SharedFunctionInfo> main_thread,
Handle<SharedFunctionInfo> off_thread) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(main_thread->flags(kRelaxedLoad), off_thread->flags(kRelaxedLoad));
DCHECK_EQ(main_thread->flags2(), off_thread->flags2());
DCHECK_EQ(main_thread->raw_function_token_offset(),
off_thread->raw_function_token_offset());
DCHECK_EQ(main_thread->internal_formal_parameter_count(),
off_thread->internal_formal_parameter_count());
DCHECK(main_thread->Name().Equals(off_thread->Name()));
if (!main_thread->script().IsScript()) {
DCHECK(!off_thread->script().IsScript());
return;
}
Script main_thread_script = Script::cast(main_thread->script());
#ifdef DEBUG
Script off_thread_script = Script::cast(off_thread->script());
#endif
DCHECK_EQ(main_thread_script.flags(), off_thread_script.flags());
DCHECK_EQ(main_thread_script.script_type(), off_thread_script.script_type());
if (main_thread_script.source().IsString()) {
DCHECK(String::cast(main_thread_script.source())
.Equals(String::cast(off_thread_script.source())));
} else {
DCHECK(!off_thread_script.source().IsString());
}
if (main_thread_script.source_url().IsString()) {
DCHECK(String::cast(main_thread_script.source())
.Equals(String::cast(off_thread_script.source())));
} else {
DCHECK(!off_thread_script.source_url().IsString());
}
if (main_thread_script.name().IsString()) {
DCHECK(String::cast(main_thread_script.name())
.Equals(String::cast(off_thread_script.name())));
} else {
DCHECK(!off_thread_script.name().IsString());
}
}
} // namespace } // namespace
MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source, Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source,
ScriptOriginOptions origin_options) { const ScriptDetails& script_details) {
if (FLAG_stress_background_compile) { if (FLAG_stress_background_compile) {
StressOffThreadDeserializeThread thread(isolate, cached_data); StressOffThreadDeserializeThread thread(isolate, cached_data);
CHECK(thread.Start()); CHECK(thread.Start());
thread.Join(); thread.Join();
return thread.Finalize(isolate, source, origin_options); MaybeHandle<SharedFunctionInfo> off_thread_result =
// TODO(leszeks): Compare off-thread deserialized data to on-thread. thread.Finalize(isolate, source, script_details);
} MaybeHandle<SharedFunctionInfo> main_thread_result =
DeserializeMain(isolate, cached_data, source, script_details);
DCHECK_EQ(off_thread_result.is_null(), main_thread_result.is_null());
if (!main_thread_result.is_null()) {
CompareSFIs(main_thread_result.ToHandleChecked(),
off_thread_result.ToHandleChecked());
}
return off_thread_result;
}
return DeserializeMain(isolate, cached_data, source, script_details);
}
MaybeHandle<SharedFunctionInfo> CodeSerializer::DeserializeMain(
Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source,
const ScriptDetails& script_details) {
base::ElapsedTimer timer; base::ElapsedTimer timer;
if (FLAG_profile_deserialization || FLAG_log_function_events) timer.Start(); if (FLAG_profile_deserialization || FLAG_log_function_events) timer.Start();
...@@ -390,7 +446,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -390,7 +446,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
SerializedCodeData::SanityCheckResult sanity_check_result = SerializedCodeData::SanityCheckResult sanity_check_result =
SerializedCodeData::CHECK_SUCCESS; SerializedCodeData::CHECK_SUCCESS;
const SerializedCodeData scd = SerializedCodeData::FromCachedData( const SerializedCodeData scd = SerializedCodeData::FromCachedData(
cached_data, SerializedCodeData::SourceHash(source, origin_options), cached_data, SerializedCodeData::SourceHash(source, script_details),
&sanity_check_result); &sanity_check_result);
if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) { if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n"); if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
...@@ -410,7 +466,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -410,7 +466,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n"); if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
return MaybeHandle<SharedFunctionInfo>(); return MaybeHandle<SharedFunctionInfo>();
} }
if (FLAG_profile_deserialization) { if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
int length = cached_data->length(); int length = cached_data->length();
...@@ -444,7 +499,6 @@ CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate, ...@@ -444,7 +499,6 @@ CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate,
MaybeHandle<SharedFunctionInfo> local_maybe_result = MaybeHandle<SharedFunctionInfo> local_maybe_result =
OffThreadObjectDeserializer::DeserializeSharedFunctionInfo( OffThreadObjectDeserializer::DeserializeSharedFunctionInfo(
local_isolate, &scd, &result.scripts); local_isolate, &scd, &result.scripts);
result.maybe_result = result.maybe_result =
local_isolate->heap()->NewPersistentMaybeHandle(local_maybe_result); local_isolate->heap()->NewPersistentMaybeHandle(local_maybe_result);
result.persistent_handles = local_isolate->heap()->DetachPersistentHandles(); result.persistent_handles = local_isolate->heap()->DetachPersistentHandles();
...@@ -455,7 +509,7 @@ CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate, ...@@ -455,7 +509,7 @@ CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate,
MaybeHandle<SharedFunctionInfo> CodeSerializer::FinishOffThreadDeserialize( MaybeHandle<SharedFunctionInfo> CodeSerializer::FinishOffThreadDeserialize(
Isolate* isolate, OffThreadDeserializeData&& data, Isolate* isolate, OffThreadDeserializeData&& data,
AlignedCachedData* cached_data, Handle<String> source, AlignedCachedData* cached_data, Handle<String> source,
ScriptOriginOptions origin_options) { const ScriptDetails& script_details) {
base::ElapsedTimer timer; base::ElapsedTimer timer;
if (FLAG_profile_deserialization || FLAG_log_function_events) timer.Start(); if (FLAG_profile_deserialization || FLAG_log_function_events) timer.Start();
...@@ -465,7 +519,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::FinishOffThreadDeserialize( ...@@ -465,7 +519,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::FinishOffThreadDeserialize(
SerializedCodeData::SanityCheckResult sanity_check_result = SerializedCodeData::SanityCheckResult sanity_check_result =
SerializedCodeData::CHECK_SUCCESS; SerializedCodeData::CHECK_SUCCESS;
const SerializedCodeData scd = SerializedCodeData::FromCachedData( const SerializedCodeData scd = SerializedCodeData::FromCachedData(
cached_data, SerializedCodeData::SourceHash(source, origin_options), cached_data, SerializedCodeData::SourceHash(source, script_details),
&sanity_check_result); &sanity_check_result);
if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) { if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
// The only case where the deserialization result could exist despite a // The only case where the deserialization result could exist despite a
...@@ -581,11 +635,12 @@ SerializedCodeData::SanityCheckWithoutSource() const { ...@@ -581,11 +635,12 @@ SerializedCodeData::SanityCheckWithoutSource() const {
} }
uint32_t SerializedCodeData::SourceHash(Handle<String> source, uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) { const ScriptDetails& script_details) {
const uint32_t source_length = source->length(); const uint32_t source_length = source->length();
static constexpr uint32_t kModuleFlagMask = (1 << 31); static constexpr uint32_t kModuleFlagMask = (1 << 31);
const uint32_t is_module = origin_options.IsModule() ? kModuleFlagMask : 0; const uint32_t is_module =
script_details.origin_options.IsModule() ? kModuleFlagMask : 0;
DCHECK_EQ(0, source_length & kModuleFlagMask); DCHECK_EQ(0, source_length & kModuleFlagMask);
return source_length | is_module; return source_length | is_module;
......
...@@ -13,6 +13,7 @@ namespace v8 { ...@@ -13,6 +13,7 @@ namespace v8 {
namespace internal { namespace internal {
class PersistentHandles; class PersistentHandles;
struct ScriptDetails;
class V8_EXPORT_PRIVATE AlignedCachedData { class V8_EXPORT_PRIVATE AlignedCachedData {
public: public:
...@@ -68,7 +69,7 @@ class CodeSerializer : public Serializer { ...@@ -68,7 +69,7 @@ class CodeSerializer : public Serializer {
V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize( V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize(
Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source, Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source,
ScriptOriginOptions origin_options); const ScriptDetails& script_details);
V8_WARN_UNUSED_RESULT static OffThreadDeserializeData V8_WARN_UNUSED_RESULT static OffThreadDeserializeData
StartDeserializeOffThread(LocalIsolate* isolate, StartDeserializeOffThread(LocalIsolate* isolate,
...@@ -78,7 +79,7 @@ class CodeSerializer : public Serializer { ...@@ -78,7 +79,7 @@ class CodeSerializer : public Serializer {
FinishOffThreadDeserialize(Isolate* isolate, OffThreadDeserializeData&& data, FinishOffThreadDeserialize(Isolate* isolate, OffThreadDeserializeData&& data,
AlignedCachedData* cached_data, AlignedCachedData* cached_data,
Handle<String> source, Handle<String> source,
ScriptOriginOptions origin_options); const ScriptDetails& script_details);
uint32_t source_hash() const { return source_hash_; } uint32_t source_hash() const { return source_hash_; }
...@@ -91,9 +92,12 @@ class CodeSerializer : public Serializer { ...@@ -91,9 +92,12 @@ class CodeSerializer : public Serializer {
private: private:
void SerializeObjectImpl(Handle<HeapObject> o) override; void SerializeObjectImpl(Handle<HeapObject> o) override;
bool SerializeReadOnlyObject(Handle<HeapObject> obj); bool SerializeReadOnlyObject(Handle<HeapObject> obj);
V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo> DeserializeMain(
Isolate* isolate, AlignedCachedData* cached_data, Handle<String> source,
const ScriptDetails& script_details);
DISALLOW_GARBAGE_COLLECTION(no_gc_) DISALLOW_GARBAGE_COLLECTION(no_gc_)
uint32_t source_hash_; uint32_t source_hash_;
}; };
...@@ -145,7 +149,7 @@ class SerializedCodeData : public SerializedData { ...@@ -145,7 +149,7 @@ class SerializedCodeData : public SerializedData {
base::Vector<const byte> Payload() const; base::Vector<const byte> Payload() const;
static uint32_t SourceHash(Handle<String> source, static uint32_t SourceHash(Handle<String> source,
ScriptOriginOptions origin_options); const ScriptDetails& script_details);
private: private:
explicit SerializedCodeData(AlignedCachedData* data); explicit SerializedCodeData(AlignedCachedData* data);
......
...@@ -1490,8 +1490,7 @@ TEST(CompilationCacheCachingBehavior) { ...@@ -1490,8 +1490,7 @@ TEST(CompilationCacheCachingBehavior) {
// The script should be in the cache now. // The script should be in the cache now.
{ {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
ScriptDetails script_details(Handle<Object>(), ScriptDetails script_details(v8::ScriptOriginOptions(true, false));
v8::ScriptOriginOptions(true, false));
MaybeHandle<SharedFunctionInfo> cached_script = MaybeHandle<SharedFunctionInfo> cached_script =
compilation_cache->LookupScript(source, script_details, language_mode); compilation_cache->LookupScript(source, script_details, language_mode);
CHECK(!cached_script.is_null()); CHECK(!cached_script.is_null());
...@@ -1501,8 +1500,7 @@ TEST(CompilationCacheCachingBehavior) { ...@@ -1501,8 +1500,7 @@ TEST(CompilationCacheCachingBehavior) {
{ {
CcTest::CollectAllGarbage(); CcTest::CollectAllGarbage();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
ScriptDetails script_details(Handle<Object>(), ScriptDetails script_details(v8::ScriptOriginOptions(true, false));
v8::ScriptOriginOptions(true, false));
MaybeHandle<SharedFunctionInfo> cached_script = MaybeHandle<SharedFunctionInfo> cached_script =
compilation_cache->LookupScript(source, script_details, language_mode); compilation_cache->LookupScript(source, script_details, language_mode);
CHECK(!cached_script.is_null()); CHECK(!cached_script.is_null());
...@@ -1521,8 +1519,7 @@ TEST(CompilationCacheCachingBehavior) { ...@@ -1521,8 +1519,7 @@ TEST(CompilationCacheCachingBehavior) {
{ {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
// Ensure code aging cleared the entry from the cache. // Ensure code aging cleared the entry from the cache.
ScriptDetails script_details(Handle<Object>(), ScriptDetails script_details(v8::ScriptOriginOptions(true, false));
v8::ScriptOriginOptions(true, false));
MaybeHandle<SharedFunctionInfo> cached_script = MaybeHandle<SharedFunctionInfo> cached_script =
compilation_cache->LookupScript(source, script_details, language_mode); compilation_cache->LookupScript(source, script_details, language_mode);
CHECK(cached_script.is_null()); CHECK(cached_script.is_null());
......
...@@ -707,6 +707,7 @@ UNINITIALIZED_TEST(ExternalCodeEventListener) { ...@@ -707,6 +707,7 @@ UNINITIALIZED_TEST(ExternalCodeEventListener) {
UNINITIALIZED_TEST(ExternalCodeEventListenerInnerFunctions) { UNINITIALIZED_TEST(ExternalCodeEventListenerInnerFunctions) {
i::FLAG_log = false; i::FLAG_log = false;
i::FLAG_prof = false; i::FLAG_prof = false;
i::FLAG_stress_background_compile = false;
v8::ScriptCompiler::CachedData* cache; v8::ScriptCompiler::CachedData* cache;
static const char* source_cstring = static const char* source_cstring =
......
...@@ -4129,7 +4129,9 @@ TEST(WeakArraySerializationInCodeCache) { ...@@ -4129,7 +4129,9 @@ TEST(WeakArraySerializationInCodeCache) {
.ToHandleChecked(); .ToHandleChecked();
AlignedCachedData* cache = nullptr; AlignedCachedData* cache = nullptr;
ScriptDetails script_details(src); // TODO(leszeks): Fix off-thread deserialization.
ScriptDetails script_details(
isolate->factory()->NewStringFromAsciiChecked(source));
CompileScriptAndProduceCache(isolate, src, script_details, &cache, CompileScriptAndProduceCache(isolate, src, script_details, &cache,
v8::ScriptCompiler::kNoCompileOptions); v8::ScriptCompiler::kNoCompileOptions);
......
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