From 3160edf011b11347dd741c1c09a7fcb57bb479c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 6 May 2021 12:43:37 +0200 Subject: [PATCH] [rab/gsab] ResizableArrayBuffer / GrowableSharedArrayBuffer part 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detailed list of changes: https://docs.google.com/document/d/15i4-SZDzFDW7FfclIYuZEhFn-q-KpobCBy23x9zZZLc/edit?usp=sharing Bug: v8:11111 Change-Id: I931003bd4552cf91d57de95af04a427a9e6d6ac9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2814259 Reviewed-by: Igor Sheludko Reviewed-by: Michael Lippautz Reviewed-by: Jakob Kummerow Reviewed-by: Shu-yu Guo Reviewed-by: Leszek Swirski Commit-Queue: Marja Hölttä Cr-Commit-Position: refs/heads/master@{#74459} --- src/builtins/arraybuffer.tq | 105 ++- src/builtins/base.tq | 2 +- src/builtins/builtins-array.cc | 18 +- src/builtins/builtins-arraybuffer.cc | 231 ++++++- src/builtins/builtins-definitions.h | 5 + src/builtins/builtins-handler-gen.cc | 55 +- src/builtins/builtins-typed-array-gen.cc | 67 +- src/builtins/typed-array-createtypedarray.tq | 72 ++- src/codegen/code-stub-assembler.cc | 150 +++++ src/codegen/code-stub-assembler.h | 12 + src/codegen/external-reference.cc | 3 + src/codegen/external-reference.h | 2 + src/common/message-template.h | 2 + src/diagnostics/objects-debug.cc | 3 +- src/diagnostics/objects-printer.cc | 10 +- src/flags/flag-definitions.h | 4 +- src/heap/factory.cc | 30 +- src/ic/accessor-assembler.cc | 146 +++-- src/ic/ic.cc | 14 +- src/ic/keyed-store-generic.cc | 6 +- src/init/bootstrapper.cc | 84 ++- src/init/heap-symbols.h | 437 ++++++------- src/objects/allocation-site.h | 6 +- src/objects/backing-store.cc | 230 +++++-- src/objects/backing-store.h | 33 +- src/objects/contexts.h | 15 + src/objects/contexts.tq | 24 + src/objects/elements-kind.cc | 12 + src/objects/elements-kind.h | 58 +- src/objects/elements.cc | 250 +++++++- src/objects/js-array-buffer-inl.h | 42 +- src/objects/js-array-buffer.cc | 42 +- src/objects/js-array-buffer.h | 25 +- src/objects/js-array-buffer.tq | 32 + src/objects/js-function.cc | 49 ++ src/objects/js-function.h | 5 + src/objects/js-objects.cc | 10 +- src/objects/js-objects.tq | 7 +- src/objects/lookup-inl.h | 3 +- src/objects/map-inl.h | 10 +- src/objects/map.h | 5 +- src/objects/map.tq | 3 +- src/objects/objects.cc | 1 + src/runtime/runtime-internal.cc | 1 + src/runtime/runtime-literals.cc | 1 + src/runtime/runtime-object.cc | 11 +- src/runtime/runtime-typedarray.cc | 9 + src/runtime/runtime.h | 11 +- src/snapshot/context-deserializer.cc | 4 +- src/snapshot/object-deserializer.cc | 4 +- .../PrivateAccessorAccess.golden | 8 +- .../PrivateMethodAccess.golden | 4 +- .../StaticPrivateMethodAccess.golden | 20 +- ...learraybuffer-growablesharedarraybuffer.js | 430 +++++++++++++ .../typedarray-growablesharedarraybuffer.js | 354 ++++++++++ .../typedarray-resizablearraybuffer-detach.js | 138 ++++ .../typedarray-resizablearraybuffer.js | 605 ++++++++++++++++++ tools/v8heapconst.py | 164 ++--- 58 files changed, 3506 insertions(+), 578 deletions(-) create mode 100644 test/mjsunit/resizablearraybuffer-growablesharedarraybuffer.js create mode 100644 test/mjsunit/typedarray-growablesharedarraybuffer.js create mode 100644 test/mjsunit/typedarray-resizablearraybuffer-detach.js create mode 100644 test/mjsunit/typedarray-resizablearraybuffer.js diff --git a/src/builtins/arraybuffer.tq b/src/builtins/arraybuffer.tq index 179c4b38fd..5794414443 100644 --- a/src/builtins/arraybuffer.tq +++ b/src/builtins/arraybuffer.tq @@ -9,21 +9,25 @@ transitioning javascript builtin ArrayBufferPrototypeGetByteLength( js-implicit context: NativeContext, receiver: JSAny)(): Number { // 1. Let O be the this value. // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]). + const functionName = 'get ArrayBuffer.prototype.byteLength'; const o = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'get ArrayBuffer.prototype.byteLength', receiver); + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); // 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception. if (IsSharedArrayBuffer(o)) { ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'get ArrayBuffer.prototype.byteLength', receiver); + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); } - // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. + // 4. If IsResizableArrayBuffer(O) is true, throw a TypeError exception. + if (IsResizableArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 5. If IsDetachedBuffer(O) is true, throw a TypeError exception. // TODO(v8:4895): We don't actually throw here. - // 5. Let length be O.[[ArrayBufferByteLength]]. + // 6. Let length be O.[[ArrayBufferByteLength]]. const length = o.byte_length; - // 6. Return length. + // 7. Return length. return Convert(length); } @@ -32,15 +36,43 @@ transitioning javascript builtin SharedArrayBufferPrototypeGetByteLength( js-implicit context: NativeContext, receiver: JSAny)(): Number { // 1. Let O be the this value. // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]). + const functionName = 'get SharedArrayBuffer.prototype.byteLength'; const o = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'get SharedArrayBuffer.prototype.byteLength', receiver); - // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception. + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + // 3. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]). if (!IsSharedArrayBuffer(o)) { ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'get SharedArrayBuffer.prototype.byteLength', receiver); + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 4. If IsResizableArrayBuffer(O) is true, throw a TypeError exception. + if (IsResizableArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 5. Let length be O.[[ArrayBufferByteLength]]. + const length = o.byte_length; + // 6. Return length. + return Convert(length); +} + +// #sec-get-resizablearraybuffer.prototype.bytelength +transitioning javascript builtin ResizableArrayBufferPrototypeGetByteLength( + js-implicit context: NativeContext, receiver: JSAny)(): Number { + // 1. Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]). + const functionName = 'get ResizableArrayBuffer.prototype.byteLength'; + const o = Cast(receiver) otherwise + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + if (!IsResizableArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception. + if (IsSharedArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); } // 4. Let length be O.[[ArrayBufferByteLength]]. const length = o.byte_length; @@ -48,6 +80,55 @@ transitioning javascript builtin SharedArrayBufferPrototypeGetByteLength( return Convert(length); } +// #sec-get-resizablearraybuffer.prototype.maxbytelength +transitioning javascript builtin ResizableArrayBufferPrototypeGetMaxByteLength( + js-implicit context: NativeContext, receiver: JSAny)(): Number { + // 1. Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]). + const functionName = 'get ResizableArrayBuffer.prototype.maxByteLength'; + const o = Cast(receiver) otherwise + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + if (!IsResizableArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception. + if (IsSharedArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 4. Let length be O.[[ArrayBufferMaxByteLength]]. + const length = o.max_byte_length; + // 5. Return length. + return Convert(length); +} + +// #sec-get-growablesharedarraybuffer.prototype.maxbytelength +transitioning javascript builtin +GrowableSharedArrayBufferPrototypeGetMaxByteLength( + js-implicit context: NativeContext, receiver: JSAny)(): Number { + // 1. Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]). + const functionName = 'get GrowableSharedArrayBuffer.prototype.maxByteLength'; + const o = Cast(receiver) otherwise + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + if (!IsResizableArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception. + if (!IsSharedArrayBuffer(o)) { + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, functionName, receiver); + } + // 4. Let length be O.[[ArrayBufferMaxByteLength]]. + const length = o.max_byte_length; + // 5. Return length. + return Convert(length); +} + // #sec-arraybuffer.isview transitioning javascript builtin ArrayBufferIsView(arg: JSAny): Boolean { // 1. If Type(arg) is not Object, return false. diff --git a/src/builtins/base.tq b/src/builtins/base.tq index 8dec09f487..3747383883 100644 --- a/src/builtins/base.tq +++ b/src/builtins/base.tq @@ -1696,7 +1696,7 @@ extern transitioning runtime SetOwnPropertyIgnoreAttributes( namespace runtime { extern runtime -GetDerivedMap(Context, JSFunction, JSReceiver): Map; +GetDerivedMap(Context, JSFunction, JSReceiver, JSAny): Map; } extern macro IsDeprecatedMap(Map): bool; diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc index a5dc159db9..85299b587d 100644 --- a/src/builtins/builtins-array.cc +++ b/src/builtins/builtins-array.cc @@ -889,9 +889,11 @@ uint32_t EstimateElementCount(Isolate* isolate, Handle array) { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) // External arrays are always dense. return length; + +#undef TYPED_ARRAY_CASE case NO_ELEMENTS: return 0; case FAST_SLOPPY_ARGUMENTS_ELEMENTS: @@ -965,9 +967,7 @@ void CollectElementIndices(Isolate* isolate, Handle object, } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: - TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE - { + TYPED_ARRAYS(TYPED_ARRAY_CASE) { size_t length = Handle::cast(object)->length(); if (range <= length) { length = range; @@ -983,6 +983,11 @@ void CollectElementIndices(Isolate* isolate, Handle object, if (length == range) return; // All indices accounted for already. break; } + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) + // TODO(v8:11111): Support RAB / GSAB. + UNREACHABLE(); + +#undef TYPED_ARRAY_CASE case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { DisallowGarbageCollection no_gc; @@ -1208,8 +1213,11 @@ bool IterateElements(Isolate* isolate, Handle receiver, break; #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE return IterateElementsSlow(isolate, receiver, length, visitor); + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) + // TODO(v8:11111): Support RAB / GSAB. + UNREACHABLE(); +#undef TYPED_ARRAY_CASE case FAST_STRING_WRAPPER_ELEMENTS: case SLOW_STRING_WRAPPER_ELEMENTS: // |array| is guaranteed to be an array or typed array. diff --git a/src/builtins/builtins-arraybuffer.cc b/src/builtins/builtins-arraybuffer.cc index 0f5f905186..dd59c3781a 100644 --- a/src/builtins/builtins-arraybuffer.cc +++ b/src/builtins/builtins-arraybuffer.cc @@ -23,17 +23,43 @@ namespace internal { name)); \ } +#define CHECK_RESIZABLE(expected, name, method) \ + if (name->is_resizable() != expected) { \ + THROW_NEW_ERROR_RETURN_FAILURE( \ + isolate, \ + NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ + isolate->factory()->NewStringFromAsciiChecked(method), \ + name)); \ + } + // ----------------------------------------------------------------------------- // ES#sec-arraybuffer-objects namespace { +bool RoundUpToPageSize(size_t byte_length, size_t page_size, + size_t max_allowed_byte_length, size_t* pages) { + size_t bytes_wanted = RoundUp(byte_length, page_size); + if (bytes_wanted > max_allowed_byte_length) { + return false; + } + *pages = bytes_wanted / page_size; + return true; +} + Object ConstructBuffer(Isolate* isolate, Handle target, Handle new_target, Handle length, - InitializedFlag initialized) { - SharedFlag shared = (*target != target->native_context().array_buffer_fun()) - ? SharedFlag::kShared - : SharedFlag::kNotShared; + Handle max_length, InitializedFlag initialized) { + SharedFlag shared = + (*target != target->native_context().array_buffer_fun() && + *target != target->native_context().resizable_array_buffer_fun()) + ? SharedFlag::kShared + : SharedFlag::kNotShared; + ResizableFlag resizable = + (*target == target->native_context().resizable_array_buffer_fun() || + *target == target->native_context().growable_shared_array_buffer_fun()) + ? ResizableFlag::kResizable + : ResizableFlag::kNotResizable; Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, @@ -42,9 +68,10 @@ Object ConstructBuffer(Isolate* isolate, Handle target, // Ensure that all fields are initialized because BackingStore::Allocate is // allowed to GC. Note that we cannot move the allocation of the ArrayBuffer // after BackingStore::Allocate because of the spec. - array_buffer->Setup(shared, nullptr); + array_buffer->Setup(shared, resizable, nullptr); size_t byte_length; + size_t max_byte_length = 0; if (!TryNumberToSize(*length, &byte_length) || byte_length > JSArrayBuffer::kMaxByteLength) { // ToNumber failed. @@ -52,8 +79,46 @@ Object ConstructBuffer(Isolate* isolate, Handle target, isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); } - auto backing_store = - BackingStore::Allocate(isolate, byte_length, shared, initialized); + std::unique_ptr backing_store; + if (resizable == ResizableFlag::kNotResizable) { + backing_store = + BackingStore::Allocate(isolate, byte_length, shared, initialized); + } else { + Handle number_max_length; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_max_length, + Object::ToInteger(isolate, max_length)); + + if (!TryNumberToSize(*number_max_length, &max_byte_length)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, + NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength)); + } + if (byte_length > max_byte_length) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, + NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength)); + } + + size_t page_size = AllocatePageSize(); + size_t initial_pages; + if (!RoundUpToPageSize(byte_length, page_size, + JSArrayBuffer::kMaxByteLength, &initial_pages)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); + } + + size_t max_pages; + if (!RoundUpToPageSize(max_byte_length, page_size, + JSArrayBuffer::kMaxByteLength, &max_pages)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, + NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength)); + } + constexpr bool kIsWasmMemory = false; + backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory( + isolate, byte_length, page_size, initial_pages, max_pages, + kIsWasmMemory, shared); + } if (!backing_store) { // Allocation of backing store failed. THROW_NEW_ERROR_RETURN_FAILURE( @@ -61,6 +126,7 @@ Object ConstructBuffer(Isolate* isolate, Handle target, } array_buffer->Attach(std::move(backing_store)); + array_buffer->set_max_byte_length(max_byte_length); return *array_buffer; } @@ -71,7 +137,10 @@ BUILTIN(ArrayBufferConstructor) { HandleScope scope(isolate); Handle target = args.target(); DCHECK(*target == target->native_context().array_buffer_fun() || - *target == target->native_context().shared_array_buffer_fun()); + *target == target->native_context().shared_array_buffer_fun() || + *target == target->native_context().resizable_array_buffer_fun() || + *target == + target->native_context().growable_shared_array_buffer_fun()); if (args.new_target()->IsUndefined(isolate)) { // [[Call]] THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, @@ -87,10 +156,11 @@ BUILTIN(ArrayBufferConstructor) { if (number_length->Number() < 0.0) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); - } + } - return ConstructBuffer(isolate, target, new_target, number_length, - InitializedFlag::kZeroInitialized); + Handle max_length = args.atOrUndefined(isolate, 2); + return ConstructBuffer(isolate, target, new_target, number_length, max_length, + InitializedFlag::kZeroInitialized); } // This is a helper to construct an ArrayBuffer with uinitialized memory. @@ -101,7 +171,7 @@ BUILTIN(ArrayBufferConstructor_DoNotInitialize) { Handle target(isolate->native_context()->array_buffer_fun(), isolate); Handle length = args.atOrUndefined(isolate, 1); - return ConstructBuffer(isolate, target, target, length, + return ConstructBuffer(isolate, target, target, length, Handle(), InitializedFlag::kUninitialized); } @@ -119,6 +189,8 @@ static Object SliceHelper(BuiltinArguments args, Isolate* isolate, // * [SAB] If IsSharedArrayBuffer(O) is false, throw a TypeError exception. CHECK_SHARED(is_shared, array_buffer, kMethodName); + CHECK_RESIZABLE(false, array_buffer, kMethodName); + // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception. if (!is_shared && array_buffer->was_detached()) { THROW_NEW_ERROR_RETURN_FAILURE( @@ -280,5 +352,140 @@ BUILTIN(ArrayBufferPrototypeSlice) { return SliceHelper(args, isolate, kMethodName, false); } +static Object ResizeHelper(BuiltinArguments args, Isolate* isolate, + const char* kMethodName, bool is_shared) { + HandleScope scope(isolate); + + // 1 Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]). + CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName); + CHECK_RESIZABLE(true, array_buffer, kMethodName); + + // [RAB] 3. If IsSharedArrayBuffer(O) is true, throw a *TypeError* exception + // [GSAB] 3. If IsSharedArrayBuffer(O) is false, throw a *TypeError* exception + CHECK_SHARED(is_shared, array_buffer, kMethodName); + + // Let newByteLength to ? ToIntegerOrInfinity(newLength). + Handle new_length = args.at(1); + Handle number_new_byte_length; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_new_byte_length, + Object::ToInteger(isolate, new_length)); + + // [RAB] If IsDetachedBuffer(O) is true, throw a TypeError exception. + if (!is_shared && array_buffer->was_detached()) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kDetachedOperation, + isolate->factory()->NewStringFromAsciiChecked( + kMethodName))); + } + + // [RAB] If newByteLength < 0 or newByteLength > + // O.[[ArrayBufferMaxByteLength]], throw a RangeError exception. + + // [GSAB] If newByteLength < currentByteLength or newByteLength > + // O.[[ArrayBufferMaxByteLength]], throw a RangeError exception. + size_t new_byte_length; + if (!TryNumberToSize(*number_new_byte_length, &new_byte_length)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, + isolate->factory()->NewStringFromAsciiChecked( + kMethodName))); + } + + if (is_shared && new_byte_length < array_buffer->byte_length()) { + // GrowableSharedArrayBuffer is only allowed to grow. + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, + isolate->factory()->NewStringFromAsciiChecked( + kMethodName))); + } + + if (new_byte_length > array_buffer->max_byte_length()) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, + isolate->factory()->NewStringFromAsciiChecked( + kMethodName))); + } + + size_t page_size = AllocatePageSize(); + size_t new_committed_pages; + bool round_return_value = + RoundUpToPageSize(new_byte_length, page_size, + JSArrayBuffer::kMaxByteLength, &new_committed_pages); + CHECK(round_return_value); + + // [RAB] Let hostHandled be ? HostResizeArrayBuffer(O, newByteLength). + // [GSAB] Let hostHandled be ? HostGrowArrayBuffer(O, newByteLength). + // If hostHandled is handled, return undefined. + + // TODO(v8:11111): Wasm integration. + + // [RAB] Let oldBlock be O.[[ArrayBufferData]]. + // [RAB] Let newBlock be ? CreateByteDataBlock(newByteLength). + // [RAB] Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]). + // [RAB] Perform CopyDataBlockBytes(newBlock, 0, oldBlock, 0, copyLength). + // [RAB] NOTE: Neither creation of the new Data Block nor copying from the old + // Data Block are observable. Implementations reserve the right to implement + // this method as in-place growth or shrinkage. + if (!array_buffer->GetBackingStore()->ResizeInPlace( + isolate, new_byte_length, new_committed_pages * page_size, + !is_shared)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); + } + // [RAB] Set O.[[ArrayBufferByteLength]] to newLength. + if (!is_shared) { + array_buffer->set_byte_length(new_byte_length); + } else { + // Invariant: byte_length for a GSAB is 0 (it needs to be read from the + // BackingStore). + CHECK_EQ(0, array_buffer->byte_length()); + } + return ReadOnlyRoots(isolate).undefined_value(); +} + +// ES #sec-get-growablesharedarraybuffer.prototype.bytelength +// get GrowableSharedArrayBuffer.prototype.byteLength +BUILTIN(GrowableSharedArrayBufferPrototypeGetByteLength) { + const char* const kMethodName = + "get GrowableSharedArrayBuffer.prototype.byteLength"; + HandleScope scope(isolate); + + // 1. Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxLength]]). + CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName); + CHECK_RESIZABLE(true, array_buffer, kMethodName); + // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception. + CHECK_SHARED(true, array_buffer, kMethodName); + + // 4. Let length be ArrayBufferByteLength(O, SeqCst). + + // Invariant: byte_length for GSAB is 0 (it needs to be read from the + // BackingStore). + DCHECK_EQ(0, array_buffer->byte_length()); + + size_t byte_length = + array_buffer->GetBackingStore()->byte_length(std::memory_order_seq_cst); + + // 5. Return length. + return *isolate->factory()->NewNumberFromSize(byte_length); +} + +// ES #sec-resizablearraybuffer.prototype.resize +// ResizableArrayBuffer.prototype.resize(new_size)) +BUILTIN(ResizableArrayBufferPrototypeResize) { + const char* const kMethodName = "ResizableArrayBuffer.prototype.resize"; + constexpr bool kIsShared = false; + return ResizeHelper(args, isolate, kMethodName, kIsShared); +} + +// ES #sec-growablesharedarraybuffer.prototype.grow +// GrowableSharedArrayBuffer.prototype.grow(new_size)) +BUILTIN(GrowableSharedArrayBufferPrototypeGrow) { + const char* const kMethodName = "GrowableSharedArrayBuffer.prototype.grow"; + constexpr bool kIsShared = true; + return ResizeHelper(args, isolate, kMethodName, kIsShared); +} + } // namespace internal } // namespace v8 diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 19992f8841..7cb9459e4e 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -768,6 +768,11 @@ namespace internal { ASM(RegExpInterpreterTrampoline, CCall) \ ASM(RegExpExperimentalTrampoline, CCall) \ \ + /* ResizableArrayBuffer & GrowableSharedArrayBuffer */ \ + CPP(ResizableArrayBufferPrototypeResize) \ + CPP(GrowableSharedArrayBufferPrototypeGrow) \ + CPP(GrowableSharedArrayBufferPrototypeGetByteLength) \ + \ /* Set */ \ TFJ(SetConstructor, kDontAdaptArgumentsSentinel) \ TFJ(SetPrototypeHas, 1, kReceiver, kKey) \ diff --git a/src/builtins/builtins-handler-gen.cc b/src/builtins/builtins-handler-gen.cc index 3cbd626b8e..19a31b81a7 100644 --- a/src/builtins/builtins-handler-gen.cc +++ b/src/builtins/builtins-handler-gen.cc @@ -183,28 +183,39 @@ TF_BUILTIN(ElementsTransitionAndStore_NoTransitionHandleCOW, // All elements kinds handled by EmitElementStore. Specifically, this includes // fast elements and fixed typed array elements. -#define ELEMENTS_KINDS(V) \ - V(PACKED_SMI_ELEMENTS) \ - V(HOLEY_SMI_ELEMENTS) \ - V(PACKED_ELEMENTS) \ - V(PACKED_NONEXTENSIBLE_ELEMENTS) \ - V(PACKED_SEALED_ELEMENTS) \ - V(HOLEY_ELEMENTS) \ - V(HOLEY_NONEXTENSIBLE_ELEMENTS) \ - V(HOLEY_SEALED_ELEMENTS) \ - V(PACKED_DOUBLE_ELEMENTS) \ - V(HOLEY_DOUBLE_ELEMENTS) \ - V(UINT8_ELEMENTS) \ - V(INT8_ELEMENTS) \ - V(UINT16_ELEMENTS) \ - V(INT16_ELEMENTS) \ - V(UINT32_ELEMENTS) \ - V(INT32_ELEMENTS) \ - V(FLOAT32_ELEMENTS) \ - V(FLOAT64_ELEMENTS) \ - V(UINT8_CLAMPED_ELEMENTS) \ - V(BIGUINT64_ELEMENTS) \ - V(BIGINT64_ELEMENTS) +#define ELEMENTS_KINDS(V) \ + V(PACKED_SMI_ELEMENTS) \ + V(HOLEY_SMI_ELEMENTS) \ + V(PACKED_ELEMENTS) \ + V(PACKED_NONEXTENSIBLE_ELEMENTS) \ + V(PACKED_SEALED_ELEMENTS) \ + V(HOLEY_ELEMENTS) \ + V(HOLEY_NONEXTENSIBLE_ELEMENTS) \ + V(HOLEY_SEALED_ELEMENTS) \ + V(PACKED_DOUBLE_ELEMENTS) \ + V(HOLEY_DOUBLE_ELEMENTS) \ + V(UINT8_ELEMENTS) \ + V(INT8_ELEMENTS) \ + V(UINT16_ELEMENTS) \ + V(INT16_ELEMENTS) \ + V(UINT32_ELEMENTS) \ + V(INT32_ELEMENTS) \ + V(FLOAT32_ELEMENTS) \ + V(FLOAT64_ELEMENTS) \ + V(UINT8_CLAMPED_ELEMENTS) \ + V(BIGUINT64_ELEMENTS) \ + V(BIGINT64_ELEMENTS) \ + V(RAB_GSAB_UINT8_ELEMENTS) \ + V(RAB_GSAB_INT8_ELEMENTS) \ + V(RAB_GSAB_UINT16_ELEMENTS) \ + V(RAB_GSAB_INT16_ELEMENTS) \ + V(RAB_GSAB_UINT32_ELEMENTS) \ + V(RAB_GSAB_INT32_ELEMENTS) \ + V(RAB_GSAB_FLOAT32_ELEMENTS) \ + V(RAB_GSAB_FLOAT64_ELEMENTS) \ + V(RAB_GSAB_UINT8_CLAMPED_ELEMENTS) \ + V(RAB_GSAB_BIGUINT64_ELEMENTS) \ + V(RAB_GSAB_BIGINT64_ELEMENTS) void HandlerBuiltinsAssembler::DispatchByElementsKind( TNode elements_kind, const ElementsKindSwitchCase& case_function, diff --git a/src/builtins/builtins-typed-array-gen.cc b/src/builtins/builtins-typed-array-gen.cc index 9bb904f166..d333a61e39 100644 --- a/src/builtins/builtins-typed-array-gen.cc +++ b/src/builtins/builtins-typed-array-gen.cc @@ -123,13 +123,26 @@ TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) { // Check if the {receiver} is actually a JSTypedArray. ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName); - // Default to zero if the {receiver}s buffer was detached. + TNode receiver_array = CAST(receiver); TNode receiver_buffer = - LoadJSArrayBufferViewBuffer(CAST(receiver)); - TNode byte_length = Select( - IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); }, - [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); }); - Return(ChangeUintPtrToTagged(byte_length)); + LoadJSArrayBufferViewBuffer(receiver_array); + + Label variable_length(this), normal(this); + Branch(IsVariableLengthTypedArray(receiver_array), &variable_length, &normal); + BIND(&variable_length); + { + Return(ChangeUintPtrToTagged(LoadVariableLengthJSTypedArrayByteLength( + context, receiver_array, receiver_buffer))); + } + + BIND(&normal); + { + // Default to zero if the {receiver}s buffer was detached. + TNode byte_length = Select( + IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); }, + [=] { return LoadJSArrayBufferViewByteLength(receiver_array); }); + Return(ChangeUintPtrToTagged(byte_length)); + } } // ES6 #sec-get-%typedarray%.prototype.byteoffset @@ -159,13 +172,29 @@ TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) { // Check if the {receiver} is actually a JSTypedArray. ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName); - // Default to zero if the {receiver}s buffer was detached. + TNode receiver_array = CAST(receiver); TNode receiver_buffer = - LoadJSArrayBufferViewBuffer(CAST(receiver)); - TNode length = Select( - IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); }, - [=] { return LoadJSTypedArrayLength(CAST(receiver)); }); - Return(ChangeUintPtrToTagged(length)); + LoadJSArrayBufferViewBuffer(receiver_array); + + Label variable_length(this), normal(this); + Branch(IsVariableLengthTypedArray(receiver_array), &variable_length, &normal); + BIND(&variable_length); + { + Label miss(this); + Return(ChangeUintPtrToTagged(LoadVariableLengthJSTypedArrayLength( + receiver_array, receiver_buffer, &miss))); + BIND(&miss); + Return(ChangeUintPtrToTagged(UintPtrConstant(0))); + } + + BIND(&normal); + { + // Default to zero if the {receiver}s buffer was detached. + TNode length = Select( + IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); }, + [=] { return LoadJSTypedArrayLength(receiver_array); }); + Return(ChangeUintPtrToTagged(length)); + } } TNode TypedArrayBuiltinsAssembler::IsUint8ElementsKind( @@ -322,17 +351,18 @@ void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind( int32_t elements_kinds[] = { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS, - TYPED_ARRAYS(TYPED_ARRAY_CASE) + TYPED_ARRAYS(TYPED_ARRAY_CASE) RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE }; #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this); TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE Label* elements_kind_labels[] = { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array, - TYPED_ARRAYS(TYPED_ARRAY_CASE) + TYPED_ARRAYS(TYPED_ARRAY_CASE) RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE }; STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels)); @@ -350,6 +380,15 @@ void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind( TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ + BIND(&if_##type##array); \ + { \ + case_function(TYPE##_ELEMENTS, sizeof(ctype), 0); \ + Goto(&next); \ + } + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE + BIND(&if_unknown_type); Unreachable(); diff --git a/src/builtins/typed-array-createtypedarray.tq b/src/builtins/typed-array-createtypedarray.tq index 6e416ddd98..6333ebf97f 100644 --- a/src/builtins/typed-array-createtypedarray.tq +++ b/src/builtins/typed-array-createtypedarray.tq @@ -19,11 +19,17 @@ extern macro TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields( extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)( Map, String): never; +extern runtime GrowableSharedArrayBufferByteLength(implicit context: Context)( + Object): JSAny; + transitioning macro AllocateTypedArray(implicit context: Context)( isOnHeap: constexpr bool, map: Map, buffer: JSArrayBuffer, - byteOffset: uintptr, byteLength: uintptr, length: uintptr): JSTypedArray { + byteOffset: uintptr, byteLength: uintptr, length: uintptr, + isLengthTracking: bool): JSTypedArray { let elements: ByteArray; if constexpr (isOnHeap) { + assert(!IsResizableArrayBuffer(buffer)); + assert(!isLengthTracking); elements = AllocateByteArray(byteLength); } else { elements = kEmptyByteArray; @@ -53,6 +59,9 @@ transitioning macro AllocateTypedArray(implicit context: Context)( typedArray.byte_offset = byteOffset; typedArray.byte_length = byteLength; typedArray.length = length; + typedArray.bit_field.is_length_tracking = isLengthTracking; + typedArray.bit_field.is_backed_by_rab = + IsResizableArrayBuffer(buffer) && !IsSharedArrayBuffer(buffer); typed_array::AllocateJSTypedArrayExternalPointerEntry(typedArray); if constexpr (isOnHeap) { typed_array::SetJSTypedArrayOnHeapDataPtr(typedArray, elements, byteOffset); @@ -88,8 +97,10 @@ transitioning macro TypedArrayInitialize(implicit context: Context)( const buffer = AllocateEmptyOnHeapBuffer(byteLength); const isOnHeap: constexpr bool = true; + const isLengthTracking: constexpr bool = false; const typedArray = AllocateTypedArray( - isOnHeap, map, buffer, byteOffset, byteLength, length); + isOnHeap, map, buffer, byteOffset, byteLength, length, + isLengthTracking); if constexpr (initialize) { const backingStore = typedArray.data_ptr; @@ -107,8 +118,10 @@ transitioning macro TypedArrayInitialize(implicit context: Context)( } label AttachOffHeapBuffer(bufferObj: Object) { const buffer = Cast(bufferObj) otherwise unreachable; const isOnHeap: constexpr bool = false; + const isLengthTracking: constexpr bool = false; return AllocateTypedArray( - isOnHeap, map, buffer, byteOffset, byteLength, length); + isOnHeap, map, buffer, byteOffset, byteLength, length, + isLengthTracking); } } @@ -204,8 +217,26 @@ transitioning macro ConstructByTypedArray(implicit context: Context)( // 22.2.4.5 TypedArray ( buffer, byteOffset, length ) // ES #sec-typedarray-buffer-byteoffset-length transitioning macro ConstructByArrayBuffer(implicit context: Context)( - map: Map, buffer: JSArrayBuffer, byteOffset: JSAny, length: JSAny, - elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray { + target: JSFunction, newTarget: JSReceiver, buffer: JSArrayBuffer, + byteOffset: JSAny, length: JSAny): JSTypedArray { + let map: Map; + const isLengthTracking: bool = + IsResizableArrayBuffer(buffer) && (length == Undefined); + // Pick the RAB / GSAB map (containing the corresponding RAB / GSAB + // ElementsKind). GSAB-backed non-length-tracking TypedArrays behave just like + // normal TypedArrays, so exclude them. + const rabGsab: bool = IsResizableArrayBuffer(buffer) && + (!IsSharedArrayBuffer(buffer) || isLengthTracking); + if (rabGsab) { + map = GetDerivedRabGsabMap(target, newTarget); + } else { + map = GetDerivedMap(target, newTarget); + } + + // 5. Let elementSize be the Number value of the Element Size value in Table + // 56 for constructorName. + const elementsInfo = GetTypedArrayElementsInfo(map); + try { // 6. Let offset be ? ToIndex(byteOffset). const offset: uintptr = ToIndex(byteOffset) otherwise IfInvalidOffset; @@ -226,7 +257,13 @@ transitioning macro ConstructByArrayBuffer(implicit context: Context)( } // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]]. - const bufferByteLength: uintptr = buffer.byte_length; + let bufferByteLength: uintptr; + if (IsResizableArrayBuffer(buffer) && IsSharedArrayBuffer(buffer)) { + bufferByteLength = ToIndex(GrowableSharedArrayBufferByteLength(buffer)) + otherwise unreachable; + } else { + bufferByteLength = buffer.byte_length; + } // 11. If length is either not present or undefined, then if (length == Undefined) { @@ -261,7 +298,8 @@ transitioning macro ConstructByArrayBuffer(implicit context: Context)( const isOnHeap: constexpr bool = false; return AllocateTypedArray( - isOnHeap, map, buffer, offset, newByteLength, newLength); + isOnHeap, map, buffer, offset, newByteLength, newLength, + isLengthTracking); } label IfInvalidAlignment(problemString: String) deferred { ThrowInvalidTypedArrayAlignment(map, problemString); } label IfInvalidLength deferred { @@ -286,6 +324,8 @@ transitioning macro TypedArrayCreateByLength(implicit context: Context)( // ValidateTypedArray currently returns the array, not the ViewBuffer. const newTypedArray: JSTypedArray = ValidateTypedArray(context, newTypedArrayObj, methodName); + newTypedArray.bit_field.is_length_tracking = false; + newTypedArray.bit_field.is_backed_by_rab = false; if (IsDetachedBuffer(newTypedArray.buffer)) deferred { ThrowTypeError(MessageTemplate::kDetachedOperation, methodName); @@ -336,21 +376,16 @@ transitioning builtin CreateTypedArray( assert(IsConstructor(target)); // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, // "%TypedArrayPrototype%"). - const map = GetDerivedMap(target, newTarget); - - // 5. Let elementSize be the Number value of the Element Size value in Table - // 56 for constructorName. - const elementsInfo = GetTypedArrayElementsInfo(map); - try { typeswitch (arg1) { case (length: Smi): { goto IfConstructByLength(length); } case (buffer: JSArrayBuffer): { - return ConstructByArrayBuffer(map, buffer, arg2, arg3, elementsInfo); + return ConstructByArrayBuffer(target, newTarget, buffer, arg2, arg3); } case (typedArray: JSTypedArray): { + // TODO(v8:11111): Support RAB / GSAB. ConstructByTypedArray(typedArray) otherwise IfConstructByArrayLike; } case (obj: JSReceiver): { @@ -363,9 +398,18 @@ transitioning builtin CreateTypedArray( } } } label IfConstructByLength(length: JSAny) { + const map = GetDerivedMap(target, newTarget); + // 5. Let elementSize be the Number value of the Element Size value in Table + // 56 for constructorName. + const elementsInfo = GetTypedArrayElementsInfo(map); + return ConstructByLength(map, length, elementsInfo); } label IfConstructByArrayLike( arrayLike: JSReceiver, length: uintptr, bufferConstructor: JSReceiver) { + const map = GetDerivedMap(target, newTarget); + // 5. Let elementSize be the Number value of the Element Size value in Table + // 56 for constructorName. + const elementsInfo = GetTypedArrayElementsInfo(map); return ConstructByArrayLike( map, arrayLike, length, elementsInfo, bufferConstructor); } diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc index 540e6bf648..71341a98bf 100644 --- a/src/codegen/code-stub-assembler.cc +++ b/src/codegen/code-stub-assembler.cc @@ -9603,6 +9603,7 @@ void CodeStubAssembler::TryLookupElement( BIGUINT64_ELEMENTS, BIGINT64_ELEMENTS, }; + // TODO(v8:11111): Support RAB / GSAB. Label* labels[] = { &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, @@ -10860,6 +10861,12 @@ void CodeStubAssembler::EmitElementStore( TNode context, TVariable* maybe_converted_value) { CSA_ASSERT(this, Word32BinaryNot(IsJSProxy(object))); + // TODO(v8:11111): Fast path for RAB / GSAB backed TypedArrays. + if (IsRabGsabTypedArrayElementsKind(elements_kind)) { + GotoIf(Int32TrueConstant(), bailout); + return; + } + TNode elements = LoadElements(object); if (!(IsSmiOrObjectElementsKind(elements_kind) || IsSealedElementsKind(elements_kind) || @@ -13654,6 +13661,149 @@ TNode CodeStubAssembler::LoadJSTypedArrayLength( return LoadObjectField(typed_array, JSTypedArray::kLengthOffset); } +// ES #sec-integerindexedobjectlength +TNode CodeStubAssembler::LoadVariableLengthJSTypedArrayLength( + TNode array, TNode buffer, Label* miss) { + Label is_gsab(this), is_rab(this), end(this); + TVARIABLE(UintPtrT, result); + + Branch(IsSharedArrayBuffer(buffer), &is_gsab, &is_rab); + BIND(&is_gsab); + { + // Non-length-tracking GSAB-backed TypedArrays shouldn't end up here. + CSA_ASSERT(this, IsLengthTrackingTypedArray(array)); + // Read the byte length from the BackingStore. + const TNode length_function = ExternalConstant( + ExternalReference::length_tracking_gsab_backed_typed_array_length()); + TNode isolate_ptr = + ExternalConstant(ExternalReference::isolate_address(isolate())); + result = UncheckedCast( + CallCFunction(length_function, MachineType::UintPtr(), + std::make_pair(MachineType::Pointer(), isolate_ptr), + std::make_pair(MachineType::AnyTagged(), array))); + Goto(&end); + } + + BIND(&is_rab); + { + GotoIf(IsDetachedBuffer(buffer), miss); + + TNode buffer_byte_length = LoadJSArrayBufferByteLength(buffer); + TNode array_byte_offset = LoadJSArrayBufferViewByteOffset(array); + + Label is_length_tracking(this), not_length_tracking(this); + Branch(IsLengthTrackingTypedArray(array), &is_length_tracking, + ¬_length_tracking); + + BIND(&is_length_tracking); + { + // The backing RAB might have been shrunk so that the start of the + // TypedArray is already out of bounds. + GotoIfNot(UintPtrLessThanOrEqual(array_byte_offset, buffer_byte_length), + miss); + // length = (buffer_byte_length - byte_offset) / element_size + // Conversion to signed is OK since buffer_byte_length < + // JSArrayBuffer::kMaxByteLength. + TNode element_size = + RabGsabElementsKindToElementByteSize(LoadElementsKind(array)); + TNode length = + IntPtrDiv(Signed(UintPtrSub(buffer_byte_length, array_byte_offset)), + element_size); + result = Unsigned(length); + Goto(&end); + } + + BIND(¬_length_tracking); + { + // Check if the backing RAB has shrunk so that the buffer is out of + // bounds. + TNode array_byte_length = + LoadJSArrayBufferViewByteLength(array); + GotoIfNot(UintPtrGreaterThanOrEqual( + buffer_byte_length, + UintPtrAdd(array_byte_offset, array_byte_length)), + miss); + result = LoadJSTypedArrayLength(array); + Goto(&end); + } + } + BIND(&end); + return result.value(); +} + +// ES #sec-integerindexedobjectbytelength +TNode CodeStubAssembler::LoadVariableLengthJSTypedArrayByteLength( + TNode context, TNode array, + TNode buffer) { + Label miss(this), end(this); + TVARIABLE(UintPtrT, result); + + TNode length = + LoadVariableLengthJSTypedArrayLength(array, buffer, &miss); + TNode element_size = + RabGsabElementsKindToElementByteSize(LoadElementsKind(array)); + // Conversion to signed is OK since length < JSArrayBuffer::kMaxByteLength. + TNode byte_length = IntPtrMul(Signed(length), element_size); + result = Unsigned(byte_length); + Goto(&end); + BIND(&miss); + { + result = UintPtrConstant(0); + Goto(&end); + } + BIND(&end); + return result.value(); +} + +TNode CodeStubAssembler::RabGsabElementsKindToElementByteSize( + TNode elements_kind) { + TVARIABLE(IntPtrT, result); + Label elements_8(this), elements_16(this), elements_32(this), + elements_64(this), not_found(this), end(this); + int32_t elements_kinds[] = { + RAB_GSAB_UINT8_ELEMENTS, RAB_GSAB_UINT8_CLAMPED_ELEMENTS, + RAB_GSAB_INT8_ELEMENTS, RAB_GSAB_UINT16_ELEMENTS, + RAB_GSAB_INT16_ELEMENTS, RAB_GSAB_UINT32_ELEMENTS, + RAB_GSAB_INT32_ELEMENTS, RAB_GSAB_FLOAT32_ELEMENTS, + RAB_GSAB_FLOAT64_ELEMENTS, RAB_GSAB_BIGINT64_ELEMENTS, + RAB_GSAB_BIGUINT64_ELEMENTS}; + Label* elements_kind_labels[] = {&elements_8, &elements_8, &elements_8, + &elements_16, &elements_16, &elements_32, + &elements_32, &elements_32, &elements_64, + &elements_64, &elements_64}; + const size_t kTypedElementsKindCount = + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND - + FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds)); + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels)); + Switch(elements_kind, ¬_found, elements_kinds, elements_kind_labels, + kTypedElementsKindCount); + BIND(&elements_8); + { + result = IntPtrConstant(1); + Goto(&end); + } + BIND(&elements_16); + { + result = IntPtrConstant(2); + Goto(&end); + } + BIND(&elements_32); + { + result = IntPtrConstant(4); + Goto(&end); + } + BIND(&elements_64); + { + result = IntPtrConstant(8); + Goto(&end); + } + BIND(¬_found); + { Unreachable(); } + BIND(&end); + return result.value(); +} + TNode CodeStubAssembler::GetTypedArrayBuffer( TNode context, TNode array) { Label call_runtime(this), done(this); diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h index 8b0fe48e0e..410466a848 100644 --- a/src/codegen/code-stub-assembler.h +++ b/src/codegen/code-stub-assembler.h @@ -3494,6 +3494,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode array_buffer_view); TNode LoadJSArrayBufferViewByteLength( TNode array_buffer_view); + TNode LoadJSArrayBufferViewByteOffset( TNode array_buffer_view); void ThrowIfArrayBufferViewBufferIsDetached( @@ -3502,6 +3503,17 @@ class V8_EXPORT_PRIVATE CodeStubAssembler // JSTypedArray helpers TNode LoadJSTypedArrayLength(TNode typed_array); + // Helper for length tracking JSTypedArrays and JSTypedArrays backed by + // ResizableArrayBuffer. + TNode LoadVariableLengthJSTypedArrayLength( + TNode array, TNode buffer, Label* miss); + // Helper for length tracking JSTypedArrays and JSTypedArrays backed by + // ResizableArrayBuffer. + TNode LoadVariableLengthJSTypedArrayByteLength( + TNode context, TNode array, + TNode buffer); + TNode RabGsabElementsKindToElementByteSize( + TNode elementsKind); TNode LoadJSTypedArrayDataPtr(TNode typed_array); TNode GetTypedArrayBuffer(TNode context, TNode array); diff --git a/src/codegen/external-reference.cc b/src/codegen/external-reference.cc index b019d2979c..3e91306b15 100644 --- a/src/codegen/external-reference.cc +++ b/src/codegen/external-reference.cc @@ -819,6 +819,9 @@ ExternalReference ExternalReference::search_string_raw() { FUNCTION_REFERENCE(jsarray_array_join_concat_to_sequential_string, JSArray::ArrayJoinConcatToSequentialString) +FUNCTION_REFERENCE(length_tracking_gsab_backed_typed_array_length, + JSTypedArray::LengthTrackingGsabBackedTypedArrayLength) + ExternalReference ExternalReference::search_string_raw_one_one() { return search_string_raw(); } diff --git a/src/codegen/external-reference.h b/src/codegen/external-reference.h index 9ac18a1aa1..f75a5c694a 100644 --- a/src/codegen/external-reference.h +++ b/src/codegen/external-reference.h @@ -169,6 +169,8 @@ class StatsCounter; V(jsarray_array_join_concat_to_sequential_string, \ "jsarray_array_join_concat_to_sequential_string") \ V(jsreceiver_create_identity_hash, "jsreceiver_create_identity_hash") \ + V(length_tracking_gsab_backed_typed_array_length, \ + "LengthTrackingGsabBackedTypedArrayLength") \ V(libc_memchr_function, "libc_memchr") \ V(libc_memcpy_function, "libc_memcpy") \ V(libc_memmove_function, "libc_memmove") \ diff --git a/src/common/message-template.h b/src/common/message-template.h index 8bbcc3601b..73995213fc 100644 --- a/src/common/message-template.h +++ b/src/common/message-template.h @@ -330,6 +330,8 @@ namespace internal { "Expected letters optionally connected with underscores or hyphens for " \ "a location, got %") \ T(InvalidArrayBufferLength, "Invalid array buffer length") \ + T(InvalidArrayBufferMaxLength, "Invalid array buffer max length") \ + T(InvalidArrayBufferResizeLength, "%: Invalid length parameter") \ T(ArrayBufferAllocationFailed, "Array buffer allocation failed") \ T(Invalid, "Invalid % : %") \ T(InvalidArrayLength, "Invalid array length") \ diff --git a/src/diagnostics/objects-debug.cc b/src/diagnostics/objects-debug.cc index d4591fd5f8..28b7c7b453 100644 --- a/src/diagnostics/objects-debug.cc +++ b/src/diagnostics/objects-debug.cc @@ -1437,7 +1437,7 @@ void JSArrayBufferView::JSArrayBufferViewVerify(Isolate* isolate) { void JSTypedArray::JSTypedArrayVerify(Isolate* isolate) { TorqueGeneratedClassVerifiers::JSTypedArrayVerify(*this, isolate); - CHECK_LE(length(), JSTypedArray::kMaxLength); + CHECK_LE(GetLength(), JSTypedArray::kMaxLength); } void JSDataView::JSDataViewVerify(Isolate* isolate) { @@ -1805,6 +1805,7 @@ void JSObject::IncrementSpillStatistics(Isolate* isolate, #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE { info->number_of_objects_with_fast_elements_++; diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc index 7b0c2d8e55..06b5025fb2 100644 --- a/src/diagnostics/objects-printer.cc +++ b/src/diagnostics/objects-printer.cc @@ -508,7 +508,7 @@ void JSObject::PrintElements(std::ostream& os) { #define PRINT_ELEMENTS(Type, type, TYPE, elementType) \ case TYPE##_ELEMENTS: { \ - size_t length = JSTypedArray::cast(*this).length(); \ + size_t length = JSTypedArray::cast(*this).GetLength(); \ bool is_on_heap = JSTypedArray::cast(*this).is_on_heap(); \ const elementType* data_ptr = \ static_cast(JSTypedArray::cast(*this).DataPtr()); \ @@ -516,6 +516,7 @@ void JSObject::PrintElements(std::ostream& os) { break; \ } TYPED_ARRAYS(PRINT_ELEMENTS) + RAB_GSAB_TYPED_ARRAYS(PRINT_ELEMENTS) #undef PRINT_ELEMENTS case DICTIONARY_ELEMENTS: @@ -572,7 +573,7 @@ static void JSObjectPrintBody(std::ostream& os, JSObject obj, os << "}\n"; if (print_elements) { - size_t length = obj.IsJSTypedArray() ? JSTypedArray::cast(obj).length() + size_t length = obj.IsJSTypedArray() ? JSTypedArray::cast(obj).GetLength() : obj.elements().length(); if (length > 0) obj.PrintElements(os); } @@ -1391,6 +1392,7 @@ void JSArrayBuffer::JSArrayBufferPrint(std::ostream& os) { if (is_detachable()) os << "\n - detachable"; if (was_detached()) os << "\n - detached"; if (is_shared()) os << "\n - shared"; + if (is_resizable()) os << "\n - resizable"; JSObjectPrintBody(os, *this, !was_detached()); } @@ -1399,7 +1401,7 @@ void JSTypedArray::JSTypedArrayPrint(std::ostream& os) { os << "\n - buffer: " << Brief(buffer()); os << "\n - byte_offset: " << byte_offset(); os << "\n - byte_length: " << byte_length(); - os << "\n - length: " << length(); + os << "\n - length: " << GetLength(); os << "\n - data_ptr: " << DataPtr(); Tagged_t base_ptr = static_cast(base_pointer().ptr()); os << "\n - base_pointer: " @@ -1411,6 +1413,8 @@ void JSTypedArray::JSTypedArrayPrint(std::ostream& os) { return; } if (WasDetached()) os << "\n - detached"; + if (is_length_tracking()) os << "\n - length-tracking"; + if (is_backed_by_rab()) os << "\n - backed-by-rab"; JSObjectPrintBody(os, *this, !WasDetached()); } diff --git a/src/flags/flag-definitions.h b/src/flags/flag-definitions.h index 364b994190..12d1e944c2 100644 --- a/src/flags/flag-definitions.h +++ b/src/flags/flag-definitions.h @@ -273,7 +273,9 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features") V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \ V(harmony_weak_refs_with_cleanup_some, \ "harmony weak references with FinalizationRegistry.prototype.cleanupSome") \ - V(harmony_import_assertions, "harmony import assertions") + V(harmony_import_assertions, "harmony import assertions") \ + V(harmony_rab_gsab, \ + "harmony ResizableArrayBuffer / GrowableSharedArrayBuffer") #ifdef V8_INTL_SUPPORT #define HARMONY_INPROGRESS(V) \ diff --git a/src/heap/factory.cc b/src/heap/factory.cc index d583ef9d44..cb4a52a30f 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -2518,7 +2518,8 @@ Handle Factory::NewJSArrayBuffer( isolate()); auto result = Handle::cast(NewJSObjectFromMap(map, allocation)); - result->Setup(SharedFlag::kNotShared, std::move(backing_store)); + result->Setup(SharedFlag::kNotShared, ResizableFlag::kNotResizable, + std::move(backing_store)); return result; } @@ -2536,18 +2537,32 @@ MaybeHandle Factory::NewJSArrayBufferAndBackingStore( isolate()); auto array_buffer = Handle::cast(NewJSObjectFromMap(map, allocation)); - array_buffer->Setup(SharedFlag::kNotShared, std::move(backing_store)); + array_buffer->Setup(SharedFlag::kNotShared, ResizableFlag::kNotResizable, + std::move(backing_store)); return array_buffer; } Handle Factory::NewJSSharedArrayBuffer( std::shared_ptr backing_store) { - Handle map( - isolate()->native_context()->shared_array_buffer_fun().initial_map(), - isolate()); + Handle map; + if (backing_store->is_resizable()) { + DCHECK(FLAG_harmony_rab_gsab); + map = Handle(isolate() + ->native_context() + ->growable_shared_array_buffer_fun() + .initial_map(), + isolate()); + } else { + map = Handle( + isolate()->native_context()->shared_array_buffer_fun().initial_map(), + isolate()); + } auto result = Handle::cast( NewJSObjectFromMap(map, AllocationType::kYoung)); - result->Setup(SharedFlag::kShared, std::move(backing_store)); + ResizableFlag resizable = backing_store->is_resizable() + ? ResizableFlag::kResizable + : ResizableFlag::kNotResizable; + result->Setup(SharedFlag::kShared, resizable, std::move(backing_store)); return result; } @@ -2602,6 +2617,7 @@ void Factory::TypeAndSizeForElementsKind(ElementsKind kind, *element_size = sizeof(ctype); \ break; TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS_WITH_TYPED_ARRAY_TYPE(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE default: @@ -2684,6 +2700,8 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type, raw.AllocateExternalPointerEntries(isolate()); raw.set_length(length); raw.SetOffHeapDataPtr(isolate(), buffer->backing_store(), byte_offset); + raw.set_is_length_tracking(false); + raw.set_is_backed_by_rab(!buffer->is_shared() && buffer->is_resizable()); return typed_array; } diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc index 0dd67e757c..463d379367 100644 --- a/src/ic/accessor-assembler.cc +++ b/src/ic/accessor-assembler.cc @@ -2086,9 +2086,9 @@ void AccessorAssembler::EmitElementLoad( Label* if_hole, Label* rebox_double, TVariable* var_double_value, Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss, ExitPoint* exit_point, LoadAccessMode access_mode) { - Label if_typed_array(this), if_fast(this), if_fast_packed(this), - if_fast_holey(this), if_fast_double(this), if_fast_holey_double(this), - if_nonfast(this), if_dictionary(this); + Label if_rab_gsab_typed_array(this), if_typed_array(this), if_fast(this), + if_fast_packed(this), if_fast_holey(this), if_fast_double(this), + if_fast_holey_double(this), if_nonfast(this), if_dictionary(this); Branch(Int32GreaterThan(elements_kind, Int32Constant(LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)), &if_nonfast, &if_fast); @@ -2169,7 +2169,16 @@ void AccessorAssembler::EmitElementLoad( BIND(&if_nonfast); { - STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); + Label uint8_elements(this), int8_elements(this), uint16_elements(this), + int16_elements(this), uint32_elements(this), int32_elements(this), + float32_elements(this), float64_elements(this), bigint64_elements(this), + biguint64_elements(this); + STATIC_ASSERT(LAST_ELEMENTS_KIND == + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND); + GotoIf(Int32GreaterThanOrEqual( + elements_kind, + Int32Constant(FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), + &if_rab_gsab_typed_array); GotoIf(Int32GreaterThanOrEqual( elements_kind, Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), @@ -2195,88 +2204,129 @@ void AccessorAssembler::EmitElementLoad( exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant() : value); } - - BIND(&if_typed_array); { - Comment("typed elements"); - // Check if buffer has been detached. - TNode buffer = LoadJSArrayBufferViewBuffer(CAST(object)); - GotoIf(IsDetachedBuffer(buffer), miss); + TVARIABLE(RawPtrT, data_ptr); + BIND(&if_rab_gsab_typed_array); + { + Comment("rab gsab typed elements"); + Label variable_length(this), normal(this), length_check_ok(this); - // Bounds check. - TNode length = LoadJSTypedArrayLength(CAST(object)); - GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds); - if (access_mode == LoadAccessMode::kHas) { - exit_point->Return(TrueConstant()); - } else { - TNode data_ptr = LoadJSTypedArrayDataPtr(CAST(object)); + TNode array = CAST(object); + TNode buffer = LoadJSArrayBufferViewBuffer(array); - Label uint8_elements(this), int8_elements(this), uint16_elements(this), - int16_elements(this), uint32_elements(this), int32_elements(this), - float32_elements(this), float64_elements(this), - bigint64_elements(this), biguint64_elements(this); - Label* elements_kind_labels[] = { - &uint8_elements, &uint8_elements, &int8_elements, - &uint16_elements, &int16_elements, &uint32_elements, - &int32_elements, &float32_elements, &float64_elements, - &bigint64_elements, &biguint64_elements}; - int32_t elements_kinds[] = { - UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS, - UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS, - INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS, - BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS}; - const size_t kTypedElementsKindCount = - LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; - DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds)); - DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels)); - Switch(elements_kind, miss, elements_kinds, elements_kind_labels, - kTypedElementsKindCount); + // Bounds check (incl. detachedness check). + TNode length = + LoadVariableLengthJSTypedArrayLength(array, buffer, miss); + Branch(UintPtrLessThan(intptr_index, length), &length_check_ok, + out_of_bounds); + BIND(&length_check_ok); + { + if (access_mode == LoadAccessMode::kHas) { + exit_point->Return(TrueConstant()); + } else { + data_ptr = LoadJSTypedArrayDataPtr(array); + Label* elements_kind_labels[] = { + &uint8_elements, &uint8_elements, &int8_elements, + &uint16_elements, &int16_elements, &uint32_elements, + &int32_elements, &float32_elements, &float64_elements, + &bigint64_elements, &biguint64_elements}; + int32_t elements_kinds[] = { + RAB_GSAB_UINT8_ELEMENTS, RAB_GSAB_UINT8_CLAMPED_ELEMENTS, + RAB_GSAB_INT8_ELEMENTS, RAB_GSAB_UINT16_ELEMENTS, + RAB_GSAB_INT16_ELEMENTS, RAB_GSAB_UINT32_ELEMENTS, + RAB_GSAB_INT32_ELEMENTS, RAB_GSAB_FLOAT32_ELEMENTS, + RAB_GSAB_FLOAT64_ELEMENTS, RAB_GSAB_BIGINT64_ELEMENTS, + RAB_GSAB_BIGUINT64_ELEMENTS}; + const size_t kTypedElementsKindCount = + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND - + FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds)); + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels)); + Switch(elements_kind, miss, elements_kinds, elements_kind_labels, + kTypedElementsKindCount); + } + } + } + BIND(&if_typed_array); + { + Comment("typed elements"); + // Check if buffer has been detached. + TNode buffer = LoadJSArrayBufferViewBuffer(CAST(object)); + GotoIf(IsDetachedBuffer(buffer), miss); + + // Bounds check. + TNode length = LoadJSTypedArrayLength(CAST(object)); + GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds); + if (access_mode == LoadAccessMode::kHas) { + exit_point->Return(TrueConstant()); + } else { + data_ptr = LoadJSTypedArrayDataPtr(CAST(object)); + + Label* elements_kind_labels[] = { + &uint8_elements, &uint8_elements, &int8_elements, + &uint16_elements, &int16_elements, &uint32_elements, + &int32_elements, &float32_elements, &float64_elements, + &bigint64_elements, &biguint64_elements}; + int32_t elements_kinds[] = { + UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS, + UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS, + INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS, + BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS}; + const size_t kTypedElementsKindCount = + LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds)); + DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels)); + Switch(elements_kind, miss, elements_kinds, elements_kind_labels, + kTypedElementsKindCount); + } + } + if (access_mode != LoadAccessMode::kHas) { BIND(&uint8_elements); { Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too. - TNode element = Load(data_ptr, intptr_index); + TNode element = Load(data_ptr.value(), intptr_index); exit_point->Return(SmiFromInt32(element)); } BIND(&int8_elements); { Comment("INT8_ELEMENTS"); - TNode element = Load(data_ptr, intptr_index); + TNode element = Load(data_ptr.value(), intptr_index); exit_point->Return(SmiFromInt32(element)); } BIND(&uint16_elements); { Comment("UINT16_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(1)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); exit_point->Return(SmiFromInt32(element)); } BIND(&int16_elements); { Comment("INT16_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(1)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); exit_point->Return(SmiFromInt32(element)); } BIND(&uint32_elements); { Comment("UINT32_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(2)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); exit_point->Return(ChangeUint32ToTagged(element)); } BIND(&int32_elements); { Comment("INT32_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(2)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); exit_point->Return(ChangeInt32ToTagged(element)); } BIND(&float32_elements); { Comment("FLOAT32_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(2)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); *var_double_value = ChangeFloat32ToFloat64(element); Goto(rebox_double); } @@ -2284,7 +2334,7 @@ void AccessorAssembler::EmitElementLoad( { Comment("FLOAT64_ELEMENTS"); TNode index = WordShl(intptr_index, IntPtrConstant(3)); - TNode element = Load(data_ptr, index); + TNode element = Load(data_ptr.value(), index); *var_double_value = element; Goto(rebox_double); } @@ -2292,13 +2342,13 @@ void AccessorAssembler::EmitElementLoad( { Comment("BIGINT64_ELEMENTS"); exit_point->Return(LoadFixedTypedArrayElementAsTagged( - data_ptr, Unsigned(intptr_index), BIGINT64_ELEMENTS)); + data_ptr.value(), Unsigned(intptr_index), BIGINT64_ELEMENTS)); } BIND(&biguint64_elements); { Comment("BIGUINT64_ELEMENTS"); exit_point->Return(LoadFixedTypedArrayElementAsTagged( - data_ptr, Unsigned(intptr_index), BIGUINT64_ELEMENTS)); + data_ptr.value(), Unsigned(intptr_index), BIGUINT64_ELEMENTS)); } } } diff --git a/src/ic/ic.cc b/src/ic/ic.cc index afcdd72157..b7723559c3 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1266,7 +1266,7 @@ Handle KeyedLoadIC::LoadElementHandler(Handle receiver_map, } DCHECK(IsFastElementsKind(elements_kind) || IsAnyNonextensibleElementsKind(elements_kind) || - IsTypedArrayElementsKind(elements_kind)); + IsTypedArrayOrRabGsabTypedArrayElementsKind(elements_kind)); bool convert_hole_to_undefined = (elements_kind == HOLEY_SMI_ELEMENTS || elements_kind == HOLEY_ELEMENTS) && @@ -1382,7 +1382,7 @@ bool IsOutOfBoundsAccess(Handle receiver, size_t index) { if (receiver->IsJSArray()) { length = JSArray::cast(*receiver).length().Number(); } else if (receiver->IsJSTypedArray()) { - length = JSTypedArray::cast(*receiver).length(); + length = JSTypedArray::cast(*receiver).GetLength(); } else if (receiver->IsJSObject()) { length = JSObject::cast(*receiver).elements().length(); } else if (receiver->IsString()) { @@ -2032,7 +2032,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle receiver_map, "unsupported combination of arrays (potentially read-only length)"); return; - } else if (map->has_typed_array_elements()) { + } else if (map->has_typed_array_or_rab_gsab_typed_array_elements()) { DCHECK(!IsStoreInArrayLiteralICKind(kind())); external_arrays++; } @@ -2086,7 +2086,9 @@ Handle KeyedStoreIC::StoreElementHandler( receiver_map->has_typed_array_elements()) { TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code(); - if (receiver_map->has_typed_array_elements()) return code; + if (receiver_map->has_typed_array_elements()) { + return code; + } } else if (IsStoreInArrayLiteralICKind(kind())) { // TODO(jgruber): Update counter name. TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub); @@ -2095,7 +2097,9 @@ Handle KeyedStoreIC::StoreElementHandler( // TODO(jgruber): Update counter name. TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() || - receiver_map->has_frozen_elements()); + receiver_map->has_frozen_elements() || + receiver_map->has_rab_gsab_typed_array_elements()); + // TODO(v8:11111): Add fast paths for RAB / GSAB. code = StoreHandler::StoreSlow(isolate(), store_mode); } diff --git a/src/ic/keyed-store-generic.cc b/src/ic/keyed-store-generic.cc index b07ea64483..8218d3d521 100644 --- a/src/ic/keyed-store-generic.cc +++ b/src/ic/keyed-store-generic.cc @@ -568,7 +568,8 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( // dispatch. BIND(&if_nonfast); { - STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); + STATIC_ASSERT(LAST_ELEMENTS_KIND == + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND); GotoIf(Int32GreaterThanOrEqual( elements_kind, Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), @@ -588,7 +589,8 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( BIND(&if_typed_array); { Comment("Typed array"); - // TODO(jkummerow): Support typed arrays. + // TODO(jkummerow): Support typed arrays. Note: RAB / GSAB backed typed + // arrays end up here too. Goto(slow); } } diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc index bf410d713c..7d42b60d08 100644 --- a/src/init/bootstrapper.cc +++ b/src/init/bootstrapper.cc @@ -235,6 +235,8 @@ class Genesis { enum ArrayBufferKind { ARRAY_BUFFER, SHARED_ARRAY_BUFFER, + RESIZABLE_ARRAY_BUFFER, + GROWABLE_SHARED_ARRAY_BUFFER }; Handle CreateArrayBuffer(Handle name, ArrayBufferKind array_buffer_kind); @@ -244,7 +246,8 @@ class Genesis { Handle InstallTypedArray(const char* name, ElementsKind elements_kind, - InstanceType type); + InstanceType type, + int rab_gsab_initial_map_index); void InitializeNormalizedMapCaches(); enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED }; @@ -3290,6 +3293,25 @@ void Genesis::InitializeGlobal(Handle global_object, InstallSpeciesGetter(isolate_, shared_array_buffer_fun); } + { // R e s i z a b l e A r r a y B u f f e r + Handle name = factory->ResizableArrayBuffer_string(); + Handle resizable_array_buffer_fun = + CreateArrayBuffer(name, RESIZABLE_ARRAY_BUFFER); + InstallWithIntrinsicDefaultProto(isolate_, resizable_array_buffer_fun, + Context::RESIZABLE_ARRAY_BUFFER_FUN_INDEX); + InstallSpeciesGetter(isolate_, resizable_array_buffer_fun); + } + + { // G r o w a b l e S h a r e d A r r a y B u f f e r + Handle name = factory->GrowableSharedArrayBuffer_string(); + Handle growable_shared_array_buffer_fun = + CreateArrayBuffer(name, GROWABLE_SHARED_ARRAY_BUFFER); + InstallWithIntrinsicDefaultProto( + isolate_, growable_shared_array_buffer_fun, + Context::GROWABLE_SHARED_ARRAY_BUFFER_FUN_INDEX); + InstallSpeciesGetter(isolate_, growable_shared_array_buffer_fun); + } + { // -- A t o m i c s Handle atomics_object = factory->NewJSObject(isolate_->object_function(), AllocationType::kOld); @@ -3419,12 +3441,13 @@ void Genesis::InitializeGlobal(Handle global_object, } {// -- T y p e d A r r a y s -#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype) \ - { \ - Handle fun = InstallTypedArray( \ - #Type "Array", TYPE##_ELEMENTS, TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE); \ - InstallWithIntrinsicDefaultProto(isolate_, fun, \ - Context::TYPE##_ARRAY_FUN_INDEX); \ +#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype) \ + { \ + Handle fun = InstallTypedArray( \ + #Type "Array", TYPE##_ELEMENTS, TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE, \ + Context::RAB_GSAB_##TYPE##_ARRAY_MAP_INDEX); \ + InstallWithIntrinsicDefaultProto(isolate_, fun, \ + Context::TYPE##_ARRAY_FUN_INDEX); \ } TYPED_ARRAYS(INSTALL_TYPED_ARRAY) #undef INSTALL_TYPED_ARRAY @@ -4055,7 +4078,8 @@ void Genesis::InitializeGlobal(Handle global_object, Handle Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind, - InstanceType type) { + InstanceType type, + int rab_gsab_initial_map_index) { Handle global = Handle(native_context()->global_object(), isolate()); @@ -4092,6 +4116,15 @@ Handle Genesis::InstallTypedArray(const char* name, prototype->map().set_instance_type(JS_TYPED_ARRAY_PROTOTYPE_TYPE); InstallConstant(isolate(), prototype, "BYTES_PER_ELEMENT", bytes_per_element); + + // RAB / GSAB backed TypedArrays don't have separate constructors, but they + // have their own maps. Create the corresponding map here. + Handle rab_gsab_initial_map = factory()->NewMap( + JS_TYPED_ARRAY_TYPE, JSTypedArray::kSizeWithEmbedderFields, + GetCorrespondingRabGsabElementsKind(elements_kind), 0); + native_context()->set(rab_gsab_initial_map_index, *rab_gsab_initial_map); + Map::SetPrototype(isolate(), rab_gsab_initial_map, prototype); + return result; } @@ -4553,6 +4586,19 @@ void Genesis::InitializeGlobal_harmony_intl_locale_info() { #endif // V8_INTL_SUPPORT +void Genesis::InitializeGlobal_harmony_rab_gsab() { + if (!FLAG_harmony_rab_gsab) return; + + Handle global(native_context()->global_object(), isolate()); + + JSObject::AddProperty(isolate_, global, "ResizableArrayBuffer", + isolate()->resizable_array_buffer_fun(), DONT_ENUM); + + JSObject::AddProperty(isolate_, global, "GrowableSharedArrayBuffer", + isolate()->growable_shared_array_buffer_fun(), + DONT_ENUM); +} + Handle Genesis::CreateArrayBuffer( Handle name, ArrayBufferKind array_buffer_kind) { // Create the %ArrayBufferPrototype% @@ -4596,6 +4642,28 @@ Handle Genesis::CreateArrayBuffer( Builtins::kSharedArrayBufferPrototypeSlice, 2, true); break; + case RESIZABLE_ARRAY_BUFFER: + SimpleInstallGetter(isolate(), prototype, factory()->byte_length_string(), + Builtins::kResizableArrayBufferPrototypeGetByteLength, + false); + SimpleInstallGetter( + isolate(), prototype, factory()->max_byte_length_string(), + Builtins::kResizableArrayBufferPrototypeGetMaxByteLength, false); + SimpleInstallFunction(isolate(), prototype, "resize", + Builtins::kResizableArrayBufferPrototypeResize, 1, + true); + break; + case GROWABLE_SHARED_ARRAY_BUFFER: + SimpleInstallGetter( + isolate(), prototype, factory()->byte_length_string(), + Builtins::kGrowableSharedArrayBufferPrototypeGetByteLength, true); + SimpleInstallGetter( + isolate(), prototype, factory()->max_byte_length_string(), + Builtins::kGrowableSharedArrayBufferPrototypeGetMaxByteLength, false); + SimpleInstallFunction(isolate(), prototype, "grow", + Builtins::kGrowableSharedArrayBufferPrototypeGrow, + 1, true); + break; } return array_buffer_fun; diff --git a/src/init/heap-symbols.h b/src/init/heap-symbols.h index b4043f9855..4d0213e8d1 100644 --- a/src/init/heap-symbols.h +++ b/src/init/heap-symbols.h @@ -131,223 +131,226 @@ #define INTERNALIZED_STRING_LIST_GENERATOR_INTL(V, _) #endif // V8_INTL_SUPPORT -#define INTERNALIZED_STRING_LIST_GENERATOR(V, _) \ - INTERNALIZED_STRING_LIST_GENERATOR_INTL(V, _) \ - V(_, add_string, "add") \ - V(_, AggregateError_string, "AggregateError") \ - V(_, always_string, "always") \ - V(_, anonymous_function_string, "(anonymous function)") \ - V(_, anonymous_string, "anonymous") \ - V(_, apply_string, "apply") \ - V(_, Arguments_string, "Arguments") \ - V(_, arguments_string, "arguments") \ - V(_, arguments_to_string, "[object Arguments]") \ - V(_, Array_string, "Array") \ - V(_, array_to_string, "[object Array]") \ - V(_, ArrayBuffer_string, "ArrayBuffer") \ - V(_, ArrayIterator_string, "Array Iterator") \ - V(_, as_string, "as") \ - V(_, assert_string, "assert") \ - V(_, async_string, "async") \ - V(_, auto_string, "auto") \ - V(_, await_string, "await") \ - V(_, BigInt_string, "BigInt") \ - V(_, bigint_string, "bigint") \ - V(_, BigInt64Array_string, "BigInt64Array") \ - V(_, BigUint64Array_string, "BigUint64Array") \ - V(_, bind_string, "bind") \ - V(_, Boolean_string, "Boolean") \ - V(_, boolean_string, "boolean") \ - V(_, boolean_to_string, "[object Boolean]") \ - V(_, bound__string, "bound ") \ - V(_, buffer_string, "buffer") \ - V(_, byte_length_string, "byteLength") \ - V(_, byte_offset_string, "byteOffset") \ - V(_, CompileError_string, "CompileError") \ - V(_, callee_string, "callee") \ - V(_, caller_string, "caller") \ - V(_, cause_string, "cause") \ - V(_, character_string, "character") \ - V(_, closure_string, "(closure)") \ - V(_, code_string, "code") \ - V(_, column_string, "column") \ - V(_, computed_string, "") \ - V(_, configurable_string, "configurable") \ - V(_, conjunction_string, "conjunction") \ - V(_, construct_string, "construct") \ - V(_, constructor_string, "constructor") \ - V(_, current_string, "current") \ - V(_, Date_string, "Date") \ - V(_, date_to_string, "[object Date]") \ - V(_, default_string, "default") \ - V(_, defineProperty_string, "defineProperty") \ - V(_, deleteProperty_string, "deleteProperty") \ - V(_, disjunction_string, "disjunction") \ - V(_, done_string, "done") \ - V(_, dot_brand_string, ".brand") \ - V(_, dot_catch_string, ".catch") \ - V(_, dot_default_string, ".default") \ - V(_, dot_for_string, ".for") \ - V(_, dot_generator_object_string, ".generator_object") \ - V(_, dot_home_object_string, ".home_object") \ - V(_, dot_result_string, ".result") \ - V(_, dot_repl_result_string, ".repl_result") \ - V(_, dot_static_home_object_string, "._static_home_object") \ - V(_, dot_string, ".") \ - V(_, dot_switch_tag_string, ".switch_tag") \ - V(_, dotAll_string, "dotAll") \ - V(_, enumerable_string, "enumerable") \ - V(_, element_string, "element") \ - V(_, Error_string, "Error") \ - V(_, errors_string, "errors") \ - V(_, error_to_string, "[object Error]") \ - V(_, eval_string, "eval") \ - V(_, EvalError_string, "EvalError") \ - V(_, exec_string, "exec") \ - V(_, false_string, "false") \ - V(_, FinalizationRegistry_string, "FinalizationRegistry") \ - V(_, flags_string, "flags") \ - V(_, Float32Array_string, "Float32Array") \ - V(_, Float64Array_string, "Float64Array") \ - V(_, from_string, "from") \ - V(_, Function_string, "Function") \ - V(_, function_native_code_string, "function () { [native code] }") \ - V(_, function_string, "function") \ - V(_, function_to_string, "[object Function]") \ - V(_, Generator_string, "Generator") \ - V(_, get_space_string, "get ") \ - V(_, get_string, "get") \ - V(_, getOwnPropertyDescriptor_string, "getOwnPropertyDescriptor") \ - V(_, getPrototypeOf_string, "getPrototypeOf") \ - V(_, global_string, "global") \ - V(_, globalThis_string, "globalThis") \ - V(_, groups_string, "groups") \ - V(_, has_string, "has") \ - V(_, has_indices_string, "hasIndices") \ - V(_, ignoreCase_string, "ignoreCase") \ - V(_, illegal_access_string, "illegal access") \ - V(_, illegal_argument_string, "illegal argument") \ - V(_, index_string, "index") \ - V(_, indices_string, "indices") \ - V(_, Infinity_string, "Infinity") \ - V(_, infinity_string, "infinity") \ - V(_, input_string, "input") \ - V(_, Int16Array_string, "Int16Array") \ - V(_, Int32Array_string, "Int32Array") \ - V(_, Int8Array_string, "Int8Array") \ - V(_, isExtensible_string, "isExtensible") \ - V(_, jsMemoryEstimate_string, "jsMemoryEstimate") \ - V(_, jsMemoryRange_string, "jsMemoryRange") \ - V(_, keys_string, "keys") \ - V(_, lastIndex_string, "lastIndex") \ - V(_, length_string, "length") \ - V(_, let_string, "let") \ - V(_, line_string, "line") \ - V(_, linear_string, "linear") \ - V(_, LinkError_string, "LinkError") \ - V(_, long_string, "long") \ - V(_, Map_string, "Map") \ - V(_, MapIterator_string, "Map Iterator") \ - V(_, medium_string, "medium") \ - V(_, message_string, "message") \ - V(_, meta_string, "meta") \ - V(_, minus_Infinity_string, "-Infinity") \ - V(_, Module_string, "Module") \ - V(_, multiline_string, "multiline") \ - V(_, name_string, "name") \ - V(_, NaN_string, "NaN") \ - V(_, narrow_string, "narrow") \ - V(_, native_string, "native") \ - V(_, new_target_string, ".new.target") \ - V(_, next_string, "next") \ - V(_, NFC_string, "NFC") \ - V(_, NFD_string, "NFD") \ - V(_, NFKC_string, "NFKC") \ - V(_, NFKD_string, "NFKD") \ - V(_, not_equal_string, "not-equal") \ - V(_, null_string, "null") \ - V(_, null_to_string, "[object Null]") \ - V(_, Number_string, "Number") \ - V(_, number_string, "number") \ - V(_, number_to_string, "[object Number]") \ - V(_, Object_string, "Object") \ - V(_, object_string, "object") \ - V(_, object_to_string, "[object Object]") \ - V(_, of_string, "of") \ - V(_, ok_string, "ok") \ - V(_, one_string, "1") \ - V(_, other_string, "other") \ - V(_, ownKeys_string, "ownKeys") \ - V(_, percent_string, "percent") \ - V(_, position_string, "position") \ - V(_, preventExtensions_string, "preventExtensions") \ - V(_, private_constructor_string, "#constructor") \ - V(_, Promise_string, "Promise") \ - V(_, proto_string, "__proto__") \ - V(_, prototype_string, "prototype") \ - V(_, proxy_string, "proxy") \ - V(_, Proxy_string, "Proxy") \ - V(_, query_colon_string, "(?:)") \ - V(_, RangeError_string, "RangeError") \ - V(_, raw_string, "raw") \ - V(_, ReferenceError_string, "ReferenceError") \ - V(_, ReflectGet_string, "Reflect.get") \ - V(_, ReflectHas_string, "Reflect.has") \ - V(_, RegExp_string, "RegExp") \ - V(_, regexp_to_string, "[object RegExp]") \ - V(_, resolve_string, "resolve") \ - V(_, return_string, "return") \ - V(_, revoke_string, "revoke") \ - V(_, RuntimeError_string, "RuntimeError") \ - V(_, Script_string, "Script") \ - V(_, script_string, "script") \ - V(_, short_string, "short") \ - V(_, Set_string, "Set") \ - V(_, sentence_string, "sentence") \ - V(_, set_space_string, "set ") \ - V(_, set_string, "set") \ - V(_, SetIterator_string, "Set Iterator") \ - V(_, setPrototypeOf_string, "setPrototypeOf") \ - V(_, SharedArrayBuffer_string, "SharedArrayBuffer") \ - V(_, source_string, "source") \ - V(_, sourceText_string, "sourceText") \ - V(_, stack_string, "stack") \ - V(_, stackTraceLimit_string, "stackTraceLimit") \ - V(_, sticky_string, "sticky") \ - V(_, String_string, "String") \ - V(_, string_string, "string") \ - V(_, string_to_string, "[object String]") \ - V(_, symbol_species_string, "[Symbol.species]") \ - V(_, Symbol_string, "Symbol") \ - V(_, symbol_string, "symbol") \ - V(_, SyntaxError_string, "SyntaxError") \ - V(_, target_string, "target") \ - V(_, then_string, "then") \ - V(_, this_function_string, ".this_function") \ - V(_, this_string, "this") \ - V(_, throw_string, "throw") \ - V(_, timed_out_string, "timed-out") \ - V(_, toJSON_string, "toJSON") \ - V(_, toString_string, "toString") \ - V(_, true_string, "true") \ - V(_, total_string, "total") \ - V(_, TypeError_string, "TypeError") \ - V(_, Uint16Array_string, "Uint16Array") \ - V(_, Uint32Array_string, "Uint32Array") \ - V(_, Uint8Array_string, "Uint8Array") \ - V(_, Uint8ClampedArray_string, "Uint8ClampedArray") \ - V(_, undefined_string, "undefined") \ - V(_, undefined_to_string, "[object Undefined]") \ - V(_, unicode_string, "unicode") \ - V(_, URIError_string, "URIError") \ - V(_, value_string, "value") \ - V(_, valueOf_string, "valueOf") \ - V(_, WeakMap_string, "WeakMap") \ - V(_, WeakRef_string, "WeakRef") \ - V(_, WeakSet_string, "WeakSet") \ - V(_, week_string, "week") \ - V(_, word_string, "word") \ - V(_, writable_string, "writable") \ +#define INTERNALIZED_STRING_LIST_GENERATOR(V, _) \ + INTERNALIZED_STRING_LIST_GENERATOR_INTL(V, _) \ + V(_, add_string, "add") \ + V(_, AggregateError_string, "AggregateError") \ + V(_, always_string, "always") \ + V(_, anonymous_function_string, "(anonymous function)") \ + V(_, anonymous_string, "anonymous") \ + V(_, apply_string, "apply") \ + V(_, Arguments_string, "Arguments") \ + V(_, arguments_string, "arguments") \ + V(_, arguments_to_string, "[object Arguments]") \ + V(_, Array_string, "Array") \ + V(_, array_to_string, "[object Array]") \ + V(_, ArrayBuffer_string, "ArrayBuffer") \ + V(_, ArrayIterator_string, "Array Iterator") \ + V(_, as_string, "as") \ + V(_, assert_string, "assert") \ + V(_, async_string, "async") \ + V(_, auto_string, "auto") \ + V(_, await_string, "await") \ + V(_, BigInt_string, "BigInt") \ + V(_, bigint_string, "bigint") \ + V(_, BigInt64Array_string, "BigInt64Array") \ + V(_, BigUint64Array_string, "BigUint64Array") \ + V(_, bind_string, "bind") \ + V(_, Boolean_string, "Boolean") \ + V(_, boolean_string, "boolean") \ + V(_, boolean_to_string, "[object Boolean]") \ + V(_, bound__string, "bound ") \ + V(_, buffer_string, "buffer") \ + V(_, byte_length_string, "byteLength") \ + V(_, byte_offset_string, "byteOffset") \ + V(_, CompileError_string, "CompileError") \ + V(_, callee_string, "callee") \ + V(_, caller_string, "caller") \ + V(_, cause_string, "cause") \ + V(_, character_string, "character") \ + V(_, closure_string, "(closure)") \ + V(_, code_string, "code") \ + V(_, column_string, "column") \ + V(_, computed_string, "") \ + V(_, configurable_string, "configurable") \ + V(_, conjunction_string, "conjunction") \ + V(_, construct_string, "construct") \ + V(_, constructor_string, "constructor") \ + V(_, current_string, "current") \ + V(_, Date_string, "Date") \ + V(_, date_to_string, "[object Date]") \ + V(_, default_string, "default") \ + V(_, defineProperty_string, "defineProperty") \ + V(_, deleteProperty_string, "deleteProperty") \ + V(_, disjunction_string, "disjunction") \ + V(_, done_string, "done") \ + V(_, dot_brand_string, ".brand") \ + V(_, dot_catch_string, ".catch") \ + V(_, dot_default_string, ".default") \ + V(_, dot_for_string, ".for") \ + V(_, dot_generator_object_string, ".generator_object") \ + V(_, dot_home_object_string, ".home_object") \ + V(_, dot_result_string, ".result") \ + V(_, dot_repl_result_string, ".repl_result") \ + V(_, dot_static_home_object_string, "._static_home_object") \ + V(_, dot_string, ".") \ + V(_, dot_switch_tag_string, ".switch_tag") \ + V(_, dotAll_string, "dotAll") \ + V(_, enumerable_string, "enumerable") \ + V(_, element_string, "element") \ + V(_, Error_string, "Error") \ + V(_, errors_string, "errors") \ + V(_, error_to_string, "[object Error]") \ + V(_, eval_string, "eval") \ + V(_, EvalError_string, "EvalError") \ + V(_, exec_string, "exec") \ + V(_, false_string, "false") \ + V(_, FinalizationRegistry_string, "FinalizationRegistry") \ + V(_, flags_string, "flags") \ + V(_, Float32Array_string, "Float32Array") \ + V(_, Float64Array_string, "Float64Array") \ + V(_, from_string, "from") \ + V(_, Function_string, "Function") \ + V(_, function_native_code_string, "function () { [native code] }") \ + V(_, function_string, "function") \ + V(_, function_to_string, "[object Function]") \ + V(_, Generator_string, "Generator") \ + V(_, get_space_string, "get ") \ + V(_, get_string, "get") \ + V(_, getOwnPropertyDescriptor_string, "getOwnPropertyDescriptor") \ + V(_, getPrototypeOf_string, "getPrototypeOf") \ + V(_, global_string, "global") \ + V(_, globalThis_string, "globalThis") \ + V(_, groups_string, "groups") \ + V(_, GrowableSharedArrayBuffer_string, "GrowableSharedArrayBuffer") \ + V(_, has_string, "has") \ + V(_, has_indices_string, "hasIndices") \ + V(_, ignoreCase_string, "ignoreCase") \ + V(_, illegal_access_string, "illegal access") \ + V(_, illegal_argument_string, "illegal argument") \ + V(_, index_string, "index") \ + V(_, indices_string, "indices") \ + V(_, Infinity_string, "Infinity") \ + V(_, infinity_string, "infinity") \ + V(_, input_string, "input") \ + V(_, Int16Array_string, "Int16Array") \ + V(_, Int32Array_string, "Int32Array") \ + V(_, Int8Array_string, "Int8Array") \ + V(_, isExtensible_string, "isExtensible") \ + V(_, jsMemoryEstimate_string, "jsMemoryEstimate") \ + V(_, jsMemoryRange_string, "jsMemoryRange") \ + V(_, keys_string, "keys") \ + V(_, lastIndex_string, "lastIndex") \ + V(_, length_string, "length") \ + V(_, let_string, "let") \ + V(_, line_string, "line") \ + V(_, linear_string, "linear") \ + V(_, LinkError_string, "LinkError") \ + V(_, long_string, "long") \ + V(_, Map_string, "Map") \ + V(_, MapIterator_string, "Map Iterator") \ + V(_, max_byte_length_string, "maxByteLength") \ + V(_, medium_string, "medium") \ + V(_, message_string, "message") \ + V(_, meta_string, "meta") \ + V(_, minus_Infinity_string, "-Infinity") \ + V(_, Module_string, "Module") \ + V(_, multiline_string, "multiline") \ + V(_, name_string, "name") \ + V(_, NaN_string, "NaN") \ + V(_, narrow_string, "narrow") \ + V(_, native_string, "native") \ + V(_, new_target_string, ".new.target") \ + V(_, next_string, "next") \ + V(_, NFC_string, "NFC") \ + V(_, NFD_string, "NFD") \ + V(_, NFKC_string, "NFKC") \ + V(_, NFKD_string, "NFKD") \ + V(_, not_equal_string, "not-equal") \ + V(_, null_string, "null") \ + V(_, null_to_string, "[object Null]") \ + V(_, Number_string, "Number") \ + V(_, number_string, "number") \ + V(_, number_to_string, "[object Number]") \ + V(_, Object_string, "Object") \ + V(_, object_string, "object") \ + V(_, object_to_string, "[object Object]") \ + V(_, of_string, "of") \ + V(_, ok_string, "ok") \ + V(_, one_string, "1") \ + V(_, other_string, "other") \ + V(_, ownKeys_string, "ownKeys") \ + V(_, percent_string, "percent") \ + V(_, position_string, "position") \ + V(_, preventExtensions_string, "preventExtensions") \ + V(_, private_constructor_string, "#constructor") \ + V(_, Promise_string, "Promise") \ + V(_, proto_string, "__proto__") \ + V(_, prototype_string, "prototype") \ + V(_, proxy_string, "proxy") \ + V(_, Proxy_string, "Proxy") \ + V(_, query_colon_string, "(?:)") \ + V(_, RangeError_string, "RangeError") \ + V(_, raw_string, "raw") \ + V(_, ReferenceError_string, "ReferenceError") \ + V(_, ReflectGet_string, "Reflect.get") \ + V(_, ReflectHas_string, "Reflect.has") \ + V(_, RegExp_string, "RegExp") \ + V(_, regexp_to_string, "[object RegExp]") \ + V(_, ResizableArrayBuffer_string, "ResizableArrayBuffer") \ + V(_, resolve_string, "resolve") \ + V(_, return_string, "return") \ + V(_, revoke_string, "revoke") \ + V(_, RuntimeError_string, "RuntimeError") \ + V(_, Script_string, "Script") \ + V(_, script_string, "script") \ + V(_, short_string, "short") \ + V(_, Set_string, "Set") \ + V(_, sentence_string, "sentence") \ + V(_, set_space_string, "set ") \ + V(_, set_string, "set") \ + V(_, SetIterator_string, "Set Iterator") \ + V(_, setPrototypeOf_string, "setPrototypeOf") \ + V(_, SharedArrayBuffer_string, "SharedArrayBuffer") \ + V(_, source_string, "source") \ + V(_, sourceText_string, "sourceText") \ + V(_, stack_string, "stack") \ + V(_, stackTraceLimit_string, "stackTraceLimit") \ + V(_, sticky_string, "sticky") \ + V(_, String_string, "String") \ + V(_, string_string, "string") \ + V(_, string_to_string, "[object String]") \ + V(_, symbol_species_string, "[Symbol.species]") \ + V(_, Symbol_string, "Symbol") \ + V(_, symbol_string, "symbol") \ + V(_, SyntaxError_string, "SyntaxError") \ + V(_, target_string, "target") \ + V(_, then_string, "then") \ + V(_, this_function_string, ".this_function") \ + V(_, this_string, "this") \ + V(_, throw_string, "throw") \ + V(_, timed_out_string, "timed-out") \ + V(_, toJSON_string, "toJSON") \ + V(_, toString_string, "toString") \ + V(_, true_string, "true") \ + V(_, total_string, "total") \ + V(_, TypeError_string, "TypeError") \ + V(_, Uint16Array_string, "Uint16Array") \ + V(_, Uint32Array_string, "Uint32Array") \ + V(_, Uint8Array_string, "Uint8Array") \ + V(_, Uint8ClampedArray_string, "Uint8ClampedArray") \ + V(_, undefined_string, "undefined") \ + V(_, undefined_to_string, "[object Undefined]") \ + V(_, unicode_string, "unicode") \ + V(_, URIError_string, "URIError") \ + V(_, value_string, "value") \ + V(_, valueOf_string, "valueOf") \ + V(_, WeakMap_string, "WeakMap") \ + V(_, WeakRef_string, "WeakRef") \ + V(_, WeakSet_string, "WeakSet") \ + V(_, week_string, "week") \ + V(_, word_string, "word") \ + V(_, writable_string, "writable") \ V(_, zero_string, "0") #define PRIVATE_SYMBOL_LIST_GENERATOR(V, _) \ diff --git a/src/objects/allocation-site.h b/src/objects/allocation-site.h index 6e842d56c6..549e82a4da 100644 --- a/src/objects/allocation-site.h +++ b/src/objects/allocation-site.h @@ -70,9 +70,9 @@ class AllocationSite : public Struct { bool IsNested(); // transition_info bitfields, for constructed array transition info. - using ElementsKindBits = base::BitField; - using DoNotInlineBit = base::BitField; - // Unused bits 6-30. + using ElementsKindBits = base::BitField; + using DoNotInlineBit = base::BitField; + // Unused bits 7-30. // Bitfields for pretenure_data using MementoFoundCountBits = base::BitField; diff --git a/src/objects/backing-store.cc b/src/objects/backing-store.cc index 08288ef62c..37a89d471c 100644 --- a/src/objects/backing-store.cc +++ b/src/objects/backing-store.cc @@ -160,6 +160,8 @@ BackingStore::~BackingStore() { #if V8_ENABLE_WEBASSEMBLY if (is_wasm_memory_) { + // TODO(v8:11111): RAB / GSAB - Wasm integration. + DCHECK(!is_resizable_); DCHECK(free_on_destruct_); DCHECK(!custom_deleter_); size_t reservation_size = @@ -189,6 +191,23 @@ BackingStore::~BackingStore() { } #endif // V8_ENABLE_WEBASSEMBLY + if (is_resizable_) { + DCHECK(free_on_destruct_); + DCHECK(!custom_deleter_); + size_t reservation_size = + GetReservationSize(has_guard_regions_, byte_capacity_); + auto region = + GetReservedRegion(has_guard_regions_, buffer_start_, byte_capacity_); + + bool pages_were_freed = + region.size() == 0 /* no need to free any pages */ || + FreePages(GetPlatformPageAllocator(), + reinterpret_cast(region.begin()), region.size()); + CHECK(pages_were_freed); + BackingStore::ReleaseReservation(reservation_size); + Clear(); + return; + } if (custom_deleter_) { DCHECK(free_on_destruct_); TRACE_BS("BS:custom deleter bs=%p mem=%p (length=%zu, capacity=%zu)\n", @@ -252,15 +271,16 @@ std::unique_ptr BackingStore::Allocate( } } - auto result = new BackingStore(buffer_start, // start - byte_length, // length - byte_length, // capacity - shared, // shared - false, // is_wasm_memory - true, // free_on_destruct - false, // has_guard_regions - false, // custom_deleter - false); // empty_deleter + auto result = new BackingStore(buffer_start, // start + byte_length, // length + byte_length, // capacity + shared, // shared + ResizableFlag::kNotResizable, // resizable + false, // is_wasm_memory + true, // free_on_destruct + false, // has_guard_regions + false, // custom_deleter + false); // empty_deleter TRACE_BS("BS:alloc bs=%p mem=%p (length=%zu)\n", result, result->buffer_start(), byte_length); @@ -305,12 +325,37 @@ void BackingStore::ReleaseReservation(uint64_t num_bytes) { std::unique_ptr BackingStore::TryAllocateWasmMemory( Isolate* isolate, size_t initial_pages, size_t maximum_pages, SharedFlag shared) { + // Compute size of reserved memory. + size_t engine_max_pages = wasm::max_mem_pages(); + maximum_pages = std::min(engine_max_pages, maximum_pages); + + auto result = TryAllocateAndPartiallyCommitMemory( + isolate, initial_pages * wasm::kWasmPageSize, wasm::kWasmPageSize, + initial_pages, maximum_pages, true, shared); + // Shared Wasm memories need an anchor for the memory object list. + if (result && shared == SharedFlag::kShared) { + result->type_specific_data_.shared_wasm_memory_data = + new SharedWasmMemoryData(); + } + return result; +} +#endif // V8_ENABLE_WEBASSEMBLY + +std::unique_ptr BackingStore::TryAllocateAndPartiallyCommitMemory( + Isolate* isolate, size_t byte_length, size_t page_size, + size_t initial_pages, size_t maximum_pages, bool is_wasm_memory, + SharedFlag shared) { + // Enforce engine limitation on the maximum number of pages. + if (maximum_pages > std::numeric_limits::max() / page_size) { + return nullptr; + } + // Cannot reserve 0 pages on some OSes. if (maximum_pages == 0) maximum_pages = 1; TRACE_BS("BSw:try %zu pages, %zu max\n", initial_pages, maximum_pages); - bool guards = trap_handler::IsTrapHandlerEnabled(); + bool guards = is_wasm_memory && trap_handler::IsTrapHandlerEnabled(); // For accounting purposes, whether a GC was necessary. bool did_retry = false; @@ -329,16 +374,7 @@ std::unique_ptr BackingStore::TryAllocateWasmMemory( return false; }; - // Compute size of reserved memory. - - size_t engine_max_pages = wasm::max_mem_pages(); - maximum_pages = std::min(engine_max_pages, maximum_pages); - // If the platform doesn't support so many pages, attempting to allocate - // is guaranteed to fail, so we don't even try. - if (maximum_pages > kPlatformMaxPages) return {}; - CHECK_LE(maximum_pages, - std::numeric_limits::max() / wasm::kWasmPageSize); - size_t byte_capacity = maximum_pages * wasm::kWasmPageSize; + size_t byte_capacity = maximum_pages * page_size; size_t reservation_size = GetReservationSize(guards, byte_capacity); //-------------------------------------------------------------------------- @@ -366,7 +402,7 @@ std::unique_ptr BackingStore::TryAllocateWasmMemory( auto allocate_pages = [&] { allocation_base = AllocatePages(GetPlatformPageAllocator(), nullptr, reservation_size, - wasm::kWasmPageSize, PageAllocator::kNoAccess); + page_size, PageAllocator::kNoAccess); return allocation_base != nullptr; }; if (!gc_retry(allocate_pages)) { @@ -385,17 +421,17 @@ std::unique_ptr BackingStore::TryAllocateWasmMemory( //-------------------------------------------------------------------------- // 3. Commit the initial pages (allow read/write). //-------------------------------------------------------------------------- - size_t byte_length = initial_pages * wasm::kWasmPageSize; + size_t committed_byte_length = initial_pages * page_size; auto commit_memory = [&] { - return byte_length == 0 || - SetPermissions(GetPlatformPageAllocator(), buffer_start, byte_length, - PageAllocator::kReadWrite); + return committed_byte_length == 0 || + SetPermissions(GetPlatformPageAllocator(), buffer_start, + committed_byte_length, PageAllocator::kReadWrite); }; if (!gc_retry(commit_memory)) { TRACE_BS("BSw:try failed to set permissions (%p, %zu)\n", buffer_start, - byte_length); + committed_byte_length); // SetPermissions put us over the process memory limit. - V8::FatalProcessOutOfMemory(nullptr, "BackingStore::AllocateWasmMemory()"); + V8::FatalProcessOutOfMemory(nullptr, "BackingStore::AllocateMemory()"); } DebugCheckZero(buffer_start, byte_length); // touch the bytes. @@ -403,30 +439,29 @@ std::unique_ptr BackingStore::TryAllocateWasmMemory( RecordStatus(isolate, did_retry ? AllocationStatus::kSuccessAfterRetry : AllocationStatus::kSuccess); - auto result = new BackingStore(buffer_start, // start - byte_length, // length - byte_capacity, // capacity - shared, // shared - true, // is_wasm_memory - true, // free_on_destruct - guards, // has_guard_regions - false, // custom_deleter - false); // empty_deleter + ResizableFlag resizable = + is_wasm_memory ? ResizableFlag::kNotResizable : ResizableFlag::kResizable; + + auto result = new BackingStore(buffer_start, // start + byte_length, // length + byte_capacity, // capacity + shared, // shared + resizable, // resizable + is_wasm_memory, // is_wasm_memory + true, // free_on_destruct + guards, // has_guard_regions + false, // custom_deleter + false); // empty_deleter TRACE_BS( "BSw:alloc bs=%p mem=%p (length=%zu, capacity=%zu, reservation=%zu)\n", result, result->buffer_start(), byte_length, byte_capacity, reservation_size); - // Shared Wasm memories need an anchor for the memory object list. - if (shared == SharedFlag::kShared) { - result->type_specific_data_.shared_wasm_memory_data = - new SharedWasmMemoryData(); - } - return std::unique_ptr(result); } +#if V8_ENABLE_WEBASSEMBLY // Allocate a backing store for a Wasm memory. Always use the page allocator // and add guard regions. std::unique_ptr BackingStore::AllocateWasmMemory( @@ -583,18 +618,83 @@ void BackingStore::UpdateSharedWasmMemoryObjects(Isolate* isolate) { } #endif // V8_ENABLE_WEBASSEMBLY +// Commit already reserved memory. +bool BackingStore::ResizeInPlace(Isolate* isolate, size_t new_byte_length, + size_t new_committed_length, + bool allow_shrinking) { + DCHECK_LE(new_byte_length, new_committed_length); + // See comment in GrowWasmMemoryInPlace. + // GrowableSharedArrayBuffer.prototype.grow can be called from several + // threads. If two threads try to grow() in a racy way, the spec allows the + // larger grow to throw also if the smaller grow succeeds first. The + // implementation below doesn't throw in that case - instead, it retries and + // succeeds. If the larger grow finishes first though, the smaller grow must + // throw. + size_t old_byte_length = byte_length_.load(std::memory_order_seq_cst); + while (true) { + if (new_byte_length < old_byte_length) { + // TOOO(v8:11111): Figure out a strategy for shrinking - when do we + // un-commit the memory? + if (allow_shrinking) { + // This branch is only relevant for RABs and they are not shared between + // threads. + DCHECK(!is_shared()); + + // Zero the memory so that in case the buffer is grown later, we have + // zeroed the contents already. + memset(reinterpret_cast(buffer_start_) + new_byte_length, 0, + old_byte_length - new_byte_length); + + // Changing the byte length wouldn't strictly speaking be needed, since + // the JSArrayBuffer already stores the updated length. This is to keep + // the BackingStore and JSArrayBuffer in sync. + byte_length_ = new_byte_length; + return true; + } + return false; + } + if (new_byte_length == 0) { + DCHECK_EQ(0, old_byte_length); + // i::SetPermissions with size 0 fails on some platforms. + return true; + } + + // Try to adjust the permissions on the memory. + if (!i::SetPermissions(GetPlatformPageAllocator(), buffer_start_, + new_committed_length, PageAllocator::kReadWrite)) { + return false; + } + + // compare_exchange_weak updates old_byte_length. + if (byte_length_.compare_exchange_weak(old_byte_length, new_byte_length, + std::memory_order_seq_cst)) { + // Successfully updated both the length and permissions. + break; + } + } + DCHECK(free_on_destruct_); + if (!is_shared_) { + // Only do per-isolate accounting for non-shared backing stores. + reinterpret_cast(isolate) + ->AdjustAmountOfExternalAllocatedMemory(new_byte_length - + old_byte_length); + } + return true; +} + std::unique_ptr BackingStore::WrapAllocation( Isolate* isolate, void* allocation_base, size_t allocation_length, SharedFlag shared, bool free_on_destruct) { - 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 - false); // empty_deleter + auto result = new BackingStore(allocation_base, // start + allocation_length, // length + allocation_length, // capacity + shared, // shared + ResizableFlag::kNotResizable, // resizable + false, // is_wasm_memory + free_on_destruct, // free_on_destruct + false, // has_guard_regions + false, // custom_deleter + false); // empty_deleter result->SetAllocatorFromIsolate(isolate); TRACE_BS("BS:wrap bs=%p mem=%p (length=%zu)\n", result, result->buffer_start(), result->byte_length()); @@ -606,10 +706,11 @@ std::unique_ptr BackingStore::WrapAllocation( v8::BackingStore::DeleterCallback deleter, void* deleter_data, SharedFlag shared) { bool is_empty_deleter = (deleter == v8::BackingStore::EmptyDeleter); - auto result = new BackingStore(allocation_base, // start - allocation_length, // length - allocation_length, // capacity - shared, // shared + auto result = new BackingStore(allocation_base, // start + allocation_length, // length + allocation_length, // capacity + shared, // shared + ResizableFlag::kNotResizable, // resizable false, // is_wasm_memory true, // free_on_destruct false, // has_guard_regions @@ -623,15 +724,16 @@ std::unique_ptr BackingStore::WrapAllocation( std::unique_ptr BackingStore::EmptyBackingStore( SharedFlag shared) { - auto result = new BackingStore(nullptr, // start - 0, // length - 0, // capacity - shared, // shared - false, // is_wasm_memory - true, // free_on_destruct - false, // has_guard_regions - false, // custom_deleter - false); // empty_deleter + auto result = new BackingStore(nullptr, // start + 0, // length + 0, // capacity + shared, // shared + ResizableFlag::kNotResizable, // resizable + false, // is_wasm_memory + true, // free_on_destruct + false, // has_guard_regions + false, // custom_deleter + false); // empty_deleter return std::unique_ptr(result); } diff --git a/src/objects/backing-store.h b/src/objects/backing-store.h index eb879d5e8a..bf9e712d2a 100644 --- a/src/objects/backing-store.h +++ b/src/objects/backing-store.h @@ -21,6 +21,9 @@ class WasmMemoryObject; // Whether the backing store is shared or not. enum class SharedFlag : uint8_t { kNotShared, kShared }; +// Whether the backing store is resizable or not. +enum class ResizableFlag : uint8_t { kNotResizable, kResizable }; + // Whether the backing store memory is initialied to zero or not. enum class InitializedFlag : uint8_t { kUninitialized, kZeroInitialized }; @@ -56,6 +59,12 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase { SharedFlag shared); #endif // V8_ENABLE_WEBASSEMBLY + // Tries to allocate `maximum_pages` of memory and commit `initial_pages`. + static std::unique_ptr TryAllocateAndPartiallyCommitMemory( + Isolate* isolate, size_t byte_length, size_t page_size, + size_t initial_pages, size_t maximum_pages, bool is_wasm_memory, + SharedFlag shared); + // Create a backing store that wraps existing allocated memory. // If {free_on_destruct} is {true}, the memory will be freed using the // ArrayBufferAllocator::Free() callback when this backing store is @@ -77,15 +86,20 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase { // Accessors. void* buffer_start() const { return buffer_start_; } - size_t byte_length() const { - return byte_length_.load(std::memory_order_relaxed); + size_t byte_length( + std::memory_order memory_order = std::memory_order_relaxed) const { + return byte_length_.load(memory_order); } size_t byte_capacity() const { return byte_capacity_; } bool is_shared() const { return is_shared_; } + bool is_resizable() const { return is_resizable_; } bool is_wasm_memory() const { return is_wasm_memory_; } bool has_guard_regions() const { return has_guard_regions_; } bool free_on_destruct() const { return free_on_destruct_; } + bool ResizeInPlace(Isolate* isolate, size_t new_byte_length, + size_t new_committed_length, bool allow_shrinking); + // Wrapper around ArrayBuffer::Allocator::Reallocate. bool Reallocate(Isolate* isolate, size_t new_byte_length); @@ -148,19 +162,26 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase { friend class GlobalBackingStoreRegistry; 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 custom_deleter, bool empty_deleter) + SharedFlag shared, ResizableFlag resizable, bool is_wasm_memory, + bool free_on_destruct, bool has_guard_regions, + bool custom_deleter, bool empty_deleter) : buffer_start_(buffer_start), byte_length_(byte_length), byte_capacity_(byte_capacity), is_shared_(shared == SharedFlag::kShared), + is_resizable_(resizable == ResizableFlag::kResizable), is_wasm_memory_(is_wasm_memory), holds_shared_ptr_to_allocator_(false), free_on_destruct_(free_on_destruct), has_guard_regions_(has_guard_regions), globally_registered_(false), custom_deleter_(custom_deleter), - empty_deleter_(empty_deleter) {} + empty_deleter_(empty_deleter) { + // TODO(v8:11111): RAB / GSAB - Wasm integration. + DCHECK_IMPLIES(is_wasm_memory_, !is_resizable_); + DCHECK_IMPLIES(is_resizable_, !custom_deleter_); + DCHECK_IMPLIES(is_resizable_, free_on_destruct_); + } BackingStore(const BackingStore&) = delete; BackingStore& operator=(const BackingStore&) = delete; void SetAllocatorFromIsolate(Isolate* isolate); @@ -199,6 +220,8 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase { } type_specific_data_; bool is_shared_ : 1; + // Backing stores for (Resizable|GrowableShared)ArrayBuffer + bool is_resizable_ : 1; bool is_wasm_memory_ : 1; bool holds_shared_ptr_to_allocator_ : 1; bool free_on_destruct_ : 1; diff --git a/src/objects/contexts.h b/src/objects/contexts.h index d801f6f4a3..427675e102 100644 --- a/src/objects/contexts.h +++ b/src/objects/contexts.h @@ -112,6 +112,8 @@ enum ContextLookupFlags { V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \ V(ASYNC_GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \ async_generator_object_prototype_map) \ + V(GROWABLE_SHARED_ARRAY_BUFFER_FUN_INDEX, JSFunction, \ + growable_shared_array_buffer_fun) \ V(INITIAL_ARRAY_ITERATOR_MAP_INDEX, Map, initial_array_iterator_map) \ V(INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX, JSObject, \ initial_array_iterator_prototype) \ @@ -210,6 +212,18 @@ enum ContextLookupFlags { V(PROXY_MAP_INDEX, Map, proxy_map) \ V(PROXY_REVOCABLE_RESULT_MAP_INDEX, Map, proxy_revocable_result_map) \ V(PROMISE_PROTOTYPE_INDEX, JSObject, promise_prototype) \ + V(RAB_GSAB_UINT8_ARRAY_MAP_INDEX, Map, rab_gsab_uint8_array_map) \ + V(RAB_GSAB_INT8_ARRAY_MAP_INDEX, Map, rab_gsab_int8_array_map) \ + V(RAB_GSAB_UINT16_ARRAY_MAP_INDEX, Map, rab_gsab_uint16_array_map) \ + V(RAB_GSAB_INT16_ARRAY_MAP_INDEX, Map, rab_gsab_int16_array_map) \ + V(RAB_GSAB_UINT32_ARRAY_MAP_INDEX, Map, rab_gsab_uint32_array_map) \ + V(RAB_GSAB_INT32_ARRAY_MAP_INDEX, Map, rab_gsab_int32_array_map) \ + V(RAB_GSAB_FLOAT32_ARRAY_MAP_INDEX, Map, rab_gsab_float32_array_map) \ + V(RAB_GSAB_FLOAT64_ARRAY_MAP_INDEX, Map, rab_gsab_float64_array_map) \ + V(RAB_GSAB_UINT8_CLAMPED_ARRAY_MAP_INDEX, Map, \ + rab_gsab_uint8_clamped_array_map) \ + V(RAB_GSAB_BIGUINT64_ARRAY_MAP_INDEX, Map, rab_gsab_biguint64_array_map) \ + V(RAB_GSAB_BIGINT64_ARRAY_MAP_INDEX, Map, rab_gsab_bigint64_array_map) \ V(RECORDER_CONTEXT_ID, Object, recorder_context_id) \ V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ @@ -226,6 +240,7 @@ enum ContextLookupFlags { V(REGEXP_SPLIT_FUNCTION_INDEX, JSFunction, regexp_split_function) \ V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \ initial_regexp_string_iterator_prototype_map) \ + V(RESIZABLE_ARRAY_BUFFER_FUN_INDEX, JSFunction, resizable_array_buffer_fun) \ V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \ V(SCRIPT_EXECUTION_CALLBACK_INDEX, Object, script_execution_callback) \ V(SECURITY_TOKEN_INDEX, Object, security_token) \ diff --git a/src/objects/contexts.tq b/src/objects/contexts.tq index 99eb178021..b73644ebad 100644 --- a/src/objects/contexts.tq +++ b/src/objects/contexts.tq @@ -120,6 +120,30 @@ extern enum ContextSlot extends intptr constexpr 'Context::Field' { FUNCTION_CONTEXT_MAP_INDEX: Slot, FUNCTION_PROTOTYPE_APPLY_INDEX: Slot, + UINT8_ARRAY_FUN_INDEX: Slot, + INT8_ARRAY_FUN_INDEX: Slot, + UINT16_ARRAY_FUN_INDEX: Slot, + INT16_ARRAY_FUN_INDEX: Slot, + UINT32_ARRAY_FUN_INDEX: Slot, + INT32_ARRAY_FUN_INDEX: Slot, + FLOAT32_ARRAY_FUN_INDEX: Slot, + FLOAT64_ARRAY_FUN_INDEX: Slot, + UINT8_CLAMPED_ARRAY_FUN_INDEX: Slot, + BIGUINT64_ARRAY_FUN_INDEX: Slot, + BIGINT64_ARRAY_FUN_INDEX: Slot, + + RAB_GSAB_UINT8_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_INT8_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_UINT16_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_INT16_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_UINT32_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_INT32_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_FLOAT32_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_FLOAT64_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_UINT8_CLAMPED_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_BIGUINT64_ARRAY_MAP_INDEX: Slot, + RAB_GSAB_BIGINT64_ARRAY_MAP_INDEX: Slot, + PROMISE_FUNCTION_INDEX: Slot, PROMISE_THEN_INDEX: Slot, PROMISE_PROTOTYPE_INDEX: Slot, diff --git a/src/objects/elements-kind.cc b/src/objects/elements-kind.cc index 78670f25bd..6ffa34b868 100644 --- a/src/objects/elements-kind.cc +++ b/src/objects/elements-kind.cc @@ -17,19 +17,30 @@ int ElementsKindToShiftSize(ElementsKind elements_kind) { case UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: + case RAB_GSAB_UINT8_ELEMENTS: + case RAB_GSAB_INT8_ELEMENTS: + case RAB_GSAB_UINT8_CLAMPED_ELEMENTS: return 0; case UINT16_ELEMENTS: case INT16_ELEMENTS: + case RAB_GSAB_UINT16_ELEMENTS: + case RAB_GSAB_INT16_ELEMENTS: return 1; case UINT32_ELEMENTS: case INT32_ELEMENTS: case FLOAT32_ELEMENTS: + case RAB_GSAB_UINT32_ELEMENTS: + case RAB_GSAB_INT32_ELEMENTS: + case RAB_GSAB_FLOAT32_ELEMENTS: return 2; case PACKED_DOUBLE_ELEMENTS: case HOLEY_DOUBLE_ELEMENTS: case FLOAT64_ELEMENTS: case BIGINT64_ELEMENTS: case BIGUINT64_ELEMENTS: + case RAB_GSAB_FLOAT64_ELEMENTS: + case RAB_GSAB_BIGINT64_ELEMENTS: + case RAB_GSAB_BIGUINT64_ELEMENTS: return 3; case PACKED_SMI_ELEMENTS: case PACKED_ELEMENTS: @@ -109,6 +120,7 @@ const char* ElementsKindToString(ElementsKind kind) { return #TYPE "ELEMENTS"; TYPED_ARRAYS(PRINT_NAME); + RAB_GSAB_TYPED_ARRAYS(PRINT_NAME); #undef PRINT_NAME case NO_ELEMENTS: return "NO_ELEMENTS"; diff --git a/src/objects/elements-kind.h b/src/objects/elements-kind.h index ec3ca3402d..b19e21136f 100644 --- a/src/objects/elements-kind.h +++ b/src/objects/elements-kind.h @@ -28,6 +28,36 @@ namespace internal { V(BigUint64, biguint64, BIGUINT64, uint64_t) \ V(BigInt64, bigint64, BIGINT64, int64_t) +#define RAB_GSAB_TYPED_ARRAYS(V) \ + V(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8, uint8_t) \ + V(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8, int8_t) \ + V(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16, uint16_t) \ + V(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16, int16_t) \ + V(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32, uint32_t) \ + V(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32, int32_t) \ + V(RabGsabFloat32, rab_gsab_float32, RAB_GSAB_FLOAT32, float) \ + V(RabGsabFloat64, rab_gsab_float64, RAB_GSAB_FLOAT64, double) \ + V(RabGsabUint8Clamped, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, \ + uint8_t) \ + V(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t) \ + V(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64, int64_t) + +// The TypedArrays backed by RAB / GSAB are called Uint8Array, Uint16Array etc, +// and not RabGsabUint8Array, RabGsabUint16Array etc. This macro is used for +// generating code which refers to the TypedArray type. +#define RAB_GSAB_TYPED_ARRAYS_WITH_TYPED_ARRAY_TYPE(V) \ + V(Uint8, rab_gsab_uint8, RAB_GSAB_UINT8, uint8_t) \ + V(Int8, rab_gsab_int8, RAB_GSAB_INT8, int8_t) \ + V(Uint16, rab_gsab_uint16, RAB_GSAB_UINT16, uint16_t) \ + V(Int16, rab_gsab_int16, RAB_GSAB_INT16, int16_t) \ + V(Uint32, rab_gsab_uint32, RAB_GSAB_UINT32, uint32_t) \ + V(Int32, rab_gsab_int32, RAB_GSAB_INT32, int32_t) \ + V(Float32, rab_gsab_float32, RAB_GSAB_FLOAT32, float) \ + V(Float64, rab_gsab_float64, RAB_GSAB_FLOAT64, double) \ + V(Uint8Clamped, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) \ + V(BigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t) \ + V(BigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64, int64_t) + enum ElementsKind : uint8_t { // The "fast" kind for elements that only contain SMI values. Must be first // to make it possible to efficiently check maps for this kind. @@ -71,6 +101,7 @@ enum ElementsKind : uint8_t { // Fixed typed arrays. #define TYPED_ARRAY_ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS, TYPED_ARRAYS(TYPED_ARRAY_ELEMENTS_KIND) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_ELEMENTS_KIND) #undef TYPED_ARRAY_ELEMENTS_KIND // Sentinel ElementsKind for objects with no elements. @@ -78,11 +109,13 @@ enum ElementsKind : uint8_t { // Derived constants from ElementsKind. FIRST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS, - LAST_ELEMENTS_KIND = BIGINT64_ELEMENTS, + LAST_ELEMENTS_KIND = RAB_GSAB_BIGINT64_ELEMENTS, FIRST_FAST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS, LAST_FAST_ELEMENTS_KIND = HOLEY_DOUBLE_ELEMENTS, FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = BIGINT64_ELEMENTS, + FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND = RAB_GSAB_UINT8_ELEMENTS, + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND = RAB_GSAB_BIGINT64_ELEMENTS, TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS, FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = PACKED_NONEXTENSIBLE_ELEMENTS, LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = HOLEY_FROZEN_ELEMENTS, @@ -103,7 +136,7 @@ constexpr int kFastElementsKindCount = constexpr int kFastElementsKindPackedToHoley = HOLEY_SMI_ELEMENTS - PACKED_SMI_ELEMENTS; -constexpr int kElementsKindBits = 5; +constexpr int kElementsKindBits = 6; STATIC_ASSERT((1 << kElementsKindBits) > LAST_ELEMENTS_KIND); STATIC_ASSERT((1 << (kElementsKindBits - 1)) <= LAST_ELEMENTS_KIND); @@ -150,8 +183,20 @@ inline bool IsTypedArrayElementsKind(ElementsKind kind) { LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); } +inline bool IsRabGsabTypedArrayElementsKind(ElementsKind kind) { + return base::IsInRange(kind, FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND, + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND); +} + +inline bool IsTypedArrayOrRabGsabTypedArrayElementsKind(ElementsKind kind) { + return base::IsInRange(kind, FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, + LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND); +} + inline bool IsTerminalElementsKind(ElementsKind kind) { - return kind == TERMINAL_FAST_ELEMENTS_KIND || IsTypedArrayElementsKind(kind); + return kind == TERMINAL_FAST_ELEMENTS_KIND || + IsTypedArrayElementsKind(kind) || + IsRabGsabTypedArrayElementsKind(kind); } inline bool IsFastElementsKind(ElementsKind kind) { @@ -281,6 +326,13 @@ inline ElementsKind GetHoleyElementsKind(ElementsKind packed_kind) { return packed_kind; } +inline ElementsKind GetCorrespondingRabGsabElementsKind( + ElementsKind typed_array_kind) { + DCHECK(IsTypedArrayElementsKind(typed_array_kind)); + return ElementsKind(typed_array_kind - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + + FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND); +} + inline bool UnionElementsKindUptoPackedness(ElementsKind* a_out, ElementsKind b) { // Assert that the union of two ElementKinds can be computed via std::max. diff --git a/src/objects/elements.cc b/src/objects/elements.cc index 6e8e539ff8..79ea0ac495 100644 --- a/src/objects/elements.cc +++ b/src/objects/elements.cc @@ -59,6 +59,17 @@ // - Uint8ClampedElementsAccessor // - BigUint64ElementsAccessor // - BigInt64ElementsAccessor +// - RabGsabUint8ElementsAccessor +// - RabGsabInt8ElementsAccessor +// - RabGsabUint16ElementsAccessor +// - RabGsabInt16ElementsAccessor +// - RabGsabUint32ElementsAccessor +// - RabGsabInt32ElementsAccessor +// - RabGsabFloat32ElementsAccessor +// - RabGsabFloat64ElementsAccessor +// - RabGsabUint8ClampedElementsAccessor +// - RabGsabBigUint64ElementsAccessor +// - RabGsabBigInt64ElementsAccessor // - DictionaryElementsAccessor // - SloppyArgumentsElementsAccessor // - FastSloppyArgumentsElementsAccessor @@ -129,7 +140,19 @@ enum Where { AT_START, AT_END }; V(Float64ElementsAccessor, FLOAT64_ELEMENTS, ByteArray) \ V(Uint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, ByteArray) \ V(BigUint64ElementsAccessor, BIGUINT64_ELEMENTS, ByteArray) \ - V(BigInt64ElementsAccessor, BIGINT64_ELEMENTS, ByteArray) + V(BigInt64ElementsAccessor, BIGINT64_ELEMENTS, ByteArray) \ + V(RabGsabUint8ElementsAccessor, RAB_GSAB_UINT8_ELEMENTS, ByteArray) \ + V(RabGsabInt8ElementsAccessor, RAB_GSAB_INT8_ELEMENTS, ByteArray) \ + V(RabGsabUint16ElementsAccessor, RAB_GSAB_UINT16_ELEMENTS, ByteArray) \ + V(RabGsabInt16ElementsAccessor, RAB_GSAB_INT16_ELEMENTS, ByteArray) \ + V(RabGsabUint32ElementsAccessor, RAB_GSAB_UINT32_ELEMENTS, ByteArray) \ + V(RabGsabInt32ElementsAccessor, RAB_GSAB_INT32_ELEMENTS, ByteArray) \ + V(RabGsabFloat32ElementsAccessor, RAB_GSAB_FLOAT32_ELEMENTS, ByteArray) \ + V(RabGsabFloat64ElementsAccessor, RAB_GSAB_FLOAT64_ELEMENTS, ByteArray) \ + V(RabGsabUint8ClampedElementsAccessor, RAB_GSAB_UINT8_CLAMPED_ELEMENTS, \ + ByteArray) \ + V(RabGsabBigUint64ElementsAccessor, RAB_GSAB_BIGUINT64_ELEMENTS, ByteArray) \ + V(RabGsabBigInt64ElementsAccessor, RAB_GSAB_BIGINT64_ELEMENTS, ByteArray) template class ElementsKindTraits { @@ -2520,6 +2543,7 @@ class FastSmiOrObjectElementsAccessor case SLOW_STRING_WRAPPER_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE // This function is currently only used for JSArrays with non-zero // length. @@ -2935,6 +2959,7 @@ class FastDoubleElementsAccessor case NO_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE // This function is currently only used for JSArrays with non-zero // length. @@ -3056,7 +3081,7 @@ class TypedElementsAccessor static void SetImpl(Handle holder, InternalIndex entry, Object value) { Handle typed_array = Handle::cast(holder); - DCHECK_LE(entry.raw_value(), typed_array->length()); + DCHECK_LE(entry.raw_value(), typed_array->GetLength()); SetImpl(static_cast(typed_array->DataPtr()), entry.raw_value(), FromObject(value)); } @@ -3108,7 +3133,7 @@ class TypedElementsAccessor InternalIndex entry) { Handle typed_array = Handle::cast(holder); Isolate* isolate = typed_array->GetIsolate(); - DCHECK_LE(entry.raw_value(), typed_array->length()); + DCHECK_LT(entry.raw_value(), typed_array->GetLength()); DCHECK(!typed_array->WasDetached()); ElementType elem = GetImpl( static_cast(typed_array->DataPtr()), entry.raw_value()); @@ -3208,8 +3233,7 @@ class TypedElementsAccessor static size_t GetCapacityImpl(JSObject holder, FixedArrayBase backing_store) { JSTypedArray typed_array = JSTypedArray::cast(holder); - if (typed_array.WasDetached()) return 0; - return typed_array.length(); + return typed_array.GetLength(); } static size_t NumberOfElementsImpl(JSObject receiver, @@ -3970,9 +3994,225 @@ Handle TypedElementsAccessor::ToHandle( return BigInt::FromUint64(isolate, value); } +// static +template <> +Handle TypedElementsAccessor::ToHandle( + Isolate* isolate, int8_t value) { + return handle(Smi::FromInt(value), isolate); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + uint8_t value) { + return handle(Smi::FromInt(value), isolate); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + int16_t value) { + return handle(Smi::FromInt(value), isolate); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + uint16_t value) { + return handle(Smi::FromInt(value), isolate); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + int32_t value) { + return isolate->factory()->NewNumberFromInt(value); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + uint32_t value) { + return isolate->factory()->NewNumberFromUint(value); +} + +// static +template <> +float TypedElementsAccessor::FromScalar( + double value) { + return DoubleToFloat32(value); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + float value) { + return isolate->factory()->NewNumber(value); +} + +// static +template <> +double TypedElementsAccessor::FromScalar( + double value) { + return value; +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + double value) { + return isolate->factory()->NewNumber(value); +} + +// static +template <> +uint8_t TypedElementsAccessor::FromScalar(int value) { + if (value < 0x00) return 0x00; + if (value > 0xFF) return 0xFF; + return static_cast(value); +} + +// static +template <> +uint8_t TypedElementsAccessor::FromScalar(uint32_t value) { + // We need this special case for Uint32 -> Uint8Clamped, because the highest + // Uint32 values will be negative as an int, clamping to 0, rather than 255. + if (value > 0xFF) return 0xFF; + return static_cast(value); +} + +// static +template <> +uint8_t TypedElementsAccessor::FromScalar(double value) { + // Handle NaNs and less than zero values which clamp to zero. + if (!(value > 0)) return 0; + if (value > 0xFF) return 0xFF; + return static_cast(lrint(value)); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + uint8_t value) { + return handle(Smi::FromInt(value), isolate); +} + +// static +template <> +int64_t TypedElementsAccessor::FromScalar( + int value) { + UNREACHABLE(); +} + +// static +template <> +int64_t TypedElementsAccessor::FromScalar( + uint32_t value) { + UNREACHABLE(); +} + +// static +template <> +int64_t TypedElementsAccessor::FromScalar( + double value) { + UNREACHABLE(); +} + +// static +template <> +int64_t TypedElementsAccessor::FromScalar( + int64_t value) { + return value; +} + +// static +template <> +int64_t TypedElementsAccessor::FromScalar( + uint64_t value) { + return static_cast(value); +} + +// static +template <> +int64_t TypedElementsAccessor::FromObject( + Object value, bool* lossless) { + return BigInt::cast(value).AsInt64(lossless); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + int64_t value) { + return BigInt::FromInt64(isolate, value); +} + +// static +template <> +uint64_t TypedElementsAccessor::FromScalar(int value) { + UNREACHABLE(); +} + +// static +template <> +uint64_t TypedElementsAccessor::FromScalar(uint32_t value) { + UNREACHABLE(); +} + +// static +template <> +uint64_t TypedElementsAccessor::FromScalar(double value) { + UNREACHABLE(); +} + +// static +template <> +uint64_t TypedElementsAccessor::FromScalar(int64_t value) { + return static_cast(value); +} + +// static +template <> +uint64_t TypedElementsAccessor::FromScalar(uint64_t value) { + return value; +} + +// static +template <> +uint64_t TypedElementsAccessor::FromObject(Object value, + bool* lossless) { + return BigInt::cast(value).AsUint64(lossless); +} + +// static +template <> +Handle TypedElementsAccessor::ToHandle(Isolate* isolate, + uint64_t value) { + return BigInt::FromUint64(isolate, value); +} + #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype) \ using Type##ElementsAccessor = TypedElementsAccessor; TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR) +RAB_GSAB_TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR) #undef FIXED_ELEMENTS_ACCESSOR template diff --git a/src/objects/js-array-buffer-inl.h b/src/objects/js-array-buffer-inl.h index eb2a976389..0fa5737ec7 100644 --- a/src/objects/js-array-buffer-inl.h +++ b/src/objects/js-array-buffer-inl.h @@ -168,6 +168,8 @@ BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_asmjs_memory, JSArrayBuffer::IsAsmJsMemoryBit) BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_shared, JSArrayBuffer::IsSharedBit) +BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_resizable, + JSArrayBuffer::IsResizableBit) size_t JSArrayBufferView::byte_offset() const { return ReadField(kByteOffsetOffset); @@ -189,11 +191,49 @@ bool JSArrayBufferView::WasDetached() const { return JSArrayBuffer::cast(buffer()).was_detached(); } +BIT_FIELD_ACCESSORS(JSTypedArray, bit_field, is_length_tracking, + JSTypedArray::IsLengthTrackingBit) +BIT_FIELD_ACCESSORS(JSTypedArray, bit_field, is_backed_by_rab, + JSTypedArray::IsBackedByRabBit) + +bool JSTypedArray::IsVariableLength() const { + return is_length_tracking() || is_backed_by_rab(); +} + +size_t JSTypedArray::GetLength() const { + if (WasDetached()) return 0; + if (is_length_tracking()) { + if (is_backed_by_rab()) { + return buffer().byte_length() / element_size(); + } + return buffer().GetBackingStore()->byte_length(std::memory_order_seq_cst) / + element_size(); + } + size_t array_length = LengthUnchecked(); + if (is_backed_by_rab()) { + // The sum can't overflow, since we have managed to allocate the + // JSTypedArray. + if (byte_offset() + array_length * element_size() > + buffer().byte_length()) { + return 0; + } + } + return array_length; +} + void JSTypedArray::AllocateExternalPointerEntries(Isolate* isolate) { InitExternalPointerField(kExternalPointerOffset, isolate); } -size_t JSTypedArray::length() const { return ReadField(kLengthOffset); } +size_t JSTypedArray::length() const { + DCHECK(!is_length_tracking()); + DCHECK(!is_backed_by_rab()); + return ReadField(kLengthOffset); +} + +size_t JSTypedArray::LengthUnchecked() const { + return ReadField(kLengthOffset); +} void JSTypedArray::set_length(size_t value) { WriteField(kLengthOffset, value); diff --git a/src/objects/js-array-buffer.cc b/src/objects/js-array-buffer.cc index 0ba72536c3..91175309f9 100644 --- a/src/objects/js-array-buffer.cc +++ b/src/objects/js-array-buffer.cc @@ -35,11 +35,12 @@ bool CanonicalNumericIndexString(Isolate* isolate, Handle s, } } // anonymous namespace -void JSArrayBuffer::Setup(SharedFlag shared, +void JSArrayBuffer::Setup(SharedFlag shared, ResizableFlag resizable, std::shared_ptr backing_store) { clear_padding(); set_bit_field(0); set_is_shared(shared == SharedFlag::kShared); + set_is_resizable(resizable == ResizableFlag::kResizable); set_is_detachable(shared != SharedFlag::kShared); for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) { SetEmbedderField(i, Smi::zero()); @@ -61,10 +62,17 @@ void JSArrayBuffer::Setup(SharedFlag shared, void JSArrayBuffer::Attach(std::shared_ptr backing_store) { DCHECK_NOT_NULL(backing_store); DCHECK_EQ(is_shared(), backing_store->is_shared()); + DCHECK_EQ(is_resizable(), backing_store->is_resizable()); DCHECK(!was_detached()); Isolate* isolate = GetIsolate(); set_backing_store(isolate, backing_store->buffer_start()); - set_byte_length(backing_store->byte_length()); + if (is_shared() && is_resizable()) { + // GSABs need to read their byte_length from the BackingStore. Maintain the + // invariant that their byte_length field is always 0. + set_byte_length(0); + } else { + set_byte_length(backing_store->byte_length()); + } if (backing_store->is_wasm_memory()) set_is_detachable(false); if (!backing_store->free_on_destruct()) set_is_external(true); Heap* heap = isolate->heap(); @@ -154,14 +162,14 @@ void JSArrayBuffer::YoungMarkExtensionPromoted() { Handle JSTypedArray::GetBuffer() { Isolate* isolate = GetIsolate(); Handle self(*this, isolate); - DCHECK(IsTypedArrayElementsKind(self->GetElementsKind())); - + DCHECK(IsTypedArrayOrRabGsabTypedArrayElementsKind(self->GetElementsKind())); Handle array_buffer(JSArrayBuffer::cast(self->buffer()), isolate); if (!is_on_heap()) { // Already is off heap, so return the existing buffer. return array_buffer; } + DCHECK(!array_buffer->is_resizable()); // The existing array buffer should be empty. DCHECK_NULL(array_buffer->backing_store()); @@ -182,7 +190,8 @@ Handle JSTypedArray::GetBuffer() { } // Attach the backing store to the array buffer. - array_buffer->Setup(SharedFlag::kNotShared, std::move(backing_store)); + array_buffer->Setup(SharedFlag::kNotShared, ResizableFlag::kNotResizable, + std::move(backing_store)); // Clear the elements of the typed array. self->set_elements(ReadOnlyRoots(isolate).empty_byte_array()); @@ -270,6 +279,7 @@ ExternalArrayType JSTypedArray::type() { return kExternal##Type##Array; TYPED_ARRAYS(ELEMENTS_KIND_TO_ARRAY_TYPE) + RAB_GSAB_TYPED_ARRAYS_WITH_TYPED_ARRAY_TYPE(ELEMENTS_KIND_TO_ARRAY_TYPE) #undef ELEMENTS_KIND_TO_ARRAY_TYPE default: @@ -277,13 +287,14 @@ ExternalArrayType JSTypedArray::type() { } } -size_t JSTypedArray::element_size() { +size_t JSTypedArray::element_size() const { switch (map().elements_kind()) { #define ELEMENTS_KIND_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \ case TYPE##_ELEMENTS: \ return sizeof(ctype); TYPED_ARRAYS(ELEMENTS_KIND_TO_ELEMENT_SIZE) + RAB_GSAB_TYPED_ARRAYS(ELEMENTS_KIND_TO_ELEMENT_SIZE) #undef ELEMENTS_KIND_TO_ELEMENT_SIZE default: @@ -291,5 +302,24 @@ size_t JSTypedArray::element_size() { } } +size_t JSTypedArray::LengthTrackingGsabBackedTypedArrayLength( + Isolate* isolate, Address raw_array) { + // TODO(v8:11111): Cache the last seen length in JSArrayBuffer and use it + // in bounds checks to minimize the need for calling this function. + DCHECK(FLAG_harmony_rab_gsab); + DisallowGarbageCollection no_gc; + DisallowJavascriptExecution no_js(isolate); + JSTypedArray array = JSTypedArray::cast(Object(raw_array)); + CHECK(array.is_length_tracking()); + JSArrayBuffer buffer = array.buffer(); + CHECK(buffer.is_resizable()); + CHECK(buffer.is_shared()); + size_t backing_byte_length = + buffer.GetBackingStore()->byte_length(std::memory_order_seq_cst); + CHECK_GE(backing_byte_length, array.byte_offset()); + auto element_byte_size = ElementsKindToByteSize(array.GetElementsKind()); + return (backing_byte_length - array.byte_offset()) / element_byte_size; +} + } // namespace internal } // namespace v8 diff --git a/src/objects/js-array-buffer.h b/src/objects/js-array-buffer.h index 5d5a5445fe..f723380772 100644 --- a/src/objects/js-array-buffer.h +++ b/src/objects/js-array-buffer.h @@ -77,13 +77,18 @@ class JSArrayBuffer // [is_asmjs_memory]: true => this buffer was once used as asm.js memory. DECL_BOOLEAN_ACCESSORS(is_asmjs_memory) - // [is_shared]: tells whether this is an ArrayBuffer or a SharedArrayBuffer. + // [is_shared]: true if this is a SharedArrayBuffer or a + // GrowableSharedArrayBuffer. DECL_BOOLEAN_ACCESSORS(is_shared) + // [is_resizable]: true if this is a ResizableArrayBuffer or a + // GrowableSharedArrayBuffer. + DECL_BOOLEAN_ACCESSORS(is_resizable) + // Initializes the fields of the ArrayBuffer. The provided backing_store can // be nullptr. If it is not nullptr, then the function registers it with // src/heap/array-buffer-tracker.h. - V8_EXPORT_PRIVATE void Setup(SharedFlag shared, + V8_EXPORT_PRIVATE void Setup(SharedFlag shared, ResizableFlag resizable, std::shared_ptr backing_store); // Attaches the backing store to an already constructed empty ArrayBuffer. @@ -259,6 +264,9 @@ class JSTypedArray // eventually. static constexpr size_t kMaxLength = v8::TypedArray::kMaxLength; + // Bit positions for [bit_field]. + DEFINE_TORQUE_GENERATED_JS_TYPED_ARRAY_FLAGS() + // [length]: length of typed array in elements. DECL_PRIMITIVE_GETTER(length, size_t) @@ -271,7 +279,7 @@ class JSTypedArray PropertyDescriptor* desc, Maybe should_throw); ExternalArrayType type(); - V8_EXPORT_PRIVATE size_t element_size(); + V8_EXPORT_PRIVATE size_t element_size() const; V8_EXPORT_PRIVATE Handle GetBuffer(); @@ -296,6 +304,14 @@ class JSTypedArray inline bool is_on_heap() const; inline bool is_on_heap(AcquireLoadTag tag) const; + DECL_BOOLEAN_ACCESSORS(is_length_tracking) + DECL_BOOLEAN_ACCESSORS(is_backed_by_rab) + inline bool IsVariableLength() const; + inline size_t GetLength() const; + + static size_t LengthTrackingGsabBackedTypedArrayLength(Isolate* isolate, + Address raw_array); + // Note: this is a pointer compression specific optimization. // Normally, on-heap typed arrays contain HeapObject value in |base_pointer| // field and an offset in |external_pointer|. @@ -352,6 +368,9 @@ class JSTypedArray friend class Factory; DECL_PRIMITIVE_SETTER(length, size_t) + // Reads the "length" field, doesn't assert the TypedArray is not RAB / GSAB + // backed. + inline size_t LengthUnchecked() const; DECL_GETTER(external_pointer, Address) DECL_GETTER(external_pointer_raw, ExternalPointer_t) diff --git a/src/objects/js-array-buffer.tq b/src/objects/js-array-buffer.tq index 72e74cc99b..ddd90d4c81 100644 --- a/src/objects/js-array-buffer.tq +++ b/src/objects/js-array-buffer.tq @@ -8,11 +8,13 @@ bitfield struct JSArrayBufferFlags extends uint32 { was_detached: bool: 1 bit; is_asm_js_memory: bool: 1 bit; is_shared: bool: 1 bit; + is_resizable: bool: 1 bit; } @generateCppClass extern class JSArrayBuffer extends JSObject { byte_length: uintptr; + max_byte_length: uintptr; backing_store: ExternalPointer; extension: RawPtr; bit_field: JSArrayBufferFlags; @@ -29,10 +31,16 @@ macro IsDetachedBuffer(buffer: JSArrayBuffer): bool { return buffer.bit_field.was_detached; } +@export macro IsSharedArrayBuffer(buffer: JSArrayBuffer): bool { return buffer.bit_field.is_shared; } +@export +macro IsResizableArrayBuffer(buffer: JSArrayBuffer): bool { + return buffer.bit_field.is_resizable; +} + @abstract @generateCppClass extern class JSArrayBufferView extends JSObject { @@ -41,11 +49,35 @@ extern class JSArrayBufferView extends JSObject { byte_length: uintptr; } +// We have 4 different TypedArrays: +// 1) Normal (backed by AB / SAB) or non-length tracking backed by GSAB (can't +// go oob once constructed) 2) Non-length tracking backed by RAB (can go oob +// once constructed) 3) Length-tracking backed by RAB (JSArrayBuffer stores the +// length) 4) Length-tracking backed by GSAB (BackingStore stores the length) +bitfield struct JSTypedArrayFlags extends uint32 { + is_length_tracking: bool: 1 bit; + is_backed_by_rab: bool: 1 bit; +} + @generateCppClass extern class JSTypedArray extends JSArrayBufferView { length: uintptr; external_pointer: ExternalPointer; base_pointer: ByteArray|Smi; + bit_field: JSTypedArrayFlags; + // Pads header size to be a multiple of kTaggedSize. + @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; + @ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void; +} + +@export +macro IsVariableLengthTypedArray(array: JSTypedArray): bool { + return array.bit_field.is_length_tracking || array.bit_field.is_backed_by_rab; +} + +@export +macro IsLengthTrackingTypedArray(array: JSTypedArray): bool { + return array.bit_field.is_length_tracking; } @generateCppClass diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc index c4cfbd56e0..b191746fae 100644 --- a/src/objects/js-function.cc +++ b/src/objects/js-function.cc @@ -796,6 +796,55 @@ MaybeHandle JSFunction::GetDerivedMap(Isolate* isolate, return map; } +Handle JSFunction::GetDerivedRabGsabMap(Isolate* isolate, + Handle constructor, + Handle new_target) { + { + DisallowHeapAllocation no_alloc; + NativeContext context = isolate->context().native_context(); + if (*new_target == context.uint8_array_fun()) { + return handle(context.rab_gsab_uint8_array_map(), isolate); + } + if (*new_target == context.int8_array_fun()) { + return handle(context.rab_gsab_int8_array_map(), isolate); + } + if (*new_target == context.uint16_array_fun()) { + return handle(context.rab_gsab_uint16_array_map(), isolate); + } + if (*new_target == context.int16_array_fun()) { + return handle(context.rab_gsab_int16_array_map(), isolate); + } + if (*new_target == context.uint32_array_fun()) { + return handle(context.rab_gsab_uint32_array_map(), isolate); + } + if (*new_target == context.int32_array_fun()) { + return handle(context.rab_gsab_int32_array_map(), isolate); + } + if (*new_target == context.float32_array_fun()) { + return handle(context.rab_gsab_float32_array_map(), isolate); + } + if (*new_target == context.float64_array_fun()) { + return handle(context.rab_gsab_float64_array_map(), isolate); + } + if (*new_target == context.biguint64_array_fun()) { + return handle(context.rab_gsab_biguint64_array_map(), isolate); + } + if (*new_target == context.bigint64_array_fun()) { + return handle(context.rab_gsab_bigint64_array_map(), isolate); + } + } + + // This only happens when subclassing TypedArrays. Create a new map with the + // corresponding RAB / GSAB ElementsKind. Note: the map is not cached and + // reused -> every array gets a unique map, making ICs slow. + Handle map = + GetDerivedMap(isolate, constructor, new_target).ToHandleChecked(); + Handle rab_gsab_map = Map::Copy(isolate, map, "RAB / GSAB"); + rab_gsab_map->set_elements_kind( + GetCorrespondingRabGsabElementsKind(map->elements_kind())); + return rab_gsab_map; +} + int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) { CHECK(has_initial_map()); if (initial_map().IsInobjectSlackTrackingInProgress()) { diff --git a/src/objects/js-function.h b/src/objects/js-function.h index 037f7f54a1..9d0fc533f4 100644 --- a/src/objects/js-function.h +++ b/src/objects/js-function.h @@ -237,6 +237,11 @@ class JSFunction : public JSFunctionOrBoundFunction { Isolate* isolate, Handle constructor, Handle new_target); + // Like GetDerivedMap, but returns a map with a RAB / GSAB ElementsKind. + static V8_WARN_UNUSED_RESULT Handle GetDerivedRabGsabMap( + Isolate* isolate, Handle constructor, + Handle new_target); + // Get and set the prototype property on a JSFunction. If the // function has an initial map the prototype is set on the initial // map. Otherwise, the prototype is put in the initial map field diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc index 90d2cac308..aa83fccb0f 100644 --- a/src/objects/js-objects.cc +++ b/src/objects/js-objects.cc @@ -4220,10 +4220,15 @@ bool JSObject::HasEnumerableElements() { } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: - TYPED_ARRAYS(TYPED_ARRAY_CASE) + TYPED_ARRAYS(TYPED_ARRAY_CASE) { + size_t length = JSTypedArray::cast(object).length(); + return length > 0; + } + + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE { - size_t length = JSTypedArray::cast(object).length(); + size_t length = JSTypedArray::cast(object).GetLength(); return length > 0; } case DICTIONARY_ELEMENTS: { @@ -5025,6 +5030,7 @@ int JSObject::GetFastElementsUsage() { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE UNREACHABLE(); } diff --git a/src/objects/js-objects.tq b/src/objects/js-objects.tq index 9f5bf8554e..e21f874bbb 100644 --- a/src/objects/js-objects.tq +++ b/src/objects/js-objects.tq @@ -67,10 +67,15 @@ macro GetDerivedMap(implicit context: Context)( return map; } label SlowPath { - return runtime::GetDerivedMap(context, target, newTarget); + return runtime::GetDerivedMap(context, target, newTarget, FalseConstant()); } } +macro GetDerivedRabGsabMap(implicit context: Context)( + target: JSFunction, newTarget: JSReceiver): Map { + return runtime::GetDerivedMap(context, target, newTarget, TrueConstant()); +} + macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map): JSObject { let properties: EmptyFixedArray|NameDictionary|SwissNameDictionary = diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h index 2d48405317..84a1627985 100644 --- a/src/objects/lookup-inl.h +++ b/src/objects/lookup-inl.h @@ -169,7 +169,8 @@ Handle LookupIterator::GetName() { bool LookupIterator::IsElement(JSReceiver object) const { return index_ <= JSObject::kMaxElementIndex || - (index_ != kInvalidIndex && object.map().has_typed_array_elements()); + (index_ != kInvalidIndex && + object.map().has_typed_array_or_rab_gsab_typed_array_elements()); } bool LookupIterator::is_dictionary_holder() const { diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h index eb3401e184..96626f28eb 100644 --- a/src/objects/map-inl.h +++ b/src/objects/map-inl.h @@ -239,7 +239,7 @@ FixedArrayBase Map::GetInitialElements() const { if (has_fast_elements() || has_fast_string_wrapper_elements() || has_any_nonextensible_elements()) { result = GetReadOnlyRoots().empty_fixed_array(); - } else if (has_typed_array_elements()) { + } else if (has_typed_array_or_rab_gsab_typed_array_elements()) { result = GetReadOnlyRoots().empty_byte_array(); } else if (has_dictionary_elements()) { result = GetReadOnlyRoots().empty_slow_element_dictionary(); @@ -593,6 +593,14 @@ bool Map::has_typed_array_elements() const { return IsTypedArrayElementsKind(elements_kind()); } +bool Map::has_rab_gsab_typed_array_elements() const { + return IsRabGsabTypedArrayElementsKind(elements_kind()); +} + +bool Map::has_typed_array_or_rab_gsab_typed_array_elements() const { + return IsTypedArrayOrRabGsabTypedArrayElementsKind(elements_kind()); +} + bool Map::has_dictionary_elements() const { return IsDictionaryElementsKind(elements_kind()); } diff --git a/src/objects/map.h b/src/objects/map.h index 33d9394b43..83e5dfa365 100644 --- a/src/objects/map.h +++ b/src/objects/map.h @@ -151,8 +151,7 @@ using MapHandles = std::vector>; // | Byte | [bit_field2] | // | | - new_target_is_base (bit 0) | // | | - is_immutable_proto (bit 1) | -// | | - unused bit (bit 2) | -// | | - elements_kind (bits 3..7) | +// | | - elements_kind (bits 2..7) | // +----+----------+-------------------------------------------------+ // | Int | [bit_field3] | // | | - enum_length (bit 0..9) | @@ -416,6 +415,8 @@ class Map : public HeapObject { inline bool has_fast_sloppy_arguments_elements() const; inline bool has_fast_string_wrapper_elements() const; inline bool has_typed_array_elements() const; + inline bool has_rab_gsab_typed_array_elements() const; + inline bool has_typed_array_or_rab_gsab_typed_array_elements() const; inline bool has_dictionary_elements() const; inline bool has_any_nonextensible_elements() const; inline bool has_nonextensible_elements() const; diff --git a/src/objects/map.tq b/src/objects/map.tq index 4cd3f2d67f..49b2e5be36 100644 --- a/src/objects/map.tq +++ b/src/objects/map.tq @@ -16,8 +16,7 @@ bitfield struct MapBitFields1 extends uint8 { bitfield struct MapBitFields2 extends uint8 { new_target_is_base: bool: 1 bit; is_immutable_prototype: bool: 1 bit; - unused: bool: 1 bit; - elements_kind: ElementsKind: 5 bit; + elements_kind: ElementsKind: 6 bit; } bitfield struct MapBitFields3 extends uint32 { diff --git a/src/objects/objects.cc b/src/objects/objects.cc index 94fda3f450..860e007154 100644 --- a/src/objects/objects.cc +++ b/src/objects/objects.cc @@ -2812,6 +2812,7 @@ Maybe Object::SetDataProperty(LookupIterator* it, Handle value) { Handle to_assign = value; // Convert the incoming value to a number for storing into typed arrays. + // TODO(v8:11111): Support RAB / GSAB. if (it->IsElement() && receiver->IsJSObject() && JSObject::cast(*receiver).HasTypedArrayElements()) { ElementsKind elements_kind = JSObject::cast(*receiver).GetElementsKind(); diff --git a/src/runtime/runtime-internal.cc b/src/runtime/runtime-internal.cc index f974c6f850..6d569c2be2 100644 --- a/src/runtime/runtime-internal.cc +++ b/src/runtime/runtime-internal.cc @@ -140,6 +140,7 @@ const char* ElementsKindToType(ElementsKind fixed_elements_kind) { return #Type "Array"; TYPED_ARRAYS(ELEMENTS_KIND_CASE) + RAB_GSAB_TYPED_ARRAYS_WITH_TYPED_ARRAY_TYPE(ELEMENTS_KIND_CASE) #undef ELEMENTS_KIND_CASE default: diff --git a/src/runtime/runtime-literals.cc b/src/runtime/runtime-literals.cc index d4f7a7ea90..c4285f2403 100644 --- a/src/runtime/runtime-literals.cc +++ b/src/runtime/runtime-literals.cc @@ -218,6 +218,7 @@ MaybeHandle JSObjectWalkVisitor::StructureWalk( #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) + RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE // Typed elements cannot be created using an object literal. UNREACHABLE(); diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index 56f3af33c6..eec942088e 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -972,11 +972,16 @@ RUNTIME_FUNCTION(Runtime_NewObject) { RUNTIME_FUNCTION(Runtime_GetDerivedMap) { HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); + DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); - RETURN_RESULT_OR_FAILURE( - isolate, JSFunction::GetDerivedMap(isolate, target, new_target)); + CONVERT_ARG_HANDLE_CHECKED(Object, rab_gsab, 2); + if (rab_gsab->IsTrue()) { + return *JSFunction::GetDerivedRabGsabMap(isolate, target, new_target); + } else { + RETURN_RESULT_OR_FAILURE( + isolate, JSFunction::GetDerivedMap(isolate, target, new_target)); + } } RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTrackingForMap) { diff --git a/src/runtime/runtime-typedarray.cc b/src/runtime/runtime-typedarray.cc index 4f42f093bc..1e323a170c 100644 --- a/src/runtime/runtime-typedarray.cc +++ b/src/runtime/runtime-typedarray.cc @@ -53,6 +53,15 @@ RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { return *holder->GetBuffer(); } +RUNTIME_FUNCTION(Runtime_GrowableSharedArrayBufferByteLength) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); + + CHECK_EQ(0, array_buffer->byte_length()); + size_t byte_length = array_buffer->GetBackingStore()->byte_length(); + return *isolate->factory()->NewNumberFromSize(byte_length); +} namespace { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 21fe3d19dc..aa6ab53b0f 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -556,11 +556,12 @@ namespace internal { F(RegExpSpeciesProtector, 0, 1) \ F(Is64Bit, 0, 1) -#define FOR_EACH_INTRINSIC_TYPEDARRAY(F, I) \ - F(ArrayBufferDetach, 1, 1) \ - F(TypedArrayCopyElements, 3, 1) \ - F(TypedArrayGetBuffer, 1, 1) \ - F(TypedArraySet, 2, 1) \ +#define FOR_EACH_INTRINSIC_TYPEDARRAY(F, I) \ + F(ArrayBufferDetach, 1, 1) \ + F(GrowableSharedArrayBufferByteLength, 1, 1) \ + F(TypedArrayCopyElements, 3, 1) \ + F(TypedArrayGetBuffer, 1, 1) \ + F(TypedArraySet, 2, 1) \ F(TypedArraySortFast, 1, 1) #define FOR_EACH_INTRINSIC_WASM(F, I) \ diff --git a/src/snapshot/context-deserializer.cc b/src/snapshot/context-deserializer.cc index 04756b5ffe..ad109bacca 100644 --- a/src/snapshot/context-deserializer.cc +++ b/src/snapshot/context-deserializer.cc @@ -62,9 +62,11 @@ void ContextDeserializer::SetupOffHeapArrayBufferBackingStores() { uint32_t store_index = buffer->GetBackingStoreRefForDeserialization(); auto bs = backing_store(store_index); buffer->AllocateExternalPointerEntries(isolate()); + // TODO(v8:11111): Support RAB / GSAB. + CHECK(!buffer->is_resizable()); SharedFlag shared = bs && bs->is_shared() ? SharedFlag::kShared : SharedFlag::kNotShared; - buffer->Setup(shared, bs); + buffer->Setup(shared, ResizableFlag::kNotResizable, bs); } } diff --git a/src/snapshot/object-deserializer.cc b/src/snapshot/object-deserializer.cc index 929996ee10..d5ce8cc6e9 100644 --- a/src/snapshot/object-deserializer.cc +++ b/src/snapshot/object-deserializer.cc @@ -66,7 +66,9 @@ void ObjectDeserializer::CommitPostProcessedObjects() { auto bs = backing_store(store_index); SharedFlag shared = bs && bs->is_shared() ? SharedFlag::kShared : SharedFlag::kNotShared; - buffer->Setup(shared, bs); + // TODO(v8:11111): Support RAB / GSAB. + CHECK(!bs || !bs->is_resizable()); + buffer->Setup(shared, ResizableFlag::kNotResizable, bs); } for (Handle