[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* 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.
|
||||
*/
|
||||
|
@ -8350,6 +8350,41 @@ std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore(
|
||||
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() {
|
||||
i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
|
||||
i::Handle<i::JSArrayBuffer> buffer;
|
||||
|
@ -347,9 +347,11 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
||||
// Collect garbage and retry.
|
||||
did_retry = true;
|
||||
// TODO(wasm): try Heap::EagerlyFreeExternalMemory() first?
|
||||
if (isolate != nullptr) {
|
||||
isolate->heap()->MemoryPressureNotification(
|
||||
MemoryPressureLevel::kCritical, true);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -368,7 +370,9 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
||||
};
|
||||
if (!gc_retry(allocate_pages)) {
|
||||
// Page allocator could not reserve enough pages.
|
||||
if (isolate != nullptr) {
|
||||
RecordStatus(isolate, AllocationStatus::kOtherFailure);
|
||||
}
|
||||
TRACE_BS("BSw:try failed to allocate pages\n");
|
||||
return {};
|
||||
}
|
||||
@ -403,8 +407,10 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory(
|
||||
|
||||
DebugCheckZero(buffer_start, byte_length); // touch the bytes.
|
||||
|
||||
if (isolate != nullptr) {
|
||||
RecordStatus(isolate, did_retry ? AllocationStatus::kSuccessAfterRetry
|
||||
: AllocationStatus::kSuccess);
|
||||
}
|
||||
|
||||
const bool is_wasm_memory = wasm_memory != WasmMemoryFlag::kNotWasm;
|
||||
ResizableFlag resizable =
|
||||
|
@ -62,6 +62,10 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase {
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
// 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(
|
||||
Isolate* isolate, size_t byte_length, size_t max_byte_length,
|
||||
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 =
|
||||
v8::ArrayBuffer::NewBackingStore(isolate, 100);
|
||||
CHECK(!backing_store->IsShared());
|
||||
CHECK(!backing_store->IsResizableByUserJavaScript());
|
||||
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());
|
||||
}
|
||||
|
||||
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) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
@ -461,6 +479,7 @@ THREADED_TEST(SharedArrayBuffer_NewBackingStore) {
|
||||
std::shared_ptr<v8::BackingStore> backing_store =
|
||||
v8::SharedArrayBuffer::NewBackingStore(isolate, 100);
|
||||
CHECK(backing_store->IsShared());
|
||||
CHECK(!backing_store->IsResizableByUserJavaScript());
|
||||
Local<v8::SharedArrayBuffer> ab =
|
||||
v8::SharedArrayBuffer::New(isolate, backing_store);
|
||||
CHECK_EQ(backing_store.get(), ab->GetBackingStore().get());
|
||||
@ -819,7 +838,6 @@ TEST(ArrayBuffer_Resizable) {
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
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 });";
|
||||
v8::Local<v8::ArrayBuffer> rab = CompileRun(rab_source).As<v8::ArrayBuffer>();
|
||||
CHECK(rab->GetBackingStore()->IsResizableByUserJavaScript());
|
||||
|
Loading…
Reference in New Issue
Block a user