summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-02-18 22:58:19 +0100
committerAnna Henningsen <anna@addaleax.net>2019-02-25 02:01:05 +0100
commit6c257cdf271384555d0ced77104a1d6b0480e246 (patch)
tree3b44f52c44ed83ecb5f0e5f98231e0f1c6fc1c1e /src
parent376735345088d4b37e0e289c2eb7720419ed37ee (diff)
downloadandroid-node-v8-6c257cdf271384555d0ced77104a1d6b0480e246.tar.gz
android-node-v8-6c257cdf271384555d0ced77104a1d6b0480e246.tar.bz2
android-node-v8-6c257cdf271384555d0ced77104a1d6b0480e246.zip
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: 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')
-rw-r--r--src/env-inl.h98
-rw-r--r--src/env.cc18
-rw-r--r--src/env.h41
3 files changed, 157 insertions, 0 deletions
diff --git a/src/env-inl.h b/src/env-inl.h
index 51c7e0d7b0..63b71daf15 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -715,6 +715,104 @@ inline IsolateData* Environment::isolate_data() const {
return isolate_data_;
}
+inline char* Environment::AllocateUnchecked(size_t size) {
+ return static_cast<char*>(
+ isolate_data()->allocator()->AllocateUninitialized(size));
+}
+
+inline char* Environment::Allocate(size_t size) {
+ char* ret = AllocateUnchecked(size);
+ CHECK_NE(ret, nullptr);
+ return ret;
+}
+
+inline void Environment::Free(char* data, size_t size) {
+ if (data != nullptr)
+ isolate_data()->allocator()->Free(data, size);
+}
+
+inline AllocatedBuffer Environment::AllocateManaged(size_t size, bool checked) {
+ char* data = checked ? Allocate(size) : AllocateUnchecked(size);
+ if (data == nullptr) size = 0;
+ return AllocatedBuffer(this, uv_buf_init(data, size));
+}
+
+inline AllocatedBuffer::AllocatedBuffer(Environment* env, uv_buf_t buf)
+ : env_(env), buffer_(buf) {}
+
+inline void AllocatedBuffer::Resize(size_t len) {
+ char* new_data = env_->Reallocate(buffer_.base, buffer_.len, len);
+ CHECK_IMPLIES(len > 0, new_data != nullptr);
+ buffer_ = uv_buf_init(new_data, len);
+}
+
+inline uv_buf_t AllocatedBuffer::release() {
+ uv_buf_t ret = buffer_;
+ buffer_ = uv_buf_init(nullptr, 0);
+ return ret;
+}
+
+inline char* AllocatedBuffer::data() {
+ return buffer_.base;
+}
+
+inline const char* AllocatedBuffer::data() const {
+ return buffer_.base;
+}
+
+inline size_t AllocatedBuffer::size() const {
+ return buffer_.len;
+}
+
+inline AllocatedBuffer::AllocatedBuffer(Environment* env)
+ : env_(env), buffer_(uv_buf_init(nullptr, 0)) {}
+
+inline AllocatedBuffer::AllocatedBuffer(AllocatedBuffer&& other)
+ : AllocatedBuffer() {
+ *this = std::move(other);
+}
+
+inline AllocatedBuffer& AllocatedBuffer::operator=(AllocatedBuffer&& other) {
+ clear();
+ env_ = other.env_;
+ buffer_ = other.release();
+ return *this;
+}
+
+inline AllocatedBuffer::~AllocatedBuffer() {
+ clear();
+}
+
+inline void AllocatedBuffer::clear() {
+ uv_buf_t buf = release();
+ env_->Free(buf.base, buf.len);
+}
+
+// It's a bit awkward to define this Buffer::New() overload here, but it
+// avoids a circular dependency with node_internals.h.
+namespace Buffer {
+v8::MaybeLocal<v8::Object> New(Environment* env,
+ char* data,
+ size_t length,
+ bool uses_malloc);
+}
+
+inline v8::MaybeLocal<v8::Object> AllocatedBuffer::ToBuffer() {
+ CHECK_NOT_NULL(env_);
+ v8::MaybeLocal<v8::Object> obj = Buffer::New(env_, data(), size(), false);
+ if (!obj.IsEmpty()) release();
+ return obj;
+}
+
+inline v8::Local<v8::ArrayBuffer> AllocatedBuffer::ToArrayBuffer() {
+ CHECK_NOT_NULL(env_);
+ uv_buf_t buf = release();
+ return v8::ArrayBuffer::New(env_->isolate(),
+ buf.base,
+ buf.len,
+ v8::ArrayBufferCreationMode::kInternalized);
+}
+
inline void Environment::ThrowError(const char* errmsg) {
ThrowError(v8::Exception::Error, errmsg);
}
diff --git a/src/env.cc b/src/env.cc
index b7b6d745d8..fce949f63a 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -21,6 +21,7 @@
namespace node {
using errors::TryCatchScope;
+using v8::ArrayBuffer;
using v8::Boolean;
using v8::Context;
using v8::EmbedderGraph;
@@ -905,6 +906,23 @@ void Environment::BuildEmbedderGraph(Isolate* isolate,
});
}
+char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
+ // If we know that the allocator is our ArrayBufferAllocator, we can let
+ // if reallocate directly.
+ if (isolate_data()->uses_node_allocator()) {
+ return static_cast<char*>(
+ isolate_data()->node_allocator()->Reallocate(data, old_size, size));
+ }
+ // Generic allocators do not provide a reallocation method; we need to
+ // allocate a new chunk of memory and copy the data over.
+ char* new_data = AllocateUnchecked(size);
+ if (new_data == nullptr) return nullptr;
+ memcpy(new_data, data, std::min(size, old_size));
+ if (size > old_size)
+ memset(new_data + old_size, 0, size - old_size);
+ Free(data, old_size);
+ return new_data;
+}
// Not really any better place than env.cc at this moment.
void BaseObject::DeleteMe(void* data) {
diff --git a/src/env.h b/src/env.h
index 527a28f695..3856f5241d 100644
--- a/src/env.h
+++ b/src/env.h
@@ -476,6 +476,38 @@ enum class DebugCategory {
CATEGORY_COUNT
};
+// A unique-pointer-ish object that is compatible with the JS engine's
+// ArrayBuffer::Allocator.
+struct AllocatedBuffer {
+ public:
+ explicit inline AllocatedBuffer(Environment* env = nullptr);
+ inline AllocatedBuffer(Environment* env, uv_buf_t buf);
+ inline ~AllocatedBuffer();
+ inline void Resize(size_t len);
+
+ inline uv_buf_t release();
+ inline char* data();
+ inline const char* data() const;
+ inline size_t size() const;
+ inline void clear();
+
+ inline v8::MaybeLocal<v8::Object> ToBuffer();
+ inline v8::Local<v8::ArrayBuffer> ToArrayBuffer();
+
+ inline AllocatedBuffer(AllocatedBuffer&& other);
+ inline AllocatedBuffer& operator=(AllocatedBuffer&& other);
+ AllocatedBuffer(const AllocatedBuffer& other) = delete;
+ AllocatedBuffer& operator=(const AllocatedBuffer& other) = delete;
+
+ private:
+ Environment* env_;
+ // We do not pass this to libuv directly, but uv_buf_t is a convenient way
+ // to represent a chunk of memory, and plays nicely with other parts of core.
+ uv_buf_t buffer_;
+
+ friend class Environment;
+};
+
class Environment {
public:
class AsyncHooks {
@@ -697,6 +729,15 @@ class Environment {
inline IsolateData* isolate_data() const;
+ // Utilites that allocate memory using the Isolate's ArrayBuffer::Allocator.
+ // In particular, using AllocateManaged() will provide a RAII-style object
+ // with easy conversion to `Buffer` and `ArrayBuffer` objects.
+ inline AllocatedBuffer AllocateManaged(size_t size, bool checked = true);
+ inline char* Allocate(size_t size);
+ inline char* AllocateUnchecked(size_t size);
+ char* Reallocate(char* data, size_t old_size, size_t size);
+ inline void Free(char* data, size_t size);
+
inline bool printed_error() const;
inline void set_printed_error(bool value);