RAB: Integrate staging tests for the .set method (#4173)

* Import relevant files from #3888

* Removing parts in resizableArrayBufferUtils.js and adding it in includes,
and renaming helper function.
This commit is contained in:
Ioanna M Dimitriou H 2024-08-05 23:09:41 +02:00 committed by GitHub
parent ea37a19a4a
commit c0942e0883
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1177 additions and 0 deletions

View File

@ -0,0 +1,113 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by resizable buffers
that are grown mid-iteration due to a Proxy source.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
function CreateSourceProxy(length, rab, resizeAt, resizeTo) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const resizeAt = 2;
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(fixedLength), [
1,
1,
1,
1
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
1,
1,
1,
1,
0,
0
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const resizeAt = 1;
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(fixedLengthWithOffset), [
1,
1
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
1,
1,
0,
0
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const resizeAt = 2;
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(lengthTracking), [
1,
1,
4,
6,
0,
0
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
1,
1,
4,
6,
0,
0
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeAt = 1;
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(lengthTrackingWithOffset), [
1,
1,
0,
0
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
1,
1,
0,
0
]);
}

View File

@ -0,0 +1,64 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by a
resizable buffer is grown due to the source's length getter
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateSourceProxy(length, rab, resizeTo) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Test that we still throw for lengthTracking TAs if the source length is
// too large, even though we resized in the length getter (we check against
// the original length).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assert.throws(RangeError, () => {
lengthTracking.set(CreateSourceProxy(6, rab, resizeTo));
});
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4,
6,
0,
0
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assert.throws(RangeError, () => {
lengthTrackingWithOffset.set(CreateSourceProxy(4, rab, resizeTo));
});
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4,
6,
0,
0
]);
}

View File

@ -0,0 +1,99 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by resizable buffers
that are shrunk mid-iteration due to a Proxy source.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
function CreateSourceProxy(length, rab, resizeAt, resizeTo) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const resizeAt = 2;
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
1,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const resizeAt = 2;
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
1
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const resizeAt = 2;
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(lengthTracking), [
1,
1,
4
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
1,
1,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeAt = 2;
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(lengthTrackingWithOffset), [1]);
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
1
]);
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeAt = 1;
const resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2, rab, resizeAt, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [0]);
}

View File

@ -0,0 +1,147 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by resizable buffers
that are shrunk due to the source's length getter.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateSourceProxy(length, rab, resizeTo) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Tests where the length getter returns a non-zero value -> these are nop if
// the TA went OOB.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(1, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(1, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(1, rab, resizeTo));
assert.compareArray(ToNumbers(lengthTracking), [
1,
2,
4
]);
assert.compareArray(ToNumbers(new ctor(rab)), [
1,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(1, rab, resizeTo));
assert.compareArray(ToNumbers(lengthTrackingWithOffset), [1]);
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
1
]);
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(1, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [0]);
}
// Tests where the length getter returns a zero -> these don't throw even if
// the TA went OOB.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(0, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(0, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(0, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [
0,
2,
4
]);
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0, rab, resizeTo));
assert.compareArray(ToNumbers(new ctor(rab)), [0]);
}

View File

