Skip to content

Commit efb1133

Browse files
joyeecheungV8 LUCI CQ
authored andcommitted
[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/node#42566 (comment) Change-Id: Ia1d677b949050add961af6fbf62c44342c061312 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4905290 Reviewed-by: Marja Hölttä <[email protected]> Reviewed-by: Toon Verwaest <[email protected]> Commit-Queue: Joyee Cheung <[email protected]> Cr-Commit-Position: refs/heads/main@{#90833}
1 parent 45d4d77 commit efb1133

4 files changed

Lines changed: 108 additions & 16 deletions

File tree

include/v8-script.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,27 @@ class V8_EXPORT ScriptCompiler {
405405
CachedData(const uint8_t* data, int length,
406406
BufferPolicy buffer_policy = BufferNotOwned);
407407
~CachedData();
408+
409+
enum CompatibilityCheckResult {
410+
// Don't change order/existing values of this enum since it keys into the
411+
// `code_cache_reject_reason` histogram. Append-only!
412+
kSuccess = 0,
413+
kMagicNumberMismatch = 1,
414+
kVersionMismatch = 2,
415+
kSourceMismatch = 3,
416+
kFlagsMismatch = 5,
417+
kChecksumMismatch = 6,
418+
kInvalidHeader = 7,
419+
kLengthMismatch = 8,
420+
kReadOnlySnapshotChecksumMismatch = 9,
421+
422+
// This should always point at the last real enum value.
423+
kLast = kReadOnlySnapshotChecksumMismatch
424+
};
425+
426+
// Check if the CachedData can be loaded in the given isolate.
427+
CompatibilityCheckResult CompatibilityCheck(Isolate* isolate);
428+
408429
// TODO(marja): Async compilation; add constructors which take a callback
409430
// which will be called when V8 no longer needs the data.
410431
const uint8_t* data;

src/api/api.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,18 @@ ScriptCompiler::CachedData::~CachedData() {
19631963
}
19641964
}
19651965

1966+
ScriptCompiler::CachedData::CompatibilityCheckResult
1967+
ScriptCompiler::CachedData::CompatibilityCheck(Isolate* isolate) {
1968+
i::AlignedCachedData aligned(data, length);
1969+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1970+
i::SerializedCodeSanityCheckResult result;
1971+
i::SerializedCodeData scd =
1972+
i::SerializedCodeData::FromCachedDataWithoutSource(
1973+
i_isolate->AsLocalIsolate(), &aligned, &result);
1974+
return static_cast<ScriptCompiler::CachedData::CompatibilityCheckResult>(
1975+
result);
1976+
}
1977+
19661978
ScriptCompiler::StreamedSource::StreamedSource(
19671979
std::unique_ptr<ExternalSourceStream> stream, Encoding encoding)
19681980
: impl_(new i::ScriptStreamingData(std::move(stream), encoding)) {}

src/snapshot/code-serializer.h

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,9 @@ class V8_EXPORT_PRIVATE AlignedCachedData {
4949
int length_;
5050
};
5151

52-
enum class SerializedCodeSanityCheckResult {
53-
// Don't change order/existing values of this enum since it keys into the
54-
// `code_cache_reject_reason` histogram. Append-only!
55-
kSuccess = 0,
56-
kMagicNumberMismatch = 1,
57-
kVersionMismatch = 2,
58-
kSourceMismatch = 3,
59-
kFlagsMismatch = 5,
60-
kChecksumMismatch = 6,
61-
kInvalidHeader = 7,
62-
kLengthMismatch = 8,
63-
kReadOnlySnapshotChecksumMismatch = 9,
64-
65-
// This should always point at the last real enum value.
66-
kLast = kReadOnlySnapshotChecksumMismatch
67-
};
52+
typedef v8::ScriptCompiler::CachedData::CompatibilityCheckResult
53+
SerializedCodeSanityCheckResult;
54+
6855
// If this fails, update the static_assert AND the code_cache_reject_reason
6956
// histogram definition.
7057
static_assert(static_cast<int>(SerializedCodeSanityCheckResult::kLast) == 9);

test/cctest/test-serialize.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,6 +2799,78 @@ TEST(CodeSerializerFlagChange) {
27992799
isolate2->Dispose();
28002800
}
28012801

2802+
TEST(CachedDataCompatibilityCheck) {
2803+
{
2804+
v8::Isolate::CreateParams create_params;
2805+
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2806+
v8::Isolate* isolate = v8::Isolate::New(create_params);
2807+
// Hand-craft a zero-filled cached data which cannot be valid.
2808+
int length = 64;
2809+
uint8_t* payload = new uint8_t[length];
2810+
memset(payload, 0, length);
2811+
v8::ScriptCompiler::CachedData cache(
2812+
payload, length, v8::ScriptCompiler::CachedData::BufferOwned);
2813+
{
2814+
v8::Isolate::Scope iscope(isolate);
2815+
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
2816+
cache.CompatibilityCheck(isolate);
2817+
CHECK_NE(result, v8::ScriptCompiler::CachedData::kSuccess);
2818+
}
2819+
isolate->Dispose();
2820+
}
2821+
2822+
const char* js_source = "function f() { return 'abc'; }; f() + 'def'";
2823+
std::unique_ptr<v8::ScriptCompiler::CachedData> cache;
2824+
{
2825+
v8::Isolate::CreateParams create_params;
2826+
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2827+
v8::Isolate* isolate = v8::Isolate::New(create_params);
2828+
{
2829+
v8::Isolate::Scope iscope(isolate);
2830+
v8::HandleScope scope(isolate);
2831+
v8::Local<v8::Context> context = v8::Context::New(isolate);
2832+
v8::Context::Scope context_scope(context);
2833+
v8::ScriptCompiler::Source source(v8_str(js_source),
2834+
{isolate, v8_str("test")});
2835+
v8::Local<v8::UnboundScript> script =
2836+
v8::ScriptCompiler::CompileUnboundScript(
2837+
isolate, &source, v8::ScriptCompiler::kEagerCompile)
2838+
.ToLocalChecked();
2839+
cache.reset(ScriptCompiler::CreateCodeCache(script));
2840+
}
2841+
isolate->Dispose();
2842+
}
2843+
2844+
{
2845+
v8::Isolate::CreateParams create_params;
2846+
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2847+
v8::Isolate* isolate = v8::Isolate::New(create_params);
2848+
{
2849+
v8::Isolate::Scope iscope(isolate);
2850+
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
2851+
cache->CompatibilityCheck(isolate);
2852+
CHECK_EQ(result, v8::ScriptCompiler::CachedData::kSuccess);
2853+
}
2854+
isolate->Dispose();
2855+
}
2856+
2857+
{
2858+
v8_flags.allow_natives_syntax =
2859+
true; // Flag change should trigger cache reject.
2860+
FlagList::EnforceFlagImplications();
2861+
v8::Isolate::CreateParams create_params;
2862+
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
2863+
v8::Isolate* isolate = v8::Isolate::New(create_params);
2864+
{
2865+
v8::Isolate::Scope iscope(isolate);
2866+
v8::ScriptCompiler::CachedData::CompatibilityCheckResult result =
2867+
cache->CompatibilityCheck(isolate);
2868+
CHECK_EQ(result, v8::ScriptCompiler::CachedData::kFlagsMismatch);
2869+
}
2870+
isolate->Dispose();
2871+
}
2872+
}
2873+
28022874
TEST(CodeSerializerBitFlip) {
28032875
i::v8_flags.verify_snapshot_checksum = true;
28042876
const char* js_source = "function f() { return 'abc'; }; f() + 'def'";

0 commit comments

Comments
 (0)