From ef72bd1c4450258049bb0521037aa629f274869a Mon Sep 17 00:00:00 2001 From: Ioanna M Dimitriou H <9728696+ioannad@users.noreply.github.com> Date: Tue, 6 Aug 2024 02:22:10 +0200 Subject: [PATCH] RAB: Integrate staging tests for the .sort method (#4176) * Import relevant files from #3888 * Removing parts in resizableArrayBufferUtils.js and adding it in includes, while applying review changes from PRs for previously tested methods. * Renamed test files * Some minor documentation fixes and removing onlyStrict flag --- .../Array/prototype/sort/comparefn-grow.js | 69 ++++++ .../sort/comparefn-resizable-buffer.js | 191 ++++++++++++++++ .../Array/prototype/sort/comparefn-shrink.js | 71 ++++++ .../resizable-buffer-default-comparator.js | 173 +++++++++++++++ .../prototype/sort/comparefn-grow.js | 71 ++++++ .../sort/comparefn-resizable-buffer.js | 206 ++++++++++++++++++ .../prototype/sort/comparefn-shrink.js | 73 +++++++ .../resizable-buffer-default-comparator.js | 182 ++++++++++++++++ 8 files changed, 1036 insertions(+) create mode 100644 test/built-ins/Array/prototype/sort/comparefn-grow.js create mode 100644 test/built-ins/Array/prototype/sort/comparefn-resizable-buffer.js create mode 100644 test/built-ins/Array/prototype/sort/comparefn-shrink.js create mode 100644 test/built-ins/Array/prototype/sort/resizable-buffer-default-comparator.js create mode 100644 test/built-ins/TypedArray/prototype/sort/comparefn-grow.js create mode 100644 test/built-ins/TypedArray/prototype/sort/comparefn-resizable-buffer.js create mode 100644 test/built-ins/TypedArray/prototype/sort/comparefn-shrink.js create mode 100644 test/built-ins/TypedArray/prototype/sort/resizable-buffer-default-comparator.js diff --git a/test/built-ins/Array/prototype/sort/comparefn-grow.js b/test/built-ins/Array/prototype/sort/comparefn-grow.js new file mode 100644 index 0000000000..640cdda2ae --- /dev/null +++ b/test/built-ins/Array/prototype/sort/comparefn-grow.js @@ -0,0 +1,69 @@ +// 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.sort +description: > + Array.p.sort behaves correctly on TypedArrays backed by resizable buffers which + are grown by the comparison callback. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +function ResizeAndCompare(rab, resizeTo) { + return (a, b) => { + rab.resize(resizeTo); + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } +} + +function WriteUnsortedData(taFull) { + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } +} + +// Fixed length TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 6 * ctor.BYTES_PER_ELEMENT; + const fixedLength = new ctor(rab, 0, 4); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + Array.prototype.sort.call(fixedLength, ResizeAndCompare(rab, resizeTo)); + // Growing doesn't affect the sorting. + assert.compareArray(ToNumbers(taFull), [ + 7, + 8, + 9, + 10, + 0, + 0 + ]); +} + +// Length-tracking TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 6 * ctor.BYTES_PER_ELEMENT; + const lengthTracking = new ctor(rab, 0); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + Array.prototype.sort.call(lengthTracking, ResizeAndCompare(rab, resizeTo)); + // Growing doesn't affect the sorting. Only the elements that were part of + // the original TA are sorted. + assert.compareArray(ToNumbers(taFull), [ + 7, + 8, + 9, + 10, + 0, + 0 + ]); +} diff --git a/test/built-ins/Array/prototype/sort/comparefn-resizable-buffer.js b/test/built-ins/Array/prototype/sort/comparefn-resizable-buffer.js new file mode 100644 index 0000000000..b575811e80 --- /dev/null +++ b/test/built-ins/Array/prototype/sort/comparefn-resizable-buffer.js @@ -0,0 +1,191 @@ +// 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.sort +description: > + Array.p.sort behaves correctly on TypedArrays backed by resizable buffers and + is passed a user-provided comparison callback. +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); + const taFull = new ctor(rab, 0); + function WriteUnsortedData() { + // Write some data into the array. + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } + } + function OddBeforeEvenComparison(a, b) { + // Sort all odd numbers before even numbers. + a = Number(a); + b = Number(b); + if (a % 2 == 1 && b % 2 == 0) { + return -1; + } + if (a % 2 == 0 && b % 2 == 1) { + return 1; + } + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } + // Orig. array: [10, 9, 8, 7] + // [10, 9, 8, 7] << fixedLength + // [8, 7] << fixedLengthWithOffset + // [10, 9, 8, 7, ...] << lengthTracking + // [8, 7, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLengthWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 9, 8] + // [10, 9, 8, ...] << lengthTracking + // [8, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + Array.prototype.sort.call(fixedLengthWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 9, + 8, + 10 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [10]); + Array.prototype.sort.call(fixedLengthWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [10]); + Array.prototype.sort.call(lengthTrackingWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [10]); + + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [10]); + + // Shrink to zero. + rab.resize(0); + Array.prototype.sort.call(fixedLength, OddBeforeEvenComparison); + Array.prototype.sort.call(fixedLengthWithOffset, OddBeforeEvenComparison); + Array.prototype.sort.call(lengthTrackingWithOffset, OddBeforeEvenComparison); + + Array.prototype.sort.call(lengthTracking, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), []); + + // Grow so that all TAs are back in-bounds. + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 9, 8, 7, 6, 5] + // [10, 9, 8, 7] << fixedLength + // [8, 7] << fixedLengthWithOffset + // [10, 9, 8, 7, 6, 5, ...] << lengthTracking + // [8, 7, 6, 5, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10, + 6, + 5 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLengthWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8, + 6, + 5 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 5, + 7, + 9, + 6, + 8, + 10 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset, OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 5, + 7, + 6, + 8 + ]); +} diff --git a/test/built-ins/Array/prototype/sort/comparefn-shrink.js b/test/built-ins/Array/prototype/sort/comparefn-shrink.js new file mode 100644 index 0000000000..c9c26f01c6 --- /dev/null +++ b/test/built-ins/Array/prototype/sort/comparefn-shrink.js @@ -0,0 +1,71 @@ +// 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.sort +description: > + Array.p.sort behaves correctly on TypedArrays backed by resizable buffers and + is shrunk by the comparison callback. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer, Array.prototype.includes] +---*/ + +function ResizeAndCompare(rab, resizeTo) { + return (a, b) => { + rab.resize(resizeTo); + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } +} + +function WriteUnsortedData(taFull) { + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } +} + +// Fixed length TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 2 * ctor.BYTES_PER_ELEMENT; + const fixedLength = new ctor(rab, 0, 4); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + Array.prototype.sort.call(fixedLength, ResizeAndCompare(rab, resizeTo)); + // The data is unchanged. + assert.compareArray(ToNumbers(taFull), [ + 10, + 9 + ]); +} + +// Length-tracking TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 2 * ctor.BYTES_PER_ELEMENT; + const lengthTracking = new ctor(rab, 0); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + Array.prototype.sort.call(lengthTracking, ResizeAndCompare(rab, resizeTo)); + // The sort result is implementation defined, but it contains 2 elements out + // of the 4 original ones. + const newData = ToNumbers(taFull); + assert.sameValue(newData.length, 2); + assert([ + 10, + 9, + 8, + 7 + ].includes(newData[0])); + assert([ + 10, + 9, + 8, + 7 + ].includes(newData[1])); +} diff --git a/test/built-ins/Array/prototype/sort/resizable-buffer-default-comparator.js b/test/built-ins/Array/prototype/sort/resizable-buffer-default-comparator.js new file mode 100644 index 0000000000..38b1c065da --- /dev/null +++ b/test/built-ins/Array/prototype/sort/resizable-buffer-default-comparator.js @@ -0,0 +1,173 @@ +// 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.sort +description: > + Array.p.sort behaves correctly on TypedArrays backed by resizable buffers. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] + +---*/ + +// The default comparison function for Array.prototype.sort is the string sort. + +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, 0); + function WriteUnsortedData() { + // Write some data into the array. + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - 2 * i); + } + } + // Orig. array: [10, 8, 6, 4] + // [10, 8, 6, 4] << fixedLength + // [6, 4] << fixedLengthWithOffset + // [10, 8, 6, 4, ...] << lengthTracking + // [6, 4, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength); + assert.compareArray(ToNumbers(taFull), [ + 10, + 4, + 6, + 8 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLengthWithOffset); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking); + assert.compareArray(ToNumbers(taFull), [ + 10, + 4, + 6, + 8 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 8, 6] + // [10, 8, 6, ...] << lengthTracking + // [6, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 6 + ]); + Array.prototype.sort.call(fixedLengthWithOffset); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 6 + ]); + Array.prototype.sort.call(lengthTracking); + assert.compareArray(ToNumbers(taFull), [ + 10, + 6, + 8 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 6 + ]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), [10]); + Array.prototype.sort.call(fixedLengthWithOffset); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), [10]); + Array.prototype.sort.call(lengthTrackingWithOffset); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), [10]); + Array.prototype.sort.call(lengthTracking); + assert.compareArray(ToNumbers(taFull), [10]); + + // Shrink to zero. + rab.resize(0); + Array.prototype.sort.call(fixedLength); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), []); + Array.prototype.sort.call(fixedLengthWithOffset); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), []); + Array.prototype.sort.call(lengthTrackingWithOffset); // OOB -> NOOP + assert.compareArray(ToNumbers(taFull), []); + Array.prototype.sort.call(lengthTracking); + assert.compareArray(ToNumbers(taFull), []); + + // Grow so that all TAs are back in-bounds. + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 8, 6, 4, 2, 0] + // [10, 8, 6, 4] << fixedLength + // [6, 4] << fixedLengthWithOffset + // [10, 8, 6, 4, 2, 0, ...] << lengthTracking + // [6, 4, 2, 0, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + Array.prototype.sort.call(fixedLength); + assert.compareArray(ToNumbers(taFull), [ + 10, + 4, + 6, + 8, + 2, + 0 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(fixedLengthWithOffset); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6, + 2, + 0 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTracking); + assert.compareArray(ToNumbers(taFull), [ + 0, + 10, + 2, + 4, + 6, + 8 + ]); + WriteUnsortedData(); + Array.prototype.sort.call(lengthTrackingWithOffset); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 0, + 2, + 4, + 6 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/sort/comparefn-grow.js b/test/built-ins/TypedArray/prototype/sort/comparefn-grow.js new file mode 100644 index 0000000000..11f09bf467 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/sort/comparefn-grow.js @@ -0,0 +1,71 @@ +// 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.sort +description: > + TypedArray.p.sort behaves correctly on TypedArrays backed by resizable buffers + which are grown by the comparison callback. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +// Returns a function that resizes rab to size resizeTo and then compares its +// arguments. Such a result function is to be used as an argument to .sort. +function ResizeAndCompare(rab, resizeTo) { + return (a, b) => { + rab.resize(resizeTo); + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } +} + +function WriteUnsortedData(taFull) { + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } +} + +// Fixed length TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 6 * ctor.BYTES_PER_ELEMENT; + const fixedLength = new ctor(rab, 0, 4); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + fixedLength.sort(ResizeAndCompare(rab, resizeTo)); + // Growing doesn't affect the sorting. + assert.compareArray(ToNumbers(taFull), [ + 7, + 8, + 9, + 10, + 0, + 0 + ]); +} + +// Length-tracking TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 6 * ctor.BYTES_PER_ELEMENT; + const lengthTracking = new ctor(rab, 0); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + lengthTracking.sort(ResizeAndCompare(rab, resizeTo)); + // Growing doesn't affect the sorting. Only the elements that were part of + // the original TA are sorted. + assert.compareArray(ToNumbers(taFull), [ + 7, + 8, + 9, + 10, + 0, + 0 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/sort/comparefn-resizable-buffer.js b/test/built-ins/TypedArray/prototype/sort/comparefn-resizable-buffer.js new file mode 100644 index 0000000000..c3c8c93371 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/sort/comparefn-resizable-buffer.js @@ -0,0 +1,206 @@ +// 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.sort +description: > + TypedArray.p.sort behaves correctly on TypedArrays backed by resizable buffers + and passed a user-provided comparison callback. +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); + const taFull = new ctor(rab, 0); + function WriteUnsortedData() { + // Write some data into the array. + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } + } + function OddBeforeEvenComparison(a, b) { + // Sort all odd numbers before even numbers. + a = Number(a); + b = Number(b); + if (a % 2 == 1 && b % 2 == 0) { + return -1; + } + if (a % 2 == 0 && b % 2 == 1) { + return 1; + } + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } + // Orig. array: [10, 9, 8, 7] + // [10, 9, 8, 7] << fixedLength + // [8, 7] << fixedLengthWithOffset + // [10, 9, 8, 7, ...] << lengthTracking + // [8, 7, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + fixedLength.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10 + ]); + WriteUnsortedData(); + fixedLengthWithOffset.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8 + ]); + WriteUnsortedData(); + lengthTracking.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 9, 8] + // [10, 9, 8, ...] << lengthTracking + // [8, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLength.sort(OddBeforeEvenComparison); + }); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(OddBeforeEvenComparison); + }); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + WriteUnsortedData(); + lengthTracking.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 9, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 8 + ]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLength.sort(OddBeforeEvenComparison); + }); + assert.compareArray(ToNumbers(taFull), [10]); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(OddBeforeEvenComparison); + }); + assert.compareArray(ToNumbers(taFull), [10]); + assert.throws(TypeError, () => { + lengthTrackingWithOffset.sort(OddBeforeEvenComparison); + }); + assert.compareArray(ToNumbers(taFull), [10]); + + WriteUnsortedData(); + lengthTracking.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [10]); + + // Shrink to zero. + rab.resize(0); + assert.throws(TypeError, () => { + fixedLength.sort(OddBeforeEvenComparison); + }); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(OddBeforeEvenComparison); + }); + assert.throws(TypeError, () => { + lengthTrackingWithOffset.sort(OddBeforeEvenComparison); + }); + + lengthTracking.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), []); + + // Grow so that all TAs are back in-bounds. + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 9, 8, 7, 6, 5] + // [10, 9, 8, 7] << fixedLength + // [8, 7] << fixedLengthWithOffset + // [10, 9, 8, 7, 6, 5, ...] << lengthTracking + // [8, 7, 6, 5, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + fixedLength.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 7, + 9, + 8, + 10, + 6, + 5 + ]); + WriteUnsortedData(); + fixedLengthWithOffset.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 7, + 8, + 6, + 5 + ]); + WriteUnsortedData(); + lengthTracking.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 5, + 7, + 9, + 6, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(OddBeforeEvenComparison); + assert.compareArray(ToNumbers(taFull), [ + 10, + 9, + 5, + 7, + 6, + 8 + ]); +} diff --git a/test/built-ins/TypedArray/prototype/sort/comparefn-shrink.js b/test/built-ins/TypedArray/prototype/sort/comparefn-shrink.js new file mode 100644 index 0000000000..b057179066 --- /dev/null +++ b/test/built-ins/TypedArray/prototype/sort/comparefn-shrink.js @@ -0,0 +1,73 @@ +// 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.sort +description: > + TypedArray.p.sort behaves correctly on TypedArrays backed by a + resizable buffer and is shrunk by the comparison callback +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer, Array.prototype.includes] +---*/ + +// Returns a function that resizes rab to size resizeTo and then compares its +// arguments. Such a result function is to be used as an argument to .sort. +function ResizeAndCompare(rab, resizeTo) { + return (a, b) => { + rab.resize(resizeTo); + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; + } +} + +function WriteUnsortedData(taFull) { + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - i); + } +} + +// Fixed length TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 2 * ctor.BYTES_PER_ELEMENT; + const fixedLength = new ctor(rab, 0, 4); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + fixedLength.sort(ResizeAndCompare(rab, resizeTo)); + // The data is unchanged. + assert.compareArray(ToNumbers(taFull), [ + 10, + 9 + ]); +} + +// Length-tracking TA. +for (let ctor of ctors) { + const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); + const resizeTo = 2 * ctor.BYTES_PER_ELEMENT; + const lengthTracking = new ctor(rab, 0); + const taFull = new ctor(rab, 0); + WriteUnsortedData(taFull); + lengthTracking.sort(ResizeAndCompare(rab, resizeTo)); + // The sort result is implementation defined, but it contains 2 elements out + // of the 4 original ones. + const newData = ToNumbers(taFull); + assert.sameValue(newData.length, 2); + assert([ + 10, + 9, + 8, + 7 + ].includes(newData[0])); + assert([ + 10, + 9, + 8, + 7 + ].includes(newData[1])); +} diff --git a/test/built-ins/TypedArray/prototype/sort/resizable-buffer-default-comparator.js b/test/built-ins/TypedArray/prototype/sort/resizable-buffer-default-comparator.js new file mode 100644 index 0000000000..f3386199bd --- /dev/null +++ b/test/built-ins/TypedArray/prototype/sort/resizable-buffer-default-comparator.js @@ -0,0 +1,182 @@ +// 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.sort +description: > + TypedArray.p.sort behaves correctly on TypedArrays backed by resizable buffers. +includes: [compareArray.js, resizableArrayBufferUtils.js] +features: [resizable-arraybuffer] +---*/ + +// This test cannot be reused between TypedArray.protoype.sort and +// Array.prototype.sort, since the default sorting functions differ. + +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, 0); + function WriteUnsortedData() { + // Write some data into the array. + for (let i = 0; i < taFull.length; ++i) { + WriteToTypedArray(taFull, i, 10 - 2 * i); + } + } + // Orig. array: [10, 8, 6, 4] + // [10, 8, 6, 4] << fixedLength + // [6, 4] << fixedLengthWithOffset + // [10, 8, 6, 4, ...] << lengthTracking + // [6, 4, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + fixedLength.sort(); + assert.compareArray(ToNumbers(taFull), [ + 4, + 6, + 8, + 10 + ]); + WriteUnsortedData(); + fixedLengthWithOffset.sort(); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6 + ]); + WriteUnsortedData(); + lengthTracking.sort(); + assert.compareArray(ToNumbers(taFull), [ + 4, + 6, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6 + ]); + + // Shrink so that fixed length TAs go out of bounds. + rab.resize(3 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 8, 6] + // [10, 8, 6, ...] << lengthTracking + // [6, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLength.sort(); + }); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(); + }); + WriteUnsortedData(); + lengthTracking.sort(); + assert.compareArray(ToNumbers(taFull), [ + 6, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 6 + ]); + + // Shrink so that the TAs with offset go out of bounds. + rab.resize(1 * ctor.BYTES_PER_ELEMENT); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLength.sort(); + }); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(); + }); + WriteUnsortedData(); + lengthTracking.sort(); + assert.compareArray(ToNumbers(taFull), [10]); + WriteUnsortedData(); + assert.throws(TypeError, () => { + lengthTrackingWithOffset.sort(); + }); + + // Shrink to zero. + rab.resize(0); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLength.sort(); + }); + WriteUnsortedData(); + assert.throws(TypeError, () => { + fixedLengthWithOffset.sort(); + }); + WriteUnsortedData(); + lengthTracking.sort(); + assert.compareArray(ToNumbers(taFull), []); + WriteUnsortedData(); + assert.throws(TypeError, () => { + lengthTrackingWithOffset.sort(); + }); + + // Grow so that all TAs are back in-bounds. + rab.resize(6 * ctor.BYTES_PER_ELEMENT); + + // Orig. array: [10, 8, 6, 4, 2, 0] + // [10, 8, 6, 4] << fixedLength + // [6, 4] << fixedLengthWithOffset + // [10, 8, 6, 4, 2, 0, ...] << lengthTracking + // [6, 4, 2, 0, ...] << lengthTrackingWithOffset + + WriteUnsortedData(); + fixedLength.sort(); + assert.compareArray(ToNumbers(taFull), [ + 4, + 6, + 8, + 10, + 2, + 0 + ]); + WriteUnsortedData(); + fixedLengthWithOffset.sort(); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 4, + 6, + 2, + 0 + ]); + WriteUnsortedData(); + lengthTracking.sort(); + assert.compareArray(ToNumbers(taFull), [ + 0, + 2, + 4, + 6, + 8, + 10 + ]); + WriteUnsortedData(); + lengthTrackingWithOffset.sort(); + assert.compareArray(ToNumbers(taFull), [ + 10, + 8, + 0, + 2, + 4, + 6 + ]); +}