Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2826076

Browse filesBrowse files
committed
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: #26207 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Backport-PR-URL: #26302 Reviewed-By: Michaël Zasso <targos@protonmail.com>
1 parent 238fa57 commit 2826076
Copy full SHA for 2826076

File tree

Expand file treeCollapse file tree

3 files changed

+157
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+157
-0
lines changed
Open diff view settings
Collapse file

‎src/env-inl.h‎

Copy file name to clipboardExpand all lines: src/env-inl.h
+98Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,104 @@ inline IsolateData* Environment::isolate_data() const {
715715
return isolate_data_;
716716
}
717717

718+
inline char* Environment::AllocateUnchecked(size_t size) {
719+
return static_cast<char*>(
720+
isolate_data()->allocator()->AllocateUninitialized(size));
721+
}
722+
723+
inline char* Environment::Allocate(size_t size) {
724+
char* ret = AllocateUnchecked(size);
725+
CHECK_NE(ret, nullptr);
726+
return ret;
727+
}
728+
729+
inline void Environment::Free(char* data, size_t size) {
730+
if (data != nullptr)
731+
isolate_data()->allocator()->Free(data, size);
732+
}
733+
734+
inline AllocatedBuffer Environment::AllocateManaged(size_t size, bool checked) {
735+
char* data = checked ? Allocate(size) : AllocateUnchecked(size);
736+
if (data == nullptr) size = 0;
737+
return AllocatedBuffer(this, uv_buf_init(data, size));
738+
}
739+
740+
inline AllocatedBuffer::AllocatedBuffer(Environment* env, uv_buf_t buf)
741+
: env_(env), buffer_(buf) {}
742+
743+
inline void AllocatedBuffer::Resize(size_t len) {
744+
char* new_data = env_->Reallocate(buffer_.base, buffer_.len, len);
745+
CHECK_IMPLIES(len > 0, new_data != nullptr);
746+
buffer_ = uv_buf_init(new_data, len);
747+
}
748+
749+
inline uv_buf_t AllocatedBuffer::release() {
750+
uv_buf_t ret = buffer_;
751+
buffer_ = uv_buf_init(nullptr, 0);
752+
return ret;
753+
}
754+
755+
inline char* AllocatedBuffer::data() {
756+
return buffer_.base;
757+
}
758+
759+
inline const char* AllocatedBuffer::data() const {
760+
return buffer_.base;
761+
}
762+
763+
inline size_t AllocatedBuffer::size() const {
764+
return buffer_.len;
765+
}
766+
767+
inline AllocatedBuffer::AllocatedBuffer(Environment* env)
768+
: env_(env), buffer_(uv_buf_init(nullptr, 0)) {}
769+
770+
inline AllocatedBuffer::AllocatedBuffer(AllocatedBuffer&& other)
771+
: AllocatedBuffer() {
772+
*this = std::move(other);
773+
}
774+
775+
inline AllocatedBuffer& AllocatedBuffer::operator=(AllocatedBuffer&& other) {
776+
clear();
777+
env_ = other.env_;
778+
buffer_ = other.release();
779+
return *this;
780+
}
781+
782+
inline AllocatedBuffer::~AllocatedBuffer() {
783+
clear();
784+
}
785+
786+
inline void AllocatedBuffer::clear() {
787+
uv_buf_t buf = release();
788+
env_->Free(buf.base, buf.len);
789+
}
790+
791+
// It's a bit awkward to define this Buffer::New() overload here, but it
792+
// avoids a circular dependency with node_internals.h.
793+
namespace Buffer {
794+
v8::MaybeLocal<v8::Object> New(Environment* env,
795+
char* data,
796+
size_t length,
797+
bool uses_malloc);
798+
}
799+
800+
inline v8::MaybeLocal<v8::Object> AllocatedBuffer::ToBuffer() {
801+
CHECK_NOT_NULL(env_);
802+
v8::MaybeLocal<v8::Object> obj = Buffer::New(env_, data(), size(), false);
803+
if (!obj.IsEmpty()) release();
804+
return obj;
805+
}
806+
807+
inline v8::Local<v8::ArrayBuffer> AllocatedBuffer::ToArrayBuffer() {
808+
CHECK_NOT_NULL(env_);
809+
uv_buf_t buf = release();
810+
return v8::ArrayBuffer::New(env_->isolate(),
811+
buf.base,
812+
buf.len,
813+
v8::ArrayBufferCreationMode::kInternalized);
814+
}
815+
718816
inline void Environment::ThrowError(const char* errmsg) {
719817
ThrowError(v8::Exception::Error, errmsg);
720818
}
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
namespace node {
2222

2323
using errors::TryCatchScope;
24+
using v8::ArrayBuffer;
2425
using v8::Boolean;
2526
using v8::Context;
2627
using v8::EmbedderGraph;
@@ -924,6 +925,23 @@ void Environment::BuildEmbedderGraph(Isolate* isolate,
924925
});
925926
}
926927

