diff options
author | Chengzhong Wu <legendecas@gmail.com> | 2022-08-31 17:41:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-31 17:41:42 +0300 |
commit | 81d9cdb8cd5109f1beadf78558ff9e37b4c63473 (patch) | |
tree | 4e1a457a544f18539ac0087c52cb5720ee8ef83e /src | |
parent | ad3c7bcb033ef98fe3452182c7e43727de069949 (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.cc | 11 | ||||
-rw-r--r-- | src/base_object-inl.h | 6 | ||||
-rw-r--r-- | src/base_object.h | 5 | ||||
-rw-r--r-- | src/env-inl.h | 37 | ||||
-rw-r--r-- | src/env.cc | 209 | ||||
-rw-r--r-- | src/env.h | 488 | ||||
-rw-r--r-- | src/env_properties.h | 433 | ||||
-rw-r--r-- | src/node.cc | 156 | ||||
-rw-r--r-- | src/node_context_data.h | 7 | ||||
-rw-r--r-- | src/node_contextify.cc | 2 | ||||
-rw-r--r-- | src/node_internals.h | 4 | ||||
-rw-r--r-- | src/node_main_instance.cc | 4 | ||||
-rw-r--r-- | src/node_process.h | 3 | ||||
-rw-r--r-- | src/node_process_object.cc | 22 | ||||
-rw-r--r-- | src/node_realm-inl.h | 62 | ||||
-rw-r--r-- | src/node_realm.cc | 308 | ||||
-rw-r--r-- | src/node_realm.h | 100 | ||||
-rw-r--r-- | src/node_snapshotable.cc | 95 | ||||
-rw-r--r-- | src/node_snapshotable.h | 8 |
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) \ |