Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
bootstrap: do not generate code cache in an unfinalized isolate
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.
  • Loading branch information
joyeecheung committed Aug 15, 2023
commit c35a69a0db71ea038599cd3daa1408b5faac3552
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