Skip to content

Commit

Permalink
bootstrap: do not generate code cache in an unfinalized isolate
Browse files Browse the repository at this point in the history
V8 now no longer supports serializing code cache in an isolate
with unfinalized read-only space. So guard the code cache regeneration
with the `is_building_snapshot()` flag. When the isolate is created
for snapshot generation, the code cache is going to be serialized
separately anyway, so there is no need to do it in the builtin loader.

PR-URL: #49108
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
  • Loading branch information
joyeecheung authored and UlisesGascon committed Sep 10, 2023
1 parent 11c85ff commit af6dc17
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 22 deletions.
53 changes: 32 additions & 21 deletions src/node_builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal(
Local<Context> context,
const char* id,
std::vector<Local<String>>* parameters,
BuiltinLoader::Result* result) {
Realm* optional_realm) {
Isolate* isolate = context->GetIsolate();
EscapableHandleScope scope(isolate);

Expand Down Expand Up @@ -320,9 +320,13 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal(
// will never be in any of these two sets, but the two sets are only for
// testing anyway.

*result = (has_cache && !script_source.GetCachedData()->rejected)
? Result::kWithCache
: Result::kWithoutCache;
Result result = (has_cache && !script_source.GetCachedData()->rejected)
? Result::kWithCache
: Result::kWithoutCache;
if (optional_realm != nullptr) {
DCHECK_EQ(this, optional_realm->env()->builtin_loader());
RecordResult(id, result, optional_realm);
}

if (has_cache) {
per_process::Debug(DebugCategory::CODE_CACHE,
Expand All @@ -336,28 +340,35 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal(
: "is accepted");
}

if (*result == Result::kWithoutCache) {
if (result == Result::kWithoutCache && optional_realm != nullptr &&
!optional_realm->env()->isolate_data()->is_building_snapshot()) {
// We failed to accept this cache, maybe because it was rejected, maybe
// because it wasn't present. Either way, we'll attempt to replace this
// code cache info with a new one.
std::shared_ptr<ScriptCompiler::CachedData> new_cached_data(
ScriptCompiler::CreateCodeCacheForFunction(fun));
CHECK_NOT_NULL(new_cached_data);

{
RwLock::ScopedLock lock(code_cache_->mutex);
code_cache_->map.insert_or_assign(
id, BuiltinCodeCacheData(std::move(new_cached_data)));
}
// This is only done when the isolate is not being serialized because
// V8 does not support serializing code cache with an unfinalized read-only
// space (which is what isolates pending to be serialized have).
SaveCodeCache(id, fun);
}

return scope.Escape(fun);
}

void BuiltinLoader::SaveCodeCache(const char* id, Local<Function> fun) {
std::shared_ptr<ScriptCompiler::CachedData> new_cached_data(
ScriptCompiler::CreateCodeCacheForFunction(fun));
CHECK_NOT_NULL(new_cached_data);

{
RwLock::ScopedLock lock(code_cache_->mutex);
code_cache_->map.insert_or_assign(
id, BuiltinCodeCacheData(std::move(new_cached_data)));
}
}

MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
const char* id,
Realm* optional_realm) {
Result result;
std::vector<Local<String>> parameters;
Isolate* isolate = context->GetIsolate();
// Detects parameters of the scripts based on module ids.
Expand Down Expand Up @@ -403,11 +414,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
}

MaybeLocal<Function> maybe =
LookupAndCompileInternal(context, id, &parameters, &result);
if (optional_realm != nullptr) {
DCHECK_EQ(this, optional_realm->env()->builtin_loader());
RecordResult(id, result, optional_realm);
}
LookupAndCompileInternal(context, id, &parameters, optional_realm);
return maybe;
}

Expand Down Expand Up @@ -483,13 +490,17 @@ bool BuiltinLoader::CompileAllBuiltins(Local<Context> context) {
continue;
}
v8::TryCatch bootstrapCatch(context->GetIsolate());
USE(LookupAndCompile(context, id.data(), nullptr));
auto fn = LookupAndCompile(context, id.data(), nullptr);
if (bootstrapCatch.HasCaught()) {
per_process::Debug(DebugCategory::CODE_CACHE,
"Failed to compile code cache for %s\n",
id.data());
all_succeeded = false;
PrintCaughtException(context->GetIsolate(), context, bootstrapCatch);
} else {
// This is used by the snapshot builder, so save the code cache
// unconditionally.
SaveCodeCache(id.data(), fn.ToLocalChecked());
}
}
return all_succeeded;
Expand Down
3 changes: 2 additions & 1 deletion src/node_builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
v8::Local<v8::Context> context,
const char* id,
std::vector<v8::Local<v8::String>>* parameters,
Result* result);
Realm* optional_realm);
void SaveCodeCache(const char* id, v8::Local<v8::Function> fn);

static void RecordResult(const char* id,
BuiltinLoader::Result result,
Expand Down

0 comments on commit af6dc17

Please sign in to comment.