Skip to content

Commit e2c47cd

Browse files
addaleaxRafaelGSS
authored andcommitted
src: make BuiltinLoader threadsafe and non-global
As discussed in #45888, using a global `BuiltinLoader` instance is probably undesirable in a world in which embedders are able to create Node.js Environments with different sources and therefore mutually incompatible code caching properties. This PR makes it so that `BuiltinLoader` is no longer a global singleton and instead only shared between `Environment`s that have a direct relation to each other, and addresses a few thread safety issues along with that. PR-URL: #45942 Reviewed-By: Joyee Cheung <[email protected]>
1 parent bbf9da8 commit e2c47cd

15 files changed

+347
-173
lines changed

src/api/environment.cc

+10-3
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ MaybeLocal<Value> LoadEnvironment(
473473
return LoadEnvironment(
474474
env, [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
475475
std::string name = "embedder_main_" + std::to_string(env->thread_id());
476-
builtins::BuiltinLoader::Add(name.c_str(), main_script_source_utf8);
476+
env->builtin_loader()->Add(name.c_str(), main_script_source_utf8);
477477
Realm* realm = env->principal_realm();
478478

479479
return realm->ExecuteBootstrapper(name.c_str());
@@ -714,10 +714,17 @@ Maybe<bool> InitializePrimordials(Local<Context> context) {
714714
"internal/per_context/messageport",
715715
nullptr};
716716

717+
// We do not have access to a per-Environment BuiltinLoader instance
718+
// at this point, because this code runs before an Environment exists
719+
// in the first place. However, creating BuiltinLoader instances is
720+
// relatively cheap and all the scripts that we may want to run at
721+
// startup are always present in it.
722+
thread_local builtins::BuiltinLoader builtin_loader;
717723
for (const char** module = context_files; *module != nullptr; module++) {
718724
Local<Value> arguments[] = {exports, primordials};
719-
if (builtins::BuiltinLoader::CompileAndCall(
720-
context, *module, arraysize(arguments), arguments, nullptr)
725+
if (builtin_loader
726+
.CompileAndCall(
727+
context, *module, arraysize(arguments), arguments, nullptr)
721728
.IsEmpty()) {
722729
// Execution failed during context creation.
723730
return Nothing<bool>();

src/env-inl.h

+4
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,10 @@ inline std::vector<double>* Environment::destroy_async_id_list() {
430430
return &destroy_async_id_list_;
431431
}
432432

433+
inline builtins::BuiltinLoader* Environment::builtin_loader() {
434+
return &builtin_loader_;
435+
}
436+
433437
inline double Environment::new_async_id() {
434438
async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
435439
return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];

src/env.cc

+9
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,15 @@ Environment::Environment(IsolateData* isolate_data,
674674
thread_id_(thread_id.id == static_cast<uint64_t>(-1)
675675
? AllocateEnvironmentThreadId().id
676676
: thread_id.id) {
677+
#ifdef NODE_V8_SHARED_RO_HEAP
678+
if (!is_main_thread()) {
679+
CHECK_NOT_NULL(isolate_data->worker_context());
680+
// TODO(addaleax): Adjust for the embedder API snapshot support changes
681+
builtin_loader()->CopySourceAndCodeCacheReferenceFrom(
682+
isolate_data->worker_context()->env()->builtin_loader());
683+
}
684+
#endif
685+
677686
// We'll be creating new objects so make sure we've entered the context.
678687
HandleScope handle_scope(isolate);
679688

src/env.h

+4
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ class Environment : public MemoryRetainer {
719719
// List of id's that have been destroyed and need the destroy() cb called.
720720
inline std::vector<double>* destroy_async_id_list();
721721

722+
builtins::BuiltinLoader* builtin_loader();
723+
722724
std::unordered_multimap<int, loader::ModuleWrap*> hash_to_module_map;
723725
std::unordered_map<uint32_t, loader::ModuleWrap*> id_to_module_map;
724726
std::unordered_map<uint32_t, contextify::ContextifyScript*>
@@ -1134,6 +1136,8 @@ class Environment : public MemoryRetainer {
11341136

11351137
std::unique_ptr<Realm> principal_realm_ = nullptr;
11361138

1139+
builtins::BuiltinLoader builtin_loader_;
1140+
11371141
// Used by allocate_managed_buffer() and release_managed_buffer() to keep
11381142
// track of the BackingStore for a given pointer.
11391143
std::unordered_map<char*, std::unique_ptr<v8::BackingStore>>

src/node.cc

-5
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,6 @@
126126

127127
namespace node {
128128

129-
using builtins::BuiltinLoader;
130-
131129
using v8::EscapableHandleScope;
132130
using v8::Isolate;
133131
using v8::Local;
@@ -1183,9 +1181,6 @@ ExitCode LoadSnapshotDataAndRun(const SnapshotData** snapshot_data_ptr,
11831181
}
11841182
}
11851183

1186-
if ((*snapshot_data_ptr) != nullptr) {
1187-
BuiltinLoader::RefreshCodeCache((*snapshot_data_ptr)->code_cache);
1188-
}
11891184
NodeMainInstance main_instance(*snapshot_data_ptr,
11901185
uv_default_loop(),
11911186
per_process::v8_platform.Platform(),

src/node_binding.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -631,13 +631,13 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
631631
CHECK(exports->SetPrototype(context, Null(isolate)).FromJust());
632632
DefineConstants(isolate, exports);
633633
} else if (!strcmp(*module_v, "natives")) {
634-
exports = builtins::BuiltinLoader::GetSourceObject(context);
634+
exports = realm->env()->builtin_loader()->GetSourceObject(context);
635635
// Legacy feature: process.binding('natives').config contains stringified
636636
// config.gypi
637637
CHECK(exports
638638
->Set(context,
639639
realm->isolate_data()->config_string(),
640-
builtins::BuiltinLoader::GetConfigString(isolate))
640+
realm->env()->builtin_loader()->GetConfigString(isolate))
641641
.FromJust());
642642
} else {
643643
return THROW_ERR_INVALID_MODULE(isolate, "No such binding: %s", *module_v);

0 commit comments

Comments
 (0)