Commit bd2fce57 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[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/+/3315438Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78317}
parent 35ae6344
......@@ -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],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment