Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit b2ed6c3

Browse files
addaleaxdeepak1556
authored andcommitted
src: add allocation utils to env
Add a RAII utility for managing blocks of memory that have been allocated with the `ArrayBuffer::Allocator` for a given `Isolate`. PR-URL: nodejs/node#26207 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 8867a26 commit b2ed6c3

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed

src/env-inl.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,104 @@ inline IsolateData* Environment::isolate_data() const {
669669
return isolate_data_;
670670
}
671671

672+
inline char* Environment::AllocateUnchecked(size_t size) {
673+
return static_cast<char*>(
674+
isolate_data()->allocator()->AllocateUninitialized(size));
675+
}
676+
677+
inline char* Environment::Allocate(size_t size) {
678+
char* ret = AllocateUnchecked(size);
679+
CHECK_NE(ret, nullptr);
680+
return ret;
681+
}
682+
683+
inline void Environment::Free(char* data, size_t size) {
684+
if (data != nullptr)
685+
isolate_data()->allocator()->Free(data, size);
686+
}
687+
688+
inline AllocatedBuffer Environment::AllocateManaged(size_t size, bool checked) {
689+
char* data = checked ? Allocate(size) : AllocateUnchecked(size);
690+
if (data == nullptr) size = 0;
691+
return AllocatedBuffer(this, uv_buf_init(data, size));
692+
}
693+
694+
inline AllocatedBuffer::AllocatedBuffer(Environment* env, uv_buf_t buf)
695+
: env_(env), buffer_(buf) {}
696+
697+
inline void AllocatedBuffer::Resize(size_t len) {
698+
char* new_data = env_->Reallocate(buffer_.base, buffer_.len, len);
699+
CHECK_IMPLIES(len > 0, new_data != nullptr);
700+
buffer_ = uv_buf_init(new_data, len);
701+
}
702+
703+
inline uv_buf_t AllocatedBuffer::release() {
704+
uv_buf_t ret = buffer_;
705+
buffer_ = uv_buf_init(nullptr, 0);
706+
return ret;
707+
}
708+
709+
inline char* AllocatedBuffer::data() {
710+
return buffer_.base;
711+
}
712+
713+
inline const char* AllocatedBuffer::data() const {
714+
return buffer_.base;
715+
}
716+
717+
inline size_t AllocatedBuffer::size() const {
718+
return buffer_.len;
719+
}
720+
721+
inline AllocatedBuffer::AllocatedBuffer(Environment* env)
722+
: env_(env), buffer_(uv_buf_init(nullptr, 0)) {}
723+
724+
inline AllocatedBuffer::AllocatedBuffer(AllocatedBuffer&& other)
725+
: AllocatedBuffer() {
726+
*this = std::move(other);
727+
}
728+
729+
inline AllocatedBuffer& AllocatedBuffer::operator=(AllocatedBuffer&& other) {
730+
clear();
731+
env_ = other.env_;
732+
buffer_ = other.release();
733+
return *this;
734+
}
735+
736+
inline AllocatedBuffer::~AllocatedBuffer() {
737+
clear();
738+
}
739+
740+
inline void AllocatedBuffer::clear() {
741+
uv_buf_t buf = release();
742+
env_->Free(buf.base, buf.len);
743+
}
744+
745+
// It's a bit awkward to define this Buffer::New() overload here, but it
746+
// avoids a circular dependency with node_internals.h.
747+
namespace Buffer {
748+
v8::MaybeLocal<v8::Object> New(Environment* env,
749+
char* data,
750+
size_t length,
751+
bool uses_malloc);
752+
}
753+
754+
inline v8::MaybeLocal<v8::Object> AllocatedBuffer::ToBuffer() {
755+
CHECK_NOT_NULL(env_);
756+
v8::MaybeLocal<v8::Object> obj = Buffer::New(env_, data(), size(), false);
757+
if (!obj.IsEmpty()) release();
758+
return obj;
759+
}
760+
761+
inline v8::Local<v8::ArrayBuffer> AllocatedBuffer::ToArrayBuffer() {
762+
CHECK_NOT_NULL(env_);
763+
uv_buf_t buf = release();
764+
return v8::ArrayBuffer::New(env_->isolate(),
765+
buf.base,
766+
buf.len,
767+
v8::ArrayBufferCreationMode::kInternalized);
768+
}
769+
672770
inline void Environment::ThrowError(const char* errmsg) {
673771
ThrowError(v8::Exception::Error, errmsg);
674772
}

