Bug 1885489 - Part 5: Add SnapshotIterator::readInt32(). r=iain
[gecko.git] / js / src / builtin / Array.js
blobb62edef7e9615a1ceff393a045681cd27a312ecd
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /* ES5 15.4.4.16. */
6 function ArrayEvery(callbackfn /*, thisArg*/) {
7   /* Step 1. */
8   var O = ToObject(this);
10   /* Steps 2-3. */
11   var len = ToLength(O.length);
13   /* Step 4. */
14   if (ArgumentsLength() === 0) {
15     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.every");
16   }
17   if (!IsCallable(callbackfn)) {
18     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
19   }
21   /* Step 5. */
22   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
24   /* Steps 6-7. */
25   /* Steps a (implicit), and d. */
26   for (var k = 0; k < len; k++) {
27     /* Step b */
28     if (k in O) {
29       /* Step c. */
30       if (!callContentFunction(callbackfn, T, O[k], k, O)) {
31         return false;
32       }
33     }
34   }
36   /* Step 8. */
37   return true;
39 // Inlining this enables inlining of the callback function.
40 SetIsInlinableLargeFunction(ArrayEvery);
42 /* ES5 15.4.4.17. */
43 function ArraySome(callbackfn /*, thisArg*/) {
44   /* Step 1. */
45   var O = ToObject(this);
47   /* Steps 2-3. */
48   var len = ToLength(O.length);
50   /* Step 4. */
51   if (ArgumentsLength() === 0) {
52     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.some");
53   }
54   if (!IsCallable(callbackfn)) {
55     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
56   }
58   /* Step 5. */
59   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
61   /* Steps 6-7. */
62   /* Steps a (implicit), and d. */
63   for (var k = 0; k < len; k++) {
64     /* Step b */
65     if (k in O) {
66       /* Step c. */
67       if (callContentFunction(callbackfn, T, O[k], k, O)) {
68         return true;
69       }
70     }
71   }
73   /* Step 8. */
74   return false;
76 // Inlining this enables inlining of the callback function.
77 SetIsInlinableLargeFunction(ArraySome);
79 /* ES5 15.4.4.18. */
80 function ArrayForEach(callbackfn /*, thisArg*/) {
81   /* Step 1. */
82   var O = ToObject(this);
84   /* Steps 2-3. */
85   var len = ToLength(O.length);
87   /* Step 4. */
88   if (ArgumentsLength() === 0) {
89     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach");
90   }
91   if (!IsCallable(callbackfn)) {
92     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
93   }
95   /* Step 5. */
96   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
98   /* Steps 6-7. */
99   /* Steps a (implicit), and d. */
100   for (var k = 0; k < len; k++) {
101     /* Step b */
102     if (k in O) {
103       /* Step c. */
104       callContentFunction(callbackfn, T, O[k], k, O);
105     }
106   }
108   /* Step 8. */
109   return undefined;
111 // Inlining this enables inlining of the callback function.
112 SetIsInlinableLargeFunction(ArrayForEach);
114 /* ES 2016 draft Mar 25, 2016 22.1.3.15. */
115 function ArrayMap(callbackfn /*, thisArg*/) {
116   /* Step 1. */
117   var O = ToObject(this);
119   /* Step 2. */
120   var len = ToLength(O.length);
122   /* Step 3. */
123   if (ArgumentsLength() === 0) {
124     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.map");
125   }
126   if (!IsCallable(callbackfn)) {
127     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
128   }
130   /* Step 4. */
131   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
133   /* Steps 5. */
134   var A = ArraySpeciesCreate(O, len);
136   /* Steps 6-7. */
137   /* Steps 7.a (implicit), and 7.d. */
138   for (var k = 0; k < len; k++) {
139     /* Steps 7.b-c. */
140     if (k in O) {
141       /* Steps 7.c.i-iii. */
142       var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
143       DefineDataProperty(A, k, mappedValue);
144     }
145   }
147   /* Step 8. */
148   return A;
150 // Inlining this enables inlining of the callback function.
151 SetIsInlinableLargeFunction(ArrayMap);
153 /* ES 2016 draft Mar 25, 2016 22.1.3.7 Array.prototype.filter. */
154 function ArrayFilter(callbackfn /*, thisArg*/) {
155   /* Step 1. */
156   var O = ToObject(this);
158   /* Step 2. */
159   var len = ToLength(O.length);
161   /* Step 3. */
162   if (ArgumentsLength() === 0) {
163     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.filter");
164   }
165   if (!IsCallable(callbackfn)) {
166     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
167   }
169   /* Step 4. */
170   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
172   /* Step 5. */
173   var A = ArraySpeciesCreate(O, 0);
175   /* Steps 6-8. */
176   /* Steps 8.a (implicit), and 8.d. */
177   for (var k = 0, to = 0; k < len; k++) {
178     /* Steps 8.b-c. */
179     if (k in O) {
180       /* Step 8.c.i. */
181       var kValue = O[k];
182       /* Steps 8.c.ii-iii. */
183       if (callContentFunction(callbackfn, T, kValue, k, O)) {
184         DefineDataProperty(A, to++, kValue);
185       }
186     }
187   }
189   /* Step 9. */
190   return A;
192 // Inlining this enables inlining of the callback function.
193 SetIsInlinableLargeFunction(ArrayFilter);
195 /* ES5 15.4.4.21. */
196 function ArrayReduce(callbackfn /*, initialValue*/) {
197   /* Step 1. */
198   var O = ToObject(this);
200   /* Steps 2-3. */
201   var len = ToLength(O.length);
203   /* Step 4. */
204   if (ArgumentsLength() === 0) {
205     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce");
206   }
207   if (!IsCallable(callbackfn)) {
208     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
209   }
211   /* Step 6. */
212   var k = 0;
214   /* Steps 5, 7-8. */
215   var accumulator;
216   if (ArgumentsLength() > 1) {
217     accumulator = GetArgument(1);
218   } else {
219     /* Step 5. */
220     // Add an explicit |throw| here and below to inform Ion that the
221     // ThrowTypeError calls exit this function.
222     if (len === 0) {
223       throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
224     }
226     // Use a |do-while| loop to let Ion know that the loop will definitely
227     // be entered at least once. When Ion is then also able to inline the
228     // |in| operator, it can optimize away the whole loop.
229     var kPresent = false;
230     do {
231       if (k in O) {
232         kPresent = true;
233         break;
234       }
235     } while (++k < len);
236     if (!kPresent) {
237       throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
238     }
240     // Moved outside of the loop to ensure the assignment is non-conditional.
241     accumulator = O[k++];
242   }
244   /* Step 9. */
245   /* Steps a (implicit), and d. */
246   for (; k < len; k++) {
247     /* Step b */
248     if (k in O) {
249       /* Step c. */
250       accumulator = callContentFunction(
251         callbackfn,
252         undefined,
253         accumulator,
254         O[k],
255         k,
256         O
257       );
258     }
259   }
261   /* Step 10. */
262   return accumulator;
265 /* ES5 15.4.4.22. */
266 function ArrayReduceRight(callbackfn /*, initialValue*/) {
267   /* Step 1. */
268   var O = ToObject(this);
270   /* Steps 2-3. */
271   var len = ToLength(O.length);
273   /* Step 4. */
274   if (ArgumentsLength() === 0) {
275     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce");
276   }
277   if (!IsCallable(callbackfn)) {
278     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
279   }
281   /* Step 6. */
282   var k = len - 1;
284   /* Steps 5, 7-8. */
285   var accumulator;
286   if (ArgumentsLength() > 1) {
287     accumulator = GetArgument(1);
288   } else {
289     /* Step 5. */
290     // Add an explicit |throw| here and below to inform Ion that the
291     // ThrowTypeError calls exit this function.
292     if (len === 0) {
293       throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
294     }
296     // Use a |do-while| loop to let Ion know that the loop will definitely
297     // be entered at least once. When Ion is then also able to inline the
298     // |in| operator, it can optimize away the whole loop.
299     var kPresent = false;
300     do {
301       if (k in O) {
302         kPresent = true;
303         break;
304       }
305     } while (--k >= 0);
306     if (!kPresent) {
307       throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE);
308     }
310     // Moved outside of the loop to ensure the assignment is non-conditional.
311     accumulator = O[k--];
312   }
314   /* Step 9. */
315   /* Steps a (implicit), and d. */
316   for (; k >= 0; k--) {
317     /* Step b */
318     if (k in O) {
319       /* Step c. */
320       accumulator = callContentFunction(
321         callbackfn,
322         undefined,
323         accumulator,
324         O[k],
325         k,
326         O
327       );
328     }
329   }
331   /* Step 10. */
332   return accumulator;
335 /* ES6 draft 2013-05-14 15.4.3.23. */
336 function ArrayFind(predicate /*, thisArg*/) {
337   /* Steps 1-2. */
338   var O = ToObject(this);
340   /* Steps 3-5. */
341   var len = ToLength(O.length);
343   /* Step 6. */
344   if (ArgumentsLength() === 0) {
345     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find");
346   }
347   if (!IsCallable(predicate)) {
348     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
349   }
351   /* Step 7. */
352   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
354   /* Steps 8-9. */
355   /* Steps a (implicit), and g. */
356   for (var k = 0; k < len; k++) {
357     /* Steps a-c. */
358     var kValue = O[k];
359     /* Steps d-f. */
360     if (callContentFunction(predicate, T, kValue, k, O)) {
361       return kValue;
362     }
363   }
365   /* Step 10. */
366   return undefined;
368 // Inlining this enables inlining of the callback function.
369 SetIsInlinableLargeFunction(ArrayFind);
371 /* ES6 draft 2013-05-14 15.4.3.23. */
372 function ArrayFindIndex(predicate /*, thisArg*/) {
373   /* Steps 1-2. */
374   var O = ToObject(this);
376   /* Steps 3-5. */
377   var len = ToLength(O.length);
379   /* Step 6. */
380   if (ArgumentsLength() === 0) {
381     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find");
382   }
383   if (!IsCallable(predicate)) {
384     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
385   }
387   /* Step 7. */
388   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
390   /* Steps 8-9. */
391   /* Steps a (implicit), and g. */
392   for (var k = 0; k < len; k++) {
393     /* Steps a-f. */
394     if (callContentFunction(predicate, T, O[k], k, O)) {
395       return k;
396     }
397   }
399   /* Step 10. */
400   return -1;
402 // Inlining this enables inlining of the callback function.
403 SetIsInlinableLargeFunction(ArrayFindIndex);
405 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
406 // 22.1.3.3 Array.prototype.copyWithin ( target, start [ , end ] )
407 function ArrayCopyWithin(target, start, end = undefined) {
408   // Step 1.
409   var O = ToObject(this);
411   // Step 2.
412   var len = ToLength(O.length);
414   // Step 3.
415   var relativeTarget = ToInteger(target);
417   // Step 4.
418   var to =
419     relativeTarget < 0
420       ? std_Math_max(len + relativeTarget, 0)
421       : std_Math_min(relativeTarget, len);
423   // Step 5.
424   var relativeStart = ToInteger(start);
426   // Step 6.
427   var from =
428     relativeStart < 0
429       ? std_Math_max(len + relativeStart, 0)
430       : std_Math_min(relativeStart, len);
432   // Step 7.
433   var relativeEnd = end === undefined ? len : ToInteger(end);
435   // Step 8.
436   var final =
437     relativeEnd < 0
438       ? std_Math_max(len + relativeEnd, 0)
439       : std_Math_min(relativeEnd, len);
441   // Step 9.
442   var count = std_Math_min(final - from, len - to);
444   // Steps 10-12.
445   if (from < to && to < from + count) {
446     // Steps 10.b-c.
447     from = from + count - 1;
448     to = to + count - 1;
450     // Step 12.
451     while (count > 0) {
452       if (from in O) {
453         O[to] = O[from];
454       } else {
455         delete O[to];
456       }
458       from--;
459       to--;
460       count--;
461     }
462   } else {
463     // Step 12.
464     while (count > 0) {
465       if (from in O) {
466         O[to] = O[from];
467       } else {
468         delete O[to];
469       }
471       from++;
472       to++;
473       count--;
474     }
475   }
477   // Step 13.
478   return O;
481 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
482 // 22.1.3.6 Array.prototype.fill ( value [ , start [ , end ] ] )
483 function ArrayFill(value, start = 0, end = undefined) {
484   // Step 1.
485   var O = ToObject(this);
487   // Step 2.
488   var len = ToLength(O.length);
490   // Step 3.
491   var relativeStart = ToInteger(start);
493   // Step 4.
494   var k =
495     relativeStart < 0
496       ? std_Math_max(len + relativeStart, 0)
497       : std_Math_min(relativeStart, len);
499   // Step 5.
500   var relativeEnd = end === undefined ? len : ToInteger(end);
502   // Step 6.
503   var final =
504     relativeEnd < 0
505       ? std_Math_max(len + relativeEnd, 0)
506       : std_Math_min(relativeEnd, len);
508   // Step 7.
509   for (; k < final; k++) {
510     O[k] = value;
511   }
513   // Step 8.
514   return O;
517 // ES6 draft specification, section 22.1.5.1, version 2013-09-05.
518 function CreateArrayIterator(obj, kind) {
519   var iteratedObject = ToObject(obj);
520   var iterator = NewArrayIterator();
521   UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
522   UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
523   UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
524   return iterator;
527 // ES6, 22.1.5.2.1
528 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next
529 function ArrayIteratorNext() {
530   // Step 1-3.
531   var obj = this;
532   if (!IsObject(obj) || (obj = GuardToArrayIterator(obj)) === null) {
533     return callFunction(
534       CallArrayIteratorMethodIfWrapped,
535       this,
536       "ArrayIteratorNext"
537     );
538   }
540   // Step 4.
541   var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET);
542   var result = { value: undefined, done: false };
544   // Step 5.
545   if (a === null) {
546     result.done = true;
547     return result;
548   }
550   // Step 6.
551   // The index might not be an integer, so we have to do a generic get here.
552   var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
554   // Step 7.
555   var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
557   // Step 8-9.
558   var len;
559   if (IsPossiblyWrappedTypedArray(a)) {
560     len = PossiblyWrappedTypedArrayLength(a);
562     // If the length is non-zero, the buffer can't be detached.
563     if (len === 0) {
564       if (PossiblyWrappedTypedArrayHasDetachedBuffer(a)) {
565         ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
566       }
567     }
568   } else {
569     len = ToLength(a.length);
570   }
572   // Step 10.
573   if (index >= len) {
574     UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null);
575     result.done = true;
576     return result;
577   }
579   // Step 11.
580   UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1);
582   // Step 16.
583   if (itemKind === ITEM_KIND_VALUE) {
584     result.value = a[index];
585     return result;
586   }
588   // Step 13.
589   if (itemKind === ITEM_KIND_KEY_AND_VALUE) {
590     var pair = [index, a[index]];
591     result.value = pair;
592     return result;
593   }
595   // Step 12.
596   assert(itemKind === ITEM_KIND_KEY, itemKind);
597   result.value = index;
598   return result;
600 // We want to inline this to do scalar replacement of the result object.
601 SetIsInlinableLargeFunction(ArrayIteratorNext);
603 // Uncloned functions with `$` prefix are allocated as extended function
604 // to store the original name in `SetCanonicalName`.
605 function $ArrayValues() {
606   return CreateArrayIterator(this, ITEM_KIND_VALUE);
608 SetCanonicalName($ArrayValues, "values");
610 function ArrayEntries() {
611   return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
614 function ArrayKeys() {
615   return CreateArrayIterator(this, ITEM_KIND_KEY);
618 // https://tc39.es/proposal-array-from-async/
619 // TODO: Bug 1834560 The step numbers in this will need updating when this is merged
620 // into the main spec.
621 function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
622   // Step 1. Let C be the this value.
623   var C = this;
625   // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
626   // 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:
627   var fromAsyncClosure = async () => {
628     // Step 3.a. If mapfn is undefined, let mapping be false.
629     // Step 3.b. Else,
630     //     Step 3.b.i. If IsCallable(mapfn) is false, throw a TypeError exception.
631     //     Step 3.b.ii. Let mapping be true.
632     var mapping = mapfn !== undefined;
633     if (mapping && !IsCallable(mapfn)) {
634       ThrowTypeError(JSMSG_NOT_FUNCTION, ToSource(mapfn));
635     }
637     // Step 3.c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator).
638     var usingAsyncIterator = asyncItems[GetBuiltinSymbol("asyncIterator")];
639     if (usingAsyncIterator === null) {
640       usingAsyncIterator = undefined;
641     }
643     var usingSyncIterator = undefined;
644     if (usingAsyncIterator !== undefined) {
645       if (!IsCallable(usingAsyncIterator)) {
646         ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems));
647       }
648     } else {
649       // Step 3.d. If usingAsyncIterator is undefined, then
651       // Step 3.d.i. Let usingSyncIterator be ? GetMethod(asyncItems, @@iterator).
652       usingSyncIterator = asyncItems[GetBuiltinSymbol("iterator")];
653       if (usingSyncIterator === null) {
654         usingSyncIterator = undefined;
655       }
657       if (usingSyncIterator !== undefined) {
658         if (!IsCallable(usingSyncIterator)) {
659           ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems));
660         }
661       }
662     }
664     // Step 3.g. Let iteratorRecord be undefined.
665     // Step 3.j. If iteratorRecord is not undefined, then ...
666     if (usingAsyncIterator !== undefined || usingSyncIterator !== undefined) {
667       // Note: The published spec as of f6acfc4f0277e625f13fd22068138aec61a12df3
668       //       is incorrect. See https://github.com/tc39/proposal-array-from-async/issues/33
669       //       Here we use the implementation provided by @bakkot in that bug
670       //       in lieu for now; This allows to use a for-await loop below.
672       // Steps 3.h-i are implicit through the for-await loop.
674       // Step 3.h. If usingAsyncIterator is not undefined, then
675       //     Step 3.h.i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
676       // Step 3.i. Else if usingSyncIterator is not undefined, then
677       //     Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
679       // https://github.com/tc39/proposal-array-from-async/pull/41
680       // Step 3.e. If IsConstructor(C) is true, then
681       //     Step 3.e.i. Let A be ? Construct(C).
682       // Step 3.f. Else,
683       //     Step 3.f.i. Let A be ! ArrayCreate(0).
684       var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
687       // Step 3.j.i. Let k be 0.
688       var k = 0;
690       // Step 3.j.ii. Repeat,
691       for await (var nextValue of allowContentIterWith(
692         asyncItems,
693         usingAsyncIterator,
694         usingSyncIterator
695       )) {
696         // Following in the steps of Array.from, we don't actually implement 3.j.ii.1.
697         // The comment in Array.from also applies here; we should only encounter this
698         // after a huge loop around a proxy
699         // Step 3.j.ii.1. If k ≥ 2**53 - 1, then
700         //     Step 3.j.ii.1.a. Let error be ThrowCompletion(a newly created TypeError object).
701         //     Step 3.j.ii.1.b. Return ? AsyncIteratorClose(iteratorRecord, error).
702         // Step 3.j.ii.2. Let Pk be ! ToString(𝔽(k)).
704         // Step 3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
706         // Step 3.j.ii.5. Let nextValue be ? IteratorValue(next). (Implicit through the for-await loop).
708         // Step 3.j.ii.7. Else, let mappedValue be nextValue. (Reordered)
709         var mappedValue = nextValue;
711         // Step 3.j.ii.6. If mapping is true, then
712         if (mapping) {
713           // Step 3.j.ii.6.a. Let mappedValue be Call(mapfn, thisArg, « nextValue, 𝔽(k) »).
714           // Step 3.j.ii.6.b. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
715           //   Abrupt completion will be handled by the for-await loop.
716           mappedValue = callContentFunction(mapfn, thisArg, nextValue, k);
718           // Step 3.j.ii.6.c. Set mappedValue to Await(mappedValue).
719           // Step 3.j.ii.6.d. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
720           mappedValue = await mappedValue;
721         }
723         // Step 3.j.ii.8. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
724         // Step 3.j.ii.9. If defineStatus is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, defineStatus).
725         DefineDataProperty(A, k, mappedValue);
727         // Step 3.j.ii.10. Set k to k + 1.
728         k = k + 1;
729       }
731       // Step 3.j.ii.4. If next is false, then (Reordered)
733       // Step 3.j.ii.4.a. Perform ? Set(A, "length", 𝔽(k), true).
734       A.length = k;
736       // Step 3.j.ii.4.b. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
737       return A;
738     }
740     // Step 3.k. Else,
742     // Step 3.k.i. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object.
743     // Step 3.k.ii. Let arrayLike be ! ToObject(asyncItems).
744     var arrayLike = ToObject(asyncItems);
746     // Step 3.k.iii. Let len be ? LengthOfArrayLike(arrayLike).
747     var len = ToLength(arrayLike.length);
749     // Step 3.k.iv. If IsConstructor(C) is true, then
750     //     Step 3.k.iv.1. Let A be ? Construct(C, « 𝔽(len) »).
751     // Step 3.k.v. Else,
752     //     Step 3.k.v.1. Let A be ? ArrayCreate(len).
753     var A = IsConstructor(C) ? constructContentFunction(C, C, len) : std_Array(len);
755     // Step 3.k.vi. Let k be 0.
756     var k = 0;
758     // Step 3.k.vii. Repeat, while k < len,
759     while (k < len) {
760       // Step 3.k.vii.1. Let Pk be ! ToString(𝔽(k)).
761       // Step 3.k.vii.2. Let kValue be ? Get(arrayLike, Pk).
762       // Step 3.k.vii.3. Let kValue be ? Await(kValue).
763       var kValue = await arrayLike[k];
765       // Step 3.k.vii.4. If mapping is true, then
766       //     Step 3.k.vii.4.a. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽(k) »).
767       //     Step 3.k.vii.4.b. Let mappedValue be ? Await(mappedValue).
768       // Step 3.k.vii.5. Else, let mappedValue be kValue.
769       var mappedValue = mapping
770         ? await callContentFunction(mapfn, thisArg, kValue, k)
771         : kValue;
773       // Step 3.k.vii.6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
774       DefineDataProperty(A, k, mappedValue);
776       // Step 3.k.vii.7. Set k to k + 1.
777       k = k + 1;
778     }
780     // Step 3.k.viii. Perform ? Set(A, "length", 𝔽(len), true).
781     A.length = len;
783     // Step 3.k.ix. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
784     return A;
785   };
787   // Step 4. Perform AsyncFunctionStart(promiseCapability, fromAsyncClosure).
788   // Step 5. Return promiseCapability.[[Promise]].
789   return fromAsyncClosure();
792 // ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1
793 function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
794   // Step 1.
795   var C = this;
797   // Steps 2-3.
798   var mapping = mapfn !== undefined;
799   if (mapping && !IsCallable(mapfn)) {
800     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
801   }
802   var T = thisArg;
804   // Step 4.
805   // Inlined: GetMethod, steps 1-2.
806   var usingIterator = items[GetBuiltinSymbol("iterator")];
808   // Step 5.
809   // Inlined: GetMethod, step 3.
810   if (!IsNullOrUndefined(usingIterator)) {
811     // Inlined: GetMethod, step 4.
812     if (!IsCallable(usingIterator)) {
813       ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, items));
814     }
816     // Steps 5.a-b.
817     var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
819     // Step 5.d.
820     var k = 0;
822     // Steps 5.c, 5.e
823     for (var nextValue of allowContentIterWith(items, usingIterator)) {
824       // Step 5.e.i.
825       // Disabled for performance reason.  We won't hit this case on
826       // normal array, since DefineDataProperty will throw before it.
827       // We could hit this when |A| is a proxy and it ignores
828       // |DefineDataProperty|, but it happens only after too long loop.
829       /*
830       if (k >= 0x1fffffffffffff) {
831           ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
832       }
833       */
835       // Steps 5.e.vi-vii.
836       var mappedValue = mapping
837         ? callContentFunction(mapfn, T, nextValue, k)
838         : nextValue;
840       // Steps 5.e.ii (reordered), 5.e.viii.
841       DefineDataProperty(A, k++, mappedValue);
842     }
844     // Step 5.e.iv.
845     A.length = k;
846     return A;
847   }
849   // Step 7 is an assertion: items is not an Iterator. Testing this is
850   // literally the very last thing we did, so we don't assert here.
852   // Steps 8-9.
853   var arrayLike = ToObject(items);
855   // Steps 10-11.
856   var len = ToLength(arrayLike.length);
858   // Steps 12-14.
859   var A = IsConstructor(C)
860     ? constructContentFunction(C, C, len)
861     : std_Array(len);
863   // Steps 15-16.
864   for (var k = 0; k < len; k++) {
865     // Steps 16.a-c.
866     var kValue = items[k];
868     // Steps 16.d-e.
869     var mappedValue = mapping
870       ? callContentFunction(mapfn, T, kValue, k)
871       : kValue;
873     // Steps 16.f-g.
874     DefineDataProperty(A, k, mappedValue);
875   }
877   // Steps 17-18.
878   A.length = len;
880   // Step 19.
881   return A;
884 // ES2015 22.1.3.27 Array.prototype.toString.
885 function ArrayToString() {
886   // Steps 1-2.
887   var array = ToObject(this);
889   // Steps 3-4.
890   var func = array.join;
892   // Steps 5-6.
893   if (!IsCallable(func)) {
894     return callFunction(std_Object_toString, array);
895   }
896   return callContentFunction(func, array);
899 // ES2017 draft rev f8a9be8ea4bd97237d176907a1e3080dce20c68f
900 // 22.1.3.27 Array.prototype.toLocaleString ([ reserved1 [ , reserved2 ] ])
901 // ES2017 Intl draft rev 78bbe7d1095f5ff3760ac4017ed366026e4cb276
902 // 13.4.1 Array.prototype.toLocaleString ([ locales [ , options ]])
903 function ArrayToLocaleString(locales, options) {
904   // Step 1 (ToObject already performed in native code).
905   assert(IsObject(this), "|this| should be an object");
906   var array = this;
908   // Step 2.
909   var len = ToLength(array.length);
911   // Step 4.
912   if (len === 0) {
913     return "";
914   }
916   // Step 5.
917   var firstElement = array[0];
919   // Steps 6-7.
920   var R;
921   if (IsNullOrUndefined(firstElement)) {
922     R = "";
923   } else {
924 #if JS_HAS_INTL_API
925     R = ToString(
926       callContentFunction(
927         firstElement.toLocaleString,
928         firstElement,
929         locales,
930         options
931       )
932     );
933 #else
934     R = ToString(
935       callContentFunction(firstElement.toLocaleString, firstElement)
936     );
937 #endif
938   }
940   // Step 3 (reordered).
941   // We don't (yet?) implement locale-dependent separators.
942   var separator = ",";
944   // Steps 8-9.
945   for (var k = 1; k < len; k++) {
946     // Step 9.b.
947     var nextElement = array[k];
949     // Steps 9.a, 9.c-e.
950     R += separator;
951     if (!IsNullOrUndefined(nextElement)) {
952 #if JS_HAS_INTL_API
953       R += ToString(
954         callContentFunction(
955           nextElement.toLocaleString,
956           nextElement,
957           locales,
958           options
959         )
960       );
961 #else
962       R += ToString(
963         callContentFunction(nextElement.toLocaleString, nextElement)
964       );
965 #endif
966     }
967   }
969   // Step 10.
970   return R;
973 // ES 2016 draft Mar 25, 2016 22.1.2.5.
974 function $ArraySpecies() {
975   // Step 1.
976   return this;
978 SetCanonicalName($ArraySpecies, "get [Symbol.species]");
980 // ES 2016 draft Mar 25, 2016 9.4.2.3.
981 function ArraySpeciesCreate(originalArray, length) {
982   // Step 1.
983   assert(typeof length === "number", "length should be a number");
984   assert(length >= 0, "length should be a non-negative number");
986   // Step 2.
987   // eslint-disable-next-line no-compare-neg-zero
988   if (length === -0) {
989     length = 0;
990   }
992   // Step 4, 6.
993   if (!IsArray(originalArray)) {
994     return std_Array(length);
995   }
997   // Step 5.a.
998   var C = originalArray.constructor;
1000   // Step 5.b.
1001   if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) {
1002     return std_Array(length);
1003   }
1005   // Step 5.c.
1006   if (IsObject(C)) {
1007     // Step 5.c.i.
1008     C = C[GetBuiltinSymbol("species")];
1010     // Optimized path for an ordinary Array.
1011     if (C === GetBuiltinConstructor("Array")) {
1012       return std_Array(length);
1013     }
1015     // Step 5.c.ii.
1016     if (C === null) {
1017       return std_Array(length);
1018     }
1019   }
1021   // Step 6.
1022   if (C === undefined) {
1023     return std_Array(length);
1024   }
1026   // Step 7.
1027   if (!IsConstructor(C)) {
1028     ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, "constructor property");
1029   }
1031   // Step 8.
1032   return constructContentFunction(C, C, length);
1035 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
1036 // 22.1.3.11 Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
1037 function ArrayFlatMap(mapperFunction /*, thisArg*/) {
1038   // Step 1.
1039   var O = ToObject(this);
1041   // Step 2.
1042   var sourceLen = ToLength(O.length);
1044   // Step 3.
1045   if (!IsCallable(mapperFunction)) {
1046     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
1047   }
1049   // Step 4.
1050   var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
1052   // Step 5.
1053   var A = ArraySpeciesCreate(O, 0);
1055   // Step 6.
1056   FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
1058   // Step 7.
1059   return A;
1062 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
1063 // 22.1.3.10 Array.prototype.flat ( [ depth ] )
1064 function ArrayFlat(/* depth */) {
1065   // Step 1.
1066   var O = ToObject(this);
1068   // Step 2.
1069   var sourceLen = ToLength(O.length);
1071   // Step 3.
1072   var depthNum = 1;
1074   // Step 4.
1075   if (ArgumentsLength() && GetArgument(0) !== undefined) {
1076     depthNum = ToInteger(GetArgument(0));
1077   }
1079   // Step 5.
1080   var A = ArraySpeciesCreate(O, 0);
1082   // Step 6.
1083   FlattenIntoArray(A, O, sourceLen, 0, depthNum);
1085   // Step 7.
1086   return A;
1089 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
1090 // 22.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
1091 function FlattenIntoArray(
1092   target,
1093   source,
1094   sourceLen,
1095   start,
1096   depth,
1097   mapperFunction,
1098   thisArg
1099 ) {
1100   // Step 1.
1101   var targetIndex = start;
1103   // Steps 2-3.
1104   for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
1105     // Steps 3.a-c.
1106     if (sourceIndex in source) {
1107       // Step 3.c.i.
1108       var element = source[sourceIndex];
1110       if (mapperFunction) {
1111         // Step 3.c.ii.1.
1112         assert(ArgumentsLength() === 7, "thisArg is present");
1114         // Step 3.c.ii.2.
1115         element = callContentFunction(
1116           mapperFunction,
1117           thisArg,
1118           element,
1119           sourceIndex,
1120           source
1121         );
1122       }
1124       // Step 3.c.iii.
1125       var shouldFlatten = false;
1127       // Step 3.c.iv.
1128       if (depth > 0) {
1129         // Step 3.c.iv.1.
1130         shouldFlatten = IsArray(element);
1131       }
1133       // Step 3.c.v.
1134       if (shouldFlatten) {
1135         // Step 3.c.v.1.
1136         var elementLen = ToLength(element.length);
1138         // Step 3.c.v.2.
1139         targetIndex = FlattenIntoArray(
1140           target,
1141           element,
1142           elementLen,
1143           targetIndex,
1144           depth - 1
1145         );
1146       } else {
1147         // Step 3.c.vi.1.
1148         if (targetIndex >= MAX_NUMERIC_INDEX) {
1149           ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
1150         }
1152         // Step 3.c.vi.2.
1153         DefineDataProperty(target, targetIndex, element);
1155         // Step 3.c.vi.3.
1156         targetIndex++;
1157       }
1158     }
1159   }
1161   // Step 4.
1162   return targetIndex;
1165 // https://github.com/tc39/proposal-relative-indexing-method
1166 // Array.prototype.at ( index )
1167 function ArrayAt(index) {
1168   // Step 1.
1169   var O = ToObject(this);
1171   // Step 2.
1172   var len = ToLength(O.length);
1174   // Step 3.
1175   var relativeIndex = ToInteger(index);
1177   // Steps 4-5.
1178   var k;
1179   if (relativeIndex >= 0) {
1180     k = relativeIndex;
1181   } else {
1182     k = len + relativeIndex;
1183   }
1185   // Step 6.
1186   if (k < 0 || k >= len) {
1187     return undefined;
1188   }
1190   // Step 7.
1191   return O[k];
1193 // This function is only barely too long for normal inlining.
1194 SetIsInlinableLargeFunction(ArrayAt);
1196 // https://github.com/tc39/proposal-change-array-by-copy
1197 // Array.prototype.toReversed()
1198 function ArrayToReversed() {
1199   // Step 1. Let O be ? ToObject(this value).
1200   var O = ToObject(this);
1202   // Step 2. Let len be ? LengthOfArrayLike(O).
1203   var len = ToLength(O.length);
1205   // Step 3. Let A be ArrayCreate(𝔽(len)).
1206   var A = std_Array(len);
1208   // Step 4. Let k be 0.
1209   // Step 5. Repeat, while k < len,
1210   for (var k = 0; k < len; k++) {
1211     // Step 5.a. Let from be ! ToString(𝔽(len - k - 1)).
1212     var from = len - k - 1;
1214     // Skip Step 5.b. Let Pk be ToString(𝔽(k)).
1215     // k is coerced into a string through the property access.
1217     // Step 5.c. Let fromValue be ? Get(O, from).
1218     var fromValue = O[from];
1220     // Step 5.d. Perform ! CreateDataPropertyOrThrow(A, 𝔽(k), fromValue).
1221     DefineDataProperty(A, k, fromValue);
1222   }
1224   // Step 6. Return A.
1225   return A;
1228 // https://github.com/tc39/proposal-change-array-by-copy
1229 // Array.prototype.toSorted()
1230 function ArrayToSorted(comparefn) {
1231   // Step 1.  If comparefn is not undefined and IsCallable(comparefn) is
1232   // false, throw a TypeError exception.
1233   if (comparefn !== undefined && !IsCallable(comparefn)) {
1234     ThrowTypeError(JSMSG_BAD_TOSORTED_ARG);
1235   }
1237   // Step 2. Let O be ? ToObject(this value).
1238   var O = ToObject(this);
1240   // Step 3. Let len be ? LengthOfArrayLike(O).
1241   var len = ToLength(O.length);
1243   // Step 4. Let A be ? ArrayCreate(𝔽(len)).
1244   var items = std_Array(len);
1246   // We depart from steps 5-8 of the spec for performance reasons, as
1247   // following the spec would require copying the input array twice.
1248   // Instead, we create a new array that replaces holes with undefined,
1249   // and sort this array.
1250   for (var k = 0; k < len; k++) {
1251     DefineDataProperty(items, k, O[k]);
1252   }
1254   // Arrays with less than two elements remain unchanged when sorted.
1255   if (len <= 1) {
1256     return items;
1257   }
1259   // Steps 5-9.
1260   return callFunction(std_Array_sort, items, comparefn);
1263 // https://github.com/tc39/proposal-array-find-from-last
1264 // Array.prototype.findLast ( predicate, thisArg )
1265 function ArrayFindLast(predicate /*, thisArg*/) {
1266   // Step 1.
1267   var O = ToObject(this);
1269   // Step 2.
1270   var len = ToLength(O.length);
1272   // Step 3.
1273   if (ArgumentsLength() === 0) {
1274     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLast");
1275   }
1276   if (!IsCallable(predicate)) {
1277     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
1278   }
1280   var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
1282   // Steps 4-5.
1283   for (var k = len - 1; k >= 0; k--) {
1284     // Steps 5.a-b.
1285     var kValue = O[k];
1287     // Steps 5.c-d.
1288     if (callContentFunction(predicate, thisArg, kValue, k, O)) {
1289       return kValue;
1290     }
1291   }
1293   // Step 6.
1294   return undefined;
1296 // Inlining this enables inlining of the callback function.
1297 SetIsInlinableLargeFunction(ArrayFindLast);
1299 // https://github.com/tc39/proposal-array-find-from-last
1300 // Array.prototype.findLastIndex ( predicate, thisArg )
1301 function ArrayFindLastIndex(predicate /*, thisArg*/) {
1302   // Step 1.
1303   var O = ToObject(this);
1305   // Steps 2.
1306   var len = ToLength(O.length);
1308   // Step 3.
1309   if (ArgumentsLength() === 0) {
1310     ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLastIndex");
1311   }
1312   if (!IsCallable(predicate)) {
1313     ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
1314   }
1316   var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
1318   // Steps 4-5.
1319   for (var k = len - 1; k >= 0; k--) {
1320     // Steps 5.a-d.
1321     if (callContentFunction(predicate, thisArg, O[k], k, O)) {
1322       return k;
1323     }
1324   }
1326   // Step 6.
1327   return -1;
1329 // Inlining this enables inlining of the callback function.
1330 SetIsInlinableLargeFunction(ArrayFindLastIndex);