1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5(function(global, utils, extrasUtils) { 6 7"use strict"; 8 9%CheckIsBootstrapping(); 10 11// ------------------------------------------------------------------- 12// Imports 13 14var GetIterator; 15var GetMethod; 16var GlobalArray = global.Array; 17var InternalArray = utils.InternalArray; 18var InternalPackedArray = utils.InternalPackedArray; 19var MaxSimple; 20var MinSimple; 21var ObjectHasOwnProperty; 22var ObjectToString = utils.ImportNow("object_to_string"); 23var iteratorSymbol = utils.ImportNow("iterator_symbol"); 24var unscopablesSymbol = utils.ImportNow("unscopables_symbol"); 25 26utils.Import(function(from) { 27 GetIterator = from.GetIterator; 28 GetMethod = from.GetMethod; 29 MaxSimple = from.MaxSimple; 30 MinSimple = from.MinSimple; 31 ObjectHasOwnProperty = from.ObjectHasOwnProperty; 32}); 33 34// ------------------------------------------------------------------- 35 36 37function ArraySpeciesCreate(array, length) { 38 length = INVERT_NEG_ZERO(length); 39 var constructor = %ArraySpeciesConstructor(array); 40 return new constructor(length); 41} 42 43 44function KeySortCompare(a, b) { 45 return a - b; 46} 47 48function GetSortedArrayKeys(array, indices) { 49 if (IS_NUMBER(indices)) { 50 // It's an interval 51 var limit = indices; 52 var keys = new InternalArray(); 53 for (var i = 0; i < limit; ++i) { 54 var e = array[i]; 55 if (!IS_UNDEFINED(e) || i in array) { 56 keys.push(i); 57 } 58 } 59 return keys; 60 } 61 return InnerArraySort(indices, indices.length, KeySortCompare); 62} 63 64 65function SparseJoinWithSeparatorJS(array, keys, length, use_locale, separator) { 66 var keys_length = keys.length; 67 var elements = new InternalArray(keys_length * 2); 68 for (var i = 0; i < keys_length; i++) { 69 var key = keys[i]; 70 elements[i * 2] = key; 71 elements[i * 2 + 1] = ConvertToString(use_locale, array[key]); 72 } 73 return %SparseJoinWithSeparator(elements, length, separator); 74} 75 76 77// Optimized for sparse arrays if separator is ''. 78function SparseJoin(array, keys, use_locale) { 79 var keys_length = keys.length; 80 var elements = new InternalArray(keys_length); 81 for (var i = 0; i < keys_length; i++) { 82 elements[i] = ConvertToString(use_locale, array[keys[i]]); 83 } 84 return %StringBuilderConcat(elements, keys_length, ''); 85} 86 87 88function UseSparseVariant(array, length, is_array, touched) { 89 // Only use the sparse variant on arrays that are likely to be sparse and the 90 // number of elements touched in the operation is relatively small compared to 91 // the overall size of the array. 92 if (!is_array || length < 1000 || %HasComplexElements(array)) { 93 return false; 94 } 95 if (!%_IsSmi(length)) { 96 return true; 97 } 98 var elements_threshold = length >> 2; // No more than 75% holes 99 var estimated_elements = %EstimateNumberOfElements(array); 100 return (estimated_elements < elements_threshold) && 101 (touched > estimated_elements * 4); 102} 103 104function Stack() { 105 this.length = 0; 106 this.values = new InternalArray(); 107} 108 109// Predeclare the instance variables on the prototype. Otherwise setting them in 110// the constructor will leak the instance through settings on Object.prototype. 111Stack.prototype.length = null; 112Stack.prototype.values = null; 113 114function StackPush(stack, value) { 115 stack.values[stack.length++] = value; 116} 117 118function StackPop(stack) { 119 stack.values[--stack.length] = null 120} 121 122function StackHas(stack, v) { 123 var length = stack.length; 124 var values = stack.values; 125 for (var i = 0; i < length; i++) { 126 if (values[i] === v) return true; 127 } 128 return false; 129} 130 131// Global list of arrays visited during toString, toLocaleString and 132// join invocations. 133var visited_arrays = new Stack(); 134 135function DoJoin(array, length, is_array, separator, use_locale) { 136 if (UseSparseVariant(array, length, is_array, length)) { 137 %NormalizeElements(array); 138 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length)); 139 if (separator === '') { 140 if (keys.length === 0) return ''; 141 return SparseJoin(array, keys, use_locale); 142 } else { 143 return SparseJoinWithSeparatorJS( 144 array, keys, length, use_locale, separator); 145 } 146 } 147 148 // Fast case for one-element arrays. 149 if (length === 1) { 150 return ConvertToString(use_locale, array[0]); 151 } 152 153 // Construct an array for the elements. 154 var elements = new InternalArray(length); 155 for (var i = 0; i < length; i++) { 156 elements[i] = ConvertToString(use_locale, array[i]); 157 } 158 159 if (separator === '') { 160 return %StringBuilderConcat(elements, length, ''); 161 } else { 162 return %StringBuilderJoin(elements, length, separator); 163 } 164} 165 166function Join(array, length, separator, use_locale) { 167 if (length === 0) return ''; 168 169 var is_array = IS_ARRAY(array); 170 171 if (is_array) { 172 // If the array is cyclic, return the empty string for already 173 // visited arrays. 174 if (StackHas(visited_arrays, array)) return ''; 175 StackPush(visited_arrays, array); 176 } 177 178 // Attempt to convert the elements. 179 try { 180 return DoJoin(array, length, is_array, separator, use_locale); 181 } finally { 182 // Make sure to remove the last element of the visited array no 183 // matter what happens. 184 if (is_array) StackPop(visited_arrays); 185 } 186} 187 188 189function ConvertToString(use_locale, x) { 190 if (IS_NULL_OR_UNDEFINED(x)) return ''; 191 return TO_STRING(use_locale ? x.toLocaleString() : x); 192} 193 194 195// This function implements the optimized splice implementation that can use 196// special array operations to handle sparse arrays in a sensible fashion. 197function SparseSlice(array, start_i, del_count, len, deleted_elements) { 198 // Move deleted elements to a new array (the return value from splice). 199 var indices = %GetArrayKeys(array, start_i + del_count); 200 if (IS_NUMBER(indices)) { 201 var limit = indices; 202 for (var i = start_i; i < limit; ++i) { 203 var current = array[i]; 204 if (!IS_UNDEFINED(current) || i in array) { 205 %CreateDataProperty(deleted_elements, i - start_i, current); 206 } 207 } 208 } else { 209 var length = indices.length; 210 for (var k = 0; k < length; ++k) { 211 var key = indices[k]; 212 if (key >= start_i) { 213 var current = array[key]; 214 if (!IS_UNDEFINED(current) || key in array) { 215 %CreateDataProperty(deleted_elements, key - start_i, current); 216 } 217 } 218 } 219 } 220} 221 222 223// This function implements the optimized splice implementation that can use 224// special array operations to handle sparse arrays in a sensible fashion. 225function SparseMove(array, start_i, del_count, len, num_additional_args) { 226 // Bail out if no moving is necessary. 227 if (num_additional_args === del_count) return; 228 // Move data to new array. 229 var new_array = new InternalArray( 230 // Clamp array length to 2^32-1 to avoid early RangeError. 231 MinSimple(len - del_count + num_additional_args, 0xffffffff)); 232 var big_indices; 233 var indices = %GetArrayKeys(array, len); 234 if (IS_NUMBER(indices)) { 235 var limit = indices; 236 for (var i = 0; i < start_i && i < limit; ++i) { 237 var current = array[i]; 238 if (!IS_UNDEFINED(current) || i in array) { 239 new_array[i] = current; 240 } 241 } 242 for (var i = start_i + del_count; i < limit; ++i) { 243 var current = array[i]; 244 if (!IS_UNDEFINED(current) || i in array) { 245 new_array[i - del_count + num_additional_args] = current; 246 } 247 } 248 } else { 249 var length = indices.length; 250 for (var k = 0; k < length; ++k) { 251 var key = indices[k]; 252 if (key < start_i) { 253 var current = array[key]; 254 if (!IS_UNDEFINED(current) || key in array) { 255 new_array[key] = current; 256 } 257 } else if (key >= start_i + del_count) { 258 var current = array[key]; 259 if (!IS_UNDEFINED(current) || key in array) { 260 var new_key = key - del_count + num_additional_args; 261 new_array[new_key] = current; 262 if (new_key > 0xfffffffe) { 263 big_indices = big_indices || new InternalArray(); 264 big_indices.push(new_key); 265 } 266 } 267 } 268 } 269 } 270 // Move contents of new_array into this array 271 %MoveArrayContents(new_array, array); 272 // Add any moved values that aren't elements anymore. 273 if (!IS_UNDEFINED(big_indices)) { 274 var length = big_indices.length; 275 for (var i = 0; i < length; ++i) { 276 var key = big_indices[i]; 277 array[key] = new_array[key]; 278 } 279 } 280} 281 282 283// This is part of the old simple-minded splice. We are using it either 284// because the receiver is not an array (so we have no choice) or because we 285// know we are not deleting or moving a lot of elements. 286function SimpleSlice(array, start_i, del_count, len, deleted_elements) { 287 for (var i = 0; i < del_count; i++) { 288 var index = start_i + i; 289 if (index in array) { 290 var current = array[index]; 291 %CreateDataProperty(deleted_elements, i, current); 292 } 293 } 294} 295 296 297function SimpleMove(array, start_i, del_count, len, num_additional_args) { 298 if (num_additional_args !== del_count) { 299 // Move the existing elements after the elements to be deleted 300 // to the right position in the resulting array. 301 if (num_additional_args > del_count) { 302 for (var i = len - del_count; i > start_i; i--) { 303 var from_index = i + del_count - 1; 304 var to_index = i + num_additional_args - 1; 305 if (from_index in array) { 306 array[to_index] = array[from_index]; 307 } else { 308 delete array[to_index]; 309 } 310 } 311 } else { 312 for (var i = start_i; i < len - del_count; i++) { 313 var from_index = i + del_count; 314 var to_index = i + num_additional_args; 315 if (from_index in array) { 316 array[to_index] = array[from_index]; 317 } else { 318 delete array[to_index]; 319 } 320 } 321 for (var i = len; i > len - del_count + num_additional_args; i--) { 322 delete array[i - 1]; 323 } 324 } 325 } 326} 327 328 329// ------------------------------------------------------------------- 330 331 332function ArrayToString() { 333 var array; 334 var func; 335 if (IS_ARRAY(this)) { 336 func = this.join; 337 if (func === ArrayJoin) { 338 return Join(this, this.length, ',', false); 339 } 340 array = this; 341 } else { 342 array = TO_OBJECT(this); 343 func = array.join; 344 } 345 if (!IS_CALLABLE(func)) { 346 return %_Call(ObjectToString, array); 347 } 348 return %_Call(func, array); 349} 350 351 352function InnerArrayToLocaleString(array, length) { 353 return Join(array, TO_LENGTH(length), ',', true); 354} 355 356 357function ArrayToLocaleString() { 358 var array = TO_OBJECT(this); 359 var arrayLen = array.length; 360 return InnerArrayToLocaleString(array, arrayLen); 361} 362 363 364function InnerArrayJoin(separator, array, length) { 365 if (IS_UNDEFINED(separator)) { 366 separator = ','; 367 } else { 368 separator = TO_STRING(separator); 369 } 370 371 // Fast case for one-element arrays. 372 if (length === 1) { 373 var e = array[0]; 374 if (IS_NULL_OR_UNDEFINED(e)) return ''; 375 return TO_STRING(e); 376 } 377 378 return Join(array, length, separator, false); 379} 380 381 382function ArrayJoin(separator) { 383 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join"); 384 385 var array = TO_OBJECT(this); 386 var length = TO_LENGTH(array.length); 387 388 return InnerArrayJoin(separator, array, length); 389} 390 391 392// Removes the last element from the array and returns it. See 393// ECMA-262, section 15.4.4.6. 394function ArrayPop() { 395 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop"); 396 397 var array = TO_OBJECT(this); 398 var n = TO_LENGTH(array.length); 399 if (n == 0) { 400 array.length = n; 401 return; 402 } 403 404 n--; 405 var value = array[n]; 406 %DeleteProperty_Strict(array, n); 407 array.length = n; 408 return value; 409} 410 411 412// Appends the arguments to the end of the array and returns the new 413// length of the array. See ECMA-262, section 15.4.4.7. 414function ArrayPush() { 415 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push"); 416 417 var array = TO_OBJECT(this); 418 var n = TO_LENGTH(array.length); 419 var m = arguments.length; 420 421 // Subtract n from kMaxSafeInteger rather than testing m + n > 422 // kMaxSafeInteger. n may already be kMaxSafeInteger. In that case adding 423 // e.g., 1 would not be safe. 424 if (m > kMaxSafeInteger - n) throw %make_type_error(kPushPastSafeLength, m, n); 425 426 for (var i = 0; i < m; i++) { 427 array[i+n] = arguments[i]; 428 } 429 430 var new_length = n + m; 431 array.length = new_length; 432 return new_length; 433} 434 435 436// For implementing reverse() on large, sparse arrays. 437function SparseReverse(array, len) { 438 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); 439 var high_counter = keys.length - 1; 440 var low_counter = 0; 441 while (low_counter <= high_counter) { 442 var i = keys[low_counter]; 443 var j = keys[high_counter]; 444 445 var j_complement = len - j - 1; 446 var low, high; 447 448 if (j_complement <= i) { 449 high = j; 450 while (keys[--high_counter] == j) { } 451 low = j_complement; 452 } 453 if (j_complement >= i) { 454 low = i; 455 while (keys[++low_counter] == i) { } 456 high = len - i - 1; 457 } 458 459 var current_i = array[low]; 460 if (!IS_UNDEFINED(current_i) || low in array) { 461 var current_j = array[high]; 462 if (!IS_UNDEFINED(current_j) || high in array) { 463 array[low] = current_j; 464 array[high] = current_i; 465 } else { 466 array[high] = current_i; 467 delete array[low]; 468 } 469 } else { 470 var current_j = array[high]; 471 if (!IS_UNDEFINED(current_j) || high in array) { 472 array[low] = current_j; 473 delete array[high]; 474 } 475 } 476 } 477} 478 479function PackedArrayReverse(array, len) { 480 var j = len - 1; 481 for (var i = 0; i < j; i++, j--) { 482 var current_i = array[i]; 483 var current_j = array[j]; 484 array[i] = current_j; 485 array[j] = current_i; 486 } 487 return array; 488} 489 490 491function GenericArrayReverse(array, len) { 492 var j = len - 1; 493 for (var i = 0; i < j; i++, j--) { 494 if (i in array) { 495 var current_i = array[i]; 496 if (j in array) { 497 var current_j = array[j]; 498 array[i] = current_j; 499 array[j] = current_i; 500 } else { 501 array[j] = current_i; 502 delete array[i]; 503 } 504 } else { 505 if (j in array) { 506 var current_j = array[j]; 507 array[i] = current_j; 508 delete array[j]; 509 } 510 } 511 } 512 return array; 513} 514 515 516function ArrayReverse() { 517 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse"); 518 519 var array = TO_OBJECT(this); 520 var len = TO_LENGTH(array.length); 521 var isArray = IS_ARRAY(array); 522 523 if (UseSparseVariant(array, len, isArray, len)) { 524 %NormalizeElements(array); 525 SparseReverse(array, len); 526 return array; 527 } else if (isArray && %_HasFastPackedElements(array)) { 528 return PackedArrayReverse(array, len); 529 } else { 530 return GenericArrayReverse(array, len); 531 } 532} 533 534 535function ArrayShift() { 536 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift"); 537 538 var array = TO_OBJECT(this); 539 var len = TO_LENGTH(array.length); 540 541 if (len === 0) { 542 array.length = 0; 543 return; 544 } 545 546 if (%object_is_sealed(array)) throw %make_type_error(kArrayFunctionsOnSealed); 547 548 var first = array[0]; 549 550 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) { 551 SparseMove(array, 0, 1, len, 0); 552 } else { 553 SimpleMove(array, 0, 1, len, 0); 554 } 555 556 array.length = len - 1; 557 558 return first; 559} 560 561 562function ArrayUnshift(arg1) { // length == 1 563 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); 564 565 var array = TO_OBJECT(this); 566 var len = TO_LENGTH(array.length); 567 var num_arguments = arguments.length; 568 569 if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) && 570 !%object_is_sealed(array)) { 571 SparseMove(array, 0, 0, len, num_arguments); 572 } else { 573 SimpleMove(array, 0, 0, len, num_arguments); 574 } 575 576 for (var i = 0; i < num_arguments; i++) { 577 array[i] = arguments[i]; 578 } 579 580 var new_length = len + num_arguments; 581 array.length = new_length; 582 return new_length; 583} 584 585 586function ArraySlice(start, end) { 587 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice"); 588 589 var array = TO_OBJECT(this); 590 var len = TO_LENGTH(array.length); 591 var start_i = TO_INTEGER(start); 592 var end_i = len; 593 594 if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end); 595 596 if (start_i < 0) { 597 start_i += len; 598 if (start_i < 0) start_i = 0; 599 } else { 600 if (start_i > len) start_i = len; 601 } 602 603 if (end_i < 0) { 604 end_i += len; 605 if (end_i < 0) end_i = 0; 606 } else { 607 if (end_i > len) end_i = len; 608 } 609 610 var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0)); 611 612 if (end_i < start_i) return result; 613 614 if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) { 615 %NormalizeElements(array); 616 if (IS_ARRAY(result)) %NormalizeElements(result); 617 SparseSlice(array, start_i, end_i - start_i, len, result); 618 } else { 619 SimpleSlice(array, start_i, end_i - start_i, len, result); 620 } 621 622 result.length = end_i - start_i; 623 624 return result; 625} 626 627 628function ComputeSpliceStartIndex(start_i, len) { 629 if (start_i < 0) { 630 start_i += len; 631 return start_i < 0 ? 0 : start_i; 632 } 633 634 return start_i > len ? len : start_i; 635} 636 637 638function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) { 639 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 640 // given as a request to delete all the elements from the start. 641 // And it differs from the case of undefined delete count. 642 // This does not follow ECMA-262, but we do the same for 643 // compatibility. 644 var del_count = 0; 645 if (num_arguments == 1) 646 return len - start_i; 647 648 del_count = TO_INTEGER(delete_count); 649 if (del_count < 0) 650 return 0; 651 652 if (del_count > len - start_i) 653 return len - start_i; 654 655 return del_count; 656} 657 658 659function ArraySplice(start, delete_count) { 660 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice"); 661 662 var num_arguments = arguments.length; 663 var array = TO_OBJECT(this); 664 var len = TO_LENGTH(array.length); 665 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); 666 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, 667 start_i); 668 var deleted_elements = ArraySpeciesCreate(array, del_count); 669 deleted_elements.length = del_count; 670 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; 671 672 if (del_count != num_elements_to_add && %object_is_sealed(array)) { 673 throw %make_type_error(kArrayFunctionsOnSealed); 674 } else if (del_count > 0 && %object_is_frozen(array)) { 675 throw %make_type_error(kArrayFunctionsOnFrozen); 676 } 677 678 var changed_elements = del_count; 679 if (num_elements_to_add != del_count) { 680 // If the slice needs to do a actually move elements after the insertion 681 // point, then include those in the estimate of changed elements. 682 changed_elements += len - start_i - del_count; 683 } 684 if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) { 685 %NormalizeElements(array); 686 if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements); 687 SparseSlice(array, start_i, del_count, len, deleted_elements); 688 SparseMove(array, start_i, del_count, len, num_elements_to_add); 689 } else { 690 SimpleSlice(array, start_i, del_count, len, deleted_elements); 691 SimpleMove(array, start_i, del_count, len, num_elements_to_add); 692 } 693 694 // Insert the arguments into the resulting array in 695 // place of the deleted elements. 696 var i = start_i; 697 var arguments_index = 2; 698 var arguments_length = arguments.length; 699 while (arguments_index < arguments_length) { 700 array[i++] = arguments[arguments_index++]; 701 } 702 array.length = len - del_count + num_elements_to_add; 703 704 // Return the deleted elements. 705 return deleted_elements; 706} 707 708 709function InnerArraySort(array, length, comparefn) { 710 // In-place QuickSort algorithm. 711 // For short (length <= 22) arrays, insertion sort is used for efficiency. 712 713 if (!IS_CALLABLE(comparefn)) { 714 comparefn = function (x, y) { 715 if (x === y) return 0; 716 if (%_IsSmi(x) && %_IsSmi(y)) { 717 return %SmiLexicographicCompare(x, y); 718 } 719 x = TO_STRING(x); 720 y = TO_STRING(y); 721 if (x == y) return 0; 722 else return x < y ? -1 : 1; 723 }; 724 } 725 function InsertionSort(a, from, to) { 726 for (var i = from + 1; i < to; i++) { 727 var element = a[i]; 728 for (var j = i - 1; j >= from; j--) { 729 var tmp = a[j]; 730 var order = comparefn(tmp, element); 731 if (order > 0) { 732 a[j + 1] = tmp; 733 } else { 734 break; 735 } 736 } 737 a[j + 1] = element; 738 } 739 }; 740 741 function GetThirdIndex(a, from, to) { 742 var t_array = new InternalArray(); 743 // Use both 'from' and 'to' to determine the pivot candidates. 744 var increment = 200 + ((to - from) & 15); 745 var j = 0; 746 from += 1; 747 to -= 1; 748 for (var i = from; i < to; i += increment) { 749 t_array[j] = [i, a[i]]; 750 j++; 751 } 752 t_array.sort(function(a, b) { 753 return comparefn(a[1], b[1]); 754 }); 755 var third_index = t_array[t_array.length >> 1][0]; 756 return third_index; 757 } 758 759 function QuickSort(a, from, to) { 760 var third_index = 0; 761 while (true) { 762 // Insertion sort is faster for short arrays. 763 if (to - from <= 10) { 764 InsertionSort(a, from, to); 765 return; 766 } 767 if (to - from > 1000) { 768 third_index = GetThirdIndex(a, from, to); 769 } else { 770 third_index = from + ((to - from) >> 1); 771 } 772 // Find a pivot as the median of first, last and middle element. 773 var v0 = a[from]; 774 var v1 = a[to - 1]; 775 var v2 = a[third_index]; 776 var c01 = comparefn(v0, v1); 777 if (c01 > 0) { 778 // v1 < v0, so swap them. 779 var tmp = v0; 780 v0 = v1; 781 v1 = tmp; 782 } // v0 <= v1. 783 var c02 = comparefn(v0, v2); 784 if (c02 >= 0) { 785 // v2 <= v0 <= v1. 786 var tmp = v0; 787 v0 = v2; 788 v2 = v1; 789 v1 = tmp; 790 } else { 791 // v0 <= v1 && v0 < v2 792 var c12 = comparefn(v1, v2); 793 if (c12 > 0) { 794 // v0 <= v2 < v1 795 var tmp = v1; 796 v1 = v2; 797 v2 = tmp; 798 } 799 } 800 // v0 <= v1 <= v2 801 a[from] = v0; 802 a[to - 1] = v2; 803 var pivot = v1; 804 var low_end = from + 1; // Upper bound of elements lower than pivot. 805 var high_start = to - 1; // Lower bound of elements greater than pivot. 806 a[third_index] = a[low_end]; 807 a[low_end] = pivot; 808 809 // From low_end to i are elements equal to pivot. 810 // From i to high_start are elements that haven't been compared yet. 811 partition: for (var i = low_end + 1; i < high_start; i++) { 812 var element = a[i]; 813 var order = comparefn(element, pivot); 814 if (order < 0) { 815 a[i] = a[low_end]; 816 a[low_end] = element; 817 low_end++; 818 } else if (order > 0) { 819 do { 820 high_start--; 821 if (high_start == i) break partition; 822 var top_elem = a[high_start]; 823 order = comparefn(top_elem, pivot); 824 } while (order > 0); 825 a[i] = a[high_start]; 826 a[high_start] = element; 827 if (order < 0) { 828 element = a[i]; 829 a[i] = a[low_end]; 830 a[low_end] = element; 831 low_end++; 832 } 833 } 834 } 835 if (to - high_start < low_end - from) { 836 QuickSort(a, high_start, to); 837 to = low_end; 838 } else { 839 QuickSort(a, from, low_end); 840 from = high_start; 841 } 842 } 843 }; 844 845 // Copy elements in the range 0..length from obj's prototype chain 846 // to obj itself, if obj has holes. Return one more than the maximal index 847 // of a prototype property. 848 function CopyFromPrototype(obj, length) { 849 var max = 0; 850 for (var proto = %object_get_prototype_of(obj); proto; 851 proto = %object_get_prototype_of(proto)) { 852 var indices = IS_PROXY(proto) ? length : %GetArrayKeys(proto, length); 853 if (IS_NUMBER(indices)) { 854 // It's an interval. 855 var proto_length = indices; 856 for (var i = 0; i < proto_length; i++) { 857 if (!HAS_OWN_PROPERTY(obj, i) && HAS_OWN_PROPERTY(proto, i)) { 858 obj[i] = proto[i]; 859 if (i >= max) { max = i + 1; } 860 } 861 } 862 } else { 863 for (var i = 0; i < indices.length; i++) { 864 var index = indices[i]; 865 if (!HAS_OWN_PROPERTY(obj, index) && HAS_OWN_PROPERTY(proto, index)) { 866 obj[index] = proto[index]; 867 if (index >= max) { max = index + 1; } 868 } 869 } 870 } 871 } 872 return max; 873 }; 874 875 // Set a value of "undefined" on all indices in the range from..to 876 // where a prototype of obj has an element. I.e., shadow all prototype 877 // elements in that range. 878 function ShadowPrototypeElements(obj, from, to) { 879 for (var proto = %object_get_prototype_of(obj); proto; 880 proto = %object_get_prototype_of(proto)) { 881 var indices = IS_PROXY(proto) ? to : %GetArrayKeys(proto, to); 882 if (IS_NUMBER(indices)) { 883 // It's an interval. 884 var proto_length = indices; 885 for (var i = from; i < proto_length; i++) { 886 if (HAS_OWN_PROPERTY(proto, i)) { 887 obj[i] = UNDEFINED; 888 } 889 } 890 } else { 891 for (var i = 0; i < indices.length; i++) { 892 var index = indices[i]; 893 if (from <= index && HAS_OWN_PROPERTY(proto, index)) { 894 obj[index] = UNDEFINED; 895 } 896 } 897 } 898 } 899 }; 900 901 function SafeRemoveArrayHoles(obj) { 902 // Copy defined elements from the end to fill in all holes and undefineds 903 // in the beginning of the array. Write undefineds and holes at the end 904 // after loop is finished. 905 var first_undefined = 0; 906 var last_defined = length - 1; 907 var num_holes = 0; 908 while (first_undefined < last_defined) { 909 // Find first undefined element. 910 while (first_undefined < last_defined && 911 !IS_UNDEFINED(obj[first_undefined])) { 912 first_undefined++; 913 } 914 // Maintain the invariant num_holes = the number of holes in the original 915 // array with indices <= first_undefined or > last_defined. 916 if (!HAS_OWN_PROPERTY(obj, first_undefined)) { 917 num_holes++; 918 } 919 920 // Find last defined element. 921 while (first_undefined < last_defined && 922 IS_UNDEFINED(obj[last_defined])) { 923 if (!HAS_OWN_PROPERTY(obj, last_defined)) { 924 num_holes++; 925 } 926 last_defined--; 927 } 928 if (first_undefined < last_defined) { 929 // Fill in hole or undefined. 930 obj[first_undefined] = obj[last_defined]; 931 obj[last_defined] = UNDEFINED; 932 } 933 } 934 // If there were any undefineds in the entire array, first_undefined 935 // points to one past the last defined element. Make this true if 936 // there were no undefineds, as well, so that first_undefined == number 937 // of defined elements. 938 if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++; 939 // Fill in the undefineds and the holes. There may be a hole where 940 // an undefined should be and vice versa. 941 var i; 942 for (i = first_undefined; i < length - num_holes; i++) { 943 obj[i] = UNDEFINED; 944 } 945 for (i = length - num_holes; i < length; i++) { 946 // For compatability with Webkit, do not expose elements in the prototype. 947 if (i in %object_get_prototype_of(obj)) { 948 obj[i] = UNDEFINED; 949 } else { 950 delete obj[i]; 951 } 952 } 953 954 // Return the number of defined elements. 955 return first_undefined; 956 }; 957 958 if (length < 2) return array; 959 960 var is_array = IS_ARRAY(array); 961 var max_prototype_element; 962 if (!is_array) { 963 // For compatibility with JSC, we also sort elements inherited from 964 // the prototype chain on non-Array objects. 965 // We do this by copying them to this object and sorting only 966 // own elements. This is not very efficient, but sorting with 967 // inherited elements happens very, very rarely, if at all. 968 // The specification allows "implementation dependent" behavior 969 // if an element on the prototype chain has an element that 970 // might interact with sorting. 971 max_prototype_element = CopyFromPrototype(array, length); 972 } 973 974 // %RemoveArrayHoles returns -1 if fast removal is not supported. 975 var num_non_undefined = %RemoveArrayHoles(array, length); 976 977 if (num_non_undefined == -1) { 978 // There were indexed accessors in the array. 979 // Move array holes and undefineds to the end using a Javascript function 980 // that is safe in the presence of accessors. 981 num_non_undefined = SafeRemoveArrayHoles(array); 982 } 983 984 QuickSort(array, 0, num_non_undefined); 985 986 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { 987 // For compatibility with JSC, we shadow any elements in the prototype 988 // chain that has become exposed by sort moving a hole to its position. 989 ShadowPrototypeElements(array, num_non_undefined, max_prototype_element); 990 } 991 992 return array; 993} 994 995 996function ArraySort(comparefn) { 997 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort"); 998 999 var array = TO_OBJECT(this); 1000 var length = TO_LENGTH(array.length); 1001 return InnerArraySort(array, length, comparefn); 1002} 1003 1004 1005// The following functions cannot be made efficient on sparse arrays while 1006// preserving the semantics, since the calls to the receiver function can add 1007// or delete elements from the array. 1008function InnerArrayFilter(f, receiver, array, length, result) { 1009 var result_length = 0; 1010 for (var i = 0; i < length; i++) { 1011 if (i in array) { 1012 var element = array[i]; 1013 if (%_Call(f, receiver, element, i, array)) { 1014 %CreateDataProperty(result, result_length, element); 1015 result_length++; 1016 } 1017 } 1018 } 1019 return result; 1020} 1021 1022 1023 1024function ArrayFilter(f, receiver) { 1025 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter"); 1026 1027 // Pull out the length so that modifications to the length in the 1028 // loop will not affect the looping and side effects are visible. 1029 var array = TO_OBJECT(this); 1030 var length = TO_LENGTH(array.length); 1031 if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f); 1032 var result = ArraySpeciesCreate(array, 0); 1033 return InnerArrayFilter(f, receiver, array, length, result); 1034} 1035 1036 1037function InnerArrayForEach(f, receiver, array, length) { 1038 if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f); 1039 1040 if (IS_UNDEFINED(receiver)) { 1041 for (var i = 0; i < length; i++) { 1042 if (i in array) { 1043 var element = array[i]; 1044 f(element, i, array); 1045 } 1046 } 1047 } else { 1048 for (var i = 0; i < length; i++) { 1049 if (i in array) { 1050 var element = array[i]; 1051 %_Call(f, receiver, element, i, array); 1052 } 1053 } 1054 } 1055} 1056 1057 1058function ArrayForEach(f, receiver) { 1059 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach"); 1060 1061 // Pull out the length so that modifications to the length in the 1062 // loop will not affect the looping and side effects are visible. 1063 var array = TO_OBJECT(this); 1064 var length = TO_LENGTH(array.length); 1065 InnerArrayForEach(f, receiver, array, length); 1066} 1067 1068 1069function InnerArraySome(f, receiver, array, length) { 1070 if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f); 1071 1072 for (var i = 0; i < length; i++) { 1073 if (i in array) { 1074 var element = array[i]; 1075 if (%_Call(f, receiver, element, i, array)) return true; 1076 } 1077 } 1078 return false; 1079} 1080 1081 1082// Executes the function once for each element present in the 1083// array until it finds one where callback returns true. 1084function ArraySome(f, receiver) { 1085 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some"); 1086 1087 // Pull out the length so that modifications to the length in the 1088 // loop will not affect the looping and side effects are visible. 1089 var array = TO_OBJECT(this); 1090 var length = TO_LENGTH(array.length); 1091 return InnerArraySome(f, receiver, array, length); 1092} 1093 1094 1095function InnerArrayEvery(f, receiver, array, length) { 1096 if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f); 1097 1098 for (var i = 0; i < length; i++) { 1099 if (i in array) { 1100 var element = array[i]; 1101 if (!%_Call(f, receiver, element, i, array)) return false; 1102 } 1103 } 1104 return true; 1105} 1106 1107function ArrayEvery(f, receiver) { 1108 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every"); 1109 1110 // Pull out the length so that modifications to the length in the 1111 // loop will not affect the looping and side effects are visible. 1112 var array = TO_OBJECT(this); 1113 var length = TO_LENGTH(array.length); 1114 return InnerArrayEvery(f, receiver, array, length); 1115} 1116 1117 1118function ArrayMap(f, receiver) { 1119 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map"); 1120 1121 // Pull out the length so that modifications to the length in the 1122 // loop will not affect the looping and side effects are visible. 1123 var array = TO_OBJECT(this); 1124 var length = TO_LENGTH(array.length); 1125 if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f); 1126 var result = ArraySpeciesCreate(array, length); 1127 for (var i = 0; i < length; i++) { 1128 if (i in array) { 1129 var element = array[i]; 1130 %CreateDataProperty(result, i, %_Call(f, receiver, element, i, array)); 1131 } 1132 } 1133 return result; 1134} 1135 1136 1137function InnerArrayLastIndexOf(array, element, index, length, argumentsLength) { 1138 if (length == 0) return -1; 1139 if (argumentsLength < 2) { 1140 index = length - 1; 1141 } else { 1142 index = INVERT_NEG_ZERO(TO_INTEGER(index)); 1143 // If index is negative, index from end of the array. 1144 if (index < 0) index += length; 1145 // If index is still negative, do not search the array. 1146 if (index < 0) return -1; 1147 else if (index >= length) index = length - 1; 1148 } 1149 var min = 0; 1150 var max = index; 1151 if (UseSparseVariant(array, length, IS_ARRAY(array), index)) { 1152 %NormalizeElements(array); 1153 var indices = %GetArrayKeys(array, index + 1); 1154 if (IS_NUMBER(indices)) { 1155 // It's an interval. 1156 max = indices; // Capped by index already. 1157 // Fall through to loop below. 1158 } else { 1159 if (indices.length == 0) return -1; 1160 // Get all the keys in sorted order. 1161 var sortedKeys = GetSortedArrayKeys(array, indices); 1162 var i = sortedKeys.length - 1; 1163 while (i >= 0) { 1164 var key = sortedKeys[i]; 1165 if (array[key] === element) return key; 1166 i--; 1167 } 1168 return -1; 1169 } 1170 } 1171 // Lookup through the array. 1172 if (!IS_UNDEFINED(element)) { 1173 for (var i = max; i >= min; i--) { 1174 if (array[i] === element) return i; 1175 } 1176 return -1; 1177 } 1178 for (var i = max; i >= min; i--) { 1179 if (IS_UNDEFINED(array[i]) && i in array) { 1180 return i; 1181 } 1182 } 1183 return -1; 1184} 1185 1186 1187function ArrayLastIndexOf(element, index) { 1188 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf"); 1189 1190 var length = TO_LENGTH(this.length); 1191 return InnerArrayLastIndexOf(this, element, index, length, 1192 arguments.length); 1193} 1194 1195 1196function InnerArrayReduce(callback, current, array, length, argumentsLength) { 1197 if (!IS_CALLABLE(callback)) { 1198 throw %make_type_error(kCalledNonCallable, callback); 1199 } 1200 1201 var i = 0; 1202 find_initial: if (argumentsLength < 2) { 1203 for (; i < length; i++) { 1204 if (i in array) { 1205 current = array[i++]; 1206 break find_initial; 1207 } 1208 } 1209 throw %make_type_error(kReduceNoInitial); 1210 } 1211 1212 for (; i < length; i++) { 1213 if (i in array) { 1214 var element = array[i]; 1215 current = callback(current, element, i, array); 1216 } 1217 } 1218 return current; 1219} 1220 1221 1222function ArrayReduce(callback, current) { 1223 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce"); 1224 1225 // Pull out the length so that modifications to the length in the 1226 // loop will not affect the looping and side effects are visible. 1227 var array = TO_OBJECT(this); 1228 var length = TO_LENGTH(array.length); 1229 return InnerArrayReduce(callback, current, array, length, 1230 arguments.length); 1231} 1232 1233 1234function InnerArrayReduceRight(callback, current, array, length, 1235 argumentsLength) { 1236 if (!IS_CALLABLE(callback)) { 1237 throw %make_type_error(kCalledNonCallable, callback); 1238 } 1239 1240 var i = length - 1; 1241 find_initial: if (argumentsLength < 2) { 1242 for (; i >= 0; i--) { 1243 if (i in array) { 1244 current = array[i--]; 1245 break find_initial; 1246 } 1247 } 1248 throw %make_type_error(kReduceNoInitial); 1249 } 1250 1251 for (; i >= 0; i--) { 1252 if (i in array) { 1253 var element = array[i]; 1254 current = callback(current, element, i, array); 1255 } 1256 } 1257 return current; 1258} 1259 1260 1261function ArrayReduceRight(callback, current) { 1262 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduceRight"); 1263 1264 // Pull out the length so that side effects are visible before the 1265 // callback function is checked. 1266 var array = TO_OBJECT(this); 1267 var length = TO_LENGTH(array.length); 1268 return InnerArrayReduceRight(callback, current, array, length, 1269 arguments.length); 1270} 1271 1272 1273// ES#sec-array.prototype.copywithin 1274// (Array.prototype.copyWithin ( target, start [ , end ] ) 1275function ArrayCopyWithin(target, start, end) { 1276 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin"); 1277 1278 var array = TO_OBJECT(this); 1279 var length = TO_LENGTH(array.length); 1280 1281 target = TO_INTEGER(target); 1282 var to; 1283 if (target < 0) { 1284 to = MaxSimple(length + target, 0); 1285 } else { 1286 to = MinSimple(target, length); 1287 } 1288 1289 start = TO_INTEGER(start); 1290 var from; 1291 if (start < 0) { 1292 from = MaxSimple(length + start, 0); 1293 } else { 1294 from = MinSimple(start, length); 1295 } 1296 1297 end = IS_UNDEFINED(end) ? length : TO_INTEGER(end); 1298 var final; 1299 if (end < 0) { 1300 final = MaxSimple(length + end, 0); 1301 } else { 1302 final = MinSimple(end, length); 1303 } 1304 1305 var count = MinSimple(final - from, length - to); 1306 var direction = 1; 1307 if (from < to && to < (from + count)) { 1308 direction = -1; 1309 from = from + count - 1; 1310 to = to + count - 1; 1311 } 1312 1313 while (count > 0) { 1314 if (from in array) { 1315 array[to] = array[from]; 1316 } else { 1317 delete array[to]; 1318 } 1319 from = from + direction; 1320 to = to + direction; 1321 count--; 1322 } 1323 1324 return array; 1325} 1326 1327 1328function InnerArrayFind(predicate, thisArg, array, length) { 1329 if (!IS_CALLABLE(predicate)) { 1330 throw %make_type_error(kCalledNonCallable, predicate); 1331 } 1332 1333 for (var i = 0; i < length; i++) { 1334 var element = array[i]; 1335 if (%_Call(predicate, thisArg, element, i, array)) { 1336 return element; 1337 } 1338 } 1339 1340 return; 1341} 1342 1343 1344// ES6 draft 07-15-13, section 15.4.3.23 1345function ArrayFind(predicate, thisArg) { 1346 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find"); 1347 1348 var array = TO_OBJECT(this); 1349 var length = TO_INTEGER(array.length); 1350 1351 return InnerArrayFind(predicate, thisArg, array, length); 1352} 1353 1354 1355function InnerArrayFindIndex(predicate, thisArg, array, length) { 1356 if (!IS_CALLABLE(predicate)) { 1357 throw %make_type_error(kCalledNonCallable, predicate); 1358 } 1359 1360 for (var i = 0; i < length; i++) { 1361 var element = array[i]; 1362 if (%_Call(predicate, thisArg, element, i, array)) { 1363 return i; 1364 } 1365 } 1366 1367 return -1; 1368} 1369 1370 1371// ES6 draft 07-15-13, section 15.4.3.24 1372function ArrayFindIndex(predicate, thisArg) { 1373 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex"); 1374 1375 var array = TO_OBJECT(this); 1376 var length = TO_INTEGER(array.length); 1377 1378 return InnerArrayFindIndex(predicate, thisArg, array, length); 1379} 1380 1381 1382// ES6, draft 04-05-14, section 22.1.3.6 1383function InnerArrayFill(value, start, end, array, length) { 1384 var i = IS_UNDEFINED(start) ? 0 : TO_INTEGER(start); 1385 var end = IS_UNDEFINED(end) ? length : TO_INTEGER(end); 1386 1387 if (i < 0) { 1388 i += length; 1389 if (i < 0) i = 0; 1390 } else { 1391 if (i > length) i = length; 1392 } 1393 1394 if (end < 0) { 1395 end += length; 1396 if (end < 0) end = 0; 1397 } else { 1398 if (end > length) end = length; 1399 } 1400 1401 if ((end - i) > 0 && %object_is_frozen(array)) { 1402 throw %make_type_error(kArrayFunctionsOnFrozen); 1403 } 1404 1405 for (; i < end; i++) 1406 array[i] = value; 1407 return array; 1408} 1409 1410 1411// ES6, draft 04-05-14, section 22.1.3.6 1412function ArrayFill(value, start, end) { 1413 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill"); 1414 1415 var array = TO_OBJECT(this); 1416 var length = TO_LENGTH(array.length); 1417 1418 return InnerArrayFill(value, start, end, array, length); 1419} 1420 1421 1422// ES6, draft 10-14-14, section 22.1.2.1 1423function ArrayFrom(arrayLike, mapfn, receiver) { 1424 var items = TO_OBJECT(arrayLike); 1425 var mapping = !IS_UNDEFINED(mapfn); 1426 1427 if (mapping) { 1428 if (!IS_CALLABLE(mapfn)) { 1429 throw %make_type_error(kCalledNonCallable, mapfn); 1430 } 1431 } 1432 1433 var iterable = GetMethod(items, iteratorSymbol); 1434 var k; 1435 var result; 1436 var mappedValue; 1437 var nextValue; 1438 1439 if (!IS_UNDEFINED(iterable)) { 1440 result = %IsConstructor(this) ? new this() : []; 1441 k = 0; 1442 1443 for (nextValue of 1444 { [iteratorSymbol]() { return GetIterator(items, iterable) } }) { 1445 if (mapping) { 1446 mappedValue = %_Call(mapfn, receiver, nextValue, k); 1447 } else { 1448 mappedValue = nextValue; 1449 } 1450 %CreateDataProperty(result, k, mappedValue); 1451 k++; 1452 } 1453 result.length = k; 1454 return result; 1455 } else { 1456 var len = TO_LENGTH(items.length); 1457 result = %IsConstructor(this) ? new this(len) : new GlobalArray(len); 1458 1459 for (k = 0; k < len; ++k) { 1460 nextValue = items[k]; 1461 if (mapping) { 1462 mappedValue = %_Call(mapfn, receiver, nextValue, k); 1463 } else { 1464 mappedValue = nextValue; 1465 } 1466 %CreateDataProperty(result, k, mappedValue); 1467 } 1468 1469 result.length = k; 1470 return result; 1471 } 1472} 1473 1474 1475// ES6, draft 05-22-14, section 22.1.2.3 1476function ArrayOf(...args) { 1477 var length = args.length; 1478 var constructor = this; 1479 // TODO: Implement IsConstructor (ES6 section 7.2.5) 1480 var array = %IsConstructor(constructor) ? new constructor(length) : []; 1481 for (var i = 0; i < length; i++) { 1482 %CreateDataProperty(array, i, args[i]); 1483 } 1484 array.length = length; 1485 return array; 1486} 1487 1488// ------------------------------------------------------------------- 1489 1490// Set up non-enumerable constructor property on the Array.prototype 1491// object. 1492%AddNamedProperty(GlobalArray.prototype, "constructor", GlobalArray, 1493 DONT_ENUM); 1494 1495// Set up unscopable properties on the Array.prototype object. 1496var unscopables = { 1497 __proto__: null, 1498 copyWithin: true, 1499 entries: true, 1500 fill: true, 1501 find: true, 1502 findIndex: true, 1503 includes: true, 1504 keys: true, 1505}; 1506 1507%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables, 1508 DONT_ENUM | READ_ONLY); 1509 1510%FunctionSetLength(ArrayFrom, 1); 1511 1512// Set up non-enumerable functions on the Array object. 1513utils.InstallFunctions(GlobalArray, DONT_ENUM, [ 1514 "from", ArrayFrom, 1515 "of", ArrayOf 1516]); 1517 1518var specialFunctions = %SpecialArrayFunctions(); 1519 1520function getFunction(name, jsBuiltin, len) { 1521 var f = jsBuiltin; 1522 if (specialFunctions.hasOwnProperty(name)) { 1523 f = specialFunctions[name]; 1524 } 1525 if (!IS_UNDEFINED(len)) { 1526 %FunctionSetLength(f, len); 1527 } 1528 return f; 1529}; 1530 1531// Array prototype functions that return iterators. They are exposed to the 1532// public API via Template::SetIntrinsicDataProperty(). 1533var IteratorFunctions = { 1534 "entries": getFunction("entries", null, 0), 1535 "forEach": getFunction("forEach", ArrayForEach, 1), 1536 "keys": getFunction("keys", null, 0), 1537 "values": getFunction("values", null, 0) 1538} 1539 1540// Set up non-enumerable functions of the Array.prototype object and 1541// set their names. 1542// Manipulate the length of some of the functions to meet 1543// expectations set by ECMA-262 or Mozilla. 1544utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [ 1545 "toString", getFunction("toString", ArrayToString), 1546 "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString), 1547 "join", getFunction("join", ArrayJoin), 1548 "pop", getFunction("pop", ArrayPop), 1549 "push", getFunction("push", ArrayPush, 1), 1550 "reverse", getFunction("reverse", ArrayReverse), 1551 "shift", getFunction("shift", ArrayShift), 1552 "unshift", getFunction("unshift", ArrayUnshift, 1), 1553 "slice", getFunction("slice", ArraySlice, 2), 1554 "splice", getFunction("splice", ArraySplice, 2), 1555 "sort", getFunction("sort", ArraySort), 1556 "filter", getFunction("filter", ArrayFilter, 1), 1557 "some", getFunction("some", ArraySome, 1), 1558 "every", getFunction("every", ArrayEvery, 1), 1559 "map", getFunction("map", ArrayMap, 1), 1560 "indexOf", getFunction("indexOf", null, 1), 1561 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1), 1562 "reduce", getFunction("reduce", ArrayReduce, 1), 1563 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1), 1564 "copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2), 1565 "find", getFunction("find", ArrayFind, 1), 1566 "findIndex", getFunction("findIndex", ArrayFindIndex, 1), 1567 "fill", getFunction("fill", ArrayFill, 1), 1568 "includes", getFunction("includes", null, 1), 1569 "entries", IteratorFunctions.entries, 1570 "forEach", IteratorFunctions.forEach, 1571 "keys", IteratorFunctions.keys, 1572 iteratorSymbol, IteratorFunctions.values 1573]); 1574 1575utils.ForEachFunction = GlobalArray.prototype.forEach; 1576 1577%FunctionSetName(IteratorFunctions.entries, "entries"); 1578%FunctionSetName(IteratorFunctions.forEach, "forEach"); 1579%FunctionSetName(IteratorFunctions.keys, "keys"); 1580%FunctionSetName(IteratorFunctions.values, "values"); 1581 1582%FinishArrayPrototypeSetup(GlobalArray.prototype); 1583 1584// The internal Array prototype doesn't need to be fancy, since it's never 1585// exposed to user code. 1586// Adding only the functions that are actually used. 1587utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [ 1588 "indexOf", getFunction("indexOf", null), 1589 "join", getFunction("join", ArrayJoin), 1590 "pop", getFunction("pop", ArrayPop), 1591 "push", getFunction("push", ArrayPush), 1592 "shift", getFunction("shift", ArrayShift), 1593 "sort", getFunction("sort", ArraySort), 1594 "splice", getFunction("splice", ArraySplice) 1595]); 1596 1597utils.SetUpLockedPrototype(InternalPackedArray, GlobalArray(), [ 1598 "join", getFunction("join", ArrayJoin), 1599 "pop", getFunction("pop", ArrayPop), 1600 "push", getFunction("push", ArrayPush), 1601 "shift", getFunction("shift", ArrayShift) 1602]); 1603 1604// V8 extras get a separate copy of InternalPackedArray. We give them the basic 1605// manipulation methods. 1606utils.SetUpLockedPrototype(extrasUtils.InternalPackedArray, GlobalArray(), [ 1607 "push", getFunction("push", ArrayPush), 1608 "pop", getFunction("pop", ArrayPop), 1609 "shift", getFunction("shift", ArrayShift), 1610 "unshift", getFunction("unshift", ArrayUnshift), 1611 "splice", getFunction("splice", ArraySplice), 1612 "slice", getFunction("slice", ArraySlice) 1613]); 1614 1615// ------------------------------------------------------------------- 1616// Exports 1617 1618utils.Export(function(to) { 1619 to.ArrayFrom = ArrayFrom; 1620 to.ArrayJoin = ArrayJoin; 1621 to.ArrayPush = ArrayPush; 1622 to.ArrayToString = ArrayToString; 1623 to.ArrayValues = IteratorFunctions.values, 1624 to.InnerArrayEvery = InnerArrayEvery; 1625 to.InnerArrayFill = InnerArrayFill; 1626 to.InnerArrayFilter = InnerArrayFilter; 1627 to.InnerArrayFind = InnerArrayFind; 1628 to.InnerArrayFindIndex = InnerArrayFindIndex; 1629 to.InnerArrayForEach = InnerArrayForEach; 1630 to.InnerArrayJoin = InnerArrayJoin; 1631 to.InnerArrayLastIndexOf = InnerArrayLastIndexOf; 1632 to.InnerArrayReduce = InnerArrayReduce; 1633 to.InnerArrayReduceRight = InnerArrayReduceRight; 1634 to.InnerArraySome = InnerArraySome; 1635 to.InnerArraySort = InnerArraySort; 1636 to.InnerArrayToLocaleString = InnerArrayToLocaleString; 1637 to.PackedArrayReverse = PackedArrayReverse; 1638}); 1639 1640%InstallToContext([ 1641 "array_entries_iterator", IteratorFunctions.entries, 1642 "array_for_each_iterator", IteratorFunctions.forEach, 1643 "array_keys_iterator", IteratorFunctions.keys, 1644 "array_pop", ArrayPop, 1645 "array_push", ArrayPush, 1646 "array_shift", ArrayShift, 1647 "array_splice", ArraySplice, 1648 "array_slice", ArraySlice, 1649 "array_unshift", ArrayUnshift, 1650 "array_values_iterator", IteratorFunctions.values, 1651]); 1652 1653}); 1654