[rab / gsab] RAB / GSAB support for TA.p.set

Bug: v8:11111
Change-Id: I757e67cbcad98b6cacb3ad08b6a364194feead1f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3427201
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78937}
This commit is contained in:
Marja Hölttä 2022-02-04 07:51:39 +01:00 committed by V8 LUCI CQ
parent efd28c14c2
commit f733dc0f31
12 changed files with 1257 additions and 97 deletions

View File

@ -186,8 +186,12 @@ TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
TNode<BoolT> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
TNode<Int32T> kind) {
return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
return Word32Or(
Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS))),
Word32Or(
Word32Equal(kind, Int32Constant(RAB_GSAB_UINT8_ELEMENTS)),
Word32Equal(kind, Int32Constant(RAB_GSAB_UINT8_CLAMPED_ELEMENTS))));
}
TNode<BoolT> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(

View File

@ -28,10 +28,12 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<UintPtrT> CalculateExternalPointer(TNode<UintPtrT> backing_store,
TNode<UintPtrT> byte_offset);
// Returns true if kind is either UINT8_ELEMENTS or UINT8_CLAMPED_ELEMENTS.
// Returns true if kind is either UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS,
// RAB_GSAB_UINT8_ELEMENTS, or RAB_GSAB_UINT8_CLAMPED_ELEMENTS.
TNode<BoolT> IsUint8ElementsKind(TNode<Int32T> kind);
// Returns true if kind is either BIGINT64_ELEMENTS or BIGUINT64_ELEMENTS.
// Returns true if kind is either BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS,
// RAB_GSAB_BIGINT64_ELEMENTS, or RAB_GSAB_BIGUINT64_ELEMENTS.
TNode<BoolT> IsBigInt64ElementsKind(TNode<Int32T> kind);
// Returns the byte size of an element for a TypedArray elements kind.

View File

@ -84,11 +84,6 @@ javascript builtin DataViewPrototypeGetBuffer(
return dataView.buffer;
}
extern macro IsJSArrayBufferViewDetachedOrOutOfBounds(JSArrayBufferView):
never labels DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
extern macro LoadVariableLengthJSArrayBufferViewByteLength(
JSArrayBufferView, JSArrayBuffer): uintptr labels DetachedOrOutOfBounds;
// ES6 section 24.2.4.2 get DataView.prototype.byteLength
javascript builtin DataViewPrototypeGetByteLength(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number {
@ -118,7 +113,7 @@ javascript builtin DataViewPrototypeGetByteOffset(
const dataView: JSDataView =
ValidateDataView(context, receiver, 'get DataView.prototype.byte_offset');
try {
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
typed_array::IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
} label DetachedOrOutOfBounds {
ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameByteOffset);
@ -399,7 +394,7 @@ transitioning macro DataViewGet(
// 7. If IsViewOutOfBounds(view, getBufferByteLength) is true, throw a
// TypeError exception.
try {
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
typed_array::IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
} label DetachedOrOutOfBounds {
ThrowTypeError(
@ -718,7 +713,7 @@ transitioning macro DataViewSet(
// 10. If IsViewOutOfBounds(view, getBufferByteLength) is true, throw a
// TypeError exception.
try {
IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
typed_array::IsJSArrayBufferViewDetachedOrOutOfBounds(dataView)
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
} label DetachedOrOutOfBounds {
ThrowTypeError(

View File

@ -70,63 +70,62 @@ TypedArrayPrototypeSet(
// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
// exception.
const utarget = typed_array::EnsureAttached(target) otherwise IsDetached;
const attachedTargetAndLength = EnsureAttachedAndReadLength(target)
otherwise IsDetachedOrOutOfBounds;
const overloadedArg = arguments[0];
try {
// 1. Choose 22.2.3.23.2 or 22.2.3.23.1 depending on whether the
// overloadedArg has a [[TypedArrayName]] internal slot.
// If it does, the definition in 22.2.3.23.2 applies.
// If it does not, the definition in 22.2.3.23.1 applies.
// 1. Choose SetTypedArrayFromTypedArray or SetTypedArrayFromArrayLike
// depending on whether the overloadedArg has a [[TypedArrayName]]
// internal slot.
const typedArray =
Cast<JSTypedArray>(overloadedArg) otherwise NotTypedArray;
// Step 9 is not observable, do it later.
// Step 3 is not observable, do it later.
// 10. Let srcBuffer be typedArray.[[ViewedArrayBuffer]].
// 11. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
// 4. Let srcBuffer be typedArray.[[ViewedArrayBuffer]].
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
// exception.
const utypedArray =
typed_array::EnsureAttached(typedArray) otherwise IsDetached;
const attachedSourceAndLength = EnsureAttachedAndReadLength(typedArray)
otherwise IsDetachedOrOutOfBounds;
TypedArrayPrototypeSetTypedArray(
utarget, utypedArray, targetOffset, targetOffsetOverflowed)
attachedTargetAndLength, attachedSourceAndLength, targetOffset,
targetOffsetOverflowed)
otherwise OffsetOutOfBounds;
return Undefined;
} label NotTypedArray deferred {
TypedArrayPrototypeSetArray(
utarget, overloadedArg, targetOffset, targetOffsetOverflowed)
otherwise OffsetOutOfBounds, IsDetached;
target, attachedTargetAndLength.length, overloadedArg, targetOffset,
targetOffsetOverflowed)
otherwise OffsetOutOfBounds;
return Undefined;
}
} label OffsetOutOfBounds deferred {
ThrowRangeError(MessageTemplate::kTypedArraySetOffsetOutOfBounds);
} label IsDetached deferred {
} label IsDetachedOrOutOfBounds deferred {
ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSet);
}
}
// %TypedArray%.prototype.set ( array [ , offset ] )
// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-array-offset
// SetTypedArrayFromArrayLike
// https://tc39.es/ecma262/#sec-settypedarrayfromarraylike
transitioning macro
TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)(
target: JSTypedArray, arrayArg: JSAny, targetOffset: uintptr,
targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds,
IfDetached {
// Steps 9-13 are not observable, do them later.
target: JSTypedArray, targetLength: uintptr, arrayArg: JSAny,
targetOffset: uintptr,
targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds {
// Steps 3-7 are not observable, do them later.
// 14. Let src be ? ToObject(array).
// 8. Let src be ? ToObject(source).
const src: JSReceiver = ToObject_Inline(context, arrayArg);
// 15. Let srcLength be ? LengthOfArrayLike(src).
// 9. Let srcLength be ? LengthOfArrayLike(src).
const srcLengthNum: Number = GetLengthProperty(src);
// 10. If targetOffset is +∞, throw a RangeError exception.
if (targetOffsetOverflowed) goto IfOffsetOutOfBounds;
// 9. Let targetLength be target.[[ArrayLength]].
const targetLength = target.length;
// 16. If srcLength + targetOffset > targetLength, throw a RangeError
// 11. If srcLength + targetOffset > targetLength, throw a RangeError
// exception.
const srcLength = ChangeSafeIntegerNumberToUintPtr(srcLengthNum)
otherwise IfOffsetOutOfBounds;
@ -137,10 +136,10 @@ TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)(
// to do with the empty source array.
if (srcLength == 0) return;
// 10. Let targetName be the String value of target.[[TypedArrayName]].
// 11. Let targetElementSize be the Element Size value specified in
// Table 62 for targetName.
// 12. Let targetType be the Element Type value in Table 62 for
// 4. Let targetName be the String value of target.[[TypedArrayName]].
// 5. Let targetElementSize be the Element Size value specified in
// Table 69 for targetName.
// 6. Let targetType be the Element Type value in Table 69 for
// targetName.
try {
@ -161,7 +160,10 @@ TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)(
IsElementsKindInRange(
srcKind, ElementsKind::PACKED_DOUBLE_ELEMENTS,
ElementsKind::HOLEY_DOUBLE_ELEMENTS)) {
const utarget = typed_array::EnsureAttached(target) otherwise IfDetached;
// If the source is a JSArray (no custom length getter or elements
// getter), there's nothing that could detach or resize the target, so
// it's always non-detached here. Also we don't need to reload the length.
const utarget = typed_array::EnsureAttached(target) otherwise unreachable;
CallCCopyFastNumberJSArrayElementsToTypedArray(
context, fastSrc, utarget, srcLength, targetOffset);
@ -174,56 +176,56 @@ TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)(
}
}
// %TypedArray%.prototype.set ( typedArray [ , offset ] )
// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-typedarray-offset
// SetTypedArrayFromTypedArray
// https://tc39.es/ecma262/#sec-settypedarrayfromtypedarray
transitioning macro
TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
target: AttachedJSTypedArray, typedArray: AttachedJSTypedArray,
attachedTargetAndLength: AttachedJSTypedArrayAndLength,
attachedSourceAndLength: AttachedJSTypedArrayAndLength,
targetOffset: uintptr,
targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds {
// Steps 12-20 are not observable, so we can handle offset overflow
// at step 21 here.
// Steps 6-14 are not observable, so we can handle offset overflow
// at step 15 here.
if (targetOffsetOverflowed) goto IfOffsetOutOfBounds;
// 9. Let targetLength be target.[[ArrayLength]].
const targetLength = target.length;
// 3. Let targetLength be IntegerIndexedObjectLength(target).
const target = attachedTargetAndLength.array;
const targetLength = attachedTargetAndLength.length;
// 19. Let srcLength be typedArray.[[ArrayLength]].
const srcLength: uintptr = typedArray.length;
// 13. Let srcLength be IntegerIndexedObjectLength(source).
const source = attachedSourceAndLength.array;
const srcLength = attachedSourceAndLength.length;
// Steps 12-20 are not observable, so we can do step 21 here.
// 21. If srcLength + targetOffset > targetLength, throw a RangeError
// 16. If srcLength + targetOffset > targetLength, throw a RangeError
// exception.
CheckIntegerIndexAdditionOverflow(srcLength, targetOffset, targetLength)
otherwise IfOffsetOutOfBounds;
// 12. Let targetName be the String value of target.[[TypedArrayName]].
// 13. Let targetType be the Element Type value in Table 62 for
// 6. Let targetName be the String value of target.[[TypedArrayName]].
// 7. Let targetType be the Element Type value in Table 62 for
// targetName.
// 14. Let targetElementSize be the Element Size value specified in
// 8. Let targetElementSize be the Element Size value specified in
// Table 62 for targetName.
const targetElementsInfo = GetTypedArrayElementsInfo(target);
// 16. Let srcName be the String value of typedArray.[[TypedArrayName]].
// 17. Let srcType be the Element Type value in Table 62 for srcName.
// 18. Let srcElementSize be the Element Size value specified in
// 10. Let srcName be the String value of source.[[TypedArrayName]].
// 11. Let srcType be the Element Type value in Table 62 for srcName.
// 12. Let srcElementSize be the Element Size value specified in
// Table 62 for srcName.
const srcKind: ElementsKind = typedArray.elements_kind;
// const srcElementsInfo = GetTypedArrayElementsInfo(typedArray);
const srcKind: ElementsKind = source.elements_kind;
// We skip steps 23-25 because both memmove and
// We skip steps 18-20 because both memmove and
// CopyTypedArrayElementsToTypedArray() properly handle overlapping
// regions.
// 23. If both IsSharedArrayBuffer(srcBuffer) and
// 18. If both IsSharedArrayBuffer(srcBuffer) and
// IsSharedArrayBuffer(targetBuffer) are true, then
// 23a. If srcBuffer.[[ArrayBufferData]] and
// a. If srcBuffer.[[ArrayBufferData]] and
// targetBuffer.[[ArrayBufferData]] are the same Shared Data Block
// values, let same be true; else let same be false.
// 24. Else, let same be SameValue(srcBuffer, targetBuffer).
// 25. If same is true, then
// a. Let srcByteLength be typedArray.[[ByteLength]].
// 19. Else, let same be SameValue(srcBuffer, targetBuffer).
// 20. If same is true, then
// a. Let srcByteLength be source.[[ByteLength]].
// b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset,
// srcByteLength, %ArrayBuffer%).
// c. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known
@ -232,6 +234,8 @@ TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
try {
// Use memmove if possible.
// TODO(v8:11111): Enable fast copying between a RAB/GSAB element kind and
// the corresponding non-RAB/GSAB element kind.
if (srcKind != targetElementsInfo.kind) {
// Uint8/Uint8Clamped elements could still be copied with memmove.
if (!IsUint8ElementsKind(srcKind) ||
@ -255,10 +259,19 @@ TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
otherwise unreachable;
const dstPtr: RawPtr = target.data_ptr + Convert<intptr>(startOffset);
dcheck(countBytes <= target.byte_length - startOffset);
dcheck(countBytes <= typedArray.byte_length);
// We've already checked for detachedness, and there's nothing that could've
// detached the buffers until here.
@if(DEBUG) {
const targetByteLength = LoadJSArrayBufferViewByteLength(
target, target.buffer) otherwise unreachable;
const sourceByteLength = LoadJSArrayBufferViewByteLength(
source, source.buffer) otherwise unreachable;
// 29. If srcType is the same as targetType, then
dcheck(countBytes <= targetByteLength - startOffset);
dcheck(countBytes <= sourceByteLength);
}
// 24. If srcType is the same as targetType, then
// a. NOTE: If srcType and targetType are the same, the transfer must
// be performed in a manner that preserves the bit-level encoding of
// the source data.
@ -271,13 +284,13 @@ TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
// iv. Set targetByteIndex to targetByteIndex + 1.
if (IsSharedArrayBuffer(target.buffer)) {
// SABs need a relaxed memmove to preserve atomicity.
CallCRelaxedMemmove(dstPtr, typedArray.data_ptr, countBytes);
CallCRelaxedMemmove(dstPtr, source.data_ptr, countBytes);
} else {
CallCMemmove(dstPtr, typedArray.data_ptr, countBytes);
CallCMemmove(dstPtr, source.data_ptr, countBytes);
}
} label IfSlow deferred {
// 22. If target.[[ContentType]] is not equal to
// typedArray.[[ContentType]], throw a TypeError exception.
// 17. If target.[[ContentType]] is not equal to
// source.[[ContentType]], throw a TypeError exception.
if (IsBigInt64ElementsKind(srcKind) !=
IsBigInt64ElementsKind(targetElementsInfo.kind))
deferred {
@ -288,7 +301,7 @@ TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
// to do with the empty source array.
if (srcLength == 0) return;
// 30. Else,
// 25. Else,
// a. Repeat, while targetByteIndex < limit
// i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex,
// srcType, true, Unordered).
@ -297,7 +310,7 @@ TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)(
// iii. Set srcByteIndex to srcByteIndex + srcElementSize.
// iv. Set targetByteIndex to targetByteIndex + targetElementSize.
CallCCopyTypedArrayElementsToTypedArray(
typedArray, target, srcLength, targetOffset);
source, target, srcLength, targetOffset);
}
}
}

View File

@ -3611,6 +3611,7 @@ class TypedElementsAccessor
}
}
// TODO(v8:11111): Update this once we have external RAB / GSAB array types.
static bool HasSimpleRepresentation(ExternalArrayType type) {
return !(type == kExternalFloat32Array || type == kExternalFloat64Array ||
type == kExternalUint8ClampedArray);
@ -3642,9 +3643,9 @@ class TypedElementsAccessor
CHECK(!source.WasDetached());
CHECK(!destination.WasDetached());
DCHECK_LE(offset, destination.length());
DCHECK_LE(length, destination.length() - offset);
DCHECK_LE(length, source.length());
DCHECK_LE(offset, destination.GetLength());
DCHECK_LE(length, destination.GetLength() - offset);
DCHECK_LE(length, source.GetLength());
ExternalArrayType source_type = source.type();
ExternalArrayType destination_type = destination.type();
@ -3705,6 +3706,7 @@ class TypedElementsAccessor
source_shared || destination_shared ? kShared : kUnshared); \
break;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
default:
UNREACHABLE();
break;
@ -3739,12 +3741,15 @@ class TypedElementsAccessor
static bool TryCopyElementsFastNumber(Context context, JSArray source,
JSTypedArray destination, size_t length,
size_t offset) {
if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) return false;
if (IsBigIntTypedArrayElementsKind(Kind)) return false;
Isolate* isolate = source.GetIsolate();
DisallowGarbageCollection no_gc;
DisallowJavascriptExecution no_js(isolate);
CHECK(!destination.WasDetached());
bool out_of_bounds = false;
CHECK(destination.GetLengthOrOutOfBounds(out_of_bounds) >= length);
CHECK(!out_of_bounds);
size_t current_length;
DCHECK(source.length().IsNumber() &&
@ -3752,7 +3757,7 @@ class TypedElementsAccessor
length <= current_length);
USE(current_length);
size_t dest_length = destination.length();
size_t dest_length = destination.GetLength();
DCHECK(length + offset <= dest_length);
USE(dest_length);
@ -3830,15 +3835,16 @@ class TypedElementsAccessor
LookupIterator it(isolate, source, i);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
Object::GetProperty(&it));
if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
if (IsBigIntTypedArrayElementsKind(Kind)) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
BigInt::FromObject(isolate, elem));
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
Object::ToNumber(isolate, elem));
}
if (V8_UNLIKELY(destination->WasDetached())) {
bool out_of_bounds = false;
size_t new_length = destination->GetLengthOrOutOfBounds(out_of_bounds);
if (V8_UNLIKELY(out_of_bounds || destination->WasDetached())) {
const char* op = "set";
const MessageTemplate message = MessageTemplate::kDetachedOperation;
Handle<String> operation =
@ -3846,8 +3852,14 @@ class TypedElementsAccessor
THROW_NEW_ERROR_RETURN_FAILURE(isolate,
NewTypeError(message, operation));
}
// The spec says we store the length, then get each element, so we don't
// need to check changes to length.
if (V8_UNLIKELY(new_length <= offset + i)) {
// Proceed with the loop so that we call get getters for the source even
// though we don't set the values in the target.
// TODO(v8:11111): Maybe change this, depending on how
// https://github.com/tc39/proposal-resizablearraybuffer/issues/86 is
// resolved.
continue;
}
SetImpl(destination, InternalIndex(offset + i), *elem);
}
return *isolate->factory()->undefined_value();
@ -3860,15 +3872,24 @@ class TypedElementsAccessor
Handle<JSObject> destination,
size_t length, size_t offset) {
Isolate* isolate = destination->GetIsolate();
if (length == 0) return *isolate->factory()->undefined_value();
Handle<JSTypedArray> destination_ta =
Handle<JSTypedArray>::cast(destination);
DCHECK_LE(offset + length, destination_ta->length());
if (length == 0) return *isolate->factory()->undefined_value();
// All conversions from TypedArrays can be done without allocation.
if (source->IsJSTypedArray()) {
// TODO(v8:11111): Add RAB/GSAB support.
DCHECK(!destination_ta->is_length_tracking());
DCHECK(!destination_ta->is_backed_by_rab());
DCHECK(!Handle<JSTypedArray>::cast(source)->is_length_tracking());
DCHECK(!Handle<JSTypedArray>::cast(source)->is_backed_by_rab());
CHECK(!destination_ta->WasDetached());
bool out_of_bounds = false;
CHECK_LE(offset + length,
destination_ta->GetLengthOrOutOfBounds(out_of_bounds));
CHECK(!out_of_bounds);
Handle<JSTypedArray> source_ta = Handle<JSTypedArray>::cast(source);
ElementsKind source_kind = source_ta->GetElementsKind();
bool source_is_bigint =
@ -3884,6 +3905,10 @@ class TypedElementsAccessor
}
} else if (source->IsJSArray()) {
CHECK(!destination_ta->WasDetached());
bool out_of_bounds = false;
CHECK_LE(offset + length,
destination_ta->GetLengthOrOutOfBounds(out_of_bounds));
CHECK(!out_of_bounds);
// Fast cases for packed numbers kinds where we don't need to allocate.
Handle<JSArray> source_js_array = Handle<JSArray>::cast(source);
size_t current_length;
@ -3898,7 +3923,8 @@ class TypedElementsAccessor
}
}
// Final generic case that handles prototype chain lookups, getters, proxies
// and observable side effects via valueOf, etc.
// and observable side effects via valueOf, etc. In this case, it's possible
// that the length getter detached / resized the underlying buffer.
return CopyElementsHandleSlow(source, destination_ta, length, offset);
}
};
@ -5209,6 +5235,7 @@ void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context,
context, source, destination, length, offset)); \
break;
TYPED_ARRAYS(TYPED_ARRAYS_CASE)
RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAYS_CASE)
#undef TYPED_ARRAYS_CASE
default:
UNREACHABLE();
@ -5228,6 +5255,7 @@ void CopyTypedArrayElementsToTypedArray(Address raw_source,
length, offset); \
break;
TYPED_ARRAYS(TYPED_ARRAYS_CASE)
RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAYS_CASE)
#undef TYPED_ARRAYS_CASE
default:
UNREACHABLE();

