@@ -234,6 +234,89 @@ index 84a650885a79bc5c49efdc26f62ec8db48de775c..ba442937bf0d7831c9a84b5a57211e9f
234234 struct IsolateDataSerializeInfo {
235235 std::vector<SnapshotIndex> primitive_values;
236236 std::vector<PropInfo> template_values;
237+ diff --git a/src/node_buffer.cc b/src/node_buffer.cc
238+ index 49df0b4284748effb27b05ecd69f05699dd8be75..eb104ab80fd2052d1523cb2f2ecdb6d23ac3be98 100644
239+ --- a/src/node_buffer.cc
240+ +++ b/src/node_buffer.cc
241+ @@ -81,6 +81,7 @@ using v8::SharedArrayBuffer;
242+ using v8::String;
243+ using v8::Uint32;
244+ using v8::Uint8Array;
245+ + using v8::Uint32Array;
246+ using v8::Value;
247+
248+ namespace {
249+ @@ -1243,6 +1244,45 @@ void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
250+ realm->set_buffer_prototype_object(proto);
251+ }
252+
253+ + void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
254+ + Environment* env = Environment::GetCurrent(args);
255+ + NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator();
256+ + Local<ArrayBuffer> ab;
257+ + // It can be a nullptr when running inside an isolate where we
258+ + // do not own the ArrayBuffer allocator.
259+ + if (allocator == nullptr || env->isolate_data()->is_building_snapshot()) {
260+ + // Create a dummy Uint32Array - the JS land can only toggle the C++ land
261+ + // setting when the allocator uses our toggle. With this the toggle in JS
262+ + // land results in no-ops.
263+ + // When building a snapshot, just use a dummy toggle as well to avoid
264+ + // introducing the dynamic external reference. We'll re-initialize the
265+ + // toggle with a real one connected to the C++ allocator after snapshot
266+ + // deserialization.
267+ +
268+ + ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t));
269+ + } else {
270+ + // TODO(joyeecheung): save ab->GetBackingStore()->Data() in the Node.js
271+ + // array buffer allocator and include it into the C++ toggle while the
272+ + // Environment is still alive.
273+ + uint32_t* zero_fill_field = allocator->zero_fill_field();
274+ + std::unique_ptr<BackingStore> backing =
275+ + ArrayBuffer::NewBackingStore(zero_fill_field,
276+ + sizeof(*zero_fill_field),
277+ + [](void*, size_t, void*) {},
278+ + nullptr);
279+ + ab = ArrayBuffer::New(env->isolate(), std::move(backing));
280+ + }
281+ +
282+ + if (ab->SetPrivate(env->context(),
283+ + env->untransferable_object_private_symbol(),
284+ + True(env->isolate()))
285+ + .IsNothing()) {
286+ + return;
287+ + }
288+ +
289+ + args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1));
290+ + }
291+ +
292+ static void Btoa(const FunctionCallbackInfo<Value>& args) {
293+ CHECK_EQ(args.Length(), 1);
294+ Environment* env = Environment::GetCurrent(args);
295+ @@ -1420,7 +1460,7 @@ inline size_t CheckNumberToSize(Local<Value> number) {
296+ CHECK(value >= 0 && value < maxSize);
297+ size_t size = static_cast<size_t>(value);
298+ #ifdef V8_ENABLE_SANDBOX
299+ - CHECK_LE(size, kMaxSafeBufferSizeForSandbox);
300+ + CHECK_LE(size, v8::internal::kMaxSafeBufferSizeForSandbox);
301+ #endif
302+ return size;
303+ }
304+ @@ -1638,6 +1678,7 @@ void Initialize(Local<Object> target,
305+ "utf8WriteStatic",
306+ SlowWriteString<UTF8>,
307+ &fast_write_string_utf8);
308+ + SetMethod(context, target, "getZeroFillToggle", GetZeroFillToggle);
309+ }
310+
311+ } // anonymous namespace
312+ @@ -1686,6 +1727,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
313+ registry->Register(StringWrite<HEX>);
314+ registry->Register(StringWrite<UCS2>);
315+ registry->Register(StringWrite<UTF8>);
316+ + registry->Register(GetZeroFillToggle);
317+
318+ registry->Register(CopyArrayBuffer);
319+ registry->Register(CreateUnsafeArrayBuffer);
237320diff --git a/src/node_i18n.cc b/src/node_i18n.cc
238321index 3c4f419aa29470b3280174b58680b9421b0340b5..3b24ad2a2316f89d98b067e2c13988f87a9a00d2 100644
239322--- a/src/node_i18n.cc
@@ -274,6 +357,28 @@ index 3c4f419aa29470b3280174b58680b9421b0340b5..3b24ad2a2316f89d98b067e2c13988f8
274357 }
275358
276359 constexpr const char* EncodingName(const enum encoding encoding) {
360+ diff --git a/src/node_internals.h b/src/node_internals.h
361+ index 61a58b6ccfb26efefd6d3b61a1c8741f9550ae8d..29d1ecc2b209c9c3c2e956263ba2d57fb688b34c 100644
362+ --- a/src/node_internals.h
363+ +++ b/src/node_internals.h
364+ @@ -124,6 +124,9 @@ v8::MaybeLocal<v8::Object> InitializePrivateSymbols(
365+
366+ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
367+ public:
368+ + NodeArrayBufferAllocator();
369+ + ~NodeArrayBufferAllocator() override;
370+ + inline uint32_t* zero_fill_field() { return zero_fill_field_; }
371+ void* Allocate(size_t size) override; // Defined in src/node.cc
372+ void* AllocateUninitialized(size_t size) override;
373+ void Free(void* data, size_t size) override;
374+ @@ -140,6 +143,7 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
375+ }
376+
377+ private:
378+ + uint32_t* zero_fill_field_ = nullptr; // Boolean but exposed as uint32 to JS land.
379+ std::atomic<size_t> total_mem_usage_ {0};
380+
381+ // Delegate to V8's allocator for compatibility with the V8 memory cage.
277382diff --git a/src/node_serdes.cc b/src/node_serdes.cc
278383index 00fcd4b6afccce47ff21c4447d9cd60f25c11835..5f96ee2051e5339456185efddb149c4d43093f31 100644
279384--- a/src/node_serdes.cc
0 commit comments