From 90742c6040eddcc591dac0a0dc4565cca698974e Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Dec 2022 17:29:09 -0800 Subject: [PATCH] [api] Add resizable getters to ArrayBuffer APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds v8::[Shared]ArrayBuffer::MaxByteLength and v8::BackingStore::IsResizableByUserJavaScript. This is needed for embedders who need to check if a buffer is resizable by user JS, like blink, to check for the [AllowResizable] WebIDL extended attribute. Bug: v8:11111 Change-Id: Ie7e03979ef3884123df8a3eeb5c3516c4a6967c2 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4082276 Reviewed-by: Marja Hölttä Reviewed-by: Camillo Bruni Commit-Queue: Shu-yu Guo Cr-Commit-Position: refs/heads/main@{#84715} --- include/v8-array-buffer.h | 17 +++++++++++ src/api/api.cc | 14 +++++++++ test/cctest/test-api-array-buffer.cc | 44 ++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/include/v8-array-buffer.h b/include/v8-array-buffer.h index 841bd02a79..c942ef592f 100644 --- a/include/v8-array-buffer.h +++ b/include/v8-array-buffer.h @@ -59,6 +59,13 @@ class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase { */ bool IsShared() const; + /** + * Indicates whether the backing store was created for a resizable ArrayBuffer + * or a growable SharedArrayBuffer, and thus may be resized by user JavaScript + * code. + */ + bool IsResizableByUserJavaScript() const; + /** * Prevent implicit instantiation of operator delete with size_t argument. * The size_t argument would be incorrect because ptr points to the @@ -189,6 +196,11 @@ class V8_EXPORT ArrayBuffer : public Object { */ size_t ByteLength() const; + /** + * Maximum length in bytes. + */ + size_t MaxByteLength() const; + /** * Create a new ArrayBuffer. Allocate |byte_length| bytes. * Allocated memory will be owned by a created ArrayBuffer and @@ -392,6 +404,11 @@ class V8_EXPORT SharedArrayBuffer : public Object { */ size_t ByteLength() const; + /** + * Maximum length in bytes. + */ + size_t MaxByteLength() const; + /** * Create a new SharedArrayBuffer. Allocate |byte_length| bytes. * Allocated memory will be owned by a created SharedArrayBuffer and diff --git a/src/api/api.cc b/src/api/api.cc index fe8b64ee4f..09217e9730 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -4195,6 +4195,10 @@ bool v8::BackingStore::IsShared() const { return reinterpret_cast(this)->is_shared(); } +bool v8::BackingStore::IsResizableByUserJavaScript() const { + return reinterpret_cast(this)->is_resizable_by_js(); +} + // static std::unique_ptr v8::BackingStore::Reallocate( v8::Isolate* v8_isolate, std::unique_ptr backing_store, @@ -8263,6 +8267,11 @@ size_t v8::ArrayBuffer::ByteLength() const { return obj->GetByteLength(); } +size_t v8::ArrayBuffer::MaxByteLength() const { + i::Handle obj = Utils::OpenHandle(this); + return obj->max_byte_length(); +} + Local v8::ArrayBuffer::New(Isolate* v8_isolate, size_t byte_length) { i::Isolate* i_isolate = reinterpret_cast(v8_isolate); @@ -8478,6 +8487,11 @@ size_t v8::SharedArrayBuffer::ByteLength() const { return obj->GetByteLength(); } +size_t v8::SharedArrayBuffer::MaxByteLength() const { + i::Handle obj = Utils::OpenHandle(this); + return obj->max_byte_length(); +} + Local v8::SharedArrayBuffer::New(Isolate* v8_isolate, size_t byte_length) { CHECK(i::v8_flags.harmony_sharedarraybuffer); diff --git a/test/cctest/test-api-array-buffer.cc b/test/cctest/test-api-array-buffer.cc index ad30146664..50feb1d270 100644 --- a/test/cctest/test-api-array-buffer.cc +++ b/test/cctest/test-api-array-buffer.cc @@ -6,6 +6,7 @@ #include "src/base/strings.h" #include "src/objects/js-array-buffer-inl.h" #include "test/cctest/test-api.h" +#include "test/common/flag-utils.h" using ::v8::Array; using ::v8::Context; @@ -810,3 +811,46 @@ TEST(BackingStore_ReallocateShared) { v8::BackingStore::Reallocate(isolate, std::move(backing_store), 10); CHECK(new_backing_store->IsShared()); } + +TEST(ArrayBuffer_Resizable) { + FLAG_SCOPE(harmony_rab_gsab); + + LocalContext env; + 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 rab = CompileRun(rab_source).As(); + CHECK(rab->GetBackingStore()->IsResizableByUserJavaScript()); + CHECK_EQ(32, rab->ByteLength()); + CHECK_EQ(1024, rab->MaxByteLength()); + + const char gsab_source[] = + "new SharedArrayBuffer(32, { maxByteLength: 1024 });"; + v8::Local gsab = + CompileRun(gsab_source).As(); + CHECK(gsab->GetBackingStore()->IsResizableByUserJavaScript()); + CHECK_EQ(32, gsab->ByteLength()); + CHECK_EQ(1024, gsab->MaxByteLength()); +} + +TEST(ArrayBuffer_FixedLength) { + FLAG_SCOPE(harmony_rab_gsab); + + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + // Fixed-length ArrayBuffers' byte length are equal to their max byte length. + v8::Local ab = + CompileRun("new ArrayBuffer(32);").As(); + CHECK(!ab->GetBackingStore()->IsResizableByUserJavaScript()); + CHECK_EQ(32, ab->ByteLength()); + CHECK_EQ(32, ab->MaxByteLength()); + v8::Local sab = + CompileRun("new SharedArrayBuffer(32);").As(); + CHECK(!sab->GetBackingStore()->IsResizableByUserJavaScript()); + CHECK_EQ(32, sab->ByteLength()); + CHECK_EQ(32, sab->MaxByteLength()); +}