From cd2001d42eb7601bd0b1687f8f2a3270b8fad7e8 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Wed, 8 Feb 2023 13:51:35 +0800 Subject: [PATCH] src: per-realm binding data Binding data is inherited from BaseObject and created in a specific realm. They need to be tracked on a per-realm basis so that they can be released properly when a realm is disposed. --- src/README.md | 10 +++---- src/base_object-inl.h | 6 +++- src/env-inl.h | 42 ---------------------------- src/env.cc | 4 +-- src/env.h | 21 -------------- src/node_blob.cc | 22 +++++++-------- src/node_blob.h | 2 +- src/node_context_data.h | 6 ++-- src/node_file-inl.h | 2 +- src/node_file.cc | 55 +++++++++++++++++++------------------ src/node_file.h | 2 +- src/node_http2.cc | 11 ++++---- src/node_http2_state.h | 38 ++++++++++++------------- src/node_http_parser.cc | 10 +++---- src/node_process.h | 2 +- src/node_process_methods.cc | 24 ++++++++-------- src/node_realm-inl.h | 48 ++++++++++++++++++++++++++++++++ src/node_realm.cc | 1 + src/node_realm.h | 22 +++++++++++++++ src/node_snapshotable.cc | 5 ++-- src/node_snapshotable.h | 2 +- src/node_stat_watcher.cc | 3 +- src/node_util.cc | 20 ++++++-------- src/node_util.h | 4 +-- src/node_v8.cc | 38 +++++++++++++------------ src/node_v8.h | 2 +- 26 files changed, 206 insertions(+), 196 deletions(-) diff --git a/src/README.md b/src/README.md index 1b2b8a951d8852..58718935820ada 100644 --- a/src/README.md +++ b/src/README.md @@ -482,7 +482,7 @@ Which explains that the unregistered external reference is Some internal bindings, such as the HTTP parser, maintain internal state that only affects that particular binding. In that case, one common way to store -that state is through the use of `Environment::AddBindingData`, which gives +that state is through the use of `Realm::AddBindingData`, which gives binding functions access to an object for storing such state. That object is always a [`BaseObject`][]. @@ -507,7 +507,7 @@ class BindingData : public BaseObject { // Available for binding functions, e.g. the HTTP Parser constructor: static void New(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); new Parser(binding_data, args.This()); } @@ -517,12 +517,12 @@ void InitializeHttpParser(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); BindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; - Local t = env->NewFunctionTemplate(Parser::New); + Local t = NewFunctionTemplate(realm->isolate(), Parser::New); ... } ``` diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 675a472dab48f1..77b7e35288647c 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -33,7 +33,11 @@ namespace node { BaseObject::BaseObject(Environment* env, v8::Local object) - : BaseObject(env->principal_realm(), object) {} + : BaseObject(env->principal_realm(), object) { + // Check the shorthand is only used in the principal realm. + DCHECK_EQ(object->GetCreationContextChecked(), + env->principal_realm()->context()); +} // static v8::Local BaseObject::GetConstructorTemplate( diff --git a/src/env-inl.h b/src/env-inl.h index 0ca495bd58df6f..d84d28c7065822 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -201,48 +201,6 @@ inline Environment* Environment::GetCurrent( return GetCurrent(info.GetIsolate()->GetCurrentContext()); } -template -inline T* Environment::GetBindingData(const v8::PropertyCallbackInfo& info) { - return GetBindingData(info.GetIsolate()->GetCurrentContext()); -} - -template -inline T* Environment::GetBindingData( - const v8::FunctionCallbackInfo& info) { - return GetBindingData(info.GetIsolate()->GetCurrentContext()); -} - -template -inline T* Environment::GetBindingData(v8::Local context) { - BindingDataStore* map = static_cast( - context->GetAlignedPointerFromEmbedderData( - ContextEmbedderIndex::kBindingListIndex)); - DCHECK_NOT_NULL(map); - auto it = map->find(T::type_name); - if (UNLIKELY(it == map->end())) return nullptr; - T* result = static_cast(it->second.get()); - DCHECK_NOT_NULL(result); - DCHECK_EQ(result->env(), GetCurrent(context)); - return result; -} - -template -inline T* Environment::AddBindingData( - v8::Local context, - v8::Local target) { - DCHECK_EQ(GetCurrent(context), this); - // This won't compile if T is not a BaseObject subclass. - BaseObjectPtr item = MakeDetachedBaseObject(this, target); - BindingDataStore* map = static_cast( - context->GetAlignedPointerFromEmbedderData( - ContextEmbedderIndex::kBindingListIndex)); - DCHECK_NOT_NULL(map); - auto result = map->emplace(T::type_name, item); - CHECK(result.second); - DCHECK_EQ(GetBindingData(context), item.get()); - return item.get(); -} - inline v8::Isolate* Environment::isolate() const { return isolate_; } diff --git a/src/env.cc b/src/env.cc index 692a344703a196..8371c00302b416 100644 --- a/src/env.cc +++ b/src/env.cc @@ -545,7 +545,8 @@ void Environment::AssignToContext(Local context, context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm); // Used to retrieve bindings context->SetAlignedPointerInEmbedderData( - ContextEmbedderIndex::kBindingListIndex, &(this->bindings_)); + ContextEmbedderIndex::kBindingDataStoreIndex, + realm->binding_data_store()); // ContextifyContexts will update this to a pointer to the native object. context->SetAlignedPointerInEmbedderData( @@ -1018,7 +1019,6 @@ MaybeLocal Environment::RunSnapshotDeserializeMain() const { void Environment::RunCleanup() { started_cleanup_ = true; TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunCleanup"); - bindings_.clear(); // Only BaseObject's cleanups are registered as per-realm cleanup hooks now. // Defer the BaseObject cleanup after handles are cleaned up. CleanupHandles(); diff --git a/src/env.h b/src/env.h index c2eb764e740400..bff108373789ce 100644 --- a/src/env.h +++ b/src/env.h @@ -587,25 +587,6 @@ class Environment : public MemoryRetainer { static inline Environment* GetCurrent( const v8::PropertyCallbackInfo& info); - // Methods created using SetMethod(), SetPrototypeMethod(), etc. inside - // this scope can access the created T* object using - // GetBindingData(args) later. - template - T* AddBindingData(v8::Local context, - v8::Local target); - template - static inline T* GetBindingData(const v8::PropertyCallbackInfo& info); - template - static inline T* GetBindingData( - const v8::FunctionCallbackInfo& info); - template - static inline T* GetBindingData(v8::Local context); - - typedef std::unordered_map< - FastStringKey, - BaseObjectPtr, - FastStringKey::Hash> BindingDataStore; - // Create an Environment without initializing a main Context. Use // InitializeMainContext() to initialize a main context for it. Environment(IsolateData* isolate_data, @@ -1134,8 +1115,6 @@ class Environment : public MemoryRetainer { void RequestInterruptFromV8(); static void CheckImmediate(uv_check_t* handle); - BindingDataStore bindings_; - CleanupQueue cleanup_queue_; bool started_cleanup_ = false; diff --git a/src/node_blob.cc b/src/node_blob.cc index f35a44c6b7958d..a9dfce75c7a1ef 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -37,10 +37,11 @@ void Blob::Initialize( Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); BlobBindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; SetMethod(context, target, "createBlob", New); @@ -238,8 +239,7 @@ std::unique_ptr Blob::CloneForMessaging() const { void Blob::StoreDataObject(const v8::FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - BlobBindingData* binding_data = - Environment::GetBindingData(args); + BlobBindingData* binding_data = Realm::GetBindingData(args); CHECK(args[0]->IsString()); // ID key CHECK(Blob::HasInstance(env, args[1])); // Blob @@ -262,8 +262,7 @@ void Blob::StoreDataObject(const v8::FunctionCallbackInfo& args) { } void Blob::RevokeDataObject(const v8::FunctionCallbackInfo& args) { - BlobBindingData* binding_data = - Environment::GetBindingData(args); + BlobBindingData* binding_data = Realm::GetBindingData(args); Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsString()); // ID key @@ -274,8 +273,7 @@ void Blob::RevokeDataObject(const v8::FunctionCallbackInfo& args) { } void Blob::GetDataObject(const v8::FunctionCallbackInfo& args) { - BlobBindingData* binding_data = - Environment::GetBindingData(args); + BlobBindingData* binding_data = Realm::GetBindingData(args); Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsString()); @@ -430,8 +428,8 @@ BlobBindingData::StoredDataObject::StoredDataObject( length(length_), type(type_) {} -BlobBindingData::BlobBindingData(Environment* env, Local wrap) - : SnapshotableObject(env, wrap, type_int) { +BlobBindingData::BlobBindingData(Realm* realm, Local wrap) + : SnapshotableObject(realm, wrap, type_int) { MakeWeak(); } @@ -467,9 +465,9 @@ void BlobBindingData::Deserialize(Local context, InternalFieldInfoBase* info) { DCHECK_EQ(index, BaseObject::kEmbedderType); HandleScope scope(context->GetIsolate()); - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); BlobBindingData* binding = - env->AddBindingData(context, holder); + realm->AddBindingData(context, holder); CHECK_NOT_NULL(binding); } diff --git a/src/node_blob.h b/src/node_blob.h index f0340f313bde6f..d3426d05d09dcd 100644 --- a/src/node_blob.h +++ b/src/node_blob.h @@ -141,7 +141,7 @@ class FixedSizeBlobCopyJob : public AsyncWrap, public ThreadPoolWork { class BlobBindingData : public SnapshotableObject { public: - explicit BlobBindingData(Environment* env, v8::Local wrap); + explicit BlobBindingData(Realm* realm, v8::Local wrap); using InternalFieldInfo = InternalFieldInfoBase; diff --git a/src/node_context_data.h b/src/node_context_data.h index 4278a17f4b6ad0..009d46c34dc4ef 100644 --- a/src/node_context_data.h +++ b/src/node_context_data.h @@ -24,8 +24,8 @@ namespace node { #define NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX 34 #endif -#ifndef NODE_BINDING_LIST -#define NODE_BINDING_LIST_INDEX 35 +#ifndef NODE_BINDING_DATA_STORE_INDEX +#define NODE_BINDING_DATA_STORE_INDEX 35 #endif #ifndef NODE_CONTEXT_ALLOW_CODE_GENERATION_FROM_STRINGS_INDEX @@ -51,7 +51,7 @@ enum ContextEmbedderIndex { kEnvironment = NODE_CONTEXT_EMBEDDER_DATA_INDEX, kSandboxObject = NODE_CONTEXT_SANDBOX_OBJECT_INDEX, kAllowWasmCodeGeneration = NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX, - kBindingListIndex = NODE_BINDING_LIST_INDEX, + kBindingDataStoreIndex = NODE_BINDING_DATA_STORE_INDEX, kAllowCodeGenerationFromStrings = NODE_CONTEXT_ALLOW_CODE_GENERATION_FROM_STRINGS_INDEX, kContextifyContext = NODE_CONTEXT_CONTEXTIFY_CONTEXT_INDEX, diff --git a/src/node_file-inl.h b/src/node_file-inl.h index adce4cab53eba6..2ba5906d614f1c 100644 --- a/src/node_file-inl.h +++ b/src/node_file-inl.h @@ -277,7 +277,7 @@ FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo& args, return Unwrap(value.As()); } - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); if (value->StrictEquals(env->fs_use_promises_symbol())) { if (use_bigint) { diff --git a/src/node_file.cc b/src/node_file.cc index 49ed96eca05416..f742d3b56c0b5b 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -253,7 +253,7 @@ FileHandle* FileHandle::New(BindingData* binding_data, } void FileHandle::New(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); CHECK(args.IsConstructCall()); CHECK(args[0]->IsInt32()); @@ -313,7 +313,7 @@ BaseObjectPtr FileHandle::TransferData::Deserialize( Environment* env, v8::Local context, std::unique_ptr self) { - BindingData* bd = Environment::GetBindingData(context); + BindingData* bd = Realm::GetBindingData(context); if (bd == nullptr) return {}; int fd = fd_; @@ -708,7 +708,7 @@ void FSReqCallback::SetReturnValue(const FunctionCallbackInfo& args) { void NewFSReqCallback(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); new FSReqCallback(binding_data, args.This(), args[0]->IsTrue()); } @@ -1115,7 +1115,7 @@ static void InternalModuleStat(const FunctionCallbackInfo& args) { } static void Stat(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); const int argc = args.Length(); @@ -1148,7 +1148,7 @@ static void Stat(const FunctionCallbackInfo& args) { } static void LStat(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); const int argc = args.Length(); @@ -1182,7 +1182,7 @@ static void LStat(const FunctionCallbackInfo& args) { } static void FStat(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); const int argc = args.Length(); @@ -1214,7 +1214,7 @@ static void FStat(const FunctionCallbackInfo& args) { } static void StatFs(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); const int argc = args.Length(); @@ -1929,7 +1929,7 @@ static void Open(const FunctionCallbackInfo& args) { } static void OpenFileHandle(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); Environment* env = binding_data->env(); Isolate* isolate = env->isolate(); @@ -2619,29 +2619,31 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { file_handle_read_wrap_freelist); } -BindingData::BindingData(Environment* env, v8::Local wrap) - : SnapshotableObject(env, wrap, type_int), - stats_field_array(env->isolate(), kFsStatsBufferLength), - stats_field_bigint_array(env->isolate(), kFsStatsBufferLength), - statfs_field_array(env->isolate(), kFsStatFsBufferLength), - statfs_field_bigint_array(env->isolate(), kFsStatFsBufferLength) { - wrap->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"), +BindingData::BindingData(Realm* realm, v8::Local wrap) + : SnapshotableObject(realm, wrap, type_int), + stats_field_array(realm->isolate(), kFsStatsBufferLength), + stats_field_bigint_array(realm->isolate(), kFsStatsBufferLength), + statfs_field_array(realm->isolate(), kFsStatFsBufferLength), + statfs_field_bigint_array(realm->isolate(), kFsStatFsBufferLength) { + Isolate* isolate = realm->isolate(); + Local context = realm->context(); + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "statValues"), stats_field_array.GetJSArray()) .Check(); - wrap->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"), + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"), stats_field_bigint_array.GetJSArray()) .Check(); - wrap->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "statFsValues"), + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "statFsValues"), statfs_field_array.GetJSArray()) .Check(); - wrap->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatFsValues"), + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "bigintStatFsValues"), statfs_field_bigint_array.GetJSArray()) .Check(); } @@ -2652,8 +2654,8 @@ void BindingData::Deserialize(Local context, InternalFieldInfoBase* info) { DCHECK_EQ(index, BaseObject::kEmbedderType); HandleScope scope(context->GetIsolate()); - Environment* env = Environment::GetCurrent(context); - BindingData* binding = env->AddBindingData(context, holder); + Realm* realm = Realm::GetCurrent(context); + BindingData* binding = realm->AddBindingData(context, holder); CHECK_NOT_NULL(binding); } @@ -2682,10 +2684,11 @@ void Initialize(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); Isolate* isolate = env->isolate(); BindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; SetMethod(context, target, "access", Access); diff --git a/src/node_file.h b/src/node_file.h index 5554ba7de51a2a..a4ca120d918127 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -56,7 +56,7 @@ constexpr size_t kFsStatFsBufferLength = class BindingData : public SnapshotableObject { public: - explicit BindingData(Environment* env, v8::Local wrap); + explicit BindingData(Realm* realm, v8::Local wrap); AliasedFloat64Array stats_field_array; AliasedBigInt64Array stats_field_bigint_array; diff --git a/src/node_http2.cc b/src/node_http2.cc index bb4057c9925676..91def097f00230 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -2579,7 +2579,7 @@ void HttpErrorString(const FunctionCallbackInfo& args) { // would be suitable, for instance, for creating the Base64 // output for an HTTP2-Settings header field. void PackSettings(const FunctionCallbackInfo& args) { - Http2State* state = Environment::GetBindingData(args); + Http2State* state = Realm::GetBindingData(args); args.GetReturnValue().Set(Http2Settings::Pack(state)); } @@ -2587,7 +2587,7 @@ void PackSettings(const FunctionCallbackInfo& args) { // default SETTINGS. RefreshDefaultSettings updates that TypedArray with the // default values. void RefreshDefaultSettings(const FunctionCallbackInfo& args) { - Http2State* state = Environment::GetBindingData(args); + Http2State* state = Realm::GetBindingData(args); Http2Settings::RefreshDefaults(state); } @@ -2670,7 +2670,7 @@ void Http2Session::RefreshState(const FunctionCallbackInfo& args) { // Constructor for new Http2Session instances. void Http2Session::New(const FunctionCallbackInfo& args) { - Http2State* state = Environment::GetBindingData(args); + Http2State* state = Realm::GetBindingData(args); Environment* env = state->env(); CHECK(args.IsConstructCall()); SessionType type = @@ -3198,11 +3198,12 @@ void Initialize(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); Isolate* isolate = env->isolate(); HandleScope handle_scope(isolate); - Http2State* const state = env->AddBindingData(context, target); + Http2State* const state = realm->AddBindingData(context, target); if (state == nullptr) return; #define SET_STATE_TYPEDARRAY(name, field) \ diff --git a/src/node_http2_state.h b/src/node_http2_state.h index 7cf40ff1017ca3..75a98bf476b2f7 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -83,34 +83,32 @@ namespace http2 { class Http2State : public BaseObject { public: - Http2State(Environment* env, v8::Local obj) - : BaseObject(env, obj), - root_buffer(env->isolate(), sizeof(http2_state_internal)), + Http2State(Realm* realm, v8::Local obj) + : BaseObject(realm, obj), + root_buffer(realm->isolate(), sizeof(http2_state_internal)), session_state_buffer( - env->isolate(), + realm->isolate(), offsetof(http2_state_internal, session_state_buffer), IDX_SESSION_STATE_COUNT, root_buffer), - stream_state_buffer( - env->isolate(), - offsetof(http2_state_internal, stream_state_buffer), - IDX_STREAM_STATE_COUNT, - root_buffer), - stream_stats_buffer( - env->isolate(), - offsetof(http2_state_internal, stream_stats_buffer), - IDX_STREAM_STATS_COUNT, - root_buffer), + stream_state_buffer(realm->isolate(), + offsetof(http2_state_internal, stream_state_buffer), + IDX_STREAM_STATE_COUNT, + root_buffer), + stream_stats_buffer(realm->isolate(), + offsetof(http2_state_internal, stream_stats_buffer), + IDX_STREAM_STATS_COUNT, + root_buffer), session_stats_buffer( - env->isolate(), + realm->isolate(), offsetof(http2_state_internal, session_stats_buffer), IDX_SESSION_STATS_COUNT, root_buffer), - options_buffer(env->isolate(), - offsetof(http2_state_internal, options_buffer), - IDX_OPTIONS_FLAGS + 1, - root_buffer), - settings_buffer(env->isolate(), + options_buffer(realm->isolate(), + offsetof(http2_state_internal, options_buffer), + IDX_OPTIONS_FLAGS + 1, + root_buffer), + settings_buffer(realm->isolate(), offsetof(http2_state_internal, settings_buffer), IDX_SETTINGS_COUNT + 1, root_buffer) {} diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 1bfa8e0faf23cf..0026f0c611930b 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -93,8 +93,7 @@ inline bool IsOWS(char c) { class BindingData : public BaseObject { public: - BindingData(Environment* env, Local obj) - : BaseObject(env, obj) {} + BindingData(Realm* realm, Local obj) : BaseObject(realm, obj) {} static constexpr FastStringKey type_name { "http_parser" }; @@ -531,7 +530,7 @@ class Parser : public AsyncWrap, public StreamListener { } static void New(const FunctionCallbackInfo& args) { - BindingData* binding_data = Environment::GetBindingData(args); + BindingData* binding_data = Realm::GetBindingData(args); new Parser(binding_data, args.This()); } @@ -1197,10 +1196,11 @@ void InitializeHttpParser(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); Isolate* isolate = env->isolate(); BindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; Local t = NewFunctionTemplate(isolate, Parser::New); diff --git a/src/node_process.h b/src/node_process.h index 8065378960887d..30f655dfc71f23 100644 --- a/src/node_process.h +++ b/src/node_process.h @@ -58,7 +58,7 @@ class BindingData : public SnapshotableObject { static constexpr EmbedderObjectType type_int = EmbedderObjectType::k_process_binding_data; - BindingData(Environment* env, v8::Local object); + BindingData(Realm* realm, v8::Local object); void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(BindingData) diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc index 06fd7313d7f01c..091845ab819d52 100644 --- a/src/node_process_methods.cc +++ b/src/node_process_methods.cc @@ -464,14 +464,13 @@ static void ReallyExit(const FunctionCallbackInfo& args) { namespace process { -BindingData::BindingData(Environment* env, v8::Local object) - : SnapshotableObject(env, object, type_int) { - Local ab = ArrayBuffer::New(env->isolate(), kBufferSize); - array_buffer_.Reset(env->isolate(), ab); - object - ->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "hrtimeBuffer"), - ab) +BindingData::BindingData(Realm* realm, v8::Local object) + : SnapshotableObject(realm, object, type_int) { + Isolate* isolate = realm->isolate(); + Local context = realm->context(); + Local ab = ArrayBuffer::New(isolate, kBufferSize); + array_buffer_.Reset(isolate, ab); + object->Set(context, FIXED_ONE_BYTE_STRING(isolate, "hrtimeBuffer"), ab) .ToChecked(); backing_store_ = ab->GetBackingStore(); } @@ -563,9 +562,9 @@ void BindingData::Deserialize(Local context, InternalFieldInfoBase* info) { DCHECK_EQ(index, BaseObject::kEmbedderType); v8::HandleScope scope(context->GetIsolate()); - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); // Recreate the buffer in the constructor. - BindingData* binding = env->AddBindingData(context, holder); + BindingData* binding = realm->AddBindingData(context, holder); CHECK_NOT_NULL(binding); } @@ -573,9 +572,10 @@ static void Initialize(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); BindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; binding_data->AddMethods(); diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h index 95a09dafac76e3..4042e1c927425c 100644 --- a/src/node_realm-inl.h +++ b/src/node_realm-inl.h @@ -46,6 +46,54 @@ inline bool Realm::has_run_bootstrapping_code() const { return has_run_bootstrapping_code_; } +// static +template +inline T* Realm::GetBindingData(const v8::PropertyCallbackInfo& info) { + return GetBindingData(info.GetIsolate()->GetCurrentContext()); +} + +// static +template +inline T* Realm::GetBindingData( + const v8::FunctionCallbackInfo& info) { + return GetBindingData(info.GetIsolate()->GetCurrentContext()); +} + +// static +template +inline T* Realm::GetBindingData(v8::Local context) { + BindingDataStore* map = + static_cast(context->GetAlignedPointerFromEmbedderData( + ContextEmbedderIndex::kBindingDataStoreIndex)); + DCHECK_NOT_NULL(map); + auto it = map->find(T::type_name); + if (UNLIKELY(it == map->end())) return nullptr; + T* result = static_cast(it->second.get()); + DCHECK_NOT_NULL(result); + DCHECK_EQ(result->env(), GetCurrent(context)); + return result; +} + +template +inline T* Realm::AddBindingData(v8::Local context, + v8::Local target) { + DCHECK_EQ(GetCurrent(context), this); + // This won't compile if T is not a BaseObject subclass. + BaseObjectPtr item = MakeDetachedBaseObject(this, target); + BindingDataStore* map = + static_cast(context->GetAlignedPointerFromEmbedderData( + ContextEmbedderIndex::kBindingDataStoreIndex)); + DCHECK_NOT_NULL(map); + auto result = map->emplace(T::type_name, item); + CHECK(result.second); + DCHECK_EQ(GetBindingData(context), item.get()); + return item.get(); +} + +inline BindingDataStore* Realm::binding_data_store() { + return &binding_data_store_; +} + template void Realm::ForEachBaseObject(T&& iterator) const { cleanup_queue_.ForEachBaseObject(std::forward(iterator)); diff --git a/src/node_realm.cc b/src/node_realm.cc index e0fcd3a0775973..9452e336ea789f 100644 --- a/src/node_realm.cc +++ b/src/node_realm.cc @@ -302,6 +302,7 @@ void Realm::DoneBootstrapping() { void Realm::RunCleanup() { TRACE_EVENT0(TRACING_CATEGORY_NODE1(realm), "RunCleanup"); + binding_data_store_.clear(); cleanup_queue_.Drain(); } diff --git a/src/node_realm.h b/src/node_realm.h index c97a3a3e9ae082..cf37fe31bdd6e4 100644 --- a/src/node_realm.h +++ b/src/node_realm.h @@ -4,6 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include +#include #include "cleanup_queue.h" #include "env_properties.h" #include "memory_tracker.h" @@ -20,6 +21,10 @@ struct RealmSerializeInfo { friend std::ostream& operator<<(std::ostream& o, const RealmSerializeInfo& i); }; +using BindingDataStore = std::unordered_map, + FastStringKey::Hash>; + /** * node::Realm is a container for a set of JavaScript objects and functions * that associated with a particular global environment. @@ -85,6 +90,21 @@ class Realm : public MemoryRetainer { inline v8::Local context() const; inline bool has_run_bootstrapping_code() const; + // Methods created using SetMethod(), SetPrototypeMethod(), etc. inside + // this scope can access the created T* object using + // GetBindingData(args) later. + template + T* AddBindingData(v8::Local context, + v8::Local target); + template + static inline T* GetBindingData(const v8::PropertyCallbackInfo& info); + template + static inline T* GetBindingData( + const v8::FunctionCallbackInfo& info); + template + static inline T* GetBindingData(v8::Local context); + inline BindingDataStore* binding_data_store(); + // The BaseObject count is a debugging helper that makes sure that there are // no memory leaks caused by BaseObjects staying alive longer than expected // (in particular, no circular BaseObjectPtr references). @@ -121,6 +141,8 @@ class Realm : public MemoryRetainer { int64_t base_object_count_ = 0; int64_t base_object_created_by_bootstrap_ = 0; + BindingDataStore binding_data_store_; + CleanupQueue cleanup_queue_; #define V(PropertyName, TypeName) v8::Global PropertyName##_; diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 1a19f44bec8198..e9d593a510915b 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1283,11 +1283,10 @@ ExitCode SnapshotBuilder::Generate(std::ostream& out, return exit_code; } -SnapshotableObject::SnapshotableObject(Environment* env, +SnapshotableObject::SnapshotableObject(Realm* realm, Local wrap, EmbedderObjectType type) - : BaseObject(env, wrap), type_(type) { -} + : BaseObject(realm, wrap), type_(type) {} std::string_view SnapshotableObject::GetTypeName() const { switch (type_) { diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index a825350806bfb0..3f4d0780131e20 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -98,7 +98,7 @@ struct InternalFieldInfoBase { // in the object. class SnapshotableObject : public BaseObject { public: - SnapshotableObject(Environment* env, + SnapshotableObject(Realm* realm, v8::Local wrap, EmbedderObjectType type); std::string_view GetTypeName() const; diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index de8c099ca58594..83b96e9dd2030e 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -97,8 +97,7 @@ void StatWatcher::Callback(uv_fs_poll_t* handle, void StatWatcher::New(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); - fs::BindingData* binding_data = - Environment::GetBindingData(args); + fs::BindingData* binding_data = Realm::GetBindingData(args); new StatWatcher(binding_data, args.This(), args[0]->IsTrue()); } diff --git a/src/node_util.cc b/src/node_util.cc index 39660130ba4d1a..0ce3af33c82466 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -179,20 +179,20 @@ void ArrayBufferViewHasBuffer(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(args[0].As()->HasBuffer()); } -WeakReference::WeakReference(Environment* env, +WeakReference::WeakReference(Realm* realm, Local object, Local target) - : WeakReference(env, object, target, 0) {} + : WeakReference(realm, object, target, 0) {} -WeakReference::WeakReference(Environment* env, +WeakReference::WeakReference(Realm* realm, Local object, Local target, uint64_t reference_count) - : SnapshotableObject(env, object, type_int), + : SnapshotableObject(realm, object, type_int), reference_count_(reference_count) { MakeWeak(); if (!target.IsEmpty()) { - target_.Reset(env->isolate(), target); + target_.Reset(realm->isolate(), target); if (reference_count_ == 0) { target_.SetWeak(); } @@ -245,17 +245,15 @@ void WeakReference::Deserialize(Local context, target = context->GetDataFromSnapshotOnce(weak_info->target) .ToLocalChecked(); } - new WeakReference(Environment::GetCurrent(context), - holder, - target, - weak_info->reference_count); + new WeakReference( + Realm::GetCurrent(context), holder, target, weak_info->reference_count); } void WeakReference::New(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Realm* realm = Realm::GetCurrent(args); CHECK(args.IsConstructCall()); CHECK(args[0]->IsObject()); - new WeakReference(env, args.This(), args[0].As()); + new WeakReference(realm, args.This(), args[0].As()); } void WeakReference::Get(const FunctionCallbackInfo& args) { diff --git a/src/node_util.h b/src/node_util.h index 9590842ae4764d..7192e080f2b08e 100644 --- a/src/node_util.h +++ b/src/node_util.h @@ -18,7 +18,7 @@ class WeakReference : public SnapshotableObject { static constexpr EmbedderObjectType type_int = EmbedderObjectType::k_util_weak_reference; - WeakReference(Environment* env, + WeakReference(Realm* realm, v8::Local object, v8::Local target); static void New(const v8::FunctionCallbackInfo& args); @@ -37,7 +37,7 @@ class WeakReference : public SnapshotableObject { }; private: - WeakReference(Environment* env, + WeakReference(Realm* realm, v8::Local object, v8::Local target, uint64_t reference_count); diff --git a/src/node_v8.cc b/src/node_v8.cc index 890f59eea673c5..f4900328cfe553 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -91,23 +91,24 @@ static const size_t kHeapCodeStatisticsPropertiesCount = HEAP_CODE_STATISTICS_PROPERTIES(V); #undef V -BindingData::BindingData(Environment* env, Local obj) - : SnapshotableObject(env, obj, type_int), - heap_statistics_buffer(env->isolate(), kHeapStatisticsPropertiesCount), - heap_space_statistics_buffer(env->isolate(), +BindingData::BindingData(Realm* realm, Local obj) + : SnapshotableObject(realm, obj, type_int), + heap_statistics_buffer(realm->isolate(), kHeapStatisticsPropertiesCount), + heap_space_statistics_buffer(realm->isolate(), kHeapSpaceStatisticsPropertiesCount), - heap_code_statistics_buffer(env->isolate(), + heap_code_statistics_buffer(realm->isolate(), kHeapCodeStatisticsPropertiesCount) { - obj->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "heapStatisticsBuffer"), + Local context = realm->context(); + obj->Set(context, + FIXED_ONE_BYTE_STRING(realm->isolate(), "heapStatisticsBuffer"), heap_statistics_buffer.GetJSArray()) .Check(); - obj->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "heapCodeStatisticsBuffer"), + obj->Set(context, + FIXED_ONE_BYTE_STRING(realm->isolate(), "heapCodeStatisticsBuffer"), heap_code_statistics_buffer.GetJSArray()) .Check(); - obj->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "heapSpaceStatisticsBuffer"), + obj->Set(context, + FIXED_ONE_BYTE_STRING(realm->isolate(), "heapSpaceStatisticsBuffer"), heap_space_statistics_buffer.GetJSArray()) .Check(); } @@ -130,8 +131,8 @@ void BindingData::Deserialize(Local context, InternalFieldInfoBase* info) { DCHECK_EQ(index, BaseObject::kEmbedderType); HandleScope scope(context->GetIsolate()); - Environment* env = Environment::GetCurrent(context); - BindingData* binding = env->AddBindingData(context, holder); + Realm* realm = Realm::GetCurrent(context); + BindingData* binding = realm->AddBindingData(context, holder); CHECK_NOT_NULL(binding); } @@ -168,7 +169,7 @@ void SetHeapSnapshotNearHeapLimit(const FunctionCallbackInfo& args) { } void UpdateHeapStatisticsBuffer(const FunctionCallbackInfo& args) { - BindingData* data = Environment::GetBindingData(args); + BindingData* data = Realm::GetBindingData(args); HeapStatistics s; args.GetIsolate()->GetHeapStatistics(&s); AliasedFloat64Array& buffer = data->heap_statistics_buffer; @@ -179,7 +180,7 @@ void UpdateHeapStatisticsBuffer(const FunctionCallbackInfo& args) { void UpdateHeapSpaceStatisticsBuffer(const FunctionCallbackInfo& args) { - BindingData* data = Environment::GetBindingData(args); + BindingData* data = Realm::GetBindingData(args); HeapSpaceStatistics s; Isolate* const isolate = args.GetIsolate(); CHECK(args[0]->IsUint32()); @@ -194,7 +195,7 @@ void UpdateHeapSpaceStatisticsBuffer(const FunctionCallbackInfo& args) { } void UpdateHeapCodeStatisticsBuffer(const FunctionCallbackInfo& args) { - BindingData* data = Environment::GetBindingData(args); + BindingData* data = Realm::GetBindingData(args); HeapCodeStatistics s; args.GetIsolate()->GetHeapCodeAndMetadataStatistics(&s); AliasedFloat64Array& buffer = data->heap_code_statistics_buffer; @@ -393,9 +394,10 @@ void Initialize(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); BindingData* const binding_data = - env->AddBindingData(context, target); + realm->AddBindingData(context, target); if (binding_data == nullptr) return; SetMethodNoSideEffect( diff --git a/src/node_v8.h b/src/node_v8.h index ecab454603b36b..2d95002bcfc473 100644 --- a/src/node_v8.h +++ b/src/node_v8.h @@ -18,7 +18,7 @@ struct InternalFieldInfoBase; namespace v8_utils { class BindingData : public SnapshotableObject { public: - BindingData(Environment* env, v8::Local obj); + BindingData(Realm* realm, v8::Local obj); using InternalFieldInfo = InternalFieldInfoBase;