Skip to content

Commit 58639f9

Browse files
authored
Array sort update - return to Native Implementation (chakra-core#6852)
Update Array.prototype.sort and TypedArray.prototype.sort implementation for spec changes. 1. Removed existing JsBuiltin Array.prototype.sort implementation 2. Rewrote native Array.prototype.sort implementation in JavascriptArray.cpp to be stable using an Insertion sort for short arrays and merge sort for longer arrays. 3. Incorporated recent spec changes including copying the array to a "List" before sorting. 4. Following the defunct previous native implementation, an Array Sort without a compare method converts the array into structs of string & value pairs to optimise the use of the string comparison the spec requires. 5. To avoid duplicating code, updated the TypedArray.prototype.sort to use the same sort implementation, this required defining CompareVarsInfo struct in the JavascriptArray.h header so it's accessible from TypedArray.cpp, also a helper method TypedArraySort is implemented within JavascriptArray.cpp in order to ensure instantiation of the correct versions of the template sort methods 6. Various clean ups and corrects to the test suite to ensure elements of the new spec are being tested 7. Also deleted some defunct comments and fixed an unrelated compile error affecting a new version of macOS
1 parent 0cfe82d commit 58639f9

17 files changed

+3545
-4362
lines changed

lib/Common/Memory/RecyclerObjectGraphDumper.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "CommonMemoryPch.h"
@@ -58,7 +59,7 @@ void RecyclerObjectGraphDumper::BeginDumpObject(void * objectAddress)
5859
{
5960
Assert(false);
6061
this->dumpObjectTypeInfo = nullptr;
61-
this->dumpObjectIsArray = nullptr;
62+
this->dumpObjectIsArray = false;
6263
}
6364
}
6465
#endif

lib/Runtime/ByteCode/ByteCodeCacheReleaseFileVersion.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// NOTE: If there is a merge conflict the correct fix is to make a new GUID.
77
// This file was generated with tools/regenByteCode.py
88

9-
// {5659e34b-2f03-4880-bed4-7a688cd73df1}
9+
// {d31c196c-a985-4c41-a9b3-5a895b7dc567}
1010
const GUID byteCodeCacheReleaseFileVersion =
11-
{ 0x5659e34b, 0x2f03, 0x4880, {0xbe, 0xd4, 0x7a, 0x68, 0x8c, 0xd7, 0x3d, 0xf1 } };
11+
{ 0xd31c196c, 0xa985, 0x4c41, {0xa9, 0xb3, 0x5a, 0x89, 0x5b, 0x7d, 0xc5, 0x67 } };
1212

lib/Runtime/Library/InJavascript/Array_prototype.js

-135
Original file line numberDiff line numberDiff line change
@@ -169,141 +169,6 @@
169169
}
170170
});
171171

172-
platform.registerChakraLibraryFunction("MergeSort", function(array, length, compareFn) {
173-
const buffer = [];
174-
buffer.__proto__ = null;
175-
176-
let bucketSize = 2, lastSize = 1, position = 0;
177-
const doubleLength = length + length;
178-
179-
while (bucketSize < doubleLength) {
180-
while (position < length) {
181-
const left = position;
182-
const mid = left + lastSize;
183-
184-
// perform a merge but only if it's necessary
185-
if (mid < length && compareFn(array[mid], array[mid - 1]) < 0) {
186-
let right = position + bucketSize;
187-
right = right < length ? right : length;
188-
let i = mid - 1, j = 0, k = mid;
189-
190-
while (k < right) {
191-
buffer[j++] = array[k++];
192-
}
193-
194-
let rightElement = buffer[--j];
195-
let leftElement = array[i];
196-
197-
for (;;) {
198-
if (compareFn(rightElement, leftElement) < 0) {
199-
array[--k] = leftElement;
200-
if (i > left) {
201-
leftElement = array[--i];
202-
} else {
203-
array[--k] = rightElement;
204-
break;
205-
}
206-
} else {
207-
array[--k] = rightElement;
208-
if (j > 0) {
209-
rightElement = buffer[--j];
210-
} else {
211-
break;
212-
}
213-
}
214-
}
215-
216-
while (j > 0) {
217-
array[--k] = buffer[--j];
218-
}
219-
}
220-
position += bucketSize;
221-
}
222-
position = 0;
223-
lastSize = bucketSize;
224-
bucketSize *= 2;
225-
}
226-
});
227-
228-
platform.registerChakraLibraryFunction("DefaultSortCompare", function(left, right) {
229-
// only have to handle the less than case due to the logic of the sort
230-
return `${left}` < `${right}` ? -1 : 0;
231-
});
232-
233-
platform.registerFunction('sort', function (compareFn) {
234-
//#sec-array.prototype.sort
235-
if (compareFn !== undefined) {
236-
if (typeof compareFn !== "function") {
237-
__chakraLibrary.raiseFunctionArgument_NeedFunction("Array.prototype.sort");
238-
}
239-
} else {
240-
compareFn = __chakraLibrary.DefaultSortCompare;
241-
}
242-
243-
const {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.sort");
244-
const buffer = [];
245-
buffer.__proto__ = null;
246-
247-
// check for if the array has any missing values
248-
// also pull in any values from the prototype
249-
let length = 0, undefinedCount = 0;
250-
for (let i = 0; i < len; ++i) {
251-
if (i in o) {
252-
const temp = o[i];
253-
if (temp !== undefined) {
254-
buffer[length++] = o[i];
255-
} else {
256-
++undefinedCount;
257-
}
258-
}
259-
}
260-
261-
if (length < 2048) {
262-
let sortedCount = 1, lowerBound = 0, insertPoint = 0, upperBound = 0;
263-
while (sortedCount < length) {
264-
const item = buffer[sortedCount];
265-
upperBound = sortedCount;
266-
insertPoint = sortedCount - 1; // this lets us check for already ordered first
267-
lowerBound = 0;
268-
for (;;) {
269-
if (compareFn (item, buffer[insertPoint]) < 0) {
270-
upperBound = insertPoint;
271-
} else {
272-
lowerBound = insertPoint + 1;
273-
}
274-
if (lowerBound >= upperBound) {
275-
break;
276-
}
277-
insertPoint = lowerBound + (upperBound - lowerBound >> 1);
278-
}
279-
insertPoint = sortedCount;
280-
while (insertPoint > lowerBound) {
281-
buffer[insertPoint--] = buffer[insertPoint];
282-
}
283-
buffer[lowerBound] = item;
284-
++sortedCount;
285-
}
286-
} else {
287-
__chakraLibrary.MergeSort(buffer, length, compareFn);
288-
}
289-
290-
let i = 0;
291-
for (; i < length; ++i)
292-
{
293-
o[i] = buffer[i];
294-
}
295-
for (let j = 0; j < undefinedCount; ++j)
296-
{
297-
o[i++] = undefined;
298-
}
299-
for (; i < len; ++i)
300-
{
301-
delete o[i];
302-
}
303-
304-
return o;
305-
});
306-
307172
platform.registerFunction('filter', function (callbackfn, thisArg = undefined) {
308173
// ECMAScript 2017 #sec-array.prototype.filter
309174

0 commit comments

Comments
 (0)