@ -0,0 +1,525 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by resizable buffers.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
function SetNumOrBigInt(target, source, offset) {
if (target instanceof BigInt64Array || target instanceof BigUint64Array) {
const bigIntSource = [];
for (const s of source) {
bigIntSource.push(BigInt(s));
}
source = bigIntSource;
}
if (offset == undefined) {
return target.set(source);
}
return target.set(source, offset);
}
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);
const taFull = new ctor(rab);
// Orig. array: [0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, ...] << lengthTracking
// [0, 0, ...] << lengthTrackingWithOffset
// For making sure we're not calling the source length or element getters
// if the target is OOB.
const throwingProxy = new Proxy({}, {
get(target, prop, receiver) {
throw new Error('Called getter for ' + prop);
}
});
SetNumOrBigInt(fixedLength, [
1,
2
]);
assert.compareArray(ToNumbers(taFull), [
1,
2,
0,
0
]);
SetNumOrBigInt(fixedLength, [
3,
4
], 1);
assert.compareArray(ToNumbers(taFull), [
1,
3,
4,
0
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLength, [
0,
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLength, [
0,
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
1,
3,
4,
0
]);
SetNumOrBigInt(fixedLengthWithOffset, [
5,
6
]);
assert.compareArray(ToNumbers(taFull), [
1,
3,
5,
6
]);
SetNumOrBigInt(fixedLengthWithOffset, [7], 1);
assert.compareArray(ToNumbers(taFull), [
1,
3,
5,
7
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, [
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, [
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
1,
3,
5,
7
]);
SetNumOrBigInt(lengthTracking, [
8,
9
]);
assert.compareArray(ToNumbers(taFull), [
8,
9,
5,
7
]);
SetNumOrBigInt(lengthTracking, [
10,
11
], 1);
assert.compareArray(ToNumbers(taFull), [
8,
10,
11,
7
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
8,
10,
11,
7
]);
SetNumOrBigInt(lengthTrackingWithOffset, [
12,
13
]);
assert.compareArray(ToNumbers(taFull), [
8,
10,
12,
13
]);
SetNumOrBigInt(lengthTrackingWithOffset, [14], 1);
assert.compareArray(ToNumbers(taFull), [
8,
10,
12,
14
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
8,
10,
12,
14
]);
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [8, 10, 12]
// [8, 10, 12, ...] << lengthTracking
// [12, ...] << lengthTrackingWithOffset
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLength, throwingProxy);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, throwingProxy);
});
assert.compareArray(ToNumbers(taFull), [
8,
10,
12
]);
SetNumOrBigInt(lengthTracking, [
15,
16
]);
assert.compareArray(ToNumbers(taFull), [
15,
16,
12
]);
SetNumOrBigInt(lengthTracking, [
17,
18
], 1);
assert.compareArray(ToNumbers(taFull), [
15,
17,
18
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
15,
17,
18
]);
SetNumOrBigInt(lengthTrackingWithOffset, [19]);
assert.compareArray(ToNumbers(taFull), [
15,
17,
19
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [0], 1);
});
assert.compareArray(ToNumbers(taFull), [
15,
17,
19
]);
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLength, throwingProxy);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, throwingProxy);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, throwingProxy);
});
assert.compareArray(ToNumbers(taFull), [15]);
SetNumOrBigInt(lengthTracking, [20]);
assert.compareArray(ToNumbers(taFull), [20]);
// Shrink to zero.
rab.resize(0);
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLength, throwingProxy);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, throwingProxy);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, throwingProxy);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [0]);
});
assert.compareArray(ToNumbers(taFull), []);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 0, 0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, 0, 0, ...] << lengthTracking
// [0, 0, 0, 0, ...] << lengthTrackingWithOffset
SetNumOrBigInt(fixedLength, [
21,
22
]);
assert.compareArray(ToNumbers(taFull), [
21,
22,
0,
0,
0,
0
]);
SetNumOrBigInt(fixedLength, [
23,
24
], 1);
assert.compareArray(ToNumbers(taFull), [
21,
23,
24,
0,
0,
0
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLength, [
0,
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLength, [
0,
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
21,
23,
24,
0,
0,
0
]);
SetNumOrBigInt(fixedLengthWithOffset, [
25,
26
]);
assert.compareArray(ToNumbers(taFull), [
21,
23,
25,
26,
0,
0
]);
SetNumOrBigInt(fixedLengthWithOffset, [27], 1);
assert.compareArray(ToNumbers(taFull), [
21,
23,
25,
27,
0,
0
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, [
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(fixedLengthWithOffset, [
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
21,
23,
25,
27,
0,
0
]);
SetNumOrBigInt(lengthTracking, [
28,
29,
30,
31,
32,
33
]);
assert.compareArray(ToNumbers(taFull), [
28,
29,
30,
31,
32,
33
]);
SetNumOrBigInt(lengthTracking, [
34,
35,
36,
37,
38
], 1);
assert.compareArray(ToNumbers(taFull), [
28,
34,
35,
36,
37,
38
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0,
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTracking, [
0,
0,
0,
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
28,
34,
35,
36,
37,
38
]);
SetNumOrBigInt(lengthTrackingWithOffset, [
39,
40,
41,
42
]);
assert.compareArray(ToNumbers(taFull), [
28,
34,
39,
40,
41,
42
]);
SetNumOrBigInt(lengthTrackingWithOffset, [
43,
44,
45
], 1);
assert.compareArray(ToNumbers(taFull), [
28,
34,
39,
43,
44,
45
]);
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [
0,
0,
0,
0,
0
]);
});
assert.throws(RangeError, () => {
SetNumOrBigInt(lengthTrackingWithOffset, [
0,
0,
0,
0
], 1);
});
assert.compareArray(ToNumbers(taFull), [
28,
34,
39,
43,
44,
45
]);
}

View File

@ -0,0 +1,229 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.set
description: >
TypedArray.p.set behaves correctly on TypedArrays backed by resizable buffers.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
function IsBigIntTypedArray(ta) {
return ta instanceof BigInt64Array || ta instanceof BigUint64Array;
}
function SetNumOrBigInt(target, source, offset) {
if (IsBigIntTypedArray(target)) {
const bigIntSource = [];
for (const s of source) {
bigIntSource.push(BigInt(s));
}
source = bigIntSource;
}
if (offset == undefined) {
return target.set(source);
}
return target.set(source, offset);
}
for (let targetIsResizable of [
false,
true
]) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
const rab = CreateResizableArrayBuffer(4 * sourceCtor.BYTES_PER_ELEMENT, 8 * sourceCtor.BYTES_PER_ELEMENT);
const fixedLength = new sourceCtor(rab, 0, 4);
const fixedLengthWithOffset = new sourceCtor(rab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new sourceCtor(rab, 0);
const lengthTrackingWithOffset = new sourceCtor(rab, 2 * sourceCtor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new sourceCtor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, ...] << lengthTracking
// [3, 4, ...] << lengthTrackingWithOffset
const targetAb = targetIsResizable ? new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT) : new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT, { maxByteLength: 8 * targetCtor.BYTES_PER_ELEMENT });
const target = new targetCtor(targetAb);
if (IsBigIntTypedArray(target) != IsBigIntTypedArray(taFull)) {
// Can't mix BigInt and non-BigInt types.
continue;
}
SetNumOrBigInt(target, fixedLength);
assert.compareArray(ToNumbers(target), [
1,
2,
3,
4,
0,
0
]);
SetNumOrBigInt(target, fixedLengthWithOffset);
assert.compareArray(ToNumbers(target), [
3,
4,
3,
4,
0,
0
]);
SetNumOrBigInt(target, lengthTracking, 1);
assert.compareArray(ToNumbers(target), [
3,
1,
2,
3,
4,
0
]);
SetNumOrBigInt(target, lengthTrackingWithOffset, 1);
assert.compareArray(ToNumbers(target), [
3,
3,
4,
3,
4,
0
]);
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * sourceCtor.BYTES_PER_ELEMENT);
// Orig. array: [1, 2, 3]
// [1, 2, 3, ...] << lengthTracking
// [3, ...] << lengthTrackingWithOffset
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLength);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLengthWithOffset);
});
assert.compareArray(ToNumbers(target), [
3,
3,
4,
3,
4,
0
]);
SetNumOrBigInt(target, lengthTracking);
assert.compareArray(ToNumbers(target), [
1,
2,
3,
3,
4,
0
]);
SetNumOrBigInt(target, lengthTrackingWithOffset);
assert.compareArray(ToNumbers(target), [
3,
2,
3,
3,
4,
0
]);
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * sourceCtor.BYTES_PER_ELEMENT);
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLength);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLengthWithOffset);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(target, lengthTrackingWithOffset);
});
SetNumOrBigInt(target, lengthTracking, 3);
assert.compareArray(ToNumbers(target), [
3,
2,
3,
1,
4,
0
]);
// Shrink to zero.
rab.resize(0);
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLength);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(target, fixedLengthWithOffset);
});
assert.throws(TypeError, () => {
SetNumOrBigInt(target, lengthTrackingWithOffset);
});
SetNumOrBigInt(target, lengthTracking, 4);
assert.compareArray(ToNumbers(target), [
3,
2,
3,
1,
4,
0
]);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * sourceCtor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, 5, 6, ...] << lengthTracking
// [3, 4, 5, 6, ...] << lengthTrackingWithOffset
SetNumOrBigInt(target, fixedLength);
assert.compareArray(ToNumbers(target), [
1,
2,
3,
4,
4,
0
]);
SetNumOrBigInt(target, fixedLengthWithOffset);
assert.compareArray(ToNumbers(target), [
3,
4,
3,
4,
4,
0
]);
SetNumOrBigInt(target, lengthTracking, 0);
assert.compareArray(ToNumbers(target), [
1,
2,
3,
4,
5,
6
]);
SetNumOrBigInt(target, lengthTrackingWithOffset, 1);
assert.compareArray(ToNumbers(target), [
1,
3,
4,
5,
6,
6
]);
}
}
}