Skip to content

Commit

Permalink
deps: V8: cherry-pick efb1133eb894
Browse files Browse the repository at this point in the history
Original commit message:

    [api] Add v8::ScriptCompiler::CachedData::CompatibilityCheck()

    This patch adds a new API v8::ScriptCompiler::CachedData::CompatibilityCheck()
    in order to allow embedders to check if the code cache can be used in
    the current isolate without looking up for the source code. It also returns more detailed reasons about why the code cache cannot be used
    when it's bound to be rejected. This makes it possible to enforce
    portability checks in case code code becomes CPU-dependent in the
    future.

    Refs: nodejs#42566 (comment)

    Change-Id: Ia1d677b949050add961af6fbf62c44342c061312
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4905290
    Reviewed-by: Marja Hölttä <marja@chromium.org>
    Reviewed-by: Toon Verwaest <verwaest@chromium.org>
    Commit-Queue: Joyee Cheung <joyee@igalia.com>
    Cr-Commit-Position: refs/heads/main@{#90833}

Refs: v8/v8@efb1133
PR-URL: nodejs#51551
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
  • Loading branch information
joyeecheung authored and rdw-msft committed Feb 9, 2024
1 parent ddf730c commit 26e94df
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 17 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.12',
'v8_embedder_string': '-node.13',

##### V8 defaults for Node.js #####

Expand Down
21 changes: 21 additions & 0 deletions deps/v8/include/v8-script.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,27 @@ class V8_EXPORT ScriptCompiler {
CachedData(const uint8_t* data, int length,
BufferPolicy buffer_policy = BufferNotOwned);
~CachedData();

enum CompatibilityCheckResult {
// Don't change order/existing values of this enum since it keys into the
// `code_cache_reject_reason` histogram. Append-only!
kSuccess = 0,
kMagicNumberMismatch = 1,
kVersionMismatch = 2,
kSourceMismatch = 3,
kFlagsMismatch = 5,
kChecksumMismatch = 6,
kInvalidHeader = 7,
kLengthMismatch = 8,
kReadOnlySnapshotChecksumMismatch = 9,

// This should always point at the last real enum value.
kLast = kReadOnlySnapshotChecksumMismatch
};

// Check if the CachedData can be loaded in the given isolate.
CompatibilityCheckResult CompatibilityCheck(Isolate* isolate);

// TODO(marja): Async compilation; add constructors which take a callback
// which will be called when V8 no longer needs the data.
const uint8_t* data;
Expand Down
12 changes: 12 additions & 0 deletions deps/v8/src/api/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,18 @@ ScriptCompiler::CachedData::~CachedData() {
}
}

ScriptCompiler::CachedData::CompatibilityCheckResult
ScriptCompiler::CachedData::CompatibilityCheck(Isolate* isolate) {
i::AlignedCachedData aligned(data, length);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::SerializedCodeSanityCheckResult result;
i::SerializedCodeData scd =
i::SerializedCodeData::FromCachedDataWithoutSource(
i_isolate->AsLocalIsolate(), &aligned, &result);
return static_cast<ScriptCompiler::CachedData::CompatibilityCheckResult>(
result);
}

ScriptCompiler::StreamedSource::StreamedSource(
std::unique_ptr<ExternalSourceStream> stream, Encoding encoding)
: impl_(new i::ScriptStreamingData(std::move(stream), encoding)) {}
Expand Down
19 changes: 3 additions & 16 deletions deps/v8/src/snapshot/code-serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,9 @@ class V8_EXPORT_PRIVATE AlignedCachedData {
int length_;
};

enum class SerializedCodeSanityCheckResult {
// Don't change order/existing values of this enum since it keys into the
// `code_cache_reject_reason` histogram. Append-only!
kSuccess = 0,
kMagicNumberMismatch = 1,
kVersionMismatch = 2,
kSourceMismatch = 3,
kFlagsMismatch = 5,
kChecksumMismatch = 6,
kInvalidHeader = 7,
kLengthMismatch = 8,
kReadOnlySnapshotChecksumMismatch = 9,

// This should always point at the last real enum value.
kLast = kReadOnlySnapshotChecksumMismatch
};
typedef v8::ScriptCompiler::CachedData::CompatibilityCheckResult
SerializedCodeSanityCheckResult;

// If this fails, update the static_assert AND the code_cache_reject_reason
// histogram definition.
static_assert(static_cast<int>(SerializedCodeSanityCheckResult::kLast) == 9);
Expand Down
72 changes: 72 additions & 0 deletions deps/v8/test/cctest/test-serialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2799,6 +2799,78 @@ TEST(CodeSerializerFlagChange) {
isolate2->Dispose();
}

TEST(CachedDataCompatibilityCheck) {
{
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
// Hand-craft a zero-filled cached data which cannot be valid.
int length = 64;
uint8_t* payload = new uint8_t[length];
memset(payload, 0, length);
v8::ScriptCompiler::CachedData cache(
payload, length, v8::ScriptCompiler::CachedData::BufferOwned);
{
v8::Isolate::Scope iscope(isolate);
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
cache.CompatibilityCheck(isolate);
CHECK_NE(result, v8::ScriptCompiler::CachedData::kSuccess);
}
isolate->Dispose();
}

const char* js_source = "function f() { return 'abc'; }; f() + 'def'";
std::unique_ptr<v8::ScriptCompiler::CachedData> cache;
{
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope iscope(isolate);
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::ScriptCompiler::Source source(v8_str(js_source),
{isolate, v8_str("test")});
v8::Local<v8::UnboundScript> script =
v8::ScriptCompiler::CompileUnboundScript(
isolate, &source, v8::ScriptCompiler::kEagerCompile)
.ToLocalChecked();
cache.reset(ScriptCompiler::CreateCodeCache(script));
}
isolate->Dispose();
}

{
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope iscope(isolate);
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
cache->CompatibilityCheck(isolate);
CHECK_EQ(result, v8::ScriptCompiler::CachedData::kSuccess);
}
isolate->Dispose();
}

{
v8_flags.allow_natives_syntax =
true; // Flag change should trigger cache reject.
FlagList::EnforceFlagImplications();
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope iscope(isolate);
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
cache->CompatibilityCheck(isolate);
CHECK_EQ(result, v8::ScriptCompiler::CachedData::kFlagsMismatch);
}
isolate->Dispose();
}
}

TEST(CodeSerializerBitFlip) {
i::v8_flags.verify_snapshot_checksum = true;
const char* js_source = "function f() { return 'abc'; }; f() + 'def'";
Expand Down

0 comments on commit 26e94df

Please sign in to comment.