Skip to content

Commit

Permalink
Bug 1763606 - Part 5: Sort TypedArray elements in a temporary buffer.…
Browse files Browse the repository at this point in the history
… r=tcampbell

<tc39/ecma262#1585> changed `Array.prototype.sort` to
first collect all elements in a temporary list. And because `TypedArray.prototype.sort`
follows `Array.prototype.sort`, the same copying has to happen here.

Depends on D143288

Differential Revision: https://phabricator.services.mozilla.com/D143289
  • Loading branch information
anba committed May 6, 2022
1 parent 94a65cf commit 52e851e
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 9 deletions.
29 changes: 20 additions & 9 deletions js/src/builtin/Sorting.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,31 @@ function MergeSortTypedArray(array, len, comparefn) {
assert(IsPossiblyWrappedTypedArray(array),
"MergeSortTypedArray works only with typed arrays.");

// Use the same TypedArray kind for the buffer.
var C = ConstructorForTypedArray(array);

var lBuffer = new C(len);

// Copy all elements into a temporary buffer, so that any modifications
// when calling |comparefn| are ignored.
for (var i = 0; i < len; i++) {
lBuffer[i] = array[i];
}

// Insertion sort for small arrays, where "small" is defined by performance
// testing.
if (len < 8) {
InsertionSort(array, 0, len - 1, comparefn);
InsertionSort(lBuffer, 0, len - 1, comparefn);

// Move the sorted elements into the array.
for (var i = 0; i < len; i++) {
array[i] = lBuffer[i];
}

return array;
}

// Use the same TypedArray kind for the buffer.
var C = ConstructorForTypedArray(array);

// We do all of our allocating up front.
var lBuffer = array;
var rBuffer = new C(len);

// Use insertion sort for the initial ranges.
Expand Down Expand Up @@ -204,10 +217,8 @@ function MergeSortTypedArray(array, len, comparefn) {
}

// Move the sorted elements into the array.
if (lBuffer !== array) {
for (var i = 0; i < len; i++) {
array[i] = lBuffer[i];
}
for (var i = 0; i < len; i++) {
array[i] = lBuffer[i];
}

return array;
Expand Down
73 changes: 73 additions & 0 deletions js/src/tests/non262/TypedArray/sort_modifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const TAConstructors = [
Int8Array,
Uint8Array,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Uint8ClampedArray,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
];

// Use different size classes to catch any implementation-specific
// optimisations.
const sizes = [
4, 8, 64, 128, 1024
];

function ToNumeric(TA) {
if (TA === BigInt64Array || TA === BigUint64Array) {
return BigInt;
}
return Number;
}

function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}

function descending(a, b) {
return -ascending(a, b);
}

for (let TA of TAConstructors) {
let toNumeric = ToNumeric(TA);
for (let size of sizes) {
let sorted = new TA(size);

// Fill with |1..size| and then sort to account for wrap-arounds.
for (let i = 0; i < size; ++i) {
sorted[i] = toNumeric(i + 1);
}
sorted.sort();

// Create a copy in descending order.
let ta = new TA(sorted);
ta.sort(descending);

// Sort the copy in ascending order and on the first call reset all
// elements to zero.
let called = false;
ta.sort(function(a, b) {
if (!called) {
called = true;
ta.fill(toNumeric(0));
}
return ascending(a, b);
});

// Ensure the comparator function was called.
assertEq(called, true);

// All elements should be sorted correctly. No elements should be zero.
for (let i = 0; i < size; ++i) {
assertEq(ta[i], sorted[i], `${TA.name} at index ${i} for size ${size}`);
}
}
}

if (typeof reportCompare === "function")
reportCompare(true, true);

0 comments on commit 52e851e

Please sign in to comment.