[rab / gsab] Add RAB / GSAB support to TA.p.indexOf & lastIndexOf
Bug: v8:11111 Change-Id: I243832c05b6eb1ba2f13dc98f9b8fb177b351112 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3315438 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Shu-yu Guo <syg@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/main@{#78317}
This commit is contained in:
parent
35ae63443b
commit
bd2fce5773
@ -246,7 +246,7 @@ BUILTIN(TypedArrayPrototypeIndexOf) {
|
||||
isolate, array,
|
||||
JSTypedArray::Validate(isolate, args.receiver(), method_name));
|
||||
|
||||
int64_t len = array->length();
|
||||
int64_t len = array->GetLength();
|
||||
if (len == 0) return Smi::FromInt(-1);
|
||||
|
||||
int64_t index = 0;
|
||||
@ -259,6 +259,14 @@ BUILTIN(TypedArrayPrototypeIndexOf) {
|
||||
|
||||
if (V8_UNLIKELY(array->WasDetached())) return Smi::FromInt(-1);
|
||||
|
||||
if (V8_UNLIKELY(array->IsVariableLength())) {
|
||||
bool out_of_bounds = false;
|
||||
array->GetLengthOrOutOfBounds(out_of_bounds);
|
||||
if (out_of_bounds) {
|
||||
return Smi::FromInt(-1);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Object> search_element = args.atOrUndefined(isolate, 1);
|
||||
ElementsAccessor* elements = array->GetElementsAccessor();
|
||||
Maybe<int64_t> result =
|
||||
@ -276,7 +284,7 @@ BUILTIN(TypedArrayPrototypeLastIndexOf) {
|
||||
isolate, array,
|
||||
JSTypedArray::Validate(isolate, args.receiver(), method_name));
|
||||
|
||||
int64_t len = array->length();
|
||||
int64_t len = array->GetLength();
|
||||
if (len == 0) return Smi::FromInt(-1);
|
||||
|
||||
int64_t index = len - 1;
|
||||
@ -291,8 +299,14 @@ BUILTIN(TypedArrayPrototypeLastIndexOf) {
|
||||
|
||||
if (index < 0) return Smi::FromInt(-1);
|
||||
|
||||
// TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
|
||||
if (V8_UNLIKELY(array->WasDetached())) return Smi::FromInt(-1);
|
||||
if (V8_UNLIKELY(array->IsVariableLength())) {
|
||||
bool out_of_bounds = false;
|
||||
array->GetLengthOrOutOfBounds(out_of_bounds);
|
||||
if (out_of_bounds) {
|
||||
return Smi::FromInt(-1);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Object> search_element = args.atOrUndefined(isolate, 1);
|
||||
ElementsAccessor* elements = array->GetElementsAccessor();
|
||||
|
@ -220,6 +220,11 @@ inline bool IsBigIntTypedArrayElementsKind(ElementsKind kind) {
|
||||
kind == RAB_GSAB_BIGUINT64_ELEMENTS;
|
||||
}
|
||||
|
||||
inline bool IsFloatTypedArrayElementsKind(ElementsKind kind) {
|
||||
return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS ||
|
||||
kind == RAB_GSAB_FLOAT32_ELEMENTS || kind == RAB_GSAB_FLOAT64_ELEMENTS;
|
||||
}
|
||||
|
||||
inline bool IsWasmArrayElementsKind(ElementsKind kind) {
|
||||
return kind == WASM_ARRAY_ELEMENTS;
|
||||
}
|
||||
|
@ -3407,13 +3407,29 @@ class TypedElementsAccessor
|
||||
DisallowGarbageCollection no_gc;
|
||||
JSTypedArray typed_array = JSTypedArray::cast(*receiver);
|
||||
|
||||
if (typed_array.WasDetached()) return Just<int64_t>(-1);
|
||||
// If this is called via Array.prototype.indexOf (not
|
||||
// TypedArray.prototype.indexOf), it's possible that the TypedArray is
|
||||
// detached / out of bounds here.
|
||||
if V8_UNLIKELY (typed_array.WasDetached()) return Just<int64_t>(-1);
|
||||
bool out_of_bounds = false;
|
||||
size_t typed_array_length =
|
||||
typed_array.GetLengthOrOutOfBounds(out_of_bounds);
|
||||
if V8_UNLIKELY (out_of_bounds) {
|
||||
return Just<int64_t>(-1);
|
||||
}
|
||||
|
||||
// Prototype has no elements, and not searching for the hole --- limit
|
||||
// search to backing store length.
|
||||
if (typed_array_length < length) {
|
||||
length = typed_array_length;
|
||||
}
|
||||
|
||||
ElementType typed_search_value;
|
||||
|
||||
ElementType* data_ptr =
|
||||
reinterpret_cast<ElementType*>(typed_array.DataPtr());
|
||||
if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
|
||||
|
||||
if (IsBigIntTypedArrayElementsKind(Kind)) {
|
||||
if (!value->IsBigInt()) return Just<int64_t>(-1);
|
||||
bool lossless;
|
||||
typed_search_value = FromHandle(value, &lossless);
|
||||
@ -3423,7 +3439,7 @@ class TypedElementsAccessor
|
||||
double search_value = value->Number();
|
||||
if (!std::isfinite(search_value)) {
|
||||
// Integral types cannot represent +Inf or NaN.
|
||||
if (Kind < FLOAT32_ELEMENTS || Kind > FLOAT64_ELEMENTS) {
|
||||
if (!IsFloatTypedArrayElementsKind(Kind)) {
|
||||
return Just<int64_t>(-1);
|
||||
}
|
||||
if (std::isnan(search_value)) {
|
||||
@ -3440,12 +3456,6 @@ class TypedElementsAccessor
|
||||
}
|
||||
}
|
||||
|
||||
// Prototype has no elements, and not searching for the hole --- limit
|
||||
// search to backing store length.
|
||||
if (typed_array.length() < length) {
|
||||
length = typed_array.length();
|
||||
}
|
||||
|
||||
auto is_shared = typed_array.buffer().is_shared() ? kShared : kUnshared;
|
||||
for (size_t k = start_from; k < length; ++k) {
|
||||
ElementType elem_k = AccessorClass::GetImpl(data_ptr + k, is_shared);
|
||||
@ -3461,12 +3471,17 @@ class TypedElementsAccessor
|
||||
JSTypedArray typed_array = JSTypedArray::cast(*receiver);
|
||||
|
||||
DCHECK(!typed_array.WasDetached());
|
||||
#if DEBUG
|
||||
bool out_of_bounds = false;
|
||||
typed_array.GetLengthOrOutOfBounds(out_of_bounds);
|
||||
DCHECK(!out_of_bounds);
|
||||
#endif
|
||||
|
||||
ElementType typed_search_value;
|
||||
|
||||
ElementType* data_ptr =
|
||||
reinterpret_cast<ElementType*>(typed_array.DataPtr());
|
||||
if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
|
||||
if (IsBigIntTypedArrayElementsKind(Kind)) {
|
||||
if (!value->IsBigInt()) return Just<int64_t>(-1);
|
||||
bool lossless;
|
||||
typed_search_value = FromHandle(value, &lossless);
|
||||
@ -3493,7 +3508,14 @@ class TypedElementsAccessor
|
||||
}
|
||||
}
|
||||
|
||||
DCHECK_LT(start_from, typed_array.length());
|
||||
size_t typed_array_length = typed_array.GetLength();
|
||||
if (start_from >= typed_array_length) {
|
||||
// This can happen if the TypedArray got resized when we did ToInteger
|
||||
// on the last parameter of lastIndexOf.
|
||||
DCHECK(typed_array.IsVariableLength());
|
||||
start_from = typed_array_length - 1;
|
||||
}
|
||||
|
||||
size_t k = start_from;
|
||||
auto is_shared = typed_array.buffer().is_shared() ? kShared : kUnshared;
|
||||
do {
|
||||
|
@ -2213,11 +2213,6 @@ function TestIterationAndGrow(ta, expected, gsab, grow_after,
|
||||
})();
|
||||
|
||||
(function IncludesSpecialValues() {
|
||||
const floatCtors = [
|
||||
Float32Array,
|
||||
Float64Array,
|
||||
MyFloat32Array
|
||||
];
|
||||
for (let ctor of floatCtors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
@ -2230,3 +2225,229 @@ function TestIterationAndGrow(ta, expected, gsab, grow_after,
|
||||
assertTrue(lengthTracking.includes(NaN));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfLastIndexOf() {
|
||||
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 taWrite = new ctor(gsab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
|
||||
}
|
||||
|
||||
// Orig. array: [0, 0, 1, 1]
|
||||
// [0, 0, 1, 1] << fixedLength
|
||||
// [1, 1] << fixedLengthWithOffset
|
||||
// [0, 0, 1, 1, ...] << lengthTracking
|
||||
// [1, 1, ...] << lengthTrackingWithOffset
|
||||
|
||||
assertEquals(0, IndexOfHelper(fixedLength, 0));
|
||||
assertEquals(1, IndexOfHelper(fixedLength, 0, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 0, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 0, -2));
|
||||
assertEquals(1, IndexOfHelper(fixedLength, 0, -3));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, 1));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, -3));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, -2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 1));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, 1));
|
||||
assertEquals(2, LastIndexOfHelper(fixedLength, 1, -2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1, -2));
|
||||
assertEquals(1, IndexOfHelper(fixedLengthWithOffset, 1, -1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(0, LastIndexOfHelper(fixedLengthWithOffset, 1, -2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1, -1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0, 2));
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 1, -3));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, 2));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, 1));
|
||||
assertEquals(2, LastIndexOfHelper(lengthTracking, 1, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(1, IndexOfHelper(lengthTrackingWithOffset, 1, 1));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1, -2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, 1));
|
||||
assertEquals(0, LastIndexOfHelper(lengthTrackingWithOffset, 1, -2));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, -1));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
// Grow.
|
||||
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
|
||||
}
|
||||
|
||||
// Orig. array: [0, 0, 1, 1, 2, 2]
|
||||
// [0, 0, 1, 1] << fixedLength
|
||||
// [1, 1] << fixedLengthWithOffset
|
||||
// [0, 0, 1, 1, 2, 2, ...] << lengthTracking
|
||||
// [1, 1, 2, 2, ...] << lengthTrackingWithOffset
|
||||
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(3, LastIndexOfHelper(fixedLength, 1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 1));
|
||||
assertEquals(4, IndexOfHelper(lengthTracking, 2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(3, LastIndexOfHelper(lengthTracking, 1));
|
||||
assertEquals(5, LastIndexOfHelper(lengthTracking, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(2, IndexOfHelper(lengthTrackingWithOffset, 2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(3, LastIndexOfHelper(lengthTrackingWithOffset, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfParameterConversionGrows() {
|
||||
// Growing + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(gsab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, 1);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0));
|
||||
// The TA grew but we only look at the data until the original length.
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
// Growing + length-tracking TA, index conversion.
|
||||
for (let ctor of ctors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(gsab);
|
||||
WriteToTypedArray(lengthTracking, 0, 1);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -4;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 1, -4));
|
||||
// The TA grew but the start index conversion is done based on the original
|
||||
// length.
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 1, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function LastIndexOfParameterConversionGrows() {
|
||||
// Growing + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(gsab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, 1);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -1;
|
||||
}};
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0));
|
||||
// Because lastIndexOf iterates from the given index downwards, it's not
|
||||
// possible to test that "we only look at the data until the original
|
||||
// length" without also testing that the index conversion happening with the
|
||||
// original length.
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
// Growing + length-tracking TA, index conversion.
|
||||
for (let ctor of ctors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(gsab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -4;
|
||||
}};
|
||||
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, -4));
|
||||
// The TA grew but the start index conversion is done based on the original
|
||||
// length.
|
||||
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfLastIndexOfSpecialValues() {
|
||||
for (let ctor of floatCtors) {
|
||||
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(gsab);
|
||||
lengthTracking[0] = -Infinity;
|
||||
lengthTracking[1] = -Infinity;
|
||||
lengthTracking[2] = Infinity;
|
||||
lengthTracking[3] = Infinity;
|
||||
lengthTracking[4] = NaN;
|
||||
lengthTracking[5] = NaN;
|
||||
assertEquals(0, lengthTracking.indexOf(-Infinity));
|
||||
assertEquals(1, lengthTracking.lastIndexOf(-Infinity));
|
||||
assertEquals(2, lengthTracking.indexOf(Infinity));
|
||||
assertEquals(3, lengthTracking.lastIndexOf(Infinity));
|
||||
// NaN is never found.
|
||||
assertEquals(-1, lengthTracking.indexOf(NaN));
|
||||
assertEquals(-1, lengthTracking.lastIndexOf(NaN));
|
||||
}
|
||||
})();
|
||||
|
@ -22,6 +22,12 @@ const ctors = [
|
||||
MyBigInt64Array,
|
||||
];
|
||||
|
||||
const floatCtors = [
|
||||
Float32Array,
|
||||
Float64Array,
|
||||
MyFloat32Array
|
||||
];
|
||||
|
||||
// Each element of the following array is [getter, setter, size, isBigInt].
|
||||
const dataViewAccessorsAndSizes = [[DataView.prototype.getUint8,
|
||||
DataView.prototype.setUint8, 1, false],
|
||||
@ -131,6 +137,41 @@ function IncludesHelper(array, n, fromIndex) {
|
||||
return array.includes(n, fromIndex);
|
||||
}
|
||||
|
||||
function IndexOfHelper(array, n, fromIndex) {
|
||||
if (typeof n == 'number' &&
|
||||
(array instanceof BigInt64Array || array instanceof BigUint64Array)) {
|
||||
if (fromIndex == undefined) {
|
||||
// Technically, passing fromIndex here would still result in the correct
|
||||
// behavior, since "undefined" gets converted to 0 which is a good
|
||||
// "default" index.
|
||||
return array.indexOf(BigInt(n));
|
||||
}
|
||||
return array.indexOf(BigInt(n), fromIndex);
|
||||
}
|
||||
if (fromIndex == undefined) {
|
||||
return array.indexOf(n);
|
||||
}
|
||||
return array.indexOf(n, fromIndex);
|
||||
}
|
||||
|
||||
function LastIndexOfHelper(array, n, fromIndex) {
|
||||
if (typeof n == 'number' &&
|
||||
(array instanceof BigInt64Array || array instanceof BigUint64Array)) {
|
||||
if (fromIndex == undefined) {
|
||||
// Shouldn't pass fromIndex here, since passing "undefined" is not the
|
||||
// same as not passing the parameter at all. "Undefined" will get
|
||||
// converted to 0 which is not a good "default" index, since lastIndexOf
|
||||
// iterates from the index downwards.
|
||||
return array.lastIndexOf(BigInt(n));
|
||||
}
|
||||
return array.lastIndexOf(BigInt(n), fromIndex);
|
||||
}
|
||||
if (fromIndex == undefined) {
|
||||
return array.lastIndexOf(n);
|
||||
}
|
||||
return array.lastIndexOf(n, fromIndex);
|
||||
}
|
||||
|
||||
function testDataViewMethodsUpToSize(view, bufferSize) {
|
||||
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
|
||||
for (let i = 0; i <= bufferSize - size; ++i) {
|
||||
|
@ -805,3 +805,63 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
assertFalse(IncludesHelper(fixedLength, 0, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfParameterConversionDetaches() {
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 0));
|
||||
// The buffer is detached so indexOf returns -1.
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 0));
|
||||
// The buffer is detached so indexOf returns -1, also for undefined).
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function LastIndexOfParameterConversionDetaches() {
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 2;
|
||||
}};
|
||||
assertEquals(3, LastIndexOfHelper(lengthTracking, 0));
|
||||
// The buffer is detached so lastIndexOf returns -1.
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
%ArrayBufferDetach(rab);
|
||||
return 2;
|
||||
}};
|
||||
assertEquals(3, LastIndexOfHelper(lengthTracking, 0));
|
||||
// The buffer is detached so lastIndexOf returns -1, also for undefined).
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined, evil));
|
||||
}
|
||||
})();
|
||||
|
@ -4017,11 +4017,6 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
|
||||
})();
|
||||
|
||||
(function IncludesSpecialValues() {
|
||||
const floatCtors = [
|
||||
Float32Array,
|
||||
Float64Array,
|
||||
MyFloat32Array
|
||||
];
|
||||
for (let ctor of floatCtors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
@ -4034,3 +4029,386 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
|
||||
assertTrue(lengthTracking.includes(NaN));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfLastIndexOf() {
|
||||
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);
|
||||
|
||||
// Write some data into the array.
|
||||
const taWrite = new ctor(rab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
|
||||
}
|
||||
|
||||
// Orig. array: [0, 0, 1, 1]
|
||||
// [0, 0, 1, 1] << fixedLength
|
||||
// [1, 1] << fixedLengthWithOffset
|
||||
// [0, 0, 1, 1, ...] << lengthTracking
|
||||
// [1, 1, ...] << lengthTrackingWithOffset
|
||||
|
||||
assertEquals(0, IndexOfHelper(fixedLength, 0));
|
||||
assertEquals(1, IndexOfHelper(fixedLength, 0, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 0, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 0, -2));
|
||||
assertEquals(1, IndexOfHelper(fixedLength, 0, -3));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, 1));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, -3));
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1, -2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 1));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, 1));
|
||||
assertEquals(2, LastIndexOfHelper(fixedLength, 1, -2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1, -2));
|
||||
assertEquals(1, IndexOfHelper(fixedLengthWithOffset, 1, -1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(0, LastIndexOfHelper(fixedLengthWithOffset, 1, -2));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1, -1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0, 2));
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 1, -3));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, 2));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, 1));
|
||||
assertEquals(2, LastIndexOfHelper(lengthTracking, 1, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, -3));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(1, IndexOfHelper(lengthTrackingWithOffset, 1, 1));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1, -2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, 1));
|
||||
assertEquals(0, LastIndexOfHelper(lengthTrackingWithOffset, 1, -2));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, -1));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
// Shrink so that fixed length TAs go out of bounds.
|
||||
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
|
||||
|
||||
// Orig. array: [0, 0, 1]
|
||||
// [0, 0, 1, ...] << lengthTracking
|
||||
// [1, ...] << lengthTrackingWithOffset
|
||||
|
||||
assertThrows(() => { IndexOfHelper(fixedLength, 1); });
|
||||
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 1); });
|
||||
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLength, 1); });
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 1); });
|
||||
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 1));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(1, LastIndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, LastIndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
// Shrink so that the TAs with offset go out of bounds.
|
||||
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
|
||||
|
||||
assertThrows(() => { IndexOfHelper(fixedLength, 0); });
|
||||
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 0); });
|
||||
assertThrows(() => { IndexOfHelper(lengthTrackingWithOffset, 0); });
|
||||
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLength, 0); });
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 0); });
|
||||
assertThrows(() => { LastIndexOfHelper(lengthTrackingWithOffset, 0); });
|
||||
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 0));
|
||||
|
||||
assertEquals(0, LastIndexOfHelper(lengthTracking, 0));
|
||||
|
||||
// Shrink to zero.
|
||||
rab.resize(0);
|
||||
|
||||
assertThrows(() => { IndexOfHelper(fixedLength, 0); });
|
||||
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 0); });
|
||||
assertThrows(() => { IndexOfHelper(lengthTrackingWithOffset, 0); });
|
||||
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLength, 0); });
|
||||
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 0); });
|
||||
assertThrows(() => { LastIndexOfHelper(lengthTrackingWithOffset, 0); });
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
// Grow so that all TAs are back in-bounds.
|
||||
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
|
||||
}
|
||||
|
||||
// Orig. array: [0, 0, 1, 1, 2, 2]
|
||||
// [0, 0, 1, 1] << fixedLength
|
||||
// [1, 1] << fixedLengthWithOffset
|
||||
// [0, 0, 1, 1, 2, 2, ...] << lengthTracking
|
||||
// [1, 1, 2, 2, ...] << lengthTrackingWithOffset
|
||||
|
||||
assertEquals(2, IndexOfHelper(fixedLength, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(3, LastIndexOfHelper(fixedLength, 1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 2));
|
||||
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
|
||||
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 1));
|
||||
assertEquals(4, IndexOfHelper(lengthTracking, 2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(3, LastIndexOfHelper(lengthTracking, 1));
|
||||
assertEquals(5, LastIndexOfHelper(lengthTracking, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
|
||||
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(2, IndexOfHelper(lengthTrackingWithOffset, 2));
|
||||
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
|
||||
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
|
||||
assertEquals(3, LastIndexOfHelper(lengthTrackingWithOffset, 2));
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfParameterConversionShrinks() {
|
||||
// Shinking + fixed-length TA.
|
||||
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);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(fixedLength, 0));
|
||||
// The TA is OOB so indexOf returns -1.
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, 0, evil));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(fixedLength, 0));
|
||||
// The TA is OOB so indexOf returns -1, also for undefined).
|
||||
assertEquals(-1, IndexOfHelper(fixedLength, undefined, evil));
|
||||
}
|
||||
|
||||
// Shrinking + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, i);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(2, IndexOfHelper(lengthTracking, 2));
|
||||
// 2 no longer found.
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 2, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function LastIndexOfParameterConversionShrinks() {
|
||||
// Shinking + fixed-length TA.
|
||||
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);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 2;
|
||||
}};
|
||||
assertEquals(3, LastIndexOfHelper(fixedLength, 0));
|
||||
// The TA is OOB so lastIndexOf returns -1.
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, 0, evil));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 2;
|
||||
}};
|
||||
assertEquals(3, LastIndexOfHelper(fixedLength, 0));
|
||||
// The TA is OOB so lastIndexOf returns -1, also for undefined).
|
||||
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined, evil));
|
||||
}
|
||||
|
||||
// Shrinking + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, i);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||
return 2;
|
||||
}};
|
||||
assertEquals(2, LastIndexOfHelper(lengthTracking, 2));
|
||||
// 2 no longer found.
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 2, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfParameterConversionGrows() {
|
||||
// Growing + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, 1);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return 0;
|
||||
}};
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0));
|
||||
// The TA grew but we only look at the data until the original length.
|
||||
assertEquals(-1, IndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
// Growing + length-tracking TA, index conversion.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
WriteToTypedArray(lengthTracking, 0, 1);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -4;
|
||||
}};
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 1, -4));
|
||||
// The TA grew but the start index conversion is done based on the original
|
||||
// length.
|
||||
assertEquals(0, IndexOfHelper(lengthTracking, 1, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function LastIndexOfParameterConversionGrows() {
|
||||
// Growing + length-tracking TA.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
WriteToTypedArray(lengthTracking, i, 1);
|
||||
}
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -1;
|
||||
}};
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0));
|
||||
// Because lastIndexOf iterates from the given index downwards, it's not
|
||||
// possible to test that "we only look at the data until the original
|
||||
// length" without also testing that the index conversion happening with the
|
||||
// original length.
|
||||
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
|
||||
// Growing + length-tracking TA, index conversion.
|
||||
for (let ctor of ctors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
|
||||
let evil = { valueOf: () => {
|
||||
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||
return -4;
|
||||
}};
|
||||
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, -4));
|
||||
// The TA grew but the start index conversion is done based on the original
|
||||
// length.
|
||||
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, evil));
|
||||
}
|
||||
})();
|
||||
|
||||
(function IndexOfLastIndexOfSpecialValues() {
|
||||
for (let ctor of floatCtors) {
|
||||
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
|
||||
8 * ctor.BYTES_PER_ELEMENT);
|
||||
const lengthTracking = new ctor(rab);
|
||||
lengthTracking[0] = -Infinity;
|
||||
lengthTracking[1] = -Infinity;
|
||||
lengthTracking[2] = Infinity;
|
||||
lengthTracking[3] = Infinity;
|
||||
lengthTracking[4] = NaN;
|
||||
lengthTracking[5] = NaN;
|
||||
assertEquals(0, lengthTracking.indexOf(-Infinity));
|
||||
assertEquals(1, lengthTracking.lastIndexOf(-Infinity));
|
||||
assertEquals(2, lengthTracking.indexOf(Infinity));
|
||||
assertEquals(3, lengthTracking.lastIndexOf(Infinity));
|
||||
// NaN is never found.
|
||||
assertEquals(-1, lengthTracking.indexOf(NaN));
|
||||
assertEquals(-1, lengthTracking.lastIndexOf(NaN));
|
||||
}
|
||||
})();
|
||||
|
@ -283,12 +283,8 @@
|
||||
# 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/indexOf/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/indexOf/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/join/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/join/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/lastIndexOf/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/lastIndexOf/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/map/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/map/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
'built-ins/TypedArray/prototype/reverse/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
|
||||
|
Loading…
Reference in New Issue
Block a user