Skip to content

Commit f4b3f6e

Browse files
joyeecheungV8 LUCI CQ
authored andcommitted
[compiler] support isolate compilation cache in CompileFunction()
Previously there was no isolate compilation cache support for scripts compiled Script::CompileFunction() with wrapped arguments. This patch adds support for that. Refs: nodejs/node#35375 Change-Id: Id1849961ecd1282eb2dac95829157d167a3aa9a1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4962094 Reviewed-by: Camillo Bruni <[email protected]> Commit-Queue: Joyee Cheung <[email protected]> Cr-Commit-Position: refs/heads/main@{#91681}
1 parent 59acab8 commit f4b3f6e

9 files changed

Lines changed: 357 additions & 39 deletions

File tree

src/api/api.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2766,6 +2766,7 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInternal(
27662766
i_isolate, source->resource_name, source->resource_line_offset,
27672767
source->resource_column_offset, source->source_map_url,
27682768
source->host_defined_options, source->resource_options);
2769+
script_details.wrapped_arguments = arguments_list;
27692770

27702771
std::unique_ptr<i::AlignedCachedData> cached_data;
27712772
if (options == kConsumeCodeCache) {
@@ -2778,8 +2779,8 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInternal(
27782779
i::Handle<i::JSFunction> scoped_result;
27792780
has_exception =
27802781
!i::Compiler::GetWrappedFunction(
2781-
Utils::OpenHandle(*source->source_string), arguments_list, context,
2782-
script_details, cached_data.get(), options, no_cache_reason)
2782+
Utils::OpenHandle(*source->source_string), context, script_details,
2783+
cached_data.get(), options, no_cache_reason)
27832784
.ToHandle(&scoped_result);
27842785
if (options == kConsumeCodeCache) {
27852786
source->cached_data->rejected = cached_data->rejected();

src/codegen/compilation-cache.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ void CompilationCacheScript::Put(Handle<String> source,
189189
Handle<SharedFunctionInfo> function_info) {
190190
HandleScope scope(isolate());
191191
Handle<CompilationCacheTable> table = GetTable();
192-
table_ = *CompilationCacheTable::PutScript(table, source, function_info,
193-
isolate());
192+
table_ = *CompilationCacheTable::PutScript(table, source, kNullMaybeHandle,
193+
function_info, isolate());
194194
}
195195

196196
InfoCellPair CompilationCacheEval::Lookup(Handle<String> source,

src/codegen/compiler.cc

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,14 +3373,13 @@ struct ScriptCompileTimerScope {
33733373
}
33743374
};
33753375

3376-
Handle<Script> NewScript(
3377-
Isolate* isolate, ParseInfo* parse_info, Handle<String> source,
3378-
ScriptDetails script_details, NativesFlag natives,
3379-
MaybeHandle<FixedArray> maybe_wrapped_arguments = kNullMaybeHandle) {
3376+
Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
3377+
Handle<String> source, ScriptDetails script_details,
3378+
NativesFlag natives) {
33803379
// Create a script object describing the script to be compiled.
3381-
Handle<Script> script =
3382-
parse_info->CreateScript(isolate, source, maybe_wrapped_arguments,
3383-
script_details.origin_options, natives);
3380+
Handle<Script> script = parse_info->CreateScript(
3381+
isolate, source, script_details.wrapped_arguments,
3382+
script_details.origin_options, natives);
33843383
DisallowGarbageCollection no_gc;
33853384
SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
33863385
LOG(isolate, ScriptDetails(*script));
@@ -3790,9 +3789,8 @@ Compiler::GetSharedFunctionInfoForScriptWithCompileHints(
37903789

37913790
// static
37923791
MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
3793-
Handle<String> source, Handle<FixedArray> arguments,
3794-
Handle<Context> context, const ScriptDetails& script_details,
3795-
AlignedCachedData* cached_data,
3792+
Handle<String> source, Handle<Context> context,
3793+
const ScriptDetails& script_details, AlignedCachedData* cached_data,
37963794
v8::ScriptCompiler::CompileOptions compile_options,
37973795
v8::ScriptCompiler::NoCacheReason no_cache_reason) {
37983796
Isolate* isolate = context->GetIsolate();
@@ -3802,16 +3800,28 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
38023800

38033801
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
38043802
DCHECK(cached_data);
3803+
DCHECK_EQ(script_details.repl_mode, REPLMode::kNo);
38053804
} else {
38063805
DCHECK_NULL(cached_data);
38073806
}
38083807

38093808
LanguageMode language_mode = construct_language_mode(v8_flags.use_strict);
3810-
3809+
DCHECK(!script_details.wrapped_arguments.is_null());
38113810
MaybeHandle<SharedFunctionInfo> maybe_result;
3811+
Handle<SharedFunctionInfo> result;
3812+
Handle<Script> script;
3813+
IsCompiledScope is_compiled_scope;
38123814
bool can_consume_code_cache =
38133815
compile_options == ScriptCompiler::kConsumeCodeCache;
3814-
if (can_consume_code_cache) {
3816+
CompilationCache* compilation_cache = isolate->compilation_cache();
3817+
// First check per-isolate compilation cache.
3818+
CompilationCacheScript::LookupResult lookup_result =
3819+
compilation_cache->LookupScript(source, script_details, language_mode);
3820+
maybe_result = lookup_result.toplevel_sfi();
3821+
if (maybe_result.ToHandle(&result)) {
3822+
is_compiled_scope = result->is_compiled_scope(isolate);
3823+
compile_timer.set_hit_isolate_cache();
3824+
} else if (can_consume_code_cache) {
38153825
compile_timer.set_consuming_code_cache();
38163826
// Then check cached code provided by embedder.
38173827
NestedTimedHistogramScope timer(isolate->counters()->compile_deserialize());
@@ -3820,16 +3830,22 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
38203830
"V8.CompileDeserialize");
38213831
maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
38223832
script_details.origin_options);
3823-
if (maybe_result.is_null()) {
3833+
bool consuming_code_cache_succeeded = false;
3834+
if (maybe_result.ToHandle(&result)) {
3835+
is_compiled_scope = result->is_compiled_scope(isolate);
3836+
if (is_compiled_scope.is_compiled()) {
3837+
consuming_code_cache_succeeded = true;
3838+
// Promote to per-isolate compilation cache.
3839+
compilation_cache->PutScript(source, language_mode, result);
3840+
}
3841+
}
3842+
if (!consuming_code_cache_succeeded) {
38243843
// Deserializer failed. Fall through to compile.
38253844
compile_timer.set_consuming_code_cache_failed();
38263845
}
38273846
}
38283847

3829-
Handle<SharedFunctionInfo> wrapped;
3830-
Handle<Script> script;
3831-
IsCompiledScope is_compiled_scope;
3832-
if (!maybe_result.ToHandle(&wrapped)) {
3848+
if (maybe_result.is_null()) {
38333849
UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
38343850
isolate, true, language_mode, script_details.repl_mode,
38353851
ScriptType::kClassic, v8_flags.lazy);
@@ -3849,9 +3865,8 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
38493865
if (!IsNativeContext(*context)) {
38503866
maybe_outer_scope_info = handle(context->scope_info(), isolate);
38513867
}
3852-
38533868
script = NewScript(isolate, &parse_info, source, script_details,
3854-
NOT_NATIVES_CODE, arguments);
3869+
NOT_NATIVES_CODE);
38553870

38563871
Handle<SharedFunctionInfo> top_level;
38573872
maybe_result = v8::internal::CompileToplevel(&parse_info, script,
@@ -3864,18 +3879,23 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
38643879
for (Tagged<SharedFunctionInfo> info = infos.Next(); !info.is_null();
38653880
info = infos.Next()) {
38663881
if (info->is_wrapped()) {
3867-
wrapped = Handle<SharedFunctionInfo>(info, isolate);
3882+
result = Handle<SharedFunctionInfo>(info, isolate);
38683883
break;
38693884
}
38703885
}
3871-
DCHECK(!wrapped.is_null());
3872-
} else {
3873-
is_compiled_scope = wrapped->is_compiled_scope(isolate);
3874-
script = Handle<Script>(Script::cast(wrapped->script()), isolate);
3886+
DCHECK(!result.is_null());
3887+
3888+
is_compiled_scope = result->is_compiled_scope(isolate);
3889+
script = Handle<Script>(Script::cast(result->script()), isolate);
3890+
// Add the result to the isolate cache if there's no context extension.
3891+
if (maybe_outer_scope_info.is_null()) {
3892+
compilation_cache->PutScript(source, language_mode, result);
3893+
}
38753894
}
3895+
38763896
DCHECK(is_compiled_scope.is_compiled());
38773897

3878-
return Factory::JSFunctionBuilder{isolate, wrapped, context}
3898+
return Factory::JSFunctionBuilder{isolate, result, context}
38793899
.set_allocation_type(AllocationType::kYoung)
38803900
.Build();
38813901
}

src/codegen/compiler.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,8 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
161161
// Create a function that results from wrapping |source| in a function,
162162
// with |arguments| being a list of parameters for that function.
163163
V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
164-
Handle<String> source, Handle<FixedArray> arguments,
165-
Handle<Context> context, const ScriptDetails& script_details,
166-
AlignedCachedData* cached_data,
164+
Handle<String> source, Handle<Context> context,
165+
const ScriptDetails& script_details, AlignedCachedData* cached_data,
167166
v8::ScriptCompiler::CompileOptions compile_options,
168167
v8::ScriptCompiler::NoCacheReason no_cache_reason);
169168

src/codegen/script-details.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct ScriptDetails {
3030
MaybeHandle<Object> name_obj;
3131
MaybeHandle<Object> source_map_url;
3232
MaybeHandle<Object> host_defined_options;
33+
MaybeHandle<FixedArray> wrapped_arguments;
3334
REPLMode repl_mode;
3435
const ScriptOriginOptions origin_options;
3536
};

src/objects/compilation-cache-table-inl.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ class ScriptCacheKey : public HashTableKey {
6868
ScriptCacheKey(Handle<String> source, MaybeHandle<Object> name,
6969
int line_offset, int column_offset,
7070
v8::ScriptOriginOptions origin_options,
71-
MaybeHandle<Object> host_defined_options, Isolate* isolate);
71+
MaybeHandle<Object> host_defined_options,
72+
MaybeHandle<FixedArray> maybe_wrapped_arguments,
73+
Isolate* isolate);
7274

7375
bool IsMatch(Tagged<Object> other) override;
74-
bool MatchesOrigin(Tagged<Script> script);
76+
bool MatchesScript(Tagged<Script> script);
7577

7678
Handle<Object> AsHandle(Isolate* isolate, Handle<SharedFunctionInfo> shared);
7779

@@ -100,6 +102,7 @@ class ScriptCacheKey : public HashTableKey {
100102
int column_offset_;
101103
v8::ScriptOriginOptions origin_options_;
102104
MaybeHandle<Object> host_defined_options_;
105+
MaybeHandle<FixedArray> wrapped_arguments_;
103106
Isolate* isolate_;
104107
};
105108

src/objects/compilation-cache-table.cc

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ Tagged<Smi> ScriptHash(Tagged<String> source, MaybeHandle<Object> maybe_name,
246246
// We only re-use a cached function for some script source code if the
247247
// script originates from the same place. This is to avoid issues
248248
// when reporting errors, etc.
249-
bool ScriptCacheKey::MatchesOrigin(Tagged<Script> script) {
249+
bool ScriptCacheKey::MatchesScript(Tagged<Script> script) {
250250
DisallowGarbageCollection no_gc;
251251

252252
// If the script name isn't set, the boilerplate script should have
@@ -270,6 +270,30 @@ bool ScriptCacheKey::MatchesOrigin(Tagged<Script> script) {
270270
return false;
271271
}
272272

273+
Handle<FixedArray> wrapped_arguments_handle;
274+
if (wrapped_arguments_.ToHandle(&wrapped_arguments_handle)) {
275+
if (!script->is_wrapped()) {
276+
return false;
277+
}
278+
Tagged<FixedArray> wrapped_arguments = *wrapped_arguments_handle;
279+
Tagged<FixedArray> other_wrapped_arguments = script->wrapped_arguments();
280+
int length = wrapped_arguments->length();
281+
if (length != other_wrapped_arguments->length()) {
282+
return false;
283+
}
284+
for (int i = 0; i < length; i++) {
285+
Tagged<Object> arg = wrapped_arguments->get(i);
286+
Tagged<Object> other_arg = other_wrapped_arguments->get(i);
287+
DCHECK(IsString(arg));
288+
DCHECK(IsString(other_arg));
289+
if (!String::cast(arg)->Equals(String::cast(other_arg))) {
290+
return false;
291+
}
292+
}
293+
} else if (script->is_wrapped()) {
294+
return false;
295+
}
296+
273297
// Don't compare host options if the script was deserialized because we didn't
274298
// serialize host options (see CodeSerializer::SerializeObjectImpl())
275299
if (script->deserialized() &&
@@ -307,12 +331,14 @@ ScriptCacheKey::ScriptCacheKey(Handle<String> source,
307331
: ScriptCacheKey(source, script_details->name_obj,
308332
script_details->line_offset, script_details->column_offset,
309333
script_details->origin_options,
310-
script_details->host_defined_options, isolate) {}
334+
script_details->host_defined_options,
335+
script_details->wrapped_arguments, isolate) {}
311336

312337
ScriptCacheKey::ScriptCacheKey(Handle<String> source, MaybeHandle<Object> name,
313338
int line_offset, int column_offset,
314339
v8::ScriptOriginOptions origin_options,
315340
MaybeHandle<Object> host_defined_options,
341+
MaybeHandle<FixedArray> maybe_wrapped_arguments,
316342
Isolate* isolate)
317343
: HashTableKey(static_cast<uint32_t>(ScriptHash(*source, name, line_offset,
318344
column_offset,
@@ -324,8 +350,19 @@ ScriptCacheKey::ScriptCacheKey(Handle<String> source, MaybeHandle<Object> name,
324350
column_offset_(column_offset),
325351
origin_options_(origin_options),
326352
host_defined_options_(host_defined_options),
353+
wrapped_arguments_(maybe_wrapped_arguments),
327354
isolate_(isolate) {
328355
DCHECK(Smi::IsValid(static_cast<int>(Hash())));
356+
#ifdef DEBUG
357+
Handle<FixedArray> wrapped_arguments;
358+
if (maybe_wrapped_arguments.ToHandle(&wrapped_arguments)) {
359+
int length = wrapped_arguments->length();
360+
for (int i = 0; i < length; i++) {
361+
Tagged<Object> arg = wrapped_arguments->get(i);
362+
DCHECK(IsString(arg));
363+
}
364+
}
365+
#endif
329366
}
330367

331368
bool ScriptCacheKey::IsMatch(Tagged<Object> other) {
@@ -347,7 +384,8 @@ bool ScriptCacheKey::IsMatch(Tagged<Object> other) {
347384
}
348385
Tagged<Script> other_script = Script::cast(other_script_object);
349386
Tagged<String> other_source = String::cast(other_script->source());
350-
return other_source->Equals(*source_) && MatchesOrigin(other_script);
387+
388+
return other_source->Equals(*source_) && MatchesScript(other_script);
351389
}
352390

353391
Handle<Object> ScriptCacheKey::AsHandle(Isolate* isolate,
@@ -474,6 +512,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::EnsureScriptTableCapacity(
474512

475513
Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
476514
Handle<CompilationCacheTable> cache, Handle<String> src,
515+
MaybeHandle<FixedArray> maybe_wrapped_arguments,
477516
Handle<SharedFunctionInfo> value, Isolate* isolate) {
478517
src = String::Flatten(isolate, src);
479518
Handle<Script> script = handle(Script::cast(value->script()), isolate);
@@ -485,7 +524,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
485524
isolate);
486525
ScriptCacheKey key(src, script_name, script->line_offset(),
487526
script->column_offset(), script->origin_options(),
488-
host_defined_options, isolate);
527+
host_defined_options, maybe_wrapped_arguments, isolate);
489528
Handle<Object> k = key.AsHandle(isolate, value);
490529

491530
// Check whether there is already a matching entry. If so, we must overwrite

src/objects/compilation-cache-table.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class CompilationCacheTable
121121
const ScriptDetails& script_details, Isolate* isolate);
122122
static Handle<CompilationCacheTable> PutScript(
123123
Handle<CompilationCacheTable> cache, Handle<String> src,
124+
MaybeHandle<FixedArray> maybe_wrapped_arguments,
124125
Handle<SharedFunctionInfo> value, Isolate* isolate);
125126

126127
// Eval code only gets cached after a second probe for the

0 commit comments

Comments
 (0)