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 GlobalArray = global.Array; 15var InternalArray = utils.InternalArray; 16var MathMax = global.Math.max; 17var MathMin = global.Math.min; 18var ObjectHasOwnProperty = global.Object.prototype.hasOwnProperty; 19var ObjectToString = global.Object.prototype.toString; 20var iteratorSymbol = utils.ImportNow("iterator_symbol"); 21var unscopablesSymbol = utils.ImportNow("unscopables_symbol"); 22 23// ------------------------------------------------------------------- 24 25macro IS_PROXY(arg) 26(%_IsJSProxy(arg)) 27endmacro 28 29macro INVERT_NEG_ZERO(arg) 30((arg) + 0) 31endmacro 32 33function ArraySpeciesCreate(array, length) { 34 length = INVERT_NEG_ZERO(length); 35 var constructor = %ArraySpeciesConstructor(array); 36 return new constructor(length); 37} 38 39 40function KeySortCompare(a, b) { 41 return a - b; 42} 43 44function GetSortedArrayKeys(array, indices) { 45 if (IS_NUMBER(indices)) { 46 // It's an interval 47 var limit = indices; 48 var keys = new InternalArray(); 49 for (var i = 0; i < limit; ++i) { 50 var e = array[i]; 51 if (!IS_UNDEFINED(e) || i in array) { 52 keys.push(i); 53 } 54 } 55 return keys; 56 } 57 return InnerArraySort(indices, indices.length, KeySortCompare); 58} 59 60 61function SparseJoinWithSeparatorJS( 62 array, keys, length, use_locale, separator, locales, options) { 63 var keys_length = keys.length; 64 var elements = new InternalArray(keys_length * 2); 65 for (var i = 0; i < keys_length; i++) { 66 var key = keys[i]; 67 elements[i * 2] = key; 68 elements[i * 2 + 1] = ConvertToString( 69 use_locale, array[key], locales, options); 70 } 71 return %SparseJoinWithSeparator(elements, length, separator); 72} 73 74 75// Optimized for sparse arrays if separator is ''. 76function SparseJoin(array, keys, use_locale, locales, options) { 77 var keys_length = keys.length; 78 var elements = new InternalArray(keys_length); 79 for (var i = 0; i < keys_length; i++) { 80 elements[i] = ConvertToString(use_locale, array[keys[i]], locales, options); 81 } 82 return %StringBuilderConcat(elements, keys_length, ''); 83} 84 85 86function UseSparseVariant(array, length, is_array, touched) { 87 // Only use the sparse variant on arrays that are likely to be sparse and the 88 // number of elements touched in the operation is relatively small compared to 89 // the overall size of the array. 90 if (!is_array || length < 1000 || %HasComplexElements(array)) { 91 return false; 92 } 93 if (!%_IsSmi(length)) { 94 return true; 95 } 96 var elements_threshold = length >> 2; // No more than 75% holes 97 var estimated_elements = %EstimateNumberOfElements(array); 98 return (estimated_elements < elements_threshold) && 99 (touched > estimated_elements * 4); 100} 101 102function Stack() { 103 this.length = 0; 104 this.values = new InternalArray(); 105} 106 107// Predeclare the instance variables on the prototype. Otherwise setting them in 108// the constructor will leak the instance through settings on Object.prototype. 109Stack.prototype.length = null; 110Stack.prototype.values = null; 111 112function StackPush(stack, value) { 113 stack.values[stack.length++] = value; 114} 115 116function StackPop(stack) { 117 stack.values[--stack.length] = null 118} 119 120function StackHas(stack, v) { 121 var length = stack.length; 122 var values = stack.values; 123 for (var i = 0; i < length; i++) { 124 if (values[i] === v) return true; 125 } 126 return false; 127} 128 129// Global list of arrays visited during toString, toLocaleString and 130// join invocations. 131var visited_arrays = new Stack(); 132 133function DoJoin( 134 array, length, is_array, separator, use_locale, locales, options) { 135 if (UseSparseVariant(array, length, is_array, length)) { 136 %NormalizeElements(array); 137 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length)); 138 if (separator === '') { 139 if (keys.length === 0) return ''; 140 return SparseJoin(array, keys, use_locale, locales, options); 141 } else { 142 return SparseJoinWithSeparatorJS( 143 array, keys, length, use_locale, separator, locales, options); 144 } 145 } 146 147 // Fast case for one-element arrays. 148 if (length === 1) { 149 return ConvertToString(use_locale, array[0], locales, options); 150 } 151 152 // Construct an array for the elements. 153 var elements = new InternalArray(length); 154 for (var i = 0; i < length; i++) { 155 elements[i] = ConvertToString(use_locale, array[i], locales, options); 156 } 157 158 if (separator === '') { 159 return %StringBuilderConcat(elements, length, ''); 160 } else { 161 return %StringBuilderJoin(elements, length, separator); 162 } 163} 164 165function Join(array, length, separator, use_locale, locales, options) { 166 if (length === 0) return ''; 167 168 var is_array = IS_ARRAY(array); 169 170 if (is_array) { 171 // If the array is cyclic, return the empty string for already 172 // visited arrays. 173 if (StackHas(visited_arrays, array)) return ''; 174 StackPush(visited_arrays, array); 175 } 176 177 // Attempt to convert the elements. 178 try { 179 return DoJoin( 180 array, length, is_array, separator, use_locale, locales, options); 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, locales, options) { 190 if (IS_NULL_OR_UNDEFINED(x)) return ''; 191 if (use_locale) { 192 if (IS_NULL_OR_UNDEFINED(locales)) { 193 return TO_STRING(x.toLocaleString()); 194 } else if (IS_NULL_OR_UNDEFINED(options)) { 195 return TO_STRING(x.toLocaleString(locales)); 196 } 197 return TO_STRING(x.toLocaleString(locales, options)); 198 } 199 200 return TO_STRING(x); 201} 202 203 204// This function implements the optimized splice implementation that can use 205// special array operations to handle sparse arrays in a sensible fashion. 206function SparseSlice(array, start_i, del_count, len, deleted_elements) { 207 // Move deleted elements to a new array (the return value from splice). 208 var indices = %GetArrayKeys(array, start_i + del_count); 209 if (IS_NUMBER(indices)) { 210 var limit = indices; 211 for (var i = start_i; i < limit; ++i) { 212 var current = array[i]; 213 if (!IS_UNDEFINED(current) || i in array) { 214 %CreateDataProperty(deleted_elements, i - start_i, current); 215 } 216 } 217 } else { 218 var length = indices.length; 219 for (var k = 0; k < length; ++k) { 220 var key = indices[k]; 221 if (key >= start_i) { 222 var current = array[key]; 223 if (!IS_UNDEFINED(current) || key in array) { 224 %CreateDataProperty(deleted_elements, key - start_i, current); 225 } 226 } 227 } 228 } 229} 230 231 232// This function implements the optimized splice implementation that can use 233// special array operations to handle sparse arrays in a sensible fashion. 234function SparseMove(array, start_i, del_count, len, num_additional_args) { 235 // Bail out if no moving is necessary. 236 if (num_additional_args === del_count) return; 237 // Move data to new array. 238 var new_array = new InternalArray( 239 // Clamp array length to 2^32-1 to avoid early RangeError. 240 MathMin(len - del_count + num_additional_args, 0xffffffff)); 241 var big_indices; 242 var indices = %GetArrayKeys(array, len); 243 if (IS_NUMBER(indices)) { 244 var limit = indices; 245 for (var i = 0; i < start_i && i < limit; ++i) { 246 var current = array[i]; 247 if (!IS_UNDEFINED(current) || i in array) { 248 new_array[i] = current; 249 } 250 } 251 for (var i = start_i + del_count; i < limit; ++i) { 252 var current = array[i]; 253 if (!IS_UNDEFINED(current) || i in array) { 254 new_array[i - del_count + num_additional_args] = current; 255 } 256 } 257 } else { 258 var length = indices.length; 259 for (var k = 0; k < length; ++k) { 260 var key = indices[k]; 261 if (key < start_i) { 262 var current = array[key]; 263 if (!IS_UNDEFINED(current) || key in array) { 264 new_array[key] = current; 265 } 266 } else if (key >= start_i + del_count) { 267 var current = array[key]; 268 if (!IS_UNDEFINED(current) || key in array) { 269 var new_key = key - del_count + num_additional_args; 270 new_array[new_key] = current; 271 if (new_key > 0xfffffffe) { 272 big_indices = big_indices || new InternalArray(); 273 big_indices.push(new_key); 274 } 275 } 276 } 277 } 278 } 279 // Move contents of new_array into this array 280 %MoveArrayContents(new_array, array); 281 // Add any moved values that aren't elements anymore. 282 if (!IS_UNDEFINED(big_indices)) { 283 var length = big_indices.length; 284 for (var i = 0; i < length; ++i) { 285 var key = big_indices[i]; 286 array[key] = new_array[key]; 287 } 288 } 289} 290 291 292// This is part of the old simple-minded splice. We are using it either 293// because the receiver is not an array (so we have no choice) or because we 294// know we are not deleting or moving a lot of elements. 295function SimpleSlice(array, start_i, del_count, len, deleted_elements) { 296 for (var i = 0; i < del_count; i++) { 297 var index = start_i + i; 298 if (index in array) { 299 var current = array[index]; 300 %CreateDataProperty(deleted_elements, i, current); 301 } 302 } 303} 304 305 306function SimpleMove(array, start_i, del_count, len, num_additional_args) { 307 if (num_additional_args !== del_count) { 308 // Move the existing elements after the elements to be deleted 309 // to the right position in the resulting array. 310 if (num_additional_args > del_count) { 311 for (var i = len - del_count; i > start_i; i--) { 312 var from_index = i + del_count - 1; 313 var to_index = i + num_additional_args - 1; 314 if (from_index in array) { 315 array[to_index] = array[from_index]; 316 } else { 317 delete array[to_index]; 318 } 319 } 320 } else { 321 for (var i = start_i; i < len - del_count; i++) { 322 var from_index = i + del_count; 323 var to_index = i + num_additional_args; 324 if (from_index in array) { 325 array[to_index] = array[from_index]; 326 } else { 327 delete array[to_index]; 328 } 329 } 330 for (var i = len; i > len - del_count + num_additional_args; i--) { 331 delete array[i - 1]; 332 } 333 } 334 } 335} 336 337 338// ------------------------------------------------------------------- 339 340var ArrayJoin; 341DEFINE_METHOD( 342 GlobalArray.prototype, 343 toString() { 344 var array; 345 var func; 346 if (IS_ARRAY(this)) { 347 func = this.join; 348 if (func === ArrayJoin) { 349 return Join(this, this.length, ',', false); 350 } 351 array = this; 352 } else { 353 array = TO_OBJECT(this); 354 func = array.join; 355 } 356 if (!IS_CALLABLE(func)) { 357 return %_Call(ObjectToString, array); 358 } 359 return %_Call(func, array); 360 } 361); 362 363// ecma402 #sup-array.prototype.tolocalestring 364function InnerArrayToLocaleString(array, length, locales, options) { 365 return Join(array, TO_LENGTH(length), ',', true, locales, options); 366} 367 368 369DEFINE_METHOD( 370 GlobalArray.prototype, 371 // ecma402 #sup-array.prototype.tolocalestring 372 toLocaleString() { 373 var array = TO_OBJECT(this); 374 var arrayLen = array.length; 375 var locales = arguments[0]; 376 var options = arguments[1]; 377 return InnerArrayToLocaleString(array, arrayLen, locales, options); 378 } 379); 380 381 382function InnerArrayJoin(separator, array, length) { 383 if (IS_UNDEFINED(separator)) { 384 separator = ','; 385 } else { 386 separator = TO_STRING(separator); 387 } 388 389 // Fast case for one-element arrays. 390 if (length === 1) { 391 var e = array[0]; 392 if (IS_NULL_OR_UNDEFINED(e)) return ''; 393 return TO_STRING(e); 394 } 395 396 return Join(array, length, separator, false); 397} 398 399 400DEFINE_METHOD( 401 GlobalArray.prototype, 402 join(separator) { 403 var array = TO_OBJECT(this); 404 var length = TO_LENGTH(array.length); 405 406 return InnerArrayJoin(separator, array, length); 407 } 408); 409 410 411function ArrayShiftFallback() { 412 var array = TO_OBJECT(this); 413 var len = TO_LENGTH(array.length); 414 415 if (len === 0) { 416 array.length = 0; 417 return; 418 } 419 420 var first = array[0]; 421 422 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) { 423 SparseMove(array, 0, 1, len, 0); 424 } else { 425 SimpleMove(array, 0, 1, len, 0); 426 } 427 428 array.length = len - 1; 429 430 return first; 431} 432 433 434function ArrayUnshiftFallback(arg1) { // length == 1 435 var array = TO_OBJECT(this); 436 var len = TO_LENGTH(array.length); 437 var num_arguments = arguments.length; 438 439 const new_len = len + num_arguments; 440 if (num_arguments > 0) { 441 if (new_len >= 2**53) throw %make_type_error(kInvalidArrayLength); 442 443 if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) && 444 !%object_is_sealed(array)) { 445 SparseMove(array, 0, 0, len, num_arguments); 446 } else { 447 SimpleMove(array, 0, 0, len, num_arguments); 448 } 449 450 for (var i = 0; i < num_arguments; i++) { 451 array[i] = arguments[i]; 452 } 453 } 454 455 array.length = new_len; 456 return new_len; 457} 458 459 460// Oh the humanity... don't remove the following function because js2c for some 461// reason gets symbol minifiation wrong if it's not there. Instead of spending 462// the time fixing js2c (which will go away when all of the internal .js runtime 463// files are gone), just keep this work-around. 464function ArraySliceFallback(start, end) { 465 return null; 466} 467 468function ComputeSpliceStartIndex(start_i, len) { 469 if (start_i < 0) { 470 start_i += len; 471 return start_i < 0 ? 0 : start_i; 472 } 473 474 return start_i > len ? len : start_i; 475} 476 477 478function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) { 479 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 480 // given as a request to delete all the elements from the start. 481 // And it differs from the case of undefined delete count. 482 // This does not follow ECMA-262, but we do the same for 483 // compatibility. 484 var del_count = 0; 485 if (num_arguments == 1) 486 return len - start_i; 487 488 del_count = TO_INTEGER(delete_count); 489 if (del_count < 0) 490 return 0; 491 492 if (del_count > len - start_i) 493 return len - start_i; 494 495 return del_count; 496} 497 498 499function ArraySpliceFallback(start, delete_count) { 500 var num_arguments = arguments.length; 501 var array = TO_OBJECT(this); 502 var len = TO_LENGTH(array.length); 503 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len); 504 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, 505 start_i); 506 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0; 507 508 const new_len = len - del_count + num_elements_to_add; 509 if (new_len >= 2**53) throw %make_type_error(kInvalidArrayLength); 510 511 var deleted_elements = ArraySpeciesCreate(array, del_count); 512 deleted_elements.length = del_count; 513 514 var changed_elements = del_count; 515 if (num_elements_to_add != del_count) { 516 // If the slice needs to do a actually move elements after the insertion 517 // point, then include those in the estimate of changed elements. 518 changed_elements += len - start_i - del_count; 519 } 520 if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) { 521 %NormalizeElements(array); 522 if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements); 523 SparseSlice(array, start_i, del_count, len, deleted_elements); 524 SparseMove(array, start_i, del_count, len, num_elements_to_add); 525 } else { 526 SimpleSlice(array, start_i, del_count, len, deleted_elements); 527 SimpleMove(array, start_i, del_count, len, num_elements_to_add); 528 } 529 530 // Insert the arguments into the resulting array in 531 // place of the deleted elements. 532 var i = start_i; 533 var arguments_index = 2; 534 var arguments_length = arguments.length; 535 while (arguments_index < arguments_length) { 536 array[i++] = arguments[arguments_index++]; 537 } 538 array.length = new_len; 539 540 // Return the deleted elements. 541 return deleted_elements; 542} 543 544 545function InnerArraySort(array, length, comparefn) { 546 // In-place QuickSort algorithm. 547 // For short (length <= 10) arrays, insertion sort is used for efficiency. 548 549 if (!IS_CALLABLE(comparefn)) { 550 comparefn = function (x, y) { 551 if (x === y) return 0; 552 if (%_IsSmi(x) && %_IsSmi(y)) { 553 return %SmiLexicographicCompare(x, y); 554 } 555 x = TO_STRING(x); 556 y = TO_STRING(y); 557 if (x == y) return 0; 558 else return x < y ? -1 : 1; 559 }; 560 } 561 function InsertionSort(a, from, to) { 562 for (var i = from + 1; i < to; i++) { 563 var element = a[i]; 564 for (var j = i - 1; j >= from; j--) { 565 var tmp = a[j]; 566 var order = comparefn(tmp, element); 567 if (order > 0) { 568 a[j + 1] = tmp; 569 } else { 570 break; 571 } 572 } 573 a[j + 1] = element; 574 } 575 }; 576 577 function GetThirdIndex(a, from, to) { 578 var t_array = new InternalArray(); 579 // Use both 'from' and 'to' to determine the pivot candidates. 580 var increment = 200 + ((to - from) & 15); 581 var j = 0; 582 from += 1; 583 to -= 1; 584 for (var i = from; i < to; i += increment) { 585 t_array[j] = [i, a[i]]; 586 j++; 587 } 588 t_array.sort(function(a, b) { 589 return comparefn(a[1], b[1]); 590 }); 591 var third_index = t_array[t_array.length >> 1][0]; 592 return third_index; 593 } 594 595 function QuickSort(a, from, to) { 596 var third_index = 0; 597 while (true) { 598 // Insertion sort is faster for short arrays. 599 if (to - from <= 10) { 600 InsertionSort(a, from, to); 601 return; 602 } 603 if (to - from > 1000) { 604 third_index = GetThirdIndex(a, from, to); 605 } else { 606 third_index = from + ((to - from) >> 1); 607 } 608 // Find a pivot as the median of first, last and middle element. 609 var v0 = a[from]; 610 var v1 = a[to - 1]; 611 var v2 = a[third_index]; 612 var c01 = comparefn(v0, v1); 613 if (c01 > 0) { 614 // v1 < v0, so swap them. 615 var tmp = v0; 616 v0 = v1; 617 v1 = tmp; 618 } // v0 <= v1. 619 var c02 = comparefn(v0, v2); 620 if (c02 >= 0) { 621 // v2 <= v0 <= v1. 622 var tmp = v0; 623 v0 = v2; 624 v2 = v1; 625 v1 = tmp; 626 } else { 627 // v0 <= v1 && v0 < v2 628 var c12 = comparefn(v1, v2); 629 if (c12 > 0) { 630 // v0 <= v2 < v1 631 var tmp = v1; 632 v1 = v2; 633 v2 = tmp; 634 } 635 } 636 // v0 <= v1 <= v2 637 a[from] = v0; 638 a[to - 1] = v2; 639 var pivot = v1; 640 var low_end = from + 1; // Upper bound of elements lower than pivot. 641 var high_start = to - 1; // Lower bound of elements greater than pivot. 642 a[third_index] = a[low_end]; 643 a[low_end] = pivot; 644 645 // From low_end to i are elements equal to pivot. 646 // From i to high_start are elements that haven't been compared yet. 647 partition: for (var i = low_end + 1; i < high_start; i++) { 648 var element = a[i]; 649 var order = comparefn(element, pivot); 650 if (order < 0) { 651 a[i] = a[low_end]; 652 a[low_end] = element; 653 low_end++; 654 } else if (order > 0) { 655 do { 656 high_start--; 657 if (high_start == i) break partition; 658 var top_elem = a[high_start]; 659 order = comparefn(top_elem, pivot); 660 } while (order > 0); 661 a[i] = a[high_start]; 662 a[high_start] = element; 663 if (order < 0) { 664 element = a[i]; 665 a[i] = a[low_end]; 666 a[low_end] = element; 667 low_end++; 668 } 669 } 670 } 671 if (to - high_start < low_end - from) { 672 QuickSort(a, high_start, to); 673 to = low_end; 674 } else { 675 QuickSort(a, from, low_end); 676 from = high_start; 677 } 678 } 679 }; 680 681 if (length < 2) return array; 682 683 // For compatibility with JSC, we also sort elements inherited from 684 // the prototype chain on non-Array objects. 685 // We do this by copying them to this object and sorting only 686 // own elements. This is not very efficient, but sorting with 687 // inherited elements happens very, very rarely, if at all. 688 // The specification allows "implementation dependent" behavior 689 // if an element on the prototype chain has an element that 690 // might interact with sorting. 691 // 692 // We also move all non-undefined elements to the front of the 693 // array and move the undefineds after that. Holes are removed. 694 // This happens for Array as well as non-Array objects. 695 var num_non_undefined = %PrepareElementsForSort(array, length); 696 697 QuickSort(array, 0, num_non_undefined); 698 699 return array; 700} 701 702 703DEFINE_METHOD_LEN( 704 GlobalArray.prototype, 705 lastIndexOf(element, index) { 706 var array = TO_OBJECT(this); 707 var length = TO_LENGTH(this.length); 708 709 if (length == 0) return -1; 710 if (arguments.length < 2) { 711 index = length - 1; 712 } else { 713 index = INVERT_NEG_ZERO(TO_INTEGER(index)); 714 // If index is negative, index from end of the array. 715 if (index < 0) index += length; 716 // If index is still negative, do not search the array. 717 if (index < 0) return -1; 718 else if (index >= length) index = length - 1; 719 } 720 var min = 0; 721 var max = index; 722 if (UseSparseVariant(array, length, IS_ARRAY(array), index)) { 723 %NormalizeElements(array); 724 var indices = %GetArrayKeys(array, index + 1); 725 if (IS_NUMBER(indices)) { 726 // It's an interval. 727 max = indices; // Capped by index already. 728 // Fall through to loop below. 729 } else { 730 if (indices.length == 0) return -1; 731 // Get all the keys in sorted order. 732 var sortedKeys = GetSortedArrayKeys(array, indices); 733 var i = sortedKeys.length - 1; 734 while (i >= 0) { 735 var key = sortedKeys[i]; 736 if (array[key] === element) return key; 737 i--; 738 } 739 return -1; 740 } 741 } 742 // Lookup through the array. 743 for (var i = max; i >= min; i--) { 744 if (i in array && array[i] === element) return i; 745 } 746 return -1; 747 }, 748 1 /* Set function length */ 749); 750 751 752 753// Set up unscopable properties on the Array.prototype object. 754var unscopables = { 755 __proto__: null, 756 copyWithin: true, 757 entries: true, 758 fill: true, 759 find: true, 760 findIndex: true, 761 includes: true, 762 keys: true, 763}; 764 765%ToFastProperties(unscopables); 766 767%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables, 768 DONT_ENUM | READ_ONLY); 769 770var ArrayIndexOf = GlobalArray.prototype.indexOf; 771var ArrayJoin = GlobalArray.prototype.join; 772var ArrayPop = GlobalArray.prototype.pop; 773var ArrayPush = GlobalArray.prototype.push; 774var ArraySlice = GlobalArray.prototype.slice; 775var ArrayShift = GlobalArray.prototype.shift; 776var ArraySort = GlobalArray.prototype.sort; 777var ArraySplice = GlobalArray.prototype.splice; 778var ArrayToString = GlobalArray.prototype.toString; 779var ArrayUnshift = GlobalArray.prototype.unshift; 780 781// Array prototype functions that return iterators. They are exposed to the 782// public API via Template::SetIntrinsicDataProperty(). 783var ArrayEntries = GlobalArray.prototype.entries; 784var ArrayForEach = GlobalArray.prototype.forEach; 785var ArrayKeys = GlobalArray.prototype.keys; 786var ArrayValues = GlobalArray.prototype[iteratorSymbol]; 787 788 789// The internal Array prototype doesn't need to be fancy, since it's never 790// exposed to user code. 791// Adding only the functions that are actually used. 792utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [ 793 "indexOf", ArrayIndexOf, 794 "join", ArrayJoin, 795 "pop", ArrayPop, 796 "push", ArrayPush, 797 "shift", ArrayShift, 798 "sort", ArraySort, 799 "splice", ArraySplice 800]); 801 802// V8 extras get a separate copy of InternalPackedArray. We give them the basic 803// manipulation methods. 804utils.SetUpLockedPrototype(extrasUtils.InternalPackedArray, GlobalArray(), [ 805 "push", ArrayPush, 806 "pop", ArrayPop, 807 "shift", ArrayShift, 808 "unshift", ArrayUnshift, 809 "splice", ArraySplice, 810 "slice", ArraySlice 811]); 812 813// ------------------------------------------------------------------- 814// Exports 815 816utils.Export(function(to) { 817 to.ArrayJoin = ArrayJoin; 818 to.ArrayPush = ArrayPush; 819 to.ArrayToString = ArrayToString; 820 to.ArrayValues = ArrayValues; 821 to.InnerArrayJoin = InnerArrayJoin; 822 to.InnerArrayToLocaleString = InnerArrayToLocaleString; 823}); 824 825%InstallToContext([ 826 "array_entries_iterator", ArrayEntries, 827 "array_for_each_iterator", ArrayForEach, 828 "array_keys_iterator", ArrayKeys, 829 "array_values_iterator", ArrayValues, 830 // Fallback implementations of Array builtins. 831 "array_shift", ArrayShiftFallback, 832 "array_splice", ArraySpliceFallback, 833 "array_unshift", ArrayUnshiftFallback, 834]); 835 836}); 837