[rab/gsab,api] Add resizable BackingStore creation
This CL adds v8::ArrayBuffer::NewResizableBackingStore. This API is needed to support Mojo cross-process serialization of resizable buffers. See https://chromium-review.googlesource.com/c/chromium/src/+/4086949 Bug: chromium:1396361, v8:11111 Change-Id: I1d3ad367f28015184fd80fd2f05a37a3659d3a66 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4093555 Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/main@{#84826}
This commit is contained in:
parent
c3568fdb87
commit
4757205b3c
@ -256,6 +256,21 @@ class V8_EXPORT ArrayBuffer : public Object {
|
|||||||
void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
|
void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter,
|
||||||
void* deleter_data);
|
void* deleter_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new resizable standalone BackingStore that is allocated using the
|
||||||
|
* array buffer allocator of the isolate. The result can be later passed to
|
||||||
|
* ArrayBuffer::New.
|
||||||
|
*
|
||||||
|
* |byte_length| must be <= |max_byte_length|.
|
||||||
|
*
|
||||||
|
* This function is usable without an isolate. Unlike |NewBackingStore| calls
|
||||||
|
* with an isolate, GCs cannot be triggered, and there are no
|
||||||
|
* retries. Allocation failure will cause the function to crash with an
|
||||||
|
* out-of-memory error.
|
||||||
|
*/
|
||||||
|
static std::unique_ptr<BackingStore> NewResizableBackingStore(
|
||||||
|
size_t byte_length, size_t max_byte_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this ArrayBuffer may be detached.
|
* Returns true if this ArrayBuffer may be detached.
|
||||||
*/
|
*/
|
||||||
|
@ -8350,6 +8350,41 @@ std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
|
|||||||
static_cast<v8::BackingStore*>(backing_store.release()));
|
static_cast<v8::BackingStore*>(backing_store.release()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
std::unique_ptr<BackingStore> v8::ArrayBuffer::NewResizableBackingStore(
|
||||||
|
size_t byte_length, size_t max_byte_length) {
|
||||||
|
Utils::ApiCheck(i::v8_flags.harmony_rab_gsab,
|
||||||
|
"v8::ArrayBuffer::NewResizableBackingStore",
|
||||||
|
"Constructing resizable ArrayBuffers is not supported");
|
||||||
|
Utils::ApiCheck(byte_length <= max_byte_length,
|
||||||
|
"v8::ArrayBuffer::NewResizableBackingStore",
|
||||||
|
"Cannot construct resizable ArrayBuffer, byte_length must be "
|
||||||
|
"<= max_byte_length");
|
||||||
|
Utils::ApiCheck(
|
||||||
|
byte_length <= i::JSArrayBuffer::kMaxByteLength,
|
||||||
|
"v8::ArrayBuffer::NewResizableBackingStore",
|
||||||
|
"Cannot construct resizable ArrayBuffer, requested length is too big");
|
||||||
|
|
||||||
|
size_t page_size, initial_pages, max_pages;
|
||||||
|
if (i::JSArrayBuffer::GetResizableBackingStorePageConfiguration(
|
||||||
|
nullptr, byte_length, max_byte_length, i::kDontThrow, &page_size,
|
||||||
|
&initial_pages, &max_pages)
|
||||||
|
.IsNothing()) {
|
||||||
|
i::V8::FatalProcessOutOfMemory(nullptr,
|
||||||
|
"v8::ArrayBuffer::NewResizableBackingStore");
|
||||||
|
}
|
||||||
|
std::unique_ptr<i::BackingStoreBase> backing_store =
|
||||||
|
i::BackingStore::TryAllocateAndPartiallyCommitMemory(
|
||||||
|
nullptr, byte_length, max_byte_length, page_size, initial_pages,
|
||||||
|
max_pages, i::WasmMemoryFlag::kNotWasm, i::SharedFlag::kNotShared);
|
||||||
|
if (!backing_store) {
|
||||||
|
i::V8::FatalProcessOutOfMemory(nullptr,
|
||||||
|
"v8::ArrayBuffer::NewResizableBackingStore");
|
||||||
|
}
|
||||||
|
return std::unique_ptr<v8::BackingStore>(
|
||||||
|
static_cast<v8::BackingStore*>(backing_store.release()));
|
||||||
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
|
Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
|
||||||
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
|
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
|
||||||
i::Handle<i::JSArrayBuffer> buffer;
|
i::Handle<i::JSArrayBuffer> buffer;
|
||||||
|
@ -347,8 +347,10 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
|||||||
// Collect garbage and retry.
|
// Collect garbage and retry.
|
||||||
did_retry = true;
|
did_retry = true;
|
||||||
// TODO(wasm): try Heap::EagerlyFreeExternalMemory() first?
|
// TODO(wasm): try Heap::EagerlyFreeExternalMemory() first?
|
||||||
isolate->heap()->MemoryPressureNotification(
|
if (isolate != nullptr) {
|
||||||
MemoryPressureLevel::kCritical, true);
|
isolate->heap()->MemoryPressureNotification(
|
||||||
|
MemoryPressureLevel::kCritical, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -368,7 +370,9 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
|||||||
};
|
};
|
||||||
if (!gc_retry(allocate_pages)) {
|
if (!gc_retry(allocate_pages)) {
|
||||||
// Page allocator could not reserve enough pages.
|
// Page allocator could not reserve enough pages.
|
||||||
RecordStatus(isolate, AllocationStatus::kOtherFailure);
|
if (isolate != nullptr) {
|
||||||
|
RecordStatus(isolate, AllocationStatus::kOtherFailure);
|
||||||
|
}
|
||||||
TRACE_BS("BSw:try failed to allocate pages\n");
|
TRACE_BS("BSw:try failed to allocate pages\n");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -403,8 +407,10 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
|||||||
|
|
||||||
DebugCheckZero(buffer_start, byte_length); // touch the bytes.
|
DebugCheckZero(buffer_start, byte_length); // touch the bytes.
|
||||||
|
|
||||||
RecordStatus(isolate, did_retry ? AllocationStatus::kSuccessAfterRetry
|
if (isolate != nullptr) {
|
||||||
: AllocationStatus::kSuccess);
|
RecordStatus(isolate, did_retry ? AllocationStatus::kSuccessAfterRetry
|
||||||
|
: AllocationStatus::kSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
const bool is_wasm_memory = wasm_memory != WasmMemoryFlag::kNotWasm;
|
const bool is_wasm_memory = wasm_memory != WasmMemoryFlag::kNotWasm;
|
||||||
ResizableFlag resizable =
|
ResizableFlag resizable =
|
||||||
|
@ -62,6 +62,10 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
|
|||||||
#endif // V8_ENABLE_WEBASSEMBLY
|
#endif // V8_ENABLE_WEBASSEMBLY
|
||||||
|
|
||||||
// Tries to allocate `maximum_pages` of memory and commit `initial_pages`.
|
// Tries to allocate `maximum_pages` of memory and commit `initial_pages`.
|
||||||
|
//
|
||||||
|
// If {isolate} is not null, initial failure to allocate the backing store may
|
||||||
|
// trigger GC, after which the allocation is retried. If {isolate} is null, no
|
||||||
|
// GC will be triggered.
|
||||||
static std::unique_ptr<BackingStore> TryAllocateAndPartiallyCommitMemory(
|
static std::unique_ptr<BackingStore> TryAllocateAndPartiallyCommitMemory(
|
||||||
Isolate* isolate, size_t byte_length, size_t max_byte_length,
|
Isolate* isolate, size_t byte_length, size_t max_byte_length,
|
||||||
size_t page_size, size_t initial_pages, size_t maximum_pages,
|
size_t page_size, size_t initial_pages, size_t maximum_pages,
|
||||||
|
@ -449,11 +449,29 @@ THREADED_TEST(ArrayBuffer_NewBackingStore) {
|
|||||||
std::shared_ptr<v8::BackingStore> backing_store =
|
std::shared_ptr<v8::BackingStore> backing_store =
|
||||||
v8::ArrayBuffer::NewBackingStore(isolate, 100);
|
v8::ArrayBuffer::NewBackingStore(isolate, 100);
|
||||||
CHECK(!backing_store->IsShared());
|
CHECK(!backing_store->IsShared());
|
||||||
|
CHECK(!backing_store->IsResizableByUserJavaScript());
|
||||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, backing_store);
|
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, backing_store);
|
||||||
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
||||||
CHECK_EQ(backing_store->Data(), ab->Data());
|
CHECK_EQ(backing_store->Data(), ab->Data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THREADED_TEST(ArrayBuffer_NewResizableBackingStore) {
|
||||||
|
FLAG_SCOPE(harmony_rab_gsab);
|
||||||
|
|
||||||
|
LocalContext env;
|
||||||
|
v8::Isolate* isolate = env->GetIsolate();
|
||||||
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
std::shared_ptr<v8::BackingStore> backing_store =
|
||||||
|
v8::ArrayBuffer::NewResizableBackingStore(32, 1024);
|
||||||
|
CHECK(!backing_store->IsShared());
|
||||||
|
CHECK(backing_store->IsResizableByUserJavaScript());
|
||||||
|
CHECK_EQ(1024, backing_store->MaxByteLength());
|
||||||
|
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, backing_store);
|
||||||
|
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
||||||
|
CHECK_EQ(backing_store->Data(), ab->Data());
|
||||||
|
CHECK_EQ(backing_store->MaxByteLength(), ab->MaxByteLength());
|
||||||
|
}
|
||||||
|
|
||||||
THREADED_TEST(SharedArrayBuffer_NewBackingStore) {
|
THREADED_TEST(SharedArrayBuffer_NewBackingStore) {
|
||||||
LocalContext env;
|
LocalContext env;
|
||||||
v8::Isolate* isolate = env->GetIsolate();
|
v8::Isolate* isolate = env->GetIsolate();
|
||||||
@ -461,6 +479,7 @@ THREADED_TEST(SharedArrayBuffer_NewBackingStore) {
|
|||||||
std::shared_ptr<v8::BackingStore> backing_store =
|
std::shared_ptr<v8::BackingStore> backing_store =
|
||||||
v8::SharedArrayBuffer::NewBackingStore(isolate, 100);
|
v8::SharedArrayBuffer::NewBackingStore(isolate, 100);
|
||||||
CHECK(backing_store->IsShared());
|
CHECK(backing_store->IsShared());
|
||||||
|
CHECK(!backing_store->IsResizableByUserJavaScript());
|
||||||
Local<v8::SharedArrayBuffer> ab =
|
Local<v8::SharedArrayBuffer> ab =
|
||||||
v8::SharedArrayBuffer::New(isolate, backing_store);
|
v8::SharedArrayBuffer::New(isolate, backing_store);
|
||||||
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
||||||
@ -819,7 +838,6 @@ TEST(ArrayBuffer_Resizable) {
|
|||||||
v8::Isolate* isolate = env->GetIsolate();
|
v8::Isolate* isolate = env->GetIsolate();
|
||||||
v8::HandleScope handle_scope(isolate);
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
// TODO(v8:11111): Expose ability to create resizable buffers to API?
|
|
||||||
const char rab_source[] = "new ArrayBuffer(32, { maxByteLength: 1024 });";
|
const char rab_source[] = "new ArrayBuffer(32, { maxByteLength: 1024 });";
|
||||||
v8::Local<v8::ArrayBuffer> rab = CompileRun(rab_source).As<v8::ArrayBuffer>();
|
v8::Local<v8::ArrayBuffer> rab = CompileRun(rab_source).As<v8::ArrayBuffer>();
|
||||||
CHECK(rab->GetBackingStore()->IsResizableByUserJavaScript());
|
CHECK(rab->GetBackingStore()->IsResizableByUserJavaScript());
|
||||||
|
Loading…
Reference in New Issue
Block a user