928+
char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
929+
// If we know that the allocator is our ArrayBufferAllocator, we can let
930+
// if reallocate directly.
931+
if (isolate_data()->uses_node_allocator()) {
932+
return static_cast<char*>(
933+
isolate_data()->node_allocator()->Reallocate(data, old_size, size));
934+
}
935+
// Generic allocators do not provide a reallocation method; we need to
936+
// allocate a new chunk of memory and copy the data over.
937+
char* new_data = AllocateUnchecked(size);
938+
if (new_data == nullptr) return nullptr;
939+
memcpy(new_data, data, std::min(size, old_size));
940+
if (size > old_size)
941+
memset(new_data + old_size, 0, size - old_size);
942+
Free(data, old_size);
943+
return new_data;
944+
}
927945

928946
// Not really any better place than env.cc at this moment.
929947
void BaseObject::DeleteMe(void* data) {
Collapse file

‎src/env.h‎

Copy file name to clipboardExpand all lines: src/env.h
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,38 @@ enum class DebugCategory {
474474
CATEGORY_COUNT
475475
};
476476

477+
// A unique-pointer-ish object that is compatible with the JS engine's
478+
// ArrayBuffer::Allocator.
479+
struct AllocatedBuffer {
480+
public:
481+
explicit inline AllocatedBuffer(Environment* env = nullptr);
482+
inline AllocatedBuffer(Environment* env, uv_buf_t buf);
483+
inline ~AllocatedBuffer();
484+
inline void Resize(size_t len);
485+
486+
inline uv_buf_t release();
487+
inline char* data();
488+
inline const char* data() const;
489+
inline size_t size() const;
490+
inline void clear();
491+
492+
inline v8::MaybeLocal<v8::Object> ToBuffer();
493+
inline v8::Local<v8::ArrayBuffer> ToArrayBuffer();
494+
495+
inline AllocatedBuffer(AllocatedBuffer&& other);
496+
inline AllocatedBuffer& operator=(AllocatedBuffer&& other);
497+
AllocatedBuffer(const AllocatedBuffer& other) = delete;
498+
AllocatedBuffer& operator=(const AllocatedBuffer& other) = delete;
499+
500+
private:
501+
Environment* env_;
502+
// We do not pass this to libuv directly, but uv_buf_t is a convenient way
503+
// to represent a chunk of memory, and plays nicely with other parts of core.
504+
uv_buf_t buffer_;
505+
506+
friend class Environment;
507+
};
508+
477509
class Environment {
478510
public:
479511
class AsyncHooks {
@@ -695,6 +727,15 @@ class Environment {
695727

696728
inline IsolateData* isolate_data() const;
697729

730+
// Utilites that allocate memory using the Isolate's ArrayBuffer::Allocator.
731+
// In particular, using AllocateManaged() will provide a RAII-style object
732+
// with easy conversion to `Buffer` and `ArrayBuffer` objects.
733+
inline AllocatedBuffer AllocateManaged(size_t size, bool checked = true);
734+
inline char* Allocate(size_t size);
735+
inline char* AllocateUnchecked(size_t size);
736+
char* Reallocate(char* data, size_t old_size, size_t size);
737+
inline void Free(char* data, size_t size);
738+
698739
inline bool printed_error() const;
699740
inline void set_printed_error(bool value);
700741

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.