src/env.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace node {
1515

16+
using v8::ArrayBuffer;
1617
using v8::Context;
1718
using v8::FunctionTemplate;
1819
using v8::HandleScope;
@@ -691,6 +692,23 @@ void Environment::BuildEmbedderGraph(v8::Isolate* isolate,
691692
});
692693
}
693694

695+
char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
696+
// If we know that the allocator is our ArrayBufferAllocator, we can let
697+
// if reallocate directly.
698+
if (isolate_data()->uses_node_allocator()) {
699+
return static_cast<char*>(
700+
isolate_data()->node_allocator()->Reallocate(data, old_size, size));
701+
}
702+
// Generic allocators do not provide a reallocation method; we need to
703+
// allocate a new chunk of memory and copy the data over.
704+
char* new_data = AllocateUnchecked(size);
705+
if (new_data == nullptr) return nullptr;
706+
memcpy(new_data, data, std::min(size, old_size));
707+
if (size > old_size)
708+
memset(new_data + old_size, 0, size - old_size);
709+
Free(data, old_size);
710+
return new_data;
711+
}
694712

695713
// Not really any better place than env.cc at this moment.
696714
void BaseObject::DeleteMe(void* data) {

src/env.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,38 @@ enum class DebugCategory {
434434
CATEGORY_COUNT
435435
};
436436

437+
// A unique-pointer-ish object that is compatible with the JS engine's
438+
// ArrayBuffer::Allocator.
439+
struct AllocatedBuffer {
440+
public:
441+
explicit inline AllocatedBuffer(Environment* env = nullptr);
442+
inline AllocatedBuffer(Environment* env, uv_buf_t buf);
443+
inline ~AllocatedBuffer();
444+
inline void Resize(size_t len);
445+
446+
inline uv_buf_t release();
447+
inline char* data();
448+
inline const char* data() const;
449+
inline size_t size() const;
450+
inline void clear();
451+
452+
inline v8::MaybeLocal<v8::Object> ToBuffer();
453+
inline v8::Local<v8::ArrayBuffer> ToArrayBuffer();
454+
455+
inline AllocatedBuffer(AllocatedBuffer&& other);
456+
inline AllocatedBuffer& operator=(AllocatedBuffer&& other);
457+
AllocatedBuffer(const AllocatedBuffer& other) = delete;
458+
AllocatedBuffer& operator=(const AllocatedBuffer& other) = delete;
459+
460+
private:
461+
Environment* env_;
462+
// We do not pass this to libuv directly, but uv_buf_t is a convenient way
463+
// to represent a chunk of memory, and plays nicely with other parts of core.
464+
uv_buf_t buffer_;
465+
466+
friend class Environment;
467+
};
468+
437469
class Environment {
438470
public:
439471
class AsyncHooks {
@@ -648,6 +680,15 @@ class Environment {
648680

649681
inline IsolateData* isolate_data() const;
650682

683+
// Utilites that allocate memory using the Isolate's ArrayBuffer::Allocator.
684+
// In particular, using AllocateManaged() will provide a RAII-style object
685+
// with easy conversion to `Buffer` and `ArrayBuffer` objects.
686+
inline AllocatedBuffer AllocateManaged(size_t size, bool checked = true);
687+
inline char* Allocate(size_t size);
688+
inline char* AllocateUnchecked(size_t size);
689+
char* Reallocate(char* data, size_t old_size, size_t size);
690+
inline void Free(char* data, size_t size);
691+
651692
inline bool printed_error() const;
652693
inline void set_printed_error(bool value);
653694

0 commit comments

Comments
 (0)