blob: 1406df336d03825cb8dac8f47abd0abd2f058323 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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 AddIndexedProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015var FLAG_harmony_species;
16var GetIterator;
17var GetMethod;
18var GlobalArray = global.Array;
19var InternalArray = utils.InternalArray;
20var InternalPackedArray = utils.InternalPackedArray;
21var MakeTypeError;
22var MaxSimple;
23var MinSimple;
24var ObjectDefineProperty;
25var ObjectHasOwnProperty;
26var ObjectToString = utils.ImportNow("object_to_string");
27var ObserveBeginPerformSplice;
28var ObserveEndPerformSplice;
29var ObserveEnqueueSpliceRecord;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030var iteratorSymbol = utils.ImportNow("iterator_symbol");
31var unscopablesSymbol = utils.ImportNow("unscopables_symbol");
32
33utils.Import(function(from) {
34 AddIndexedProperty = from.AddIndexedProperty;
35 GetIterator = from.GetIterator;
36 GetMethod = from.GetMethod;
37 MakeTypeError = from.MakeTypeError;
38 MaxSimple = from.MaxSimple;
39 MinSimple = from.MinSimple;
40 ObjectDefineProperty = from.ObjectDefineProperty;
41 ObjectHasOwnProperty = from.ObjectHasOwnProperty;
42 ObserveBeginPerformSplice = from.ObserveBeginPerformSplice;
43 ObserveEndPerformSplice = from.ObserveEndPerformSplice;
44 ObserveEnqueueSpliceRecord = from.ObserveEnqueueSpliceRecord;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045});
46
47utils.ImportFromExperimental(function(from) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 FLAG_harmony_species = from.FLAG_harmony_species;
49});
50
51// -------------------------------------------------------------------
52
53
54function ArraySpeciesCreate(array, length) {
55 var constructor;
56 if (FLAG_harmony_species) {
57 constructor = %ArraySpeciesConstructor(array);
58 } else {
59 constructor = GlobalArray;
60 }
61 return new constructor(length);
62}
63
64
65function DefineIndexedProperty(array, i, value) {
66 if (FLAG_harmony_species) {
67 var result = ObjectDefineProperty(array, i, {
68 value: value, writable: true, configurable: true, enumerable: true
69 });
70 if (!result) throw MakeTypeError(kStrictCannotAssign, i);
71 } else {
72 AddIndexedProperty(array, i, value);
73 }
74}
75
Ben Murdochda12d292016-06-02 14:46:10 +010076function KeySortCompare(a, b) {
77 return a - b;
78}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080function GetSortedArrayKeys(array, indices) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 if (IS_NUMBER(indices)) {
Ben Murdochda12d292016-06-02 14:46:10 +010082 var keys = new InternalArray();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 // It's an interval
84 var limit = indices;
85 for (var i = 0; i < limit; ++i) {
86 var e = array[i];
87 if (!IS_UNDEFINED(e) || i in array) {
88 keys.push(i);
89 }
90 }
Ben Murdochda12d292016-06-02 14:46:10 +010091 return keys;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 }
Ben Murdochda12d292016-06-02 14:46:10 +010093 return InnerArraySort(indices, indices.length, KeySortCompare);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094}
95
96
Ben Murdochda12d292016-06-02 14:46:10 +010097function SparseJoinWithSeparatorJS(array, keys, length, convert, separator) {
98 var keys_length = keys.length;
99 var elements = new InternalArray(keys_length * 2);
100 for (var i = 0; i < keys_length; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 var key = keys[i];
Ben Murdochda12d292016-06-02 14:46:10 +0100102 var e = array[key];
103 elements[i * 2] = key;
104 elements[i * 2 + 1] = IS_STRING(e) ? e : convert(e);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 }
Ben Murdochda12d292016-06-02 14:46:10 +0100106 return %SparseJoinWithSeparator(elements, length, separator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107}
108
109
110// Optimized for sparse arrays if separator is ''.
Ben Murdochda12d292016-06-02 14:46:10 +0100111function SparseJoin(array, keys, convert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 var keys_length = keys.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 var elements = new InternalArray(keys_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 for (var i = 0; i < keys_length; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100115 var e = array[keys[i]];
116 elements[i] = IS_STRING(e) ? e : convert(e);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 }
Ben Murdochda12d292016-06-02 14:46:10 +0100118 return %StringBuilderConcat(elements, keys_length, '');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119}
120
121
122function UseSparseVariant(array, length, is_array, touched) {
123 // Only use the sparse variant on arrays that are likely to be sparse and the
124 // number of elements touched in the operation is relatively small compared to
125 // the overall size of the array.
126 if (!is_array || length < 1000 || %IsObserved(array) ||
127 %HasComplexElements(array)) {
128 return false;
129 }
130 if (!%_IsSmi(length)) {
131 return true;
132 }
133 var elements_threshold = length >> 2; // No more than 75% holes
134 var estimated_elements = %EstimateNumberOfElements(array);
135 return (estimated_elements < elements_threshold) &&
136 (touched > estimated_elements * 4);
137}
138
Ben Murdochda12d292016-06-02 14:46:10 +0100139function Stack() {
140 this.length = 0;
141 this.values = new InternalArray();
142}
143
144// Predeclare the instance variables on the prototype. Otherwise setting them in
145// the constructor will leak the instance through settings on Object.prototype.
146Stack.prototype.length = null;
147Stack.prototype.values = null;
148
149function StackPush(stack, value) {
150 stack.values[stack.length++] = value;
151}
152
153function StackPop(stack) {
154 stack.values[--stack.length] = null
155}
156
157function StackHas(stack, v) {
158 var length = stack.length;
159 var values = stack.values;
160 for (var i = 0; i < length; i++) {
161 if (values[i] === v) return true;
162 }
163 return false;
164}
165
166// Global list of arrays visited during toString, toLocaleString and
167// join invocations.
168var visited_arrays = new Stack();
169
170function DoJoin(array, length, is_array, separator, convert) {
171 if (UseSparseVariant(array, length, is_array, length)) {
172 %NormalizeElements(array);
173 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length));
174 if (separator === '') {
175 if (keys.length === 0) return '';
176 return SparseJoin(array, keys, convert);
177 } else {
178 return SparseJoinWithSeparatorJS(array, keys, length, convert, separator);
179 }
180 }
181
182 // Fast case for one-element arrays.
183 if (length === 1) {
184 var e = array[0];
185 return IS_STRING(e) ? e : convert(e);
186 }
187
188 // Construct an array for the elements.
189 var elements = new InternalArray(length);
190
191 // We pull the empty separator check outside the loop for speed!
192 if (separator === '') {
193 for (var i = 0; i < length; i++) {
194 var e = array[i];
195 elements[i] = IS_STRING(e) ? e : convert(e);
196 }
197 return %StringBuilderConcat(elements, length, '');
198 }
199 // Non-empty separator case.
200 // If the first element is a number then use the heuristic that the
201 // remaining elements are also likely to be numbers.
202 var e = array[0];
203 if (IS_NUMBER(e)) {
204 elements[0] = %_NumberToString(e);
205 for (var i = 1; i < length; i++) {
206 e = array[i];
207 if (IS_NUMBER(e)) {
208 elements[i] = %_NumberToString(e);
209 } else {
210 elements[i] = IS_STRING(e) ? e : convert(e);
211 }
212 }
213 } else {
214 elements[0] = IS_STRING(e) ? e : convert(e);
215 for (var i = 1; i < length; i++) {
216 e = array[i];
217 elements[i] = IS_STRING(e) ? e : convert(e);
218 }
219 }
220 return %StringBuilderJoin(elements, length, separator);
221}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222
223function Join(array, length, separator, convert) {
Ben Murdochda12d292016-06-02 14:46:10 +0100224 if (length === 0) return '';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225
226 var is_array = IS_ARRAY(array);
227
228 if (is_array) {
229 // If the array is cyclic, return the empty string for already
230 // visited arrays.
Ben Murdochda12d292016-06-02 14:46:10 +0100231 if (StackHas(visited_arrays, array)) return '';
232 StackPush(visited_arrays, array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 }
234
235 // Attempt to convert the elements.
236 try {
Ben Murdochda12d292016-06-02 14:46:10 +0100237 return DoJoin(array, length, is_array, separator, convert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 } finally {
239 // Make sure to remove the last element of the visited array no
240 // matter what happens.
Ben Murdochda12d292016-06-02 14:46:10 +0100241 if (is_array) StackPop(visited_arrays);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 }
243}
244
245
246function ConvertToString(x) {
Ben Murdochda12d292016-06-02 14:46:10 +0100247 if (IS_NULL_OR_UNDEFINED(x)) return '';
248 return TO_STRING(x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249}
250
251
252function ConvertToLocaleString(e) {
Ben Murdochda12d292016-06-02 14:46:10 +0100253 if (IS_NULL_OR_UNDEFINED(e)) return '';
254 return TO_STRING(e.toLocaleString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255}
256
257
258// This function implements the optimized splice implementation that can use
259// special array operations to handle sparse arrays in a sensible fashion.
260function SparseSlice(array, start_i, del_count, len, deleted_elements) {
261 // Move deleted elements to a new array (the return value from splice).
262 var indices = %GetArrayKeys(array, start_i + del_count);
263 if (IS_NUMBER(indices)) {
264 var limit = indices;
265 for (var i = start_i; i < limit; ++i) {
266 var current = array[i];
267 if (!IS_UNDEFINED(current) || i in array) {
268 DefineIndexedProperty(deleted_elements, i - start_i, current);
269 }
270 }
271 } else {
272 var length = indices.length;
273 for (var k = 0; k < length; ++k) {
274 var key = indices[k];
Ben Murdochda12d292016-06-02 14:46:10 +0100275 if (key >= start_i) {
276 var current = array[key];
277 if (!IS_UNDEFINED(current) || key in array) {
278 DefineIndexedProperty(deleted_elements, key - start_i, current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 }
280 }
281 }
282 }
283}
284
285
286// This function implements the optimized splice implementation that can use
287// special array operations to handle sparse arrays in a sensible fashion.
288function SparseMove(array, start_i, del_count, len, num_additional_args) {
289 // Bail out if no moving is necessary.
290 if (num_additional_args === del_count) return;
291 // Move data to new array.
292 var new_array = new InternalArray(
293 // Clamp array length to 2^32-1 to avoid early RangeError.
294 MinSimple(len - del_count + num_additional_args, 0xffffffff));
295 var big_indices;
296 var indices = %GetArrayKeys(array, len);
297 if (IS_NUMBER(indices)) {
298 var limit = indices;
299 for (var i = 0; i < start_i && i < limit; ++i) {
300 var current = array[i];
301 if (!IS_UNDEFINED(current) || i in array) {
302 new_array[i] = current;
303 }
304 }
305 for (var i = start_i + del_count; i < limit; ++i) {
306 var current = array[i];
307 if (!IS_UNDEFINED(current) || i in array) {
308 new_array[i - del_count + num_additional_args] = current;
309 }
310 }
311 } else {
312 var length = indices.length;
313 for (var k = 0; k < length; ++k) {
314 var key = indices[k];
Ben Murdochda12d292016-06-02 14:46:10 +0100315 if (key < start_i) {
316 var current = array[key];
317 if (!IS_UNDEFINED(current) || key in array) {
318 new_array[key] = current;
319 }
320 } else if (key >= start_i + del_count) {
321 var current = array[key];
322 if (!IS_UNDEFINED(current) || key in array) {
323 var new_key = key - del_count + num_additional_args;
324 new_array[new_key] = current;
325 if (new_key > 0xfffffffe) {
326 big_indices = big_indices || new InternalArray();
327 big_indices.push(new_key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 }
329 }
330 }
331 }
332 }
333 // Move contents of new_array into this array
334 %MoveArrayContents(new_array, array);
335 // Add any moved values that aren't elements anymore.
336 if (!IS_UNDEFINED(big_indices)) {
337 var length = big_indices.length;
338 for (var i = 0; i < length; ++i) {
339 var key = big_indices[i];
340 array[key] = new_array[key];
341 }
342 }
343}
344
345
346// This is part of the old simple-minded splice. We are using it either
347// because the receiver is not an array (so we have no choice) or because we
348// know we are not deleting or moving a lot of elements.
349function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
350 var is_array = IS_ARRAY(array);
351 for (var i = 0; i < del_count; i++) {
352 var index = start_i + i;
353 if (HAS_INDEX(array, index, is_array)) {
354 var current = array[index];
355 DefineIndexedProperty(deleted_elements, i, current);
356 }
357 }
358}
359
360
361function SimpleMove(array, start_i, del_count, len, num_additional_args) {
362 var is_array = IS_ARRAY(array);
363 if (num_additional_args !== del_count) {
364 // Move the existing elements after the elements to be deleted
365 // to the right position in the resulting array.
366 if (num_additional_args > del_count) {
367 for (var i = len - del_count; i > start_i; i--) {
368 var from_index = i + del_count - 1;
369 var to_index = i + num_additional_args - 1;
370 if (HAS_INDEX(array, from_index, is_array)) {
371 array[to_index] = array[from_index];
372 } else {
373 delete array[to_index];
374 }
375 }
376 } else {
377 for (var i = start_i; i < len - del_count; i++) {
378 var from_index = i + del_count;
379 var to_index = i + num_additional_args;
380 if (HAS_INDEX(array, from_index, is_array)) {
381 array[to_index] = array[from_index];
382 } else {
383 delete array[to_index];
384 }
385 }
386 for (var i = len; i > len - del_count + num_additional_args; i--) {
387 delete array[i - 1];
388 }
389 }
390 }
391}
392
393
394// -------------------------------------------------------------------
395
396
397function ArrayToString() {
398 var array;
399 var func;
400 if (IS_ARRAY(this)) {
401 func = this.join;
402 if (func === ArrayJoin) {
403 return Join(this, this.length, ',', ConvertToString);
404 }
405 array = this;
406 } else {
407 array = TO_OBJECT(this);
408 func = array.join;
409 }
410 if (!IS_CALLABLE(func)) {
411 return %_Call(ObjectToString, array);
412 }
413 return %_Call(func, array);
414}
415
416
417function InnerArrayToLocaleString(array, length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100418 var len = TO_LENGTH(length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 if (len === 0) return "";
420 return Join(array, len, ',', ConvertToLocaleString);
421}
422
423
424function ArrayToLocaleString() {
425 var array = TO_OBJECT(this);
426 var arrayLen = array.length;
427 return InnerArrayToLocaleString(array, arrayLen);
428}
429
430
431function InnerArrayJoin(separator, array, length) {
432 if (IS_UNDEFINED(separator)) {
433 separator = ',';
434 } else {
435 separator = TO_STRING(separator);
436 }
437
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 // Fast case for one-element arrays.
439 if (length === 1) {
440 var e = array[0];
441 if (IS_NULL_OR_UNDEFINED(e)) return '';
442 return TO_STRING(e);
443 }
444
445 return Join(array, length, separator, ConvertToString);
446}
447
448
449function ArrayJoin(separator) {
450 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join");
451
452 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100453 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454
455 return InnerArrayJoin(separator, array, length);
456}
457
458
459function ObservedArrayPop(n) {
460 n--;
461 var value = this[n];
462
463 try {
464 ObserveBeginPerformSplice(this);
465 delete this[n];
466 this.length = n;
467 } finally {
468 ObserveEndPerformSplice(this);
469 ObserveEnqueueSpliceRecord(this, n, [value], 0);
470 }
471
472 return value;
473}
474
475
476// Removes the last element from the array and returns it. See
477// ECMA-262, section 15.4.4.6.
478function ArrayPop() {
479 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop");
480
481 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100482 var n = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000483 if (n == 0) {
484 array.length = n;
485 return;
486 }
487
488 if (%IsObserved(array))
489 return ObservedArrayPop.call(array, n);
490
491 n--;
492 var value = array[n];
493 %DeleteProperty_Strict(array, n);
494 array.length = n;
495 return value;
496}
497
498
499function ObservedArrayPush() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100500 var n = TO_LENGTH(this.length);
501 var m = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502
503 try {
504 ObserveBeginPerformSplice(this);
505 for (var i = 0; i < m; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100506 this[i+n] = arguments[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 }
508 var new_length = n + m;
509 this.length = new_length;
510 } finally {
511 ObserveEndPerformSplice(this);
512 ObserveEnqueueSpliceRecord(this, n, [], m);
513 }
514
515 return new_length;
516}
517
518
519// Appends the arguments to the end of the array and returns the new
520// length of the array. See ECMA-262, section 15.4.4.7.
521function ArrayPush() {
522 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");
523
524 if (%IsObserved(this))
525 return ObservedArrayPush.apply(this, arguments);
526
527 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100528 var n = TO_LENGTH(array.length);
529 var m = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530
531 // It appears that there is no enforced, absolute limit on the number of
532 // arguments, but it would surely blow the stack to use 2**30 or more.
533 // To avoid integer overflow, do the comparison to the max safe integer
534 // after subtracting 2**30 from both sides. (2**31 would seem like a
535 // natural value, but it is negative in JS, and 2**32 is 1.)
536 if (m > (1 << 30) || (n - (1 << 30)) + m > kMaxSafeInteger - (1 << 30)) {
537 throw MakeTypeError(kPushPastSafeLength, m, n);
538 }
539
540 for (var i = 0; i < m; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100541 array[i+n] = arguments[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 }
543
544 var new_length = n + m;
545 array.length = new_length;
546 return new_length;
547}
548
549
550// For implementing reverse() on large, sparse arrays.
551function SparseReverse(array, len) {
552 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
553 var high_counter = keys.length - 1;
554 var low_counter = 0;
555 while (low_counter <= high_counter) {
556 var i = keys[low_counter];
557 var j = keys[high_counter];
558
559 var j_complement = len - j - 1;
560 var low, high;
561
562 if (j_complement <= i) {
563 high = j;
564 while (keys[--high_counter] == j) { }
565 low = j_complement;
566 }
567 if (j_complement >= i) {
568 low = i;
569 while (keys[++low_counter] == i) { }
570 high = len - i - 1;
571 }
572
573 var current_i = array[low];
574 if (!IS_UNDEFINED(current_i) || low in array) {
575 var current_j = array[high];
576 if (!IS_UNDEFINED(current_j) || high in array) {
577 array[low] = current_j;
578 array[high] = current_i;
579 } else {
580 array[high] = current_i;
581 delete array[low];
582 }
583 } else {
584 var current_j = array[high];
585 if (!IS_UNDEFINED(current_j) || high in array) {
586 array[low] = current_j;
587 delete array[high];
588 }
589 }
590 }
591}
592
593function PackedArrayReverse(array, len) {
594 var j = len - 1;
595 for (var i = 0; i < j; i++, j--) {
596 var current_i = array[i];
597 var current_j = array[j];
598 array[i] = current_j;
599 array[j] = current_i;
600 }
601 return array;
602}
603
604
605function GenericArrayReverse(array, len) {
606 var j = len - 1;
607 for (var i = 0; i < j; i++, j--) {
608 if (i in array) {
609 var current_i = array[i];
610 if (j in array) {
611 var current_j = array[j];
612 array[i] = current_j;
613 array[j] = current_i;
614 } else {
615 array[j] = current_i;
616 delete array[i];
617 }
618 } else {
619 if (j in array) {
620 var current_j = array[j];
621 array[i] = current_j;
622 delete array[j];
623 }
624 }
625 }
626 return array;
627}
628
629
630function ArrayReverse() {
631 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse");
632
633 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100634 var len = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000635 var isArray = IS_ARRAY(array);
636
637 if (UseSparseVariant(array, len, isArray, len)) {
638 %NormalizeElements(array);
639 SparseReverse(array, len);
640 return array;
641 } else if (isArray && %_HasFastPackedElements(array)) {
642 return PackedArrayReverse(array, len);
643 } else {
644 return GenericArrayReverse(array, len);
645 }
646}
647
648
649function ObservedArrayShift(len) {
650 var first = this[0];
651
652 try {
653 ObserveBeginPerformSplice(this);
654 SimpleMove(this, 0, 1, len, 0);
655 this.length = len - 1;
656 } finally {
657 ObserveEndPerformSplice(this);
658 ObserveEnqueueSpliceRecord(this, 0, [first], 0);
659 }
660
661 return first;
662}
663
664
665function ArrayShift() {
666 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift");
667
668 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100669 var len = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670
671 if (len === 0) {
672 array.length = 0;
673 return;
674 }
675
676 if (%object_is_sealed(array)) throw MakeTypeError(kArrayFunctionsOnSealed);
677
678 if (%IsObserved(array))
679 return ObservedArrayShift.call(array, len);
680
681 var first = array[0];
682
683 if (UseSparseVariant(array, len, IS_ARRAY(array), len)) {
684 SparseMove(array, 0, 1, len, 0);
685 } else {
686 SimpleMove(array, 0, 1, len, 0);
687 }
688
689 array.length = len - 1;
690
691 return first;
692}
693
694
695function ObservedArrayUnshift() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100696 var len = TO_LENGTH(this.length);
697 var num_arguments = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698
699 try {
700 ObserveBeginPerformSplice(this);
701 SimpleMove(this, 0, 0, len, num_arguments);
702 for (var i = 0; i < num_arguments; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100703 this[i] = arguments[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 }
705 var new_length = len + num_arguments;
706 this.length = new_length;
707 } finally {
708 ObserveEndPerformSplice(this);
709 ObserveEnqueueSpliceRecord(this, 0, [], num_arguments);
710 }
711
712 return new_length;
713}
714
715
716function ArrayUnshift(arg1) { // length == 1
717 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift");
718
719 if (%IsObserved(this))
720 return ObservedArrayUnshift.apply(this, arguments);
721
722 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100723 var len = TO_LENGTH(array.length);
724 var num_arguments = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725
726 if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) &&
727 !%object_is_sealed(array)) {
728 SparseMove(array, 0, 0, len, num_arguments);
729 } else {
730 SimpleMove(array, 0, 0, len, num_arguments);
731 }
732
733 for (var i = 0; i < num_arguments; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100734 array[i] = arguments[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 }
736
737 var new_length = len + num_arguments;
738 array.length = new_length;
739 return new_length;
740}
741
742
743function ArraySlice(start, end) {
744 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");
745
746 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100747 var len = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 var start_i = TO_INTEGER(start);
749 var end_i = len;
750
751 if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);
752
753 if (start_i < 0) {
754 start_i += len;
755 if (start_i < 0) start_i = 0;
756 } else {
757 if (start_i > len) start_i = len;
758 }
759
760 if (end_i < 0) {
761 end_i += len;
762 if (end_i < 0) end_i = 0;
763 } else {
764 if (end_i > len) end_i = len;
765 }
766
767 var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0));
768
769 if (end_i < start_i) return result;
770
771 if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
772 %NormalizeElements(array);
773 %NormalizeElements(result);
774 SparseSlice(array, start_i, end_i - start_i, len, result);
775 } else {
776 SimpleSlice(array, start_i, end_i - start_i, len, result);
777 }
778
779 result.length = end_i - start_i;
780
781 return result;
782}
783
784
785function ComputeSpliceStartIndex(start_i, len) {
786 if (start_i < 0) {
787 start_i += len;
788 return start_i < 0 ? 0 : start_i;
789 }
790
791 return start_i > len ? len : start_i;
792}
793
794
795function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) {
796 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
797 // given as a request to delete all the elements from the start.
798 // And it differs from the case of undefined delete count.
799 // This does not follow ECMA-262, but we do the same for
800 // compatibility.
801 var del_count = 0;
802 if (num_arguments == 1)
803 return len - start_i;
804
805 del_count = TO_INTEGER(delete_count);
806 if (del_count < 0)
807 return 0;
808
809 if (del_count > len - start_i)
810 return len - start_i;
811
812 return del_count;
813}
814
815
816function ObservedArraySplice(start, delete_count) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100817 var num_arguments = arguments.length;
818 var len = TO_LENGTH(this.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
820 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
821 start_i);
822 var deleted_elements = [];
823 deleted_elements.length = del_count;
824 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
825
826 try {
827 ObserveBeginPerformSplice(this);
828
829 SimpleSlice(this, start_i, del_count, len, deleted_elements);
830 SimpleMove(this, start_i, del_count, len, num_elements_to_add);
831
832 // Insert the arguments into the resulting array in
833 // place of the deleted elements.
834 var i = start_i;
835 var arguments_index = 2;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100836 var arguments_length = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000837 while (arguments_index < arguments_length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100838 this[i++] = arguments[arguments_index++];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000839 }
840 this.length = len - del_count + num_elements_to_add;
841
842 } finally {
843 ObserveEndPerformSplice(this);
844 if (deleted_elements.length || num_elements_to_add) {
845 ObserveEnqueueSpliceRecord(this,
846 start_i,
847 deleted_elements.slice(),
848 num_elements_to_add);
849 }
850 }
851
852 // Return the deleted elements.
853 return deleted_elements;
854}
855
856
857function ArraySplice(start, delete_count) {
858 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice");
859
860 if (%IsObserved(this))
861 return ObservedArraySplice.apply(this, arguments);
862
Ben Murdoch097c5b22016-05-18 11:27:45 +0100863 var num_arguments = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000864 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100865 var len = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
867 var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
868 start_i);
869 var deleted_elements = ArraySpeciesCreate(array, del_count);
870 deleted_elements.length = del_count;
871 var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
872
873 if (del_count != num_elements_to_add && %object_is_sealed(array)) {
874 throw MakeTypeError(kArrayFunctionsOnSealed);
875 } else if (del_count > 0 && %object_is_frozen(array)) {
876 throw MakeTypeError(kArrayFunctionsOnFrozen);
877 }
878
879 var changed_elements = del_count;
880 if (num_elements_to_add != del_count) {
881 // If the slice needs to do a actually move elements after the insertion
882 // point, then include those in the estimate of changed elements.
883 changed_elements += len - start_i - del_count;
884 }
885 if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
886 %NormalizeElements(array);
887 %NormalizeElements(deleted_elements);
888 SparseSlice(array, start_i, del_count, len, deleted_elements);
889 SparseMove(array, start_i, del_count, len, num_elements_to_add);
890 } else {
891 SimpleSlice(array, start_i, del_count, len, deleted_elements);
892 SimpleMove(array, start_i, del_count, len, num_elements_to_add);
893 }
894
895 // Insert the arguments into the resulting array in
896 // place of the deleted elements.
897 var i = start_i;
898 var arguments_index = 2;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100899 var arguments_length = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900 while (arguments_index < arguments_length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100901 array[i++] = arguments[arguments_index++];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 }
903 array.length = len - del_count + num_elements_to_add;
904
905 // Return the deleted elements.
906 return deleted_elements;
907}
908
909
910function InnerArraySort(array, length, comparefn) {
911 // In-place QuickSort algorithm.
912 // For short (length <= 22) arrays, insertion sort is used for efficiency.
913
914 if (!IS_CALLABLE(comparefn)) {
915 comparefn = function (x, y) {
916 if (x === y) return 0;
917 if (%_IsSmi(x) && %_IsSmi(y)) {
918 return %SmiLexicographicCompare(x, y);
919 }
920 x = TO_STRING(x);
921 y = TO_STRING(y);
922 if (x == y) return 0;
923 else return x < y ? -1 : 1;
924 };
925 }
926 var InsertionSort = function InsertionSort(a, from, to) {
927 for (var i = from + 1; i < to; i++) {
928 var element = a[i];
929 for (var j = i - 1; j >= from; j--) {
930 var tmp = a[j];
931 var order = comparefn(tmp, element);
932 if (order > 0) {
933 a[j + 1] = tmp;
934 } else {
935 break;
936 }
937 }
938 a[j + 1] = element;
939 }
940 };
941
942 var GetThirdIndex = function(a, from, to) {
943 var t_array = new InternalArray();
944 // Use both 'from' and 'to' to determine the pivot candidates.
945 var increment = 200 + ((to - from) & 15);
946 var j = 0;
947 from += 1;
948 to -= 1;
949 for (var i = from; i < to; i += increment) {
950 t_array[j] = [i, a[i]];
951 j++;
952 }
953 t_array.sort(function(a, b) {
954 return comparefn(a[1], b[1]);
955 });
956 var third_index = t_array[t_array.length >> 1][0];
957 return third_index;
958 }
959
960 var QuickSort = function QuickSort(a, from, to) {
961 var third_index = 0;
962 while (true) {
963 // Insertion sort is faster for short arrays.
964 if (to - from <= 10) {
965 InsertionSort(a, from, to);
966 return;
967 }
968 if (to - from > 1000) {
969 third_index = GetThirdIndex(a, from, to);
970 } else {
971 third_index = from + ((to - from) >> 1);
972 }
973 // Find a pivot as the median of first, last and middle element.
974 var v0 = a[from];
975 var v1 = a[to - 1];
976 var v2 = a[third_index];
977 var c01 = comparefn(v0, v1);
978 if (c01 > 0) {
979 // v1 < v0, so swap them.
980 var tmp = v0;
981 v0 = v1;
982 v1 = tmp;
983 } // v0 <= v1.
984 var c02 = comparefn(v0, v2);
985 if (c02 >= 0) {
986 // v2 <= v0 <= v1.
987 var tmp = v0;
988 v0 = v2;
989 v2 = v1;
990 v1 = tmp;
991 } else {
992 // v0 <= v1 && v0 < v2
993 var c12 = comparefn(v1, v2);
994 if (c12 > 0) {
995 // v0 <= v2 < v1
996 var tmp = v1;
997 v1 = v2;
998 v2 = tmp;
999 }
1000 }
1001 // v0 <= v1 <= v2
1002 a[from] = v0;
1003 a[to - 1] = v2;
1004 var pivot = v1;
1005 var low_end = from + 1; // Upper bound of elements lower than pivot.
1006 var high_start = to - 1; // Lower bound of elements greater than pivot.
1007 a[third_index] = a[low_end];
1008 a[low_end] = pivot;
1009
1010 // From low_end to i are elements equal to pivot.
1011 // From i to high_start are elements that haven't been compared yet.
1012 partition: for (var i = low_end + 1; i < high_start; i++) {
1013 var element = a[i];
1014 var order = comparefn(element, pivot);
1015 if (order < 0) {
1016 a[i] = a[low_end];
1017 a[low_end] = element;
1018 low_end++;
1019 } else if (order > 0) {
1020 do {
1021 high_start--;
1022 if (high_start == i) break partition;
1023 var top_elem = a[high_start];
1024 order = comparefn(top_elem, pivot);
1025 } while (order > 0);
1026 a[i] = a[high_start];
1027 a[high_start] = element;
1028 if (order < 0) {
1029 element = a[i];
1030 a[i] = a[low_end];
1031 a[low_end] = element;
1032 low_end++;
1033 }
1034 }
1035 }
1036 if (to - high_start < low_end - from) {
1037 QuickSort(a, high_start, to);
1038 to = low_end;
1039 } else {
1040 QuickSort(a, from, low_end);
1041 from = high_start;
1042 }
1043 }
1044 };
1045
1046 // Copy elements in the range 0..length from obj's prototype chain
1047 // to obj itself, if obj has holes. Return one more than the maximal index
1048 // of a prototype property.
1049 var CopyFromPrototype = function CopyFromPrototype(obj, length) {
1050 var max = 0;
1051 for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001052 var indices = IS_PROXY(proto) ? length : %GetArrayKeys(proto, length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 if (IS_NUMBER(indices)) {
1054 // It's an interval.
1055 var proto_length = indices;
1056 for (var i = 0; i < proto_length; i++) {
1057 if (!HAS_OWN_PROPERTY(obj, i) && HAS_OWN_PROPERTY(proto, i)) {
1058 obj[i] = proto[i];
1059 if (i >= max) { max = i + 1; }
1060 }
1061 }
1062 } else {
1063 for (var i = 0; i < indices.length; i++) {
1064 var index = indices[i];
Ben Murdochda12d292016-06-02 14:46:10 +01001065 if (!HAS_OWN_PROPERTY(obj, index) && HAS_OWN_PROPERTY(proto, index)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 obj[index] = proto[index];
1067 if (index >= max) { max = index + 1; }
1068 }
1069 }
1070 }
1071 }
1072 return max;
1073 };
1074
1075 // Set a value of "undefined" on all indices in the range from..to
1076 // where a prototype of obj has an element. I.e., shadow all prototype
1077 // elements in that range.
1078 var ShadowPrototypeElements = function(obj, from, to) {
1079 for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001080 var indices = IS_PROXY(proto) ? to : %GetArrayKeys(proto, to);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001081 if (IS_NUMBER(indices)) {
1082 // It's an interval.
1083 var proto_length = indices;
1084 for (var i = from; i < proto_length; i++) {
1085 if (HAS_OWN_PROPERTY(proto, i)) {
1086 obj[i] = UNDEFINED;
1087 }
1088 }
1089 } else {
1090 for (var i = 0; i < indices.length; i++) {
1091 var index = indices[i];
Ben Murdochda12d292016-06-02 14:46:10 +01001092 if (from <= index && HAS_OWN_PROPERTY(proto, index)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 obj[index] = UNDEFINED;
1094 }
1095 }
1096 }
1097 }
1098 };
1099
1100 var SafeRemoveArrayHoles = function SafeRemoveArrayHoles(obj) {
1101 // Copy defined elements from the end to fill in all holes and undefineds
1102 // in the beginning of the array. Write undefineds and holes at the end
1103 // after loop is finished.
1104 var first_undefined = 0;
1105 var last_defined = length - 1;
1106 var num_holes = 0;
1107 while (first_undefined < last_defined) {
1108 // Find first undefined element.
1109 while (first_undefined < last_defined &&
1110 !IS_UNDEFINED(obj[first_undefined])) {
1111 first_undefined++;
1112 }
1113 // Maintain the invariant num_holes = the number of holes in the original
1114 // array with indices <= first_undefined or > last_defined.
1115 if (!HAS_OWN_PROPERTY(obj, first_undefined)) {
1116 num_holes++;
1117 }
1118
1119 // Find last defined element.
1120 while (first_undefined < last_defined &&
1121 IS_UNDEFINED(obj[last_defined])) {
1122 if (!HAS_OWN_PROPERTY(obj, last_defined)) {
1123 num_holes++;
1124 }
1125 last_defined--;
1126 }
1127 if (first_undefined < last_defined) {
1128 // Fill in hole or undefined.
1129 obj[first_undefined] = obj[last_defined];
1130 obj[last_defined] = UNDEFINED;
1131 }
1132 }
1133 // If there were any undefineds in the entire array, first_undefined
1134 // points to one past the last defined element. Make this true if
1135 // there were no undefineds, as well, so that first_undefined == number
1136 // of defined elements.
1137 if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++;
1138 // Fill in the undefineds and the holes. There may be a hole where
1139 // an undefined should be and vice versa.
1140 var i;
1141 for (i = first_undefined; i < length - num_holes; i++) {
1142 obj[i] = UNDEFINED;
1143 }
1144 for (i = length - num_holes; i < length; i++) {
1145 // For compatability with Webkit, do not expose elements in the prototype.
1146 if (i in %_GetPrototype(obj)) {
1147 obj[i] = UNDEFINED;
1148 } else {
1149 delete obj[i];
1150 }
1151 }
1152
1153 // Return the number of defined elements.
1154 return first_undefined;
1155 };
1156
1157 if (length < 2) return array;
1158
1159 var is_array = IS_ARRAY(array);
1160 var max_prototype_element;
1161 if (!is_array) {
1162 // For compatibility with JSC, we also sort elements inherited from
1163 // the prototype chain on non-Array objects.
1164 // We do this by copying them to this object and sorting only
1165 // own elements. This is not very efficient, but sorting with
1166 // inherited elements happens very, very rarely, if at all.
1167 // The specification allows "implementation dependent" behavior
1168 // if an element on the prototype chain has an element that
1169 // might interact with sorting.
1170 max_prototype_element = CopyFromPrototype(array, length);
1171 }
1172
1173 // %RemoveArrayHoles returns -1 if fast removal is not supported.
1174 var num_non_undefined = %RemoveArrayHoles(array, length);
1175
1176 if (num_non_undefined == -1) {
1177 // The array is observed, or there were indexed accessors in the array.
1178 // Move array holes and undefineds to the end using a Javascript function
1179 // that is safe in the presence of accessors and is observable.
1180 num_non_undefined = SafeRemoveArrayHoles(array);
1181 }
1182
1183 QuickSort(array, 0, num_non_undefined);
1184
1185 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {
1186 // For compatibility with JSC, we shadow any elements in the prototype
1187 // chain that has become exposed by sort moving a hole to its position.
1188 ShadowPrototypeElements(array, num_non_undefined, max_prototype_element);
1189 }
1190
1191 return array;
1192}
1193
1194
1195function ArraySort(comparefn) {
1196 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort");
1197
1198 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001199 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 return InnerArraySort(array, length, comparefn);
1201}
1202
1203
1204// The following functions cannot be made efficient on sparse arrays while
1205// preserving the semantics, since the calls to the receiver function can add
1206// or delete elements from the array.
1207function InnerArrayFilter(f, receiver, array, length, result) {
1208 var result_length = 0;
1209 var is_array = IS_ARRAY(array);
1210 for (var i = 0; i < length; i++) {
1211 if (HAS_INDEX(array, i, is_array)) {
1212 var element = array[i];
1213 if (%_Call(f, receiver, element, i, array)) {
1214 DefineIndexedProperty(result, result_length, element);
1215 result_length++;
1216 }
1217 }
1218 }
1219 return result;
1220}
1221
1222
1223
1224function ArrayFilter(f, receiver) {
1225 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter");
1226
1227 // Pull out the length so that modifications to the length in the
1228 // loop will not affect the looping and side effects are visible.
1229 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001230 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001231 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
1232 var result = ArraySpeciesCreate(array, 0);
1233 return InnerArrayFilter(f, receiver, array, length, result);
1234}
1235
1236
1237function InnerArrayForEach(f, receiver, array, length) {
1238 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
1239
1240 var is_array = IS_ARRAY(array);
Ben Murdochda12d292016-06-02 14:46:10 +01001241 if (IS_UNDEFINED(receiver)) {
1242 for (var i = 0; i < length; i++) {
1243 if (HAS_INDEX(array, i, is_array)) {
1244 var element = array[i];
1245 f(element, i, array);
1246 }
1247 }
1248 } else {
1249 for (var i = 0; i < length; i++) {
1250 if (HAS_INDEX(array, i, is_array)) {
1251 var element = array[i];
1252 %_Call(f, receiver, element, i, array);
1253 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254 }
1255 }
1256}
1257
1258
1259function ArrayForEach(f, receiver) {
1260 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach");
1261
1262 // Pull out the length so that modifications to the length in the
1263 // loop will not affect the looping and side effects are visible.
1264 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001265 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 InnerArrayForEach(f, receiver, array, length);
1267}
1268
1269
1270function InnerArraySome(f, receiver, array, length) {
1271 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
1272
1273 var is_array = IS_ARRAY(array);
1274 for (var i = 0; i < length; i++) {
1275 if (HAS_INDEX(array, i, is_array)) {
1276 var element = array[i];
1277 if (%_Call(f, receiver, element, i, array)) return true;
1278 }
1279 }
1280 return false;
1281}
1282
1283
1284// Executes the function once for each element present in the
1285// array until it finds one where callback returns true.
1286function ArraySome(f, receiver) {
1287 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some");
1288
1289 // Pull out the length so that modifications to the length in the
1290 // loop will not affect the looping and side effects are visible.
1291 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001292 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001293 return InnerArraySome(f, receiver, array, length);
1294}
1295
1296
1297function InnerArrayEvery(f, receiver, array, length) {
1298 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
1299
1300 var is_array = IS_ARRAY(array);
1301 for (var i = 0; i < length; i++) {
1302 if (HAS_INDEX(array, i, is_array)) {
1303 var element = array[i];
1304 if (!%_Call(f, receiver, element, i, array)) return false;
1305 }
1306 }
1307 return true;
1308}
1309
1310function ArrayEvery(f, receiver) {
1311 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every");
1312
1313 // Pull out the length so that modifications to the length in the
1314 // loop will not affect the looping and side effects are visible.
1315 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001316 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001317 return InnerArrayEvery(f, receiver, array, length);
1318}
1319
1320
1321function ArrayMap(f, receiver) {
1322 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
1323
1324 // Pull out the length so that modifications to the length in the
1325 // loop will not affect the looping and side effects are visible.
1326 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001327 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
1329 var result = ArraySpeciesCreate(array, length);
1330 var is_array = IS_ARRAY(array);
1331 for (var i = 0; i < length; i++) {
1332 if (HAS_INDEX(array, i, is_array)) {
1333 var element = array[i];
1334 DefineIndexedProperty(result, i, %_Call(f, receiver, element, i, array));
1335 }
1336 }
1337 return result;
1338}
1339
1340
1341// For .indexOf, we don't need to pass in the number of arguments
1342// at the callsite since ToInteger(undefined) == 0; however, for
1343// .lastIndexOf, we need to pass it, since the behavior for passing
1344// undefined is 0 but for not including the argument is length-1.
1345function InnerArrayIndexOf(array, element, index, length) {
1346 if (length == 0) return -1;
1347 if (IS_UNDEFINED(index)) {
1348 index = 0;
1349 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001350 index = TO_INTEGER(index) + 0; // Add 0 to convert -0 to 0
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 // If index is negative, index from the end of the array.
1352 if (index < 0) {
1353 index = length + index;
1354 // If index is still negative, search the entire array.
1355 if (index < 0) index = 0;
1356 }
1357 }
1358 var min = index;
1359 var max = length;
1360 if (UseSparseVariant(array, length, IS_ARRAY(array), max - min)) {
1361 %NormalizeElements(array);
1362 var indices = %GetArrayKeys(array, length);
1363 if (IS_NUMBER(indices)) {
1364 // It's an interval.
1365 max = indices; // Capped by length already.
1366 // Fall through to loop below.
1367 } else {
1368 if (indices.length == 0) return -1;
1369 // Get all the keys in sorted order.
1370 var sortedKeys = GetSortedArrayKeys(array, indices);
1371 var n = sortedKeys.length;
1372 var i = 0;
1373 while (i < n && sortedKeys[i] < index) i++;
1374 while (i < n) {
1375 var key = sortedKeys[i];
Ben Murdochda12d292016-06-02 14:46:10 +01001376 if (array[key] === element) return key;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 i++;
1378 }
1379 return -1;
1380 }
1381 }
1382 // Lookup through the array.
1383 if (!IS_UNDEFINED(element)) {
1384 for (var i = min; i < max; i++) {
1385 if (array[i] === element) return i;
1386 }
1387 return -1;
1388 }
1389 // Lookup through the array.
1390 for (var i = min; i < max; i++) {
1391 if (IS_UNDEFINED(array[i]) && i in array) {
1392 return i;
1393 }
1394 }
1395 return -1;
1396}
1397
1398
1399function ArrayIndexOf(element, index) {
1400 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.indexOf");
1401
Ben Murdoch097c5b22016-05-18 11:27:45 +01001402 var length = TO_LENGTH(this.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 return InnerArrayIndexOf(this, element, index, length);
1404}
1405
1406
1407function InnerArrayLastIndexOf(array, element, index, length, argumentsLength) {
1408 if (length == 0) return -1;
1409 if (argumentsLength < 2) {
1410 index = length - 1;
1411 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001412 index = TO_INTEGER(index) + 0; // Add 0 to convert -0 to 0
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 // If index is negative, index from end of the array.
1414 if (index < 0) index += length;
1415 // If index is still negative, do not search the array.
1416 if (index < 0) return -1;
1417 else if (index >= length) index = length - 1;
1418 }
1419 var min = 0;
1420 var max = index;
1421 if (UseSparseVariant(array, length, IS_ARRAY(array), index)) {
1422 %NormalizeElements(array);
1423 var indices = %GetArrayKeys(array, index + 1);
1424 if (IS_NUMBER(indices)) {
1425 // It's an interval.
1426 max = indices; // Capped by index already.
1427 // Fall through to loop below.
1428 } else {
1429 if (indices.length == 0) return -1;
1430 // Get all the keys in sorted order.
1431 var sortedKeys = GetSortedArrayKeys(array, indices);
1432 var i = sortedKeys.length - 1;
1433 while (i >= 0) {
1434 var key = sortedKeys[i];
Ben Murdochda12d292016-06-02 14:46:10 +01001435 if (array[key] === element) return key;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001436 i--;
1437 }
1438 return -1;
1439 }
1440 }
1441 // Lookup through the array.
1442 if (!IS_UNDEFINED(element)) {
1443 for (var i = max; i >= min; i--) {
1444 if (array[i] === element) return i;
1445 }
1446 return -1;
1447 }
1448 for (var i = max; i >= min; i--) {
1449 if (IS_UNDEFINED(array[i]) && i in array) {
1450 return i;
1451 }
1452 }
1453 return -1;
1454}
1455
1456
1457function ArrayLastIndexOf(element, index) {
1458 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf");
1459
Ben Murdoch097c5b22016-05-18 11:27:45 +01001460 var length = TO_LENGTH(this.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 return InnerArrayLastIndexOf(this, element, index, length,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001462 arguments.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001463}
1464
1465
1466function InnerArrayReduce(callback, current, array, length, argumentsLength) {
1467 if (!IS_CALLABLE(callback)) {
1468 throw MakeTypeError(kCalledNonCallable, callback);
1469 }
1470
1471 var is_array = IS_ARRAY(array);
1472 var i = 0;
1473 find_initial: if (argumentsLength < 2) {
1474 for (; i < length; i++) {
1475 if (HAS_INDEX(array, i, is_array)) {
1476 current = array[i++];
1477 break find_initial;
1478 }
1479 }
1480 throw MakeTypeError(kReduceNoInitial);
1481 }
1482
1483 for (; i < length; i++) {
1484 if (HAS_INDEX(array, i, is_array)) {
1485 var element = array[i];
1486 current = callback(current, element, i, array);
1487 }
1488 }
1489 return current;
1490}
1491
1492
1493function ArrayReduce(callback, current) {
1494 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce");
1495
1496 // Pull out the length so that modifications to the length in the
1497 // loop will not affect the looping and side effects are visible.
1498 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001499 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 return InnerArrayReduce(callback, current, array, length,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001501 arguments.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502}
1503
1504
1505function InnerArrayReduceRight(callback, current, array, length,
1506 argumentsLength) {
1507 if (!IS_CALLABLE(callback)) {
1508 throw MakeTypeError(kCalledNonCallable, callback);
1509 }
1510
1511 var is_array = IS_ARRAY(array);
1512 var i = length - 1;
1513 find_initial: if (argumentsLength < 2) {
1514 for (; i >= 0; i--) {
1515 if (HAS_INDEX(array, i, is_array)) {
1516 current = array[i--];
1517 break find_initial;
1518 }
1519 }
1520 throw MakeTypeError(kReduceNoInitial);
1521 }
1522
1523 for (; i >= 0; i--) {
1524 if (HAS_INDEX(array, i, is_array)) {
1525 var element = array[i];
1526 current = callback(current, element, i, array);
1527 }
1528 }
1529 return current;
1530}
1531
1532
1533function ArrayReduceRight(callback, current) {
1534 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduceRight");
1535
1536 // Pull out the length so that side effects are visible before the
1537 // callback function is checked.
1538 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001539 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001540 return InnerArrayReduceRight(callback, current, array, length,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001541 arguments.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542}
1543
1544
1545function InnerArrayCopyWithin(target, start, end, array, length) {
1546 target = TO_INTEGER(target);
1547 var to;
1548 if (target < 0) {
1549 to = MaxSimple(length + target, 0);
1550 } else {
1551 to = MinSimple(target, length);
1552 }
1553
1554 start = TO_INTEGER(start);
1555 var from;
1556 if (start < 0) {
1557 from = MaxSimple(length + start, 0);
1558 } else {
1559 from = MinSimple(start, length);
1560 }
1561
1562 end = IS_UNDEFINED(end) ? length : TO_INTEGER(end);
1563 var final;
1564 if (end < 0) {
1565 final = MaxSimple(length + end, 0);
1566 } else {
1567 final = MinSimple(end, length);
1568 }
1569
1570 var count = MinSimple(final - from, length - to);
1571 var direction = 1;
1572 if (from < to && to < (from + count)) {
1573 direction = -1;
1574 from = from + count - 1;
1575 to = to + count - 1;
1576 }
1577
1578 while (count > 0) {
1579 if (from in array) {
1580 array[to] = array[from];
1581 } else {
1582 delete array[to];
1583 }
1584 from = from + direction;
1585 to = to + direction;
1586 count--;
1587 }
1588
1589 return array;
1590}
1591
1592
1593// ES6 draft 03-17-15, section 22.1.3.3
1594function ArrayCopyWithin(target, start, end) {
1595 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
1596
1597 var array = TO_OBJECT(this);
1598 var length = TO_LENGTH(array.length);
1599
1600 return InnerArrayCopyWithin(target, start, end, array, length);
1601}
1602
1603
1604function InnerArrayFind(predicate, thisArg, array, length) {
1605 if (!IS_CALLABLE(predicate)) {
1606 throw MakeTypeError(kCalledNonCallable, predicate);
1607 }
1608
1609 for (var i = 0; i < length; i++) {
1610 var element = array[i];
1611 if (%_Call(predicate, thisArg, element, i, array)) {
1612 return element;
1613 }
1614 }
1615
1616 return;
1617}
1618
1619
1620// ES6 draft 07-15-13, section 15.4.3.23
1621function ArrayFind(predicate, thisArg) {
1622 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find");
1623
1624 var array = TO_OBJECT(this);
1625 var length = TO_INTEGER(array.length);
1626
1627 return InnerArrayFind(predicate, thisArg, array, length);
1628}
1629
1630
1631function InnerArrayFindIndex(predicate, thisArg, array, length) {
1632 if (!IS_CALLABLE(predicate)) {
1633 throw MakeTypeError(kCalledNonCallable, predicate);
1634 }
1635
1636 for (var i = 0; i < length; i++) {
1637 var element = array[i];
1638 if (%_Call(predicate, thisArg, element, i, array)) {
1639 return i;
1640 }
1641 }
1642
1643 return -1;
1644}
1645
1646
1647// ES6 draft 07-15-13, section 15.4.3.24
1648function ArrayFindIndex(predicate, thisArg) {
1649 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex");
1650
1651 var array = TO_OBJECT(this);
1652 var length = TO_INTEGER(array.length);
1653
1654 return InnerArrayFindIndex(predicate, thisArg, array, length);
1655}
1656
1657
1658// ES6, draft 04-05-14, section 22.1.3.6
1659function InnerArrayFill(value, start, end, array, length) {
1660 var i = IS_UNDEFINED(start) ? 0 : TO_INTEGER(start);
1661 var end = IS_UNDEFINED(end) ? length : TO_INTEGER(end);
1662
1663 if (i < 0) {
1664 i += length;
1665 if (i < 0) i = 0;
1666 } else {
1667 if (i > length) i = length;
1668 }
1669
1670 if (end < 0) {
1671 end += length;
1672 if (end < 0) end = 0;
1673 } else {
1674 if (end > length) end = length;
1675 }
1676
1677 if ((end - i) > 0 && %object_is_frozen(array)) {
1678 throw MakeTypeError(kArrayFunctionsOnFrozen);
1679 }
1680
1681 for (; i < end; i++)
1682 array[i] = value;
1683 return array;
1684}
1685
1686
1687// ES6, draft 04-05-14, section 22.1.3.6
1688function ArrayFill(value, start, end) {
1689 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill");
1690
1691 var array = TO_OBJECT(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001692 var length = TO_LENGTH(array.length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001693
1694 return InnerArrayFill(value, start, end, array, length);
1695}
1696
1697
1698function InnerArrayIncludes(searchElement, fromIndex, array, length) {
1699 if (length === 0) {
1700 return false;
1701 }
1702
1703 var n = TO_INTEGER(fromIndex);
1704
1705 var k;
1706 if (n >= 0) {
1707 k = n;
1708 } else {
1709 k = length + n;
1710 if (k < 0) {
1711 k = 0;
1712 }
1713 }
1714
1715 while (k < length) {
1716 var elementK = array[k];
Ben Murdoch097c5b22016-05-18 11:27:45 +01001717 if (%SameValueZero(searchElement, elementK)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001718 return true;
1719 }
1720
1721 ++k;
1722 }
1723
1724 return false;
1725}
1726
1727
1728// ES2016 draft, section 22.1.3.11
1729function ArrayIncludes(searchElement, fromIndex) {
1730 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.includes");
1731
1732 var array = TO_OBJECT(this);
1733 var length = TO_LENGTH(array.length);
1734
1735 return InnerArrayIncludes(searchElement, fromIndex, array, length);
1736}
1737
1738
1739function AddArrayElement(constructor, array, i, value) {
1740 if (constructor === GlobalArray) {
1741 AddIndexedProperty(array, i, value);
1742 } else {
1743 ObjectDefineProperty(array, i, {
1744 value: value, writable: true, configurable: true, enumerable: true
1745 });
1746 }
1747}
1748
1749
1750// ES6, draft 10-14-14, section 22.1.2.1
1751function ArrayFrom(arrayLike, mapfn, receiver) {
1752 var items = TO_OBJECT(arrayLike);
1753 var mapping = !IS_UNDEFINED(mapfn);
1754
1755 if (mapping) {
1756 if (!IS_CALLABLE(mapfn)) {
1757 throw MakeTypeError(kCalledNonCallable, mapfn);
1758 }
1759 }
1760
1761 var iterable = GetMethod(items, iteratorSymbol);
1762 var k;
1763 var result;
1764 var mappedValue;
1765 var nextValue;
1766
1767 if (!IS_UNDEFINED(iterable)) {
1768 result = %IsConstructor(this) ? new this() : [];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001769 k = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770
Ben Murdoch097c5b22016-05-18 11:27:45 +01001771 for (nextValue of
1772 { [iteratorSymbol]() { return GetIterator(items, iterable) } }) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001773 if (mapping) {
1774 mappedValue = %_Call(mapfn, receiver, nextValue, k);
1775 } else {
1776 mappedValue = nextValue;
1777 }
1778 AddArrayElement(this, result, k, mappedValue);
1779 k++;
1780 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001781 result.length = k;
1782 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001783 } else {
1784 var len = TO_LENGTH(items.length);
1785 result = %IsConstructor(this) ? new this(len) : new GlobalArray(len);
1786
1787 for (k = 0; k < len; ++k) {
1788 nextValue = items[k];
1789 if (mapping) {
1790 mappedValue = %_Call(mapfn, receiver, nextValue, k);
1791 } else {
1792 mappedValue = nextValue;
1793 }
1794 AddArrayElement(this, result, k, mappedValue);
1795 }
1796
1797 result.length = k;
1798 return result;
1799 }
1800}
1801
1802
1803// ES6, draft 05-22-14, section 22.1.2.3
Ben Murdoch097c5b22016-05-18 11:27:45 +01001804function ArrayOf(...args) {
1805 var length = args.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001806 var constructor = this;
1807 // TODO: Implement IsConstructor (ES6 section 7.2.5)
1808 var array = %IsConstructor(constructor) ? new constructor(length) : [];
1809 for (var i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001810 AddArrayElement(constructor, array, i, args[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001811 }
1812 array.length = length;
1813 return array;
1814}
1815
1816// -------------------------------------------------------------------
1817
1818// Set up non-enumerable constructor property on the Array.prototype
1819// object.
1820%AddNamedProperty(GlobalArray.prototype, "constructor", GlobalArray,
1821 DONT_ENUM);
1822
1823// Set up unscopable properties on the Array.prototype object.
1824var unscopables = {
1825 __proto__: null,
1826 copyWithin: true,
1827 entries: true,
1828 fill: true,
1829 find: true,
1830 findIndex: true,
1831 keys: true,
1832};
1833
1834%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
1835 DONT_ENUM | READ_ONLY);
1836
1837%FunctionSetLength(ArrayFrom, 1);
1838
1839// Set up non-enumerable functions on the Array object.
1840utils.InstallFunctions(GlobalArray, DONT_ENUM, [
1841 "from", ArrayFrom,
1842 "of", ArrayOf
1843]);
1844
1845var specialFunctions = %SpecialArrayFunctions();
1846
1847var getFunction = function(name, jsBuiltin, len) {
1848 var f = jsBuiltin;
1849 if (specialFunctions.hasOwnProperty(name)) {
1850 f = specialFunctions[name];
1851 }
1852 if (!IS_UNDEFINED(len)) {
1853 %FunctionSetLength(f, len);
1854 }
1855 return f;
1856};
1857
1858// Set up non-enumerable functions of the Array.prototype object and
1859// set their names.
1860// Manipulate the length of some of the functions to meet
1861// expectations set by ECMA-262 or Mozilla.
1862utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
1863 "toString", getFunction("toString", ArrayToString),
1864 "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
1865 "join", getFunction("join", ArrayJoin),
1866 "pop", getFunction("pop", ArrayPop),
1867 "push", getFunction("push", ArrayPush, 1),
1868 "reverse", getFunction("reverse", ArrayReverse),
1869 "shift", getFunction("shift", ArrayShift),
1870 "unshift", getFunction("unshift", ArrayUnshift, 1),
1871 "slice", getFunction("slice", ArraySlice, 2),
1872 "splice", getFunction("splice", ArraySplice, 2),
1873 "sort", getFunction("sort", ArraySort),
1874 "filter", getFunction("filter", ArrayFilter, 1),
1875 "forEach", getFunction("forEach", ArrayForEach, 1),
1876 "some", getFunction("some", ArraySome, 1),
1877 "every", getFunction("every", ArrayEvery, 1),
1878 "map", getFunction("map", ArrayMap, 1),
1879 "indexOf", getFunction("indexOf", ArrayIndexOf, 1),
1880 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
1881 "reduce", getFunction("reduce", ArrayReduce, 1),
1882 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1),
1883 "copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2),
1884 "find", getFunction("find", ArrayFind, 1),
1885 "findIndex", getFunction("findIndex", ArrayFindIndex, 1),
1886 "fill", getFunction("fill", ArrayFill, 1),
1887 "includes", getFunction("includes", ArrayIncludes, 1),
1888]);
1889
1890%FinishArrayPrototypeSetup(GlobalArray.prototype);
1891
1892// The internal Array prototype doesn't need to be fancy, since it's never
1893// exposed to user code.
1894// Adding only the functions that are actually used.
1895utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [
1896 "indexOf", getFunction("indexOf", ArrayIndexOf),
1897 "join", getFunction("join", ArrayJoin),
1898 "pop", getFunction("pop", ArrayPop),
1899 "push", getFunction("push", ArrayPush),
1900 "shift", getFunction("shift", ArrayShift),
1901 "sort", getFunction("sort", ArraySort),
1902 "splice", getFunction("splice", ArraySplice)
1903]);
1904
1905utils.SetUpLockedPrototype(InternalPackedArray, GlobalArray(), [
1906 "join", getFunction("join", ArrayJoin),
1907 "pop", getFunction("pop", ArrayPop),
1908 "push", getFunction("push", ArrayPush),
1909 "shift", getFunction("shift", ArrayShift)
1910]);
1911
1912// V8 extras get a separate copy of InternalPackedArray. We give them the basic
1913// manipulation methods.
1914utils.SetUpLockedPrototype(extrasUtils.InternalPackedArray, GlobalArray(), [
1915 "push", getFunction("push", ArrayPush),
1916 "pop", getFunction("pop", ArrayPop),
1917 "shift", getFunction("shift", ArrayShift),
1918 "unshift", getFunction("unshift", ArrayUnshift),
1919 "splice", getFunction("splice", ArraySplice),
1920 "slice", getFunction("slice", ArraySlice)
1921]);
1922
1923// -------------------------------------------------------------------
1924// Exports
1925
1926utils.Export(function(to) {
1927 to.ArrayFrom = ArrayFrom;
1928 to.ArrayIndexOf = ArrayIndexOf;
1929 to.ArrayJoin = ArrayJoin;
1930 to.ArrayPush = ArrayPush;
1931 to.ArrayToString = ArrayToString;
1932 to.InnerArrayCopyWithin = InnerArrayCopyWithin;
1933 to.InnerArrayEvery = InnerArrayEvery;
1934 to.InnerArrayFill = InnerArrayFill;
1935 to.InnerArrayFilter = InnerArrayFilter;
1936 to.InnerArrayFind = InnerArrayFind;
1937 to.InnerArrayFindIndex = InnerArrayFindIndex;
1938 to.InnerArrayForEach = InnerArrayForEach;
1939 to.InnerArrayIncludes = InnerArrayIncludes;
1940 to.InnerArrayIndexOf = InnerArrayIndexOf;
1941 to.InnerArrayJoin = InnerArrayJoin;
1942 to.InnerArrayLastIndexOf = InnerArrayLastIndexOf;
1943 to.InnerArrayReduce = InnerArrayReduce;
1944 to.InnerArrayReduceRight = InnerArrayReduceRight;
1945 to.InnerArraySome = InnerArraySome;
1946 to.InnerArraySort = InnerArraySort;
1947 to.InnerArrayToLocaleString = InnerArrayToLocaleString;
1948 to.PackedArrayReverse = PackedArrayReverse;
Ben Murdochda12d292016-06-02 14:46:10 +01001949 to.Stack = Stack;
1950 to.StackHas = StackHas;
1951 to.StackPush = StackPush;
1952 to.StackPop = StackPop;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001953});
1954
1955%InstallToContext([
1956 "array_pop", ArrayPop,
1957 "array_push", ArrayPush,
1958 "array_shift", ArrayShift,
1959 "array_splice", ArraySplice,
1960 "array_slice", ArraySlice,
1961 "array_unshift", ArrayUnshift,
1962]);
1963
1964});