From 730654ca5c5241a60e635c3afc744e387be3d29e Mon Sep 17 00:00:00 2001 From: legendecas Date: Fri, 12 Aug 2022 00:42:10 +0800 Subject: [PATCH] fixup! src: introduce node::Realm --- src/base_object-inl.h | 6 ++++++ src/base_object.h | 5 ++++- src/env-inl.h | 3 ++- src/env.cc | 38 +++++++++++++++----------------------- src/env.h | 6 +++++- src/node_realm.cc | 8 ++++++-- src/node_realm.h | 16 ++++++++++++++++ 7 files changed, 54 insertions(+), 28 deletions(-) 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 842f763a56d75c..40f3880b157aeb 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -31,6 +31,7 @@ namespace node { class Environment; +class IsolateData; template class BaseObjectPtrImpl; @@ -109,8 +110,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 7341b19c78875d..34b600d315dada 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -620,11 +620,12 @@ inline bool Environment::has_run_bootstrapping_code() const { inline void Environment::DoneBootstrapping() { CHECK(has_run_bootstrapping_code()); - // TODO(legendecas): distinguish base objects with realms. // 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. + + // TODO(legendecas): track base objects by realms instead of environments. base_object_created_by_bootstrap_ = base_object_count_; } diff --git a/src/env.cc b/src/env.cc index be0bcc06e21320..1a15c8c6b6390a 100644 --- a/src/env.cc +++ b/src/env.cc @@ -428,7 +428,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, @@ -578,17 +584,6 @@ std::unique_ptr Environment::release_managed_buffer( return bs; } -void Environment::CreateProperties() { - HandleScope handle_scope(isolate_); - - Local templ = FunctionTemplate::New(isolate()); - templ->InstanceTemplate()->SetInternalFieldCount( - BaseObject::kInternalFieldCount); - templ->Inherit(BaseObject::GetConstructorTemplate(this)); - - set_binding_data_ctor_template(templ); -} - std::string GetExecPath(const std::vector& argv) { char exec_path_buf[2 * PATH_MAX]; size_t exec_path_len = sizeof(exec_path_buf); @@ -725,15 +720,10 @@ Environment::Environment(IsolateData* isolate_data, void Environment::InitializeMainContext(Local context, const EnvSerializeInfo* env_info) { principal_realm_ = std::make_unique( - isolate_data_, - this, - context, - env_info == nullptr ? nullptr : &env_info->principal_realm); + isolate_data_, this, context, MAYBE_FIELD_PTR(env_info, principal_realm)); AssignToContext(context, ContextInfo("")); if (env_info != nullptr) { DeserializeProperties(env_info); - } else { - CreateProperties(); } if (!options_->force_async_hooks_checks) { @@ -2015,12 +2005,14 @@ bool BaseObject::IsRootNode() const { return !persistent_handle_.IsWeak(); } -Local BaseObject::GetConstructorTemplate(Environment* env) { - Local tmpl = env->base_object_ctor_template(); +Local BaseObject::GetConstructorTemplate( + IsolateData* isolate_data) { + Local 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 a4eed49b35f6c3..8cab4ba900ce68 100644 --- a/src/env.h +++ b/src/env.h @@ -590,6 +590,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; @@ -604,7 +609,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(); diff --git a/src/node_realm.cc b/src/node_realm.cc index e132b9715dff78..2181a98d5cc54c 100644 --- a/src/node_realm.cc +++ b/src/node_realm.cc @@ -41,6 +41,9 @@ void Realm::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField(#PropertyName, PropertyName()); PER_REALM_STRONG_PERSISTENT_VALUES(V) #undef V + + tracker->TrackField("isolate_data", isolate_data_); + tracker->TrackField("env", env_); } void Realm::CreateProperties() { @@ -280,12 +283,13 @@ MaybeLocal Realm::RunBootstrapping() { return MaybeLocal(); } - // TODO(legendecas): distinguish req_wrap and handle_wrap with realms. - // 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()); diff --git a/src/node_realm.h b/src/node_realm.h index 5d6c34df53f972..e2a6b2acd188b5 100644 --- a/src/node_realm.h +++ b/src/node_realm.h @@ -10,6 +10,22 @@ namespace node { +/** + * 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);