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.

PR-URL: https://github.com/nodejs/node/pull/49108
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Joyee Cheung 2023-08-17 19:24:46 +02:00 committed by GitHub
parent 4c3db74a39
commit fe219e0438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 22 deletions

View File

@ -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);
@ -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,
@ -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.
@ -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;
}
@ -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;

View File

@ -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,