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