Skip to content

Commit

Permalink
Allow for accessing an ArrayBuffer contents without externalizing it
Browse files Browse the repository at this point in the history
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}
  • Loading branch information
jeisinger authored and Commit bot committed Apr 20, 2015
1 parent 8cf289c commit ad854ea
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 11 deletions.
23 changes: 20 additions & 3 deletions include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<ArrayBuffer> New(Isolate* isolate, void* data,
size_t byte_length);
static Local<ArrayBuffer> New(
Isolate* isolate, void* data, size_t byte_length,
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);

/**
* Returns true if ArrayBuffer is extrenalized, that is, does not
Expand Down Expand Up @@ -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;
Expand Down
24 changes: 16 additions & 8 deletions src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6234,14 +6234,19 @@ bool v8::ArrayBuffer::IsNeuterable() const {


v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
Utils::ApiCheck(!obj->is_external(),
"v8::ArrayBuffer::Externalize",
i::Handle<i::JSArrayBuffer> 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<size_t>(obj->byte_length()->Number());
self->set_is_external(true);
return GetContents();
}


v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents() {
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
size_t byte_length = static_cast<size_t>(self->byte_length()->Number());
Contents contents;
contents.data_ = obj->backing_store();
contents.data_ = self->backing_store();
contents.byte_length_ = byte_length;
return contents;
}
Expand Down Expand Up @@ -6279,13 +6284,16 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) {


Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data,
size_t byte_length) {
size_t byte_length,
ArrayBufferCreationMode mode) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)");
ENTER_V8(i_isolate);
i::Handle<i::JSArrayBuffer> 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);
}

Expand Down
13 changes: 13 additions & 0 deletions test/cctest/test-typedarrays.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<v8::ArrayBuffer> buffer =
v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024,
v8::ArrayBufferCreationMode::kInternalized);
CHECK(!buffer->IsExternal());
CHECK_EQ(memory, buffer->GetContents().Data());
}

0 comments on commit ad854ea

Please sign in to comment.