From 242f6f98f0f86c0a3276929b4a450438526057cb Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:04:41 +0200 Subject: [PATCH] RAB: Integrate staging tests for the .map method (#4155) * Import relevant files from #3888 * Removing parts in resizableArrayBufferUtils.js and adding it in includes, while adjusting usage of CollectValuesAndResize and applying review changes from PRs for previously tested methods. * Apply suggestions from code review --- .../resizable-buffer-grow-mid-iteration.js | 82 +++++++++ .../resizable-buffer-shrink-mid-iteration.js | 79 +++++++++ .../Array/prototype/map/resizable-buffer.js | 141 ++++++++++++++++ .../resizable-buffer-grow-mid-iteration.js | 83 +++++++++ .../resizable-buffer-shrink-mid-iteration.js | 89 ++++++++++ .../prototype/map/resizable-buffer.js | 158 ++++++++++++++++++ .../map/speciesctor-resizable-buffer-grow.js | 85 ++++++++++ .../speciesctor-resizable-buffer-shrink.js | 82 +++++++++ 8 files changed, 799 insertions(+) create mode 100644 test/built-ins/Array/prototype/map/resizable-buffer-grow-mid-iteration.js create mode 100644 test/built-ins/Array/prototype/map/resizable-buffer-shrink-mid-iteration.js create mode 100644 test/built-ins/Array/prototype/map/resizable-buffer.js create mode 100644 test/built-ins/TypedArray/prototype/map/resizable-buffer-grow-mid-iteration.js create mode 100644 test/built-ins/TypedArray/prototype/map/resizable-buffer-shrink-mid-iteration.js create mode 100644 test/built-ins/TypedArray/prototype/map/resizable-buffer.js create mode 100644 test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-grow.js create mode 100644 test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-shrink.js diff --git a/test/built-ins/Array/prototype/map/resizable-buffer-grow-mid-iteration.js b/test/built-ins/Array/prototype/map/resizable-buffer-grow-mid-iteration.js new file mode 100644 index 0000000000..4bcd91b4f6 --- /dev/null +++ b/test/built-ins/Array/prototype/map/resizable-buffer-grow-mid-iteration.js @@ -0,0 +1,82 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.map +description: > + Array.p.map behaves correctly when the resizable buffer is grown mid-iteration. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +let values; +let rab; +let resizeAfter; +let resizeTo; +// Collects the view of the resizable array buffer rab into values, with an +// iteration during which, after resizeAfter steps, rab is resized to length +// resizeTo. To be called by a method of the view being collected. +// Note that rab, values, resizeAfter, and resizeTo may need to be reset +// before calling this. +function ResizeMidIteration(n) { + CollectValuesAndResize(n, values, rab, resizeAfter, resizeTo); + return n; +} + +// Orig. array: [0, 2, 4, 6] +// [0, 2, 4, 6] << fixedLength +// [4, 6] << fixedLengthWithOffset +// [0, 2, 4, 6, ...] << lengthTracking +// [4, 6, ...] << lengthTrackingWithOffset +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLength = new ctor(rab, 0, 4); + resizeAfter = 2; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(fixedLength, ResizeMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2); + resizeAfter = 1; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(fixedLengthWithOffset, ResizeMidIteration); + assert.compareArray(values, [ + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTracking = new ctor(rab, 0); + resizeAfter = 2; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(lengthTracking, ResizeMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT); + resizeAfter = 1; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(lengthTrackingWithOffset, ResizeMidIteration); + assert.compareArray(values, [ + 4, + 6 + ]); +} diff --git a/test/built-ins/Array/prototype/map/resizable-buffer-shrink-mid-iteration.js b/test/built-ins/Array/prototype/map/resizable-buffer-shrink-mid-iteration.js new file mode 100644 index 0000000000..0c305ea252 --- /dev/null +++ b/test/built-ins/Array/prototype/map/resizable-buffer-shrink-mid-iteration.js @@ -0,0 +1,79 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.map +description: > + Array.p.map behaves correctly when the resizable buffer is shrunk mid-iteration. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +let values; +let rab; +let resizeAfter; +let resizeTo; +// Collects the view of the resizable array buffer rab into values, with an +// iteration during which, after resizeAfter steps, rab is resized to length +// resizeTo. To be called by a method of the view being collected. +// Note that rab, values, resizeAfter, and resizeTo may need to be reset +// before calling this. This version can deal with the undefined values +// resulting by shrinking rab. +function ShrinkMidIteration(n, ix, ta) { + CollectValuesAndResize(n, values, rab, resizeAfter, resizeTo); + // We still need to return a valid BigInt / non-BigInt, even if + // n is `undefined`. + if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) { + return 0n; + } + return 0; +} + +// Orig. array: [0, 2, 4, 6] +// [0, 2, 4, 6] << fixedLength +// [4, 6] << fixedLengthWithOffset +// [0, 2, 4, 6, ...] << lengthTracking +// [4, 6, ...] << lengthTrackingWithOffset +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLength = new ctor(rab, 0, 4); + resizeAfter = 2; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(fixedLength, ShrinkMidIteration); + assert.compareArray(values, [ + 0, + 2 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2); + resizeAfter = 1; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(fixedLengthWithOffset, ShrinkMidIteration); + assert.compareArray(values, [4]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTracking = new ctor(rab, 0); + resizeAfter = 2; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(lengthTracking, ShrinkMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT); + resizeAfter = 1; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + Array.prototype.map.call(lengthTrackingWithOffset, ShrinkMidIteration); + assert.compareArray(values, [4]); +} diff --git a/test/built-ins/Array/prototype/map/resizable-buffer.js b/test/built-ins/Array/prototype/map/resizable-buffer.js new file mode 100644 index 0000000000..e108395fcb --- /dev/null +++ b/test/built-ins/Array/prototype/map/resizable-buffer.js @@ -0,0 +1,141 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.map +description: > + Array.p.map behaves as expected on TypedArrays backed by resizable buffers. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +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 < taWrite.length; ++i) { + WriteToTypedArray(taWrite, i, 2 * i); + } + + // Orig. array: [0, 2, 4, 6] + // [0, 2, 4, 6] << fixedLength + // [4, 6] << fixedLengthWithOffset + // [0, 2, 4, 6, ...] << lengthTracking + // [4, 6, ...] << lengthTrackingWithOffset + + function MapGatherCompare(array) { + const values = []; + function GatherValues(n, ix) { + assert.sameValue(ix, values.length); + values.push(n); + if (typeof n == 'bigint') { + return n + 1n; + } + return n + 1; + } + const newValues = Array.prototype.map.call(array, GatherValues); + for (let i = 0; i < values.length; ++i) { + if (typeof values[i] == 'bigint') { + assert.sameValue(values[i] + 1n, newValues[i]); + } else { + assert.sameValue(values[i] + 1, newValues[i]); + } + } + return ToNumbers(values); + } + assert.compareArray(MapGatherCompare(fixedLength), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGatherCompare(fixedLengthWithOffset), [ + 4, + 6 + ]); + assert.compareArray(MapGatherCompare(lengthTracking), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGatherCompare(lengthTrackingWithOffset), [ + 4, + 6 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [0, 2, 4] + // [0, 2, 4, ...] << lengthTracking + // [4, ...] << lengthTrackingWithOffset + + assert.compareArray(MapGatherCompare(fixedLength), []); + assert.compareArray(MapGatherCompare(fixedLengthWithOffset), []); + + assert.compareArray(MapGatherCompare(lengthTracking), [ + 0, + 2, + 4 + ]); + assert.compareArray(MapGatherCompare(lengthTrackingWithOffset), [4]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + assert.compareArray(MapGatherCompare(fixedLength), []); + assert.compareArray(MapGatherCompare(fixedLengthWithOffset), []); + assert.compareArray(MapGatherCompare(lengthTrackingWithOffset), []); + + assert.compareArray(MapGatherCompare(lengthTracking), [0]); + + // Shrink to zero. + rab.resize(0); + assert.compareArray(MapGatherCompare(fixedLength), []); + assert.compareArray(MapGatherCompare(fixedLengthWithOffset), []); + assert.compareArray(MapGatherCompare(lengthTrackingWithOffset), []); + + assert.compareArray(MapGatherCompare(lengthTracking), []); + + // 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, 2 * i); + } + + // Orig. array: [0, 2, 4, 6, 8, 10] + // [0, 2, 4, 6] << fixedLength + // [4, 6] << fixedLengthWithOffset + // [0, 2, 4, 6, 8, 10, ...] << lengthTracking + // [4, 6, 8, 10, ...] << lengthTrackingWithOffset + + assert.compareArray(MapGatherCompare(fixedLength), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGatherCompare(fixedLengthWithOffset), [ + 4, + 6 + ]); + assert.compareArray(MapGatherCompare(lengthTracking), [ + 0, + 2, + 4, + 6, + 8, + 10 + ]); + assert.compareArray(MapGatherCompare(lengthTrackingWithOffset), [ + 4, + 6, + 8, + 10 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/map/resizable-buffer-grow-mid-iteration.js b/test/built-ins/TypedArray/prototype/map/resizable-buffer-grow-mid-iteration.js new file mode 100644 index 0000000000..a6f6d4545f --- /dev/null +++ b/test/built-ins/TypedArray/prototype/map/resizable-buffer-grow-mid-iteration.js @@ -0,0 +1,83 @@ +// 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.map +description: > + TypedArray.p.map behaves correctly on TypedArrays backed by resizable buffers + that are grown mid-iteration. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +let values; +let rab; +let resizeAfter; +let resizeTo; +// Collects the view of the resizable array buffer rab into values, with an +// iteration during which, after resizeAfter steps, rab is resized to length +// resizeTo. To be called by a method of the view being collected. +// Note that rab, values, resizeAfter, and resizeTo may need to be reset +// before calling this. +function ResizeMidIteration(n) { + CollectValuesAndResize(n, values, rab, resizeAfter, resizeTo); + return n; +} + +// Orig. array: [0, 2, 4, 6] +// [0, 2, 4, 6] << fixedLength +// [4, 6] << fixedLengthWithOffset +// [0, 2, 4, 6, ...] << lengthTracking +// [4, 6, ...] << lengthTrackingWithOffset +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLength = new ctor(rab, 0, 4); + resizeAfter = 2; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + fixedLength.map(ResizeMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2); + resizeAfter = 1; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + fixedLengthWithOffset.map(ResizeMidIteration); + assert.compareArray(values, [ + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTracking = new ctor(rab, 0); + resizeAfter = 2; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + lengthTracking.map(ResizeMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4, + 6 + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT); + resizeAfter = 1; + resizeTo = 5 * ctor.BYTES_PER_ELEMENT; + lengthTrackingWithOffset.map(ResizeMidIteration); + assert.compareArray(values, [ + 4, + 6 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/map/resizable-buffer-shrink-mid-iteration.js b/test/built-ins/TypedArray/prototype/map/resizable-buffer-shrink-mid-iteration.js new file mode 100644 index 0000000000..e72aba9750 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/map/resizable-buffer-shrink-mid-iteration.js @@ -0,0 +1,89 @@ +// 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.map +description: > + TypedArray.p.map behaves correctly on TypedArrays backed by resizable buffers + that are shrunk mid-iteration. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +let values; +let rab; +let resizeAfter; +let resizeTo; +// Collects the view of the resizable array buffer rab into values, with an +// iteration during which, after resizeAfter steps, rab is resized to length +// resizeTo. To be called by a method of the view being collected. +// Note that rab, values, resizeAfter, and resizeTo may need to be reset +// before calling this. This version can deal with the undefined values +// resulting by shrinking rab. +function ShrinkMidIteration(n, ix, ta) { + CollectValuesAndResize(n, values, rab, resizeAfter, resizeTo); + // We still need to return a valid BigInt / non-BigInt, even if + // n is `undefined`. + if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) { + return 0n; + } + return 0; +} + +// Orig. array: [0, 2, 4, 6] +// [0, 2, 4, 6] << fixedLength +// [4, 6] << fixedLengthWithOffset +// [0, 2, 4, 6, ...] << lengthTracking +// [4, 6, ...] << lengthTrackingWithOffset +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLength = new ctor(rab, 0, 4); + resizeAfter = 2; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + fixedLength.map(ShrinkMidIteration); + assert.compareArray(values, [ + 0, + 2, + undefined, + undefined + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2); + resizeAfter = 1; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + fixedLengthWithOffset.map(ShrinkMidIteration); + assert.compareArray(values, [ + 4, + undefined + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTracking = new ctor(rab, 0); + resizeAfter = 2; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + lengthTracking.map(ShrinkMidIteration); + assert.compareArray(values, [ + 0, + 2, + 4, + undefined + ]); +} +for (let ctor of ctors) { + values = []; + rab = CreateRabForTest(ctor); + const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT); + resizeAfter = 1; + resizeTo = 3 * ctor.BYTES_PER_ELEMENT; + lengthTrackingWithOffset.map(ShrinkMidIteration); + assert.compareArray(values, [ + 4, + undefined + ]); +} diff --git a/test/built-ins/TypedArray/prototype/map/resizable-buffer.js b/test/built-ins/TypedArray/prototype/map/resizable-buffer.js new file mode 100644 index 0000000000..24c7cf1bb4 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/map/resizable-buffer.js @@ -0,0 +1,158 @@ +// 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.map +description: > + TypedArray.p.map behaves as expected on TypedArrays backed by resizable + buffers. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +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 < taWrite.length; ++i) { + WriteToTypedArray(taWrite, i, 2 * i); + } + + // Orig. array: [0, 2, 4, 6] + // [0, 2, 4, 6] << fixedLength + // [4, 6] << fixedLengthWithOffset + // [0, 2, 4, 6, ...] << lengthTracking + // [4, 6, ...] << lengthTrackingWithOffset + + function MapGathering(array) { + const values = []; + function GatherValues(n, ix) { + assert.sameValue(ix, values.length); + values.push(n); + if (typeof n == 'bigint') { + return n + 1n; + } + return n + 1; + } + const newValues = array.map(GatherValues); + for (let i = 0; i < values.length; ++i) { + if (typeof values[i] == 'bigint') { + assert.sameValue(values[i] + 1n, newValues[i]); + } else { + assert.sameValue(values[i] + 1, newValues[i]); + } + } + return ToNumbers(values); + } + assert.compareArray(MapGathering(fixedLength), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGathering(fixedLengthWithOffset), [ + 4, + 6 + ]); + assert.compareArray(MapGathering(lengthTracking), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGathering(lengthTrackingWithOffset), [ + 4, + 6 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [0, 2, 4] + // [0, 2, 4, ...] << lengthTracking + // [4, ...] << lengthTrackingWithOffset + + assert.throws(TypeError, () => { + MapGathering(fixedLength); + }); + assert.throws(TypeError, () => { + MapGathering(fixedLengthWithOffset); + }); + + assert.compareArray(MapGathering(lengthTracking), [ + 0, + 2, + 4 + ]); + assert.compareArray(MapGathering(lengthTrackingWithOffset), [4]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + assert.throws(TypeError, () => { + MapGathering(fixedLength); + }); + assert.throws(TypeError, () => { + MapGathering(fixedLengthWithOffset); + }); + assert.throws(TypeError, () => { + MapGathering(lengthTrackingWithOffset); + }); + + assert.compareArray(MapGathering(lengthTracking), [0]); + + // Shrink to zero. + rab.resize(0); + assert.throws(TypeError, () => { + MapGathering(fixedLength); + }); + assert.throws(TypeError, () => { + MapGathering(fixedLengthWithOffset); + }); + assert.throws(TypeError, () => { + MapGathering(lengthTrackingWithOffset); + }); + + assert.compareArray(MapGathering(lengthTracking), []); + + // 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, 2 * i); + } + + // Orig. array: [0, 2, 4, 6, 8, 10] + // [0, 2, 4, 6] << fixedLength + // [4, 6] << fixedLengthWithOffset + // [0, 2, 4, 6, 8, 10, ...] << lengthTracking + // [4, 6, 8, 10, ...] << lengthTrackingWithOffset + + assert.compareArray(MapGathering(fixedLength), [ + 0, + 2, + 4, + 6 + ]); + assert.compareArray(MapGathering(fixedLengthWithOffset), [ + 4, + 6 + ]); + assert.compareArray(MapGathering(lengthTracking), [ + 0, + 2, + 4, + 6, + 8, + 10 + ]); + assert.compareArray(MapGathering(lengthTrackingWithOffset), [ + 4, + 6, + 8, + 10 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-grow.js b/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-grow.js new file mode 100644 index 0000000000..d9999cb8a2 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-grow.js @@ -0,0 +1,85 @@ +// 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.map +description: > + TypedArray.p.map behaves correctly on TypedArrays backed by resizable buffers + that are grown by the species constructor. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +// Returns a function that collects an appropriate typed array into values. Such +// a result can be used as an argument to .map. +function CollectWithUndefined(values) { + return (n, ix, ta) => { + if (typeof n == 'bigint') { + values.push(Number(n)); + } else { + values.push(n); + } + if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) { + // We still need to return a valid BigInt / non-BigInt, even if + // n is `undefined`. + return 0n; + } + return 0; + } +} + +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const taWrite = new ctor(rab); + for (let i = 0; i < 4; ++i) { + WriteToTypedArray(taWrite, i, i); + } + let resizeWhenConstructorCalled = false; + class MyArray extends ctor { + constructor(...params) { + super(...params); + if (resizeWhenConstructorCalled) { + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + } + } + }; + const fixedLength = new MyArray(rab, 0, 4); + resizeWhenConstructorCalled = true; + const values = []; + fixedLength.map(CollectWithUndefined(values)); + assert.compareArray(values, [ + 0, + 1, + 2, + 3 + ]); + assert.sameValue(rab.byteLength, 6 * ctor.BYTES_PER_ELEMENT); +} +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const taWrite = new ctor(rab); + for (let i = 0; i < 4; ++i) { + WriteToTypedArray(taWrite, i, i); + } + let resizeWhenConstructorCalled = false; + class MyArray extends ctor { + constructor(...params) { + super(...params); + if (resizeWhenConstructorCalled) { + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + } + } + } + ; + const lengthTracking = new MyArray(rab); + resizeWhenConstructorCalled = true; + const values = []; + lengthTracking.map(CollectWithUndefined(values)); + assert.compareArray(values, [ + 0, + 1, + 2, + 3 + ]); + assert.sameValue(rab.byteLength, 6 * ctor.BYTES_PER_ELEMENT); +} diff --git a/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-shrink.js b/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-shrink.js new file mode 100644 index 0000000000..7b4e47d99a --- /dev/null +++ b/test/built-ins/TypedArray/prototype/map/speciesctor-resizable-buffer-shrink.js @@ -0,0 +1,82 @@ +// 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.map +description: > + TypedArray.p.map behaves correctly on TypedArrays backed by resizable buffers + that are shrunk by the species constructor. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +// Returns a function that collects an appropriate typed array into values. Such +// a result can be used as an argument to .map. +function CollectWithUndefined(values) { + return (n, ix, ta) => { + if (typeof n == 'bigint') { + values.push(Number(n)); + } else { + values.push(n); + } + if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) { + // We still need to return a valid BigInt / non-BigInt, even if + // n is `undefined`. + return 0n; + } + return 0; + } +} + +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + let resizeWhenConstructorCalled = false; + class MyArray extends ctor { + constructor(...params) { + super(...params); + if (resizeWhenConstructorCalled) { + rab.resize(2 * ctor.BYTES_PER_ELEMENT); + } + } + } + ; + const fixedLength = new MyArray(rab, 0, 4); + resizeWhenConstructorCalled = true; + const values = []; + fixedLength.map(CollectWithUndefined(values)); + assert.compareArray(values, [ + undefined, + undefined, + undefined, + undefined + ]); + assert.sameValue(rab.byteLength, 2 * ctor.BYTES_PER_ELEMENT); +} +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const taWrite = new ctor(rab); + for (let i = 0; i < 4; ++i) { + WriteToTypedArray(taWrite, i, i); + } + let resizeWhenConstructorCalled = false; + class MyArray extends ctor { + constructor(...params) { + super(...params); + if (resizeWhenConstructorCalled) { + rab.resize(2 * ctor.BYTES_PER_ELEMENT); + } + } + } + ; + const lengthTracking = new MyArray(rab); + resizeWhenConstructorCalled = true; + const values = []; + lengthTracking.map(CollectWithUndefined(values)); + assert.compareArray(values, [ + 0, + 1, + undefined, + undefined + ]); + assert.sameValue(rab.byteLength, 2 * ctor.BYTES_PER_ELEMENT); +}