Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChengzhong Wu <legendecas@gmail.com>2022-08-31 17:41:42 +0300
committerGitHub <noreply@github.com>2022-08-31 17:41:42 +0300
commit81d9cdb8cd5109f1beadf78558ff9e37b4c63473 (patch)
tree4e1a457a544f18539ac0087c52cb5720ee8ef83e /src
parentad3c7bcb033ef98fe3452182c7e43727de069949 (diff)
src: introduce node::Realm
To distinguish per-context values from the node::Environment, split those values to a new node::Realm structure and consolidate bootstrapping methods with it. PR-URL: https://github.com/nodejs/node/pull/44179 Refs: https://github.com/nodejs/node/issues/42528 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/api/environment.cc11
-rw-r--r--src/base_object-inl.h6
-rw-r--r--src/base_object.h5
-rw-r--r--src/env-inl.h37
-rw-r--r--src/env.cc209
-rw-r--r--src/env.h488
-rw-r--r--src/env_properties.h433
-rw-r--r--src/node.cc156
-rw-r--r--src/node_context_data.h7
-rw-r--r--src/node_contextify.cc2
-rw-r--r--src/node_internals.h4
-rw-r--r--src/node_main_instance.cc4
-rw-r--r--src/node_process.h3
-rw-r--r--src/node_process_object.cc22
-rw-r--r--src/node_realm-inl.h62
-rw-r--r--src/node_realm.cc308
-rw-r--r--src/node_realm.h100
-rw-r--r--src/node_snapshotable.cc95
-rw-r--r--src/node_snapshotable.h8
19 files changed, 1131 insertions, 829 deletions
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 53581405bac..9049b4617b9 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -5,6 +5,7 @@
#include "node_internals.h"
#include "node_options-inl.h"
#include "node_platform.h"
+#include "node_realm-inl.h"
#include "node_shadow_realm.h"
#include "node_v8_platform-inl.h"
#include "node_wasm_web_api.h"
@@ -378,7 +379,7 @@ Environment* CreateEnvironment(
}
#endif
- if (env->RunBootstrapping().IsEmpty()) {
+ if (env->principal_realm()->RunBootstrapping().IsEmpty()) {
FreeEnvironment(env);
return nullptr;
}
@@ -453,11 +454,13 @@ MaybeLocal<Value> LoadEnvironment(
builtins::BuiltinLoader::Add(
name.c_str(), UnionBytes(**main_utf16, main_utf16->length()));
env->set_main_utf16(std::move(main_utf16));
+ Realm* realm = env->principal_realm();
+
// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
- std::vector<Local<Value>> args = {env->process_object(),
- env->builtin_module_require()};
- return ExecuteBootstrapper(env, name.c_str(), &args);
+ std::vector<Local<Value>> args = {realm->process_object(),
+ realm->builtin_module_require()};
+ return realm->ExecuteBootstrapper(name.c_str(), &args);
});
}
diff --git a/src/base_object-inl.h b/src/base_object-inl.h
index a246c2502b4..ceb7a7f4a65 100644
--- a/src/base_object-inl.h
+++ b/src/base_object-inl.h
@@ -32,6 +32,12 @@
namespace node {
+// static
+v8::Local<v8::FunctionTemplate> BaseObject::GetConstructorTemplate(
+ Environment* env) {
+ return BaseObject::GetConstructorTemplate(env->isolate_data());
+}
+
void BaseObject::Detach() {
CHECK_GT(pointer_data()->strong_ptr_count, 0);
pointer_data()->is_detached = true;
diff --git a/src/base_object.h b/src/base_object.h
index 6f072bf5ec0..e12c9b5d1e4 100644
--- a/src/base_object.h
+++ b/src/base_object.h
@@ -31,6 +31,7 @@
namespace node {
class Environment;
+class IsolateData;
template <typename T, bool kIsWeak>
class BaseObjectPtrImpl;
@@ -111,8 +112,10 @@ class BaseObject : public MemoryRetainer {
// a BaseObjectPtr to this object.
inline void Detach();
- static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
+ static inline v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
+ static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
+ IsolateData* isolate_data);
// Interface for transferring BaseObject instances using the .postMessage()
// method of MessagePorts (and, by extension, Workers).
diff --git a/src/env-inl.h b/src/env-inl.h
index 428e517aedb..28fb3fda0db 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -31,6 +31,7 @@
#include "node_context_data.h"
#include "node_internals.h"
#include "node_perf_common.h"
+#include "node_realm-inl.h"
#include "util-inl.h"
#include "uv.h"
#include "v8.h"
@@ -614,15 +615,7 @@ inline void Environment::set_can_call_into_js(bool can_call_into_js) {
}
inline bool Environment::has_run_bootstrapping_code() const {
- return has_run_bootstrapping_code_;
-}
-
-inline void Environment::DoneBootstrapping() {
- has_run_bootstrapping_code_ = true;
- // This adjusts the return value of base_object_created_after_bootstrap() so
- // that tests that check the count do not have to account for internally
- // created BaseObjects.
- base_object_created_by_bootstrap_ = base_object_count_;
+ return principal_realm_->has_run_bootstrapping_code();
}
inline bool Environment::has_serialized_options() const {
@@ -830,14 +823,18 @@ void Environment::modify_base_object_count(int64_t delta) {
base_object_count_ += delta;
}
-int64_t Environment::base_object_created_after_bootstrap() const {
- return base_object_count_ - base_object_created_by_bootstrap_;
-}
-
int64_t Environment::base_object_count() const {
return base_object_count_;
}
+inline void Environment::set_base_object_created_by_bootstrap(int64_t count) {
+ base_object_created_by_bootstrap_ = base_object_count_;
+}
+
+int64_t Environment::base_object_created_after_bootstrap() const {
+ return base_object_count_ - base_object_created_by_bootstrap_;
+}
+
void Environment::set_main_utf16(std::unique_ptr<v8::String::Value> str) {
CHECK(!main_utf16_);
main_utf16_ = std::move(str);
@@ -902,16 +899,22 @@ void Environment::set_process_exit_handler(
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
- return PersistentToLocal::Strong(PropertyName##_); \
+ DCHECK_NOT_NULL(principal_realm_); \
+ return principal_realm_->PropertyName(); \
} \
inline void Environment::set_##PropertyName(v8::Local<TypeName> value) { \
- PropertyName##_.Reset(isolate(), value); \
+ DCHECK_NOT_NULL(principal_realm_); \
+ principal_realm_->set_##PropertyName(value); \
}
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
#undef V
v8::Local<v8::Context> Environment::context() const {
- return PersistentToLocal::Strong(context_);
+ return principal_realm()->context();
+}
+
+Realm* Environment::principal_realm() const {
+ return principal_realm_.get();
}
} // namespace node
diff --git a/src/env.cc b/src/env.cc
index 9bc9346e653..9d3602d24aa 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -445,6 +445,12 @@ void IsolateData::CreateProperties() {
#undef V
// TODO(legendecas): eagerly create per isolate templates.
+ Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
+ templ->InstanceTemplate()->SetInternalFieldCount(
+ BaseObject::kInternalFieldCount);
+ templ->Inherit(BaseObject::GetConstructorTemplate(this));
+ set_binding_data_ctor_template(templ);
+
set_contextify_global_template(
contextify::ContextifyContext::CreateGlobalTemplate(isolate_));
}
@@ -499,6 +505,10 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
return;
}
+ if (env_->principal_realm() == nullptr) {
+ return;
+ }
+
bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
@@ -514,9 +524,11 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
}
void Environment::AssignToContext(Local<v8::Context> context,
+ Realm* realm,
const ContextInfo& info) {
context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
this);
+ context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm);
// Used to retrieve bindings
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));
@@ -591,56 +603,6 @@ std::unique_ptr<v8::BackingStore> Environment::release_managed_buffer(
return bs;
}
-void Environment::CreateProperties() {
- HandleScope handle_scope(isolate_);
- Local<Context> ctx = context();
-
- {
- Context::Scope context_scope(ctx);
- Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
- templ->InstanceTemplate()->SetInternalFieldCount(
- BaseObject::kInternalFieldCount);
- templ->Inherit(BaseObject::GetConstructorTemplate(this));
-
- set_binding_data_ctor_template(templ);
- }
-
- // Store primordials setup by the per-context script in the environment.
- Local<Object> per_context_bindings =
- GetPerContextExports(ctx).ToLocalChecked();
- Local<Value> primordials =
- per_context_bindings->Get(ctx, primordials_string()).ToLocalChecked();
- CHECK(primordials->IsObject());
- set_primordials(primordials.As<Object>());
-
- Local<String> prototype_string =
- FIXED_ONE_BYTE_STRING(isolate(), "prototype");
-
-#define V(EnvPropertyName, PrimordialsPropertyName) \
- { \
- Local<Value> ctor = \
- primordials.As<Object>() \
- ->Get(ctx, \
- FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName)) \
- .ToLocalChecked(); \
- CHECK(ctor->IsObject()); \
- Local<Value> prototype = \
- ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked(); \
- CHECK(prototype->IsObject()); \
- set_##EnvPropertyName(prototype.As<Object>()); \
- }
-
- V(primordials_safe_map_prototype_object, "SafeMap");
- V(primordials_safe_set_prototype_object, "SafeSet");
- V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
- V(primordials_safe_weak_set_prototype_object, "SafeWeakSet");
-#undef V
-
- Local<Object> process_object =
- node::CreateProcessObject(this).FromMaybe(Local<Object>());
- set_process_object(process_object);
-}
-
std::string GetExecPath(const std::vector<std::string>& argv) {
char exec_path_buf[2 * PATH_MAX];
size_t exec_path_len = sizeof(exec_path_buf);
@@ -776,12 +738,11 @@ Environment::Environment(IsolateData* isolate_data,
void Environment::InitializeMainContext(Local<Context> context,
const EnvSerializeInfo* env_info) {
- context_.Reset(context->GetIsolate(), context);
- AssignToContext(context, ContextInfo(""));
+ principal_realm_ = std::make_unique<Realm>(
+ this, context, MAYBE_FIELD_PTR(env_info, principal_realm));
+ AssignToContext(context, principal_realm_.get(), ContextInfo(""));
if (env_info != nullptr) {
DeserializeProperties(env_info);
- } else {
- CreateProperties();
}
if (!options_->force_async_hooks_checks) {
@@ -806,6 +767,9 @@ void Environment::InitializeMainContext(Local<Context> context,
}
Environment::~Environment() {
+ HandleScope handle_scope(isolate());
+ Local<Context> ctx = context();
+
if (Environment** interrupt_data = interrupt_data_.load()) {
// There are pending RequestInterrupt() callbacks. Tell them not to run,
// then force V8 to run interrupts by compiling and running an empty script
@@ -813,9 +777,8 @@ Environment::~Environment() {
*interrupt_data = nullptr;
Isolate::AllowJavascriptExecutionScope allow_js_here(isolate());
- HandleScope handle_scope(isolate());
TryCatch try_catch(isolate());
- Context::Scope context_scope(context());
+ Context::Scope context_scope(ctx);
#ifdef DEBUG
bool consistency_check = false;
@@ -825,8 +788,8 @@ Environment::~Environment() {
#endif
Local<Script> script;
- if (Script::Compile(context(), String::Empty(isolate())).ToLocal(&script))
- USE(script->Run(context()));
+ if (Script::Compile(ctx, String::Empty(isolate())).ToLocal(&script))
+ USE(script->Run(ctx));
DCHECK(consistency_check);
}
@@ -842,16 +805,15 @@ Environment::~Environment() {
isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
BuildEmbedderGraph, this);
- HandleScope handle_scope(isolate());
-
#if HAVE_INSPECTOR
// Destroy inspector agent before erasing the context. The inspector
// destructor depends on the context still being accessible.
inspector_agent_.reset();
#endif
- context()->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
- nullptr);
+ ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
+ nullptr);
+ ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, nullptr);
if (trace_state_observer_) {
tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
@@ -1690,81 +1652,14 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
info.should_abort_on_uncaught_toggle =
should_abort_on_uncaught_toggle_.Serialize(ctx, creator);
- uint32_t id = 0;
-#define V(PropertyName, TypeName) \
- do { \
- Local<TypeName> field = PropertyName(); \
- if (!field.IsEmpty()) { \
- size_t index = creator->AddData(ctx, field); \
- info.persistent_values.push_back({#PropertyName, id, index}); \
- } \
- id++; \
- } while (0);
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
-#undef V
-
// Do this after other creator->AddData() calls so that Snapshotable objects
// can use 0 to indicate that a SnapshotIndex is invalid.
SerializeSnapshotableObjects(this, creator, &info);
- info.context = creator->AddData(ctx, context());
+ info.principal_realm = principal_realm_->Serialize(creator);
return info;
}
-std::ostream& operator<<(std::ostream& output,
- const std::vector<PropInfo>& vec) {
- output << "{\n";
- for (const auto& info : vec) {
- output << " " << info << ",\n";
- }
- output << "}";
- return output;
-}
-
-std::ostream& operator<<(std::ostream& output, const PropInfo& info) {
- output << "{ \"" << info.name << "\", " << std::to_string(info.id) << ", "
- << std::to_string(info.index) << " }";
- return output;
-}
-
-std::ostream& operator<<(std::ostream& output,
- const std::vector<std::string>& vec) {
- output << "{\n";
- for (const auto& info : vec) {
- output << " \"" << info << "\",\n";
- }
- output << "}";
- return output;
-}
-
-std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
- output << "{\n"
- << "// -- native_objects begins --\n"
- << i.native_objects << ",\n"
- << "// -- native_objects ends --\n"
- << "// -- builtins begins --\n"
- << i.builtins << ",\n"
- << "// -- builtins ends --\n"
- << "// -- async_hooks begins --\n"
- << i.async_hooks << ",\n"
- << "// -- async_hooks ends --\n"
- << i.tick_info << ", // tick_info\n"
- << i.immediate_info << ", // immediate_info\n"
- << "// -- performance_state begins --\n"
- << i.performance_state << ",\n"
- << "// -- performance_state ends --\n"
- << i.exiting << ", // exiting\n"
- << i.stream_base_state << ", // stream_base_state\n"
- << i.should_abort_on_uncaught_toggle
- << ", // should_abort_on_uncaught_toggle\n"
- << "// -- persistent_values begins --\n"
- << i.persistent_values << ",\n"
- << "// -- persistent_values ends --\n"
- << i.context << ", // context\n"
- << "}";
- return output;
-}
-
void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb,
Local<Object> holder,
int index,
@@ -1802,44 +1697,12 @@ void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
stream_base_state_.Deserialize(ctx);
should_abort_on_uncaught_toggle_.Deserialize(ctx);
+ principal_realm_->DeserializeProperties(&info->principal_realm);
+
if (enabled_debug_list_.enabled(DebugCategory::MKSNAPSHOT)) {
fprintf(stderr, "deserializing...\n");
std::cerr << *info << "\n";
}
-
- const std::vector<PropInfo>& values = info->persistent_values;
- size_t i = 0; // index to the array
- uint32_t id = 0;
-#define V(PropertyName, TypeName) \
- do { \
- if (values.size() > i && id == values[i].id) { \
- const PropInfo& d = values[i]; \
- DCHECK_EQ(d.name, #PropertyName); \
- MaybeLocal<TypeName> maybe_field = \
- ctx->GetDataFromSnapshotOnce<TypeName>(d.index); \
- Local<TypeName> field; \
- if (!maybe_field.ToLocal(&field)) { \
- fprintf(stderr, \
- "Failed to deserialize environment value " #PropertyName \
- "\n"); \
- } \
- set_##PropertyName(field); \
- i++; \
- } \
- id++; \
- } while (0);
-
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V);
-#undef V
-
- MaybeLocal<Context> maybe_ctx_from_snapshot =
- ctx->GetDataFromSnapshotOnce<Context>(info->context);
- Local<Context> ctx_from_snapshot;
- if (!maybe_ctx_from_snapshot.ToLocal(&ctx_from_snapshot)) {
- fprintf(stderr,
- "Failed to deserialize context back reference from the snapshot\n");
- }
- CHECK_EQ(ctx_from_snapshot, ctx);
}
uint64_t GuessMemoryAvailableToTheProcess() {
@@ -2027,11 +1890,7 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("async_hooks", async_hooks_);
tracker->TrackField("immediate_info", immediate_info_);
tracker->TrackField("tick_info", tick_info_);
-
-#define V(PropertyName, TypeName) \
- tracker->TrackField(#PropertyName, PropertyName());
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
-#undef V
+ tracker->TrackField("principal_realm", principal_realm_);
// FIXME(joyeecheung): track other fields in Environment.
// Currently MemoryTracker is unable to track these
@@ -2180,12 +2039,14 @@ bool BaseObject::IsRootNode() const {
return !persistent_handle_.IsWeak();
}
-Local<FunctionTemplate> BaseObject::GetConstructorTemplate(Environment* env) {
- Local<FunctionTemplate> tmpl = env->base_object_ctor_template();
+Local<FunctionTemplate> BaseObject::GetConstructorTemplate(
+ IsolateData* isolate_data) {
+ Local<FunctionTemplate> tmpl = isolate_data->base_object_ctor_template();
if (tmpl.IsEmpty()) {
- tmpl = NewFunctionTemplate(env->isolate(), nullptr);
- tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "BaseObject"));
- env->set_base_object_ctor_template(tmpl);
+ tmpl = NewFunctionTemplate(isolate_data->isolate(), nullptr);
+ tmpl->SetClassName(
+ FIXED_ONE_BYTE_STRING(isolate_data->isolate(), "BaseObject"));
+ isolate_data->set_base_object_ctor_template(tmpl);
}
return tmpl;
}
diff --git a/src/env.h b/src/env.h
index 6f148dbd041..acbefe4a1c0 100644
--- a/src/env.h
+++ b/src/env.h
@@ -31,6 +31,7 @@
#endif
#include "callback_queue.h"
#include "debug_utils.h"
+#include "env_properties.h"
#include "handle_wrap.h"
#include "node.h"
#include "node_binding.h"
@@ -38,6 +39,7 @@
#include "node_main_instance.h"
#include "node_options.h"
#include "node_perf_common.h"
+#include "node_realm.h"
#include "node_snapshotable.h"
#include "req_wrap.h"
#include "util.h"
@@ -110,6 +112,9 @@ struct PackageConfig {
};
} // namespace loader
+class Environment;
+class Realm;
+
enum class FsStatsOffset {
kDev = 0,
kMode,
@@ -150,441 +155,6 @@ class NoArrayBufferZeroFillScope {
friend class Environment;
};
-// PER_ISOLATE_* macros: We have a lot of per-isolate properties
-// and adding and maintaining their getters and setters by hand would be
-// difficult so let's make the preprocessor generate them for us.
-//
-// In each macro, `V` is expected to be the name of a macro or function which
-// accepts the number of arguments provided in each tuple in the macro body,
-// typically two. The named function will be invoked against each tuple.
-//
-// Make sure that any macro V defined for use with the PER_ISOLATE_* macros is
-// undefined again after use.
-
-// Private symbols are per-isolate primitives but Environment proxies them
-// for the sake of convenience. Strings should be ASCII-only and have a
-// "node:" prefix to avoid name clashes with third-party code.
-#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
- V(alpn_buffer_private_symbol, "node:alpnBuffer") \
- V(arrow_message_private_symbol, "node:arrowMessage") \
- V(contextify_context_private_symbol, "node:contextify:context") \
- V(contextify_global_private_symbol, "node:contextify:global") \
- V(decorated_private_symbol, "node:decorated") \
- V(napi_type_tag, "node:napi:type_tag") \
- V(napi_wrapper, "node:napi:wrapper") \
- V(untransferable_object_private_symbol, "node:untransferableObject") \
- V(exiting_aliased_Uint32Array, "node:exiting_aliased_Uint32Array")
-
-// Symbols are per-isolate primitives but Environment proxies them
-// for the sake of convenience.
-#define PER_ISOLATE_SYMBOL_PROPERTIES(V) \
- V(async_id_symbol, "async_id_symbol") \
- V(handle_onclose_symbol, "handle_onclose") \
- V(no_message_symbol, "no_message_symbol") \
- V(messaging_deserialize_symbol, "messaging_deserialize_symbol") \
- V(messaging_transfer_symbol, "messaging_transfer_symbol") \
- V(messaging_clone_symbol, "messaging_clone_symbol") \
- V(messaging_transfer_list_symbol, "messaging_transfer_list_symbol") \
- V(oninit_symbol, "oninit") \
- V(owner_symbol, "owner_symbol") \
- V(onpskexchange_symbol, "onpskexchange") \
- V(resource_symbol, "resource_symbol") \
- V(trigger_async_id_symbol, "trigger_async_id_symbol") \
-
-// Strings are per-isolate primitives but Environment proxies them
-// for the sake of convenience. Strings should be ASCII-only.
-#define PER_ISOLATE_STRING_PROPERTIES(V) \
- V(ack_string, "ack") \
- V(address_string, "address") \
- V(aliases_string, "aliases") \
- V(args_string, "args") \
- V(asn1curve_string, "asn1Curve") \
- V(async_ids_stack_string, "async_ids_stack") \
- V(bits_string, "bits") \
- V(block_list_string, "blockList") \
- V(buffer_string, "buffer") \
- V(bytes_parsed_string, "bytesParsed") \
- V(bytes_read_string, "bytesRead") \
- V(bytes_written_string, "bytesWritten") \
- V(cached_data_produced_string, "cachedDataProduced") \
- V(cached_data_rejected_string, "cachedDataRejected") \
- V(cached_data_string, "cachedData") \
- V(cache_key_string, "cacheKey") \
- V(change_string, "change") \
- V(channel_string, "channel") \
- V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \
- V(clone_unsupported_type_str, "Cannot transfer object of unsupported type.") \
- V(code_string, "code") \
- V(commonjs_string, "commonjs") \
- V(config_string, "config") \
- V(constants_string, "constants") \
- V(crypto_dh_string, "dh") \
- V(crypto_dsa_string, "dsa") \
- V(crypto_ec_string, "ec") \
- V(crypto_ed25519_string, "ed25519") \
- V(crypto_ed448_string, "ed448") \
- V(crypto_x25519_string, "x25519") \
- V(crypto_x448_string, "x448") \
- V(crypto_rsa_string, "rsa") \
- V(crypto_rsa_pss_string, "rsa-pss") \
- V(cwd_string, "cwd") \
- V(data_string, "data") \
- V(default_is_true_string, "defaultIsTrue") \
- V(deserialize_info_string, "deserializeInfo") \
- V(dest_string, "dest") \
- V(destroyed_string, "destroyed") \
- V(detached_string, "detached") \
- V(dh_string, "DH") \
- V(divisor_length_string, "divisorLength") \
- V(dns_a_string, "A") \
- V(dns_aaaa_string, "AAAA") \
- V(dns_caa_string, "CAA") \
- V(dns_critical_string, "critical") \
- V(dns_cname_string, "CNAME") \
- V(dns_mx_string, "MX") \
- V(dns_naptr_string, "NAPTR") \
- V(dns_ns_string, "NS") \
- V(dns_ptr_string, "PTR") \
- V(dns_soa_string, "SOA") \
- V(dns_srv_string, "SRV") \
- V(dns_txt_string, "TXT") \
- V(done_string, "done") \
- V(duration_string, "duration") \
- V(ecdh_string, "ECDH") \
- V(emit_string, "emit") \
- V(emit_warning_string, "emitWarning") \
- V(empty_object_string, "{}") \
- V(encoding_string, "encoding") \
- V(entries_string, "entries") \
- V(entry_type_string, "entryType") \
- V(env_pairs_string, "envPairs") \
- V(env_var_settings_string, "envVarSettings") \
- V(errno_string, "errno") \
- V(error_string, "error") \
- V(exchange_string, "exchange") \
- V(exit_code_string, "exitCode") \
- V(expire_string, "expire") \
- V(exponent_string, "exponent") \
- V(exports_string, "exports") \
- V(ext_key_usage_string, "ext_key_usage") \
- V(external_stream_string, "_externalStream") \
- V(family_string, "family") \
- V(fatal_exception_string, "_fatalException") \
- V(fd_string, "fd") \
- V(fields_string, "fields") \
- V(file_string, "file") \
- V(filename_string, "filename") \
- V(fingerprint256_string, "fingerprint256") \
- V(fingerprint512_string, "fingerprint512") \
- V(fingerprint_string, "fingerprint") \
- V(flags_string, "flags") \
- V(flowlabel_string, "flowlabel") \
- V(fragment_string, "fragment") \
- V(frames_received_string, "framesReceived") \
- V(frames_sent_string, "framesSent") \
- V(function_string, "function") \
- V(get_data_clone_error_string, "_getDataCloneError") \
- V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
- V(gid_string, "gid") \
- V(h2_string, "h2") \
- V(handle_string, "handle") \
- V(hash_algorithm_string, "hashAlgorithm") \
- V(help_text_string, "helpText") \
- V(homedir_string, "homedir") \
- V(host_string, "host") \
- V(hostmaster_string, "hostmaster") \
- V(http_1_1_string, "http/1.1") \
- V(id_string, "id") \
- V(identity_string, "identity") \
- V(ignore_string, "ignore") \
- V(infoaccess_string, "infoAccess") \
- V(inherit_string, "inherit") \
- V(input_string, "input") \
- V(internal_binding_string, "internalBinding") \
- V(internal_string, "internal") \
- V(ipv4_string, "IPv4") \
- V(ipv6_string, "IPv6") \
- V(isclosing_string, "isClosing") \
- V(issuer_string, "issuer") \
- V(issuercert_string, "issuerCertificate") \
- V(jwk_crv_string, "crv") \
- V(jwk_d_string, "d") \
- V(jwk_dp_string, "dp") \
- V(jwk_dq_string, "dq") \
- V(jwk_dsa_string, "DSA") \
- V(jwk_e_string, "e") \
- V(jwk_ec_string, "EC") \
- V(jwk_g_string, "g") \
- V(jwk_k_string, "k") \
- V(jwk_p_string, "p") \
- V(jwk_q_string, "q") \
- V(jwk_qi_string, "qi") \
- V(jwk_kty_string, "kty") \
- V(jwk_n_string, "n") \
- V(jwk_oct_string, "oct") \
- V(jwk_okp_string, "OKP") \
- V(jwk_rsa_string, "RSA") \
- V(jwk_x_string, "x") \
- V(jwk_y_string, "y") \
- V(kill_signal_string, "killSignal") \
- V(kind_string, "kind") \
- V(length_string, "length") \
- V(library_string, "library") \
- V(mac_string, "mac") \
- V(max_buffer_string, "maxBuffer") \
- V(max_concurrent_streams_string, "maxConcurrentStreams") \
- V(message_port_constructor_string, "MessagePort") \
- V(message_port_string, "messagePort") \
- V(message_string, "message") \
- V(messageerror_string, "messageerror") \
- V(mgf1_hash_algorithm_string, "mgf1HashAlgorithm") \
- V(minttl_string, "minttl") \
- V(module_string, "module") \
- V(modulus_string, "modulus") \
- V(modulus_length_string, "modulusLength") \
- V(name_string, "name") \
- V(named_curve_string, "namedCurve") \
- V(netmask_string, "netmask") \
- V(next_string, "next") \
- V(nistcurve_string, "nistCurve") \
- V(node_string, "node") \
- V(nsname_string, "nsname") \
- V(object_string, "Object") \
- V(ocsp_request_string, "OCSPRequest") \
- V(oncertcb_string, "oncertcb") \
- V(onchange_string, "onchange") \
- V(onclienthello_string, "onclienthello") \
- V(oncomplete_string, "oncomplete") \
- V(onconnection_string, "onconnection") \
- V(ondone_string, "ondone") \
- V(onerror_string, "onerror") \
- V(onexit_string, "onexit") \
- V(onhandshakedone_string, "onhandshakedone") \
- V(onhandshakestart_string, "onhandshakestart") \
- V(onkeylog_string, "onkeylog") \
- V(onmessage_string, "onmessage") \
- V(onnewsession_string, "onnewsession") \
- V(onocspresponse_string, "onocspresponse") \
- V(onreadstart_string, "onreadstart") \
- V(onreadstop_string, "onreadstop") \
- V(onshutdown_string, "onshutdown") \
- V(onsignal_string, "onsignal") \
- V(onunpipe_string, "onunpipe") \
- V(onwrite_string, "onwrite") \
- V(openssl_error_stack, "opensslErrorStack") \
- V(options_string, "options") \
- V(order_string, "order") \
- V(output_string, "output") \
- V(overlapped_string, "overlapped") \
- V(parse_error_string, "Parse Error") \
- V(password_string, "password") \
- V(path_string, "path") \
- V(pending_handle_string, "pendingHandle") \
- V(pid_string, "pid") \
- V(ping_rtt_string, "pingRTT") \
- V(pipe_source_string, "pipeSource") \
- V(pipe_string, "pipe") \
- V(pipe_target_string, "pipeTarget") \
- V(port1_string, "port1") \
- V(port2_string, "port2") \
- V(port_string, "port") \
- V(preference_string, "preference") \
- V(primordials_string, "primordials") \
- V(priority_string, "priority") \
- V(process_string, "process") \
- V(promise_string, "promise") \
- V(psk_string, "psk") \
- V(pubkey_string, "pubkey") \
- V(public_exponent_string, "publicExponent") \
- V(query_string, "query") \
- V(rate_string, "rate") \
- V(raw_string, "raw") \
- V(read_host_object_string, "_readHostObject") \
- V(readable_string, "readable") \
- V(reason_string, "reason") \
- V(refresh_string, "refresh") \
- V(regexp_string, "regexp") \
- V(rename_string, "rename") \
- V(replacement_string, "replacement") \
- V(require_string, "require") \
- V(retry_string, "retry") \
- V(salt_length_string, "saltLength") \
- V(scheme_string, "scheme") \
- V(scopeid_string, "scopeid") \
- V(serial_number_string, "serialNumber") \
- V(serial_string, "serial") \
- V(servername_string, "servername") \
- V(service_string, "service") \
- V(session_id_string, "sessionId") \
- V(shell_string, "shell") \
- V(signal_string, "signal") \
- V(sink_string, "sink") \
- V(size_string, "size") \
- V(sni_context_err_string, "Invalid SNI context") \
- V(sni_context_string, "sni_context") \
- V(source_string, "source") \
- V(stack_string, "stack") \
- V(standard_name_string, "standardName") \
- V(start_time_string, "startTime") \
- V(state_string, "state") \
- V(stats_string, "stats") \
- V(status_string, "status") \
- V(stdio_string, "stdio") \
- V(stream_average_duration_string, "streamAverageDuration") \
- V(stream_count_string, "streamCount") \
- V(subject_string, "subject") \
- V(subjectaltname_string, "subjectaltname") \
- V(syscall_string, "syscall") \
- V(target_string, "target") \
- V(thread_id_string, "threadId") \
- V(ticketkeycallback_string, "onticketkeycallback") \
- V(timeout_string, "timeout") \
- V(time_to_first_byte_string, "timeToFirstByte") \
- V(time_to_first_byte_sent_string, "timeToFirstByteSent") \
- V(time_to_first_header_string, "timeToFirstHeader") \
- V(tls_ticket_string, "tlsTicket") \
- V(transfer_string, "transfer") \
- V(ttl_string, "ttl") \
- V(type_string, "type") \
- V(uid_string, "uid") \
- V(unknown_string, "<unknown>") \
- V(url_special_ftp_string, "ftp:") \
- V(url_special_file_string, "file:") \
- V(url_special_http_string, "http:") \
- V(url_special_https_string, "https:") \
- V(url_special_ws_string, "ws:") \
- V(url_special_wss_string, "wss:") \
- V(url_string, "url") \
- V(username_string, "username") \
- V(valid_from_string, "valid_from") \
- V(valid_to_string, "valid_to") \
- V(value_string, "value") \
- V(verify_error_string, "verifyError") \
- V(version_string, "version") \
- V(weight_string, "weight") \
- V(windows_hide_string, "windowsHide") \
- V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \
- V(wrap_string, "wrap") \
- V(writable_string, "writable") \
- V(write_host_object_string, "_writeHostObject") \
- V(write_queue_size_string, "writeQueueSize") \
- V(x_forwarded_string, "x-forwarded-for") \
- V(zero_return_string, "ZERO_RETURN")
-
-#define PER_ISOLATE_TEMPLATE_PROPERTIES(V) \
- V(async_wrap_ctor_template, v8::FunctionTemplate) \
- V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
- V(base_object_ctor_template, v8::FunctionTemplate) \
- V(binding_data_ctor_template, v8::FunctionTemplate) \
- V(blob_constructor_template, v8::FunctionTemplate) \
- V(blocklist_constructor_template, v8::FunctionTemplate) \
- V(contextify_global_template, v8::ObjectTemplate) \
- V(compiled_fn_entry_template, v8::ObjectTemplate) \
- V(dir_instance_template, v8::ObjectTemplate) \
- V(fd_constructor_template, v8::ObjectTemplate) \
- V(fdclose_constructor_template, v8::ObjectTemplate) \
- V(filehandlereadwrap_template, v8::ObjectTemplate) \
- V(fsreqpromise_constructor_template, v8::ObjectTemplate) \
- V(handle_wrap_ctor_template, v8::FunctionTemplate) \
- V(histogram_ctor_template, v8::FunctionTemplate) \
- V(http2settings_constructor_template, v8::ObjectTemplate) \
- V(http2stream_constructor_template, v8::ObjectTemplate) \
- V(http2ping_constructor_template, v8::ObjectTemplate) \
- V(i18n_converter_template, v8::ObjectTemplate) \
- V(intervalhistogram_constructor_template, v8::FunctionTemplate) \
- V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
- V(message_port_constructor_template, v8::FunctionTemplate) \
- V(microtask_queue_ctor_template, v8::FunctionTemplate) \
- V(pipe_constructor_template, v8::FunctionTemplate) \
- V(promise_wrap_template, v8::ObjectTemplate) \
- V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \
- V(script_context_constructor_template, v8::FunctionTemplate) \
- V(secure_context_constructor_template, v8::FunctionTemplate) \
- V(shutdown_wrap_template, v8::ObjectTemplate) \
- V(socketaddress_constructor_template, v8::FunctionTemplate) \
- V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
- V(qlogoutputstream_constructor_template, v8::ObjectTemplate) \
- V(tcp_constructor_template, v8::FunctionTemplate) \
- V(tty_constructor_template, v8::FunctionTemplate) \
- V(write_wrap_template, v8::ObjectTemplate) \
- V(worker_heap_snapshot_taker_template, v8::ObjectTemplate) \
- V(x509_constructor_template, v8::FunctionTemplate)
-
-#define ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \
- V(async_hooks_after_function, v8::Function) \
- V(async_hooks_before_function, v8::Function) \
- V(async_hooks_callback_trampoline, v8::Function) \
- V(async_hooks_binding, v8::Object) \
- V(async_hooks_destroy_function, v8::Function) \
- V(async_hooks_init_function, v8::Function) \
- V(async_hooks_promise_resolve_function, v8::Function) \
- V(buffer_prototype_object, v8::Object) \
- V(crypto_key_object_constructor, v8::Function) \
- V(crypto_key_object_handle_constructor, v8::Function) \
- V(crypto_key_object_private_constructor, v8::Function) \
- V(crypto_key_object_public_constructor, v8::Function) \
- V(crypto_key_object_secret_constructor, v8::Function) \
- V(domexception_function, v8::Function) \
- V(enhance_fatal_stack_after_inspector, v8::Function) \
- V(enhance_fatal_stack_before_inspector, v8::Function) \
- V(fs_use_promises_symbol, v8::Symbol) \
- V(get_source_map_error_source, v8::Function) \
- V(host_import_module_dynamically_callback, v8::Function) \
- V(host_initialize_import_meta_object_callback, v8::Function) \
- V(http2session_on_altsvc_function, v8::Function) \
- V(http2session_on_error_function, v8::Function) \
- V(http2session_on_frame_error_function, v8::Function) \
- V(http2session_on_goaway_data_function, v8::Function) \
- V(http2session_on_headers_function, v8::Function) \
- V(http2session_on_origin_function, v8::Function) \
- V(http2session_on_ping_function, v8::Function) \
- V(http2session_on_priority_function, v8::Function) \
- V(http2session_on_settings_function, v8::Function) \
- V(http2session_on_stream_close_function, v8::Function) \
- V(http2session_on_stream_trailers_function, v8::Function) \
- V(internal_binding_loader, v8::Function) \
- V(immediate_callback_function, v8::Function) \
- V(inspector_console_extension_installer, v8::Function) \
- V(inspector_disable_async_hooks, v8::Function) \
- V(inspector_enable_async_hooks, v8::Function) \
- V(maybe_cache_generated_source_map, v8::Function) \
- V(messaging_deserialize_create_object, v8::Function) \
- V(message_port, v8::Object) \
- V(builtin_module_require, v8::Function) \
- V(performance_entry_callback, v8::Function) \
- V(performance_entry_template, v8::Function) \
- V(prepare_stack_trace_callback, v8::Function) \
- V(process_object, v8::Object) \
- V(primordials, v8::Object) \
- V(primordials_safe_map_prototype_object, v8::Object) \
- V(primordials_safe_set_prototype_object, v8::Object) \
- V(primordials_safe_weak_map_prototype_object, v8::Object) \
- V(primordials_safe_weak_set_prototype_object, v8::Object) \
- V(promise_hook_handler, v8::Function) \
- V(promise_reject_callback, v8::Function) \
- V(snapshot_serialize_callback, v8::Function) \
- V(snapshot_deserialize_callback, v8::Function) \
- V(snapshot_deserialize_main, v8::Function) \
- V(source_map_cache_getter, v8::Function) \
- V(tick_callback_function, v8::Function) \
- V(timers_callback_function, v8::Function) \
- V(tls_wrap_constructor_function, v8::Function) \
- V(trace_category_state_function, v8::Function) \
- V(udp_constructor_function, v8::Function) \
- V(url_constructor_function, v8::Function) \
- V(wasm_streaming_compilation_impl, v8::Function) \
- V(wasm_streaming_object_constructor, v8::Function)
-
-class Environment;
-
-typedef size_t SnapshotIndex;
-
-struct PropInfo {
- std::string name; // name for debugging
- uint32_t id; // In the list - in case there are any empty entries
- SnapshotIndex index; // In the snapshot
-};
-
struct IsolateDataSerializeInfo {
std::vector<SnapshotIndex> primitive_values;
std::vector<PropInfo> template_values;
@@ -979,9 +549,7 @@ struct EnvSerializeInfo {
AliasedBufferIndex stream_base_state;
AliasedBufferIndex should_abort_on_uncaught_toggle;
- std::vector<PropInfo> persistent_values;
-
- SnapshotIndex context;
+ RealmSerializeInfo principal_realm;
friend std::ostream& operator<<(std::ostream& o, const EnvSerializeInfo& i);
};
@@ -1041,6 +609,11 @@ struct SnapshotData {
SnapshotData() = default;
};
+/**
+ * Environment is a per-isolate data structure that represents an execution
+ * environment. Each environment has a principal realm. An environment can
+ * create multiple subsidiary synthetic realms.
+ */
class Environment : public MemoryRetainer {
public:
Environment(const Environment&) = delete;
@@ -1055,7 +628,6 @@ class Environment : public MemoryRetainer {
void MemoryInfo(MemoryTracker* tracker) const override;
EnvSerializeInfo Serialize(v8::SnapshotCreator* creator);
- void CreateProperties();
void DeserializeProperties(const EnvSerializeInfo* info);
void PrintInfoForSnapshotIfDebug();
@@ -1078,10 +650,6 @@ class Environment : public MemoryRetainer {
std::unique_ptr<inspector::ParentInspectorHandle> parent_handle);
#endif
- v8::MaybeLocal<v8::Value> BootstrapInternalLoaders();
- v8::MaybeLocal<v8::Value> BootstrapNode();
- v8::MaybeLocal<v8::Value> RunBootstrapping();
-
inline size_t async_callback_scope_depth() const;
inline void PushAsyncCallbackScope();
inline void PopAsyncCallbackScope();
@@ -1125,7 +693,7 @@ class Environment : public MemoryRetainer {
ThreadId thread_id);
void InitializeMainContext(v8::Local<v8::Context> context,
const EnvSerializeInfo* env_info);
- // Create an Environment and initialize the provided main context for it.
+ // Create an Environment and initialize the provided principal context for it.
Environment(IsolateData* isolate_data,
v8::Local<v8::Context> context,
const std::vector<std::string>& args,
@@ -1162,7 +730,9 @@ class Environment : public MemoryRetainer {
template <typename T, typename OnCloseCallback>
inline void CloseHandle(T* handle, OnCloseCallback callback);
- void AssignToContext(v8::Local<v8::Context> context, const ContextInfo& info);
+ void AssignToContext(v8::Local<v8::Context> context,
+ Realm* realm,
+ const ContextInfo& info);
void StartProfilerIdleNotifier();
@@ -1267,8 +837,8 @@ class Environment : public MemoryRetainer {
// as Workers aren't directly associated with their own libuv handles.
void add_refs(int64_t diff);
+ // Convenient getter of the principal realm's has_run_bootstrapping_code().
inline bool has_run_bootstrapping_code() const;
- inline void DoneBootstrapping();
inline bool has_serialized_options() const;
inline void set_has_serialized_options(bool has_serialized_options);
@@ -1326,7 +896,7 @@ class Environment : public MemoryRetainer {
v8::MaybeLocal<v8::Value> RunSnapshotDeserializeCallback() const;
v8::MaybeLocal<v8::Value> RunSnapshotDeserializeMain() const;
- // Strings and private symbols are shared across shared contexts
+ // Primitive values are shared across realms.
// The getters simply proxy to the per-isolate primitive.
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
@@ -1345,10 +915,17 @@ class Environment : public MemoryRetainer {
inline v8::Local<TypeName> PropertyName() const; \
inline void set_ ## PropertyName(v8::Local<TypeName> value);
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
+ // Per-realm strong persistent values of the principal realm.
+ // Get/set the value with an explicit realm instead when possible.
+ // Deprecate soon.
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
#undef V
+ // Return the context of the principal realm.
+ // Get the context with an explicit realm instead when possible.
+ // Deprecate soon.
inline v8::Local<v8::Context> context() const;
+ inline Realm* principal_realm() const;
#if HAVE_INSPECTOR
inline inspector::Agent* inspector_agent() const {
@@ -1432,9 +1009,15 @@ class Environment : public MemoryRetainer {
// no memory leaks caused by BaseObjects staying alive longer than expected
// (in particular, no circular BaseObjectPtr references).
inline void modify_base_object_count(int64_t delta);
- inline int64_t base_object_created_after_bootstrap() const;
inline int64_t base_object_count() const;
+ // Base object count created in bootstrap of the principal realm.
+ // This adjusts the return value of base_object_created_after_bootstrap() so
+ // that tests that check the count do not have to account for internally
+ // created BaseObjects.
+ inline void set_base_object_created_by_bootstrap(int64_t count);
+ inline int64_t base_object_created_after_bootstrap() const;
+
inline int32_t stack_trace_limit() const { return 10; }
#if HAVE_INSPECTOR
@@ -1567,7 +1150,6 @@ class Environment : public MemoryRetainer {
double time_origin_timestamp_;
std::unique_ptr<performance::PerformanceState> performance_state_;
- bool has_run_bootstrapping_code_ = false;
bool has_serialized_options_ = false;
std::atomic_bool can_call_into_js_ { true };
@@ -1642,11 +1224,7 @@ class Environment : public MemoryRetainer {
std::function<void(Environment*, int)> process_exit_handler_ {
DefaultProcessExitHandler };
-#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName ## _;
- ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
-#undef V
-
- v8::Global<v8::Context> context_;
+ std::unique_ptr<Realm> principal_realm_ = nullptr;
// Keeps the main script source alive is one was passed to LoadEnvironment().
// We should probably find a way to just use plain `v8::String`s created from
diff --git a/src/env_properties.h b/src/env_properties.h
new file mode 100644
index 00000000000..e650e4926fb
--- /dev/null
+++ b/src/env_properties.h
@@ -0,0 +1,433 @@
+#ifndef SRC_ENV_PROPERTIES_H_
+#define SRC_ENV_PROPERTIES_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+// PER_ISOLATE_* macros: We have a lot of per-isolate properties
+// and adding and maintaining their getters and setters by hand would be
+// difficult so let's make the preprocessor generate them for us.
+//
+// In each macro, `V` is expected to be the name of a macro or function which
+// accepts the number of arguments provided in each tuple in the macro body,
+// typically two. The named function will be invoked against each tuple.
+//
+// Make sure that any macro V defined for use with the PER_ISOLATE_* macros is
+// undefined again after use.
+
+// Private symbols are per-isolate primitives but Environment proxies them
+// for the sake of convenience. Strings should be ASCII-only and have a
+// "node:" prefix to avoid name clashes with third-party code.
+#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
+ V(alpn_buffer_private_symbol, "node:alpnBuffer") \
+ V(arrow_message_private_symbol, "node:arrowMessage") \
+ V(contextify_context_private_symbol, "node:contextify:context") \
+ V(contextify_global_private_symbol, "node:contextify:global") \
+ V(decorated_private_symbol, "node:decorated") \
+ V(napi_type_tag, "node:napi:type_tag") \
+ V(napi_wrapper, "node:napi:wrapper") \
+ V(untransferable_object_private_symbol, "node:untransferableObject") \
+ V(exiting_aliased_Uint32Array, "node:exiting_aliased_Uint32Array")
+
+// Symbols are per-isolate primitives but Environment proxies them
+// for the sake of convenience.
+#define PER_ISOLATE_SYMBOL_PROPERTIES(V) \
+ V(async_id_symbol, "async_id_symbol") \
+ V(handle_onclose_symbol, "handle_onclose") \
+ V(no_message_symbol, "no_message_symbol") \
+ V(messaging_deserialize_symbol, "messaging_deserialize_symbol") \
+ V(messaging_transfer_symbol, "messaging_transfer_symbol") \
+ V(messaging_clone_symbol, "messaging_clone_symbol") \
+ V(messaging_transfer_list_symbol, "messaging_transfer_list_symbol") \
+ V(oninit_symbol, "oninit") \
+ V(owner_symbol, "owner_symbol") \
+ V(onpskexchange_symbol, "onpskexchange") \
+ V(resource_symbol, "resource_symbol") \
+ V(trigger_async_id_symbol, "trigger_async_id_symbol")
+
+// Strings are per-isolate primitives but Environment proxies them
+// for the sake of convenience. Strings should be ASCII-only.
+#define PER_ISOLATE_STRING_PROPERTIES(V) \
+ V(ack_string, "ack") \
+ V(address_string, "address") \
+ V(aliases_string, "aliases") \
+ V(args_string, "args") \
+ V(asn1curve_string, "asn1Curve") \
+ V(async_ids_stack_string, "async_ids_stack") \
+ V(bits_string, "bits") \
+ V(block_list_string, "blockList") \
+ V(buffer_string, "buffer") \
+ V(bytes_parsed_string, "bytesParsed") \
+ V(bytes_read_string, "bytesRead") \
+ V(bytes_written_string, "bytesWritten") \
+ V(cached_data_produced_string, "cachedDataProduced") \
+ V(cached_data_rejected_string, "cachedDataRejected") \
+ V(cached_data_string, "cachedData") \
+ V(cache_key_string, "cacheKey") \
+ V(change_string, "change") \
+ V(channel_string, "channel") \
+ V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \
+ V(clone_unsupported_type_str, "Cannot transfer object of unsupported type.") \
+ V(code_string, "code") \
+ V(commonjs_string, "commonjs") \
+ V(config_string, "config") \
+ V(constants_string, "constants") \
+ V(crypto_dh_string, "dh") \
+ V(crypto_dsa_string, "dsa") \
+ V(crypto_ec_string, "ec") \
+ V(crypto_ed25519_string, "ed25519") \
+ V(crypto_ed448_string, "ed448") \
+ V(crypto_x25519_string, "x25519") \
+ V(crypto_x448_string, "x448") \
+ V(crypto_rsa_string, "rsa") \
+ V(crypto_rsa_pss_string, "rsa-pss") \
+ V(cwd_string, "cwd") \
+ V(data_string, "data") \
+ V(default_is_true_string, "defaultIsTrue") \
+ V(deserialize_info_string, "deserializeInfo") \
+ V(dest_string, "dest") \
+ V(destroyed_string, "destroyed") \
+ V(detached_string, "detached") \
+ V(dh_string, "DH") \
+ V(divisor_length_string, "divisorLength") \
+ V(dns_a_string, "A") \
+ V(dns_aaaa_string, "AAAA") \
+ V(dns_caa_string, "CAA") \
+ V(dns_critical_string, "critical") \
+ V(dns_cname_string, "CNAME") \
+ V(dns_mx_string, "MX") \
+ V(dns_naptr_string, "NAPTR") \
+ V(dns_ns_string, "NS") \
+ V(dns_ptr_string, "PTR") \
+ V(dns_soa_string, "SOA") \
+ V(dns_srv_string, "SRV") \
+ V(dns_txt_string, "TXT") \
+ V(done_string, "done") \
+ V(duration_string, "duration") \
+ V(ecdh_string, "ECDH") \
+ V(emit_string, "emit") \
+ V(emit_warning_string, "emitWarning") \
+ V(empty_object_string, "{}") \
+ V(encoding_string, "encoding") \
+ V(entries_string, "entries") \
+ V(entry_type_string, "entryType") \
+ V(env_pairs_string, "envPairs") \
+ V(env_var_settings_string, "envVarSettings") \
+ V(errno_string, "errno") \
+ V(error_string, "error") \
+ V(exchange_string, "exchange") \
+ V(exit_code_string, "exitCode") \
+ V(expire_string, "expire") \
+ V(exponent_string, "exponent") \
+ V(exports_string, "exports") \
+ V(ext_key_usage_string, "ext_key_usage") \
+ V(external_stream_string, "_externalStream") \
+ V(family_string, "family") \
+ V(fatal_exception_string, "_fatalException") \
+ V(fd_string, "fd") \
+ V(fields_string, "fields") \
+ V(file_string, "file") \
+ V(filename_string, "filename") \
+ V(fingerprint256_string, "fingerprint256") \
+ V(fingerprint512_string, "fingerprint512") \
+ V(fingerprint_string, "fingerprint") \
+ V(flags_string, "flags") \
+ V(flowlabel_string, "flowlabel") \
+ V(fragment_string, "fragment") \
+ V(frames_received_string, "framesReceived") \
+ V(frames_sent_string, "framesSent") \
+ V(function_string, "function") \
+ V(get_data_clone_error_string, "_getDataCloneError") \
+ V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
+ V(gid_string, "gid") \
+ V(h2_string, "h2") \
+ V(handle_string, "handle") \
+ V(hash_algorithm_string, "hashAlgorithm") \
+ V(help_text_string, "helpText") \
+ V(homedir_string, "homedir") \
+ V(host_string, "host") \
+ V(hostmaster_string, "hostmaster") \
+ V(http_1_1_string, "http/1.1") \
+ V(id_string, "id") \
+ V(identity_string, "identity") \
+ V(ignore_string, "ignore") \
+ V(infoaccess_string, "infoAccess") \
+ V(inherit_string, "inherit") \
+ V(input_string, "input") \
+ V(internal_binding_string, "internalBinding") \
+ V(internal_string, "internal") \
+ V(ipv4_string, "IPv4") \
+ V(ipv6_string, "IPv6") \
+ V(isclosing_string, "isClosing") \
+ V(issuer_string, "issuer") \
+ V(issuercert_string, "issuerCertificate") \
+ V(jwk_crv_string, "crv") \
+ V(jwk_d_string, "d") \
+ V(jwk_dp_string, "dp") \
+ V(jwk_dq_string, "dq") \
+ V(jwk_dsa_string, "DSA") \
+ V(jwk_e_string, "e") \
+ V(jwk_ec_string, "EC") \
+ V(jwk_g_string, "g") \
+ V(jwk_k_string, "k") \
+ V(jwk_p_string, "p") \
+ V(jwk_q_string, "q") \
+ V(jwk_qi_string, "qi") \
+ V(jwk_kty_string, "kty") \
+ V(jwk_n_string, "n") \
+ V(jwk_oct_string, "oct") \
+ V(jwk_okp_string, "OKP") \
+ V(jwk_rsa_string, "RSA") \
+ V(jwk_x_string, "x") \
+ V(jwk_y_string, "y") \
+ V(kill_signal_string, "killSignal") \
+ V(kind_string, "kind") \
+ V(length_string, "length") \
+ V(library_string, "library") \
+ V(mac_string, "mac") \
+ V(max_buffer_string, "maxBuffer") \
+ V(max_concurrent_streams_string, "maxConcurrentStreams") \
+ V(message_port_constructor_string, "MessagePort") \
+ V(message_port_string, "messagePort") \
+ V(message_string, "message") \
+ V(messageerror_string, "messageerror") \
+ V(mgf1_hash_algorithm_string, "mgf1HashAlgorithm") \
+ V(minttl_string, "minttl") \
+ V(module_string, "module") \
+ V(modulus_string, "modulus") \
+ V(modulus_length_string, "modulusLength") \
+ V(name_string, "name") \
+ V(named_curve_string, "namedCurve") \
+ V(netmask_string, "netmask") \
+ V(next_string, "next") \
+ V(nistcurve_string, "nistCurve") \
+ V(node_string, "node") \
+ V(nsname_string, "nsname") \
+ V(object_string, "Object") \
+ V(ocsp_request_string, "OCSPRequest") \
+ V(oncertcb_string, "oncertcb") \
+ V(onchange_string, "onchange") \
+ V(onclienthello_string, "onclienthello") \
+ V(oncomplete_string, "oncomplete") \
+ V(onconnection_string, "onconnection") \
+ V(ondone_string, "ondone") \
+ V(onerror_string, "onerror") \
+ V(onexit_string, "onexit") \
+ V(onhandshakedone_string, "onhandshakedone") \
+ V(onhandshakestart_string, "onhandshakestart") \
+ V(onkeylog_string, "onkeylog") \
+ V(onmessage_string, "onmessage") \
+ V(onnewsession_string, "onnewsession") \
+ V(onocspresponse_string, "onocspresponse") \
+ V(onreadstart_string, "onreadstart") \
+ V(onreadstop_string, "onreadstop") \
+ V(onshutdown_string, "onshutdown") \
+ V(onsignal_string, "onsignal") \
+ V(onunpipe_string, "onunpipe") \
+ V(onwrite_string, "onwrite") \
+ V(openssl_error_stack, "opensslErrorStack") \
+ V(options_string, "options") \
+ V(order_string, "order") \
+ V(output_string, "output") \
+ V(overlapped_string, "overlapped") \
+ V(parse_error_string, "Parse Error") \
+ V(password_string, "password") \
+ V(path_string, "path") \
+ V(pending_handle_string, "pendingHandle") \
+ V(pid_string, "pid") \
+ V(ping_rtt_string, "pingRTT") \
+ V(pipe_source_string, "pipeSource") \
+ V(pipe_string, "pipe") \
+ V(pipe_target_string, "pipeTarget") \
+ V(port1_string, "port1") \
+ V(port2_string, "port2") \
+ V(port_string, "port") \
+ V(preference_string, "preference") \
+ V(primordials_string, "primordials") \
+ V(priority_string, "priority") \
+ V(process_string, "process") \
+ V(promise_string, "promise") \
+ V(psk_string, "psk") \
+ V(pubkey_string, "pubkey") \
+ V(public_exponent_string, "publicExponent") \
+ V(query_string, "query") \
+ V(rate_string, "rate") \
+ V(raw_string, "raw") \
+ V(read_host_object_string, "_readHostObject") \
+ V(readable_string, "readable") \
+ V(reason_string, "reason") \
+ V(refresh_string, "refresh") \
+ V(regexp_string, "regexp") \
+ V(rename_string, "rename") \
+ V(replacement_string, "replacement") \
+ V(require_string, "require") \
+ V(retry_string, "retry") \
+ V(salt_length_string, "saltLength") \
+ V(scheme_string, "scheme") \
+ V(scopeid_string, "scopeid") \
+ V(serial_number_string, "serialNumber") \
+ V(serial_string, "serial") \
+ V(servername_string, "servername") \
+ V(service_string, "service") \
+ V(session_id_string, "sessionId") \
+ V(shell_string, "shell") \
+ V(signal_string, "signal") \
+ V(sink_string, "sink") \
+ V(size_string, "size") \
+ V(sni_context_err_string, "Invalid SNI context") \
+ V(sni_context_string, "sni_context") \
+ V(source_string, "source") \
+ V(stack_string, "stack") \
+ V(standard_name_string, "standardName") \
+ V(start_time_string, "startTime") \
+ V(state_string, "state") \
+ V(stats_string, "stats") \
+ V(status_string, "status") \
+ V(stdio_string, "stdio") \
+ V(stream_average_duration_string, "streamAverageDuration") \
+ V(stream_count_string, "streamCount") \
+ V(subject_string, "subject") \
+ V(subjectaltname_string, "subjectaltname") \
+ V(syscall_string, "syscall") \
+ V(target_string, "target") \
+ V(thread_id_string, "threadId") \
+ V(ticketkeycallback_string, "onticketkeycallback") \
+ V(timeout_string, "timeout") \
+ V(time_to_first_byte_string, "timeToFirstByte") \
+ V(time_to_first_byte_sent_string, "timeToFirstByteSent") \
+ V(time_to_first_header_string, "timeToFirstHeader") \
+ V(tls_ticket_string, "tlsTicket") \
+ V(transfer_string, "transfer") \
+ V(ttl_string, "ttl") \
+ V(type_string, "type") \
+ V(uid_string, "uid") \
+ V(unknown_string, "<unknown>") \
+ V(url_special_ftp_string, "ftp:") \
+ V(url_special_file_string, "file:") \
+ V(url_special_http_string, "http:") \
+ V(url_special_https_string, "https:") \
+ V(url_special_ws_string, "ws:") \
+ V(url_special_wss_string, "wss:") \
+ V(url_string, "url") \
+ V(username_string, "username") \
+ V(valid_from_string, "valid_from") \
+ V(valid_to_string, "valid_to") \
+ V(value_string, "value") \
+ V(verify_error_string, "verifyError") \
+ V(version_string, "version") \
+ V(weight_string, "weight") \
+ V(windows_hide_string, "windowsHide") \
+ V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \
+ V(wrap_string, "wrap") \
+ V(writable_string, "writable") \
+ V(write_host_object_string, "_writeHostObject") \
+ V(write_queue_size_string, "writeQueueSize") \
+ V(x_forwarded_string, "x-forwarded-for") \
+ V(zero_return_string, "ZERO_RETURN")
+
+#define PER_ISOLATE_TEMPLATE_PROPERTIES(V) \
+ V(async_wrap_ctor_template, v8::FunctionTemplate) \
+ V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
+ V(base_object_ctor_template, v8::FunctionTemplate) \
+ V(binding_data_ctor_template, v8::FunctionTemplate) \
+ V(blob_constructor_template, v8::FunctionTemplate) \
+ V(blocklist_constructor_template, v8::FunctionTemplate) \
+ V(contextify_global_template, v8::ObjectTemplate) \
+ V(compiled_fn_entry_template, v8::ObjectTemplate) \
+ V(dir_instance_template, v8::ObjectTemplate) \
+ V(fd_constructor_template, v8::ObjectTemplate) \
+ V(fdclose_constructor_template, v8::ObjectTemplate) \
+ V(filehandlereadwrap_template, v8::ObjectTemplate) \
+ V(fsreqpromise_constructor_template, v8::ObjectTemplate) \
+ V(handle_wrap_ctor_template, v8::FunctionTemplate) \
+ V(histogram_ctor_template, v8::FunctionTemplate) \
+ V(http2settings_constructor_template, v8::ObjectTemplate) \
+ V(http2stream_constructor_template, v8::ObjectTemplate) \
+ V(http2ping_constructor_template, v8::ObjectTemplate) \
+ V(i18n_converter_template, v8::ObjectTemplate) \
+ V(intervalhistogram_constructor_template, v8::FunctionTemplate) \
+ V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
+ V(message_port_constructor_template, v8::FunctionTemplate) \
+ V(microtask_queue_ctor_template, v8::FunctionTemplate) \
+ V(pipe_constructor_template, v8::FunctionTemplate) \
+ V(promise_wrap_template, v8::ObjectTemplate) \
+ V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \
+ V(script_context_constructor_template, v8::FunctionTemplate) \
+ V(secure_context_constructor_template, v8::FunctionTemplate) \
+ V(shutdown_wrap_template, v8::ObjectTemplate) \
+ V(socketaddress_constructor_template, v8::FunctionTemplate) \
+ V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \
+ V(qlogoutputstream_constructor_template, v8::ObjectTemplate) \
+ V(tcp_constructor_template, v8::FunctionTemplate) \
+ V(tty_constructor_template, v8::FunctionTemplate) \
+ V(write_wrap_template, v8::ObjectTemplate) \
+ V(worker_heap_snapshot_taker_template, v8::ObjectTemplate) \
+ V(x509_constructor_template, v8::FunctionTemplate)
+
+#define PER_REALM_STRONG_PERSISTENT_VALUES(V) \
+ V(async_hooks_after_function, v8::Function) \
+ V(async_hooks_before_function, v8::Function) \
+ V(async_hooks_callback_trampoline, v8::Function) \
+ V(async_hooks_binding, v8::Object) \
+ V(async_hooks_destroy_function, v8::Function) \
+ V(async_hooks_init_function, v8::Function) \
+ V(async_hooks_promise_resolve_function, v8::Function) \
+ V(buffer_prototype_object, v8::Object) \
+ V(crypto_key_object_constructor, v8::Function) \
+ V(crypto_key_object_handle_constructor, v8::Function) \
+ V(crypto_key_object_private_constructor, v8::Function) \
+ V(crypto_key_object_public_constructor, v8::Function) \
+ V(crypto_key_object_secret_constructor, v8::Function) \
+ V(domexception_function, v8::Function) \
+ V(enhance_fatal_stack_after_inspector, v8::Function) \
+ V(enhance_fatal_stack_before_inspector, v8::Function) \
+ V(fs_use_promises_symbol, v8::Symbol) \
+ V(get_source_map_error_source, v8::Function) \
+ V(host_import_module_dynamically_callback, v8::Function) \
+ V(host_initialize_import_meta_object_callback, v8::Function) \
+ V(http2session_on_altsvc_function, v8::Function) \
+ V(http2session_on_error_function, v8::Function) \
+ V(http2session_on_frame_error_function, v8::Function) \
+ V(http2session_on_goaway_data_function, v8::Function) \
+ V(http2session_on_headers_function, v8::Function) \
+ V(http2session_on_origin_function, v8::Function) \
+ V(http2session_on_ping_function, v8::Function) \
+ V(http2session_on_priority_function, v8::Function) \
+ V(http2session_on_settings_function, v8::Function) \
+ V(http2session_on_stream_close_function, v8::Function) \
+ V(http2session_on_stream_trailers_function, v8::Function) \
+ V(internal_binding_loader, v8::Function) \
+ V(immediate_callback_function, v8::Function) \
+ V(inspector_console_extension_installer, v8::Function) \
+ V(inspector_disable_async_hooks, v8::Function) \
+ V(inspector_enable_async_hooks, v8::Function) \
+ V(maybe_cache_generated_source_map, v8::Function) \
+ V(messaging_deserialize_create_object, v8::Function) \
+ V(message_port, v8::Object) \
+ V(builtin_module_require, v8::Function) \
+ V(performance_entry_callback, v8::Function) \
+ V(performance_entry_template, v8::Function) \
+ V(prepare_stack_trace_callback, v8::Function) \
+ V(process_object, v8::Object) \
+ V(primordials, v8::Object) \
+ V(primordials_safe_map_prototype_object, v8::Object) \
+ V(primordials_safe_set_prototype_object, v8::Object) \
+ V(primordials_safe_weak_map_prototype_object, v8::Object) \
+ V(primordials_safe_weak_set_prototype_object, v8::Object) \
+ V(promise_hook_handler, v8::Function) \
+ V(promise_reject_callback, v8::Function) \
+ V(snapshot_serialize_callback, v8::Function) \
+ V(snapshot_deserialize_callback, v8::Function) \
+ V(snapshot_deserialize_main, v8::Function) \
+ V(source_map_cache_getter, v8::Function) \
+ V(tick_callback_function, v8::Function) \
+ V(timers_callback_function, v8::Function) \
+ V(tls_wrap_constructor_function, v8::Function) \
+ V(trace_category_state_function, v8::Function) \
+ V(udp_constructor_function, v8::Function) \
+ V(url_constructor_function, v8::Function) \
+ V(wasm_streaming_compilation_impl, v8::Function) \
+ V(wasm_streaming_object_constructor, v8::Function)
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_ENV_PROPERTIES_H_
diff --git a/src/node.cc b/src/node.cc
index 2891c18bb9a..c2bbfb73747 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -36,6 +36,7 @@
#include "node_options-inl.h"
#include "node_perf.h"
#include "node_process-inl.h"
+#include "node_realm-inl.h"
#include "node_report.h"
#include "node_revert.h"
#include "node_snapshot_builder.h"
@@ -124,13 +125,10 @@ namespace node {
using builtins::BuiltinLoader;
using v8::EscapableHandleScope;
-using v8::Function;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
-using v8::String;
-using v8::Undefined;
using v8::V8;
using v8::Value;
@@ -167,36 +165,6 @@ void SignalExit(int signo, siginfo_t* info, void* ucontext) {
}
#endif // __POSIX__
-MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
- const char* id,
- std::vector<Local<Value>>* arguments) {
- EscapableHandleScope scope(env->isolate());
- MaybeLocal<Function> maybe_fn =
- BuiltinLoader::LookupAndCompile(env->context(), id, env);
-
- Local<Function> fn;
- if (!maybe_fn.ToLocal(&fn)) {
- return MaybeLocal<Value>();
- }
-
- MaybeLocal<Value> result = fn->Call(env->context(),
- Undefined(env->isolate()),
- arguments->size(),
- arguments->data());
-
- // If there was an error during bootstrap, it must be unrecoverable
- // (e.g. max call stack exceeded). Clear the stack so that the
- // AsyncCallbackScope destructor doesn't fail on the id check.
- // There are only two ways to have a stack size > 1: 1) the user manually
- // called MakeCallback or 2) user awaited during bootstrap, which triggered
- // _tickCallback().
- if (result.IsEmpty()) {
- env->async_hooks()->clear_async_id_stack();
- }
-
- return scope.EscapeMaybe(result);
-}
-
#if HAVE_INSPECTOR
int Environment::InitializeInspector(
std::unique_ptr<inspector::ParentInspectorHandle> parent_handle) {
@@ -288,129 +256,11 @@ void Environment::InitializeDiagnostics() {
}
}
-MaybeLocal<Value> Environment::BootstrapInternalLoaders() {
- EscapableHandleScope scope(isolate_);
-
- // Arguments must match the parameters specified in
- // BuiltinLoader::LookupAndCompile().
- std::vector<Local<Value>> loaders_args = {
- process_object(),
- NewFunctionTemplate(isolate_, binding::GetLinkedBinding)
- ->GetFunction(context())
- .ToLocalChecked(),
- NewFunctionTemplate(isolate_, binding::GetInternalBinding)
- ->GetFunction(context())
- .ToLocalChecked(),
- primordials()};
-
- // Bootstrap internal loaders
- Local<Value> loader_exports;
- if (!ExecuteBootstrapper(this, "internal/bootstrap/loaders", &loaders_args)
- .ToLocal(&loader_exports)) {
- return MaybeLocal<Value>();
- }
- CHECK(loader_exports->IsObject());
- Local<Object> loader_exports_obj = loader_exports.As<Object>();
- Local<Value> internal_binding_loader =
- loader_exports_obj->Get(context(), internal_binding_string())
- .ToLocalChecked();
- CHECK(internal_binding_loader->IsFunction());
- set_internal_binding_loader(internal_binding_loader.As<Function>());
- Local<Value> require =
- loader_exports_obj->Get(context(), require_string()).ToLocalChecked();
- CHECK(require->IsFunction());
- set_builtin_module_require(require.As<Function>());
-
- return scope.Escape(loader_exports);
-}
-
-MaybeLocal<Value> Environment::BootstrapNode() {
- EscapableHandleScope scope(isolate_);
-
- // Arguments must match the parameters specified in
- // BuiltinLoader::LookupAndCompile().
- // process, require, internalBinding, primordials
- std::vector<Local<Value>> node_args = {process_object(),
- builtin_module_require(),
- internal_binding_loader(),
- primordials()};
-
- MaybeLocal<Value> result =
- ExecuteBootstrapper(this, "internal/bootstrap/node", &node_args);
-
- if (result.IsEmpty()) {
- return MaybeLocal<Value>();
- }
-
- if (!no_browser_globals()) {
- result =
- ExecuteBootstrapper(this, "internal/bootstrap/browser", &node_args);
-
- if (result.IsEmpty()) {
- return MaybeLocal<Value>();
- }
- }
-
- // TODO(joyeecheung): skip these in the snapshot building for workers.
- auto thread_switch_id =
- is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
- : "internal/bootstrap/switches/is_not_main_thread";
- result = ExecuteBootstrapper(this, thread_switch_id, &node_args);
-
- if (result.IsEmpty()) {
- return MaybeLocal<Value>();
- }
-
- auto process_state_switch_id =
- owns_process_state()
- ? "internal/bootstrap/switches/does_own_process_state"
- : "internal/bootstrap/switches/does_not_own_process_state";
- result = ExecuteBootstrapper(this, process_state_switch_id, &node_args);
-
- if (result.IsEmpty()) {
- return MaybeLocal<Value>();
- }
-
- Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
- Local<Object> env_var_proxy;
- if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
- process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
- return MaybeLocal<Value>();
- }
-
- return scope.EscapeMaybe(result);
-}
-
-MaybeLocal<Value> Environment::RunBootstrapping() {
- EscapableHandleScope scope(isolate_);
-
- CHECK(!has_run_bootstrapping_code());
-
- if (BootstrapInternalLoaders().IsEmpty()) {
- return MaybeLocal<Value>();
- }
-
- Local<Value> result;
- if (!BootstrapNode().ToLocal(&result)) {
- return MaybeLocal<Value>();
- }
-
- // Make sure that no request or handle is created during bootstrap -
- // if necessary those should be done in pre-execution.
- // Usually, doing so would trigger the checks present in the ReqWrap and
- // HandleWrap classes, so this is only a consistency check.
- CHECK(req_wrap_queue()->IsEmpty());
- CHECK(handle_wrap_queue()->IsEmpty());
-
- DoneBootstrapping();
-
- return scope.Escape(result);
-}
-
static
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
EscapableHandleScope scope(env->isolate());
CHECK_NOT_NULL(main_script_id);
+ Realm* realm = env->principal_realm();
// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
@@ -420,7 +270,7 @@ MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
env->primordials()};
return scope.EscapeMaybe(
- ExecuteBootstrapper(env, main_script_id, &arguments));
+ realm->ExecuteBootstrapper(main_script_id, &arguments));
}
MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
diff --git a/src/node_context_data.h b/src/node_context_data.h
index 3fe425bdf4c..4278a17f4b6 100644
--- a/src/node_context_data.h
+++ b/src/node_context_data.h
@@ -36,11 +36,15 @@ namespace node {
#define NODE_CONTEXT_CONTEXTIFY_CONTEXT_INDEX 37
#endif
+#ifndef NODE_CONTEXT_REALM_INDEX
+#define NODE_CONTEXT_REALM_INDEX 38
+#endif
+
// NODE_CONTEXT_TAG must be greater than any embedder indexes so that a single
// check on the number of embedder data fields can assure the presence of all
// embedder indexes.
#ifndef NODE_CONTEXT_TAG
-#define NODE_CONTEXT_TAG 38
+#define NODE_CONTEXT_TAG 39
#endif
enum ContextEmbedderIndex {
@@ -51,6 +55,7 @@ enum ContextEmbedderIndex {
kAllowCodeGenerationFromStrings =
NODE_CONTEXT_ALLOW_CODE_GENERATION_FROM_STRINGS_INDEX,
kContextifyContext = NODE_CONTEXT_CONTEXTIFY_CONTEXT_INDEX,
+ kRealm = NODE_CONTEXT_REALM_INDEX,
kContextTag = NODE_CONTEXT_TAG,
};
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 6c7412c10ae..c2cfe5071d0 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -278,7 +278,7 @@ bool ContextifyContext::InitializeContext(Local<Context> ctx,
}
}
- env->AssignToContext(ctx, info);
+ env->AssignToContext(ctx, nullptr, info);
// This should only be done after the initial initializations of the context
// global object is finished.
diff --git a/src/node_internals.h b/src/node_internals.h
index de81fbee07c..9cd89faca13 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -307,10 +307,6 @@ v8::Isolate* NewIsolate(v8::Isolate::CreateParams* params,
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
StartExecutionCallback cb = nullptr);
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context);
-v8::MaybeLocal<v8::Value> ExecuteBootstrapper(
- Environment* env,
- const char* id,
- std::vector<v8::Local<v8::Value>>* arguments);
void MarkBootstrapComplete(const v8::FunctionCallbackInfo<v8::Value>& args);
class InitializationResultImpl final : public InitializationResult {
diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc
index 12d51743ddd..2ec53a1b314 100644
--- a/src/node_main_instance.cc
+++ b/src/node_main_instance.cc
@@ -8,6 +8,7 @@
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_options-inl.h"
+#include "node_realm.h"
#include "node_snapshot_builder.h"
#include "node_snapshotable.h"
#include "node_v8_platform-inl.h"
@@ -181,7 +182,6 @@ NodeMainInstance::CreateMainEnvironment(int* exit_code) {
#if HAVE_INSPECTOR
env->InitializeInspector({});
#endif
- env->DoneBootstrapping();
#if HAVE_OPENSSL
crypto::InitCryptoOnce(isolate_);
@@ -200,7 +200,7 @@ NodeMainInstance::CreateMainEnvironment(int* exit_code) {
#if HAVE_INSPECTOR
env->InitializeInspector({});
#endif
- if (env->RunBootstrapping().IsEmpty()) {
+ if (env->principal_realm()->RunBootstrapping().IsEmpty()) {
return nullptr;
}
}
diff --git a/src/node_process.h b/src/node_process.h
index 7f88228e4c8..8abcd16ca60 100644
--- a/src/node_process.h
+++ b/src/node_process.h
@@ -12,6 +12,7 @@ namespace node {
class Environment;
class MemoryTracker;
class ExternalReferenceRegistry;
+class Realm;
v8::MaybeLocal<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
v8::Isolate* isolate);
@@ -41,7 +42,7 @@ v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
const char* warning,
const char* deprecation_code);
-v8::MaybeLocal<v8::Object> CreateProcessObject(Environment* env);
+v8::MaybeLocal<v8::Object> CreateProcessObject(Realm* env);
void PatchProcessObject(const v8::FunctionCallbackInfo<v8::Value>& args);
namespace process {
diff --git a/src/node_process_object.cc b/src/node_process_object.cc
index 569c93ccb31..6822601a47d 100644
--- a/src/node_process_object.cc
+++ b/src/node_process_object.cc
@@ -5,6 +5,7 @@
#include "node_metadata.h"
#include "node_options-inl.h"
#include "node_process-inl.h"
+#include "node_realm-inl.h"
#include "node_revert.h"
#include "util-inl.h"
@@ -77,13 +78,13 @@ static void GetParentProcessId(Local<Name> property,
info.GetReturnValue().Set(uv_os_getppid());
}
-MaybeLocal<Object> CreateProcessObject(Environment* env) {
- Isolate* isolate = env->isolate();
+MaybeLocal<Object> CreateProcessObject(Realm* realm) {
+ Isolate* isolate = realm->isolate();
EscapableHandleScope scope(isolate);
- Local<Context> context = env->context();
+ Local<Context> context = realm->context();
Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate);
- process_template->SetClassName(env->process_string());
+ process_template->SetClassName(realm->env()->process_string());
Local<Function> process_ctor;
Local<Object> process;
if (!process_template->GetFunction(context).ToLocal(&process_ctor) ||
@@ -94,19 +95,18 @@ MaybeLocal<Object> CreateProcessObject(Environment* env) {
// process[exiting_aliased_Uint32Array]
if (process
->SetPrivate(context,
- env->exiting_aliased_Uint32Array(),
- env->exiting().GetJSArray())
+ realm->env()->exiting_aliased_Uint32Array(),
+ realm->env()->exiting().GetJSArray())
.IsNothing()) {
return {};
}
// process.version
- READONLY_PROPERTY(process,
- "version",
- FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION));
+ READONLY_PROPERTY(
+ process, "version", FIXED_ONE_BYTE_STRING(isolate, NODE_VERSION));
// process.versions
- Local<Object> versions = Object::New(env->isolate());
+ Local<Object> versions = Object::New(isolate);
READONLY_PROPERTY(process, "versions", versions);
#define V(key) \
@@ -124,7 +124,7 @@ MaybeLocal<Object> CreateProcessObject(Environment* env) {
READONLY_STRING_PROPERTY(process, "platform", per_process::metadata.platform);
// process.release
- Local<Object> release = Object::New(env->isolate());
+ Local<Object> release = Object::New(isolate);
READONLY_PROPERTY(process, "release", release);
READONLY_STRING_PROPERTY(release, "name", per_process::metadata.release.name);
#if NODE_VERSION_IS_LTS
diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h
new file mode 100644
index 00000000000..c50ba2ebcbc
--- /dev/null
+++ b/src/node_realm-inl.h
@@ -0,0 +1,62 @@
+#ifndef SRC_NODE_REALM_INL_H_
+#define SRC_NODE_REALM_INL_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include "node_realm.h"
+
+namespace node {
+
+inline Realm* Realm::GetCurrent(v8::Isolate* isolate) {
+ if (UNLIKELY(!isolate->InContext())) return nullptr;
+ v8::HandleScope handle_scope(isolate);
+ return GetCurrent(isolate->GetCurrentContext());
+}
+
+inline Realm* Realm::GetCurrent(v8::Local<v8::Context> context) {
+ if (UNLIKELY(!ContextEmbedderTag::IsNodeContext(context))) return nullptr;
+ return static_cast<Realm*>(
+ context->GetAlignedPointerFromEmbedderData(ContextEmbedderIndex::kRealm));
+}
+
+inline Realm* Realm::GetCurrent(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ return GetCurrent(info.GetIsolate()->GetCurrentContext());
+}
+
+template <typename T>
+inline Realm* Realm::GetCurrent(const v8::PropertyCallbackInfo<T>& info) {
+ return GetCurrent(info.GetIsolate()->GetCurrentContext());
+}
+
+inline Environment* Realm::env() const {
+ return env_;
+}
+
+inline v8::Isolate* Realm::isolate() const {
+ return isolate_;
+}
+
+inline bool Realm::has_run_bootstrapping_code() const {
+ return has_run_bootstrapping_code_;
+}
+
+#define V(PropertyName, TypeName) \
+ inline v8::Local<TypeName> Realm::PropertyName() const { \
+ return PersistentToLocal::Strong(PropertyName##_); \
+ } \
+ inline void Realm::set_##PropertyName(v8::Local<TypeName> value) { \
+ PropertyName##_.Reset(isolate(), value); \
+ }
+PER_REALM_STRONG_PERSISTENT_VALUES(V)
+#undef V
+
+v8::Local<v8::Context> Realm::context() const {
+ return PersistentToLocal::Strong(context_);
+}
+
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_NODE_REALM_INL_H_
diff --git a/src/node_realm.cc b/src/node_realm.cc
new file mode 100644
index 00000000000..dd045e43fdd
--- /dev/null
+++ b/src/node_realm.cc
@@ -0,0 +1,308 @@
+#include "node_realm.h"
+#include "env-inl.h"
+
+#include "memory_tracker-inl.h"
+#include "node_builtins.h"
+#include "node_process.h"
+#include "util.h"
+
+namespace node {
+
+using builtins::BuiltinLoader;
+using v8::Context;
+using v8::EscapableHandleScope;
+using v8::Function;
+using v8::HandleScope;
+using v8::Local;
+using v8::MaybeLocal;
+using v8::Object;
+using v8::SnapshotCreator;
+using v8::String;
+using v8::Undefined;
+using v8::Value;
+
+Realm::Realm(Environment* env,
+ v8::Local<v8::Context> context,
+ const RealmSerializeInfo* realm_info)
+ : env_(env), isolate_(context->GetIsolate()) {
+ context_.Reset(isolate_, context);
+
+ // Create properties if not deserializing from snapshot.
+ // Or the properties are deserialized with DeserializeProperties() when the
+ // env drained the deserialize requests.
+ if (realm_info == nullptr) {
+ CreateProperties();
+ }
+}
+
+void Realm::MemoryInfo(MemoryTracker* tracker) const {
+#define V(PropertyName, TypeName) \
+ tracker->TrackField(#PropertyName, PropertyName());
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
+#undef V
+
+ tracker->TrackField("env", env_);
+}
+
+void Realm::CreateProperties() {
+ HandleScope handle_scope(isolate_);
+ Local<Context> ctx = context();
+
+ // Store primordials setup by the per-context script in the environment.
+ Local<Object> per_context_bindings =
+ GetPerContextExports(ctx).ToLocalChecked();
+ Local<Value> primordials =
+ per_context_bindings->Get(ctx, env_->primordials_string())
+ .ToLocalChecked();
+ CHECK(primordials->IsObject());
+ set_primordials(primordials.As<Object>());
+
+ Local<String> prototype_string =
+ FIXED_ONE_BYTE_STRING(isolate(), "prototype");
+
+#define V(EnvPropertyName, PrimordialsPropertyName) \
+ { \
+ Local<Value> ctor = \
+ primordials.As<Object>() \
+ ->Get(ctx, \
+ FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName)) \
+ .ToLocalChecked(); \
+ CHECK(ctor->IsObject()); \
+ Local<Value> prototype = \
+ ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked(); \
+ CHECK(prototype->IsObject()); \
+ set_##EnvPropertyName(prototype.As<Object>()); \
+ }
+
+ V(primordials_safe_map_prototype_object, "SafeMap");
+ V(primordials_safe_set_prototype_object, "SafeSet");
+ V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
+ V(primordials_safe_weak_set_prototype_object, "SafeWeakSet");
+#undef V
+
+ // TODO(legendecas): some methods probably doesn't need to be created with
+ // process. Distinguish them and create process object only in the principal
+ // realm.
+ Local<Object> process_object =
+ node::CreateProcessObject(this).FromMaybe(Local<Object>());
+ set_process_object(process_object);
+}
+
+RealmSerializeInfo Realm::Serialize(SnapshotCreator* creator) {
+ RealmSerializeInfo info;
+ Local<Context> ctx = context();
+
+ uint32_t id = 0;
+#define V(PropertyName, TypeName) \
+ do { \
+ Local<TypeName> field = PropertyName(); \
+ if (!field.IsEmpty()) { \
+ size_t index = creator->AddData(ctx, field); \
+ info.persistent_values.push_back({#PropertyName, id, index}); \
+ } \
+ id++; \
+ } while (0);
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
+#undef V
+
+ info.context = creator->AddData(ctx, ctx);
+ return info;
+}
+
+void Realm::DeserializeProperties(const RealmSerializeInfo* info) {
+ Local<Context> ctx = context();
+
+ const std::vector<PropInfo>& values = info->persistent_values;
+ size_t i = 0; // index to the array
+ uint32_t id = 0;
+#define V(PropertyName, TypeName) \
+ do { \
+ if (values.size() > i && id == values[i].id) { \
+ const PropInfo& d = values[i]; \
+ DCHECK_EQ(d.name, #PropertyName); \
+ MaybeLocal<TypeName> maybe_field = \
+ ctx->GetDataFromSnapshotOnce<TypeName>(d.index); \
+ Local<TypeName> field; \
+ if (!maybe_field.ToLocal(&field)) { \
+ fprintf(stderr, \
+ "Failed to deserialize realm value " #PropertyName "\n"); \
+ } \
+ set_##PropertyName(field); \
+ i++; \
+ } \
+ id++; \
+ } while (0);
+
+ PER_REALM_STRONG_PERSISTENT_VALUES(V);
+#undef V
+
+ MaybeLocal<Context> maybe_ctx_from_snapshot =
+ ctx->GetDataFromSnapshotOnce<Context>(info->context);
+ Local<Context> ctx_from_snapshot;
+ if (!maybe_ctx_from_snapshot.ToLocal(&ctx_from_snapshot)) {
+ fprintf(stderr,
+ "Failed to deserialize context back reference from the snapshot\n");
+ }
+ CHECK_EQ(ctx_from_snapshot, ctx);
+
+ DoneBootstrapping();
+}
+
+MaybeLocal<Value> Realm::ExecuteBootstrapper(
+ const char* id, std::vector<Local<Value>>* arguments) {
+ EscapableHandleScope scope(isolate());
+ Local<Context> ctx = context();
+ MaybeLocal<Function> maybe_fn =
+ BuiltinLoader::LookupAndCompile(ctx, id, env());
+
+ Local<Function> fn;
+ if (!maybe_fn.ToLocal(&fn)) {
+ return MaybeLocal<Value>();
+ }
+
+ MaybeLocal<Value> result =
+ fn->Call(ctx, Undefined(isolate()), arguments->size(), arguments->data());
+
+ // If there was an error during bootstrap, it must be unrecoverable
+ // (e.g. max call stack exceeded). Clear the stack so that the
+ // AsyncCallbackScope destructor doesn't fail on the id check.
+ // There are only two ways to have a stack size > 1: 1) the user manually
+ // called MakeCallback or 2) user awaited during bootstrap, which triggered
+ // _tickCallback().
+ if (result.IsEmpty()) {
+ env()->async_hooks()->clear_async_id_stack();
+ }
+
+ return scope.EscapeMaybe(result);
+}
+
+MaybeLocal<Value> Realm::BootstrapInternalLoaders() {
+ EscapableHandleScope scope(isolate_);
+
+ // Arguments must match the parameters specified in
+ // BuiltinLoader::LookupAndCompile().
+ std::vector<Local<Value>> loaders_args = {
+ process_object(),
+ NewFunctionTemplate(isolate_, binding::GetLinkedBinding)
+ ->GetFunction(context())
+ .ToLocalChecked(),
+ NewFunctionTemplate(isolate_, binding::GetInternalBinding)
+ ->GetFunction(context())
+ .ToLocalChecked(),
+ primordials()};
+
+ // Bootstrap internal loaders
+ Local<Value> loader_exports;
+ if (!ExecuteBootstrapper("internal/bootstrap/loaders", &loaders_args)
+ .ToLocal(&loader_exports)) {
+ return MaybeLocal<Value>();
+ }
+ CHECK(loader_exports->IsObject());
+ Local<Object> loader_exports_obj = loader_exports.As<Object>();
+ Local<Value> internal_binding_loader =
+ loader_exports_obj->Get(context(), env_->internal_binding_string())
+ .ToLocalChecked();
+ CHECK(internal_binding_loader->IsFunction());
+ set_internal_binding_loader(internal_binding_loader.As<Function>());
+ Local<Value> require =
+ loader_exports_obj->Get(context(), env_->require_string())
+ .ToLocalChecked();
+ CHECK(require->IsFunction());
+ set_builtin_module_require(require.As<Function>());
+
+ return scope.Escape(loader_exports);
+}
+
+MaybeLocal<Value> Realm::BootstrapNode() {
+ EscapableHandleScope scope(isolate_);
+
+ // Arguments must match the parameters specified in
+ // BuiltinLoader::LookupAndCompile().
+ // process, require, internalBinding, primordials
+ std::vector<Local<Value>> node_args = {process_object(),
+ builtin_module_require(),
+ internal_binding_loader(),
+ primordials()};
+
+ MaybeLocal<Value> result =
+ ExecuteBootstrapper("internal/bootstrap/node", &node_args);
+
+ if (result.IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+
+ if (!env_->no_browser_globals()) {
+ result = ExecuteBootstrapper("internal/bootstrap/browser", &node_args);
+
+ if (result.IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+ }
+
+ // TODO(joyeecheung): skip these in the snapshot building for workers.
+ auto thread_switch_id =
+ env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
+ : "internal/bootstrap/switches/is_not_main_thread";
+ result = ExecuteBootstrapper(thread_switch_id, &node_args);
+
+ if (result.IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+
+ auto process_state_switch_id =
+ env_->owns_process_state()
+ ? "internal/bootstrap/switches/does_own_process_state"
+ : "internal/bootstrap/switches/does_not_own_process_state";
+ result = ExecuteBootstrapper(process_state_switch_id, &node_args);
+
+ if (result.IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+
+ Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
+ Local<Object> env_var_proxy;
+ if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
+ process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
+ return MaybeLocal<Value>();
+ }
+
+ return scope.EscapeMaybe(result);
+}
+
+MaybeLocal<Value> Realm::RunBootstrapping() {
+ EscapableHandleScope scope(isolate_);
+
+ CHECK(!has_run_bootstrapping_code());
+
+ if (BootstrapInternalLoaders().IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+
+ Local<Value> result;
+ if (!BootstrapNode().ToLocal(&result)) {
+ return MaybeLocal<Value>();
+ }
+
+ DoneBootstrapping();
+
+ return scope.Escape(result);
+}
+
+void Realm::DoneBootstrapping() {
+ has_run_bootstrapping_code_ = true;
+
+ // Make sure that no request or handle is created during bootstrap -
+ // if necessary those should be done in pre-execution.
+ // Usually, doing so would trigger the checks present in the ReqWrap and
+ // HandleWrap classes, so this is only a consistency check.
+
+ // TODO(legendecas): track req_wrap and handle_wrap by realms instead of
+ // environments.
+ CHECK(env_->req_wrap_queue()->IsEmpty());
+ CHECK(env_->handle_wrap_queue()->IsEmpty());
+
+ // TODO(legendecas): track base object count by realms.
+ env_->set_base_object_created_by_bootstrap(env_->base_object_count());
+}
+
+} // namespace node
diff --git a/src/node_realm.h b/src/node_realm.h
new file mode 100644
index 00000000000..afaaa66c9bd
--- /dev/null
+++ b/src/node_realm.h
@@ -0,0 +1,100 @@
+#ifndef SRC_NODE_REALM_H_
+#define SRC_NODE_REALM_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include <v8.h>
+#include "env_properties.h"
+#include "memory_tracker.h"
+#include "node_snapshotable.h"
+
+namespace node {
+
+struct RealmSerializeInfo {
+ std::vector<PropInfo> persistent_values;
+
+ SnapshotIndex context;
+ friend std::ostream& operator<<(std::ostream& o, const RealmSerializeInfo& i);
+};
+
+/**
+ * node::Realm is a container for a set of JavaScript objects and functions
+ * that associated with a particular global environment.
+ *
+ * An ECMAScript realm (https://tc39.es/ecma262/#sec-code-realms) representing
+ * a global environment in which script is run. Each ECMAScript realm comes
+ * with a global object and a set of intrinsic objects. An ECMAScript realm has
+ * a [[HostDefined]] field, which contains the node::Realm object.
+ *
+ * Realm can be a principal realm or a synthetic realm. A principal realm is
+ * created with an Environment as its principal global environment to evaluate
+ * scripts. A synthetic realm is created with JS APIs like ShadowRealm.
+ *
+ * Native bindings and builtin modules can be evaluated in either a principal
+ * realm or a synthetic realm.
+ */
+class Realm : public MemoryRetainer {
+ public:
+ static inline Realm* GetCurrent(v8::Isolate* isolate);
+ static inline Realm* GetCurrent(v8::Local<v8::Context> context);
+ static inline Realm* GetCurrent(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+ template <typename T>
+ static inline Realm* GetCurrent(const v8::PropertyCallbackInfo<T>& info);
+
+ Realm(Environment* env,
+ v8::Local<v8::Context> context,
+ const RealmSerializeInfo* realm_info);
+ ~Realm() = default;
+
+ Realm(const Realm&) = delete;
+ Realm& operator=(const Realm&) = delete;
+ Realm(Realm&&) = delete;
+ Realm& operator=(Realm&&) = delete;
+
+ SET_MEMORY_INFO_NAME(Realm)
+ SET_SELF_SIZE(Realm);
+ void MemoryInfo(MemoryTracker* tracker) const override;
+
+ void CreateProperties();
+ RealmSerializeInfo Serialize(v8::SnapshotCreator* creator);
+ void DeserializeProperties(const RealmSerializeInfo* info);
+
+ v8::MaybeLocal<v8::Value> ExecuteBootstrapper(
+ const char* id, std::vector<v8::Local<v8::Value>>* arguments);
+ v8::MaybeLocal<v8::Value> BootstrapInternalLoaders();
+ v8::MaybeLocal<v8::Value> BootstrapNode();
+ v8::MaybeLocal<v8::Value> RunBootstrapping();
+
+ inline Environment* env() const;
+ inline v8::Isolate* isolate() const;
+ inline v8::Local<v8::Context> context() const;
+ inline bool has_run_bootstrapping_code() const;
+
+#define V(PropertyName, TypeName) \
+ inline v8::Local<TypeName> PropertyName() const; \
+ inline void set_##PropertyName(v8::Local<TypeName> value);
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
+#undef V
+
+ private:
+ void InitializeContext(v8::Local<v8::Context> context,
+ const RealmSerializeInfo* realm_info);
+ void DoneBootstrapping();
+
+ Environment* env_;
+ // Shorthand for isolate pointer.
+ v8::Isolate* isolate_;
+ v8::Global<v8::Context> context_;
+ bool has_run_bootstrapping_code_ = false;
+
+#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName##_;
+ PER_REALM_STRONG_PERSISTENT_VALUES(V)
+#undef V
+};
+
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_NODE_REALM_H_
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index 98660f7d171..859417d9fb5 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -71,6 +71,69 @@ std::ostream& operator<<(std::ostream& output,
return output;
}
+std::ostream& operator<<(std::ostream& output,
+ const std::vector<PropInfo>& vec) {
+ output << "{\n";
+ for (const auto& info : vec) {
+ output << " " << info << ",\n";
+ }
+ output << "}";
+ return output;
+}
+
+std::ostream& operator<<(std::ostream& output, const PropInfo& info) {
+ output << "{ \"" << info.name << "\", " << std::to_string(info.id) << ", "
+ << std::to_string(info.index) << " }";
+ return output;
+}
+
+std::ostream& operator<<(std::ostream& output,
+ const std::vector<std::string>& vec) {
+ output << "{\n";
+ for (const auto& info : vec) {
+ output << " \"" << info << "\",\n";
+ }
+ output << "}";
+ return output;
+}
+
+std::ostream& operator<<(std::ostream& output, const RealmSerializeInfo& i) {
+ output << "{\n"
+ << "// -- persistent_values begins --\n"
+ << i.persistent_values << ",\n"
+ << "// -- persistent_values ends --\n"
+ << i.context << ", // context\n"
+ << "}";
+ return output;
+}
+
+std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
+ output << "{\n"
+ << "// -- native_objects begins --\n"
+ << i.native_objects << ",\n"
+ << "// -- native_objects ends --\n"
+ << "// -- builtins begins --\n"
+ << i.builtins << ",\n"
+ << "// -- builtins ends --\n"
+ << "// -- async_hooks begins --\n"
+ << i.async_hooks << ",\n"
+ << "// -- async_hooks ends --\n"
+ << i.tick_info << ", // tick_info\n"
+ << i.immediate_info << ", // immediate_info\n"
+ << "// -- performance_state begins --\n"
+ << i.performance_state << ",\n"
+ << "// -- performance_state ends --\n"
+ << i.exiting << ", // exiting\n"
+ << i.stream_base_state << ", // stream_base_state\n"
+ << i.should_abort_on_uncaught_toggle
+ << ", // should_abort_on_uncaught_toggle\n"
+ << "// -- principal_realm begins --\n"
+ << i.principal_realm << ",\n"
+ << "// -- principal_realm ends --\n"
+ << "}";
+ return output;
+}
+
class FileIO {
public:
explicit FileIO(FILE* file)
@@ -638,6 +701,30 @@ size_t FileWriter::Write(const IsolateDataSerializeInfo& data) {
}
template <>
+RealmSerializeInfo FileReader::Read() {
+ per_process::Debug(DebugCategory::MKSNAPSHOT, "Read<RealmSerializeInfo>()\n");
+ RealmSerializeInfo result;
+ result.persistent_values = ReadVector<PropInfo>();
+ result.context = Read<SnapshotIndex>();
+ return result;
+}
+
+template <>
+size_t FileWriter::Write(const RealmSerializeInfo& data) {
+ if (is_debug) {
+ std::string str = ToStr(data);
+ Debug("\nWrite<RealmSerializeInfo>() %s\n", str.c_str());
+ }
+
+ // Use += here to ensure order of evaluation.
+ size_t written_total = WriteVector<PropInfo>(data.persistent_values);
+ written_total += Write<SnapshotIndex>(data.context);
+
+ Debug("Write<RealmSerializeInfo>() wrote %d bytes\n", written_total);
+ return written_total;
+}
+
+template <>
EnvSerializeInfo FileReader::Read() {
per_process::Debug(DebugCategory::MKSNAPSHOT, "Read<EnvSerializeInfo>()\n");
EnvSerializeInfo result;
@@ -651,8 +738,7 @@ EnvSerializeInfo FileReader::Read() {
result.exiting = Read<AliasedBufferIndex>();
result.stream_base_state = Read<AliasedBufferIndex>();
result.should_abort_on_uncaught_toggle = Read<AliasedBufferIndex>();
- result.persistent_values = ReadVector<PropInfo>();
- result.context = Read<SnapshotIndex>();
+ result.principal_realm = Read<RealmSerializeInfo>();
return result;
}
@@ -675,8 +761,7 @@ size_t FileWriter::Write(const EnvSerializeInfo& data) {
written_total += Write<AliasedBufferIndex>(data.stream_base_state);
written_total +=
Write<AliasedBufferIndex>(data.should_abort_on_uncaught_toggle);
- written_total += WriteVector<PropInfo>(data.persistent_values);
- written_total += Write<SnapshotIndex>(data.context);
+ written_total += Write<RealmSerializeInfo>(data.principal_realm);
Debug("Write<EnvSerializeInfo>() wrote %d bytes\n", written_total);
return written_total;
@@ -1083,7 +1168,7 @@ int SnapshotBuilder::Generate(SnapshotData* out,
{});
// Run scripts in lib/internal/bootstrap/
- if (env->RunBootstrapping().IsEmpty()) {
+ if (env->principal_realm()->RunBootstrapping().IsEmpty()) {
return BOOTSTRAP_ERROR;
}
// If --build-snapshot is true, lib/internal/main/mksnapshot.js would be
diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h
index d12aec586c7..6ff8c148988 100644
--- a/src/node_snapshotable.h
+++ b/src/node_snapshotable.h
@@ -14,6 +14,14 @@ struct EnvSerializeInfo;
struct SnapshotData;
class ExternalReferenceRegistry;
+using SnapshotIndex = size_t;
+
+struct PropInfo {
+ std::string name; // name for debugging
+ uint32_t id; // In the list - in case there are any empty entries
+ SnapshotIndex index; // In the snapshot
+};
+
#define SERIALIZABLE_OBJECT_TYPES(V) \
V(fs_binding_data, fs::BindingData) \
V(v8_binding_data, v8_utils::BindingData) \