Allow for accessing an ArrayBuffer contents without externalizing it
authorjochen <jochen@chromium.org>
Mon, 20 Apr 2015 15:01:55 +0000 (08:01 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 20 Apr 2015 15:01:43 +0000 (15:01 +0000)
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
src/api.cc
test/cctest/test-typedarrays.cc

index ebb0639..3bc0c71 100644 (file)
@@ -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;
index 38b3679..3a89095 100644 (file)
@@ -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);
 }
 
index 966edb7..d031048 100644 (file)
@@ -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());
+}