Skip to content

Commit bba5f1f

Browse files
ulanCommit Bot
authored andcommitted
[api] Add API functions for constructing standalone BackingStores
These are useful for the cases when an embedder works with backing stores without creating JS ArrayBuffer objects. Bug: v8:9380 Change-Id: I452bd911e7b20fb38568f18f9d15ea1a7ffb5a57 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1825339 Commit-Queue: Ulan Degenbaev <[email protected]> Reviewed-by: Andreas Haas <[email protected]> Cr-Commit-Position: refs/heads/master@{#64460}
1 parent 52a54bd commit bba5f1f

6 files changed

Lines changed: 241 additions & 14 deletions

File tree

include/v8.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4872,6 +4872,14 @@ class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase {
48724872
BackingStore();
48734873
};
48744874

4875+
/**
4876+
* This callback is used only if the memory block for this backing store cannot
4877+
* be allocated with an ArrayBuffer::Allocator. In such cases the destructor
4878+
* of this backing store object invokes the callback to free the memory block.
4879+
*/
4880+
using BackingStoreDeleterCallback = void (*)(void* data, size_t length,
4881+
void* deleter_data);
4882+
48754883
/**
48764884
* An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
48774885
*/
@@ -5022,6 +5030,29 @@ class V8_EXPORT ArrayBuffer : public Object {
50225030
static Local<ArrayBuffer> New(Isolate* isolate,
50235031
std::shared_ptr<BackingStore> backing_store);
50245032

5033+
/**
5034+
* Returns a new standalone BackingStore that is allocated using the array
5035+
* buffer allocator of the isolate. The result can be later passed to
5036+
* ArrayBuffer::New.
5037+
*
5038+
* If the allocator returns nullptr, then the function may cause GCs in the
5039+
* given isolate and re-try the allocation. If GCs do not help, then the
5040+
* function will crash with an out-of-memory error.
5041+
*/
5042+
static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
5043+
size_t byte_length);
5044+
/**
5045+
* Returns a new standalone BackingStore that takes over the ownership of
5046+
* the given buffer. The destructor of the BackingStore invokes the given
5047+
* deleter callback.
5048+
*
5049+
* The result can be later passed to ArrayBuffer::New. The raw pointer
5050+
* to the buffer must not be passed again to any V8 API function.
5051+
*/
5052+
static std::unique_ptr<BackingStore> NewBackingStore(
5053+
void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
5054+
void* deleter_data);
5055+
50255056
/**
50265057
* Returns true if ArrayBuffer is externalized, that is, does not
50275058
* own its memory block.
@@ -5472,6 +5503,29 @@ class V8_EXPORT SharedArrayBuffer : public Object {
54725503
static Local<SharedArrayBuffer> New(
54735504
Isolate* isolate, std::shared_ptr<BackingStore> backing_store);
54745505

5506+
/**
5507+
* Returns a new standalone BackingStore that is allocated using the array
5508+
* buffer allocator of the isolate. The result can be later passed to
5509+
* SharedArrayBuffer::New.
5510+
*
5511+
* If the allocator returns nullptr, then the function may cause GCs in the
5512+
* given isolate and re-try the allocation. If GCs do not help, then the
5513+
* function will crash with an out-of-memory error.
5514+
*/
5515+
static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate,
5516+
size_t byte_length);
5517+
/**
5518+
* Returns a new standalone BackingStore that takes over the ownership of
5519+
* the given buffer. The destructor of the BackingStore invokes the given
5520+
* deleter callback.
5521+
*
5522+
* The result can be later passed to SharedArrayBuffer::New. The raw pointer
5523+
* to the buffer must not be passed again to any V8 functions.
5524+
*/
5525+
static std::unique_ptr<BackingStore> NewBackingStore(
5526+
void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
5527+
void* deleter_data);
5528+
54755529
/**
54765530
* Create a new SharedArrayBuffer over an existing memory block. Propagate
54775531
* flags to indicate whether the underlying buffer can be grown.

src/api/api.cc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7458,6 +7458,32 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(
74587458
return Utils::ToLocal(obj);
74597459
}
74607460

7461+
std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
7462+
Isolate* isolate, size_t byte_length) {
7463+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
7464+
LOG_API(i_isolate, ArrayBuffer, NewBackingStore);
7465+
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
7466+
std::unique_ptr<i::BackingStoreBase> backing_store =
7467+
i::BackingStore::Allocate(i_isolate, byte_length,
7468+
i::SharedFlag::kNotShared,
7469+
i::InitializedFlag::kZeroInitialized);
7470+
if (!backing_store) {
7471+
i::FatalProcessOutOfMemory(i_isolate, "v8::ArrayBuffer::NewBackingStore");
7472+
}
7473+
return std::unique_ptr<v8::BackingStore>(
7474+
static_cast<v8::BackingStore*>(backing_store.release()));
7475+
}
7476+
7477+
std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
7478+
void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
7479+
void* deleter_data) {
7480+
std::unique_ptr<i::BackingStoreBase> backing_store =
7481+
i::BackingStore::WrapAllocation(data, byte_length, deleter, deleter_data,
7482+
i::SharedFlag::kNotShared);
7483+
return std::unique_ptr<v8::BackingStore>(
7484+
static_cast<v8::BackingStore*>(backing_store.release()));
7485+
}
7486+
74617487
Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
74627488
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
74637489
i::Handle<i::JSArrayBuffer> buffer;
@@ -7759,6 +7785,32 @@ Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
77597785
return Utils::ToLocalShared(buffer);
77607786
}
77617787

7788+
std::unique_ptr<v8::BackingStore> v8::SharedArrayBuffer::NewBackingStore(
7789+
Isolate* isolate, size_t byte_length) {
7790+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
7791+
LOG_API(i_isolate, SharedArrayBuffer, NewBackingStore);
7792+
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
7793+
std::unique_ptr<i::BackingStoreBase> backing_store =
7794+
i::BackingStore::Allocate(i_isolate, byte_length, i::SharedFlag::kShared,
7795+
i::InitializedFlag::kZeroInitialized);
7796+
if (!backing_store) {
7797+
i::FatalProcessOutOfMemory(i_isolate,
7798+
"v8::SharedArrayBuffer::NewBackingStore");
7799+
}
7800+
return std::unique_ptr<v8::BackingStore>(
7801+
static_cast<v8::BackingStore*>(backing_store.release()));
7802+
}
7803+
7804+
std::unique_ptr<v8::BackingStore> v8::SharedArrayBuffer::NewBackingStore(
7805+
void* data, size_t byte_length, BackingStoreDeleterCallback deleter,
7806+
void* deleter_data) {
7807+
std::unique_ptr<i::BackingStoreBase> backing_store =
7808+
i::BackingStore::WrapAllocation(data, byte_length, deleter, deleter_data,
7809+
i::SharedFlag::kShared);
7810+
return std::unique_ptr<v8::BackingStore>(
7811+
static_cast<v8::BackingStore*>(backing_store.release()));
7812+
}
7813+
77627814
Local<Symbol> v8::Symbol::New(Isolate* isolate, Local<String> name) {
77637815
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
77647816
LOG_API(i_isolate, Symbol, New);

src/logging/counters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ class RuntimeCallTimer final {
733733
V(ArrayBuffer_Cast) \
734734
V(ArrayBuffer_Detach) \
735735
V(ArrayBuffer_New) \
736+
V(ArrayBuffer_NewBackingStore) \
736737
V(Array_CloneElementAt) \
737738
V(Array_New) \
738739
V(BigInt64Array_New) \
@@ -851,6 +852,7 @@ class RuntimeCallTimer final {
851852
V(Set_Has) \
852853
V(Set_New) \
853854
V(SharedArrayBuffer_New) \
855+
V(SharedArrayBuffer_NewBackingStore) \
854856
V(String_Concat) \
855857
V(String_NewExternalOneByte) \
856858
V(String_NewExternalTwoByte) \

src/objects/backing-store.cc

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ BackingStore::~BackingStore() {
124124

125125
if (is_wasm_memory_) {
126126
DCHECK(free_on_destruct_);
127+
DCHECK(!custom_deleter_);
127128
TRACE_BS("BSw:free bs=%p mem=%p (length=%zu, capacity=%zu)\n", this,
128129
buffer_start_, byte_length(), byte_capacity_);
129130
if (is_shared_) {
@@ -149,6 +150,14 @@ BackingStore::~BackingStore() {
149150
Clear();
150151
return;
151152
}
153+
if (custom_deleter_) {
154+
DCHECK(free_on_destruct_);
155+
TRACE_BS("BS:custome deleter bs=%p mem=%p (length=%zu, capacity=%zu)\n",
156+
this, buffer_start_, byte_length(), byte_capacity_);
157+
type_specific_data_.deleter(buffer_start_, byte_length_, deleter_data_);
158+
Clear();
159+
return;
160+
}
152161
if (free_on_destruct_) {
153162
// JSArrayBuffer backing store. Deallocate through the embedder's allocator.
154163
auto allocator = reinterpret_cast<v8::ArrayBuffer::Allocator*>(
@@ -210,7 +219,8 @@ std::unique_ptr<BackingStore> BackingStore::Allocate(
210219
shared, // shared
211220
false, // is_wasm_memory
212221
true, // free_on_destruct
213-
false); // has_guard_regions
222+
false, // has_guard_regions
223+
false); // custom_deleter
214224

215225
TRACE_BS("BS:alloc bs=%p mem=%p (length=%zu)\n", result,
216226
result->buffer_start(), byte_length);
@@ -321,7 +331,8 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateWasmMemory(
321331
shared, // shared
322332
true, // is_wasm_memory
323333
true, // free_on_destruct
324-
guards); // has_guard_regions
334+
guards, // has_guard_regions
335+
false); // custom_deleter
325336

326337
TRACE_BS("BSw:alloc bs=%p mem=%p (length=%zu, capacity=%zu)\n", result,
327338
result->buffer_start(), byte_length, byte_capacity);
@@ -451,16 +462,40 @@ void BackingStore::UpdateSharedWasmMemoryObjects(Isolate* isolate) {
451462
std::unique_ptr<BackingStore> BackingStore::WrapAllocation(
452463
Isolate* isolate, void* allocation_base, size_t allocation_length,
453464
SharedFlag shared, bool free_on_destruct) {
454-
auto result =
455-
new BackingStore(allocation_base, allocation_length, allocation_length,
456-
shared, false, free_on_destruct, false);
465+
auto result = new BackingStore(allocation_base, // start
466+
allocation_length, // length
467+
allocation_length, // capacity
468+
shared, // shared
469+
false, // is_wasm_memory
470+
free_on_destruct, // free_on_destruct
471+
false, // has_guard_regions
472+
false); // custom_deleter
457473
result->type_specific_data_.v8_api_array_buffer_allocator =
458474
isolate->array_buffer_allocator();
459475
TRACE_BS("BS:wrap bs=%p mem=%p (length=%zu)\n", result,
460476
result->buffer_start(), result->byte_length());
461477
return std::unique_ptr<BackingStore>(result);
462478
}
463479

480+
std::unique_ptr<BackingStore> BackingStore::WrapAllocation(
481+
void* allocation_base, size_t allocation_length,
482+
v8::BackingStoreDeleterCallback deleter, void* deleter_data,
483+
SharedFlag shared) {
484+
auto result = new BackingStore(allocation_base, // start
485+
allocation_length, // length
486+
allocation_length, // capacity
487+
shared, // shared
488+
false, // is_wasm_memory
489+
true, // free_on_destruct
490+
false, // has_guard_regions
491+
true); // custom_deleter
492+
result->type_specific_data_.deleter = deleter;
493+
result->deleter_data_ = deleter_data;
494+
TRACE_BS("BS:wrap bs=%p mem=%p (length=%zu)\n", result,
495+
result->buffer_start(), result->byte_length());
496+
return std::unique_ptr<BackingStore>(result);
497+
}
498+
464499
std::unique_ptr<BackingStore> BackingStore::EmptyBackingStore(
465500
SharedFlag shared) {
466501
auto result = new BackingStore(nullptr, // start
@@ -469,7 +504,8 @@ std::unique_ptr<BackingStore> BackingStore::EmptyBackingStore(
469504
shared, // shared
470505
false, // is_wasm_memory
471506
false, // free_on_destruct
472-
false); // has_guard_regions
507+
false, // has_guard_regions
508+
false); // custom_deleter
473509

474510
return std::unique_ptr<BackingStore>(result);
475511
}
@@ -512,6 +548,9 @@ void GlobalBackingStoreRegistry::Register(
512548
// then we don't have to guarantee that there is single unique
513549
// BackingStore per buffer_start() because the destructor of
514550
// of the BackingStore will be a no-op in that case.
551+
552+
// All WASM memory has to be registered.
553+
CHECK(!backing_store->is_wasm_memory());
515554
return;
516555
}
517556

src/objects/backing-store.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <memory>
99

1010
#include "include/v8-internal.h"
11+
#include "include/v8.h"
1112
#include "src/handles/handles.h"
1213

1314
namespace v8 {
@@ -63,6 +64,11 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
6364
SharedFlag shared,
6465
bool free_on_destruct);
6566

67+
static std::unique_ptr<BackingStore> WrapAllocation(
68+
void* allocation_base, size_t allocation_length,
69+
v8::BackingStoreDeleterCallback deleter, void* deleter_data,
70+
SharedFlag shared);
71+
6672
// Create an empty backing store.
6773
static std::unique_ptr<BackingStore> EmptyBackingStore(SharedFlag shared);
6874

@@ -116,27 +122,23 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
116122

117123
BackingStore(void* buffer_start, size_t byte_length, size_t byte_capacity,
118124
SharedFlag shared, bool is_wasm_memory, bool free_on_destruct,
119-
bool has_guard_regions)
125+
bool has_guard_regions, bool custom_deleter)
120126
: buffer_start_(buffer_start),
121127
byte_length_(byte_length),
122128
byte_capacity_(byte_capacity),
123129
is_shared_(shared == SharedFlag::kShared),
124130
is_wasm_memory_(is_wasm_memory),
125131
free_on_destruct_(free_on_destruct),
126132
has_guard_regions_(has_guard_regions),
127-
globally_registered_(false) {
133+
globally_registered_(false),
134+
custom_deleter_(custom_deleter) {
128135
type_specific_data_.v8_api_array_buffer_allocator = nullptr;
136+
deleter_data_ = nullptr;
129137
}
130138

131139
void* buffer_start_ = nullptr;
132140
std::atomic<size_t> byte_length_{0};
133141
size_t byte_capacity_ = 0;
134-
bool is_shared_ : 1;
135-
bool is_wasm_memory_ : 1;
136-
bool free_on_destruct_ : 1;
137-
bool has_guard_regions_ : 1;
138-
bool globally_registered_ : 1;
139-
140142
union {
141143
// If this backing store was allocated through the ArrayBufferAllocator API,
142144
// this is a direct pointer to the API object for freeing the backing
@@ -148,8 +150,21 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
148150
// For shared Wasm memories, this is a list of all the attached memory
149151
// objects, which is needed to grow shared backing stores.
150152
SharedWasmMemoryData* shared_wasm_memory_data;
153+
154+
// Custom deleter for the backing stores that wrap memory blocks that are
155+
// allocated with a custom allocator.
156+
v8::BackingStoreDeleterCallback deleter;
151157
} type_specific_data_;
152158

159+
void* deleter_data_;
160+
161+
bool is_shared_ : 1;
162+
bool is_wasm_memory_ : 1;
163+
bool free_on_destruct_ : 1;
164+
bool has_guard_regions_ : 1;
165+
bool globally_registered_ : 1;
166+
bool custom_deleter_ : 1;
167+
153168
// Accessors for type-specific data.
154169
void* get_v8_api_array_buffer_allocator();
155170
SharedWasmMemoryData* get_shared_wasm_memory_data();

0 commit comments

Comments
 (0)