[cleanup] Remove usage of 'ReloadElements' from Array#sort
This CL is mostly a mechanical change. Loading either the receiver, the backing store or the temp array from the sort state is pushed down into each respective Load/Store builtin. This eliminates the need for reloading the elements pointer after each compare function call. R=jgruber@chromium.org, tebbi@chromium.org Bug: v8:8562 Change-Id: I453e98635f9d891da58cf7b2a86c5c58f4a4069c Reviewed-on: https://chromium-review.googlesource.com/c/1449613 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@{#59291}
This commit is contained in:
parent
30c1199f77
commit
0b2fa277fb
411
third_party/v8/builtins/array-sort.tq
vendored
411
third_party/v8/builtins/array-sort.tq
vendored
@ -112,8 +112,8 @@ namespace array {
|
||||
// it is first requested, but it has always at least this size.
|
||||
const kSortStateTempSize: Smi = 32;
|
||||
|
||||
type LoadFn = builtin(Context, FixedArray, HeapObject, Smi) => Object;
|
||||
type StoreFn = builtin(Context, FixedArray, HeapObject, Smi, Object) => Smi;
|
||||
type LoadFn = builtin(Context, FixedArray, Smi) => Object;
|
||||
type StoreFn = builtin(Context, FixedArray, Smi, Object) => Smi;
|
||||
type CanUseSameAccessorFn = builtin(Context, JSReceiver, Object, Number) =>
|
||||
Boolean;
|
||||
type CompareBuiltinFn = builtin(Context, Object, Object, Object) => Number;
|
||||
@ -125,23 +125,25 @@ namespace array {
|
||||
// through a hole.
|
||||
|
||||
transitioning builtin Load<ElementsAccessor: type>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
return GetProperty(elements, index);
|
||||
context: Context, sortState: FixedArray, index: Smi): Object {
|
||||
const receiver = GetReceiver(sortState);
|
||||
return GetProperty(receiver, index);
|
||||
}
|
||||
|
||||
Load<FastPackedSmiElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
return elems[index];
|
||||
context: Context, sortState: FixedArray, index: Smi): Object {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedArray>(object.elements);
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
Load<FastSmiOrObjectElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
const result: Object = elems[index];
|
||||
context: Context, sortState: FixedArray, index: Smi): Object {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedArray>(object.elements);
|
||||
const result: Object = elements[index];
|
||||
if (IsTheHole(result)) {
|
||||
// The pre-processing step removed all holes by compacting all elements
|
||||
// at the start of the array. Finding a hole means the cmp function or
|
||||
@ -151,13 +153,13 @@ namespace array {
|
||||
return result;
|
||||
}
|
||||
|
||||
Load<FastDoubleElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
Load<FastDoubleElements>(context: Context, sortState: FixedArray, index: Smi):
|
||||
Object {
|
||||
try {
|
||||
const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
|
||||
const value: float64 =
|
||||
LoadDoubleWithHoleCheck(elems, index) otherwise Bailout;
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedDoubleArray>(object.elements);
|
||||
const value = LoadDoubleWithHoleCheck(elements, index) otherwise Bailout;
|
||||
return AllocateHeapNumberWithValue(value);
|
||||
}
|
||||
label Bailout {
|
||||
@ -168,70 +170,71 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
Load<DictionaryElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
Load<DictionaryElements>(context: Context, sortState: FixedArray, index: Smi):
|
||||
Object {
|
||||
try {
|
||||
const dictionary: NumberDictionary =
|
||||
UnsafeCast<NumberDictionary>(elements);
|
||||
const intptrIndex: intptr = Convert<intptr>(index);
|
||||
const value: Object =
|
||||
BasicLoadNumberDictionaryElement(dictionary, intptrIndex)
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const dictionary = UnsafeCast<NumberDictionary>(object.elements);
|
||||
const intptrIndex = Convert<intptr>(index);
|
||||
return BasicLoadNumberDictionaryElement(dictionary, intptrIndex)
|
||||
otherwise Bailout, Bailout;
|
||||
return value;
|
||||
}
|
||||
label Bailout {
|
||||
return Failure(sortState);
|
||||
}
|
||||
}
|
||||
|
||||
Load<TempArrayElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
index: Smi): Object {
|
||||
Load<TempArrayElements>(context: Context, sortState: FixedArray, index: Smi):
|
||||
Object {
|
||||
const elements = GetTempArray(sortState);
|
||||
assert(IsFixedArray(elements));
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
return elems[index];
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
transitioning builtin Store<ElementsAccessor: type>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
SetProperty(elements, index, value);
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const receiver = GetReceiver(sortState);
|
||||
SetProperty(receiver, index, value);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Store<FastPackedSmiElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
StoreFixedArrayElementSmi(elems, index, value, SKIP_WRITE_BARRIER);
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedArray>(object.elements);
|
||||
StoreFixedArrayElementSmi(elements, index, value, SKIP_WRITE_BARRIER);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Store<FastSmiOrObjectElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
elems[index] = value;
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedArray>(object.elements);
|
||||
elements[index] = value;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Store<FastDoubleElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
|
||||
const heapVal: HeapNumber = UnsafeCast<HeapNumber>(value);
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const elements = UnsafeCast<FixedDoubleArray>(object.elements);
|
||||
const heapVal = UnsafeCast<HeapNumber>(value);
|
||||
// Make sure we do not store signalling NaNs into double arrays.
|
||||
const val: float64 = Float64SilenceNaN(Convert<float64>(heapVal));
|
||||
StoreFixedDoubleArrayElementWithSmiIndex(elems, index, val);
|
||||
const val = Float64SilenceNaN(Convert<float64>(heapVal));
|
||||
StoreFixedDoubleArrayElementWithSmiIndex(elements, index, val);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Store<DictionaryElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
const dictionary: NumberDictionary = UnsafeCast<NumberDictionary>(elements);
|
||||
const intptrIndex: intptr = Convert<intptr>(index);
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const receiver = GetReceiver(sortState);
|
||||
const object = UnsafeCast<JSObject>(receiver);
|
||||
const dictionary = UnsafeCast<NumberDictionary>(object.elements);
|
||||
const intptrIndex = Convert<intptr>(index);
|
||||
try {
|
||||
BasicStoreNumberDictionaryElement(dictionary, intptrIndex, value)
|
||||
otherwise Fail, Fail, ReadOnly;
|
||||
@ -240,7 +243,7 @@ namespace array {
|
||||
label ReadOnly {
|
||||
// We cannot write to read-only data properties. Throw the same TypeError
|
||||
// as SetProperty would.
|
||||
const receiver: JSReceiver = GetReceiver(sortState);
|
||||
const receiver = GetReceiver(sortState);
|
||||
ThrowTypeError(
|
||||
context, kStrictReadOnlyProperty, index, Typeof(receiver), receiver);
|
||||
}
|
||||
@ -250,10 +253,9 @@ namespace array {
|
||||
}
|
||||
|
||||
Store<TempArrayElements>(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject, index: Smi,
|
||||
value: Object): Smi {
|
||||
const elems: FixedArray = UnsafeCast<FixedArray>(elements);
|
||||
elems[index] = value;
|
||||
context: Context, sortState: FixedArray, index: Smi, value: Object): Smi {
|
||||
const elements = GetTempArray(sortState);
|
||||
elements[index] = value;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
@ -281,10 +283,10 @@ namespace array {
|
||||
}
|
||||
|
||||
// 5. Let xString be ? ToString(x).
|
||||
const xString: String = ToString_Inline(context, x);
|
||||
const xString = ToString_Inline(context, x);
|
||||
|
||||
// 6. Let yString be ? ToString(y).
|
||||
const yString: String = ToString_Inline(context, y);
|
||||
const yString = ToString_Inline(context, y);
|
||||
|
||||
// 7. Let xSmaller be the result of performing
|
||||
// Abstract Relational Comparison xString < yString.
|
||||
@ -303,11 +305,10 @@ namespace array {
|
||||
transitioning builtin SortCompareUserFn(
|
||||
context: Context, comparefn: Object, x: Object, y: Object): Number {
|
||||
assert(comparefn != Undefined);
|
||||
const cmpfn: Callable = UnsafeCast<Callable>(comparefn);
|
||||
const cmpfn = UnsafeCast<Callable>(comparefn);
|
||||
|
||||
// a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)).
|
||||
const v: Number =
|
||||
ToNumber_Inline(context, Call(context, cmpfn, Undefined, x, y));
|
||||
const v = ToNumber_Inline(context, Call(context, cmpfn, Undefined, x, y));
|
||||
|
||||
// b. If v is NaN, return +0.
|
||||
if (NumberIsNaN(v)) return 0;
|
||||
@ -365,19 +366,6 @@ namespace array {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reloading elements after returning from JS is needed since left-trimming
|
||||
// might have occurred. This means we cannot leave any pointer to the elements
|
||||
// backing store on the stack (since it would point to the filler object).
|
||||
// TODO(v8:7995): Remove reloading once left-trimming is removed.
|
||||
macro ReloadElements(implicit context: Context)(sortState: FixedArray):
|
||||
HeapObject {
|
||||
const receiver: JSReceiver = GetReceiver(sortState);
|
||||
if (sortState[kAccessorIdx] == kGenericElementsAccessorId) return receiver;
|
||||
|
||||
const object: JSObject = UnsafeCast<JSObject>(receiver);
|
||||
return object.elements;
|
||||
}
|
||||
|
||||
macro GetInitialReceiverLength(implicit context:
|
||||
Context)(sortState: FixedArray): Number {
|
||||
return UnsafeCast<Number>(sortState[kInitialReceiverLengthIdx]);
|
||||
@ -492,54 +480,52 @@ namespace array {
|
||||
// or the return value.
|
||||
|
||||
macro CallLoad(
|
||||
context: Context, sortState: FixedArray, load: LoadFn,
|
||||
elements: HeapObject, index: Smi): Object
|
||||
context: Context, sortState: FixedArray, load: LoadFn, index: Smi): Object
|
||||
labels Bailout {
|
||||
const result: Object = load(context, sortState, elements, index);
|
||||
const result: Object = load(context, sortState, index);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
return result;
|
||||
}
|
||||
|
||||
macro CallStore(
|
||||
context: Context, sortState: FixedArray, store: StoreFn,
|
||||
elements: HeapObject, index: Smi, value: Object) labels Bailout {
|
||||
store(context, sortState, elements, index, value);
|
||||
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, dstElements: HeapObject,
|
||||
dstPos: Smi, tempArray: FixedArray, srcPos: Smi, length: Smi)
|
||||
context: Context, sortState: FixedArray, dstPos: Smi, srcPos: Smi,
|
||||
length: Smi)
|
||||
labels Bailout {
|
||||
CopyFromTempArray(
|
||||
context, sortState, dstElements, dstPos, tempArray, srcPos, length);
|
||||
CopyFromTempArray(context, sortState, dstPos, srcPos, length);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
}
|
||||
|
||||
transitioning macro CallCopyWithinSortArray(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
srcPos: Smi, dstPos: Smi, length: Smi)
|
||||
context: Context, sortState: FixedArray, srcPos: Smi, dstPos: Smi,
|
||||
length: Smi)
|
||||
labels Bailout {
|
||||
CopyWithinSortArray(context, sortState, elements, srcPos, dstPos, length);
|
||||
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, useTempArray: Boolean): Smi
|
||||
base: Smi, length: Smi, hint: Smi): Smi
|
||||
labels Bailout {
|
||||
const result: Smi = GallopRight(
|
||||
context, sortState, load, key, base, length, hint, useTempArray);
|
||||
const result: Smi =
|
||||
GallopRight(context, sortState, load, key, base, length, hint);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
return result;
|
||||
}
|
||||
|
||||
macro CallGallopLeft(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, key: Object,
|
||||
base: Smi, length: Smi, hint: Smi, useTempArray: Boolean): Smi
|
||||
base: Smi, length: Smi, hint: Smi): Smi
|
||||
labels Bailout {
|
||||
const result: Smi = GallopLeft(
|
||||
context, sortState, load, key, base, length, hint, useTempArray);
|
||||
const result: Smi =
|
||||
GallopLeft(context, sortState, load, key, base, length, hint);
|
||||
EnsureSuccess(sortState) otherwise Bailout;
|
||||
return result;
|
||||
}
|
||||
@ -552,9 +538,8 @@ namespace array {
|
||||
}
|
||||
|
||||
transitioning macro CopyToTempArray(
|
||||
context: Context, sortState: FixedArray, load: LoadFn,
|
||||
srcElements: HeapObject, srcPos: Smi, tempArray: FixedArray, dstPos: Smi,
|
||||
length: Smi)
|
||||
context: Context, sortState: FixedArray, load: LoadFn, srcPos: Smi,
|
||||
tempArray: FixedArray, dstPos: Smi, length: Smi)
|
||||
labels Bailout {
|
||||
assert(srcPos >= 0);
|
||||
assert(dstPos >= 0);
|
||||
@ -566,16 +551,16 @@ namespace array {
|
||||
let to: Smi = srcPos + length;
|
||||
|
||||
while (srcIdx < to) {
|
||||
let element: Object =
|
||||
CallLoad(context, sortState, load, srcElements, srcIdx++)
|
||||
let element: Object = CallLoad(context, sortState, load, srcIdx++)
|
||||
otherwise Bailout;
|
||||
tempArray[dstIdx++] = element;
|
||||
}
|
||||
}
|
||||
|
||||
transitioning builtin CopyFromTempArray(
|
||||
context: Context, sortState: FixedArray, dstElements: HeapObject,
|
||||
dstPos: Smi, tempArray: FixedArray, srcPos: Smi, length: Smi): Smi {
|
||||
context: Context, sortState: FixedArray, dstPos: Smi, srcPos: Smi,
|
||||
length: Smi): Smi {
|
||||
const tempArray = GetTempArray(sortState);
|
||||
assert(srcPos >= 0);
|
||||
assert(dstPos >= 0);
|
||||
assert(srcPos <= tempArray.length - length);
|
||||
@ -588,9 +573,7 @@ namespace array {
|
||||
let to: Smi = srcPos + length;
|
||||
try {
|
||||
while (srcIdx < to) {
|
||||
CallStore(
|
||||
context, sortState, store, dstElements, dstIdx++,
|
||||
tempArray[srcIdx++])
|
||||
CallStore(context, sortState, store, dstIdx++, tempArray[srcIdx++])
|
||||
otherwise Bailout;
|
||||
}
|
||||
return kSuccess;
|
||||
@ -601,8 +584,8 @@ namespace array {
|
||||
}
|
||||
|
||||
transitioning builtin CopyWithinSortArray(
|
||||
context: Context, sortState: FixedArray, elements: HeapObject,
|
||||
srcPos: Smi, dstPos: Smi, length: Smi): Smi {
|
||||
context: Context, sortState: FixedArray, srcPos: Smi, dstPos: Smi,
|
||||
length: Smi): Smi {
|
||||
assert(srcPos >= 0);
|
||||
assert(dstPos >= 0);
|
||||
assert(srcPos <= GetInitialReceiverLength(sortState) - length);
|
||||
@ -616,8 +599,7 @@ namespace array {
|
||||
let srcIdx: Smi = srcPos + length - 1;
|
||||
let dstIdx: Smi = dstPos + length - 1;
|
||||
while (srcIdx >= srcPos) {
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, srcIdx--, dstIdx--)
|
||||
CopyElement(context, sortState, load, store, srcIdx--, dstIdx--)
|
||||
otherwise Bailout;
|
||||
}
|
||||
} else {
|
||||
@ -625,8 +607,7 @@ namespace array {
|
||||
let dstIdx: Smi = dstPos;
|
||||
let to: Smi = srcPos + length;
|
||||
while (srcIdx < to) {
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, srcIdx++, dstIdx++)
|
||||
CopyElement(context, sortState, load, store, srcIdx++, dstIdx++)
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
@ -653,8 +634,6 @@ namespace array {
|
||||
assert(low <= startArg && startArg <= high);
|
||||
|
||||
try {
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
@ -665,8 +644,7 @@ namespace array {
|
||||
let left: Smi = low;
|
||||
let right: Smi = start;
|
||||
|
||||
const pivot: Object =
|
||||
CallLoad(context, sortState, load, elements, right)
|
||||
const pivot: Object = CallLoad(context, sortState, load, right)
|
||||
otherwise Bailout;
|
||||
|
||||
// Invariants:
|
||||
@ -677,13 +655,11 @@ namespace array {
|
||||
// Find pivot insertion point.
|
||||
while (left < right) {
|
||||
const mid: Smi = left + ((right - left) >> 1);
|
||||
const midElement: Object =
|
||||
CallLoad(context, sortState, load, elements, mid)
|
||||
const midElement: Object = CallLoad(context, sortState, load, mid)
|
||||
otherwise Bailout;
|
||||
const order: Number =
|
||||
CallCompareFn(context, sortState, pivot, midElement)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
|
||||
if (order < 0) {
|
||||
right = mid;
|
||||
@ -702,10 +678,10 @@ namespace array {
|
||||
// sort is stable.
|
||||
// Slide over to make room.
|
||||
for (let p: Smi = start; p > left; --p) {
|
||||
CopyElement(context, sortState, load, store, elements, p - 1, p)
|
||||
CopyElement(context, sortState, load, store, p - 1, p)
|
||||
otherwise Bailout;
|
||||
}
|
||||
CallStore(context, sortState, store, elements, left, pivot)
|
||||
CallStore(context, sortState, store, left, pivot)
|
||||
otherwise Bailout;
|
||||
}
|
||||
return kSuccess;
|
||||
@ -737,7 +713,6 @@ namespace array {
|
||||
labels Bailout {
|
||||
assert(lowArg < high);
|
||||
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
@ -747,13 +722,12 @@ namespace array {
|
||||
let runLength: Smi = 2;
|
||||
|
||||
const elementLow: Object =
|
||||
CallLoad(context, sortState, load, elements, low) otherwise Bailout;
|
||||
CallLoad(context, sortState, load, low) otherwise Bailout;
|
||||
const elementLowPred: Object =
|
||||
CallLoad(context, sortState, load, elements, low - 1) otherwise Bailout;
|
||||
CallLoad(context, sortState, load, low - 1) otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, elementLow, elementLowPred)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
|
||||
// TODO(szuend): Replace with "order < 0" once Torque supports it.
|
||||
// Currently the operator<(Number, Number) has return type
|
||||
@ -763,10 +737,9 @@ namespace array {
|
||||
let previousElement: Object = elementLow;
|
||||
for (let idx: Smi = low + 1; idx < high; ++idx) {
|
||||
const currentElement: Object =
|
||||
CallLoad(context, sortState, load, elements, idx) otherwise Bailout;
|
||||
CallLoad(context, sortState, load, idx) otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, currentElement, previousElement)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
|
||||
if (isDescending) {
|
||||
if (order >= 0) break;
|
||||
@ -779,8 +752,7 @@ namespace array {
|
||||
}
|
||||
|
||||
if (isDescending) {
|
||||
ReverseRange(
|
||||
context, sortState, load, store, elements, lowArg, lowArg + runLength)
|
||||
ReverseRange(context, sortState, load, store, lowArg, lowArg + runLength)
|
||||
otherwise Bailout;
|
||||
}
|
||||
|
||||
@ -789,19 +761,19 @@ namespace array {
|
||||
|
||||
macro ReverseRange(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, store: StoreFn,
|
||||
elements: HeapObject, from: Smi, to: Smi)
|
||||
from: Smi, to: Smi)
|
||||
labels Bailout {
|
||||
let low: Smi = from;
|
||||
let high: Smi = to - 1;
|
||||
|
||||
while (low < high) {
|
||||
const elementLow: Object =
|
||||
CallLoad(context, sortState, load, elements, low) otherwise Bailout;
|
||||
CallLoad(context, sortState, load, low) otherwise Bailout;
|
||||
const elementHigh: Object =
|
||||
CallLoad(context, sortState, load, elements, high) otherwise Bailout;
|
||||
CallStore(context, sortState, store, elements, low++, elementHigh)
|
||||
CallLoad(context, sortState, load, high) otherwise Bailout;
|
||||
CallStore(context, sortState, store, low++, elementHigh)
|
||||
otherwise Bailout;
|
||||
CallStore(context, sortState, store, elements, high--, elementLow)
|
||||
CallStore(context, sortState, store, high--, elementLow)
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
@ -818,7 +790,6 @@ namespace array {
|
||||
assert(i >= 0);
|
||||
assert(i == stackSize - 2 || i == stackSize - 3);
|
||||
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
|
||||
const pendingRuns: FixedArray =
|
||||
@ -845,13 +816,11 @@ 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, elements, baseB)
|
||||
const keyRight: Object = CallLoad(context, sortState, load, baseB)
|
||||
otherwise Bailout;
|
||||
const k: Smi = CallGallopRight(
|
||||
context, sortState, load, keyRight, baseA, lengthA, 0, False)
|
||||
const k: Smi =
|
||||
CallGallopRight(context, sortState, load, keyRight, baseA, lengthA, 0)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(k >= 0);
|
||||
|
||||
baseA = baseA + k;
|
||||
@ -862,12 +831,11 @@ 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, elements, baseA + lengthA - 1)
|
||||
CallLoad(context, sortState, load, baseA + lengthA - 1)
|
||||
otherwise Bailout;
|
||||
lengthB = CallGallopLeft(
|
||||
context, sortState, load, keyLeft, baseB, lengthB, lengthB - 1, False)
|
||||
context, sortState, load, keyLeft, baseB, lengthB, lengthB - 1)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(lengthB >= 0);
|
||||
if (lengthB == 0) return kSuccess;
|
||||
|
||||
@ -887,12 +855,6 @@ namespace array {
|
||||
}
|
||||
}
|
||||
|
||||
macro LoadElementsOrTempArray(implicit context: Context)(
|
||||
useTempArray: Boolean, sortState: FixedArray): HeapObject {
|
||||
return useTempArray == True ? GetTempArray(sortState) :
|
||||
ReloadElements(sortState);
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -912,7 +874,7 @@ namespace array {
|
||||
// is plus infinity. In other words, key belongs at index base + k.
|
||||
builtin GallopLeft(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, key: Object,
|
||||
base: Smi, length: Smi, hint: Smi, useTempArray: Boolean): Smi {
|
||||
base: Smi, length: Smi, hint: Smi): Smi {
|
||||
assert(length > 0 && base >= 0);
|
||||
assert(0 <= hint && hint < length);
|
||||
|
||||
@ -920,9 +882,8 @@ namespace array {
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + hint)
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, baseHintElement, key)
|
||||
@ -935,10 +896,8 @@ namespace array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint + offset)
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
@ -966,10 +925,8 @@ namespace array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint - offset)
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
@ -1001,9 +958,8 @@ namespace array {
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
|
||||
|
||||
const baseMElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + m)
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, baseMElement, key)
|
||||
otherwise Bailout;
|
||||
@ -1035,7 +991,7 @@ namespace array {
|
||||
// or kFailure on error.
|
||||
builtin GallopRight(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, key: Object,
|
||||
base: Smi, length: Smi, hint: Smi, useTempArray: Boolean): Smi {
|
||||
base: Smi, length: Smi, hint: Smi): Smi {
|
||||
assert(length > 0 && base >= 0);
|
||||
assert(0 <= hint && hint < length);
|
||||
|
||||
@ -1043,9 +999,8 @@ namespace array {
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + hint)
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, key, baseHintElement)
|
||||
@ -1058,10 +1013,8 @@ namespace array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint - offset)
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
@ -1088,10 +1041,8 @@ namespace array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint + offset)
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
@ -1122,9 +1073,8 @@ namespace array {
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
|
||||
|
||||
const baseMElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + m)
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, baseMElement)
|
||||
otherwise Bailout;
|
||||
@ -1148,11 +1098,11 @@ namespace array {
|
||||
// Copies a single element inside the array/object (NOT the tempArray).
|
||||
macro CopyElement(
|
||||
context: Context, sortState: FixedArray, load: LoadFn, store: StoreFn,
|
||||
elements: HeapObject, from: Smi, to: Smi)
|
||||
from: Smi, to: Smi)
|
||||
labels Bailout {
|
||||
const element: Object = CallLoad(context, sortState, load, elements, from)
|
||||
const element: Object = CallLoad(context, sortState, load, from)
|
||||
otherwise Bailout;
|
||||
CallStore(context, sortState, store, elements, to, element)
|
||||
CallStore(context, sortState, store, to, element)
|
||||
otherwise Bailout;
|
||||
}
|
||||
|
||||
@ -1173,20 +1123,18 @@ namespace array {
|
||||
let lengthA: Smi = lengthAArg;
|
||||
let lengthB: Smi = lengthBArg;
|
||||
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
const tempArray: FixedArray = GetTempArray(sortState, lengthA);
|
||||
CopyToTempArray(
|
||||
context, sortState, load, elements, baseA, tempArray, 0, lengthA)
|
||||
CopyToTempArray(context, sortState, load, baseA, tempArray, 0, lengthA)
|
||||
otherwise Bailout;
|
||||
|
||||
let dest: Smi = baseA;
|
||||
let cursorTemp: Smi = 0;
|
||||
let cursorB: Smi = baseB;
|
||||
|
||||
CopyElement(context, sortState, load, store, elements, cursorB++, dest++)
|
||||
CopyElement(context, sortState, load, store, cursorB++, dest++)
|
||||
otherwise Bailout;
|
||||
|
||||
try {
|
||||
@ -1207,17 +1155,14 @@ namespace array {
|
||||
while (Int32TrueConstant()) {
|
||||
assert(lengthA > 1 && lengthB > 0);
|
||||
|
||||
let elementB: Object =
|
||||
CallLoad(context, sortState, load, elements, cursorB)
|
||||
let elementB: Object = CallLoad(context, sortState, load, cursorB)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, elementB, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
|
||||
if (order < 0) {
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, cursorB, dest)
|
||||
CopyElement(context, sortState, load, store, cursorB, dest)
|
||||
otherwise Bailout;
|
||||
|
||||
++cursorB;
|
||||
@ -1229,9 +1174,7 @@ namespace array {
|
||||
if (lengthB == 0) goto Succeed;
|
||||
if (nofWinsB >= minGallop) break;
|
||||
} else {
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest,
|
||||
tempArray[cursorTemp])
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
|
||||
++cursorTemp;
|
||||
@ -1258,19 +1201,17 @@ namespace array {
|
||||
minGallop = SmiMax(1, minGallop - 1);
|
||||
sortState[kMinGallopIdx] = minGallop;
|
||||
|
||||
let keyRight: Object =
|
||||
CallLoad(context, sortState, load, elements, cursorB)
|
||||
let keyRight: Object = CallLoad(context, sortState, load, cursorB)
|
||||
otherwise Bailout;
|
||||
nofWinsA = CallGallopRight(
|
||||
context, sortState, Load<TempArrayElements>, keyRight, cursorTemp,
|
||||
lengthA, 0, True) otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
lengthA, 0) otherwise Bailout;
|
||||
assert(nofWinsA >= 0);
|
||||
|
||||
if (nofWinsA > 0) {
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, elements, dest, tempArray, cursorTemp,
|
||||
nofWinsA) otherwise Bailout;
|
||||
context, sortState, dest, cursorTemp, nofWinsA)
|
||||
otherwise Bailout;
|
||||
dest = dest + nofWinsA;
|
||||
cursorTemp = cursorTemp + nofWinsA;
|
||||
lengthA = lengthA - nofWinsA;
|
||||
@ -1281,20 +1222,17 @@ namespace array {
|
||||
// consistent, but we can't assume that it is.
|
||||
if (lengthA == 0) goto Succeed;
|
||||
}
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, cursorB++, dest++)
|
||||
CopyElement(context, sortState, load, store, cursorB++, dest++)
|
||||
otherwise Bailout;
|
||||
if (--lengthB == 0) goto Succeed;
|
||||
|
||||
nofWinsB = CallGallopLeft(
|
||||
context, sortState, load, tempArray[cursorTemp], cursorB, lengthB,
|
||||
0, False)
|
||||
0)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(nofWinsB >= 0);
|
||||
if (nofWinsB > 0) {
|
||||
CallCopyWithinSortArray(
|
||||
context, sortState, elements, cursorB, dest, nofWinsB)
|
||||
CallCopyWithinSortArray(context, sortState, cursorB, dest, nofWinsB)
|
||||
otherwise Bailout;
|
||||
|
||||
dest = dest + nofWinsB;
|
||||
@ -1303,9 +1241,7 @@ namespace array {
|
||||
|
||||
if (lengthB == 0) goto Succeed;
|
||||
}
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest++,
|
||||
tempArray[cursorTemp++])
|
||||
CallStore(context, sortState, store, dest++, tempArray[cursorTemp++])
|
||||
otherwise Bailout;
|
||||
if (--lengthA == 1) goto CopyB;
|
||||
}
|
||||
@ -1315,20 +1251,17 @@ namespace array {
|
||||
}
|
||||
label Succeed {
|
||||
if (lengthA > 0) {
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, elements, dest, tempArray, cursorTemp, lengthA)
|
||||
CallCopyFromTempArray(context, sortState, 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, elements, cursorB, dest, lengthB)
|
||||
CallCopyWithinSortArray(context, sortState, cursorB, dest, lengthB)
|
||||
otherwise Bailout;
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest + lengthB,
|
||||
tempArray[cursorTemp])
|
||||
context, sortState, store, dest + lengthB, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
@ -1348,13 +1281,11 @@ namespace array {
|
||||
let lengthA: Smi = lengthAArg;
|
||||
let lengthB: Smi = lengthBArg;
|
||||
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
const store: StoreFn = GetStoreFn(sortState);
|
||||
|
||||
const tempArray: FixedArray = GetTempArray(sortState, lengthB);
|
||||
CopyToTempArray(
|
||||
context, sortState, load, elements, baseB, tempArray, 0, lengthB)
|
||||
CopyToTempArray(context, sortState, load, baseB, tempArray, 0, lengthB)
|
||||
otherwise Bailout;
|
||||
|
||||
// MergeHigh merges the two runs backwards.
|
||||
@ -1362,7 +1293,7 @@ namespace array {
|
||||
let cursorTemp: Smi = lengthB - 1;
|
||||
let cursorA: Smi = baseA + lengthA - 1;
|
||||
|
||||
CopyElement(context, sortState, load, store, elements, cursorA--, dest--)
|
||||
CopyElement(context, sortState, load, store, cursorA--, dest--)
|
||||
otherwise Bailout;
|
||||
|
||||
try {
|
||||
@ -1383,17 +1314,14 @@ namespace array {
|
||||
while (Int32TrueConstant()) {
|
||||
assert(lengthA > 0 && lengthB > 1);
|
||||
|
||||
let elementA: Object =
|
||||
CallLoad(context, sortState, load, elements, cursorA)
|
||||
let elementA: Object = CallLoad(context, sortState, load, cursorA)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, tempArray[cursorTemp], elementA)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
|
||||
if (order < 0) {
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, cursorA, dest)
|
||||
CopyElement(context, sortState, load, store, cursorA, dest)
|
||||
otherwise Bailout;
|
||||
|
||||
--cursorA;
|
||||
@ -1405,9 +1333,7 @@ namespace array {
|
||||
if (lengthA == 0) goto Succeed;
|
||||
if (nofWinsA >= minGallop) break;
|
||||
} else {
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest,
|
||||
tempArray[cursorTemp])
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
|
||||
--cursorTemp;
|
||||
@ -1437,9 +1363,8 @@ namespace array {
|
||||
|
||||
let k: Smi = CallGallopRight(
|
||||
context, sortState, load, tempArray[cursorTemp], baseA, lengthA,
|
||||
lengthA - 1, False)
|
||||
lengthA - 1)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(k >= 0);
|
||||
nofWinsA = lengthA - k;
|
||||
|
||||
@ -1447,25 +1372,21 @@ namespace array {
|
||||
dest = dest - nofWinsA;
|
||||
cursorA = cursorA - nofWinsA;
|
||||
CallCopyWithinSortArray(
|
||||
context, sortState, elements, cursorA + 1, dest + 1, nofWinsA)
|
||||
context, sortState, cursorA + 1, dest + 1, nofWinsA)
|
||||
otherwise Bailout;
|
||||
|
||||
lengthA = lengthA - nofWinsA;
|
||||
if (lengthA == 0) goto Succeed;
|
||||
}
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest--,
|
||||
tempArray[cursorTemp--])
|
||||
CallStore(context, sortState, store, dest--, tempArray[cursorTemp--])
|
||||
otherwise Bailout;
|
||||
if (--lengthB == 1) goto CopyA;
|
||||
|
||||
let key: Object =
|
||||
CallLoad(context, sortState, load, elements, cursorA)
|
||||
let key: Object = CallLoad(context, sortState, load, cursorA)
|
||||
otherwise Bailout;
|
||||
k = CallGallopLeft(
|
||||
context, sortState, Load<TempArrayElements>, key, 0, lengthB,
|
||||
lengthB - 1, True) otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
lengthB - 1) otherwise Bailout;
|
||||
assert(k >= 0);
|
||||
nofWinsB = lengthB - k;
|
||||
|
||||
@ -1473,8 +1394,8 @@ namespace array {
|
||||
dest = dest - nofWinsB;
|
||||
cursorTemp = cursorTemp - nofWinsB;
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, elements, dest + 1, tempArray,
|
||||
cursorTemp + 1, nofWinsB) otherwise Bailout;
|
||||
context, sortState, dest + 1, cursorTemp + 1, nofWinsB)
|
||||
otherwise Bailout;
|
||||
|
||||
lengthB = lengthB - nofWinsB;
|
||||
if (lengthB == 1) goto CopyA;
|
||||
@ -1483,8 +1404,7 @@ namespace array {
|
||||
// consistent, but we can't assume that it is.
|
||||
if (lengthB == 0) goto Succeed;
|
||||
}
|
||||
CopyElement(
|
||||
context, sortState, load, store, elements, cursorA--, dest--)
|
||||
CopyElement(context, sortState, load, store, cursorA--, dest--)
|
||||
otherwise Bailout;
|
||||
if (--lengthA == 0) goto Succeed;
|
||||
}
|
||||
@ -1496,8 +1416,8 @@ namespace array {
|
||||
if (lengthB > 0) {
|
||||
assert(lengthA == 0);
|
||||
CallCopyFromTempArray(
|
||||
context, sortState, elements, dest - (lengthB - 1), tempArray, 0,
|
||||
lengthB) otherwise Bailout;
|
||||
context, sortState, dest - (lengthB - 1), 0, lengthB)
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
label CopyA {
|
||||
@ -1507,10 +1427,9 @@ namespace array {
|
||||
dest = dest - lengthA;
|
||||
cursorA = cursorA - lengthA;
|
||||
CallCopyWithinSortArray(
|
||||
context, sortState, elements, cursorA + 1, dest + 1, lengthA)
|
||||
context, sortState, cursorA + 1, dest + 1, lengthA)
|
||||
otherwise Bailout;
|
||||
CallStore(
|
||||
context, sortState, store, elements, dest, tempArray[cursorTemp])
|
||||
CallStore(context, sortState, store, dest, tempArray[cursorTemp])
|
||||
otherwise Bailout;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user