Array.js (34402B)
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/. */ 4 5 /* ES5 15.4.4.16. */ 6 function ArrayEvery(callbackfn /*, thisArg*/) { 7 /* Step 1. */ 8 var O = ToObject(this); 9 10 /* Steps 2-3. */ 11 var len = ToLength(O.length); 12 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 } 20 21 /* Step 5. */ 22 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 23 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 } 35 36 /* Step 8. */ 37 return true; 38 } 39 // Inlining this enables inlining of the callback function. 40 SetIsInlinableLargeFunction(ArrayEvery); 41 42 /* ES5 15.4.4.17. */ 43 function ArraySome(callbackfn /*, thisArg*/) { 44 /* Step 1. */ 45 var O = ToObject(this); 46 47 /* Steps 2-3. */ 48 var len = ToLength(O.length); 49 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 } 57 58 /* Step 5. */ 59 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 60 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 } 72 73 /* Step 8. */ 74 return false; 75 } 76 // Inlining this enables inlining of the callback function. 77 SetIsInlinableLargeFunction(ArraySome); 78 79 /* ES5 15.4.4.18. */ 80 function ArrayForEach(callbackfn /*, thisArg*/) { 81 /* Step 1. */ 82 var O = ToObject(this); 83 84 /* Steps 2-3. */ 85 var len = ToLength(O.length); 86 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 } 94 95 /* Step 5. */ 96 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 97 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 } 107 108 /* Step 8. */ 109 return undefined; 110 } 111 // Inlining this enables inlining of the callback function. 112 SetIsInlinableLargeFunction(ArrayForEach); 113 114 /* ES 2016 draft Mar 25, 2016 22.1.3.15. */ 115 function ArrayMap(callbackfn /*, thisArg*/) { 116 /* Step 1. */ 117 var O = ToObject(this); 118 119 /* Step 2. */ 120 var len = ToLength(O.length); 121 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 } 129 130 /* Step 4. */ 131 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 132 133 /* Steps 5. */ 134 var A = CanOptimizeArraySpecies(O) ? std_Array(len) : ArraySpeciesCreate(O, len); 135 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 } 146 147 /* Step 8. */ 148 return A; 149 } 150 // Inlining this enables inlining of the callback function. 151 SetIsInlinableLargeFunction(ArrayMap); 152 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); 157 158 /* Step 2. */ 159 var len = ToLength(O.length); 160 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 } 168 169 /* Step 4. */ 170 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 171 172 /* Step 5. */ 173 var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0); 174 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 } 188 189 /* Step 9. */ 190 return A; 191 } 192 // Inlining this enables inlining of the callback function. 193 SetIsInlinableLargeFunction(ArrayFilter); 194 195 /* ES5 15.4.4.21. */ 196 function ArrayReduce(callbackfn /*, initialValue*/) { 197 /* Step 1. */ 198 var O = ToObject(this); 199 200 /* Steps 2-3. */ 201 var len = ToLength(O.length); 202 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 } 210 211 /* Step 6. */ 212 var k = 0; 213 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 } 225 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 } 239 240 // Moved outside of the loop to ensure the assignment is non-conditional. 241 accumulator = O[k++]; 242 } 243 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 } 260 261 /* Step 10. */ 262 return accumulator; 263 } 264 265 /* ES5 15.4.4.22. */ 266 function ArrayReduceRight(callbackfn /*, initialValue*/) { 267 /* Step 1. */ 268 var O = ToObject(this); 269 270 /* Steps 2-3. */ 271 var len = ToLength(O.length); 272 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 } 280 281 /* Step 6. */ 282 var k = len - 1; 283 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 } 295 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 } 309 310 // Moved outside of the loop to ensure the assignment is non-conditional. 311 accumulator = O[k--]; 312 } 313 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 } 330 331 /* Step 10. */ 332 return accumulator; 333 } 334 335 /* ES6 draft 2013-05-14 15.4.3.23. */ 336 function ArrayFind(predicate /*, thisArg*/) { 337 /* Steps 1-2. */ 338 var O = ToObject(this); 339 340 /* Steps 3-5. */ 341 var len = ToLength(O.length); 342 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 } 350 351 /* Step 7. */ 352 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 353 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 } 364 365 /* Step 10. */ 366 return undefined; 367 } 368 // Inlining this enables inlining of the callback function. 369 SetIsInlinableLargeFunction(ArrayFind); 370 371 /* ES6 draft 2013-05-14 15.4.3.23. */ 372 function ArrayFindIndex(predicate /*, thisArg*/) { 373 /* Steps 1-2. */ 374 var O = ToObject(this); 375 376 /* Steps 3-5. */ 377 var len = ToLength(O.length); 378 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 } 386 387 /* Step 7. */ 388 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 389 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 } 398 399 /* Step 10. */ 400 return -1; 401 } 402 // Inlining this enables inlining of the callback function. 403 SetIsInlinableLargeFunction(ArrayFindIndex); 404 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); 410 411 // Step 2. 412 var len = ToLength(O.length); 413 414 // Step 3. 415 var relativeTarget = ToInteger(target); 416 417 // Step 4. 418 var to = 419 relativeTarget < 0 420 ? std_Math_max(len + relativeTarget, 0) 421 : std_Math_min(relativeTarget, len); 422 423 // Step 5. 424 var relativeStart = ToInteger(start); 425 426 // Step 6. 427 var from = 428 relativeStart < 0 429 ? std_Math_max(len + relativeStart, 0) 430 : std_Math_min(relativeStart, len); 431 432 // Step 7. 433 var relativeEnd = end === undefined ? len : ToInteger(end); 434 435 // Step 8. 436 var final = 437 relativeEnd < 0 438 ? std_Math_max(len + relativeEnd, 0) 439 : std_Math_min(relativeEnd, len); 440 441 // Step 9. 442 var count = std_Math_min(final - from, len - to); 443 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; 449 450 // Step 12. 451 while (count > 0) { 452 if (from in O) { 453 O[to] = O[from]; 454 } else { 455 delete O[to]; 456 } 457 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 } 470 471 from++; 472 to++; 473 count--; 474 } 475 } 476 477 // Step 13. 478 return O; 479 } 480 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); 486 487 // Step 2. 488 var len = ToLength(O.length); 489 490 // Step 3. 491 var relativeStart = ToInteger(start); 492 493 // Step 4. 494 var k = 495 relativeStart < 0 496 ? std_Math_max(len + relativeStart, 0) 497 : std_Math_min(relativeStart, len); 498 499 // Step 5. 500 var relativeEnd = end === undefined ? len : ToInteger(end); 501 502 // Step 6. 503 var final = 504 relativeEnd < 0 505 ? std_Math_max(len + relativeEnd, 0) 506 : std_Math_min(relativeEnd, len); 507 508 // Step 7. 509 for (; k < final; k++) { 510 O[k] = value; 511 } 512 513 // Step 8. 514 return O; 515 } 516 517 // ES6, 22.1.5.2.1 518 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next 519 function ArrayIteratorNext() { 520 // Step 1-3. 521 var obj = this; 522 if (!IsObject(obj) || (obj = GuardToArrayIterator(obj)) === null) { 523 return callFunction( 524 CallArrayIteratorMethodIfWrapped, 525 this, 526 "ArrayIteratorNext" 527 ); 528 } 529 530 // Step 4. 531 var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET); 532 var result = { value: undefined, done: false }; 533 534 // Step 5. 535 if (a === null) { 536 result.done = true; 537 return result; 538 } 539 540 // Step 6. 541 // The index might not be an integer, so we have to do a generic get here. 542 var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); 543 544 // Step 7. 545 var itemKind = UnsafeGetInt32FromReservedSlot(obj, ARRAY_ITERATOR_SLOT_ITEM_KIND); 546 547 // Step 8-9. 548 var len; 549 if (IsPossiblyWrappedTypedArray(a)) { 550 len = PossiblyWrappedTypedArrayLength(a); 551 552 // If the length is non-zero, the buffer can't be detached. 553 if (len === 0) { 554 if (PossiblyWrappedTypedArrayHasDetachedBuffer(a)) { 555 ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); 556 } 557 } 558 } else { 559 len = ToLength(a.length); 560 } 561 562 // Step 10. 563 if (index >= len) { 564 UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); 565 result.done = true; 566 return result; 567 } 568 569 // Step 11. 570 UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1); 571 572 // Step 16. 573 if (itemKind === ITEM_KIND_VALUE) { 574 result.value = a[index]; 575 return result; 576 } 577 578 // Step 13. 579 if (itemKind === ITEM_KIND_KEY_AND_VALUE) { 580 var pair = [index, a[index]]; 581 result.value = pair; 582 return result; 583 } 584 585 // Step 12. 586 assert(itemKind === ITEM_KIND_KEY, itemKind); 587 result.value = index; 588 return result; 589 } 590 // We want to inline this to do scalar replacement of the result object. 591 SetIsInlinableLargeFunction(ArrayIteratorNext); 592 593 // Uncloned functions with `$` prefix are allocated as extended function 594 // to store the original name in `SetCanonicalName`. 595 function $ArrayValues() { 596 RETURN_ARRAY_ITERATOR(this, ITEM_KIND_VALUE); 597 } 598 SetCanonicalName($ArrayValues, "values"); 599 600 function ArrayEntries() { 601 RETURN_ARRAY_ITERATOR(this, ITEM_KIND_KEY_AND_VALUE); 602 } 603 604 function ArrayKeys() { 605 RETURN_ARRAY_ITERATOR(this, ITEM_KIND_KEY); 606 } 607 608 // https://tc39.es/proposal-array-from-async/ 609 // TODO: Bug 1834560 The step numbers in this will need updating when this is merged 610 // into the main spec. 611 function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) { 612 // Step 1. Let C be the this value. 613 var C = this; 614 615 // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). 616 // 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: 617 var fromAsyncClosure = async () => { 618 // Step 3.a. If mapfn is undefined, let mapping be false. 619 // Step 3.b. Else, 620 // Step 3.b.i. If IsCallable(mapfn) is false, throw a TypeError exception. 621 // Step 3.b.ii. Let mapping be true. 622 var mapping = mapfn !== undefined; 623 if (mapping && !IsCallable(mapfn)) { 624 ThrowTypeError(JSMSG_NOT_FUNCTION, ToSource(mapfn)); 625 } 626 627 // Step 3.c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator). 628 var usingAsyncIterator = asyncItems[GetBuiltinSymbol("asyncIterator")]; 629 if (usingAsyncIterator === null) { 630 usingAsyncIterator = undefined; 631 } 632 633 var usingSyncIterator = undefined; 634 if (usingAsyncIterator !== undefined) { 635 if (!IsCallable(usingAsyncIterator)) { 636 ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems)); 637 } 638 } else { 639 // Step 3.d. If usingAsyncIterator is undefined, then 640 641 // Step 3.d.i. Let usingSyncIterator be ? GetMethod(asyncItems, @@iterator). 642 usingSyncIterator = asyncItems[GetBuiltinSymbol("iterator")]; 643 if (usingSyncIterator === null) { 644 usingSyncIterator = undefined; 645 } 646 647 if (usingSyncIterator !== undefined) { 648 if (!IsCallable(usingSyncIterator)) { 649 ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(asyncItems)); 650 } 651 } 652 } 653 654 // Step 3.g. Let iteratorRecord be undefined. 655 // Step 3.j. If iteratorRecord is not undefined, then ... 656 if (usingAsyncIterator !== undefined || usingSyncIterator !== undefined) { 657 // Note: The published spec as of f6acfc4f0277e625f13fd22068138aec61a12df3 658 // is incorrect. See https://github.com/tc39/proposal-array-from-async/issues/33 659 // Here we use the implementation provided by @bakkot in that bug 660 // in lieu for now; This allows to use a for-await loop below. 661 662 // Steps 3.h-i are implicit through the for-await loop. 663 664 // Step 3.h. If usingAsyncIterator is not undefined, then 665 // Step 3.h.i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator). 666 // Step 3.i. Else if usingSyncIterator is not undefined, then 667 // Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)). 668 669 // https://github.com/tc39/proposal-array-from-async/pull/41 670 // Step 3.e. If IsConstructor(C) is true, then 671 // Step 3.e.i. Let A be ? Construct(C). 672 // Step 3.f. Else, 673 // Step 3.f.i. Let A be ! ArrayCreate(0). 674 var A = IsConstructor(C) ? constructContentFunction(C, C) : []; 675 676 // Step 3.j.i. Let k be 0. 677 var k = 0; 678 679 // Step 3.j.ii. Repeat, 680 for await (var nextValue of allowContentIterWith( 681 asyncItems, 682 usingAsyncIterator, 683 usingSyncIterator 684 )) { 685 // Following in the steps of Array.from, we don't actually implement 3.j.ii.1. 686 // The comment in Array.from also applies here; we should only encounter this 687 // after a huge loop around a proxy 688 // Step 3.j.ii.1. If k ≥ 2**53 - 1, then 689 // Step 3.j.ii.1.a. Let error be ThrowCompletion(a newly created TypeError object). 690 // Step 3.j.ii.1.b. Return ? AsyncIteratorClose(iteratorRecord, error). 691 // Step 3.j.ii.2. Let Pk be ! ToString(𝔽(k)). 692 693 // Step 3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)). 694 695 // Step 3.j.ii.5. Let nextValue be ? IteratorValue(next). (Implicit through the for-await loop). 696 697 // Step 3.j.ii.7. Else, let mappedValue be nextValue. (Reordered) 698 var mappedValue = nextValue; 699 700 // Step 3.j.ii.6. If mapping is true, then 701 if (mapping) { 702 // Step 3.j.ii.6.a. Let mappedValue be Call(mapfn, thisArg, « nextValue, 𝔽(k) »). 703 // Step 3.j.ii.6.b. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord). 704 // Abrupt completion will be handled by the for-await loop. 705 mappedValue = callContentFunction(mapfn, thisArg, nextValue, k); 706 707 // Step 3.j.ii.6.c. Set mappedValue to Await(mappedValue). 708 // Step 3.j.ii.6.d. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord). 709 mappedValue = await mappedValue; 710 } 711 712 // Step 3.j.ii.8. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue). 713 // Step 3.j.ii.9. If defineStatus is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, defineStatus). 714 DefineDataProperty(A, k, mappedValue); 715 716 // Step 3.j.ii.10. Set k to k + 1. 717 k = k + 1; 718 } 719 720 // Step 3.j.ii.4. If next is false, then (Reordered) 721 722 // Step 3.j.ii.4.a. Perform ? Set(A, "length", 𝔽(k), true). 723 A.length = k; 724 725 // Step 3.j.ii.4.b. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }. 726 return A; 727 } 728 729 // Step 3.k. Else, 730 731 // Step 3.k.i. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object. 732 // Step 3.k.ii. Let arrayLike be ! ToObject(asyncItems). 733 var arrayLike = ToObject(asyncItems); 734 735 // Step 3.k.iii. Let len be ? LengthOfArrayLike(arrayLike). 736 var len = ToLength(arrayLike.length); 737 738 // Step 3.k.iv. If IsConstructor(C) is true, then 739 // Step 3.k.iv.1. Let A be ? Construct(C, « 𝔽(len) »). 740 // Step 3.k.v. Else, 741 // Step 3.k.v.1. Let A be ? ArrayCreate(len). 742 var A = IsConstructor(C) ? constructContentFunction(C, C, len) : std_Array(len); 743 744 // Step 3.k.vi. Let k be 0. 745 var k = 0; 746 747 // Step 3.k.vii. Repeat, while k < len, 748 while (k < len) { 749 // Step 3.k.vii.1. Let Pk be ! ToString(𝔽(k)). 750 // Step 3.k.vii.2. Let kValue be ? Get(arrayLike, Pk). 751 // Step 3.k.vii.3. Let kValue be ? Await(kValue). 752 var kValue = await arrayLike[k]; 753 754 // Step 3.k.vii.4. If mapping is true, then 755 // Step 3.k.vii.4.a. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽(k) »). 756 // Step 3.k.vii.4.b. Let mappedValue be ? Await(mappedValue). 757 // Step 3.k.vii.5. Else, let mappedValue be kValue. 758 var mappedValue = mapping 759 ? await callContentFunction(mapfn, thisArg, kValue, k) 760 : kValue; 761 762 // Step 3.k.vii.6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). 763 DefineDataProperty(A, k, mappedValue); 764 765 // Step 3.k.vii.7. Set k to k + 1. 766 k = k + 1; 767 } 768 769 // Step 3.k.viii. Perform ? Set(A, "length", 𝔽(len), true). 770 A.length = len; 771 772 // Step 3.k.ix. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }. 773 return A; 774 }; 775 776 // Step 4. Perform AsyncFunctionStart(promiseCapability, fromAsyncClosure). 777 // Step 5. Return promiseCapability.[[Promise]]. 778 return fromAsyncClosure(); 779 } 780 781 // ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1 782 function ArrayFrom(items, mapfn = undefined, thisArg = undefined) { 783 // Step 1. 784 var C = this; 785 786 // Steps 2-3. 787 var mapping = mapfn !== undefined; 788 if (mapping && !IsCallable(mapfn)) { 789 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn)); 790 } 791 var T = thisArg; 792 793 // Step 4. 794 // Inlined: GetMethod, steps 1-2. 795 var usingIterator = items[GetBuiltinSymbol("iterator")]; 796 797 // Step 5. 798 // Inlined: GetMethod, step 3. 799 if (!IsNullOrUndefined(usingIterator)) { 800 // Inlined: GetMethod, step 4. 801 if (!IsCallable(usingIterator)) { 802 ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, items)); 803 } 804 805 // Steps 5.a-b. 806 var A = IsConstructor(C) ? constructContentFunction(C, C) : []; 807 808 // Step 5.d. 809 var k = 0; 810 811 // Steps 5.c, 5.e 812 for (var nextValue of allowContentIterWith(items, usingIterator)) { 813 // Step 5.e.i. 814 // Disabled for performance reason. We won't hit this case on 815 // normal array, since DefineDataProperty will throw before it. 816 // We could hit this when |A| is a proxy and it ignores 817 // |DefineDataProperty|, but it happens only after too long loop. 818 /* 819 if (k >= 0x1fffffffffffff) { 820 ThrowTypeError(JSMSG_TOO_LONG_ARRAY); 821 } 822 */ 823 824 // Steps 5.e.vi-vii. 825 var mappedValue = mapping 826 ? callContentFunction(mapfn, T, nextValue, k) 827 : nextValue; 828 829 // Steps 5.e.ii (reordered), 5.e.viii. 830 DefineDataProperty(A, k++, mappedValue); 831 } 832 833 // Step 5.e.iv. 834 A.length = k; 835 return A; 836 } 837 838 // Step 7 is an assertion: items is not an Iterator. Testing this is 839 // literally the very last thing we did, so we don't assert here. 840 841 // Steps 8-9. 842 var arrayLike = ToObject(items); 843 844 // Steps 10-11. 845 var len = ToLength(arrayLike.length); 846 847 // Steps 12-14. 848 var A = IsConstructor(C) 849 ? constructContentFunction(C, C, len) 850 : std_Array(len); 851 852 // Steps 15-16. 853 for (var k = 0; k < len; k++) { 854 // Steps 16.a-c. 855 var kValue = items[k]; 856 857 // Steps 16.d-e. 858 var mappedValue = mapping 859 ? callContentFunction(mapfn, T, kValue, k) 860 : kValue; 861 862 // Steps 16.f-g. 863 DefineDataProperty(A, k, mappedValue); 864 } 865 866 // Steps 17-18. 867 A.length = len; 868 869 // Step 19. 870 return A; 871 } 872 873 // ES2015 22.1.3.27 Array.prototype.toString. 874 function ArrayToString() { 875 // Steps 1-2. 876 var array = ToObject(this); 877 878 // Steps 3-4. 879 var func = array.join; 880 881 // Steps 5-6. 882 if (!IsCallable(func)) { 883 return callFunction(std_Object_toString, array); 884 } 885 return callContentFunction(func, array); 886 } 887 888 // ES2017 draft rev f8a9be8ea4bd97237d176907a1e3080dce20c68f 889 // 22.1.3.27 Array.prototype.toLocaleString ([ reserved1 [ , reserved2 ] ]) 890 // ES2017 Intl draft rev 78bbe7d1095f5ff3760ac4017ed366026e4cb276 891 // 13.4.1 Array.prototype.toLocaleString ([ locales [ , options ]]) 892 function ArrayToLocaleString(locales, options) { 893 // Step 1 (ToObject already performed in native code). 894 assert(IsObject(this), "|this| should be an object"); 895 var array = this; 896 897 // Step 2. 898 var len = ToLength(array.length); 899 900 // Step 4. 901 if (len === 0) { 902 return ""; 903 } 904 905 // Step 5. 906 var firstElement = array[0]; 907 908 // Steps 6-7. 909 var R; 910 if (IsNullOrUndefined(firstElement)) { 911 R = ""; 912 } else { 913 #if JS_HAS_INTL_API 914 R = ToString( 915 callContentFunction( 916 firstElement.toLocaleString, 917 firstElement, 918 locales, 919 options 920 ) 921 ); 922 #else 923 R = ToString( 924 callContentFunction(firstElement.toLocaleString, firstElement) 925 ); 926 #endif 927 } 928 929 // Step 3 (reordered). 930 // We don't (yet?) implement locale-dependent separators. 931 var separator = ","; 932 933 // Steps 8-9. 934 for (var k = 1; k < len; k++) { 935 // Step 9.b. 936 var nextElement = array[k]; 937 938 // Steps 9.a, 9.c-e. 939 R += separator; 940 if (!IsNullOrUndefined(nextElement)) { 941 #if JS_HAS_INTL_API 942 R += ToString( 943 callContentFunction( 944 nextElement.toLocaleString, 945 nextElement, 946 locales, 947 options 948 ) 949 ); 950 #else 951 R += ToString( 952 callContentFunction(nextElement.toLocaleString, nextElement) 953 ); 954 #endif 955 } 956 } 957 958 // Step 10. 959 return R; 960 } 961 962 // ES 2016 draft Mar 25, 2016 22.1.2.5. 963 function $ArraySpecies() { 964 // Step 1. 965 return this; 966 } 967 SetCanonicalName($ArraySpecies, "get [Symbol.species]"); 968 969 // ES 2016 draft Mar 25, 2016 9.4.2.3. 970 function ArraySpeciesCreate(originalArray, length) { 971 // Step 1. 972 assert(typeof length === "number", "length should be a number"); 973 assert(length >= 0, "length should be a non-negative number"); 974 975 // Step 2. 976 // eslint-disable-next-line no-compare-neg-zero 977 if (length === -0) { 978 length = 0; 979 } 980 981 // Step 4, 6. 982 if (!IsArray(originalArray)) { 983 return std_Array(length); 984 } 985 986 // Step 5.a. 987 var originalConstructor = originalArray.constructor; 988 var C = originalConstructor; 989 990 // Step 5.b. 991 if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) { 992 return std_Array(length); 993 } 994 995 // Step 5.c. 996 if (IsObject(C)) { 997 // Step 5.c.i. 998 C = C[GetBuiltinSymbol("species")]; 999 1000 // Optimized path for an ordinary Array. 1001 if (C === GetBuiltinConstructor("Array")) { 1002 return std_Array(length); 1003 } 1004 1005 // Step 5.c.ii. 1006 if (C === null) { 1007 return std_Array(length); 1008 } 1009 1010 } 1011 1012 // Step 6. 1013 if (C === undefined) { 1014 return std_Array(length); 1015 } 1016 1017 // Step 7. 1018 if (!IsConstructor(C)) { 1019 ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, "constructor property"); 1020 } 1021 1022 // Step 8. 1023 return constructContentFunction(C, C, length); 1024 } 1025 1026 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 1027 // 22.1.3.11 Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) 1028 function ArrayFlatMap(mapperFunction /*, thisArg*/) { 1029 // Step 1. 1030 var O = ToObject(this); 1031 1032 // Step 2. 1033 var sourceLen = ToLength(O.length); 1034 1035 // Step 3. 1036 if (!IsCallable(mapperFunction)) { 1037 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); 1038 } 1039 1040 // Step 4. 1041 var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 1042 1043 // Step 5. 1044 var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0); 1045 1046 // Step 6. 1047 FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T); 1048 1049 // Step 7. 1050 return A; 1051 } 1052 1053 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 1054 // 22.1.3.10 Array.prototype.flat ( [ depth ] ) 1055 function ArrayFlat(/* depth */) { 1056 // Step 1. 1057 var O = ToObject(this); 1058 1059 // Step 2. 1060 var sourceLen = ToLength(O.length); 1061 1062 // Step 3. 1063 var depthNum = 1; 1064 1065 // Step 4. 1066 if (ArgumentsLength() && GetArgument(0) !== undefined) { 1067 depthNum = ToInteger(GetArgument(0)); 1068 } 1069 1070 // Step 5. 1071 var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0); 1072 1073 // Step 6. 1074 FlattenIntoArray(A, O, sourceLen, 0, depthNum); 1075 1076 // Step 7. 1077 return A; 1078 } 1079 1080 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 1081 // 22.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] ) 1082 function FlattenIntoArray( 1083 target, 1084 source, 1085 sourceLen, 1086 start, 1087 depth, 1088 mapperFunction, 1089 thisArg 1090 ) { 1091 // Step 1. 1092 var targetIndex = start; 1093 1094 // Steps 2-3. 1095 for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { 1096 // Steps 3.a-c. 1097 if (sourceIndex in source) { 1098 // Step 3.c.i. 1099 var element = source[sourceIndex]; 1100 1101 if (mapperFunction) { 1102 // Step 3.c.ii.1. 1103 assert(ArgumentsLength() === 7, "thisArg is present"); 1104 1105 // Step 3.c.ii.2. 1106 element = callContentFunction( 1107 mapperFunction, 1108 thisArg, 1109 element, 1110 sourceIndex, 1111 source 1112 ); 1113 } 1114 1115 // Step 3.c.iii. 1116 var shouldFlatten = false; 1117 1118 // Step 3.c.iv. 1119 if (depth > 0) { 1120 // Step 3.c.iv.1. 1121 shouldFlatten = IsArray(element); 1122 } 1123 1124 // Step 3.c.v. 1125 if (shouldFlatten) { 1126 // Step 3.c.v.1. 1127 var elementLen = ToLength(element.length); 1128 1129 // Step 3.c.v.2. 1130 targetIndex = FlattenIntoArray( 1131 target, 1132 element, 1133 elementLen, 1134 targetIndex, 1135 depth - 1 1136 ); 1137 } else { 1138 // Step 3.c.vi.1. 1139 if (targetIndex >= MAX_NUMERIC_INDEX) { 1140 ThrowTypeError(JSMSG_TOO_LONG_ARRAY); 1141 } 1142 1143 // Step 3.c.vi.2. 1144 DefineDataProperty(target, targetIndex, element); 1145 1146 // Step 3.c.vi.3. 1147 targetIndex++; 1148 } 1149 } 1150 } 1151 1152 // Step 4. 1153 return targetIndex; 1154 } 1155 1156 // https://github.com/tc39/proposal-relative-indexing-method 1157 // Array.prototype.at ( index ) 1158 function ArrayAt(index) { 1159 // Step 1. 1160 var O = ToObject(this); 1161 1162 // Step 2. 1163 var len = ToLength(O.length); 1164 1165 // Step 3. 1166 var relativeIndex = ToInteger(index); 1167 1168 // Steps 4-5. 1169 var k; 1170 if (relativeIndex >= 0) { 1171 k = relativeIndex; 1172 } else { 1173 k = len + relativeIndex; 1174 } 1175 1176 // Step 6. 1177 if (k < 0 || k >= len) { 1178 return undefined; 1179 } 1180 1181 // Step 7. 1182 return O[k]; 1183 } 1184 // This function is only barely too long for normal inlining. 1185 SetIsInlinableLargeFunction(ArrayAt); 1186 1187 // https://github.com/tc39/proposal-change-array-by-copy 1188 // Array.prototype.toReversed() 1189 function ArrayToReversed() { 1190 // Step 1. Let O be ? ToObject(this value). 1191 var O = ToObject(this); 1192 1193 // Step 2. Let len be ? LengthOfArrayLike(O). 1194 var len = ToLength(O.length); 1195 1196 // Step 3. Let A be ArrayCreate(𝔽(len)). 1197 var A = std_Array(len); 1198 1199 // Step 4. Let k be 0. 1200 // Step 5. Repeat, while k < len, 1201 for (var k = 0; k < len; k++) { 1202 // Step 5.a. Let from be ! ToString(𝔽(len - k - 1)). 1203 var from = len - k - 1; 1204 1205 // Skip Step 5.b. Let Pk be ToString(𝔽(k)). 1206 // k is coerced into a string through the property access. 1207 1208 // Step 5.c. Let fromValue be ? Get(O, from). 1209 var fromValue = O[from]; 1210 1211 // Step 5.d. Perform ! CreateDataPropertyOrThrow(A, 𝔽(k), fromValue). 1212 DefineDataProperty(A, k, fromValue); 1213 } 1214 1215 // Step 6. Return A. 1216 return A; 1217 } 1218 1219 // https://github.com/tc39/proposal-change-array-by-copy 1220 // Array.prototype.toSorted() 1221 function ArrayToSorted(comparefn) { 1222 // Step 1. If comparefn is not undefined and IsCallable(comparefn) is 1223 // false, throw a TypeError exception. 1224 if (comparefn !== undefined && !IsCallable(comparefn)) { 1225 ThrowTypeError(JSMSG_BAD_TOSORTED_ARG); 1226 } 1227 1228 // Step 2. Let O be ? ToObject(this value). 1229 var O = ToObject(this); 1230 1231 // Step 3. Let len be ? LengthOfArrayLike(O). 1232 var len = ToLength(O.length); 1233 1234 // Step 4. Let A be ? ArrayCreate(𝔽(len)). 1235 var items = std_Array(len); 1236 1237 // We depart from steps 5-8 of the spec for performance reasons, as 1238 // following the spec would require copying the input array twice. 1239 // Instead, we create a new array that replaces holes with undefined, 1240 // and sort this array. 1241 for (var k = 0; k < len; k++) { 1242 DefineDataProperty(items, k, O[k]); 1243 } 1244 1245 // Arrays with less than two elements remain unchanged when sorted. 1246 if (len <= 1) { 1247 return items; 1248 } 1249 1250 // Steps 5-9. 1251 return callFunction(std_Array_sort, items, comparefn); 1252 } 1253 1254 // https://github.com/tc39/proposal-array-find-from-last 1255 // Array.prototype.findLast ( predicate, thisArg ) 1256 function ArrayFindLast(predicate /*, thisArg*/) { 1257 // Step 1. 1258 var O = ToObject(this); 1259 1260 // Step 2. 1261 var len = ToLength(O.length); 1262 1263 // Step 3. 1264 if (ArgumentsLength() === 0) { 1265 ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLast"); 1266 } 1267 if (!IsCallable(predicate)) { 1268 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 1269 } 1270 1271 var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 1272 1273 // Steps 4-5. 1274 for (var k = len - 1; k >= 0; k--) { 1275 // Steps 5.a-b. 1276 var kValue = O[k]; 1277 1278 // Steps 5.c-d. 1279 if (callContentFunction(predicate, thisArg, kValue, k, O)) { 1280 return kValue; 1281 } 1282 } 1283 1284 // Step 6. 1285 return undefined; 1286 } 1287 // Inlining this enables inlining of the callback function. 1288 SetIsInlinableLargeFunction(ArrayFindLast); 1289 1290 // https://github.com/tc39/proposal-array-find-from-last 1291 // Array.prototype.findLastIndex ( predicate, thisArg ) 1292 function ArrayFindLastIndex(predicate /*, thisArg*/) { 1293 // Step 1. 1294 var O = ToObject(this); 1295 1296 // Steps 2. 1297 var len = ToLength(O.length); 1298 1299 // Step 3. 1300 if (ArgumentsLength() === 0) { 1301 ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.findLastIndex"); 1302 } 1303 if (!IsCallable(predicate)) { 1304 ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); 1305 } 1306 1307 var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined; 1308 1309 // Steps 4-5. 1310 for (var k = len - 1; k >= 0; k--) { 1311 // Steps 5.a-d. 1312 if (callContentFunction(predicate, thisArg, O[k], k, O)) { 1313 return k; 1314 } 1315 } 1316 1317 // Step 6. 1318 return -1; 1319 } 1320 // Inlining this enables inlining of the callback function. 1321 SetIsInlinableLargeFunction(ArrayFindLastIndex);