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

[rab/gsab] TA.p.copywithin: Support RAB / GSAB

Bug: v8:11111
Change-Id: Id1e37770f0f196db0887fceb14f895e576b78b73
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3173673Reviewed-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@{#77003}
parent ab836859
......@@ -51,7 +51,7 @@ BUILTIN(TypedArrayPrototypeCopyWithin) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
int64_t len = array->length();
int64_t len = array->GetLength();
int64_t to = 0;
int64_t from = 0;
int64_t final = len;
......@@ -86,6 +86,30 @@ BUILTIN(TypedArrayPrototypeCopyWithin) {
// (see )
if (V8_UNLIKELY(array->WasDetached())) return *array;
if (V8_UNLIKELY(array->is_backed_by_rab())) {
bool out_of_bounds = false;
int64_t new_len = array->GetLengthOrOutOfBounds(out_of_bounds);
if (out_of_bounds) {
const MessageTemplate message = MessageTemplate::kDetachedOperation;
Handle<String> operation =
isolate->factory()->NewStringFromAsciiChecked(method);
THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message, operation));
}
if (new_len < len) {
// We don't need to account for growing, since we only copy an already
// determined number of elements and growing won't change it. If to >
// new_len or from > new_len, the count below will be < 0, so we don't
// need to check them separately.
if (final > new_len) {
final = new_len;
}
count = std::min<int64_t>(final - from, new_len - to);
if (count <= 0) {
return *array;
}
}
}
// Ensure processed indexes are within array bounds
DCHECK_GE(from, 0);
DCHECK_LT(from, len);
......
......@@ -195,13 +195,13 @@ size_t JSTypedArray::GetLengthOrOutOfBounds(bool& out_of_bounds) const {
if (WasDetached()) return 0;
if (is_length_tracking()) {
if (is_backed_by_rab()) {
if (byte_offset() >= buffer().byte_length()) {
if (byte_offset() > buffer().byte_length()) {
out_of_bounds = true;
return 0;
}
return (buffer().byte_length() - byte_offset()) / element_size();
}
if (byte_offset() >=
if (byte_offset() >
buffer().GetBackingStore()->byte_length(std::memory_order_seq_cst)) {
out_of_bounds = true;
return 0;
......
......@@ -135,3 +135,14 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
FillHelper(fixedLength, 1, 0, evil);
}
})();
(function CopyWithinParameterConversionDetaches() {
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: () => { %ArrayBufferDetach(rab); return 2;}};
fixedLength.copyWithin(evil, 0, 1);
}
})();
......@@ -1406,3 +1406,170 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
assertEquals(0, a[3]);
}
})();
(function CopyWithin() {
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, i);
}
// Orig. array: [0, 1, 2, 3]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, ...] << lengthTracking
// [2, 3, ...] << lengthTrackingWithOffset
fixedLength.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(fixedLength));
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
fixedLengthWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(fixedLengthWithOffset));
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
lengthTracking.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(lengthTracking));
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(lengthTrackingWithOffset));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 3; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2]
// [0, 1, 2, ...] << lengthTracking
// [2, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.copyWithin(0, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1); });
lengthTracking.copyWithin(0, 1);
assertEquals([1, 2, 2], ToNumbers(lengthTracking));
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([2], ToNumbers(lengthTrackingWithOffset));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
WriteToTypedArray(taWrite, 0, 0);
assertThrows(() => { fixedLength.copyWithin(0, 1, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1, 1); });
lengthTracking.copyWithin(0, 0, 1);
assertEquals([0], ToNumbers(lengthTracking));
assertThrows(() => { lengthTrackingWithOffset.copyWithin(0, 1, 1); });
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.copyWithin(0, 1, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1, 1); });
lengthTracking.copyWithin(0, 0, 1);
assertEquals([], ToNumbers(lengthTracking));
assertThrows(() => { lengthTrackingWithOffset.copyWithin(0, 1, 1); });
// 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, i);
}
// Orig. array: [0, 1, 2, 3, 4, 5]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, 4, 5, ...] << lengthTracking
// [2, 3, 4, 5, ...] << lengthTrackingWithOffset
fixedLength.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(fixedLength));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
fixedLengthWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(fixedLengthWithOffset));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// [0, 1, 2, 3, 4, 5, ...] << lengthTracking
// target ^ ^ start
lengthTracking.copyWithin(0, 2);
assertEquals([2, 3, 4, 5, 4, 5], ToNumbers(lengthTracking));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// [2, 3, 4, 5, ...] << lengthTrackingWithOffset
// target ^ ^ start
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([3, 4, 5, 5], ToNumbers(lengthTrackingWithOffset));
}
})();
(function CopyWithinParameterConversionShrinks() {
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 evil = { valueOf: () => { rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 2;}};
assertThrows(() => { fixedLength.copyWithin(evil, 0, 1); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.copyWithin(0, evil, 3); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.copyWithin(0, 1, evil); }, TypeError);
}
})();
(function CopyWithinParameterConversionGrows() {
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);
}
const evil = { valueOf: () => { rab.resize(6 * ctor.BYTES_PER_ELEMENT);
WriteToTypedArray(lengthTracking, 4, 4);
WriteToTypedArray(lengthTracking, 5, 5);
return 0;} };
// Orig. array: [0, 1, 2, 3] [4, 5]
// ^ ^ ^ new elements
// target start
lengthTracking.copyWithin(evil, 2);
assertEquals([2, 3, 2, 3, 4, 5], ToNumbers(lengthTracking));
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, i);
}
// Orig. array: [0, 1, 2, 3] [4, 5]
// ^ ^ ^ new elements
// start target
lengthTracking.copyWithin(2, evil);
assertEquals([0, 1, 0, 1, 4, 5], ToNumbers(lengthTracking));
}
})();
......@@ -330,9 +330,6 @@
'built-ins/DataView/prototype/setUint16/resizable-buffer': [FAIL],
'built-ins/DataView/prototype/setUint32/resizable-buffer': [FAIL],
'built-ins/DataView/prototype/setUint8/resizable-buffer': [FAIL],
'built-ins/TypedArray/prototype/byteOffset/BigInt/resizable-array-buffer-auto': [FAIL],
'built-ins/TypedArray/prototype/copyWithin/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
'built-ins/TypedArray/prototype/copyWithin/return-abrupt-from-this-out-of-bounds': [SKIP],
'built-ins/TypedArray/prototype/entries/BigInt/return-abrupt-from-this-out-of-bounds': [FAIL],
'built-ins/TypedArray/prototype/entries/return-abrupt-from-this-out-of-bounds': [FAIL],
'built-ins/TypedArray/prototype/every/BigInt/return-abrupt-from-this-out-of-bounds': [SKIP],
......@@ -481,7 +478,8 @@
'harness/detachArrayBuffer': [SKIP],
'harness/detachArrayBuffer-host-detachArrayBuffer': [SKIP],
# Pending update after https://github.com/tc39/proposal-resizablearraybuffer/issues/68
# https://github.com/tc39/test262/issues/3206
'built-ins/TypedArray/prototype/byteOffset/BigInt/resizable-array-buffer-auto': [FAIL],
'built-ins/TypedArray/prototype/byteOffset/resizable-array-buffer-auto': [FAIL],
############################ SKIPPED TESTS #############################
......
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