Commit ad854ea1 authored by jochen's avatar jochen Committed by Commit bot

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}
parent 8cf289ca
......@@ -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<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
......@@ -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;
......
......@@ -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;
}
......@@ -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);
}
......
......@@ -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<v8::ArrayBuffer> buffer =
v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024,
v8::ArrayBufferCreationMode::kInternalized);
CHECK(!buffer->IsExternal());
CHECK_EQ(memory, buffer->GetContents().Data());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment