[cleanup] Use implicit context and sortState for most Call* macros
This CL changes most Call* macros (and some others) in Array#sort to pass the context and sortState implicitly. This improves readability, especially for loads and stores. R=jgruber@chromium.org, tebbi@chromium.org Bug: v8:8567 Change-Id: I6528d080bb01ab676de3ba6a7bf8223b98b6db7f Reviewed-on: https://chromium-review.googlesource.com/c/1450114 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Simon Zünd <szuend@chromium.org> Cr-Commit-Position: refs/heads/master@{#59320}
This commit is contained in:
parent
2e83e74992
commit
dc4c8bdb05
390
third_party/v8/builtins/array-sort.tq
vendored
390
third_party/v8/builtins/array-sort.tq
vendored
@ -344,8 +344,8 @@ namespace array {
|
||||
return SelectBooleanConstant(obj.map == initialReceiverMap);
|
||||
}
|
||||
|
||||
macro CallCompareFn(
|
||||
context: Context, sortState: FixedArray, x: Object, y: Object): Number
|
||||
macro CallCompareFn(implicit context: Context, sortState: FixedArray)(
|
||||
x: Object, y: Object): Number
|
||||
labels Bailout {
|
||||
const userCmpFn: Object = sortState[kUserCmpFnIdx];
|
||||
const sortCompare: CompareBuiltinFn =
|
||||
@ -479,40 +479,38 @@ namespace array {
|
||||
// readable since we can use labels and do not have to check kBailoutStatus
|
||||
// or the return value.
|
||||
|
||||
macro CallLoad(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, index: Smi): Object
|
||||
macro CallLoad(implicit context: Context, sortState: FixedArray)(
|
||||
load: LoadFn, index: Smi): Object
|
||||
labels Bailout {
|
||||
const result: Object = load(context, sortState, index);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
return result;
|
||||
}
|
||||
|
||||
macro CallStore(
|
||||
context: Context, sortState: FixedArray, store: StoreFn, index: Smi,
|
||||
value: Object) labels Bailout {
|
||||
macro CallStore(implicit context: Context, sortState: FixedArray)(
|
||||
store: StoreFn, index: Smi, value: Object) labels Bailout {
|
||||
store(context, sortState, index, value);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
}
|
||||
|
||||
transitioning macro CallCopyFromTempArray(
|
||||
context: Context, sortState: FixedArray, dstPos: Smi, srcPos: Smi,
|
||||
length: Smi)
|
||||
implicit context: Context,
|
||||
sortState: FixedArray)(dstPos: Smi, srcPos: Smi, length: Smi)
|
||||
labels Bailout {
|
||||
CopyFromTempArray(context, sortState, dstPos, srcPos, length);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
}
|
||||
|
||||
transitioning macro CallCopyWithinSortArray(
|
||||
context: Context, sortState: FixedArray, srcPos: Smi, dstPos: Smi,
|
||||
length: Smi)
|
||||
implicit context: Context,
|
||||
sortState: FixedArray)(srcPos: Smi, dstPos: Smi, length: Smi)
|
||||
labels Bailout {
|
||||
CopyWithinSortArray(context, sortState, srcPos, dstPos, length);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
}
|
||||
|
||||
macro CallGallopRight(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, key: Object,
|
||||
base: Smi, length: Smi, hint: Smi): Smi
|
||||
macro CallGallopRight(implicit context: Context, sortState: FixedArray)(
|
||||
load: LoadFn, key: Object, base: Smi, length: Smi, hint: Smi): Smi
|
||||
labels Bailout {
|
||||
const result: Smi =
|
||||
GallopRight(context, sortState, load, key, base, length, hint);
|
||||
@ -520,9 +518,8 @@ namespace array {
|
||||
return result;
|
||||
}
|
||||
|
||||
macro CallGallopLeft(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, key: Object,
|
||||
base: Smi, length: Smi, hint: Smi): Smi
|
||||
macro CallGallopLeft(implicit context: Context, sortState: FixedArray)(
|
||||
load: LoadFn, key: Object, base: Smi, length: Smi, hint: Smi): Smi
|
||||
labels Bailout {
|
||||
const result: Smi =
|
||||
GallopLeft(context, sortState, load, key, base, length, hint);
|
||||
@ -531,15 +528,16 @@ namespace array {
|
||||
}
|
||||
|
||||
transitioning macro
|
||||
CallMergeAt(context: Context, sortState: FixedArray, i: Smi)
|
||||
CallMergeAt(implicit context: Context, sortState: FixedArray)(i: Smi)
|
||||
labels Bailout {
|
||||
MergeAt(context, sortState, i);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
}
|
||||
|
||||
transitioning macro CopyToTempArray(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, srcPos: Smi,
|
||||
tempArray: FixedArray, dstPos: Smi, length: Smi)
|
||||
transitioning macro
|
||||
CopyToTempArray(implicit context: Context, sortState: FixedArray)(
|
||||
load: LoadFn, srcPos: Smi, tempArray: FixedArray, dstPos: Smi,
|
||||
length: Smi)
|
||||
labels Bailout {
|
||||
assert(srcPos >= 0);
|
||||
assert(dstPos >= 0);
|
||||
@ -551,8 +549,7 @@ namespace array {
|
||||
let to: Smi = srcPos + length;
|
||||
|
||||
while (srcIdx < to) {
|
||||
let element: Object = CallLoad(context, sortState, load, srcIdx++)
|
||||
otherwise Bailout;
|
||||
const element = CallLoad(load, srcIdx++) otherwise Bailout;
|
||||
tempArray[dstIdx++] = element;
|
||||
}
|
||||
}
|
||||
@ -573,8 +570,7 @@ namespace array {
|
||||
let to: Smi = srcPos + length;
|
||||
try {
|
||||
while (srcIdx < to) {
|
||||
CallStore(context, sortState, store, dstIdx++, tempArray[srcIdx++])
|
||||
otherwise Bailout;
|
||||
CallStore(store, dstIdx++, tempArray[srcIdx++]) otherwise Bailout;
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
@ -599,16 +595,14 @@ namespace array {
|
||||
let srcIdx: Smi = srcPos + length - 1;
|
||||
let dstIdx: Smi = dstPos + length - 1;
|
||||
while (srcIdx >= srcPos) {
|
||||
CopyElement(context, sortState, load, store, srcIdx--, dstIdx--)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, srcIdx--, dstIdx--) otherwise Bailout;
|
||||
}
|
||||
} else {
|
||||
let srcIdx: Smi = srcPos;
|
||||
let dstIdx: Smi = dstPos;
|
||||
let to: Smi = srcPos + length;
|
||||
while (srcIdx < to) {
|
||||
CopyElement(context, sortState, load, store, srcIdx++, dstIdx++)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, srcIdx++, dstIdx++) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
return kSuccess;
|
||||
@ -618,16 +612,16 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
// BinaryInsertionSort is the best method for sorting small arrays: it does
|
||||
// few compares, but can do data movement quadratic in the number of elements.
|
||||
// This is an advantage since comparisons are more expensive due to
|
||||
// calling into JS.
|
||||
// BinaryInsertionSort is the best method for sorting small arrays: it
|
||||
// does few compares, but can do data movement quadratic in the number of
|
||||
// elements. This is an advantage since comparisons are more expensive due
|
||||
// to calling into JS.
|
||||
//
|
||||
// [low, high) is a contiguous range of a array, and is sorted via
|
||||
// binary insertion. This sort is stable.
|
||||
//
|
||||
// On entry, must have low <= start <= high, and that [low, start) is already
|
||||
// sorted. Pass start == low if you do not know!.
|
||||
// On entry, must have low <= start <= high, and that [low, start) is
|
||||
// already sorted. Pass start == low if you do not know!.
|
||||
builtin BinaryInsertionSort(
|
||||
context: Context, sortState: FixedArray, low: Smi, startArg: Smi,
|
||||
high: Smi): Smi {
|
||||
@ -644,8 +638,7 @@ namespace array {
|
||||
let left: Smi = low;
|
||||
let right: Smi = start;
|
||||
|
||||
const pivot: Object = CallLoad(context, sortState, load, right)
|
||||
otherwise Bailout;
|
||||
const pivot = CallLoad(load, right) otherwise Bailout;
|
||||
|
||||
// Invariants:
|
||||
// pivot >= all in [low, left).
|
||||
@ -655,11 +648,8 @@ namespace array {
|
||||
// Find pivot insertion point.
|
||||
while (left < right) {
|
||||
const mid: Smi = left + ((right - left) >> 1);
|
||||
const midElement: Object = CallLoad(context, sortState, load, mid)
|
||||
otherwise Bailout;
|
||||
const order: Number =
|
||||
CallCompareFn(context, sortState, pivot, midElement)
|
||||
otherwise Bailout;
|
||||
const midElement = CallLoad(load, mid) otherwise Bailout;
|
||||
const order = CallCompareFn(pivot, midElement) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
right = mid;
|
||||
@ -673,16 +663,13 @@ namespace array {
|
||||
// pivot >= all in [low, left) and
|
||||
// pivot < all in [left, start),
|
||||
//
|
||||
// so pivot belongs at left. Note that if there are elements equal to
|
||||
// pivot, left points to the first slot after them -- that's why this
|
||||
// sort is stable.
|
||||
// Slide over to make room.
|
||||
// so pivot belongs at left. Note that if there are elements equal
|
||||
// to pivot, left points to the first slot after them -- that's why
|
||||
// this sort is stable. Slide over to make room.
|
||||
for (let p: Smi = start; p > left; --p) {
|
||||
CopyElement(context, sortState, load, store, p - 1, p)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, p - 1, p) otherwise Bailout;
|
||||
}
|
||||
CallStore(context, sortState, store, left, pivot)
|
||||
otherwise Bailout;
|
||||
CallStore(store, left, pivot) otherwise Bailout;
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
@ -691,9 +678,9 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the length of the run beginning at low, in the range [low, high),
|
||||
// low < high is required on entry.
|
||||
// "A run" is the longest ascending sequence, with
|
||||
// Return the length of the run beginning at low, in the range [low,
|
||||
// high), low < high is required on entry. "A run" is the longest
|
||||
// ascending sequence, with
|
||||
//
|
||||
// a[low] <= a[low + 1] <= a[low + 2] <= ...
|
||||
//
|
||||
@ -701,13 +688,13 @@ namespace array {
|
||||
//
|
||||
// a[low] > a[low + 1] > a[low + 2] > ...
|
||||
//
|
||||
// For its intended use in stable mergesort, the strictness of the definition
|
||||
// of "descending" is needed so that the range can safely be reversed
|
||||
// without violating stability (strict ">" ensures there are no equal
|
||||
// elements to get out of order).
|
||||
// For its intended use in stable mergesort, the strictness of the
|
||||
// definition of "descending" is needed so that the range can safely be
|
||||
// reversed without violating stability (strict ">" ensures there are no
|
||||
// equal elements to get out of order).
|
||||
//
|
||||
// In addition, if the run is "descending", it is reversed, so the returned
|
||||
// length is always an ascending sequence.
|
||||
// In addition, if the run is "descending", it is reversed, so the
|
||||
// returned length is always an ascending sequence.
|
||||
macro CountAndMakeRun(
|
||||
context: Context, sortState: FixedArray, lowArg: Smi, high: Smi): Smi
|
||||
labels Bailout {
|
||||
@ -721,13 +708,9 @@ namespace array {
|
||||
|
||||
let runLength: Smi = 2;
|
||||
|
||||
const elementLow: Object =
|
||||
CallLoad(context, sortState, load, low) otherwise Bailout;
|
||||
const elementLowPred: Object =
|
||||
CallLoad(context, sortState, load, low - 1) otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, elementLow, elementLowPred)
|
||||
otherwise Bailout;
|
||||
const elementLow = CallLoad(load, low) otherwise Bailout;
|
||||
const elementLowPred = CallLoad(load, low - 1) otherwise Bailout;
|
||||
let order = CallCompareFn(elementLow, elementLowPred) otherwise Bailout;
|
||||
|
||||
// TODO(szuend): Replace with "order < 0" once Torque supports it.
|
||||
// Currently the operator<(Number, Number) has return type
|
||||
@ -736,10 +719,8 @@ namespace array {
|
||||
|
||||
let previousElement: Object = elementLow;
|
||||
for (let idx: Smi = low + 1; idx < high; ++idx) {
|
||||
const currentElement: Object =
|
||||
CallLoad(context, sortState, load, idx) otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, currentElement, previousElement)
|
||||
otherwise Bailout;
|
||||
const currentElement = CallLoad(load, idx) otherwise Bailout;
|
||||
order = CallCompareFn(currentElement, previousElement) otherwise Bailout;
|
||||
|
||||
if (isDescending) {
|
||||
if (order >= 0) break;
|
||||
@ -767,14 +748,10 @@ namespace array {
|
||||
let high: Smi = to - 1;
|
||||
|
||||
while (low < high) {
|
||||
const elementLow: Object =
|
||||
CallLoad(context, sortState, load, low) otherwise Bailout;
|
||||
const elementHigh: Object =
|
||||
CallLoad(context, sortState, load, high) otherwise Bailout;
|
||||
CallStore(context, sortState, store, low++, elementHigh)
|
||||
otherwise Bailout;
|
||||
CallStore(context, sortState, store, high--, elementLow)
|
||||
otherwise Bailout;
|
||||
const elementLow = CallLoad(load, low) otherwise Bailout;
|
||||
const elementHigh = CallLoad(load, high) otherwise Bailout;
|
||||
CallStore(store, low++, elementHigh) otherwise Bailout;
|
||||
CallStore(store, high--, elementLow) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,10 +793,8 @@ namespace array {
|
||||
try {
|
||||
// Where does b start in a? Elements in a before that can be ignored,
|
||||
// because they are already in place.
|
||||
const keyRight: Object = CallLoad(context, sortState, load, baseB)
|
||||
otherwise Bailout;
|
||||
const k: Smi =
|
||||
CallGallopRight(context, sortState, load, keyRight, baseA, lengthA, 0)
|
||||
const keyRight = CallLoad(load, baseB) otherwise Bailout;
|
||||
const k: Smi = CallGallopRight(load, keyRight, baseA, lengthA, 0)
|
||||
otherwise Bailout;
|
||||
assert(k >= 0);
|
||||
|
||||
@ -830,11 +805,8 @@ namespace array {
|
||||
|
||||
// Where does a end in b? Elements in b after that can be ignored,
|
||||
// because they are already in place.
|
||||
let keyLeft: Object =
|
||||
CallLoad(context, sortState, load, baseA + lengthA - 1)
|
||||
otherwise Bailout;
|
||||
lengthB = CallGallopLeft(
|
||||
context, sortState, load, keyLeft, baseB, lengthB, lengthB - 1)
|
||||
let keyLeft = CallLoad(load, baseA + lengthA - 1) otherwise Bailout;
|
||||
lengthB = CallGallopLeft(load, keyLeft, baseB, lengthB, lengthB - 1)
|
||||
otherwise Bailout;
|
||||
assert(lengthB >= 0);
|
||||
if (lengthB == 0) return kSuccess;
|
||||
@ -842,11 +814,9 @@ namespace array {
|
||||
// Merge what remains of the runs, using a temp array with
|
||||
// min(lengthA, lengthB) elements.
|
||||
if (lengthA <= lengthB) {
|
||||
MergeLow(context, sortState, baseA, lengthA, baseB, lengthB)
|
||||
otherwise Bailout;
|
||||
MergeLow(baseA, lengthA, baseB, lengthB) otherwise Bailout;
|
||||
} else {
|
||||
MergeHigh(context, sortState, baseA, lengthA, baseB, lengthB)
|
||||
otherwise Bailout;
|
||||
MergeHigh(baseA, lengthA, baseB, lengthB) otherwise Bailout;
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
@ -855,16 +825,17 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
// Locates the proper position of key in a sorted array; if the array contains
|
||||
// an element equal to key, return the position immediately to the left of
|
||||
// the leftmost equal element. (GallopRight does the same except returns the
|
||||
// position to the right of the rightmost equal element (if any)).
|
||||
// Locates the proper position of key in a sorted array; if the array
|
||||
// contains an element equal to key, return the position immediately to
|
||||
// the left of the leftmost equal element. (GallopRight does the same
|
||||
// except returns the position to the right of the rightmost equal element
|
||||
// (if any)).
|
||||
//
|
||||
// The array is sorted with "length" elements, starting at "base".
|
||||
// "length" must be > 0.
|
||||
//
|
||||
// "hint" is an index at which to begin the search, 0 <= hint < n. The closer
|
||||
// hint is to the final result, the faster this runs.
|
||||
// "hint" is an index at which to begin the search, 0 <= hint < n. The
|
||||
// closer hint is to the final result, the faster this runs.
|
||||
//
|
||||
// The return value is the int offset in 0..length such that
|
||||
//
|
||||
@ -882,12 +853,8 @@ namespace array {
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, baseHintElement, key)
|
||||
otherwise Bailout;
|
||||
const baseHintElement = CallLoad(load, base + hint) otherwise Bailout;
|
||||
let order = CallCompareFn(baseHintElement, key) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
// a[base + hint] < key: gallop right, until
|
||||
@ -896,11 +863,9 @@ namespace array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
const offsetElement =
|
||||
CallLoad(load, base + hint + offset) otherwise Bailout;
|
||||
order = CallCompareFn(offsetElement, key) otherwise Bailout;
|
||||
|
||||
// a[base + hint + offset] >= key? Break.
|
||||
if (order >= 0) break;
|
||||
@ -925,11 +890,9 @@ namespace array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
const offsetElement =
|
||||
CallLoad(load, base + hint - offset) otherwise Bailout;
|
||||
order = CallCompareFn(offsetElement, key) otherwise Bailout;
|
||||
|
||||
if (order < 0) break;
|
||||
|
||||
@ -950,19 +913,16 @@ namespace array {
|
||||
|
||||
assert(-1 <= lastOfs && lastOfs < offset && offset <= length);
|
||||
|
||||
// Now a[base+lastOfs] < key <= a[base+offset], so key belongs somewhere
|
||||
// to the right of lastOfs but no farther right than offset. Do a binary
|
||||
// search, with invariant:
|
||||
// Now a[base+lastOfs] < key <= a[base+offset], so key belongs
|
||||
// somewhere to the right of lastOfs but no farther right than offset.
|
||||
// Do a binary search, with invariant:
|
||||
// a[base + lastOfs - 1] < key <= a[base + offset].
|
||||
lastOfs++;
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
|
||||
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, baseMElement, key)
|
||||
otherwise Bailout;
|
||||
const baseMElement = CallLoad(load, base + m) otherwise Bailout;
|
||||
order = CallCompareFn(baseMElement, key) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
lastOfs = m + 1; // a[base + m] < key.
|
||||
@ -981,8 +941,8 @@ namespace array {
|
||||
}
|
||||
|
||||
// Exactly like GallopLeft, except that if key already exists in
|
||||
// [base, base + length), finds the position immediately to the right of the
|
||||
// rightmost equal value.
|
||||
// [base, base + length), finds the position immediately to the right of
|
||||
// the rightmost equal value.
|
||||
//
|
||||
// The return value is the int offset in 0..length such that
|
||||
//
|
||||
@ -999,12 +959,8 @@ namespace array {
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, key, baseHintElement)
|
||||
otherwise Bailout;
|
||||
const baseHintElement = CallLoad(load, base + hint) otherwise Bailout;
|
||||
let order = CallCompareFn(key, baseHintElement) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
// key < a[base + hint]: gallop left, until
|
||||
@ -1013,11 +969,9 @@ namespace array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
const offsetElement =
|
||||
CallLoad(load, base + hint - offset) otherwise Bailout;
|
||||
order = CallCompareFn(key, offsetElement) otherwise Bailout;
|
||||
|
||||
if (order >= 0) break;
|
||||
|
||||
@ -1041,11 +995,9 @@ namespace array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
const offsetElement =
|
||||
CallLoad(load, base + hint + offset) otherwise Bailout;
|
||||
order = CallCompareFn(key, offsetElement) otherwise Bailout;
|
||||
|
||||
// a[base + hint + ofs] <= key.
|
||||
if (order < 0) break;
|
||||
@ -1073,11 +1025,8 @@ namespace array {
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
|
||||
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, baseMElement)
|
||||
otherwise Bailout;
|
||||
const baseMElement = CallLoad(load, base + m) otherwise Bailout;
|
||||
order = CallCompareFn(key, baseMElement) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
offset = m; // key < a[base + m].
|
||||
@ -1096,14 +1045,11 @@ namespace array {
|
||||
}
|
||||
|
||||
// Copies a single element inside the array/object (NOT the tempArray).
|
||||
macro CopyElement(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, store: StoreFn,
|
||||
from: Smi, to: Smi)
|
||||
macro CopyElement(implicit context: Context, sortState: FixedArray)(
|
||||
load: LoadFn, store: StoreFn, from: Smi, to: Smi)
|
||||
labels Bailout {
|
||||
const element: Object = CallLoad(context, sortState, load, from)
|
||||
otherwise Bailout;
|
||||
CallStore(context, sortState, store, to, element)
|
||||
otherwise Bailout;
|
||||
const element = CallLoad(load, from) otherwise Bailout;
|
||||
CallStore(store, to, element) otherwise Bailout;
|
||||
}
|
||||
|
||||
// Merge the lengthA elements starting at baseA with the lengthB elements
|
||||
@ -1113,8 +1059,9 @@ namespace array {
|
||||
// that array[baseA + lengthA - 1] belongs at the end of the merge,
|
||||
// and should have lengthA <= lengthB.
|
||||
transitioning macro MergeLow(
|
||||
context: Context, sortState: FixedArray, baseA: Smi, lengthAArg: Smi,
|
||||
baseB: Smi, lengthBArg: Smi)
|
||||
implicit context: Context,
|
||||
sortState:
|
||||
FixedArray)(baseA: Smi, lengthAArg: Smi, baseB: Smi, lengthBArg: Smi)
|
||||
labels Bailout {
|
||||
assert(0 < lengthAArg && 0 < lengthBArg);
|
||||
assert(0 <= baseA && 0 < baseB);
|
||||
@ -1127,15 +1074,13 @@ namespace array {
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
const tempArray: FixedArray = GetTempArray(sortState, lengthA);
|
||||
CopyToTempArray(context, sortState, load, baseA, tempArray, 0, lengthA)
|
||||
otherwise Bailout;
|
||||
CopyToTempArray(load, baseA, tempArray, 0, lengthA) otherwise Bailout;
|
||||
|
||||
let dest: Smi = baseA;
|
||||
let cursorTemp: Smi = 0;
|
||||
let cursorB: Smi = baseB;
|
||||
|
||||
CopyElement(context, sortState, load, store, cursorB++, dest++)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorB++, dest++) otherwise Bailout;
|
||||
|
||||
try {
|
||||
if (--lengthB == 0) goto Succeed;
|
||||
@ -1155,15 +1100,12 @@ namespace array {
|
||||
while (Int32TrueConstant()) {
|
||||
assert(lengthA > 1 && lengthB > 0);
|
||||
|
||||
let elementB: Object = CallLoad(context, sortState, load, cursorB)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, elementB, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
let elementB = CallLoad(load, cursorB) otherwise Bailout;
|
||||
let order =
|
||||
CallCompareFn(elementB, tempArray[cursorTemp]) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
CopyElement(context, sortState, load, store, cursorB, dest)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorB, dest) otherwise Bailout;
|
||||
|
||||
++cursorB;
|
||||
++dest;
|
||||
@ -1174,8 +1116,7 @@ namespace array {
|
||||
if (lengthB == 0) goto Succeed;
|
||||
if (nofWinsB >= minGallop) break;
|
||||
} else {
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
CallStore(store, dest, tempArray[cursorTemp]) otherwise Bailout;
|
||||
|
||||
++cursorTemp;
|
||||
++dest;
|
||||
@ -1188,9 +1129,9 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
// One run is winning so consistently that galloping may be a huge win.
|
||||
// So try that, and continue galloping until (if ever) neither run
|
||||
// appears to be winning consistently anymore.
|
||||
// One run is winning so consistently that galloping may be a huge
|
||||
// win. So try that, and continue galloping until (if ever) neither
|
||||
// run appears to be winning consistently anymore.
|
||||
++minGallop;
|
||||
let firstIteration: bool = true;
|
||||
while (nofWinsA >= kMinGallopWins || nofWinsB >= kMinGallopWins ||
|
||||
@ -1201,17 +1142,14 @@ namespace array {
|
||||
minGallop = SmiMax(1, minGallop - 1);
|
||||
sortState[kMinGallopIdx] = minGallop;
|
||||
|
||||
let keyRight: Object = CallLoad(context, sortState, load, cursorB)
|
||||
otherwise Bailout;
|
||||
let keyRight = CallLoad(load, cursorB) otherwise Bailout;
|
||||
nofWinsA = CallGallopRight(
|
||||
context, sortState, Load<TempArrayElements>, keyRight, cursorTemp,
|
||||
lengthA, 0) otherwise Bailout;
|
||||
Load<TempArrayElements>, keyRight, cursorTemp, lengthA, 0)
|
||||
otherwise Bailout;
|
||||
assert(nofWinsA >= 0);
|
||||
|
||||
if (nofWinsA > 0) {
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, dest, cursorTemp, nofWinsA)
|
||||
otherwise Bailout;
|
||||
CallCopyFromTempArray(dest, cursorTemp, nofWinsA) otherwise Bailout;
|
||||
dest = dest + nofWinsA;
|
||||
cursorTemp = cursorTemp + nofWinsA;
|
||||
lengthA = lengthA - nofWinsA;
|
||||
@ -1222,18 +1160,15 @@ namespace array {
|
||||
// consistent, but we can't assume that it is.
|
||||
if (lengthA == 0) goto Succeed;
|
||||
}
|
||||
CopyElement(context, sortState, load, store, cursorB++, dest++)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorB++, dest++) otherwise Bailout;
|
||||
if (--lengthB == 0) goto Succeed;
|
||||
|
||||
nofWinsB = CallGallopLeft(
|
||||
context, sortState, load, tempArray[cursorTemp], cursorB, lengthB,
|
||||
0)
|
||||
nofWinsB =
|
||||
CallGallopLeft(load, tempArray[cursorTemp], cursorB, lengthB, 0)
|
||||
otherwise Bailout;
|
||||
assert(nofWinsB >= 0);
|
||||
if (nofWinsB > 0) {
|
||||
CallCopyWithinSortArray(context, sortState, cursorB, dest, nofWinsB)
|
||||
otherwise Bailout;
|
||||
CallCopyWithinSortArray(cursorB, dest, nofWinsB) otherwise Bailout;
|
||||
|
||||
dest = dest + nofWinsB;
|
||||
cursorB = cursorB + nofWinsB;
|
||||
@ -1241,8 +1176,7 @@ namespace array {
|
||||
|
||||
if (lengthB == 0) goto Succeed;
|
||||
}
|
||||
CallStore(context, sortState, store, dest++, tempArray[cursorTemp++])
|
||||
otherwise Bailout;
|
||||
CallStore(store, dest++, tempArray[cursorTemp++]) otherwise Bailout;
|
||||
if (--lengthA == 1) goto CopyB;
|
||||
}
|
||||
++minGallop; // Penalize it for leaving galloping mode
|
||||
@ -1251,18 +1185,14 @@ namespace array {
|
||||
}
|
||||
label Succeed {
|
||||
if (lengthA > 0) {
|
||||
CallCopyFromTempArray(context, sortState, dest, cursorTemp, lengthA)
|
||||
otherwise Bailout;
|
||||
CallCopyFromTempArray(dest, cursorTemp, lengthA) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
label CopyB {
|
||||
assert(lengthA == 1 && lengthB > 0);
|
||||
// The last element of run A belongs at the end of the merge.
|
||||
CallCopyWithinSortArray(context, sortState, cursorB, dest, lengthB)
|
||||
otherwise Bailout;
|
||||
CallStore(
|
||||
context, sortState, store, dest + lengthB, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
CallCopyWithinSortArray(cursorB, dest, lengthB) otherwise Bailout;
|
||||
CallStore(store, dest + lengthB, tempArray[cursorTemp]) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1271,8 +1201,9 @@ namespace array {
|
||||
// be > 0. Must also have that array[baseA + lengthA - 1] belongs at the
|
||||
// end of the merge and should have lengthA >= lengthB.
|
||||
transitioning macro MergeHigh(
|
||||
context: Context, sortState: FixedArray, baseA: Smi, lengthAArg: Smi,
|
||||
baseB: Smi, lengthBArg: Smi)
|
||||
implicit context: Context,
|
||||
sortState:
|
||||
FixedArray)(baseA: Smi, lengthAArg: Smi, baseB: Smi, lengthBArg: Smi)
|
||||
labels Bailout {
|
||||
assert(0 < lengthAArg && 0 < lengthBArg);
|
||||
assert(0 <= baseA && 0 < baseB);
|
||||
@ -1285,16 +1216,14 @@ namespace array {
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
const tempArray: FixedArray = GetTempArray(sortState, lengthB);
|
||||
CopyToTempArray(context, sortState, load, baseB, tempArray, 0, lengthB)
|
||||
otherwise Bailout;
|
||||
CopyToTempArray(load, baseB, tempArray, 0, lengthB) otherwise Bailout;
|
||||
|
||||
// MergeHigh merges the two runs backwards.
|
||||
let dest: Smi = baseB + lengthB - 1;
|
||||
let cursorTemp: Smi = lengthB - 1;
|
||||
let cursorA: Smi = baseA + lengthA - 1;
|
||||
|
||||
CopyElement(context, sortState, load, store, cursorA--, dest--)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorA--, dest--) otherwise Bailout;
|
||||
|
||||
try {
|
||||
if (--lengthA == 0) goto Succeed;
|
||||
@ -1314,15 +1243,12 @@ namespace array {
|
||||
while (Int32TrueConstant()) {
|
||||
assert(lengthA > 0 && lengthB > 1);
|
||||
|
||||
let elementA: Object = CallLoad(context, sortState, load, cursorA)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, tempArray[cursorTemp], elementA)
|
||||
otherwise Bailout;
|
||||
let elementA = CallLoad(load, cursorA) otherwise Bailout;
|
||||
let order =
|
||||
CallCompareFn(tempArray[cursorTemp], elementA) otherwise Bailout;
|
||||
|
||||
if (order < 0) {
|
||||
CopyElement(context, sortState, load, store, cursorA, dest)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorA, dest) otherwise Bailout;
|
||||
|
||||
--cursorA;
|
||||
--dest;
|
||||
@ -1333,8 +1259,7 @@ namespace array {
|
||||
if (lengthA == 0) goto Succeed;
|
||||
if (nofWinsA >= minGallop) break;
|
||||
} else {
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
CallStore(store, dest, tempArray[cursorTemp]) otherwise Bailout;
|
||||
|
||||
--cursorTemp;
|
||||
--dest;
|
||||
@ -1347,9 +1272,9 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
// One run is winning so consistently that galloping may be a huge win.
|
||||
// So try that, and continue galloping until (if ever) neither run
|
||||
// appears to be winning consistently anymore.
|
||||
// One run is winning so consistently that galloping may be a huge
|
||||
// win. So try that, and continue galloping until (if ever) neither
|
||||
// run appears to be winning consistently anymore.
|
||||
++minGallop;
|
||||
let firstIteration: bool = true;
|
||||
while (nofWinsA >= kMinGallopWins || nofWinsB >= kMinGallopWins ||
|
||||
@ -1362,8 +1287,7 @@ namespace array {
|
||||
sortState[kMinGallopIdx] = minGallop;
|
||||
|
||||
let k: Smi = CallGallopRight(
|
||||
context, sortState, load, tempArray[cursorTemp], baseA, lengthA,
|
||||
lengthA - 1)
|
||||
load, tempArray[cursorTemp], baseA, lengthA, lengthA - 1)
|
||||
otherwise Bailout;
|
||||
assert(k >= 0);
|
||||
nofWinsA = lengthA - k;
|
||||
@ -1371,30 +1295,26 @@ namespace array {
|
||||
if (nofWinsA > 0) {
|
||||
dest = dest - nofWinsA;
|
||||
cursorA = cursorA - nofWinsA;
|
||||
CallCopyWithinSortArray(
|
||||
context, sortState, cursorA + 1, dest + 1, nofWinsA)
|
||||
CallCopyWithinSortArray(cursorA + 1, dest + 1, nofWinsA)
|
||||
otherwise Bailout;
|
||||
|
||||
lengthA = lengthA - nofWinsA;
|
||||
if (lengthA == 0) goto Succeed;
|
||||
}
|
||||
CallStore(context, sortState, store, dest--, tempArray[cursorTemp--])
|
||||
otherwise Bailout;
|
||||
CallStore(store, dest--, tempArray[cursorTemp--]) otherwise Bailout;
|
||||
if (--lengthB == 1) goto CopyA;
|
||||
|
||||
let key: Object = CallLoad(context, sortState, load, cursorA)
|
||||
otherwise Bailout;
|
||||
let key = CallLoad(load, cursorA) otherwise Bailout;
|
||||
k = CallGallopLeft(
|
||||
context, sortState, Load<TempArrayElements>, key, 0, lengthB,
|
||||
lengthB - 1) otherwise Bailout;
|
||||
Load<TempArrayElements>, key, 0, lengthB, lengthB - 1)
|
||||
otherwise Bailout;
|
||||
assert(k >= 0);
|
||||
nofWinsB = lengthB - k;
|
||||
|
||||
if (nofWinsB > 0) {
|
||||
dest = dest - nofWinsB;
|
||||
cursorTemp = cursorTemp - nofWinsB;
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, dest + 1, cursorTemp + 1, nofWinsB)
|
||||
CallCopyFromTempArray(dest + 1, cursorTemp + 1, nofWinsB)
|
||||
otherwise Bailout;
|
||||
|
||||
lengthB = lengthB - nofWinsB;
|
||||
@ -1404,8 +1324,7 @@ namespace array {
|
||||
// consistent, but we can't assume that it is.
|
||||
if (lengthB == 0) goto Succeed;
|
||||
}
|
||||
CopyElement(context, sortState, load, store, cursorA--, dest--)
|
||||
otherwise Bailout;
|
||||
CopyElement(load, store, cursorA--, dest--) otherwise Bailout;
|
||||
if (--lengthA == 0) goto Succeed;
|
||||
}
|
||||
++minGallop;
|
||||
@ -1415,8 +1334,7 @@ namespace array {
|
||||
label Succeed {
|
||||
if (lengthB > 0) {
|
||||
assert(lengthA == 0);
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, dest - (lengthB - 1), 0, lengthB)
|
||||
CallCopyFromTempArray(dest - (lengthB - 1), 0, lengthB)
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
@ -1426,16 +1344,13 @@ namespace array {
|
||||
// The first element of run B belongs at the front of the merge.
|
||||
dest = dest - lengthA;
|
||||
cursorA = cursorA - lengthA;
|
||||
CallCopyWithinSortArray(
|
||||
context, sortState, cursorA + 1, dest + 1, lengthA)
|
||||
otherwise Bailout;
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
CallCopyWithinSortArray(cursorA + 1, dest + 1, lengthA) otherwise Bailout;
|
||||
CallStore(store, dest, tempArray[cursorTemp]) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute a good value for the minimum run length; natural runs shorter than
|
||||
// this are boosted artificially via binary insertion sort.
|
||||
// Compute a good value for the minimum run length; natural runs shorter
|
||||
// than this are boosted artificially via binary insertion sort.
|
||||
//
|
||||
// If n < 64, return n (it's too small to bother with fancy stuff).
|
||||
// Else if n is an exact power of 2, return 32.
|
||||
@ -1495,11 +1410,11 @@ namespace array {
|
||||
--n;
|
||||
}
|
||||
|
||||
CallMergeAt(context, sortState, n) otherwise Bailout;
|
||||
CallMergeAt(n) otherwise Bailout;
|
||||
} else if (
|
||||
GetPendingRunLength(pendingRuns, n) <=
|
||||
GetPendingRunLength(pendingRuns, n + 1)) {
|
||||
CallMergeAt(context, sortState, n) otherwise Bailout;
|
||||
CallMergeAt(n) otherwise Bailout;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -1523,7 +1438,7 @@ namespace array {
|
||||
GetPendingRunLength(pendingRuns, n + 1)) {
|
||||
--n;
|
||||
}
|
||||
CallMergeAt(context, sortState, n) otherwise Bailout;
|
||||
CallMergeAt(n) otherwise Bailout;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1599,8 +1514,7 @@ namespace array {
|
||||
transitioning builtin
|
||||
ArrayTimSort(context: Context, sortState: FixedArray, length: Smi): Object {
|
||||
try {
|
||||
ArrayTimSortImpl(context, sortState, length)
|
||||
otherwise Slow;
|
||||
ArrayTimSortImpl(context, sortState, length) otherwise Slow;
|
||||
}
|
||||
label Slow {
|
||||
if (sortState[kAccessorIdx] == kGenericElementsAccessorId) {
|
||||
|
Loading…
Reference in New Issue
Block a user