View File

@ -73,6 +73,20 @@ macro IsLengthTrackingJSArrayBufferView(array: JSArrayBufferView): bool {
return array.bit_field.is_length_tracking;
}
extern macro LoadVariableLengthJSArrayBufferViewByteLength(
JSArrayBufferView, JSArrayBuffer): uintptr labels DetachedOrOutOfBounds;
@export
macro LoadJSArrayBufferViewByteLength(
view: JSArrayBufferView, buffer: JSArrayBuffer):
uintptr labels DetachedOrOutOfBounds {
if (IsVariableLengthJSArrayBufferView(view)) {
return LoadVariableLengthJSArrayBufferViewByteLength(view, buffer)
otherwise DetachedOrOutOfBounds;
}
return view.byte_length;
}
extern class JSTypedArray extends JSArrayBufferView {
length: uintptr;
// A SandboxedPtr if the sandbox is enabled

View File

@ -67,6 +67,7 @@ class BuildFlags : public ContextualClass<BuildFlags> {
#else
build_flags_["V8_ENABLE_WEBASSEMBLY"] = false;
#endif
build_flags_["DEBUG"] = DEBUG_BOOL;
}
static bool GetFlag(const std::string& name, const char* production) {
auto it = Get().build_flags_.find(name);

View File

@ -2859,3 +2859,317 @@ function TestIterationAndGrow(ta, expected, gsab, grow_after,
assertEquals([10, 8, 6, 4, 0, 2], ToNumbers(wholeArrayView));
}
})();
(function SetWithGrowableTarget() {
for (let ctor of ctors) {
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(gsab, 0, 4);
const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(gsab, 0);
const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new ctor(gsab);
// Orig. array: [0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, ...] << lengthTracking
// [0, 0, ...] << lengthTrackingWithOffset
SetHelper(fixedLength, [1, 2]);
assertEquals([1, 2, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [3, 4], 1);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)}, RangeError);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [5, 6]);
assertEquals([1, 3, 5, 6], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [7], 1);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [8, 9]);
assertEquals([8, 9, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [10, 11], 1);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [12, 13]);
assertEquals([8, 10, 12, 13], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [14], 1);
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0], 1)},
RangeError);
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
// Grow.
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [8, 10, 12, 14, 0, 0]
// [8, 10, 12, 14] << fixedLength
// [12, 14] << fixedLengthWithOffset
// [8, 10, 12, 14, 0, 0, ...] << lengthTracking
// [12, 14, 0, 0, ...] << lengthTrackingWithOffset
SetHelper(fixedLength, [21, 22]);
assertEquals([21, 22, 12, 14, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [23, 24], 1);
assertEquals([21, 23, 24, 14, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)}, RangeError);
assertEquals([21, 23, 24, 14, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [25, 26]);
assertEquals([21, 23, 25, 26, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [27], 1);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
SetHelper(lengthTracking, [28, 29, 30, 31, 32, 33]);
assertEquals([28, 29, 30, 31, 32, 33], ToNumbers(taFull));
SetHelper(lengthTracking, [34, 35, 36, 37, 38], 1);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [39, 40, 41, 42]);
assertEquals([28, 34, 39, 40, 41, 42], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [43, 44, 45], 1);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
}
})();
(function SetSourceLengthGetterGrowsTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateGsabForTest(ctor) {
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(gsab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return gsab;
}
let gsab;
let growTo;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
gsab.grow(growTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Test that we still throw for lengthTracking TAs if the source length is
// too large, even though we resized in the length getter (we check against
// the original length).
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const lengthTracking = new ctor(gsab, 0);
growTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTracking.set(CreateSourceProxy(6)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(gsab)));
}
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT);
growTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(6)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(gsab)));
}
})();
(function SetGrowTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateGsabForTest(ctor) {
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(gsab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return gsab;
}
let gsab;
// Growing will happen when we're calling Get for the `growAt`:th data
// element, but we haven't yet written it to the target.
let growAt;
let growTo;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == growAt) {
gsab.grow(growTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const fixedLength = new ctor(gsab, 0, 4);
growAt = 2;
growTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4));
assertEquals([1, 1, 1, 1], ToNumbers(fixedLength));
assertEquals([1, 1, 1, 1, 0, 0], ToNumbers(new ctor(gsab)));
}
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2);
growAt = 1;
growTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1], ToNumbers(fixedLengthWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(gsab)));
}
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const lengthTracking = new ctor(gsab, 0);
growAt = 2;
growTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(lengthTracking));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(new ctor(gsab)));
}
for (let ctor of ctors) {
gsab = CreateGsabForTest(ctor);
const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT);
growAt = 1;
growTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1, 0, 0], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(gsab)));
}
})();
(function SetWithGrowableSource() {
for (let targetIsGrowable of [false, true]) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
const gsab = CreateGrowableSharedArrayBuffer(
4 * sourceCtor.BYTES_PER_ELEMENT,
8 * sourceCtor.BYTES_PER_ELEMENT);
const fixedLength = new sourceCtor(gsab, 0, 4);
const fixedLengthWithOffset = new sourceCtor(
gsab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new sourceCtor(gsab, 0);
const lengthTrackingWithOffset = new sourceCtor(
gsab, 2 * sourceCtor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new sourceCtor(gsab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, ...] << lengthTracking
// [3, 4, ...] << lengthTrackingWithOffset
const targetAb = targetIsGrowable ?
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT) :
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT,
{maxByteLength: 8 * targetCtor.BYTES_PER_ELEMENT});
const target = new targetCtor(targetAb);
if (IsBigIntTypedArray(target) != IsBigIntTypedArray(taFull)) {
// Can't mix BigInt and non-BigInt types.
continue;
}
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 1);
assertEquals([3, 1, 2, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([3, 3, 4, 3, 4, 0], ToNumbers(target));
// Grow.
gsab.grow(6 * sourceCtor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, 5, 6, ...] << lengthTracking
// [3, 4, 5, 6, ...] << lengthTrackingWithOffset
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 0);
assertEquals([1, 2, 3, 4, 5, 6], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([1, 3, 4, 5, 6, 6], ToNumbers(target));
}
}
}
})();

