From ad854ea11e787a673a40b7917a955bee6d7dc253 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 20 Apr 2015 08:01:55 -0700 Subject: [PATCH] Allow for accessing an ArrayBuffer contents without externalizing it The embedder has to take appropriate steps to ensure that the ArrayBuffer doesn't die while it's accessing the pointer, e.g. keep a Local handle to it around BUG=none R=dslomov@chromium.org LOG=y Review URL: https://codereview.chromium.org/1095083002 Cr-Commit-Position: refs/heads/master@{#27942} --- include/v8.h | 23 ++++++++++++++++++++--- src/api.cc | 24 ++++++++++++++++-------- test/cctest/test-typedarrays.cc | 13 +++++++++++++ 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/include/v8.h b/include/v8.h index ebb0639..3bc0c71 100644 --- a/include/v8.h +++ b/include/v8.h @@ -3301,6 +3301,10 @@ class V8_EXPORT Promise : public Object { #define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2 #endif + +enum class ArrayBufferCreationMode { kInternalized, kExternalized }; + + /** * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). * This API is experimental and may change significantly. @@ -3376,12 +3380,13 @@ class V8_EXPORT ArrayBuffer : public Object { /** * Create a new ArrayBuffer over an existing memory block. - * The created array buffer is immediately in externalized state. + * The created array buffer is by default immediately in externalized state. * The memory block will not be reclaimed when a created ArrayBuffer * is garbage-collected. */ - static Local New(Isolate* isolate, void* data, - size_t byte_length); + static Local New( + Isolate* isolate, void* data, size_t byte_length, + ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized); /** * Returns true if ArrayBuffer is extrenalized, that is, does not @@ -3413,6 +3418,18 @@ class V8_EXPORT ArrayBuffer : public Object { */ Contents Externalize(); + /** + * Get a pointer to the ArrayBuffer's underlying memory block without + * externalizing it. If the ArrayBuffer is not externalized, this pointer + * will become invalid as soon as the ArrayBuffer became garbage collected. + * + * The embedder should make sure to hold a strong reference to the + * ArrayBuffer while accessing this pointer. + * + * The memory block is guaranteed to be allocated with |Allocator::Allocate|. + */ + Contents GetContents(); + V8_INLINE static ArrayBuffer* Cast(Value* obj); static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; diff --git a/src/api.cc b/src/api.cc index 38b3679..3a89095 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6234,14 +6234,19 @@ bool v8::ArrayBuffer::IsNeuterable() const { v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() { - i::Handle obj = Utils::OpenHandle(this); - Utils::ApiCheck(!obj->is_external(), - "v8::ArrayBuffer::Externalize", + i::Handle self = Utils::OpenHandle(this); + Utils::ApiCheck(!self->is_external(), "v8::ArrayBuffer::Externalize", "ArrayBuffer already externalized"); - obj->set_is_external(true); - size_t byte_length = static_cast(obj->byte_length()->Number()); + self->set_is_external(true); + return GetContents(); +} + + +v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents() { + i::Handle self = Utils::OpenHandle(this); + size_t byte_length = static_cast(self->byte_length()->Number()); Contents contents; - contents.data_ = obj->backing_store(); + contents.data_ = self->backing_store(); contents.byte_length_ = byte_length; return contents; } @@ -6279,13 +6284,16 @@ Local v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) { Local v8::ArrayBuffer::New(Isolate* isolate, void* data, - size_t byte_length) { + size_t byte_length, + ArrayBufferCreationMode mode) { i::Isolate* i_isolate = reinterpret_cast(isolate); LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)"); ENTER_V8(i_isolate); i::Handle obj = i_isolate->factory()->NewJSArrayBuffer(); - i::Runtime::SetupArrayBuffer(i_isolate, obj, true, data, byte_length); + i::Runtime::SetupArrayBuffer(i_isolate, obj, + mode == ArrayBufferCreationMode::kExternalized, + data, byte_length); return Utils::ToLocal(obj); } diff --git a/test/cctest/test-typedarrays.cc b/test/cctest/test-typedarrays.cc index 966edb7..d031048 100644 --- a/test/cctest/test-typedarrays.cc +++ b/test/cctest/test-typedarrays.cc @@ -10,6 +10,7 @@ #include "src/api.h" #include "src/heap/heap.h" #include "src/objects.h" +#include "src/v8.h" using namespace v8::internal; @@ -66,3 +67,15 @@ TEST(CopyContentsView) { "var a = new DataView(b, 2);"); TestArrayBufferViewContents(env, true); } + + +TEST(AllocateNotExternal) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + void* memory = V8::ArrayBufferAllocator()->Allocate(1024); + v8::Local buffer = + v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024, + v8::ArrayBufferCreationMode::kInternalized); + CHECK(!buffer->IsExternal()); + CHECK_EQ(memory, buffer->GetContents().Data()); +} -- 2.7.4