From 81d9cdb8cd5109f1beadf78558ff9e37b4c63473 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Wed, 31 Aug 2022 22:41:42 +0800 Subject: [PATCH] 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 Reviewed-By: James M Snell --- node.gyp | 4 + src/api/environment.cc | 11 +- src/base_object-inl.h | 6 + src/base_object.h | 5 +- src/env-inl.h | 37 +-- src/env.cc | 209 +++---------- src/env.h | 488 +++---------------------------- src/env_properties.h | 433 +++++++++++++++++++++++++++ src/node.cc | 156 +--------- src/node_context_data.h | 7 +- src/node_contextify.cc | 2 +- src/node_internals.h | 4 - src/node_main_instance.cc | 4 +- src/node_process.h | 3 +- src/node_process_object.cc | 22 +- src/node_realm-inl.h | 62 ++++ src/node_realm.cc | 308 +++++++++++++++++++ src/node_realm.h | 100 +++++++ src/node_snapshotable.cc | 95 +++++- src/node_snapshotable.h | 8 + test/pummel/test-heapdump-env.js | 8 +- 21 files changed, 1142 insertions(+), 830 deletions(-) create mode 100644 src/env_properties.h create mode 100644 src/node_realm-inl.h create mode 100644 src/node_realm.cc create mode 100644 src/node_realm.h diff --git a/node.gyp b/node.gyp index 1570d27d26bba6..05b7e6239d730d 100644 --- a/node.gyp +++ b/node.gyp @@ -512,6 +512,7 @@ 'src/node_process_events.cc', 'src/node_process_methods.cc', 'src/node_process_object.cc', + 'src/node_realm.cc', 'src/node_report.cc', 'src/node_report_module.cc', 'src/node_report_utils.cc', @@ -570,6 +571,7 @@ 'src/connection_wrap.h', 'src/debug_utils.h', 'src/debug_utils-inl.h', + 'src/env_properties.h', 'src/env.h', 'src/env-inl.h', 'src/handle_wrap.h', @@ -617,6 +619,8 @@ 'src/node_platform.h', 'src/node_process.h', 'src/node_process-inl.h', + 'src/node_realm.h', + 'src/node_realm-inl.h', 'src/node_report.h', 'src/node_revert.h', 'src/node_root_certs.h', diff --git a/src/api/environment.cc b/src/api/environment.cc index 53581405bac712..9049b4617b9b18 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 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> args = {env->process_object(), - env->builtin_module_require()}; - return ExecuteBootstrapper(env, name.c_str(), &args); + std::vector> 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 a246c2502b48e1..ceb7a7f4a6534e 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -32,6 +32,12 @@ namespace node { +// static +v8::Local 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 6f072bf5ec0357..e12c9b5d1e4506 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -31,6 +31,7 @@ namespace node { class Environment; +class IsolateData; template class BaseObjectPtrImpl; @@ -111,8 +112,10 @@ class BaseObject : public MemoryRetainer { // a BaseObjectPtr to this object. inline void Detach(); - static v8::Local GetConstructorTemplate( + static inline v8::Local GetConstructorTemplate( Environment* env); + static v8::Local 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 428e517aedb1e8..28fb3fda0dba1d 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 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 Environment::PropertyName() const { \ - return PersistentToLocal::Strong(PropertyName##_); \ + DCHECK_NOT_NULL(principal_realm_); \ + return principal_realm_->PropertyName(); \ } \ inline void Environment::set_##PropertyName(v8::Local 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 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 9bc9346e653fe1..9d3602d24aae35 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 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 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 Environment::release_managed_buffer( return bs; } -void Environment::CreateProperties() { - HandleScope handle_scope(isolate_); - Local ctx = context(); - - { - Context::Scope context_scope(ctx); - Local 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 per_context_bindings = - GetPerContextExports(ctx).ToLocalChecked(); - Local primordials = - per_context_bindings->Get(ctx, primordials_string()).ToLocalChecked(); - CHECK(primordials->IsObject()); - set_primordials(primordials.As()); - - Local prototype_string = - FIXED_ONE_BYTE_STRING(isolate(), "prototype"); - -#define V(EnvPropertyName, PrimordialsPropertyName) \ - { \ - Local ctor = \ - primordials.As() \ - ->Get(ctx, \ - FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName)) \ - .ToLocalChecked(); \ - CHECK(ctor->IsObject()); \ - Local prototype = \ - ctor.As()->Get(ctx, prototype_string).ToLocalChecked(); \ - CHECK(prototype->IsObject()); \ - set_##EnvPropertyName(prototype.As()); \ - } - - 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 process_object = - node::CreateProcessObject(this).FromMaybe(Local()); - set_process_object(process_object); -} - std::string GetExecPath(const std::vector& 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, const EnvSerializeInfo* env_info) { - context_.Reset(context->GetIsolate(), context); - AssignToContext(context, ContextInfo("")); + principal_realm_ = std::make_unique( + 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, } Environment::~Environment() { + HandleScope handle_scope(isolate()); + Local 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