View File

@ -176,6 +176,20 @@ function LastIndexOfHelper(array, n, fromIndex) {
return array.lastIndexOf(n, fromIndex);
}
function SetHelper(target, source, offset) {
if (target instanceof BigInt64Array || target instanceof BigUint64Array) {
const bigIntSource = [];
for (s of source) {
bigIntSource.push(BigInt(s));
}
source = bigIntSource;
}
if (offset == undefined) {
return target.set(source);
}
return target.set(source, offset);
}
function testDataViewMethodsUpToSize(view, bufferSize) {
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
for (let i = 0; i <= bufferSize - size; ++i) {

View File

@ -1125,3 +1125,156 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
Helper(lengthTracking));
}
})();
(function SetSourceLengthGetterDetachesTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
%ArrayBufferDetach(rab);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Tests where the length getter returns a non-zero value -> these throw.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
assertThrows(() => { fixedLength.set(CreateSourceProxy(1)); }, TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
assertThrows(() => { fixedLengthWithOffset.set(CreateSourceProxy(1)); },
TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
assertThrows(() => { lengthTracking.set(CreateSourceProxy(1)); },
TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(1)); },
TypeError);
}
// Tests where the length getter returns a zero -> these don't throw.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
fixedLength.set(CreateSourceProxy(0));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
fixedLengthWithOffset.set(CreateSourceProxy(0));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
lengthTracking.set(CreateSourceProxy(0));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
lengthTrackingWithOffset.set(CreateSourceProxy(0));
}
})();
(function SetDetachTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
// Detaching will happen when we're calling Get for the `detachAt`:th data
// element, but we haven't yet written it to the target.
let detachAt;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == detachAt) {
%ArrayBufferDetach(rab);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
detachAt = 2;
assertThrows(() => { fixedLength.set(CreateSourceProxy(4)); }, TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
detachAt = 2;
assertThrows(() => { fixedLengthWithOffset.set(CreateSourceProxy(2)); },
TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
detachAt = 2;
assertThrows(() => { lengthTracking.set(CreateSourceProxy(2)); },
TypeError);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
detachAt = 2;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(2)); },
TypeError);
}
})();

