summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.gypi2
-rw-r--r--deps/v8/include/v8.h54
-rw-r--r--deps/v8/src/api/api.cc52
-rw-r--r--deps/v8/src/logging/counters.h2
-rw-r--r--deps/v8/src/objects/backing-store.cc51
-rw-r--r--deps/v8/src/objects/backing-store.h31
-rw-r--r--deps/v8/test/cctest/test-api-array-buffer.cc65
7 files changed, 242 insertions, 15 deletions
diff --git a/common.gypi b/common.gypi
index 5ea3e36506..ca1f853172 100644
--- a/common.gypi
+++ b/common.gypi
@@ -39,7 +39,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.11',
+ 'v8_embedder_string': '-node.12',
##### V8 defaults for Node.js #####
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index 12fc16c2be..ba801345f1 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -4850,6 +4850,14 @@ class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase {
};
/**
+ * This callback is used only if the memory block for this backing store cannot
+ * be allocated with an ArrayBuffer::Allocator. In such cases the destructor
+ * of this backing store object invokes the callback to free the memory block.
+ */
+using BackingStoreDeleterCallback = void (*)(void* data, size_t length,
+ void* deleter_data);
+
+/**
* An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
*/
class V8_EXPORT ArrayBuffer : public Object {
@@ -5000,6 +5008,29 @@ class V8_EXPORT ArrayBuffer : public Object {
std::shared_ptr<BackingStore> backing_store);
/**
+ * Returns a new standalone BackingStore that is allocated using the array
+ * buffer allocator of the isolate. The result can be later passed to
+ * ArrayBuffer::New.
+ *
+ * If the allocator returns nullptr, then the function may cause GCs in the
+ * given isolate and re-try the allocation. If GCs do not help, then the
+ * function will crash with an out-of-memory error.
+ */
+ static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
+ size_t byte_length);
+ /**
+ * Returns a new standalone BackingStore that takes over the ownership of
+ * the given buffer. The destructor of the BackingStore invokes the given
+ * deleter callback.
+ *
+ * The result can be later passed to ArrayBuffer::New. The raw pointer
+ * to the buffer must not be passed again to any V8 API function.
+ */
+ static std::unique_ptr<BackingStore> NewBackingStore(
+ void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
+ void* deleter_data);
+
+ /**
* Returns true if ArrayBuffer is externalized, that is, does not
* own its memory block.
*/
@@ -5450,6 +5481,29 @@ class V8_EXPORT SharedArrayBuffer : public Object {
Isolate* isolate, std::shared_ptr<BackingStore> backing_store);
/**
+ * Returns a new standalone BackingStore that is allocated using the array
+ * buffer allocator of the isolate. The result can be later passed to
+ * SharedArrayBuffer::New.
+ *
+ * If the allocator returns nullptr, then the function may cause GCs in the
+ * given isolate and re-try the allocation. If GCs do not help, then the
+ * function will crash with an out-of-memory error.
+ */
+ static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
+ size_t byte_length);
+ /**
+ * Returns a new standalone BackingStore that takes over the ownership of
+ * the given buffer. The destructor of the BackingStore invokes the given
+ * deleter callback.
+ *
+ * The result can be later passed to SharedArrayBuffer::New. The raw pointer
+ * to the buffer must not be passed again to any V8 functions.
+ */
+ static std::unique_ptr<BackingStore> NewBackingStore(
+ void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
+ void* deleter_data);
+
+ /**
* Create a new SharedArrayBuffer over an existing memory block. Propagate
* flags to indicate whether the underlying buffer can be grown.
*/
diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc
index 0d80f986f1..870c643491 100644
--- a/deps/v8/src/api/api.cc
+++ b/deps/v8/src/api/api.cc
@@ -7452,6 +7452,32 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(
return Utils::ToLocal(obj);
}
+std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
+ Isolate* isolate, size_t byte_length) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ LOG_API(i_isolate, ArrayBuffer, NewBackingStore);
+ ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
+ std::unique_ptr<i::BackingStoreBase> backing_store =
+ i::BackingStore::Allocate(i_isolate, byte_length,
+ i::SharedFlag::kNotShared,
+ i::InitializedFlag::kZeroInitialized);
+ if (!backing_store) {
+ i::FatalProcessOutOfMemory(i_isolate, "v8::ArrayBuffer::NewBackingStore");
+ }
+ return std::unique_ptr<v8::BackingStore>(
+ static_cast<v8::BackingStore*>(backing_store.release()));
+}
+
+std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
+ void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
+ void* deleter_data) {
+ std::unique_ptr<i::BackingStoreBase> backing_store =
+ i::BackingStore::WrapAllocation(data, byte_length, deleter, deleter_data,
+ i::SharedFlag::kNotShared);
+ return std::unique_ptr<v8::BackingStore>(
+ static_cast<v8::BackingStore*>(backing_store.release()));
+}
+
Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
i::Handle<i::JSArrayBuffer> buffer;
@@ -7753,6 +7779,32 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
return Utils::ToLocalShared(buffer);
}
+std::unique_ptr<v8::BackingStore> v8::SharedArrayBuffer::NewBackingStore(
+ Isolate* isolate, size_t byte_length) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ LOG_API(i_isolate, SharedArrayBuffer, NewBackingStore);
+ ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
+ std::unique_ptr<i::BackingStoreBase> backing_store =
+ i::BackingStore::Allocate(i_isolate, byte_length, i::SharedFlag::kShared,
+ i::InitializedFlag::kZeroInitialized);
+ if (!backing_store) {
+ i::FatalProcessOutOfMemory(i_isolate,
+ "v8::SharedArrayBuffer::NewBackingStore");
+ }
+ return std::unique_ptr<v8::BackingStore>(
+ static_cast<v8::BackingStore*>(backing_store.release()));
+}
+
+std::unique_ptr<v8::BackingStore> v8::SharedArrayBuffer::NewBackingStore(
+ void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
+ void* deleter_data) {
+ std::unique_ptr<i::BackingStoreBase> backing_store =
+ i::BackingStore::WrapAllocation(data, byte_length, deleter, deleter_data,
+ i::SharedFlag::kShared);
+ return std::unique_ptr<v8::BackingStore>(
+ static_cast<v8::BackingStore*>(backing_store.release()));
+}
+
Local<Symbol> v8::Symbol::New(Isolate* isolate, Local<String> name) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, Symbol, New);
diff --git a/deps/v8/src/logging/counters.h b/deps/v8/src/logging/counters.h
index 99a3c3cf9b..5ba1d4626e 100644
--- a/deps/v8/src/logging/counters.h
+++ b/deps/v8/src/logging/counters.h
@@ -733,6 +733,7 @@ class RuntimeCallTimer final {
V(ArrayBuffer_Cast) \
V(ArrayBuffer_Detach) \
V(ArrayBuffer_New) \
+ V(ArrayBuffer_NewBackingStore) \
V(Array_CloneElementAt) \
V(Array_New) \
V(BigInt64Array_New) \
@@ -850,6 +851,7 @@ class RuntimeCallTimer final {
V(Set_Has) \
V(Set_New) \
V(SharedArrayBuffer_New) \
+ V(SharedArrayBuffer_NewBackingStore) \
V(String_Concat) \
V(String_NewExternalOneByte) \
V(String_NewExternalTwoByte) \
diff --git a/deps/v8/src/objects/backing-store.cc b/deps/v8/src/objects/backing-store.cc
index 55957e001b..ff18a23146 100644
--- a/deps/v8/src/objects/backing-store.cc
+++ b/deps/v8/src/objects/backing-store.cc
@@ -124,6 +124,7 @@ BackingStore::~BackingStore() {
if (is_wasm_memory_) {
DCHECK(free_on_destruct_);
+ DCHECK(!custom_deleter_);
TRACE_BS("BSw:free bs=%p mem=%p (length=%zu, capacity=%zu)\n", this,
buffer_start_, byte_length(), byte_capacity_);
if (is_shared_) {
@@ -149,6 +150,14 @@ BackingStore::~BackingStore() {
Clear();
return;
}
+ if (custom_deleter_) {
+ DCHECK(free_on_destruct_);
+ TRACE_BS("BS:custome deleter bs=%p mem=%p (length=%zu, capacity=%zu)\n",
+ this, buffer_start_, byte_length(), byte_capacity_);
+ type_specific_data_.deleter(buffer_start_, byte_length_, deleter_data_);
+ Clear();
+ return;
+ }
if (free_on_destruct_) {
// JSArrayBuffer backing store. Deallocate through the embedder's allocator.
auto allocator = reinterpret_cast<v8::ArrayBuffer::Allocator*>(
@@ -210,7 +219,8 @@ std::unique_ptr<BackingStore> BackingStore::Allocate(
shared, // shared
false, // is_wasm_memory
true, // free_on_destruct
- false); // has_guard_regions
+ false, // has_guard_regions
+ false); // custom_deleter
TRACE_BS("BS:alloc bs=%p mem=%p (length=%zu)\n", result,
result->buffer_start(), byte_length);
@@ -321,7 +331,8 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateWasmMemory(
shared, // shared
true, // is_wasm_memory
true, // free_on_destruct
- guards); // has_guard_regions
+ guards, // has_guard_regions
+ false); // custom_deleter
TRACE_BS("BSw:alloc bs=%p mem=%p (length=%zu, capacity=%zu)\n", result,
result->buffer_start(), byte_length, byte_capacity);
@@ -451,9 +462,14 @@ void BackingStore::UpdateSharedWasmMemoryObjects(Isolate* isolate) {
std::unique_ptr<BackingStore> BackingStore::WrapAllocation(
Isolate* isolate, void* allocation_base, size_t allocation_length,
SharedFlag shared, bool free_on_destruct) {
- auto result =
- new BackingStore(allocation_base, allocation_length, allocation_length,
- shared, false, free_on_destruct, false);
+ auto result = new BackingStore(allocation_base, // start
+ allocation_length, // length
+ allocation_length, // capacity
+ shared, // shared
+ false, // is_wasm_memory
+ free_on_destruct, // free_on_destruct
+ false, // has_guard_regions
+ false); // custom_deleter
result->type_specific_data_.v8_api_array_buffer_allocator =
isolate->array_buffer_allocator();
TRACE_BS("BS:wrap bs=%p mem=%p (length=%zu)\n", result,
@@ -461,6 +477,25 @@ std::unique_ptr<BackingStore> BackingStore::WrapAllocation(
return std::unique_ptr<BackingStore>(result);
}
+std::unique_ptr<BackingStore> BackingStore::WrapAllocation(
+ void* allocation_base, size_t allocation_length,
+ v8::BackingStoreDeleterCallback deleter, void* deleter_data,
+ SharedFlag shared) {
+ auto result = new BackingStore(allocation_base, // start
+ allocation_length, // length
+ allocation_length, // capacity
+ shared, // shared
+ false, // is_wasm_memory
+ true, // free_on_destruct
+ false, // has_guard_regions
+ true); // custom_deleter
+ result->type_specific_data_.deleter = deleter;
+ result->deleter_data_ = deleter_data;
+ TRACE_BS("BS:wrap bs=%p mem=%p (length=%zu)\n", result,
+ result->buffer_start(), result->byte_length());
+ return std::unique_ptr<BackingStore>(result);
+}
+
std::unique_ptr<BackingStore> BackingStore::EmptyBackingStore(
SharedFlag shared) {
auto result = new BackingStore(nullptr, // start
@@ -469,7 +504,8 @@ std::unique_ptr<BackingStore> BackingStore::EmptyBackingStore(
shared, // shared
false, // is_wasm_memory
false, // free_on_destruct
- false); // has_guard_regions
+ false, // has_guard_regions
+ false); // custom_deleter
return std::unique_ptr<BackingStore>(result);
}
@@ -512,6 +548,9 @@ void GlobalBackingStoreRegistry::Register(
// then we don't have to guarantee that there is single unique
// BackingStore per buffer_start() because the destructor of
// of the BackingStore will be a no-op in that case.
+
+ // All WASM memory has to be registered.
+ CHECK(!backing_store->is_wasm_memory());
return;
}
diff --git a/deps/v8/src/objects/backing-store.h b/deps/v8/src/objects/backing-store.h
index 2c6ffb28da..c212bebf48 100644
--- a/deps/v8/src/objects/backing-store.h
+++ b/deps/v8/src/objects/backing-store.h
@@ -8,6 +8,7 @@
#include <memory>
#include "include/v8-internal.h"
+#include "include/v8.h"
#include "src/handles/handles.h"
namespace v8 {
@@ -63,6 +64,11 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
SharedFlag shared,
bool free_on_destruct);
+ static std::unique_ptr<BackingStore> WrapAllocation(
+ void* allocation_base, size_t allocation_length,
+ v8::BackingStoreDeleterCallback deleter, void* deleter_data,
+ SharedFlag shared);
+
// Create an empty backing store.
static std::unique_ptr<BackingStore> EmptyBackingStore(SharedFlag shared);
@@ -116,7 +122,7 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
BackingStore(void* buffer_start, size_t byte_length, size_t byte_capacity,
SharedFlag shared, bool is_wasm_memory, bool free_on_destruct,
- bool has_guard_regions)
+ bool has_guard_regions, bool custom_deleter)
: buffer_start_(buffer_start),
byte_length_(byte_length),
byte_capacity_(byte_capacity),
@@ -124,19 +130,15 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
is_wasm_memory_(is_wasm_memory),
free_on_destruct_(free_on_destruct),
has_guard_regions_(has_guard_regions),
- globally_registered_(false) {
+ globally_registered_(false),
+ custom_deleter_(custom_deleter) {
type_specific_data_.v8_api_array_buffer_allocator = nullptr;
+ deleter_data_ = nullptr;
}
void* buffer_start_ = nullptr;
std::atomic<size_t> byte_length_{0};
size_t byte_capacity_ = 0;
- bool is_shared_ : 1;
- bool is_wasm_memory_ : 1;
- bool free_on_destruct_ : 1;
- bool has_guard_regions_ : 1;
- bool globally_registered_ : 1;
-
union {
// If this backing store was allocated through the ArrayBufferAllocator API,
// this is a direct pointer to the API object for freeing the backing
@@ -148,8 +150,21 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
// For shared Wasm memories, this is a list of all the attached memory
// objects, which is needed to grow shared backing stores.
SharedWasmMemoryData* shared_wasm_memory_data;
+
+ // Custom deleter for the backing stores that wrap memory blocks that are
+ // allocated with a custom allocator.
+ v8::BackingStoreDeleterCallback deleter;
} type_specific_data_;
+ void* deleter_data_;
+
+ bool is_shared_ : 1;
+ bool is_wasm_memory_ : 1;
+ bool free_on_destruct_ : 1;
+ bool has_guard_regions_ : 1;
+ bool globally_registered_ : 1;
+ bool custom_deleter_ : 1;
+
// Accessors for type-specific data.
void* get_v8_api_array_buffer_allocator();
SharedWasmMemoryData* get_shared_wasm_memory_data();
diff --git a/deps/v8/test/cctest/test-api-array-buffer.cc b/deps/v8/test/cctest/test-api-array-buffer.cc
index 508604aa41..488dbde272 100644
--- a/deps/v8/test/cctest/test-api-array-buffer.cc
+++ b/deps/v8/test/cctest/test-api-array-buffer.cc
@@ -543,3 +543,68 @@ THREADED_TEST(Regress1006600) {
CHECK_NULL(ab.As<v8::Object>()->GetAlignedPointerFromInternalField(i));
}
}
+
+THREADED_TEST(ArrayBuffer_NewBackingStore) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ std::shared_ptr<v8::BackingStore> backing_store =
+ v8::ArrayBuffer::NewBackingStore(isolate, 100);
+ Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, backing_store);
+ CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
+}
+
+THREADED_TEST(SharedArrayBuffer_NewBackingStore) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ std::shared_ptr<v8::BackingStore> backing_store =
+ v8::SharedArrayBuffer::NewBackingStore(isolate, 100);
+ Local<v8::SharedArrayBuffer> ab =
+ v8::SharedArrayBuffer::New(isolate, backing_store);
+ CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
+}
+
+static void* backing_store_custom_data = nullptr;
+static size_t backing_store_custom_length = 0;
+static bool backing_store_custom_called = false;
+const intptr_t backing_store_custom_deleter_data = 1234567;
+
+static void BackingStoreCustomDeleter(void* data, size_t length,
+ void* deleter_data) {
+ CHECK(!backing_store_custom_called);
+ CHECK_EQ(backing_store_custom_data, data);
+ CHECK_EQ(backing_store_custom_length, length);
+ CHECK_EQ(backing_store_custom_deleter_data,
+ reinterpret_cast<intptr_t>(deleter_data));
+ free(data);
+ backing_store_custom_called = true;
+}
+
+TEST(ArrayBuffer_NewBackingStore_CustomDeleter) {
+ {
+ // Create and destroy a backing store.
+ backing_store_custom_called = false;
+ backing_store_custom_data = malloc(100);
+ backing_store_custom_length = 100;
+ v8::ArrayBuffer::NewBackingStore(
+ backing_store_custom_data, backing_store_custom_length,
+ BackingStoreCustomDeleter,
+ reinterpret_cast<void*>(backing_store_custom_deleter_data));
+ }
+ CHECK(backing_store_custom_called);
+}
+
+TEST(SharedArrayBuffer_NewBackingStore_CustomDeleter) {
+ {
+ // Create and destroy a backing store.
+ backing_store_custom_called = false;
+ backing_store_custom_data = malloc(100);
+ backing_store_custom_length = 100;
+ v8::SharedArrayBuffer::NewBackingStore(
+ backing_store_custom_data, backing_store_custom_length,
+ BackingStoreCustomDeleter,
+ reinterpret_cast<void*>(backing_store_custom_deleter_data));
+ }
+ CHECK(backing_store_custom_called);
+}