diff --git a/lib/fs.js b/lib/fs.js index 25534c838d0..6f82f279f28 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 a6759d4266a..996b2506a49 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 b76fa68bc1a..32dcd2cf0c9 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 58e9b6f8cef..782a125570d 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 bc858de3b3d..4c4f8ac21df 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 467c4c11efd..25f4abf6ae4 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 51e006982b9..0258b8188b1 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 3eaa46e9c2b..81e076d6ec6 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2737,33 +2737,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(); + 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, "statFsValues"), - statfs_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, "bigintStatFsValues"), - statfs_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, @@ -2773,19 +2796,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; @@ -2793,8 +2822,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 2325b6b26f7..7b43d027a2e 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 f49690714a3..6a6e2a0c51d 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 d5b721002ef..a588b02abf3 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 82ae6caa952..308d851ef62 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 002f506d208..d3797432a24 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 {