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 {
......
......@@ -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));
}
})();
......@@ -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