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}
This commit is contained in:
parent
8cf289ca4f
commit
ad854ea11e
23
include/v8.h
23
include/v8.h
@ -3301,6 +3301,10 @@ class V8_EXPORT Promise : public Object {
|
|||||||
#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
|
#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
enum class ArrayBufferCreationMode { kInternalized, kExternalized };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
|
* An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
|
||||||
* This API is experimental and may change significantly.
|
* 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.
|
* 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
|
* The memory block will not be reclaimed when a created ArrayBuffer
|
||||||
* is garbage-collected.
|
* is garbage-collected.
|
||||||
*/
|
*/
|
||||||
static Local<ArrayBuffer> New(Isolate* isolate, void* data,
|
static Local<ArrayBuffer> New(
|
||||||
size_t byte_length);
|
Isolate* isolate, void* data, size_t byte_length,
|
||||||
|
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if ArrayBuffer is extrenalized, that is, does not
|
* Returns true if ArrayBuffer is extrenalized, that is, does not
|
||||||
@ -3413,6 +3418,18 @@ class V8_EXPORT ArrayBuffer : public Object {
|
|||||||
*/
|
*/
|
||||||
Contents Externalize();
|
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);
|
V8_INLINE static ArrayBuffer* Cast(Value* obj);
|
||||||
|
|
||||||
static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
|
static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
|
||||||
|
24
src/api.cc
24
src/api.cc
@ -6234,14 +6234,19 @@ bool v8::ArrayBuffer::IsNeuterable() const {
|
|||||||
|
|
||||||
|
|
||||||
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
|
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
|
||||||
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
|
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
|
||||||
Utils::ApiCheck(!obj->is_external(),
|
Utils::ApiCheck(!self->is_external(), "v8::ArrayBuffer::Externalize",
|
||||||
"v8::ArrayBuffer::Externalize",
|
|
||||||
"ArrayBuffer already externalized");
|
"ArrayBuffer already externalized");
|
||||||
obj->set_is_external(true);
|
self->set_is_external(true);
|
||||||
size_t byte_length = static_cast<size_t>(obj->byte_length()->Number());
|
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 contents;
|
||||||
contents.data_ = obj->backing_store();
|
contents.data_ = self->backing_store();
|
||||||
contents.byte_length_ = byte_length;
|
contents.byte_length_ = byte_length;
|
||||||
return contents;
|
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,
|
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);
|
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||||
LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)");
|
LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)");
|
||||||
ENTER_V8(i_isolate);
|
ENTER_V8(i_isolate);
|
||||||
i::Handle<i::JSArrayBuffer> obj =
|
i::Handle<i::JSArrayBuffer> obj =
|
||||||
i_isolate->factory()->NewJSArrayBuffer();
|
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);
|
return Utils::ToLocal(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "src/api.h"
|
#include "src/api.h"
|
||||||
#include "src/heap/heap.h"
|
#include "src/heap/heap.h"
|
||||||
#include "src/objects.h"
|
#include "src/objects.h"
|
||||||
|
#include "src/v8.h"
|
||||||
|
|
||||||
using namespace v8::internal;
|
using namespace v8::internal;
|
||||||
|
|
||||||
@ -66,3 +67,15 @@ TEST(CopyContentsView) {
|
|||||||
"var a = new DataView(b, 2);");
|
"var a = new DataView(b, 2);");
|
||||||
TestArrayBufferViewContents(env, true);
|
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());
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user