summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Array.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/Array.js')
-rw-r--r--js/src/builtin/Array.js1561
1 files changed, 1561 insertions, 0 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
new file mode 100644
index 0000000000..4544db3771
--- /dev/null
+++ b/js/src/builtin/Array.js
@@ -0,0 +1,1561 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* ES5 15.4.4.16. */
+function ArrayEvery(callbackfn /*, thisArg*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Steps 2-3. */
+ var len = ToLength(O.length);
+
+ /* Step 4. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.every");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 5. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 6-7. */
+ /* Steps a (implicit), and d. */
+ for (var k = 0; k < len; k++) {
+ /* Step b */
+ if (k in O) {
+ /* Step c. */
+ if (!callContentFunction(callbackfn, T, O[k], k, O)) {
+ return false;
+ }
+ }
+ }
+
+ /* Step 8. */
+ return true;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayEvery);
+
+/* ES5 15.4.4.17. */
+function ArraySome(callbackfn /*, thisArg*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Steps 2-3. */
+ var len = ToLength(O.length);
+
+ /* Step 4. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.some");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 5. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 6-7. */
+ /* Steps a (implicit), and d. */
+ for (var k = 0; k < len; k++) {
+ /* Step b */
+ if (k in O) {
+ /* Step c. */
+ if (callContentFunction(callbackfn, T, O[k], k, O)) {
+ return true;
+ }
+ }
+ }
+
+ /* Step 8. */
+ return false;
+}
+// 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;
+ };
+}
+
+// ES2023 draft rev cb4224156c54156f30c18c50784c1b0148ebfae5
+// 23.1.3.30 Array.prototype.sort ( comparefn )
+function ArraySort(comparefn) {
+ // Step 1.
+ if (comparefn !== undefined) {
+ if (!IsCallable(comparefn)) {
+ ThrowTypeError(JSMSG_BAD_SORT_ARG);
+ }
+ }
+
+ // Step 2.
+ var O = ToObject(this);
+
+ // 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, O, comparefn)) {
+ return O;
+ }
+
+ // Step 3.
+ var len = ToLength(O.length);
+
+ // Arrays with less than two elements remain unchanged when sorted.
+ if (len <= 1) {
+ return O;
+ }
+
+ // Step 4.
+ var wrappedCompareFn = ArraySortCompare(comparefn);
+
+ // Step 5.
+ // To save effort we will do all of our work on a dense list, then create
+ // holes at the end.
+ var denseList = [];
+ var denseLen = 0;
+
+ for (var i = 0; i < len; i++) {
+ if (i in O) {
+ DefineDataProperty(denseList, denseLen++, O[i]);
+ }
+ }
+
+ if (denseLen < 1) {
+ return O;
+ }
+
+ var sorted = MergeSort(denseList, denseLen, wrappedCompareFn);
+
+ assert(IsPackedArray(sorted), "sorted is a packed array");
+ assert(sorted.length === denseLen, "sorted array has the correct length");
+
+ MoveHoles(O, len, sorted, denseLen);
+
+ return O;
+}
+
+/* ES5 15.4.4.18. */
+function ArrayForEach(callbackfn /*, thisArg*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Steps 2-3. */
+ var len = ToLength(O.length);
+
+ /* Step 4. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 5. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 6-7. */
+ /* Steps a (implicit), and d. */
+ for (var k = 0; k < len; k++) {
+ /* Step b */
+ if (k in O) {
+ /* Step c. */
+ callContentFunction(callbackfn, T, O[k], k, O);
+ }
+ }
+
+ /* Step 8. */
+ return undefined;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayForEach);
+
+/* ES 2016 draft Mar 25, 2016 22.1.3.15. */
+function ArrayMap(callbackfn /*, thisArg*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Step 2. */
+ var len = ToLength(O.length);
+
+ /* Step 3. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.map");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 4. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 5. */
+ var A = ArraySpeciesCreate(O, len);
+
+ /* Steps 6-7. */
+ /* Steps 7.a (implicit), and 7.d. */
+ for (var k = 0; k < len; k++) {
+ /* Steps 7.b-c. */
+ if (k in O) {
+ /* Steps 7.c.i-iii. */
+ var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
+ DefineDataProperty(A, k, mappedValue);
+ }
+ }
+
+ /* Step 8. */
+ return A;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayMap);
+
+/* ES 2016 draft Mar 25, 2016 22.1.3.7 Array.prototype.filter. */
+function ArrayFilter(callbackfn /*, thisArg*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Step 2. */
+ var len = ToLength(O.length);
+
+ /* Step 3. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.filter");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 4. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Step 5. */
+ var A = ArraySpeciesCreate(O, 0);
+
+ /* Steps 6-8. */
+ /* Steps 8.a (implicit), and 8.d. */
+ for (var k = 0, to = 0; k < len; k++) {
+ /* Steps 8.b-c. */
+ if (k in O) {
+ /* Step 8.c.i. */
+ var kValue = O[k];
+ /* Steps 8.c.ii-iii. */
+ if (callContentFunction(callbackfn, T, kValue, k, O)) {
+ DefineDataProperty(A, to++, kValue);
+ }
+ }
+ }
+
+ /* Step 9. */
+ return A;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayFilter);
+
+#ifdef NIGHTLY_BUILD
+// Array Grouping proposal
+//
+// Array.prototype.group
+// https://tc39.es/proposal-array-grouping/#sec-array.prototype.group
+function ArrayGroup(callbackfn /*, thisArg*/) {
+ /* Step 1. Let O be ? ToObject(this value). */
+ var O = ToObject(this);
+
+ /* Step 2. Let len be ? LengthOfArrayLike(O). */
+ var len = ToLength(O.length);
+
+ /* Step 3. If IsCallable(callbackfn) is false, throw a TypeError exception. */
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 5. Let groups be a new empty List. */
+ // Not applicable in our implementation.
+
+ /* Step 7. Let obj be ! OrdinaryObjectCreate(null). */
+ var object = std_Object_create(null);
+
+ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 4, 6. */
+ for (var k = 0; k < len; k++) {
+ /* Skip Step 6.a. Let Pk be ! ToString(𝔽(k)).
+ *
+ * k is coerced into a string through the property access. */
+
+ /* Step 6.b. Let kValue be ? Get(O, Pk). */
+ var kValue = O[k];
+
+ /* Step 6.c.
+ * Let propertyKey be ? ToPropertyKey(
+ * ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
+ */
+ var propertyKey = callContentFunction(callbackfn, thisArg, kValue, k, O);
+
+ // Split the step to ensure single evaluation in the TO_PROPERTY_KEY macro.
+ propertyKey = TO_PROPERTY_KEY(propertyKey);
+
+ /* Step 6.d. Perform ! AddValueToKeyedGroup(groups, propertyKey, kValue). */
+ var elements = object[propertyKey];
+ if (elements === undefined) {
+ DefineDataProperty(object, propertyKey, [kValue]);
+ } else {
+ DefineDataProperty(elements, elements.length, kValue);
+ }
+ }
+
+ /* Step 8. For each Record { [[Key]], [[Elements]] } g of groups, do
+ * a. Let elements be ! CreateArrayFromList(g.[[Elements]]).
+ * b. Perform ! CreateDataPropertyOrThrow(obj, g.[[Key]], elements).
+ */
+ // Not applicable in our implementation.
+
+ /* Step 9. Return obj. */
+ return object;
+}
+
+// Array Grouping proposal
+//
+// Array.prototype.groupToMap
+// https://tc39.es/proposal-array-grouping/#sec-array.prototype.grouptomap
+function ArrayGroupToMap(callbackfn /*, thisArg*/) {
+ /* Step 1. Let O be ? ToObject(this value). */
+ var O = ToObject(this);
+
+ /* Step 2. Let len be ? LengthOfArrayLike(O). */
+ var len = ToLength(O.length);
+
+ /* Step 3.
+ * If IsCallable(callbackfn) is false, throw a TypeError exception.
+ */
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Skipping Step 5. Let groups be a new empty List.
+ *
+ * Intermediate object isn't necessary as we have direct access
+ * to the map constructor and set/get methods.
+ */
+
+ /* Step 7. Let map be ! Construct(%Map%). */
+ var C = GetBuiltinConstructor("Map");
+ var map = new C();
+
+ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Combine Step 6. and Step 8.
+ *
+ * We have direct access to the map constructor and set/get methods.
+ * We can treat these two loops as one, as there isn't a risk that user
+ * polyfilling will impact the implementation.
+ */
+ for (var k = 0; k < len; k++) {
+ /* Skipping Step 6.a. Let Pk be ! ToString(𝔽(k)).
+ *
+ * Value is coerced to String by property access in step 6.b.
+ */
+
+ /* Step 6.b. Let kValue be ? Get(O, Pk). */
+ var kValue = O[k];
+
+ /* Step 6.c.
+ * Let key be ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
+ */
+ var key = callContentFunction(callbackfn, thisArg, kValue, k, O);
+
+ /* Skipping Step 6.d. If key is -0𝔽, set key to +0𝔽.
+ *
+ * This step is performed by std_Map_set.
+ */
+
+ /* Step 8.c. Append entry as the last element of map.[[MapData]].
+ *
+ * We are not using an intermediate object to store the values.
+ * So, this step applies it directly to the map object. Skips steps
+ * 6.e (Perform ! AddValueToKeyedGroup(groups, key, kValue))
+ * and 8.a-b as a result.
+ */
+ var elements = callFunction(std_Map_get, map, key);
+ if (elements === undefined) {
+ callFunction(std_Map_set, map, key, [kValue]);
+ } else {
+ DefineDataProperty(elements, elements.length, kValue);
+ }
+ }
+
+ /* Step 9. Return map. */
+ return map;
+}
+
+#endif
+
+/* ES5 15.4.4.21. */
+function ArrayReduce(callbackfn /*, initialValue*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Steps 2-3. */
+ var len = ToLength(O.length);
+
+ /* Step 4. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 6. */
+ var k = 0;
+
+ /* Steps 5, 7-8. */
+ var accumulator;
+ if (ArgumentsLength() > 1) {
+ accumulator = GetArgument(1);
+ } else {
+ /* Step 5. */
+ // Add an explicit |throw| here and below to inform Ion that the
+ // ThrowTypeError calls exit this function.
+ if (len === 0) {
+ throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
+ }
+
+ // Use a |do-while| loop to let Ion know that the loop will definitely
+ // be entered at least once. When Ion is then also able to inline the
+ // |in| operator, it can optimize away the whole loop.
+ var kPresent = false;
+ do {
+ if (k in O) {
+ kPresent = true;
+ break;
+ }
+ } while (++k < len);
+ if (!kPresent) {
+ throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
+ }
+
+ // Moved outside of the loop to ensure the assignment is non-conditional.
+ accumulator = O[k++];
+ }
+
+ /* Step 9. */
+ /* Steps a (implicit), and d. */
+ for (; k < len; k++) {
+ /* Step b */
+ if (k in O) {
+ /* Step c. */
+ accumulator = callContentFunction(
+ callbackfn,
+ undefined,
+ accumulator,
+ O[k],
+ k,
+ O
+ );
+ }
+ }
+
+ /* Step 10. */
+ return accumulator;
+}
+
+/* ES5 15.4.4.22. */
+function ArrayReduceRight(callbackfn /*, initialValue*/) {
+ /* Step 1. */
+ var O = ToObject(this);
+
+ /* Steps 2-3. */
+ var len = ToLength(O.length);
+
+ /* Step 4. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce");
+ }
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ /* Step 6. */
+ var k = len - 1;
+
+ /* Steps 5, 7-8. */
+ var accumulator;
+ if (ArgumentsLength() > 1) {
+ accumulator = GetArgument(1);
+ } else {
+ /* Step 5. */
+ // Add an explicit |throw| here and below to inform Ion that the
+ // ThrowTypeError calls exit this function.
+ if (len === 0) {
+ throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
+ }
+
+ // Use a |do-while| loop to let Ion know that the loop will definitely
+ // be entered at least once. When Ion is then also able to inline the
+ // |in| operator, it can optimize away the whole loop.
+ var kPresent = false;
+ do {
+ if (k in O) {
+ kPresent = true;
+ break;
+ }
+ } while (--k >= 0);
+ if (!kPresent) {
+ throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
+ }
+
+ // Moved outside of the loop to ensure the assignment is non-conditional.
+ accumulator = O[k--];
+ }
+
+ /* Step 9. */
+ /* Steps a (implicit), and d. */
+ for (; k >= 0; k--) {
+ /* Step b */
+ if (k in O) {
+ /* Step c. */
+ accumulator = callContentFunction(
+ callbackfn,
+ undefined,
+ accumulator,
+ O[k],
+ k,
+ O
+ );
+ }
+ }
+
+ /* Step 10. */
+ return accumulator;
+}
+
+/* ES6 draft 2013-05-14 15.4.3.23. */
+function ArrayFind(predicate /*, thisArg*/) {
+ /* Steps 1-2. */
+ var O = ToObject(this);
+
+ /* Steps 3-5. */
+ var len = ToLength(O.length);
+
+ /* Step 6. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find");
+ }
+ if (!IsCallable(predicate)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
+ }
+
+ /* Step 7. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 8-9. */
+ /* Steps a (implicit), and g. */
+ for (var k = 0; k < len; k++) {
+ /* Steps a-c. */
+ var kValue = O[k];
+ /* Steps d-f. */
+ if (callContentFunction(predicate, T, kValue, k, O)) {
+ return kValue;
+ }
+ }
+
+ /* Step 10. */
+ return undefined;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayFind);
+
+/* ES6 draft 2013-05-14 15.4.3.23. */
+function ArrayFindIndex(predicate /*, thisArg*/) {
+ /* Steps 1-2. */
+ var O = ToObject(this);
+
+ /* Steps 3-5. */
+ var len = ToLength(O.length);
+
+ /* Step 6. */
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find");
+ }
+ if (!IsCallable(predicate)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
+ }
+
+ /* Step 7. */
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ /* Steps 8-9. */
+ /* Steps a (implicit), and g. */
+ for (var k = 0; k < len; k++) {
+ /* Steps a-f. */
+ if (callContentFunction(predicate, T, O[k], k, O)) {
+ return k;
+ }
+ }
+
+ /* Step 10. */
+ return -1;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayFindIndex);
+
+// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
+// 22.1.3.3 Array.prototype.copyWithin ( target, start [ , end ] )
+function ArrayCopyWithin(target, start, end = undefined) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var len = ToLength(O.length);
+
+ // Step 3.
+ var relativeTarget = ToInteger(target);
+
+ // Step 4.
+ var to =
+ relativeTarget < 0
+ ? std_Math_max(len + relativeTarget, 0)
+ : std_Math_min(relativeTarget, len);
+
+ // Step 5.
+ var relativeStart = ToInteger(start);
+
+ // Step 6.
+ var from =
+ relativeStart < 0
+ ? std_Math_max(len + relativeStart, 0)
+ : std_Math_min(relativeStart, len);
+
+ // Step 7.
+ var relativeEnd = end === undefined ? len : ToInteger(end);
+
+ // Step 8.
+ var final =
+ relativeEnd < 0
+ ? std_Math_max(len + relativeEnd, 0)
+ : std_Math_min(relativeEnd, len);
+
+ // Step 9.
+ var count = std_Math_min(final - from, len - to);
+
+ // Steps 10-12.
+ if (from < to && to < from + count) {
+ // Steps 10.b-c.
+ from = from + count - 1;
+ to = to + count - 1;
+
+ // Step 12.
+ while (count > 0) {
+ if (from in O) {
+ O[to] = O[from];
+ } else {
+ delete O[to];
+ }
+
+ from--;
+ to--;
+ count--;
+ }
+ } else {
+ // Step 12.
+ while (count > 0) {
+ if (from in O) {
+ O[to] = O[from];
+ } else {
+ delete O[to];
+ }
+
+ from++;
+ to++;
+ count--;
+ }
+ }
+
+ // Step 13.
+ return O;
+}
+
+// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
+// 22.1.3.6 Array.prototype.fill ( value [ , start [ , end ] ] )
+function ArrayFill(value, start = 0, end = undefined) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var len = ToLength(O.length);
+
+ // Step 3.
+ var relativeStart = ToInteger(start);
+
+ // Step 4.
+ var k =
+ relativeStart < 0
+ ? std_Math_max(len + relativeStart, 0)
+ : std_Math_min(relativeStart, len);
+
+ // Step 5.
+ var relativeEnd = end === undefined ? len : ToInteger(end);
+
+ // Step 6.
+ var final =
+ relativeEnd < 0
+ ? std_Math_max(len + relativeEnd, 0)
+ : std_Math_min(relativeEnd, len);
+
+ // Step 7.
+ for (; k < final; k++) {
+ O[k] = value;
+ }
+
+ // Step 8.
+ return O;
+}
+
+// ES6 draft specification, section 22.1.5.1, version 2013-09-05.
+function CreateArrayIterator(obj, kind) {
+ var iteratedObject = ToObject(obj);
+ var iterator = NewArrayIterator();
+ UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
+ UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
+ UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
+ return iterator;
+}
+
+// ES6, 22.1.5.2.1
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next
+function ArrayIteratorNext() {
+ // Step 1-3.
+ var obj = this;
+ if (!IsObject(obj) || (obj = GuardToArrayIterator(obj)) === null) {
+ return callFunction(
+ CallArrayIteratorMethodIfWrapped,
+ this,
+ "ArrayIteratorNext"
+ );
+ }
+
+ // Step 4.
+ var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET);
+ var result = { value: undefined, done: false };
+
+ // Step 5.
+ if (a === null) {
+ result.done = true;
+ return result;
+ }
+
+ // Step 6.
+ // The index might not be an integer, so we have to do a generic get here.
+ var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
+
+ // Step 7.
+ var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
+
+ // Step 8-9.
+ var len;
+ if (IsPossiblyWrappedTypedArray(a)) {
+ len = PossiblyWrappedTypedArrayLength(a);
+
+ // If the length is non-zero, the buffer can't be detached.
+ if (len === 0) {
+ if (PossiblyWrappedTypedArrayHasDetachedBuffer(a)) {
+ ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+ }
+ }
+ } else {
+ len = ToLength(a.length);
+ }
+
+ // Step 10.
+ if (index >= len) {
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null);
+ result.done = true;
+ return result;
+ }
+
+ // Step 11.
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1);
+
+ // Step 16.
+ if (itemKind === ITEM_KIND_VALUE) {
+ result.value = a[index];
+ return result;
+ }
+
+ // Step 13.
+ if (itemKind === ITEM_KIND_KEY_AND_VALUE) {
+ var pair = [index, a[index]];
+ result.value = pair;
+ return result;
+ }
+
+ // Step 12.
+ assert(itemKind === ITEM_KIND_KEY, itemKind);
+ result.value = index;
+ return result;
+}
+// We want to inline this to do scalar replacement of the result object.
+SetIsInlinableLargeFunction(ArrayIteratorNext);
+
+// Uncloned functions with `$` prefix are allocated as extended function
+// to store the original name in `SetCanonicalName`.
+function $ArrayValues() {
+ return CreateArrayIterator(this, ITEM_KIND_VALUE);
+}
+SetCanonicalName($ArrayValues, "values");
+
+function ArrayEntries() {
+ return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
+}
+
+function ArrayKeys() {
+ return CreateArrayIterator(this, ITEM_KIND_KEY);
+}
+
+// https://tc39.es/proposal-array-from-async/
+// TODO: Bug 1834560 The step numbers in this will need updating when this is merged
+// into the main spec.
+function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
+ // Step 1. Let C be the this value.
+ var C = this;
+
+ // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ // Step 3. Let fromAsyncClosure be a new Abstract Closure with no parameters that captures C, mapfn, and thisArg and performs the following steps when called:
+ let fromAsyncClosure = async () => {
+ // Step 3.a. If mapfn is undefined, let mapping be false.
+ // Step 3.b. Else,
+ // Step 3.b.i. If IsCallable(mapfn) is false, throw a TypeError exception.
+ // Step 3.b.ii. Let mapping be true.
+ var mapping = mapfn !== undefined;
+ if (mapping && !IsCallable(mapfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, ToSource(mapfn));
+ }
+
+ // Step 3.c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator).
+ let usingAsyncIterator = asyncItems[GetBuiltinSymbol("asyncIterator")];
+ if (usingAsyncIterator === null) {
+ usingAsyncIterator = undefined;
+ }
+
+ let usingSyncIterator = undefined;
+ if (usingAsyncIterator !== undefined) {
+ if (!IsCallable(usingAsyncIterator)) {
+ ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems));
+ }
+ } else {
+ // Step 3.d. If usingAsyncIterator is undefined, then
+
+ // Step 3.d.i. Let usingSyncIterator be ? GetMethod(asyncItems, @@iterator).
+ usingSyncIterator = asyncItems[GetBuiltinSymbol("iterator")];
+ if (usingSyncIterator === null) {
+ usingSyncIterator = undefined;
+ }
+
+ if (usingSyncIterator !== undefined) {
+ if (!IsCallable(usingSyncIterator)) {
+ ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems));
+ }
+ }
+ }
+
+ // Step 3.g. Let iteratorRecord be undefined.
+ // Step 3.j. If iteratorRecord is not undefined, then ...
+ if (usingAsyncIterator !== undefined || usingSyncIterator !== undefined) {
+ // Note: The published spec as of f6acfc4f0277e625f13fd22068138aec61a12df3
+ // is incorrect. See https://github.com/tc39/proposal-array-from-async/issues/33
+ // Here we use the implementation provided by @bakkot in that bug
+ // in lieu for now; This allows to use a for-await loop below.
+
+ // Steps 3.h-i are implicit through the for-await loop.
+
+ // Step 3.h. If usingAsyncIterator is not undefined, then
+ // Step 3.h.i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
+ // Step 3.i. Else if usingSyncIterator is not undefined, then
+ // Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
+
+ // https://github.com/tc39/proposal-array-from-async/pull/41
+ // Step 3.e. If IsConstructor(C) is true, then
+ // Step 3.e.i. Let A be ? Construct(C).
+ // Step 3.f. Else,
+ // Step 3.f.i. Let A be ! ArrayCreate(0).
+ let A = IsConstructor(C) ? constructContentFunction(C, C) : [];
+
+
+ // Step 3.j.i. Let k be 0.
+ let k = 0;
+
+ // Step 3.j.ii. Repeat,
+ for await (let nextValue of allowContentIterWith(
+ asyncItems,
+ usingAsyncIterator,
+ usingSyncIterator
+ )) {
+ // Following in the steps of Array.from, we don't actually implement 3.j.ii.1.
+ // The comment in Array.from also applies here; we should only encounter this
+ // after a huge loop around a proxy
+ // Step 3.j.ii.1. If k ≥ 2**53 - 1, then
+ // Step 3.j.ii.1.a. Let error be ThrowCompletion(a newly created TypeError object).
+ // Step 3.j.ii.1.b. Return ? AsyncIteratorClose(iteratorRecord, error).
+ // Step 3.j.ii.2. Let Pk be ! ToString(𝔽(k)).
+
+ // Step 3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
+
+ // Step 3.j.ii.5. Let nextValue be ? IteratorValue(next). (Implicit through the for-await loop).
+
+ // Step 3.j.ii.7. Else, let mappedValue be nextValue. (Reordered)
+ let mappedValue = nextValue;
+
+ // Step 3.j.ii.6. If mapping is true, then
+ if (mapping) {
+ // Step 3.j.ii.6.a. Let mappedValue be Call(mapfn, thisArg, « nextValue, 𝔽(k) »).
+ // Step 3.j.ii.6.b. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
+ // Abrupt completion will be handled by the for-await loop.
+ mappedValue = callContentFunction(mapfn, thisArg, nextValue, k);
+
+ // Step 3.j.ii.6.c. Set mappedValue to Await(mappedValue).
+ // Step 3.j.ii.6.d. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
+ mappedValue = await mappedValue;
+ }
+
+ // Step 3.j.ii.8. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
+ // Step 3.j.ii.9. If defineStatus is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, defineStatus).
+ DefineDataProperty(A, k, mappedValue);
+
+ // Step 3.j.ii.10. Set k to k + 1.
+ k = k + 1;
+ }
+
+ // Step 3.j.ii.4. If next is false, then (Reordered)
+
+ // Step 3.j.ii.4.a. Perform ? Set(A, "length", 𝔽(k), true).
+ A.length = k;
+
+ // Step 3.j.ii.4.b. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
+ return A;
+ }
+
+ // Step 3.k. Else,
+
+ // Step 3.k.i. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object.
+ // Step 3.k.ii. Let arrayLike be ! ToObject(asyncItems).
+ let arrayLike = ToObject(asyncItems);
+
+ // Step 3.k.iii. Let len be ? LengthOfArrayLike(arrayLike).
+ let len = ToLength(arrayLike.length);
+
+ // Step 3.k.iv. If IsConstructor(C) is true, then
+ // Step 3.k.iv.1. Let A be ? Construct(C, « 𝔽(len) »).
+ // Step 3.k.v. Else,
+ // Step 3.k.v.1. Let A be ? ArrayCreate(len).
+ let A = IsConstructor(C) ? constructContentFunction(C, C, len) : std_Array(len);
+
+ // Step 3.k.vi. Let k be 0.
+ let k = 0;
+
+ // Step 3.k.vii. Repeat, while k < len,
+ while (k < len) {
+ // Step 3.k.vii.1. Let Pk be ! ToString(𝔽(k)).
+ // Step 3.k.vii.2. Let kValue be ? Get(arrayLike, Pk).
+ // Step 3.k.vii.3. Let kValue be ? Await(kValue).
+ let kValue = await arrayLike[k];
+
+ // Step 3.k.vii.4. If mapping is true, then
+ // Step 3.k.vii.4.a. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽(k) »).
+ // Step 3.k.vii.4.b. Let mappedValue be ? Await(mappedValue).
+ // Step 3.k.vii.5. Else, let mappedValue be kValue.
+ let mappedValue = mapping
+ ? await callContentFunction(mapfn, thisArg, kValue, k)
+ : kValue;
+
+ // Step 3.k.vii.6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
+ DefineDataProperty(A, k, mappedValue);
+
+ // Step 3.k.vii.7. Set k to k + 1.
+ k = k + 1;
+ }
+
+ // Step 3.k.viii. Perform ? Set(A, "length", 𝔽(len), true).
+ A.length = len;
+
+ // Step 3.k.ix. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
+ return A;
+ };
+
+ // Step 4. Perform AsyncFunctionStart(promiseCapability, fromAsyncClosure).
+ // Step 5. Return promiseCapability.[[Promise]].
+ return fromAsyncClosure();
+}
+
+// ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1
+function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
+ // Step 1.
+ var C = this;
+
+ // Steps 2-3.
+ var mapping = mapfn !== undefined;
+ if (mapping && !IsCallable(mapfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
+ }
+ var T = thisArg;
+
+ // Step 4.
+ // Inlined: GetMethod, steps 1-2.
+ var usingIterator = items[GetBuiltinSymbol("iterator")];
+
+ // Step 5.
+ // Inlined: GetMethod, step 3.
+ if (!IsNullOrUndefined(usingIterator)) {
+ // Inlined: GetMethod, step 4.
+ if (!IsCallable(usingIterator)) {
+ ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, items));
+ }
+
+ // Steps 5.a-b.
+ var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
+
+ // Step 5.d.
+ var k = 0;
+
+ // Steps 5.c, 5.e
+ for (var nextValue of allowContentIterWith(items, usingIterator)) {
+ // Step 5.e.i.
+ // Disabled for performance reason. We won't hit this case on
+ // normal array, since DefineDataProperty will throw before it.
+ // We could hit this when |A| is a proxy and it ignores
+ // |DefineDataProperty|, but it happens only after too long loop.
+ /*
+ if (k >= 0x1fffffffffffff) {
+ ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
+ }
+ */
+
+ // Steps 5.e.vi-vii.
+ var mappedValue = mapping
+ ? callContentFunction(mapfn, T, nextValue, k)
+ : nextValue;
+
+ // Steps 5.e.ii (reordered), 5.e.viii.
+ DefineDataProperty(A, k++, mappedValue);
+ }
+
+ // Step 5.e.iv.
+ A.length = k;
+ return A;
+ }
+
+ // Step 7 is an assertion: items is not an Iterator. Testing this is
+ // literally the very last thing we did, so we don't assert here.
+
+ // Steps 8-9.
+ var arrayLike = ToObject(items);
+
+ // Steps 10-11.
+ var len = ToLength(arrayLike.length);
+
+ // Steps 12-14.
+ var A = IsConstructor(C)
+ ? constructContentFunction(C, C, len)
+ : std_Array(len);
+
+ // Steps 15-16.
+ for (var k = 0; k < len; k++) {
+ // Steps 16.a-c.
+ var kValue = items[k];
+
+ // Steps 16.d-e.
+ var mappedValue = mapping
+ ? callContentFunction(mapfn, T, kValue, k)
+ : kValue;
+
+ // Steps 16.f-g.
+ DefineDataProperty(A, k, mappedValue);
+ }
+
+ // Steps 17-18.
+ A.length = len;
+
+ // Step 19.
+ return A;
+}
+
+// ES2015 22.1.3.27 Array.prototype.toString.
+function ArrayToString() {
+ // Steps 1-2.
+ var array = ToObject(this);
+
+ // Steps 3-4.
+ var func = array.join;
+
+ // Steps 5-6.
+ if (!IsCallable(func)) {
+ return callFunction(std_Object_toString, array);
+ }
+ return callContentFunction(func, array);
+}
+
+// ES2017 draft rev f8a9be8ea4bd97237d176907a1e3080dce20c68f
+// 22.1.3.27 Array.prototype.toLocaleString ([ reserved1 [ , reserved2 ] ])
+// ES2017 Intl draft rev 78bbe7d1095f5ff3760ac4017ed366026e4cb276
+// 13.4.1 Array.prototype.toLocaleString ([ locales [ , options ]])
+function ArrayToLocaleString(locales, options) {
+ // Step 1 (ToObject already performed in native code).
+ assert(IsObject(this), "|this| should be an object");
+ var array = this;
+
+ // Step 2.
+ var len = ToLength(array.length);
+
+ // Step 4.
+ if (len === 0) {
+ return "";
+ }
+
+ // Step 5.
+ var firstElement = array[0];
+
+ // Steps 6-7.
+ var R;
+ if (IsNullOrUndefined(firstElement)) {
+ R = "";
+ } else {
+#if JS_HAS_INTL_API
+ R = ToString(
+ callContentFunction(
+ firstElement.toLocaleString,
+ firstElement,
+ locales,
+ options
+ )
+ );
+#else
+ R = ToString(
+ callContentFunction(firstElement.toLocaleString, firstElement)
+ );
+#endif
+ }
+
+ // Step 3 (reordered).
+ // We don't (yet?) implement locale-dependent separators.
+ var separator = ",";
+
+ // Steps 8-9.
+ for (var k = 1; k < len; k++) {
+ // Step 9.b.
+ var nextElement = array[k];
+
+ // Steps 9.a, 9.c-e.
+ R += separator;
+ if (!IsNullOrUndefined(nextElement)) {
+#if JS_HAS_INTL_API
+ R += ToString(
+ callContentFunction(
+ nextElement.toLocaleString,
+ nextElement,
+ locales,
+ options
+ )
+ );
+#else
+ R += ToString(
+ callContentFunction(nextElement.toLocaleString, nextElement)
+ );
+#endif
+ }
+ }
+
+ // Step 10.
+ return R;
+}
+
+// ES 2016 draft Mar 25, 2016 22.1.2.5.
+function $ArraySpecies() {
+ // Step 1.
+ return this;
+}
+SetCanonicalName($ArraySpecies, "get [Symbol.species]");
+
+// ES 2016 draft Mar 25, 2016 9.4.2.3.
+function ArraySpeciesCreate(originalArray, length) {
+ // Step 1.
+ assert(typeof length === "number", "length should be a number");
+ assert(length >= 0, "length should be a non-negative number");
+
+ // Step 2.
+ // eslint-disable-next-line no-compare-neg-zero
+ if (length === -0) {
+ length = 0;
+ }
+
+ // Step 4, 6.
+ if (!IsArray(originalArray)) {
+ return std_Array(length);
+ }
+
+ // Step 5.a.
+ var C = originalArray.constructor;
+
+ // Step 5.b.
+ if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) {
+ return std_Array(length);
+ }
+
+ // Step 5.c.
+ if (IsObject(C)) {
+ // Step 5.c.i.
+ C = C[GetBuiltinSymbol("species")];
+
+ // Optimized path for an ordinary Array.
+ if (C === GetBuiltinConstructor("Array")) {
+ return std_Array(length);
+ }
+
+ // Step 5.c.ii.
+ if (C === null) {
+ return std_Array(length);
+ }
+ }
+
+ // Step 6.
+ if (C === undefined) {
+ return std_Array(length);
+ }
+
+ // Step 7.
+ if (!IsConstructor(C)) {
+ ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, "constructor property");
+ }
+
+ // Step 8.
+ return constructContentFunction(C, C, length);
+}
+
+// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
+// 22.1.3.11 Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+function ArrayFlatMap(mapperFunction /*, thisArg*/) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var sourceLen = ToLength(O.length);
+
+ // Step 3.
+ if (!IsCallable(mapperFunction)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
+ }
+
+ // Step 4.
+ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Step 5.
+ var A = ArraySpeciesCreate(O, 0);
+
+ // Step 6.
+ FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
+
+ // Step 7.
+ return A;
+}
+
+// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
+// 22.1.3.10 Array.prototype.flat ( [ depth ] )
+function ArrayFlat(/* depth */) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var sourceLen = ToLength(O.length);
+
+ // Step 3.
+ var depthNum = 1;
+
+ // Step 4.
+ if (ArgumentsLength() && GetArgument(0) !== undefined) {
+ depthNum = ToInteger(GetArgument(0));
+ }
+
+ // Step 5.
+ var A = ArraySpeciesCreate(O, 0);
+
+ // Step 6.
+ FlattenIntoArray(A, O, sourceLen, 0, depthNum);
+
+ // Step 7.
+ return A;
+}
+
+// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
+// 22.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+function FlattenIntoArray(
+ target,
+ source,
+ sourceLen,
+ start,
+ depth,
+ mapperFunction,
+ thisArg
+) {
+ // Step 1.
+ var targetIndex = start;
+
+ // Steps 2-3.
+ for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
+ // Steps 3.a-c.
+ if (sourceIndex in source) {
+ // Step 3.c.i.
+ var element = source[sourceIndex];
+
+ if (mapperFunction) {
+ // Step 3.c.ii.1.
+ assert(ArgumentsLength() === 7, "thisArg is present");
+
+ // Step 3.c.ii.2.
+ element = callContentFunction(
+ mapperFunction,
+ thisArg,
+ element,
+ sourceIndex,
+ source
+ );
+ }
+
+ // Step 3.c.iii.
+ var shouldFlatten = false;
+
+ // Step 3.c.iv.
+ if (depth > 0) {
+ // Step 3.c.iv.1.
+ shouldFlatten = IsArray(element);
+ }
+
+ // Step 3.c.v.
+ if (shouldFlatten) {
+ // Step 3.c.v.1.
+ var elementLen = ToLength(element.length);
+
+ // Step 3.c.v.2.
+ targetIndex = FlattenIntoArray(
+ target,
+ element,
+ elementLen,
+ targetIndex,
+ depth - 1
+ );
+ } else {
+ // Step 3.c.vi.1.
+ if (targetIndex >= MAX_NUMERIC_INDEX) {
+ ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
+ }
+
+ // Step 3.c.vi.2.
+ DefineDataProperty(target, targetIndex, element);
+
+ // Step 3.c.vi.3.
+ targetIndex++;
+ }
+ }
+ }
+
+ // Step 4.
+ return targetIndex;
+}
+
+// https://github.com/tc39/proposal-relative-indexing-method
+// Array.prototype.at ( index )
+function ArrayAt(index) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var len = ToLength(O.length);
+
+ // Step 3.
+ var relativeIndex = ToInteger(index);
+
+ // Steps 4-5.
+ var k;
+ if (relativeIndex >= 0) {
+ k = relativeIndex;
+ } else {
+ k = len + relativeIndex;
+ }
+
+ // Step 6.
+ if (k < 0 || k >= len) {
+ return undefined;
+ }
+
+ // Step 7.
+ return O[k];
+}
+// This function is only barely too long for normal inlining.
+SetIsInlinableLargeFunction(ArrayAt);
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// Array.prototype.toReversed()
+function ArrayToReversed() {
+ // Step 1. Let O be ? ToObject(this value).
+ var O = ToObject(this);
+
+ // Step 2. Let len be ? LengthOfArrayLike(O).
+ var len = ToLength(O.length);
+
+ // Step 3. Let A be ArrayCreate(𝔽(len)).
+ var A = std_Array(len);
+
+ // Step 4. Let k be 0.
+ // Step 5. Repeat, while k < len,
+ for (var k = 0; k < len; k++) {
+ // Step 5.a. Let from be ! ToString(𝔽(len - k - 1)).
+ var from = len - k - 1;
+
+ // Skip Step 5.b. Let Pk be ToString(𝔽(k)).
+ // k is coerced into a string through the property access.
+
+ // Step 5.c. Let fromValue be ? Get(O, from).
+ var fromValue = O[from];
+
+ // Step 5.d. Perform ! CreateDataPropertyOrThrow(A, 𝔽(k), fromValue).
+ DefineDataProperty(A, k, fromValue);
+ }
+
+ // Step 6. Return A.
+ return A;
+}
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// Array.prototype.toSorted()
+function ArrayToSorted(comparefn) {
+ // Step 1. If comparefn is not undefined and IsCallable(comparefn) is
+ // false, throw a TypeError exception.
+ if (comparefn !== undefined && !IsCallable(comparefn)) {
+ ThrowTypeError(JSMSG_BAD_TOSORTED_ARG);
+ }
+
+ // Step 2. Let O be ? ToObject(this value).
+ var O = ToObject(this);
+
+ // Step 3. Let len be ? LengthOfArrayLike(O).
+ var len = ToLength(O.length);
+
+ // Step 4. Let A be ? ArrayCreate(𝔽(len)).
+ var items = std_Array(len);
+
+ // We depart from steps 5-8 of the spec for performance reasons, as
+ // following the spec would require copying the input array twice.
+ // Instead, we create a new array that replaces holes with undefined,
+ // and sort this array.
+ for (var k = 0; k < len; k++) {
+ DefineDataProperty(items, k, O[k]);
+ }
+
+ // Arrays with less than two elements remain unchanged when sorted.
+ if (len <= 1) {
+ 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;
+}
+
+// https://github.com/tc39/proposal-array-find-from-last
+// Array.prototype.findLast ( predicate, thisArg )
+function ArrayFindLast(predicate /*, thisArg*/) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Step 2.
+ var len = ToLength(O.length);
+
+ // Step 3.
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLast");
+ }
+ if (!IsCallable(predicate)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
+ }
+
+ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Steps 4-5.
+ for (var k = len - 1; k >= 0; k--) {
+ // Steps 5.a-b.
+ var kValue = O[k];
+
+ // Steps 5.c-d.
+ if (callContentFunction(predicate, thisArg, kValue, k, O)) {
+ return kValue;
+ }
+ }
+
+ // Step 6.
+ return undefined;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayFindLast);
+
+// https://github.com/tc39/proposal-array-find-from-last
+// Array.prototype.findLastIndex ( predicate, thisArg )
+function ArrayFindLastIndex(predicate /*, thisArg*/) {
+ // Step 1.
+ var O = ToObject(this);
+
+ // Steps 2.
+ var len = ToLength(O.length);
+
+ // Step 3.
+ if (ArgumentsLength() === 0) {
+ ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLastIndex");
+ }
+ if (!IsCallable(predicate)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
+ }
+
+ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Steps 4-5.
+ for (var k = len - 1; k >= 0; k--) {
+ // Steps 5.a-d.
+ if (callContentFunction(predicate, thisArg, O[k], k, O)) {
+ return k;
+ }
+ }
+
+ // Step 6.
+ return -1;
+}
+// Inlining this enables inlining of the callback function.
+SetIsInlinableLargeFunction(ArrayFindLastIndex);