Skip to content

Commit

Permalink
src: avoid deferred gc/cleanup for Buffer.from
Browse files Browse the repository at this point in the history
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: nodejs#38300
Refs: nodejs#38336
  • Loading branch information
jasnell committed Apr 21, 2021
1 parent d666964 commit 6805449
Showing 1 changed file with 18 additions and 10 deletions.
28 changes: 18 additions & 10 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
reinterpret_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));
}


Expand Down

0 comments on commit 6805449

Please sign in to comment.