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 <anna@addaleax.net>
Reviewed-By: Khaidi Chu <i@2333.moe>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
James M Snell authored and Michaël Zasso committed 2021-04-24 10:22:38 +02:00
1 parent f9e07e432b
commit 720fdf2f80
1 file changed
+18 -10
+18 -10
View File
@@ -303,28 +303,36 @@ MaybeLocal<Object> New(Isolate* isolate,
if (!StringBytes::Size(isolate, string, enc).To(&length))
return Local<Object>();
size_t actual = 0;
char* data = nullptr;
std::unique_ptr<BackingStore> 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<Object>();
}
actual = StringBytes::Write(isolate, data, length, string, enc);
actual = StringBytes::Write(
isolate,
static_cast<char*>(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<ArrayBuffer> buf = ArrayBuffer::New(isolate, std::move(store));
Local<Object> obj;
if (UNLIKELY(!New(isolate, buf, 0, actual).ToLocal(&obj)))
return MaybeLocal<Object>();
return scope.Escape(obj);
}
}
return scope.EscapeMaybe(New(isolate, data, actual));
return scope.EscapeMaybe(New(isolate, 0));
}