From 3649ec527648ae15d2b6b979270df620879c30c3 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 21 Apr 2021 16:38:28 -0700 Subject: [PATCH] src: avoid deferred gc/cleanup for Buffer.from Previously, the code path would allocated a tracked ArrayBuffer that defers cleanup and deallocation of the underlying data with a SetImmediate. Avoid the unnecessary deferral by just allocating a `BackingStore` directly and writing into it. Fixes: https://github.com/nodejs/node/issues/38300 Refs: https://github.com/nodejs/node/pull/38336 PR-URL: https://github.com/nodejs/node/pull/38337 Reviewed-By: Anna Henningsen Reviewed-By: Khaidi Chu Reviewed-By: Matteo Collina Reviewed-By: Joyee Cheung --- src/node_buffer.cc | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 485e273f2fbe9e..9006c1de767533 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -303,28 +303,36 @@ MaybeLocal New(Isolate* isolate, if (!StringBytes::Size(isolate, string, enc).To(&length)) return Local(); size_t actual = 0; - char* data = nullptr; + std::unique_ptr store; if (length > 0) { - data = UncheckedMalloc(length); + store = ArrayBuffer::NewBackingStore(isolate, length); - if (data == nullptr) { + if (UNLIKELY(!store)) { THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); return Local(); } - actual = StringBytes::Write(isolate, data, length, string, enc); + actual = StringBytes::Write( + isolate, + static_cast(store->Data()), + length, + string, + enc); CHECK(actual <= length); - if (actual == 0) { - free(data); - data = nullptr; - } else if (actual < length) { - data = node::Realloc(data, actual); + if (LIKELY(actual > 0)) { + if (actual < length) + store = BackingStore::Reallocate(isolate, std::move(store), actual); + Local buf = ArrayBuffer::New(isolate, std::move(store)); + Local obj; + if (UNLIKELY(!New(isolate, buf, 0, actual).ToLocal(&obj))) + return MaybeLocal(); + return scope.Escape(obj); } } - return scope.EscapeMaybe(New(isolate, data, actual)); + return scope.EscapeMaybe(New(isolate, 0)); }