View File

@ -5173,3 +5173,628 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
assertEquals([10, 8, 6, 4, 0, 2], ToNumbers(wholeArrayView));
}
})();
(function SetWithResizableTarget() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const taFull = new ctor(rab);
// Orig. array: [0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, ...] << lengthTracking
// [0, 0, ...] << lengthTrackingWithOffset
// For making sure we're not calling the source length or element getters
// if the target is OOB.
const throwingProxy = new Proxy({}, {
get(target, prop, receiver) {
throw new Error('Called getter for ' + prop);
}});
SetHelper(fixedLength, [1, 2]);
assertEquals([1, 2, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [3, 4], 1);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [5, 6]);
assertEquals([1, 3, 5, 6], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [7], 1);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [8, 9]);
assertEquals([8, 9, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [10, 11], 1);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [12, 13]);
assertEquals([8, 10, 12, 13], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [14], 1);
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0])});
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0], 1)});
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [8, 10, 12]
// [8, 10, 12, ...] << lengthTracking
// [12, ...] << lengthTrackingWithOffset
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertEquals([8, 10, 12], ToNumbers(taFull));
SetHelper(lengthTracking, [15, 16]);
assertEquals([15, 16, 12], ToNumbers(taFull));
SetHelper(lengthTracking, [17, 18], 1);
assertEquals([15, 17, 18], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0], 1)}, RangeError);
assertEquals([15, 17, 18], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [19]);
assertEquals([15, 17, 19], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0], 1)},
RangeError);
assertEquals([15, 17, 19], ToNumbers(taFull));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, throwingProxy)},
TypeError);
assertEquals([15], ToNumbers(taFull));
SetHelper(lengthTracking, [20]);
assertEquals([20], ToNumbers(taFull));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTracking, [0])}, RangeError);
assertEquals([], ToNumbers(taFull));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 0, 0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, 0, 0, ...] << lengthTracking
// [0, 0, 0, 0, ...] << lengthTrackingWithOffset
SetHelper(fixedLength, [21, 22]);
assertEquals([21, 22, 0, 0, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [23, 24], 1);
assertEquals([21, 23, 24, 0, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)}, RangeError);
assertEquals([21, 23, 24, 0, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [25, 26]);
assertEquals([21, 23, 25, 26, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [27], 1);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
SetHelper(lengthTracking, [28, 29, 30, 31, 32, 33]);
assertEquals([28, 29, 30, 31, 32, 33], ToNumbers(taFull));
SetHelper(lengthTracking, [34, 35, 36, 37, 38], 1);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [39, 40, 41, 42]);
assertEquals([28, 34, 39, 40, 41, 42], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [43, 44, 45], 1);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
}
})();
(function SetSourceLengthGetterShrinksTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
let resizeTo;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Tests where the length getter returns a non-zero value -> these throw if
// the TA went OOB.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { fixedLength.set(CreateSourceProxy(1)); }, TypeError);
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { fixedLengthWithOffset.set(CreateSourceProxy(1)); },
TypeError);
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(1));
assertEquals([1, 2, 4], ToNumbers(lengthTracking));
assertEquals([1, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(1));
assertEquals([1], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(1)); },
TypeError);
assertEquals([0], ToNumbers(new ctor(rab)));
}
// Tests where the length getter returns a zero -> these don't throw even if
// the TA went OOB.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0));
assertEquals([0], ToNumbers(new ctor(rab)));
}
})();
(function SetSourceLengthGetterGrowsTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
let resizeTo;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Test that we still throw for lengthTracking TAs if the source length is
// too large, even though we resized in the length getter (we check against
// the original length).
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTracking.set(CreateSourceProxy(6)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(4)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
})();
(function SetShrinkTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
let resizeAt;
let resizeTo;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { fixedLength.set(CreateSourceProxy(4)); }, TypeError);
assertEquals([1, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { fixedLengthWithOffset.set(CreateSourceProxy(2)); },
TypeError);
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2));
assertEquals([1, 1, 4], ToNumbers(lengthTracking));
assertEquals([1, 1, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([1], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 1;
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(2)); },
TypeError);
assertEquals([0], ToNumbers(new ctor(rab)));
}
})();
(function SetGrowTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
let resizeAt;
let resizeTo;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAt = 2;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4));
assertEquals([1, 1, 1, 1], ToNumbers(fixedLength));
assertEquals([1, 1, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAt = 1;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1], ToNumbers(fixedLengthWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAt = 2;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(lengthTracking));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 1;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1, 0, 0], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
})();
(function SetWithResizableSource() {
for (let targetIsResizable of [false, true]) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
const rab = CreateResizableArrayBuffer(
4 * sourceCtor.BYTES_PER_ELEMENT,
8 * sourceCtor.BYTES_PER_ELEMENT);
const fixedLength = new sourceCtor(rab, 0, 4);
const fixedLengthWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new sourceCtor(rab, 0);
const lengthTrackingWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new sourceCtor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, ...] << lengthTracking
// [3, 4, ...] << lengthTrackingWithOffset
const targetAb = targetIsResizable ?
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT) :
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT,
{maxByteLength: 8 * targetCtor.BYTES_PER_ELEMENT});
const target = new targetCtor(targetAb);
if (IsBigIntTypedArray(target) != IsBigIntTypedArray(taFull)) {
// Can't mix BigInt and non-BigInt types.
continue;
}
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 1);
assertEquals([3, 1, 2, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([3, 3, 4, 3, 4, 0], ToNumbers(target));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * sourceCtor.BYTES_PER_ELEMENT);
// Orig. array: [1, 2, 3]
// [1, 2, 3, ...] << lengthTracking
// [3, ...] << lengthTrackingWithOffset
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertEquals([3, 3, 4, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTracking);
assertEquals([1, 2, 3, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset);
assertEquals([3, 2, 3, 3, 4, 0], ToNumbers(target));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * sourceCtor.BYTES_PER_ELEMENT);
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertThrows(() => { SetHelper(target, lengthTrackingWithOffset)},
TypeError);
SetHelper(target, lengthTracking, 3);
assertEquals([3, 2, 3, 1, 4, 0], ToNumbers(target));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertThrows(() => { SetHelper(target, lengthTrackingWithOffset)},
TypeError);
SetHelper(target, lengthTracking, 4);
assertEquals([3, 2, 3, 1, 4, 0], ToNumbers(target));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * sourceCtor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, 5, 6, ...] << lengthTracking
// [3, 4, 5, 6, ...] << lengthTrackingWithOffset
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 0);
assertEquals([1, 2, 3, 4, 5, 6], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([1, 3, 4, 5, 6, 6], ToNumbers(target));
}
}
}
})();

View File

@ -283,9 +283,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=11111
'built-ins/ArrayBuffer/prototype/transfer/*': [FAIL],
'built-ins/ArrayBuffer/prototype/transfer/this-is-sharedarraybuffer': [PASS],
'built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-target-out-of-bounds': [SKIP],
'built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-same-buffer-same-type-resized': [SKIP],
'built-ins/TypedArray/prototype/set/typedarray-arg-target-out-of-bounds': [SKIP],
'built-ins/TypedArray/prototype/sort/BigInt/return-abrupt-from-this-out-of-bounds': [FAIL],
'built-ins/TypedArray/prototype/sort/return-abrupt-from-this-out-of-bounds': [FAIL],
'built-ins/TypedArrayConstructors/ctors/typedarray-arg/out-of-bounds-when-species-retrieved-different-type': [FAIL],