From dde0e9e4609de0cc0fddcc0830e493aec61ae307 Mon Sep 17 00:00:00 2001 From: legendecas Date: Sat, 30 Jul 2022 22:15:24 +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. --- 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 | 211 +++---------- src/env.h | 487 +++---------------------------- src/env_properties.h | 432 +++++++++++++++++++++++++++ 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 | 66 +++++ src/node_realm.cc | 310 ++++++++++++++++++++ src/node_realm.h | 96 ++++++ src/node_snapshotable.cc | 95 +++++- src/node_snapshotable.h | 15 + test/pummel/test-heapdump-env.js | 8 +- 21 files changed, 1151 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 7971fad478f5e5..48b2acf0e1d559 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 a59f70e8139890..94315d736cde9c 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 ff618f08b5d394..f836d1a0d3cff9 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 c0c9f17cdc71aa..583fe4edeaff48 100644 --- a/src/env.cc +++ b/src/env.cc @@ -443,7 +443,13 @@ void IsolateData::CreateProperties() { NODE_ASYNC_PROVIDER_TYPES(V) #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); + + // TODO(legendecas): eagerly create more per-isolate templates. } IsolateData::IsolateData(Isolate* isolate, @@ -496,6 +502,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; @@ -511,10 +521,12 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() { } void Environment::AssignToContext(Local context, + Realm* realm, const ContextInfo& info) { ContextEmbedderTag::TagNodeContext(context); context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment, this); + context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm); // Used to retrieve bindings context->SetAlignedPointerInEmbedderData( ContextEmbedderIndex::kBindingListIndex, &(this->bindings_)); @@ -582,56 +594,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); @@ -767,12 +729,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( + isolate_data_, 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) { @@ -797,6 +758,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 @@ -804,9 +768,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; @@ -816,8 +779,8 @@ Environment::~Environment() { #endif Local