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

[rab/gsab] TypedArray.prototype.at: Support RAB / GSAB

Bug: v8:11111
Change-Id: I0e7db9ca74b9d61f2e86581b0cd2f424ad006db9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3151958Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76785}
parent 471f8629
......@@ -154,13 +154,13 @@ TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
// Default to zero if the {receiver}s buffer was detached / out of bounds.
Label detached_or_oob(this), not_detached_or_oob(this);
Label detached_or_oob(this), not_detached_nor_oob(this);
IsTypedArrayDetachedOrOutOfBounds(CAST(receiver), &detached_or_oob,
&not_detached_or_oob);
&not_detached_nor_oob);
BIND(&detached_or_oob);
Return(ChangeUintPtrToTagged(UintPtrConstant(0)));
BIND(&not_detached_or_oob);
BIND(&not_detached_nor_oob);
Return(
ChangeUintPtrToTagged(LoadJSArrayBufferViewByteOffset(CAST(receiver))));
}
......@@ -255,9 +255,27 @@ TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
// If the typed array's buffer is detached, throw
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
// TODO(v8:11111): Throw if the RAB / GSAB is OOB.
return CAST(obj);
}
TNode<UintPtrT> TypedArrayBuiltinsAssembler::ValidateTypedArrayAndGetLength(
TNode<Context> context, TNode<Object> obj, const char* method_name) {
// If it is not a typed array, throw
ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
Label detached_or_oob(this), not_detached_nor_oob(this);
TNode<UintPtrT> length =
LoadJSTypedArrayLengthAndCheckDetached(CAST(obj), &detached_or_oob);
Goto(&not_detached_nor_oob);
BIND(&detached_or_oob);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
BIND(&not_detached_nor_oob);
return length;
}
void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<RawPtrT> dest_ptr,
TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length) {
......
......@@ -49,6 +49,10 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<Object> obj,
const char* method_name);
TNode<UintPtrT> ValidateTypedArrayAndGetLength(TNode<Context> context,
TNode<Object> obj,
const char* method_name);
void CallCMemmove(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length);
......
......@@ -8,9 +8,10 @@ transitioning javascript builtin TypedArrayPrototypeAt(
js-implicit context: NativeContext, receiver: JSAny)(index: JSAny): JSAny {
// 1. Let O be the this value.
// 2. Perform ? ValidateTypedArray(O).
const o = ValidateTypedArray(context, receiver, '%TypedArray%.prototype.at');
// 3. Let len be O.[[ArrayLength]].
const len = Convert<Number>(o.length);
// 3. Let len be IntegerIndexedObjectLength(O).
const len = Convert<Number>(ValidateTypedArrayAndGetLength(
context, receiver, '%TypedArray%.prototype.at'));
// 4. Let relativeIndex be ? ToInteger(index).
const relativeIndex = ToInteger_Inline(index);
// 5. If relativeIndex ≥ 0, then
......@@ -23,6 +24,6 @@ transitioning javascript builtin TypedArrayPrototypeAt(
return Undefined;
}
// 8. Return ? Get(O, ! ToString(k)).
return GetProperty(o, k);
return GetProperty(receiver, k);
}
}
......@@ -56,6 +56,8 @@ extern runtime TypedArrayCopyElements(
Context, JSTypedArray, Object, Number): void;
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray(
Context, JSAny, constexpr string): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArrayAndGetLength(
Context, JSAny, constexpr string): uintptr;
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
......@@ -85,6 +87,9 @@ extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
Context, JSTypedArray, uintptr, JSAny, constexpr ElementsKind)
labels IfDetached;
extern macro LoadJSTypedArrayLengthAndCheckDetached(JSTypedArray): uintptr
labels IfDetached;
type LoadNumericFn = builtin(JSTypedArray, uintptr) => Numeric;
type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi;
type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
// Flags: --harmony-rab-gsab --allow-natives-syntax
// Flags: --harmony-relative-indexing-methods
"use strict";
......@@ -687,3 +688,32 @@ function TestIterationAndGrow(ta, expected, gsab, grow_after,
assertEquals([15, 19, 19, 20, 16, 16], ReadDataFromBuffer(gsab, ctor));
}
})();
(function At() {
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.
let ta_write = new ctor(gsab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(ta_write, i, i);
}
assertEquals(3, AtHelper(fixedLength, -1));
assertEquals(3, AtHelper(lengthTracking, -1));
assertEquals(3, AtHelper(fixedLengthWithOffset, -1));
assertEquals(3, AtHelper(lengthTrackingWithOffset, -1));
// Grow. New memory is zeroed.
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
assertEquals(3, AtHelper(fixedLength, -1));
assertEquals(0, AtHelper(lengthTracking, -1));
assertEquals(3, AtHelper(fixedLengthWithOffset, -1));
assertEquals(0, AtHelper(lengthTrackingWithOffset, -1));
}
})();
......@@ -46,10 +46,18 @@ function ToNumbers(array) {
return result;
}
function FillHelper(ta, n, start, end) {
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
ta.fill(BigInt(n), start, end);
function AtHelper(array, index) {
let result = array.at(index);
if (typeof result == 'bigint') {
return Number(result);
}
return result;
}
function FillHelper(array, n, start, end) {
if (array instanceof BigInt64Array || array instanceof BigUint64Array) {
array.fill(BigInt(n), start, end);
} else {
ta.fill(n, start, end);
array.fill(n, start, end);
}
}
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
// Flags: --harmony-rab-gsab --allow-natives-syntax
// Flags: --harmony-relative-indexing-methods
"use strict";
......@@ -1156,3 +1157,70 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
assertThrows(() => { FillHelper(fixedLength, 3, 1, evil); }, TypeError);
}
})();
(function At() {
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.
let ta_write = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(ta_write, i, i);
}
assertEquals(3, AtHelper(fixedLength, -1));
assertEquals(3, AtHelper(lengthTracking, -1));
assertEquals(3, AtHelper(fixedLengthWithOffset, -1));
assertEquals(3, AtHelper(lengthTrackingWithOffset, -1));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { AtHelper(fixedLength, -1); });
assertThrows(() => { AtHelper(fixedLengthWithOffset, -1); });
assertEquals(2, AtHelper(lengthTracking, -1));
assertEquals(2, AtHelper(lengthTrackingWithOffset, -1));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { AtHelper(fixedLength, -1); });
assertThrows(() => { AtHelper(fixedLengthWithOffset, -1); });
assertEquals(0, AtHelper(lengthTracking, -1));
assertThrows(() => { AtHelper(lengthTrackingWithOffset, -1); });
// Grow so that all TAs are back in-bounds. New memory is zeroed.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
assertEquals(0, AtHelper(fixedLength, -1));
assertEquals(0, AtHelper(lengthTracking, -1));
assertEquals(0, AtHelper(fixedLengthWithOffset, -1));
assertEquals(0, AtHelper(lengthTrackingWithOffset, -1));
}
})();
(function AtParameterConversionResizes() {
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); return 0;}};
assertEquals(undefined, AtHelper(fixedLength, 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: () => { rab.resize(2); return -1;}};
// The TypedArray is *not* out of bounds since it's length-tracking.
assertEquals(undefined, AtHelper(lengthTracking, evil));
}
})();
This diff is collapsed.
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