embedding: refactor public ArrayBufferAllocator
API
Use a RAII approach by default, and make it possible for embedders to use the `ArrayBufferAllocator` directly as a V8 `ArrayBuffer::Allocator`, e.g. when passing to `Isolate::CreateParams` manually. PR-URL: https://github.com/nodejs/node/pull/26525 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
17ab2ed3c8
commit
0e3adddd0d
@ -68,7 +68,7 @@ static void OnMessage(Local<Message> message, Local<Value> error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ArrayBufferAllocator::Allocate(size_t size) {
|
void* NodeArrayBufferAllocator::Allocate(size_t size) {
|
||||||
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
||||||
return UncheckedCalloc(size);
|
return UncheckedCalloc(size);
|
||||||
else
|
else
|
||||||
@ -81,14 +81,14 @@ DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
|
|||||||
|
|
||||||
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
|
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
void* data = ArrayBufferAllocator::Allocate(size);
|
void* data = NodeArrayBufferAllocator::Allocate(size);
|
||||||
RegisterPointerInternal(data, size);
|
RegisterPointerInternal(data, size);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
|
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
void* data = ArrayBufferAllocator::AllocateUninitialized(size);
|
void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
|
||||||
RegisterPointerInternal(data, size);
|
RegisterPointerInternal(data, size);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -96,14 +96,14 @@ void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
|
|||||||
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
|
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
UnregisterPointerInternal(data, size);
|
UnregisterPointerInternal(data, size);
|
||||||
ArrayBufferAllocator::Free(data, size);
|
NodeArrayBufferAllocator::Free(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
|
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
|
||||||
size_t old_size,
|
size_t old_size,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
void* ret = ArrayBufferAllocator::Reallocate(data, old_size, size);
|
void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
|
||||||
if (ret == nullptr) {
|
if (ret == nullptr) {
|
||||||
if (size == 0) // i.e. equivalent to free().
|
if (size == 0) // i.e. equivalent to free().
|
||||||
UnregisterPointerInternal(data, old_size);
|
UnregisterPointerInternal(data, old_size);
|
||||||
@ -146,11 +146,15 @@ void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
|
|||||||
allocations_[data] = size;
|
allocations_[data] = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayBufferAllocator* CreateArrayBufferAllocator() {
|
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
|
||||||
if (per_process::cli_options->debug_arraybuffer_allocations)
|
if (debug || per_process::cli_options->debug_arraybuffer_allocations)
|
||||||
return new DebuggingArrayBufferAllocator();
|
return std::make_unique<DebuggingArrayBufferAllocator>();
|
||||||
else
|
else
|
||||||
return new ArrayBufferAllocator();
|
return std::make_unique<NodeArrayBufferAllocator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayBufferAllocator* CreateArrayBufferAllocator() {
|
||||||
|
return ArrayBufferAllocator::Create().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
|
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
|
||||||
|
@ -57,7 +57,7 @@ inline v8::ArrayBuffer::Allocator* IsolateData::allocator() const {
|
|||||||
return allocator_;
|
return allocator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ArrayBufferAllocator* IsolateData::node_allocator() const {
|
inline NodeArrayBufferAllocator* IsolateData::node_allocator() const {
|
||||||
return node_allocator_;
|
return node_allocator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ IsolateData::IsolateData(Isolate* isolate,
|
|||||||
: isolate_(isolate),
|
: isolate_(isolate),
|
||||||
event_loop_(event_loop),
|
event_loop_(event_loop),
|
||||||
allocator_(isolate->GetArrayBufferAllocator()),
|
allocator_(isolate->GetArrayBufferAllocator()),
|
||||||
node_allocator_(node_allocator),
|
node_allocator_(node_allocator == nullptr ?
|
||||||
|
nullptr : node_allocator->GetImpl()),
|
||||||
uses_node_allocator_(allocator_ == node_allocator_),
|
uses_node_allocator_(allocator_ == node_allocator_),
|
||||||
platform_(platform) {
|
platform_(platform) {
|
||||||
CHECK_NOT_NULL(allocator_);
|
CHECK_NOT_NULL(allocator_);
|
||||||
|
@ -408,7 +408,7 @@ class IsolateData {
|
|||||||
|
|
||||||
inline bool uses_node_allocator() const;
|
inline bool uses_node_allocator() const;
|
||||||
inline v8::ArrayBuffer::Allocator* allocator() const;
|
inline v8::ArrayBuffer::Allocator* allocator() const;
|
||||||
inline ArrayBufferAllocator* node_allocator() const;
|
inline NodeArrayBufferAllocator* node_allocator() const;
|
||||||
|
|
||||||
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
|
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
|
||||||
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
|
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
|
||||||
@ -443,7 +443,7 @@ class IsolateData {
|
|||||||
v8::Isolate* const isolate_;
|
v8::Isolate* const isolate_;
|
||||||
uv_loop_t* const event_loop_;
|
uv_loop_t* const event_loop_;
|
||||||
v8::ArrayBuffer::Allocator* const allocator_;
|
v8::ArrayBuffer::Allocator* const allocator_;
|
||||||
ArrayBufferAllocator* const node_allocator_;
|
NodeArrayBufferAllocator* const node_allocator_;
|
||||||
const bool uses_node_allocator_;
|
const bool uses_node_allocator_;
|
||||||
MultiIsolatePlatform* platform_;
|
MultiIsolatePlatform* platform_;
|
||||||
std::shared_ptr<PerIsolateOptions> options_;
|
std::shared_ptr<PerIsolateOptions> options_;
|
||||||
|
26
src/node.h
26
src/node.h
@ -64,6 +64,8 @@
|
|||||||
#include "v8-platform.h" // NOLINT(build/include_order)
|
#include "v8-platform.h" // NOLINT(build/include_order)
|
||||||
#include "node_version.h" // NODE_MODULE_VERSION
|
#include "node_version.h" // NODE_MODULE_VERSION
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define NODE_MAKE_VERSION(major, minor, patch) \
|
#define NODE_MAKE_VERSION(major, minor, patch) \
|
||||||
((major) * 0x1000 + (minor) * 0x100 + (patch))
|
((major) * 0x1000 + (minor) * 0x100 + (patch))
|
||||||
|
|
||||||
@ -210,8 +212,30 @@ NODE_EXTERN void Init(int* argc,
|
|||||||
int* exec_argc,
|
int* exec_argc,
|
||||||
const char*** exec_argv);
|
const char*** exec_argv);
|
||||||
|
|
||||||
class ArrayBufferAllocator;
|
class NodeArrayBufferAllocator;
|
||||||
|
|
||||||
|
// An ArrayBuffer::Allocator class with some Node.js-specific tweaks. If you do
|
||||||
|
// not have to use another allocator, using this class is recommended:
|
||||||
|
// - It supports Buffer.allocUnsafe() and Buffer.allocUnsafeSlow() with
|
||||||
|
// uninitialized memory.
|
||||||
|
// - It supports transferring, rather than copying, ArrayBuffers when using
|
||||||
|
// MessagePorts.
|
||||||
|
class NODE_EXTERN ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
||||||
|
public:
|
||||||
|
// If `always_debug` is true, create an ArrayBuffer::Allocator instance
|
||||||
|
// that performs additional integrity checks (e.g. make sure that only memory
|
||||||
|
// that was allocated by the it is also freed by it).
|
||||||
|
// This can also be set using the --debug-arraybuffer-allocations flag.
|
||||||
|
static std::unique_ptr<ArrayBufferAllocator> Create(
|
||||||
|
bool always_debug = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual NodeArrayBufferAllocator* GetImpl() = 0;
|
||||||
|
|
||||||
|
friend class IsolateData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Legacy equivalents for ArrayBufferAllocator::Create().
|
||||||
NODE_EXTERN ArrayBufferAllocator* CreateArrayBufferAllocator();
|
NODE_EXTERN ArrayBufferAllocator* CreateArrayBufferAllocator();
|
||||||
NODE_EXTERN void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator);
|
NODE_EXTERN void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator);
|
||||||
|
|
||||||
|
@ -1104,7 +1104,8 @@ void Initialize(Local<Object> target,
|
|||||||
|
|
||||||
// It can be a nullptr when running inside an isolate where we
|
// It can be a nullptr when running inside an isolate where we
|
||||||
// do not own the ArrayBuffer allocator.
|
// do not own the ArrayBuffer allocator.
|
||||||
if (ArrayBufferAllocator* allocator = env->isolate_data()->node_allocator()) {
|
if (NodeArrayBufferAllocator* allocator =
|
||||||
|
env->isolate_data()->node_allocator()) {
|
||||||
uint32_t* zero_fill_field = allocator->zero_fill_field();
|
uint32_t* zero_fill_field = allocator->zero_fill_field();
|
||||||
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
|
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
|
||||||
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
|
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
|
||||||
|
@ -101,7 +101,7 @@ namespace task_queue {
|
|||||||
void PromiseRejectCallback(v8::PromiseRejectMessage message);
|
void PromiseRejectCallback(v8::PromiseRejectMessage message);
|
||||||
} // namespace task_queue
|
} // namespace task_queue
|
||||||
|
|
||||||
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
class NodeArrayBufferAllocator : public ArrayBufferAllocator {
|
||||||
public:
|
public:
|
||||||
inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
|
inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
|
||||||
|
|
||||||
@ -116,11 +116,13 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
|||||||
virtual void RegisterPointer(void* data, size_t size) {}
|
virtual void RegisterPointer(void* data, size_t size) {}
|
||||||
virtual void UnregisterPointer(void* data, size_t size) {}
|
virtual void UnregisterPointer(void* data, size_t size) {}
|
||||||
|
|
||||||
|
NodeArrayBufferAllocator* GetImpl() final { return this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
|
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebuggingArrayBufferAllocator final : public ArrayBufferAllocator {
|
class DebuggingArrayBufferAllocator final : public NodeArrayBufferAllocator {
|
||||||
public:
|
public:
|
||||||
~DebuggingArrayBufferAllocator() override;
|
~DebuggingArrayBufferAllocator() override;
|
||||||
void* Allocate(size_t size) override;
|
void* Allocate(size_t size) override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user