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.

PR-URL: https://github.com/nodejs/node/pull/47354
Refs: https://github.com/nodejs/node/issues/47353
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Joyee Cheung 2023-04-20 05:28:35 +02:00 committed by GitHub
parent df15a4732c
commit b68cedd4d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 228 additions and 99 deletions

View File

@ -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);

View File

@ -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 };
}

View File

@ -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 {

View File

@ -70,14 +70,14 @@ AliasedBufferBase<NativeT, V8T>::AliasedBufferBase(
count_(that.count_),
byte_offset_(that.byte_offset_),
buffer_(that.buffer_) {
DCHECK_NULL(index_);
DCHECK(is_valid());
js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
}
template <typename NativeT, typename V8T>
AliasedBufferIndex AliasedBufferBase<NativeT, V8T>::Serialize(
v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
DCHECK_NULL(index_);
DCHECK(is_valid());
return creator->AddData(context, GetJSArray());
}
@ -100,7 +100,7 @@ inline void AliasedBufferBase<NativeT, V8T>::Deserialize(
template <typename NativeT, typename V8T>
AliasedBufferBase<NativeT, V8T>& AliasedBufferBase<NativeT, V8T>::operator=(
AliasedBufferBase<NativeT, V8T>&& that) noexcept {
DCHECK_NULL(index_);
DCHECK(is_valid());
this->~AliasedBufferBase();
isolate_ = that.isolate_;
count_ = that.count_;
@ -116,7 +116,7 @@ AliasedBufferBase<NativeT, V8T>& AliasedBufferBase<NativeT, V8T>::operator=(
template <typename NativeT, typename V8T>
v8::Local<V8T> AliasedBufferBase<NativeT, V8T>::GetJSArray() const {
DCHECK_NULL(index_);
DCHECK(is_valid());
return js_array_.Get(isolate_);
}
@ -126,6 +126,21 @@ void AliasedBufferBase<NativeT, V8T>::Release() {
js_array_.Reset();
}
template <typename NativeT, typename V8T>
inline void AliasedBufferBase<NativeT, V8T>::WeakCallback(
const v8::WeakCallbackInfo<AliasedBufferBase<NativeT, V8T>>& data) {
AliasedBufferBase<NativeT, V8T>* buffer = data.GetParameter();
DCHECK(buffer->is_valid());
buffer->cleared_ = true;
buffer->js_array_.Reset();
}
template <typename NativeT, typename V8T>
inline void AliasedBufferBase<NativeT, V8T>::MakeWeak() {
DCHECK(is_valid());
js_array_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
}
template <typename NativeT, typename V8T>
v8::Local<v8::ArrayBuffer> AliasedBufferBase<NativeT, V8T>::GetArrayBuffer()
const {
@ -134,7 +149,7 @@ v8::Local<v8::ArrayBuffer> AliasedBufferBase<NativeT, V8T>::GetArrayBuffer()
template <typename NativeT, typename V8T>
inline const NativeT* AliasedBufferBase<NativeT, V8T>::GetNativeBuffer() const {
DCHECK_NULL(index_);
DCHECK(is_valid());
return buffer_;
}
@ -147,14 +162,14 @@ template <typename NativeT, typename V8T>
inline void AliasedBufferBase<NativeT, V8T>::SetValue(const size_t index,
NativeT value) {
DCHECK_LT(index, count_);
DCHECK_NULL(index_);
DCHECK(is_valid());
buffer_[index] = value;
}
template <typename NativeT, typename V8T>
inline const NativeT AliasedBufferBase<NativeT, V8T>::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<NativeT, V8T>::GetValue(
template <typename NativeT, typename V8T>
typename AliasedBufferBase<NativeT, V8T>::Reference
AliasedBufferBase<NativeT, V8T>::operator[](size_t index) {
DCHECK_NULL(index_);
DCHECK(is_valid());
return Reference(this, index);
}
@ -178,7 +193,7 @@ size_t AliasedBufferBase<NativeT, V8T>::Length() const {
template <typename NativeT, typename V8T>
void AliasedBufferBase<NativeT, V8T>::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<NativeT, V8T>::reserve(size_t new_capacity) {
count_ = new_capacity;
}
template <typename NativeT, typename V8T>
inline bool AliasedBufferBase<NativeT, V8T>::is_valid() const {
return index_ == nullptr && !cleared_;
}
template <typename NativeT, typename V8T>
inline size_t AliasedBufferBase<NativeT, V8T>::SelfSize() const {
return sizeof(*this);

View File

@ -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<AliasedBufferBase<NativeT, V8T>>& data);
v8::Isolate* isolate_ = nullptr;
size_t count_ = 0;
size_t byte_offset_ = 0;
NativeT* buffer_ = nullptr;
v8::Global<V8T> js_array_;
bool cleared_ = false;
// Deserialize data
const AliasedBufferIndex* index_ = nullptr;

View File

@ -28,21 +28,32 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const {
encode_into_results_buffer_);
}
BindingData::BindingData(Realm* realm, v8::Local<v8::Object> object)
BindingData::BindingData(Realm* realm,
v8::Local<v8::Object> 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> 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<InternalFieldInfo>(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> context,
InternalFieldInfoBase* BindingData::Serialize(int index) {
DCHECK_EQ(index, BaseObject::kEmbedderType);
InternalFieldInfo* info =
InternalFieldInfoBase::New<InternalFieldInfo>(type());
InternalFieldInfo* info = internal_field_info_;
internal_field_info_ = nullptr;
return info;
}
@ -63,7 +74,9 @@ void BindingData::Deserialize(Local<Context> context,
v8::HandleScope scope(context->GetIsolate());
Realm* realm = Realm::GetCurrent(context);
// Recreate the buffer in the constructor.
BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
BindingData* binding =
realm->AddBindingData<BindingData>(context, holder, casted_info);
CHECK_NOT_NULL(binding);
}

View File

@ -14,10 +14,13 @@ class ExternalReferenceRegistry;
namespace encoding_binding {
class BindingData : public SnapshotableObject {
public:
BindingData(Realm* realm, v8::Local<v8::Object> obj);
using InternalFieldInfo = InternalFieldInfoBase;
struct InternalFieldInfo : public node::InternalFieldInfoBase {
AliasedBufferIndex encode_into_results_buffer;
};
BindingData(Realm* realm,
v8::Local<v8::Object> 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

View File

@ -2737,33 +2737,56 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const {
file_handle_read_wrap_freelist);
}
BindingData::BindingData(Realm* realm, v8::Local<v8::Object> wrap)
BindingData::BindingData(Realm* realm,
v8::Local<v8::Object> 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> 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> context,
@ -2773,19 +2796,25 @@ void BindingData::Deserialize(Local<Context> context,
DCHECK_EQ(index, BaseObject::kEmbedderType);
HandleScope scope(context->GetIsolate());
Realm* realm = Realm::GetCurrent(context);
BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
BindingData* binding =
realm->AddBindingData<BindingData>(context, holder, casted_info);
CHECK_NOT_NULL(binding);
}
bool BindingData::PrepareForSerialization(Local<Context> 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<InternalFieldInfo>(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> context,
InternalFieldInfoBase* BindingData::Serialize(int index) {
DCHECK_EQ(index, BaseObject::kEmbedderType);
InternalFieldInfo* info =
InternalFieldInfoBase::New<InternalFieldInfo>(type());
InternalFieldInfo* info = internal_field_info_;
internal_field_info_ = nullptr;
return info;
}

View File

@ -57,7 +57,15 @@ constexpr size_t kFsStatFsBufferLength =
class BindingData : public SnapshotableObject {
public:
explicit BindingData(Realm* realm, v8::Local<v8::Object> 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<v8::Object> wrap,
InternalFieldInfo* info = nullptr);
AliasedFloat64Array stats_field_array;
AliasedBigInt64Array stats_field_bigint_array;
@ -68,13 +76,15 @@ class BindingData : public SnapshotableObject {
std::vector<BaseObjectPtr<FileHandleReadWrap>>
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.

View File

@ -80,12 +80,14 @@ inline T* Realm::GetBindingData(v8::Local<v8::Context> context) {
return result;
}
template <typename T>
template <typename T, typename... Args>
inline T* Realm::AddBindingData(v8::Local<v8::Context> context,
v8::Local<v8::Object> target) {
v8::Local<v8::Object> target,
Args&&... args) {
DCHECK_EQ(GetCurrent(context), this);
// This won't compile if T is not a BaseObject subclass.
BaseObjectPtr<T> item = MakeDetachedBaseObject<T>(this, target);
BaseObjectPtr<T> item =
MakeDetachedBaseObject<T>(this, target, std::forward<Args>(args)...);
BindingDataStore* map =
static_cast<BindingDataStore*>(context->GetAlignedPointerFromEmbedderData(
ContextEmbedderIndex::kBindingDataStoreIndex));

View File

@ -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<T>(args) later.
template <typename T>
template <typename T, typename... Args>
T* AddBindingData(v8::Local<v8::Context> context,
v8::Local<v8::Object> target);
v8::Local<v8::Object> target,
Args&&... args);
template <typename T, typename U>
static inline T* GetBindingData(const v8::PropertyCallbackInfo<U>& info);
template <typename T>

View File

@ -92,35 +92,57 @@ static const size_t kHeapCodeStatisticsPropertiesCount =
HEAP_CODE_STATISTICS_PROPERTIES(V);
#undef V
BindingData::BindingData(Realm* realm, Local<Object> obj)
BindingData::BindingData(Realm* realm,
Local<Object> 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> 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> 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<InternalFieldInfo>(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> context,
DCHECK_EQ(index, BaseObject::kEmbedderType);
HandleScope scope(context->GetIsolate());
Realm* realm = Realm::GetCurrent(context);
BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
// Recreate the buffer in the constructor.
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
BindingData* binding =
realm->AddBindingData<BindingData>(context, holder, casted_info);
CHECK_NOT_NULL(binding);
}
InternalFieldInfoBase* BindingData::Serialize(int index) {
DCHECK_EQ(index, BaseObject::kEmbedderType);
InternalFieldInfo* info =
InternalFieldInfoBase::New<InternalFieldInfo>(type());
InternalFieldInfo* info = internal_field_info_;
internal_field_info_ = nullptr;
return info;
}

View File

@ -18,9 +18,14 @@ struct InternalFieldInfoBase;
namespace v8_utils {
class BindingData : public SnapshotableObject {
public:
BindingData(Realm* realm, v8::Local<v8::Object> 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<v8::Object> 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 {