diff options
author | Anna Henningsen <anna@addaleax.net> | 2019-02-19 00:58:27 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-02-25 04:01:11 +0300 |
commit | 84e02b178ad14fae0df2a514e8a39bfa50ffdc2d (patch) | |
tree | ddc0435b6bd0b7811e0bf47687777c56b2857fd0 /src/node_buffer.cc | |
parent | 6c257cdf271384555d0ced77104a1d6b0480e246 (diff) |
src: allocate Buffer memory using ArrayBuffer allocator
Always use the right allocator for memory that is turned into
an `ArrayBuffer` at a later point.
This enables embedders to use their own `ArrayBuffer::Allocator`s,
and is inspired by Electron’s electron/node@f61bae3440e. It should
render their downstream patch unnecessary.
Refs: https://github.com/electron/node/commit/f61bae3440e1bfcc83bba6ff0785adfb89b4045e
PR-URL: https://github.com/nodejs/node/pull/26207
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Diffstat (limited to 'src/node_buffer.cc')
-rw-r--r-- | src/node_buffer.cc | 98 |
1 files changed, 40 insertions, 58 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 9fed15622e0..aca1842c30b 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -54,17 +54,6 @@ size_t length = end - start; namespace node { - -namespace { - -inline void* BufferMalloc(size_t length) { - return per_process::cli_options->zero_fill_all_buffers ? - node::UncheckedCalloc(length) : - node::UncheckedMalloc(length); -} - -} // namespace - namespace Buffer { using v8::ArrayBuffer; @@ -260,7 +249,7 @@ MaybeLocal<Object> New(Isolate* isolate, char* data = nullptr; if (length > 0) { - data = static_cast<char*>(BufferMalloc(length)); + data = UncheckedMalloc(length); if (data == nullptr) { THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); @@ -278,13 +267,7 @@ MaybeLocal<Object> New(Isolate* isolate, } } - Local<Object> buf; - if (New(isolate, data, actual).ToLocal(&buf)) - return scope.Escape(buf); - - // Object failed to be created. Clean up resources. - free(data); - return Local<Object>(); + return scope.EscapeMaybe(New(isolate, data, actual)); } @@ -311,26 +294,16 @@ MaybeLocal<Object> New(Environment* env, size_t length) { return Local<Object>(); } - void* data; + AllocatedBuffer ret(env); if (length > 0) { - data = BufferMalloc(length); - if (data == nullptr) { + ret = env->AllocateManaged(length, false); + if (ret.data() == nullptr) { THROW_ERR_MEMORY_ALLOCATION_FAILED(env); return Local<Object>(); } - } else { - data = nullptr; } - Local<ArrayBuffer> ab = - ArrayBuffer::New(env->isolate(), - data, - length, - ArrayBufferCreationMode::kInternalized); - Local<Object> obj; - if (Buffer::New(env, ab, 0, length).ToLocal(&obj)) - return scope.Escape(obj); - return Local<Object>(); + return scope.EscapeMaybe(ret.ToBuffer()); } @@ -357,28 +330,18 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) { return Local<Object>(); } - void* new_data; + AllocatedBuffer ret(env); if (length > 0) { CHECK_NOT_NULL(data); - new_data = node::UncheckedMalloc(length); - if (new_data == nullptr) { + ret = env->AllocateManaged(length, false); + if (ret.data() == nullptr) { THROW_ERR_MEMORY_ALLOCATION_FAILED(env); return Local<Object>(); } - memcpy(new_data, data, length); - } else { - new_data = nullptr; + memcpy(ret.data(), data, length); } - Local<ArrayBuffer> ab = - ArrayBuffer::New(env->isolate(), - new_data, - length, - ArrayBufferCreationMode::kInternalized); - Local<Object> obj; - if (Buffer::New(env, ab, 0, length).ToLocal(&obj)) - return scope.Escape(obj); - return Local<Object>(); + return scope.EscapeMaybe(ret.ToBuffer()); } @@ -425,7 +388,8 @@ MaybeLocal<Object> New(Environment* env, return scope.Escape(ui.ToLocalChecked()); } - +// Warning: This function needs `data` to be allocated with malloc() and not +// necessarily isolate's ArrayBuffer::Allocator. MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) { EscapableHandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); @@ -435,18 +399,37 @@ MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) { return MaybeLocal<Object>(); } Local<Object> obj; - if (Buffer::New(env, data, length).ToLocal(&obj)) + if (Buffer::New(env, data, length, true).ToLocal(&obj)) return handle_scope.Escape(obj); return Local<Object>(); } - -MaybeLocal<Object> New(Environment* env, char* data, size_t length) { +// Warning: If this call comes through the public node_buffer.h API, +// the contract for this function is that `data` is allocated with malloc() +// and not necessarily isolate's ArrayBuffer::Allocator. +MaybeLocal<Object> New(Environment* env, + char* data, + size_t length, + bool uses_malloc) { if (length > 0) { CHECK_NOT_NULL(data); CHECK(length <= kMaxLength); } + if (uses_malloc) { + if (env->isolate_data()->uses_node_allocator()) { + // We don't know for sure that the allocator is malloc()-based, so we need + // to fall back to the FreeCallback variant. + auto free_callback = [](char* data, void* hint) { free(data); }; + return New(env, data, length, free_callback, nullptr); + } else { + // This is malloc()-based, so we can acquire it into our own + // ArrayBufferAllocator. + CHECK_NOT_NULL(env->isolate_data()->node_allocator()); + env->isolate_data()->node_allocator()->RegisterPointer(data, length); + } + } + Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, @@ -1053,15 +1036,13 @@ static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) { Local<String> str = args[0].As<String>(); size_t length = str->Utf8Length(isolate); - char* data = node::UncheckedMalloc(length); + AllocatedBuffer buf = env->AllocateManaged(length); str->WriteUtf8(isolate, - data, + buf.data(), -1, // We are certain that `data` is sufficiently large nullptr, String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8); - auto array_buf = ArrayBuffer::New( - isolate, data, length, ArrayBufferCreationMode::kInternalized); - auto array = Uint8Array::New(array_buf, 0, length); + auto array = Uint8Array::New(buf.ToArrayBuffer(), 0, length); args.GetReturnValue().Set(array); } @@ -1123,7 +1104,8 @@ void Initialize(Local<Object> target, // It can be a nullptr when running inside an isolate where we // do not own the ArrayBuffer allocator. - if (uint32_t* zero_fill_field = env->isolate_data()->zero_fill_field()) { + if (ArrayBufferAllocator* allocator = env->isolate_data()->node_allocator()) { + uint32_t* zero_fill_field = allocator->zero_fill_field(); Local<ArrayBuffer> array_buffer = ArrayBuffer::New( env->isolate(), zero_fill_field, sizeof(*zero_fill_field)); CHECK(target |