mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
Bug 1884360 part 6 - Use std_Array_sort in Array.prototype.toSorted. r=iain
Longer-term we could make `toSorted` itself a trampoline native, but that's more complicated and this patch gets us most of the performance and code reuse benefits. Differential Revision: https://phabricator.services.mozilla.com/D204629
This commit is contained in:
parent
9e031a7731
commit
fa62f291f8
@ -2028,46 +2028,6 @@ static bool FillWithUndefined(JSContext* cx, HandleObject obj, uint32_t start,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ArrayNativeSortImpl(JSContext* cx, Handle<JSObject*> obj,
|
||||
Handle<Value> fval, ComparatorMatchResult comp);
|
||||
|
||||
bool js::intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc, Value* vp) {
|
||||
// This function is called from the self-hosted Array.prototype.sort
|
||||
// implementation. It returns |true| if the array was sorted, otherwise it
|
||||
// returns |false| to notify the self-hosted code to perform the sorting.
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
|
||||
HandleValue fval = args[0];
|
||||
MOZ_ASSERT(fval.isUndefined() || IsCallable(fval));
|
||||
|
||||
ComparatorMatchResult comp;
|
||||
if (fval.isObject()) {
|
||||
comp = MatchNumericComparator(cx, &fval.toObject());
|
||||
if (comp == Match_Failure) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (comp == Match_None) {
|
||||
// Non-optimized user supplied comparators perform much better when
|
||||
// called from within a self-hosted sorting function.
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
comp = Match_None;
|
||||
}
|
||||
|
||||
Rooted<JSObject*> obj(cx, &args.thisv().toObject());
|
||||
|
||||
if (!ArrayNativeSortImpl(cx, obj, fval, comp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ArrayNativeSortImpl(JSContext* cx, Handle<JSObject*> obj,
|
||||
Handle<Value> fval,
|
||||
ComparatorMatchResult comp) {
|
||||
|
@ -111,9 +111,6 @@ extern bool GetElements(JSContext* cx, HandleObject aobj, uint32_t length,
|
||||
|
||||
/* Natives exposed for optimization by the interpreter and JITs. */
|
||||
|
||||
extern bool intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc,
|
||||
js::Value* vp);
|
||||
|
||||
extern bool array_includes(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
extern bool array_indexOf(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
extern bool array_lastIndexOf(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
@ -76,29 +76,6 @@ function ArraySome(callbackfn /*, thisArg*/) {
|
||||
// Inlining this enables inlining of the callback function.
|
||||
SetIsInlinableLargeFunction(ArraySome);
|
||||
|
||||
// ES2023 draft rev cb4224156c54156f30c18c50784c1b0148ebfae5
|
||||
// 23.1.3.30 Array.prototype.sort ( comparefn )
|
||||
function ArraySortCompare(comparefn) {
|
||||
return function(x, y) {
|
||||
// Steps 4.a-c.
|
||||
if (x === undefined) {
|
||||
if (y === undefined) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (y === undefined) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Step 4.d.i.
|
||||
var v = ToNumber(callContentFunction(comparefn, undefined, x, y));
|
||||
|
||||
// Steps 4.d.ii-iii.
|
||||
return v !== v ? 0 : v;
|
||||
};
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.18. */
|
||||
function ArrayForEach(callbackfn /*, thisArg*/) {
|
||||
/* Step 1. */
|
||||
@ -1279,22 +1256,8 @@ function ArrayToSorted(comparefn) {
|
||||
return items;
|
||||
}
|
||||
|
||||
// First try to sort the array in native code, if that fails, indicated by
|
||||
// returning |false| from ArrayNativeSort, sort it in self-hosted code.
|
||||
if (callFunction(ArrayNativeSort, items, comparefn)) {
|
||||
return items;
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
var wrappedCompareFn = ArraySortCompare(comparefn);
|
||||
|
||||
// Steps 6-9.
|
||||
var sorted = MergeSort(items, len, wrappedCompareFn);
|
||||
|
||||
assert(IsPackedArray(sorted), "sorted is a packed array");
|
||||
assert(sorted.length === len, "sorted array has the correct length");
|
||||
|
||||
return sorted;
|
||||
// Steps 5-9.
|
||||
return callFunction(std_Array_sort, items, comparefn);
|
||||
}
|
||||
|
||||
// https://github.com/tc39/proposal-array-find-from-last
|
||||
|
@ -6,7 +6,7 @@
|
||||
// consolidated here to avoid confusion and re-implementation of existing
|
||||
// algorithms.
|
||||
|
||||
// For sorting small arrays.
|
||||
// For sorting small typed arrays.
|
||||
function InsertionSort(array, from, to, comparefn) {
|
||||
var item, swap, i, j;
|
||||
for (i = from + 1; i <= to; i++) {
|
||||
@ -22,101 +22,6 @@ function InsertionSort(array, from, to, comparefn) {
|
||||
}
|
||||
}
|
||||
|
||||
// A helper function for MergeSort.
|
||||
//
|
||||
// Merge comparefn-sorted slices list[start..<=mid] and list[mid+1..<=end],
|
||||
// storing the merged sequence in out[start..<=end].
|
||||
function Merge(list, out, start, mid, end, comparefn) {
|
||||
// Skip lopsided runs to avoid doing useless work.
|
||||
// Skip calling the comparator if the sub-list is already sorted.
|
||||
if (
|
||||
mid >= end ||
|
||||
callContentFunction(comparefn, undefined, list[mid], list[mid + 1]) <= 0
|
||||
) {
|
||||
for (var i = start; i <= end; i++) {
|
||||
DefineDataProperty(out, i, list[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var i = start;
|
||||
var j = mid + 1;
|
||||
var k = start;
|
||||
while (i <= mid && j <= end) {
|
||||
var lvalue = list[i];
|
||||
var rvalue = list[j];
|
||||
if (callContentFunction(comparefn, undefined, lvalue, rvalue) <= 0) {
|
||||
DefineDataProperty(out, k++, lvalue);
|
||||
i++;
|
||||
} else {
|
||||
DefineDataProperty(out, k++, rvalue);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty out any remaining elements.
|
||||
while (i <= mid) {
|
||||
DefineDataProperty(out, k++, list[i++]);
|
||||
}
|
||||
while (j <= end) {
|
||||
DefineDataProperty(out, k++, list[j++]);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for overwriting a sparse array with a
|
||||
// dense array, filling remaining slots with holes.
|
||||
function MoveHoles(sparse, sparseLen, dense, denseLen) {
|
||||
for (var i = 0; i < denseLen; i++) {
|
||||
sparse[i] = dense[i];
|
||||
}
|
||||
for (var j = denseLen; j < sparseLen; j++) {
|
||||
delete sparse[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Iterative, bottom up, mergesort.
|
||||
function MergeSort(array, len, comparefn) {
|
||||
assert(IsPackedArray(array), "array is packed");
|
||||
assert(array.length === len, "length mismatch");
|
||||
assert(len > 0, "array should be non-empty");
|
||||
|
||||
// Insertion sort for small arrays, where "small" is defined by performance
|
||||
// testing.
|
||||
if (len < 24) {
|
||||
InsertionSort(array, 0, len - 1, comparefn);
|
||||
return array;
|
||||
}
|
||||
|
||||
// We do all of our allocating up front
|
||||
var lBuffer = array;
|
||||
var rBuffer = [];
|
||||
|
||||
// Use insertion sort for initial ranges.
|
||||
var windowSize = 4;
|
||||
for (var start = 0; start < len - 1; start += windowSize) {
|
||||
var end = std_Math_min(start + windowSize - 1, len - 1);
|
||||
InsertionSort(lBuffer, start, end, comparefn);
|
||||
}
|
||||
|
||||
for (; windowSize < len; windowSize = 2 * windowSize) {
|
||||
for (var start = 0; start < len; start += 2 * windowSize) {
|
||||
// The midpoint between the two subarrays.
|
||||
var mid = start + windowSize - 1;
|
||||
|
||||
// To keep from going over the edge.
|
||||
var end = std_Math_min(start + 2 * windowSize - 1, len - 1);
|
||||
|
||||
Merge(lBuffer, rBuffer, start, mid, end, comparefn);
|
||||
}
|
||||
|
||||
// Swap both lists.
|
||||
var swap = lBuffer;
|
||||
lBuffer = rBuffer;
|
||||
rBuffer = swap;
|
||||
}
|
||||
return lBuffer;
|
||||
}
|
||||
|
||||
// A helper function for MergeSortTypedArray.
|
||||
//
|
||||
// Merge comparefn-sorted slices list[start..<=mid] and list[mid+1..<=end],
|
||||
|
@ -1963,7 +1963,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable",
|
||||
intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0,
|
||||
IntrinsicArrayIteratorPrototypeOptimizable),
|
||||
JS_FN("ArrayNativeSort", intrinsic_ArrayNativeSort, 1, 0),
|
||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0),
|
||||
JS_FN("CallArrayBufferMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
|
||||
|
Loading…
Reference in New Issue
Block a user