diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
index 3efe5c409b..a257a2547d 100644
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -265,10 +265,9 @@ function ArrayToSorted(comparefn) {
var len = ToLength(O.length);
var items = new List();
- var itemsLen = 0;
+ var itemsLen = len;
for (var k = 0; k < len; k++) {
- if (k in O)
- items[itemsLen++] = O[k];
+ items[k] = O[k];
}
var wrappedCompareFn = comparefn;
@@ -303,9 +302,7 @@ function ArrayToSorted(comparefn) {
if (itemsLen > 1)
MergeSort(items, itemsLen, sortCompare);
- var A = ArraySpeciesCreate(O, 0);
- A.length = len;
-
+ var A = ArraySpeciesCreate(O, len);
for (var j = 0; j < itemsLen; j++)
_DefineDataProperty(A, j, items[j]);
diff --git a/js/src/tests/ecma_6/Array/toSorted.html b/js/src/tests/ecma_6/Array/toSorted.html
new file mode 100644
index 0000000000..3738b05c48
--- /dev/null
+++ b/js/src/tests/ecma_6/Array/toSorted.html
@@ -0,0 +1,59 @@
+
+
+
Array.prototype.toSorted test
+
+
+
+
diff --git a/js/src/tests/ecma_6/Array/toSorted.js b/js/src/tests/ecma_6/Array/toSorted.js
new file mode 100644
index 0000000000..fbd2540deb
--- /dev/null
+++ b/js/src/tests/ecma_6/Array/toSorted.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+assertEq(typeof Array.prototype.toSorted, "function");
+
+// Non-mutating behavior.
+let original = [3, 1, 2];
+let sorted = original.toSorted();
+assertEq(original !== sorted, true);
+assertEq(original.join(","), "3,1,2");
+assertEq(sorted.join(","), "1,2,3");
+
+// Compare function.
+let nums = [10, 1, 5];
+let desc = nums.toSorted((a, b) => b - a);
+assertEq(desc.join(","), "10,5,1");
+
+// Stable sort.
+let stableInput = [
+ {v: 1, id: "a"},
+ {v: 1, id: "b"},
+ {v: 1, id: "c"}
+];
+let stableSorted = stableInput.toSorted((x, y) => x.v - y.v);
+assertEq(stableSorted.map(o => o.id).join(""), "abc");
+
+// Holes are treated as undefined (properties are created).
+let sparse = [3, , 1];
+let sparseSorted = sparse.toSorted();
+assertEq(sparseSorted.length, 3);
+assertEq(sparseSorted[0], 1);
+assertEq(sparseSorted[1], 3);
+assertEq(2 in sparseSorted, true);
+assertEq(sparseSorted[2], undefined);
+
+// Array-like input.
+let arrayLike = {0: 2, 1: 1, length: 2};
+let arrayLikeSorted = Array.prototype.toSorted.call(arrayLike);
+assertEq(Array.isArray(arrayLikeSorted), true);
+assertEq(arrayLikeSorted.join(","), "1,2");
+
+// Getter access order (ascending indices).
+let accessLog = [];
+let getterArr = {
+ length: 3,
+ get 0() { accessLog.push(0); return 3; },
+ get 1() { accessLog.push(1); return 1; },
+ get 2() { accessLog.push(2); return 2; }
+};
+Array.prototype.toSorted.call(getterArr);
+assertEq(accessLog.join(","), "0,1,2");
+
+// Comparator errors propagate.
+assertThrowsInstanceOf(() => [1, 2].toSorted(1), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);