From 540c37f6405d9c3395f051110a78103d31568c14 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 1 Apr 2023 04:16:55 +0200 Subject: [PATCH] src: make AliasedBuffers in the binding data weak The binding data holds references to the AliasedBuffers directly from their wrappers which already ensures that the AliasedBuffers won't be accessed when the wrappers are GC'ed. So we can just make the global references to the AliasedBuffers weak. This way we can simply deserialize the typed arrays when deserialize the binding data and avoid the extra Object::Set() calls. It also eliminates the caveat in the JS land where aliased buffers must be dynamically read from the binding. --- lib/fs.js | 16 +++---- lib/internal/encoding.js | 3 +- lib/v8.js | 10 +++-- src/aliased_buffer-inl.h | 38 ++++++++++++---- src/aliased_buffer.h | 12 ++++++ src/encoding_binding.cc | 39 +++++++++++------ src/encoding_binding.h | 10 +++-- src/node_file.cc | 93 ++++++++++++++++++++++++++-------------- src/node_file.h | 14 +++++- src/node_realm-inl.h | 8 ++-- src/node_realm.h | 5 ++- src/node_v8.cc | 69 +++++++++++++++++++---------- src/node_v8.h | 14 ++++-- 13 files changed, 230 insertions(+), 101 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 25534c838d0201..6f82f279f28526 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -59,9 +59,6 @@ const { const pathModule = require('path'); const { isArrayBufferView } = require('internal/util/types'); -// We need to get the statValues from the binding at the callsite since -// it's re-initialized after deserialization. - const binding = internalBinding('fs'); const { createBlobFromFilePath } = require('internal/blob'); @@ -78,7 +75,10 @@ const { uvException, } = require('internal/errors'); -const { FSReqCallback } = binding; +const { + FSReqCallback, + statValues, +} = binding; const { toPathIfFileURL } = require('internal/url'); const { customPromisifyArgs: kCustomPromisifyArgsSymbol, @@ -2569,8 +2569,8 @@ function realpathSync(p, options) { // Continue if not a symlink, break if a pipe/socket if (knownHard.has(base) || cache?.get(base) === base) { - if (isFileType(binding.statValues, S_IFIFO) || - isFileType(binding.statValues, S_IFSOCK)) { + if (isFileType(statValues, S_IFIFO) || + isFileType(statValues, S_IFSOCK)) { break; } continue; @@ -2727,8 +2727,8 @@ function realpath(p, options, callback) { // Continue if not a symlink, break if a pipe/socket if (knownHard.has(base)) { - if (isFileType(binding.statValues, S_IFIFO) || - isFileType(binding.statValues, S_IFSOCK)) { + if (isFileType(statValues, S_IFIFO) || + isFileType(statValues, S_IFSOCK)) { return callback(null, encodeRealpathResult(p, options)); } return process.nextTick(LOOP); diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index a6759d4266ae84..996b2506a49d3b 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -51,6 +51,7 @@ const { const binding = internalBinding('encoding_binding'); const { encodeInto, + encodeIntoResults, encodeUtf8String, decodeUTF8, } = binding; @@ -341,7 +342,7 @@ class TextEncoder { encodeInto(src, dest); // We need to read from the binding here since the buffer gets refreshed // from the snapshot. - const { 0: read, 1: written } = binding.encodeIntoResults; + const { 0: read, 1: written } = encodeIntoResults; return { read, written }; } diff --git a/lib/v8.js b/lib/v8.js index b76fa68bc1a8ba..32dcd2cf0c95e1 100644 --- a/lib/v8.js +++ b/lib/v8.js @@ -139,6 +139,10 @@ const { kBytecodeAndMetadataSizeIndex, kExternalScriptSourceSizeIndex, kCPUProfilerMetaDataSizeIndex, + + heapStatisticsBuffer, + heapCodeStatisticsBuffer, + heapSpaceStatisticsBuffer, } = binding; const kNumberOfHeapSpaces = kHeapSpaces.length; @@ -170,7 +174,7 @@ function setFlagsFromString(flags) { * }} */ function getHeapStatistics() { - const buffer = binding.heapStatisticsBuffer; + const buffer = heapStatisticsBuffer; updateHeapStatisticsBuffer(); @@ -204,7 +208,7 @@ function getHeapStatistics() { */ function getHeapSpaceStatistics() { const heapSpaceStatistics = new Array(kNumberOfHeapSpaces); - const buffer = binding.heapSpaceStatisticsBuffer; + const buffer = heapSpaceStatisticsBuffer; for (let i = 0; i < kNumberOfHeapSpaces; i++) { updateHeapSpaceStatisticsBuffer(i); @@ -230,7 +234,7 @@ function getHeapSpaceStatistics() { * }} */ function getHeapCodeStatistics() { - const buffer = binding.heapCodeStatisticsBuffer; + const buffer = heapCodeStatisticsBuffer; updateHeapCodeStatisticsBuffer(); return { diff --git a/src/aliased_buffer-inl.h b/src/aliased_buffer-inl.h index 58e9b6f8cef149..782a125570d06d 100644 --- a/src/aliased_buffer-inl.h +++ b/src/aliased_buffer-inl.h @@ -70,14 +70,14 @@ AliasedBufferBase::AliasedBufferBase( count_(that.count_), byte_offset_(that.byte_offset_), buffer_(that.buffer_) { - DCHECK_NULL(index_); + DCHECK(is_valid()); js_array_ = v8::Global(that.isolate_, that.GetJSArray()); } template AliasedBufferIndex AliasedBufferBase::Serialize( v8::Local context, v8::SnapshotCreator* creator) { - DCHECK_NULL(index_); + DCHECK(is_valid()); return creator->AddData(context, GetJSArray()); } @@ -100,7 +100,7 @@ inline void AliasedBufferBase::Deserialize( template AliasedBufferBase& AliasedBufferBase::operator=( AliasedBufferBase&& that) noexcept { - DCHECK_NULL(index_); + DCHECK(is_valid()); this->~AliasedBufferBase(); isolate_ = that.isolate_; count_ = that.count_; @@ -116,7 +116,7 @@ AliasedBufferBase& AliasedBufferBase::operator=( template v8::Local AliasedBufferBase::GetJSArray() const { - DCHECK_NULL(index_); + DCHECK(is_valid()); return js_array_.Get(isolate_); } @@ -126,6 +126,21 @@ void AliasedBufferBase::Release() { js_array_.Reset(); } +template +inline void AliasedBufferBase::WeakCallback( + const v8::WeakCallbackInfo>& data) { + AliasedBufferBase* buffer = data.GetParameter(); + DCHECK(buffer->is_valid()); + buffer->cleared_ = true; + buffer->js_array_.Reset(); +} + +template +inline void AliasedBufferBase::MakeWeak() { + DCHECK(is_valid()); + js_array_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); +} + template v8::Local AliasedBufferBase::GetArrayBuffer() const { @@ -134,7 +149,7 @@ v8::Local AliasedBufferBase::GetArrayBuffer() template inline const NativeT* AliasedBufferBase::GetNativeBuffer() const { - DCHECK_NULL(index_); + DCHECK(is_valid()); return buffer_; } @@ -147,14 +162,14 @@ template inline void AliasedBufferBase::SetValue(const size_t index, NativeT value) { DCHECK_LT(index, count_); - DCHECK_NULL(index_); + DCHECK(is_valid()); buffer_[index] = value; } template inline const NativeT AliasedBufferBase::GetValue( const size_t index) const { - DCHECK_NULL(index_); + DCHECK(is_valid()); DCHECK_LT(index, count_); return buffer_[index]; } @@ -162,7 +177,7 @@ inline const NativeT AliasedBufferBase::GetValue( template typename AliasedBufferBase::Reference AliasedBufferBase::operator[](size_t index) { - DCHECK_NULL(index_); + DCHECK(is_valid()); return Reference(this, index); } @@ -178,7 +193,7 @@ size_t AliasedBufferBase::Length() const { template void AliasedBufferBase::reserve(size_t new_capacity) { - DCHECK_NULL(index_); + DCHECK(is_valid()); DCHECK_GE(new_capacity, count_); DCHECK_EQ(byte_offset_, 0); const v8::HandleScope handle_scope(isolate_); @@ -206,6 +221,11 @@ void AliasedBufferBase::reserve(size_t new_capacity) { count_ = new_capacity; } +template +inline bool AliasedBufferBase::is_valid() const { + return index_ == nullptr && !cleared_; +} + template inline size_t AliasedBufferBase::SelfSize() const { return sizeof(*this); diff --git a/src/aliased_buffer.h b/src/aliased_buffer.h index bc858de3b3d268..4c4f8ac21dfc4a 100644 --- a/src/aliased_buffer.h +++ b/src/aliased_buffer.h @@ -117,6 +117,14 @@ class AliasedBufferBase : public MemoryRetainer { void Release(); + /** + * Make the global reference to the typed array weak. The caller must make + * sure that no operation can be done on the AliasedBuffer when the typed + * array becomes unreachable. Usually this means the caller must maintain + * a JS reference to the typed array from JS object. + */ + inline void MakeWeak(); + /** * Get the underlying v8::ArrayBuffer underlying the TypedArray and * overlaying the native buffer @@ -164,11 +172,15 @@ class AliasedBufferBase : public MemoryRetainer { inline void MemoryInfo(node::MemoryTracker* tracker) const override; private: + inline bool is_valid() const; + static inline void WeakCallback( + const v8::WeakCallbackInfo>& data); v8::Isolate* isolate_ = nullptr; size_t count_ = 0; size_t byte_offset_ = 0; NativeT* buffer_ = nullptr; v8::Global js_array_; + bool cleared_ = false; // Deserialize data const AliasedBufferIndex* index_ = nullptr; diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc index 467c4c11efd2bf..25f4abf6ae47ca 100644 --- a/src/encoding_binding.cc +++ b/src/encoding_binding.cc @@ -28,21 +28,32 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { encode_into_results_buffer_); } -BindingData::BindingData(Realm* realm, v8::Local object) +BindingData::BindingData(Realm* realm, + v8::Local object, + InternalFieldInfo* info) : SnapshotableObject(realm, object, type_int), - encode_into_results_buffer_(realm->isolate(), kEncodeIntoResultsLength) { - object - ->Set(realm->context(), - FIXED_ONE_BYTE_STRING(realm->isolate(), "encodeIntoResults"), - encode_into_results_buffer_.GetJSArray()) - .Check(); + encode_into_results_buffer_( + realm->isolate(), + kEncodeIntoResultsLength, + MAYBE_FIELD_PTR(info, encode_into_results_buffer)) { + if (info == nullptr) { + object + ->Set(realm->context(), + FIXED_ONE_BYTE_STRING(realm->isolate(), "encodeIntoResults"), + encode_into_results_buffer_.GetJSArray()) + .Check(); + } else { + encode_into_results_buffer_.Deserialize(realm->context()); + } + encode_into_results_buffer_.MakeWeak(); } bool BindingData::PrepareForSerialization(Local context, v8::SnapshotCreator* creator) { - // We'll just re-initialize the buffers in the constructor since their - // contents can be thrown away once consumed in the previous call. - encode_into_results_buffer_.Release(); + DCHECK_NULL(internal_field_info_); + internal_field_info_ = InternalFieldInfoBase::New(type()); + internal_field_info_->encode_into_results_buffer = + encode_into_results_buffer_.Serialize(context, creator); // Return true because we need to maintain the reference to the binding from // JS land. return true; @@ -50,8 +61,8 @@ bool BindingData::PrepareForSerialization(Local context, InternalFieldInfoBase* BindingData::Serialize(int index) { DCHECK_EQ(index, BaseObject::kEmbedderType); - InternalFieldInfo* info = - InternalFieldInfoBase::New(type()); + InternalFieldInfo* info = internal_field_info_; + internal_field_info_ = nullptr; return info; } @@ -63,7 +74,9 @@ void BindingData::Deserialize(Local context, v8::HandleScope scope(context->GetIsolate()); Realm* realm = Realm::GetCurrent(context); // Recreate the buffer in the constructor. - BindingData* binding = realm->AddBindingData(context, holder); + InternalFieldInfo* casted_info = static_cast(info); + BindingData* binding = + realm->AddBindingData(context, holder, casted_info); CHECK_NOT_NULL(binding); } diff --git a/src/encoding_binding.h b/src/encoding_binding.h index 51e006982b9363..0258b8188b106d 100644 --- a/src/encoding_binding.h +++ b/src/encoding_binding.h @@ -14,10 +14,13 @@ class ExternalReferenceRegistry; namespace encoding_binding { class BindingData : public SnapshotableObject { public: - BindingData(Realm* realm, v8::Local obj); - - using InternalFieldInfo = InternalFieldInfoBase; + struct InternalFieldInfo : public node::InternalFieldInfoBase { + AliasedBufferIndex encode_into_results_buffer; + }; + BindingData(Realm* realm, + v8::Local obj, + InternalFieldInfo* info = nullptr); SERIALIZABLE_OBJECT_METHODS() SET_BINDING_ID(encoding_binding_data) @@ -39,6 +42,7 @@ class BindingData : public SnapshotableObject { private: static constexpr size_t kEncodeIntoResultsLength = 2; AliasedUint32Array encode_into_results_buffer_; + InternalFieldInfo* internal_field_info_ = nullptr; }; } // namespace encoding_binding diff --git a/src/node_file.cc b/src/node_file.cc index 9e0083d10a2f87..6f6381e163dd0d 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2717,33 +2717,56 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { file_handle_read_wrap_freelist); } -BindingData::BindingData(Realm* realm, v8::Local wrap) +BindingData::BindingData(Realm* realm, + v8::Local wrap, + InternalFieldInfo* info) : 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) { + stats_field_array(realm->isolate(), + kFsStatsBufferLength, + MAYBE_FIELD_PTR(info, stats_field_array)), + stats_field_bigint_array(realm->isolate(), + kFsStatsBufferLength, + MAYBE_FIELD_PTR(info, stats_field_bigint_array)), + statfs_field_array(realm->isolate(), + kFsStatFsBufferLength, + MAYBE_FIELD_PTR(info, statfs_field_array)), + statfs_field_bigint_array( + realm->isolate(), + kFsStatFsBufferLength, + MAYBE_FIELD_PTR(info, statfs_field_bigint_array)) { Isolate* isolate = realm->isolate(); Local context = realm->context(); - wrap->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "statValues"), - stats_field_array.GetJSArray()) - .Check(); - - wrap->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"), - stats_field_bigint_array.GetJSArray()) - .Check(); - - wrap->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "statFsValues"), - statfs_field_array.GetJSArray()) - .Check(); - wrap->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "bigintStatFsValues"), - statfs_field_bigint_array.GetJSArray()) - .Check(); + if (info == nullptr) { + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "statValues"), + stats_field_array.GetJSArray()) + .Check(); + + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"), + stats_field_bigint_array.GetJSArray()) + .Check(); + + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "statFsValues"), + statfs_field_array.GetJSArray()) + .Check(); + + wrap->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "bigintStatFsValues"), + statfs_field_bigint_array.GetJSArray()) + .Check(); + } else { + stats_field_array.Deserialize(realm->context()); + stats_field_bigint_array.Deserialize(realm->context()); + statfs_field_array.Deserialize(realm->context()); + statfs_field_bigint_array.Deserialize(realm->context()); + } + stats_field_array.MakeWeak(); + stats_field_bigint_array.MakeWeak(); + statfs_field_array.MakeWeak(); + statfs_field_bigint_array.MakeWeak(); } void BindingData::Deserialize(Local context, @@ -2753,19 +2776,25 @@ void BindingData::Deserialize(Local context, DCHECK_EQ(index, BaseObject::kEmbedderType); HandleScope scope(context->GetIsolate()); Realm* realm = Realm::GetCurrent(context); - BindingData* binding = realm->AddBindingData(context, holder); + InternalFieldInfo* casted_info = static_cast(info); + BindingData* binding = + realm->AddBindingData(context, holder, casted_info); CHECK_NOT_NULL(binding); } bool BindingData::PrepareForSerialization(Local context, v8::SnapshotCreator* creator) { CHECK(file_handle_read_wrap_freelist.empty()); - // We'll just re-initialize the buffers in the constructor since their - // contents can be thrown away once consumed in the previous call. - stats_field_array.Release(); - stats_field_bigint_array.Release(); - statfs_field_array.Release(); - statfs_field_bigint_array.Release(); + DCHECK_NULL(internal_field_info_); + internal_field_info_ = InternalFieldInfoBase::New(type()); + internal_field_info_->stats_field_array = + stats_field_array.Serialize(context, creator); + internal_field_info_->stats_field_bigint_array = + stats_field_bigint_array.Serialize(context, creator); + internal_field_info_->statfs_field_array = + statfs_field_array.Serialize(context, creator); + internal_field_info_->statfs_field_bigint_array = + statfs_field_bigint_array.Serialize(context, creator); // Return true because we need to maintain the reference to the binding from // JS land. return true; @@ -2773,8 +2802,8 @@ bool BindingData::PrepareForSerialization(Local context, InternalFieldInfoBase* BindingData::Serialize(int index) { DCHECK_EQ(index, BaseObject::kEmbedderType); - InternalFieldInfo* info = - InternalFieldInfoBase::New(type()); + InternalFieldInfo* info = internal_field_info_; + internal_field_info_ = nullptr; return info; } diff --git a/src/node_file.h b/src/node_file.h index 2325b6b26f756e..7b43d027a2e652 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -57,7 +57,15 @@ constexpr size_t kFsStatFsBufferLength = class BindingData : public SnapshotableObject { public: - explicit BindingData(Realm* realm, v8::Local wrap); + struct InternalFieldInfo : public node::InternalFieldInfoBase { + AliasedBufferIndex stats_field_array; + AliasedBufferIndex stats_field_bigint_array; + AliasedBufferIndex statfs_field_array; + AliasedBufferIndex statfs_field_bigint_array; + }; + explicit BindingData(Realm* realm, + v8::Local wrap, + InternalFieldInfo* info = nullptr); AliasedFloat64Array stats_field_array; AliasedBigInt64Array stats_field_bigint_array; @@ -68,13 +76,15 @@ class BindingData : public SnapshotableObject { std::vector> file_handle_read_wrap_freelist; - using InternalFieldInfo = InternalFieldInfoBase; SERIALIZABLE_OBJECT_METHODS() SET_BINDING_ID(fs_binding_data) void MemoryInfo(MemoryTracker* tracker) const override; SET_SELF_SIZE(BindingData) SET_MEMORY_INFO_NAME(BindingData) + + private: + InternalFieldInfo* internal_field_info_ = nullptr; }; // structure used to store state during a complex operation, e.g., mkdirp. diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h index f49690714a3ea5..6a6e2a0c51d307 100644 --- a/src/node_realm-inl.h +++ b/src/node_realm-inl.h @@ -80,12 +80,14 @@ inline T* Realm::GetBindingData(v8::Local context) { return result; } -template +template inline T* Realm::AddBindingData(v8::Local context, - v8::Local target) { + v8::Local target, + Args&&... args) { DCHECK_EQ(GetCurrent(context), this); // This won't compile if T is not a BaseObject subclass. - BaseObjectPtr item = MakeDetachedBaseObject(this, target); + BaseObjectPtr item = + MakeDetachedBaseObject(this, target, std::forward(args)...); BindingDataStore* map = static_cast(context->GetAlignedPointerFromEmbedderData( ContextEmbedderIndex::kBindingDataStoreIndex)); diff --git a/src/node_realm.h b/src/node_realm.h index 4bff386baff227..f1cd2bdbf3eaca 100644 --- a/src/node_realm.h +++ b/src/node_realm.h @@ -92,9 +92,10 @@ class Realm : public MemoryRetainer { // Methods created using SetMethod(), SetPrototypeMethod(), etc. inside // this scope can access the created T* object using // GetBindingData(args) later. - template + template T* AddBindingData(v8::Local context, - v8::Local target); + v8::Local target, + Args&&... args); template static inline T* GetBindingData(const v8::PropertyCallbackInfo& info); template diff --git a/src/node_v8.cc b/src/node_v8.cc index 82ae6caa952be7..308d851ef62278 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -92,35 +92,57 @@ static const size_t kHeapCodeStatisticsPropertiesCount = HEAP_CODE_STATISTICS_PROPERTIES(V); #undef V -BindingData::BindingData(Realm* realm, Local obj) +BindingData::BindingData(Realm* realm, + Local obj, + InternalFieldInfo* info) : SnapshotableObject(realm, obj, type_int), - heap_statistics_buffer(realm->isolate(), kHeapStatisticsPropertiesCount), - heap_space_statistics_buffer(realm->isolate(), - kHeapSpaceStatisticsPropertiesCount), - heap_code_statistics_buffer(realm->isolate(), - kHeapCodeStatisticsPropertiesCount) { + heap_statistics_buffer(realm->isolate(), + kHeapStatisticsPropertiesCount, + MAYBE_FIELD_PTR(info, heap_statistics_buffer)), + heap_space_statistics_buffer( + realm->isolate(), + kHeapSpaceStatisticsPropertiesCount, + MAYBE_FIELD_PTR(info, heap_space_statistics_buffer)), + heap_code_statistics_buffer( + realm->isolate(), + kHeapCodeStatisticsPropertiesCount, + MAYBE_FIELD_PTR(info, heap_code_statistics_buffer)) { Local context = realm->context(); - obj->Set(context, - FIXED_ONE_BYTE_STRING(realm->isolate(), "heapStatisticsBuffer"), - heap_statistics_buffer.GetJSArray()) - .Check(); - obj->Set(context, + if (info == nullptr) { + obj->Set(context, + FIXED_ONE_BYTE_STRING(realm->isolate(), "heapStatisticsBuffer"), + heap_statistics_buffer.GetJSArray()) + .Check(); + obj->Set( + context, FIXED_ONE_BYTE_STRING(realm->isolate(), "heapCodeStatisticsBuffer"), heap_code_statistics_buffer.GetJSArray()) - .Check(); - obj->Set(context, + .Check(); + obj->Set( + context, FIXED_ONE_BYTE_STRING(realm->isolate(), "heapSpaceStatisticsBuffer"), heap_space_statistics_buffer.GetJSArray()) - .Check(); + .Check(); + } else { + heap_statistics_buffer.Deserialize(realm->context()); + heap_code_statistics_buffer.Deserialize(realm->context()); + heap_space_statistics_buffer.Deserialize(realm->context()); + } + heap_statistics_buffer.MakeWeak(); + heap_space_statistics_buffer.MakeWeak(); + heap_code_statistics_buffer.MakeWeak(); } bool BindingData::PrepareForSerialization(Local context, v8::SnapshotCreator* creator) { - // We'll just re-initialize the buffers in the constructor since their - // contents can be thrown away once consumed in the previous call. - heap_statistics_buffer.Release(); - heap_space_statistics_buffer.Release(); - heap_code_statistics_buffer.Release(); + DCHECK_NULL(internal_field_info_); + internal_field_info_ = InternalFieldInfoBase::New(type()); + internal_field_info_->heap_statistics_buffer = + heap_statistics_buffer.Serialize(context, creator); + internal_field_info_->heap_space_statistics_buffer = + heap_space_statistics_buffer.Serialize(context, creator); + internal_field_info_->heap_code_statistics_buffer = + heap_code_statistics_buffer.Serialize(context, creator); // Return true because we need to maintain the reference to the binding from // JS land. return true; @@ -133,14 +155,17 @@ void BindingData::Deserialize(Local context, DCHECK_EQ(index, BaseObject::kEmbedderType); HandleScope scope(context->GetIsolate()); Realm* realm = Realm::GetCurrent(context); - BindingData* binding = realm->AddBindingData(context, holder); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast(info); + BindingData* binding = + realm->AddBindingData(context, holder, casted_info); CHECK_NOT_NULL(binding); } InternalFieldInfoBase* BindingData::Serialize(int index) { DCHECK_EQ(index, BaseObject::kEmbedderType); - InternalFieldInfo* info = - InternalFieldInfoBase::New(type()); + InternalFieldInfo* info = internal_field_info_; + internal_field_info_ = nullptr; return info; } diff --git a/src/node_v8.h b/src/node_v8.h index 002f506d20833e..d3797432a24db7 100644 --- a/src/node_v8.h +++ b/src/node_v8.h @@ -18,9 +18,14 @@ struct InternalFieldInfoBase; namespace v8_utils { class BindingData : public SnapshotableObject { public: - BindingData(Realm* realm, v8::Local obj); - - using InternalFieldInfo = InternalFieldInfoBase; + struct InternalFieldInfo : public node::InternalFieldInfoBase { + AliasedBufferIndex heap_statistics_buffer; + AliasedBufferIndex heap_space_statistics_buffer; + AliasedBufferIndex heap_code_statistics_buffer; + }; + BindingData(Realm* realm, + v8::Local obj, + InternalFieldInfo* info = nullptr); SERIALIZABLE_OBJECT_METHODS() SET_BINDING_ID(v8_binding_data) @@ -32,6 +37,9 @@ class BindingData : public SnapshotableObject { void MemoryInfo(MemoryTracker* tracker) const override; SET_SELF_SIZE(BindingData) SET_MEMORY_INFO_NAME(BindingData) + + private: + InternalFieldInfo* internal_field_info_ = nullptr; }; class GCProfiler : public BaseObject {