From af6dc1754d4abe9656f7111bee464ac5465430e0 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 17 Aug 2023 19:24:46 +0200 Subject: [PATCH] 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 Reviewed-By: Yagiz Nizipli --- src/node_builtins.cc | 53 ++++++++++++++++++++++++++------------------ src/node_builtins.h | 3 ++- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/node_builtins.cc b/src/node_builtins.cc index d78ad3dd811432..84815969b6d1fa 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -254,7 +254,7 @@ MaybeLocal BuiltinLoader::LookupAndCompileInternal( Local context, const char* id, std::vector>* parameters, - BuiltinLoader::Result* result) { + Realm* optional_realm) { Isolate* isolate = context->GetIsolate(); EscapableHandleScope scope(isolate); @@ -320,9 +320,13 @@ MaybeLocal 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 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 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 fun) { + std::shared_ptr 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 BuiltinLoader::LookupAndCompile(Local context, const char* id, Realm* optional_realm) { - Result result; std::vector> parameters; Isolate* isolate = context->GetIsolate(); // Detects parameters of the scripts based on module ids. @@ -403,11 +414,7 @@ MaybeLocal BuiltinLoader::LookupAndCompile(Local context, } MaybeLocal maybe = - LookupAndCompileInternal(context, id, ¶meters, &result); - if (optional_realm != nullptr) { - DCHECK_EQ(this, optional_realm->env()->builtin_loader()); - RecordResult(id, result, optional_realm); - } + LookupAndCompileInternal(context, id, ¶meters, optional_realm); return maybe; } @@ -483,13 +490,17 @@ bool BuiltinLoader::CompileAllBuiltins(Local 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; diff --git a/src/node_builtins.h b/src/node_builtins.h index f91c2a8105bfe5..9f2fbc1e539374 100644 --- a/src/node_builtins.h +++ b/src/node_builtins.h @@ -147,7 +147,8 @@ class NODE_EXTERN_PRIVATE BuiltinLoader { v8::Local context, const char* id, std::vector>* parameters, - Result* result); + Realm* optional_realm); + void SaveCodeCache(const char* id, v8::Local fn); static void RecordResult(const char* id, BuiltinLoader::Result result,