blob: 1298434d5975cec4cc3deed9a989765938ae49b1 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// This file relies on the fact that the following declarations have been made
29// in runtime.js:
30// const $Array = global.Array;
31
32// -------------------------------------------------------------------
33
34// Global list of arrays visited during toString, toLocaleString and
35// join invocations.
36var visited_arrays = new $Array();
37
38
39// Gets a sorted array of array keys. Useful for operations on sparse
40// arrays. Dupes have not been removed.
41function GetSortedArrayKeys(array, intervals) {
42 var length = intervals.length;
43 var keys = [];
44 for (var k = 0; k < length; k++) {
45 var key = intervals[k];
46 if (key < 0) {
47 var j = -1 - key;
48 var limit = j + intervals[++k];
49 for (; j < limit; j++) {
50 var e = array[j];
51 if (!IS_UNDEFINED(e) || j in array) {
52 keys.push(j);
53 }
54 }
55 } else {
56 // The case where key is undefined also ends here.
57 if (!IS_UNDEFINED(key)) {
58 var e = array[key];
59 if (!IS_UNDEFINED(e) || key in array) {
60 keys.push(key);
61 }
62 }
63 }
64 }
65 keys.sort(function(a, b) { return a - b; });
66 return keys;
67}
68
69
70// Optimized for sparse arrays if separator is ''.
71function SparseJoin(array, len, convert) {
72 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
Steve Blocka7e24c12009-10-30 11:49:00 +000073 var last_key = -1;
74 var keys_length = keys.length;
Leon Clarkee46be812010-01-19 14:06:41 +000075
76 var elements = new $Array(keys_length);
77 var elements_length = 0;
78
Steve Blocka7e24c12009-10-30 11:49:00 +000079 for (var i = 0; i < keys_length; i++) {
80 var key = keys[i];
81 if (key != last_key) {
82 var e = array[key];
Leon Clarkee46be812010-01-19 14:06:41 +000083 if (!IS_STRING(e)) e = convert(e);
84 elements[elements_length++] = e;
Steve Blocka7e24c12009-10-30 11:49:00 +000085 last_key = key;
86 }
87 }
Leon Clarkee46be812010-01-19 14:06:41 +000088 return %StringBuilderConcat(elements, elements_length, '');
Steve Blocka7e24c12009-10-30 11:49:00 +000089}
90
91
92function UseSparseVariant(object, length, is_array) {
93 return is_array &&
94 length > 1000 &&
95 (!%_IsSmi(length) ||
96 %EstimateNumberOfElements(object) < (length >> 2));
97}
98
99
100function Join(array, length, separator, convert) {
101 if (length == 0) return '';
102
103 var is_array = IS_ARRAY(array);
104
105 if (is_array) {
106 // If the array is cyclic, return the empty string for already
107 // visited arrays.
108 if (!%PushIfAbsent(visited_arrays, array)) return '';
109 }
110
111 // Attempt to convert the elements.
112 try {
Leon Clarkee46be812010-01-19 14:06:41 +0000113 if (UseSparseVariant(array, length, is_array) && (separator.length == 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 return SparseJoin(array, length, convert);
115 }
116
117 // Fast case for one-element arrays.
118 if (length == 1) {
119 var e = array[0];
Ben Murdochb8e0da22011-05-16 14:20:40 +0100120 if (IS_STRING(e)) return e;
121 return convert(e);
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 }
123
Leon Clarkee46be812010-01-19 14:06:41 +0000124 // Construct an array for the elements.
Ben Murdoch086aeea2011-05-13 15:57:08 +0100125 var elements = new $Array(length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126
Steve Blockd0582a62009-12-15 09:54:21 +0000127 // We pull the empty separator check outside the loop for speed!
128 if (separator.length == 0) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100129 var elements_length = 0;
Steve Blockd0582a62009-12-15 09:54:21 +0000130 for (var i = 0; i < length; i++) {
131 var e = array[i];
Ben Murdoch086aeea2011-05-13 15:57:08 +0100132 if (!IS_UNDEFINED(e)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000133 if (!IS_STRING(e)) e = convert(e);
134 elements[elements_length++] = e;
Steve Blockd0582a62009-12-15 09:54:21 +0000135 }
136 }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100137 elements.length = elements_length;
138 var result = %_FastAsciiArrayJoin(elements, '');
139 if (!IS_UNDEFINED(result)) return result;
140 return %StringBuilderConcat(elements, elements_length, '');
141 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100142 // Non-empty separator case.
143 // If the first element is a number then use the heuristic that the
144 // remaining elements are also likely to be numbers.
145 if (!IS_NUMBER(array[0])) {
146 for (var i = 0; i < length; i++) {
147 var e = array[i];
Ben Murdoch086aeea2011-05-13 15:57:08 +0100148 if (!IS_STRING(e)) e = convert(e);
149 elements[i] = e;
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100151 } else {
152 for (var i = 0; i < length; i++) {
153 var e = array[i];
154 if (IS_NUMBER(e)) elements[i] = %_NumberToString(e);
155 else {
156 if (!IS_STRING(e)) e = convert(e);
157 elements[i] = e;
158 }
159 }
160 }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100161 var result = %_FastAsciiArrayJoin(elements, separator);
162 if (!IS_UNDEFINED(result)) return result;
163
164 var length2 = (length << 1) - 1;
165 var j = length2;
166 var i = length;
167 elements[--j] = elements[--i];
168 while (i > 0) {
169 elements[--j] = separator;
170 elements[--j] = elements[--i];
171 }
172 return %StringBuilderConcat(elements, length2, '');
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 } finally {
Steve Block1e0659c2011-05-24 12:43:12 +0100174 // Make sure to remove the last element of the visited array no
175 // matter what happens.
176 if (is_array) visited_arrays.length = visited_arrays.length - 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 }
178}
179
180
Ben Murdochb0fe1622011-05-05 13:52:32 +0100181function ConvertToString(x) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100182 // Assumes x is a non-string.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100183 if (IS_NUMBER(x)) return %_NumberToString(x);
184 if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
185 return (IS_NULL_OR_UNDEFINED(x)) ? '' : %ToString(%DefaultString(x));
Steve Blocka7e24c12009-10-30 11:49:00 +0000186}
187
188
189function ConvertToLocaleString(e) {
Leon Clarkee46be812010-01-19 14:06:41 +0000190 if (e == null) {
191 return '';
192 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 // e_obj's toLocaleString might be overwritten, check if it is a function.
194 // Call ToString if toLocaleString is not a function.
195 // See issue 877615.
196 var e_obj = ToObject(e);
197 if (IS_FUNCTION(e_obj.toLocaleString))
Steve Blockd0582a62009-12-15 09:54:21 +0000198 return ToString(e_obj.toLocaleString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 else
200 return ToString(e);
201 }
202}
203
204
205// This function implements the optimized splice implementation that can use
206// special array operations to handle sparse arrays in a sensible fashion.
207function SmartSlice(array, start_i, del_count, len, deleted_elements) {
208 // Move deleted elements to a new array (the return value from splice).
209 // Intervals array can contain keys and intervals. See comment in Concat.
210 var intervals = %GetArrayKeys(array, start_i + del_count);
211 var length = intervals.length;
212 for (var k = 0; k < length; k++) {
213 var key = intervals[k];
214 if (key < 0) {
215 var j = -1 - key;
216 var interval_limit = j + intervals[++k];
217 if (j < start_i) {
218 j = start_i;
219 }
220 for (; j < interval_limit; j++) {
221 // ECMA-262 15.4.4.12 line 10. The spec could also be
222 // interpreted such that %HasLocalProperty would be the
223 // appropriate test. We follow KJS in consulting the
224 // prototype.
225 var current = array[j];
226 if (!IS_UNDEFINED(current) || j in array) {
227 deleted_elements[j - start_i] = current;
228 }
229 }
230 } else {
231 if (!IS_UNDEFINED(key)) {
232 if (key >= start_i) {
233 // ECMA-262 15.4.4.12 line 10. The spec could also be
234 // interpreted such that %HasLocalProperty would be the
235 // appropriate test. We follow KJS in consulting the
236 // prototype.
237 var current = array[key];
238 if (!IS_UNDEFINED(current) || key in array) {
239 deleted_elements[key - start_i] = current;
240 }
241 }
242 }
243 }
244 }
245}
246
247
248// This function implements the optimized splice implementation that can use
249// special array operations to handle sparse arrays in a sensible fashion.
250function SmartMove(array, start_i, del_count, len, num_additional_args) {
251 // Move data to new array.
252 var new_array = new $Array(len - del_count + num_additional_args);
253 var intervals = %GetArrayKeys(array, len);
254 var length = intervals.length;
255 for (var k = 0; k < length; k++) {
256 var key = intervals[k];
257 if (key < 0) {
258 var j = -1 - key;
259 var interval_limit = j + intervals[++k];
260 while (j < start_i && j < interval_limit) {
261 // The spec could also be interpreted such that
262 // %HasLocalProperty would be the appropriate test. We follow
263 // KJS in consulting the prototype.
264 var current = array[j];
265 if (!IS_UNDEFINED(current) || j in array) {
266 new_array[j] = current;
267 }
268 j++;
269 }
270 j = start_i + del_count;
271 while (j < interval_limit) {
272 // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also be
273 // interpreted such that %HasLocalProperty would be the
274 // appropriate test. We follow KJS in consulting the
275 // prototype.
276 var current = array[j];
277 if (!IS_UNDEFINED(current) || j in array) {
278 new_array[j - del_count + num_additional_args] = current;
279 }
280 j++;
281 }
282 } else {
283 if (!IS_UNDEFINED(key)) {
284 if (key < start_i) {
285 // The spec could also be interpreted such that
286 // %HasLocalProperty would be the appropriate test. We follow
287 // KJS in consulting the prototype.
288 var current = array[key];
289 if (!IS_UNDEFINED(current) || key in array) {
290 new_array[key] = current;
291 }
292 } else if (key >= start_i + del_count) {
293 // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also
294 // be interpreted such that %HasLocalProperty would be the
295 // appropriate test. We follow KJS in consulting the
296 // prototype.
297 var current = array[key];
298 if (!IS_UNDEFINED(current) || key in array) {
299 new_array[key - del_count + num_additional_args] = current;
300 }
301 }
302 }
303 }
304 }
305 // Move contents of new_array into this array
306 %MoveArrayContents(new_array, array);
307}
308
309
310// This is part of the old simple-minded splice. We are using it either
311// because the receiver is not an array (so we have no choice) or because we
312// know we are not deleting or moving a lot of elements.
313function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
314 for (var i = 0; i < del_count; i++) {
315 var index = start_i + i;
316 // The spec could also be interpreted such that %HasLocalProperty
317 // would be the appropriate test. We follow KJS in consulting the
318 // prototype.
319 var current = array[index];
320 if (!IS_UNDEFINED(current) || index in array)
321 deleted_elements[i] = current;
322 }
323}
324
325
326function SimpleMove(array, start_i, del_count, len, num_additional_args) {
327 if (num_additional_args !== del_count) {
328 // Move the existing elements after the elements to be deleted
329 // to the right position in the resulting array.
330 if (num_additional_args > del_count) {
331 for (var i = len - del_count; i > start_i; i--) {
332 var from_index = i + del_count - 1;
333 var to_index = i + num_additional_args - 1;
334 // The spec could also be interpreted such that
335 // %HasLocalProperty would be the appropriate test. We follow
336 // KJS in consulting the prototype.
337 var current = array[from_index];
338 if (!IS_UNDEFINED(current) || from_index in array) {
339 array[to_index] = current;
340 } else {
341 delete array[to_index];
342 }
343 }
344 } else {
345 for (var i = start_i; i < len - del_count; i++) {
346 var from_index = i + del_count;
347 var to_index = i + num_additional_args;
348 // The spec could also be interpreted such that
349 // %HasLocalProperty would be the appropriate test. We follow
350 // KJS in consulting the prototype.
351 var current = array[from_index];
352 if (!IS_UNDEFINED(current) || from_index in array) {
353 array[to_index] = current;
354 } else {
355 delete array[to_index];
356 }
357 }
358 for (var i = len; i > len - del_count + num_additional_args; i--) {
359 delete array[i - 1];
360 }
361 }
362 }
363}
364
365
366// -------------------------------------------------------------------
367
368
369function ArrayToString() {
370 if (!IS_ARRAY(this)) {
371 throw new $TypeError('Array.prototype.toString is not generic');
372 }
373 return Join(this, this.length, ',', ConvertToString);
374}
375
376
377function ArrayToLocaleString() {
378 if (!IS_ARRAY(this)) {
379 throw new $TypeError('Array.prototype.toString is not generic');
380 }
381 return Join(this, this.length, ',', ConvertToLocaleString);
382}
383
384
385function ArrayJoin(separator) {
Leon Clarkee46be812010-01-19 14:06:41 +0000386 if (IS_UNDEFINED(separator)) {
387 separator = ',';
388 } else if (!IS_STRING(separator)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100389 separator = NonStringToString(separator);
Leon Clarkee46be812010-01-19 14:06:41 +0000390 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800391
392 var result = %_FastAsciiArrayJoin(this, separator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100393 if (!IS_UNDEFINED(result)) return result;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800394
Ben Murdochb0fe1622011-05-05 13:52:32 +0100395 return Join(this, TO_UINT32(this.length), separator, ConvertToString);
Steve Blocka7e24c12009-10-30 11:49:00 +0000396}
397
398
399// Removes the last element from the array and returns it. See
400// ECMA-262, section 15.4.4.6.
401function ArrayPop() {
Leon Clarkee46be812010-01-19 14:06:41 +0000402 var n = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 if (n == 0) {
404 this.length = n;
405 return;
406 }
407 n--;
408 var value = this[n];
409 this.length = n;
410 delete this[n];
411 return value;
412}
413
414
415// Appends the arguments to the end of the array and returns the new
416// length of the array. See ECMA-262, section 15.4.4.7.
417function ArrayPush() {
Leon Clarkee46be812010-01-19 14:06:41 +0000418 var n = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 var m = %_ArgumentsLength();
420 for (var i = 0; i < m; i++) {
421 this[i+n] = %_Arguments(i);
422 }
423 this.length = n + m;
424 return this.length;
425}
426
427
428function ArrayConcat(arg1) { // length == 1
429 // TODO: can we just use arguments?
430 var arg_count = %_ArgumentsLength();
431 var arrays = new $Array(1 + arg_count);
432 arrays[0] = this;
433 for (var i = 0; i < arg_count; i++) {
434 arrays[i + 1] = %_Arguments(i);
435 }
436
437 return %ArrayConcat(arrays);
438}
439
440
441// For implementing reverse() on large, sparse arrays.
442function SparseReverse(array, len) {
443 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
444 var high_counter = keys.length - 1;
445 var low_counter = 0;
446 while (low_counter <= high_counter) {
447 var i = keys[low_counter];
448 var j = keys[high_counter];
449
450 var j_complement = len - j - 1;
451 var low, high;
452
453 if (j_complement <= i) {
454 high = j;
455 while (keys[--high_counter] == j);
456 low = j_complement;
457 }
458 if (j_complement >= i) {
459 low = i;
460 while (keys[++low_counter] == i);
461 high = len - i - 1;
462 }
463
464 var current_i = array[low];
465 if (!IS_UNDEFINED(current_i) || low in array) {
466 var current_j = array[high];
467 if (!IS_UNDEFINED(current_j) || high in array) {
468 array[low] = current_j;
469 array[high] = current_i;
470 } else {
471 array[high] = current_i;
472 delete array[low];
473 }
474 } else {
475 var current_j = array[high];
476 if (!IS_UNDEFINED(current_j) || high in array) {
477 array[low] = current_j;
478 delete array[high];
479 }
480 }
481 }
482}
483
484
485function ArrayReverse() {
Leon Clarkee46be812010-01-19 14:06:41 +0000486 var j = TO_UINT32(this.length) - 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000487
488 if (UseSparseVariant(this, j, IS_ARRAY(this))) {
489 SparseReverse(this, j+1);
490 return this;
491 }
492
493 for (var i = 0; i < j; i++, j--) {
494 var current_i = this[i];
495 if (!IS_UNDEFINED(current_i) || i in this) {
496 var current_j = this[j];
497 if (!IS_UNDEFINED(current_j) || j in this) {
498 this[i] = current_j;
499 this[j] = current_i;
500 } else {
501 this[j] = current_i;
502 delete this[i];
503 }
504 } else {
505 var current_j = this[j];
506 if (!IS_UNDEFINED(current_j) || j in this) {
507 this[i] = current_j;
508 delete this[j];
509 }
510 }
511 }
512 return this;
513}
514
515
516function ArrayShift() {
Leon Clarkee46be812010-01-19 14:06:41 +0000517 var len = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000518
519 if (len === 0) {
520 this.length = 0;
521 return;
522 }
523
524 var first = this[0];
525
526 if (IS_ARRAY(this))
527 SmartMove(this, 0, 1, len, 0);
528 else
529 SimpleMove(this, 0, 1, len, 0);
530
531 this.length = len - 1;
532
533 return first;
534}
535
536
537function ArrayUnshift(arg1) { // length == 1
Leon Clarkee46be812010-01-19 14:06:41 +0000538 var len = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000539 var num_arguments = %_ArgumentsLength();
540
541 if (IS_ARRAY(this))
542 SmartMove(this, 0, 0, len, num_arguments);
543 else
544 SimpleMove(this, 0, 0, len, num_arguments);
545
546 for (var i = 0; i < num_arguments; i++) {
547 this[i] = %_Arguments(i);
548 }
549
550 this.length = len + num_arguments;
551
552 return len + num_arguments;
553}
554
555
556function ArraySlice(start, end) {
Leon Clarkee46be812010-01-19 14:06:41 +0000557 var len = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000558 var start_i = TO_INTEGER(start);
559 var end_i = len;
560
561 if (end !== void 0) end_i = TO_INTEGER(end);
562
563 if (start_i < 0) {
564 start_i += len;
565 if (start_i < 0) start_i = 0;
566 } else {
567 if (start_i > len) start_i = len;
568 }
569
570 if (end_i < 0) {
571 end_i += len;
572 if (end_i < 0) end_i = 0;
573 } else {
574 if (end_i > len) end_i = len;
575 }
576
577 var result = [];
578
579 if (end_i < start_i) return result;
580
581 if (IS_ARRAY(this)) {
582 SmartSlice(this, start_i, end_i - start_i, len, result);
583 } else {
584 SimpleSlice(this, start_i, end_i - start_i, len, result);
585 }
586
587 result.length = end_i - start_i;
588
589 return result;
590}
591
592
593function ArraySplice(start, delete_count) {
594 var num_arguments = %_ArgumentsLength();
595
Leon Clarkee46be812010-01-19 14:06:41 +0000596 var len = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 var start_i = TO_INTEGER(start);
598
599 if (start_i < 0) {
600 start_i += len;
601 if (start_i < 0) start_i = 0;
602 } else {
603 if (start_i > len) start_i = len;
604 }
605
Andrei Popescu402d9372010-02-26 13:31:12 +0000606 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
Steve Block1e0659c2011-05-24 12:43:12 +0100607 // given as a request to delete all the elements from the start.
608 // And it differs from the case of undefined delete count.
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 // This does not follow ECMA-262, but we do the same for
610 // compatibility.
611 var del_count = 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100612 if (num_arguments == 1) {
613 del_count = len - start_i;
614 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 del_count = TO_INTEGER(delete_count);
616 if (del_count < 0) del_count = 0;
617 if (del_count > len - start_i) del_count = len - start_i;
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 }
619
620 var deleted_elements = [];
621 deleted_elements.length = del_count;
622
623 // Number of elements to add.
624 var num_additional_args = 0;
625 if (num_arguments > 2) {
626 num_additional_args = num_arguments - 2;
627 }
628
629 var use_simple_splice = true;
630
631 if (IS_ARRAY(this) && num_additional_args !== del_count) {
632 // If we are only deleting/moving a few things near the end of the
633 // array then the simple version is going to be faster, because it
634 // doesn't touch most of the array.
635 var estimated_non_hole_elements = %EstimateNumberOfElements(this);
636 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) {
637 use_simple_splice = false;
638 }
639 }
640
641 if (use_simple_splice) {
642 SimpleSlice(this, start_i, del_count, len, deleted_elements);
643 SimpleMove(this, start_i, del_count, len, num_additional_args);
644 } else {
645 SmartSlice(this, start_i, del_count, len, deleted_elements);
646 SmartMove(this, start_i, del_count, len, num_additional_args);
647 }
648
649 // Insert the arguments into the resulting array in
650 // place of the deleted elements.
651 var i = start_i;
652 var arguments_index = 2;
653 var arguments_length = %_ArgumentsLength();
654 while (arguments_index < arguments_length) {
655 this[i++] = %_Arguments(arguments_index++);
656 }
657 this.length = len - del_count + num_additional_args;
658
659 // Return the deleted elements.
660 return deleted_elements;
661}
662
663
664function ArraySort(comparefn) {
665 // In-place QuickSort algorithm.
666 // For short (length <= 22) arrays, insertion sort is used for efficiency.
667
Steve Block6ded16b2010-05-10 14:33:55 +0100668 if (!IS_FUNCTION(comparefn)) {
669 comparefn = function (x, y) {
670 if (x === y) return 0;
671 if (%_IsSmi(x) && %_IsSmi(y)) {
672 return %SmiLexicographicCompare(x, y);
673 }
674 x = ToString(x);
675 y = ToString(y);
676 if (x == y) return 0;
677 else return x < y ? -1 : 1;
678 };
679 }
680 var global_receiver = %GetGlobalReceiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000681
682 function InsertionSort(a, from, to) {
683 for (var i = from + 1; i < to; i++) {
684 var element = a[i];
Steve Block6ded16b2010-05-10 14:33:55 +0100685 for (var j = i - 1; j >= from; j--) {
686 var tmp = a[j];
687 var order = %_CallFunction(global_receiver, tmp, element, comparefn);
688 if (order > 0) {
689 a[j + 1] = tmp;
690 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 break;
692 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 }
Steve Block6ded16b2010-05-10 14:33:55 +0100694 a[j + 1] = element;
Steve Blocka7e24c12009-10-30 11:49:00 +0000695 }
696 }
697
698 function QuickSort(a, from, to) {
699 // Insertion sort is faster for short arrays.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100700 if (to - from <= 10) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000701 InsertionSort(a, from, to);
702 return;
703 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100704 // Find a pivot as the median of first, last and middle element.
705 var v0 = a[from];
706 var v1 = a[to - 1];
707 var middle_index = from + ((to - from) >> 1);
708 var v2 = a[middle_index];
709 var c01 = %_CallFunction(global_receiver, v0, v1, comparefn);
710 if (c01 > 0) {
711 // v1 < v0, so swap them.
712 var tmp = v0;
713 v0 = v1;
714 v1 = tmp;
715 } // v0 <= v1.
716 var c02 = %_CallFunction(global_receiver, v0, v2, comparefn);
717 if (c02 >= 0) {
718 // v2 <= v0 <= v1.
719 var tmp = v0;
720 v0 = v2;
721 v2 = v1;
722 v1 = tmp;
723 } else {
724 // v0 <= v1 && v0 < v2
725 var c12 = %_CallFunction(global_receiver, v1, v2, comparefn);
726 if (c12 > 0) {
727 // v0 <= v2 < v1
728 var tmp = v1;
729 v1 = v2;
730 v2 = tmp;
731 }
732 }
733 // v0 <= v1 <= v2
734 a[from] = v0;
735 a[to - 1] = v2;
736 var pivot = v1;
737 var low_end = from + 1; // Upper bound of elements lower than pivot.
738 var high_start = to - 1; // Lower bound of elements greater than pivot.
739 a[middle_index] = a[low_end];
740 a[low_end] = pivot;
741
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 // From low_end to i are elements equal to pivot.
743 // From i to high_start are elements that haven't been compared yet.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100744 partition: for (var i = low_end + 1; i < high_start; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000745 var element = a[i];
Steve Block6ded16b2010-05-10 14:33:55 +0100746 var order = %_CallFunction(global_receiver, element, pivot, comparefn);
Steve Blocka7e24c12009-10-30 11:49:00 +0000747 if (order < 0) {
Steve Block6ded16b2010-05-10 14:33:55 +0100748 %_SwapElements(a, i, low_end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000749 low_end++;
750 } else if (order > 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100751 do {
752 high_start--;
753 if (high_start == i) break partition;
754 var top_elem = a[high_start];
755 order = %_CallFunction(global_receiver, top_elem, pivot, comparefn);
756 } while (order > 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100757 %_SwapElements(a, i, high_start);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100758 if (order < 0) {
759 %_SwapElements(a, i, low_end);
760 low_end++;
761 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 }
763 }
764 QuickSort(a, from, low_end);
765 QuickSort(a, high_start, to);
766 }
767
Ben Murdochb0fe1622011-05-05 13:52:32 +0100768 // Copy elements in the range 0..length from obj's prototype chain
769 // to obj itself, if obj has holes. Return one more than the maximal index
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 // of a prototype property.
771 function CopyFromPrototype(obj, length) {
772 var max = 0;
773 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
774 var indices = %GetArrayKeys(proto, length);
775 if (indices.length > 0) {
776 if (indices[0] == -1) {
777 // It's an interval.
778 var proto_length = indices[1];
779 for (var i = 0; i < proto_length; i++) {
780 if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
781 obj[i] = proto[i];
782 if (i >= max) { max = i + 1; }
783 }
784 }
785 } else {
786 for (var i = 0; i < indices.length; i++) {
787 var index = indices[i];
788 if (!IS_UNDEFINED(index) &&
789 !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
790 obj[index] = proto[index];
791 if (index >= max) { max = index + 1; }
792 }
793 }
794 }
795 }
796 }
797 return max;
798 }
799
800 // Set a value of "undefined" on all indices in the range from..to
801 // where a prototype of obj has an element. I.e., shadow all prototype
802 // elements in that range.
803 function ShadowPrototypeElements(obj, from, to) {
804 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
805 var indices = %GetArrayKeys(proto, to);
806 if (indices.length > 0) {
807 if (indices[0] == -1) {
808 // It's an interval.
809 var proto_length = indices[1];
810 for (var i = from; i < proto_length; i++) {
811 if (proto.hasOwnProperty(i)) {
812 obj[i] = void 0;
813 }
814 }
815 } else {
816 for (var i = 0; i < indices.length; i++) {
817 var index = indices[i];
818 if (!IS_UNDEFINED(index) && from <= index &&
819 proto.hasOwnProperty(index)) {
820 obj[index] = void 0;
821 }
822 }
823 }
824 }
825 }
826 }
827
828 function SafeRemoveArrayHoles(obj) {
829 // Copy defined elements from the end to fill in all holes and undefineds
830 // in the beginning of the array. Write undefineds and holes at the end
831 // after loop is finished.
832 var first_undefined = 0;
833 var last_defined = length - 1;
834 var num_holes = 0;
835 while (first_undefined < last_defined) {
836 // Find first undefined element.
837 while (first_undefined < last_defined &&
838 !IS_UNDEFINED(obj[first_undefined])) {
839 first_undefined++;
840 }
841 // Maintain the invariant num_holes = the number of holes in the original
842 // array with indices <= first_undefined or > last_defined.
843 if (!obj.hasOwnProperty(first_undefined)) {
844 num_holes++;
845 }
846
847 // Find last defined element.
848 while (first_undefined < last_defined &&
849 IS_UNDEFINED(obj[last_defined])) {
850 if (!obj.hasOwnProperty(last_defined)) {
851 num_holes++;
852 }
853 last_defined--;
854 }
855 if (first_undefined < last_defined) {
856 // Fill in hole or undefined.
857 obj[first_undefined] = obj[last_defined];
858 obj[last_defined] = void 0;
859 }
860 }
861 // If there were any undefineds in the entire array, first_undefined
862 // points to one past the last defined element. Make this true if
863 // there were no undefineds, as well, so that first_undefined == number
864 // of defined elements.
865 if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++;
866 // Fill in the undefineds and the holes. There may be a hole where
867 // an undefined should be and vice versa.
868 var i;
869 for (i = first_undefined; i < length - num_holes; i++) {
870 obj[i] = void 0;
871 }
872 for (i = length - num_holes; i < length; i++) {
873 // For compatability with Webkit, do not expose elements in the prototype.
874 if (i in obj.__proto__) {
875 obj[i] = void 0;
876 } else {
877 delete obj[i];
878 }
879 }
880
881 // Return the number of defined elements.
882 return first_undefined;
883 }
884
Steve Block6ded16b2010-05-10 14:33:55 +0100885 var length = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 if (length < 2) return this;
887
888 var is_array = IS_ARRAY(this);
889 var max_prototype_element;
890 if (!is_array) {
891 // For compatibility with JSC, we also sort elements inherited from
892 // the prototype chain on non-Array objects.
893 // We do this by copying them to this object and sorting only
894 // local elements. This is not very efficient, but sorting with
895 // inherited elements happens very, very rarely, if at all.
896 // The specification allows "implementation dependent" behavior
897 // if an element on the prototype chain has an element that
898 // might interact with sorting.
899 max_prototype_element = CopyFromPrototype(this, length);
900 }
901
902 var num_non_undefined = %RemoveArrayHoles(this, length);
903 if (num_non_undefined == -1) {
904 // There were indexed accessors in the array. Move array holes and
905 // undefineds to the end using a Javascript function that is safe
906 // in the presence of accessors.
907 num_non_undefined = SafeRemoveArrayHoles(this);
908 }
909
910 QuickSort(this, 0, num_non_undefined);
911
912 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {
913 // For compatibility with JSC, we shadow any elements in the prototype
914 // chain that has become exposed by sort moving a hole to its position.
915 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element);
916 }
917
918 return this;
919}
920
921
922// The following functions cannot be made efficient on sparse arrays while
923// preserving the semantics, since the calls to the receiver function can add
924// or delete elements from the array.
925function ArrayFilter(f, receiver) {
926 if (!IS_FUNCTION(f)) {
927 throw MakeTypeError('called_non_callable', [ f ]);
928 }
929 // Pull out the length so that modifications to the length in the
930 // loop will not affect the looping.
931 var length = this.length;
932 var result = [];
933 var result_length = 0;
934 for (var i = 0; i < length; i++) {
935 var current = this[i];
936 if (!IS_UNDEFINED(current) || i in this) {
937 if (f.call(receiver, current, i, this)) result[result_length++] = current;
938 }
939 }
940 return result;
941}
942
943
944function ArrayForEach(f, receiver) {
945 if (!IS_FUNCTION(f)) {
946 throw MakeTypeError('called_non_callable', [ f ]);
947 }
948 // Pull out the length so that modifications to the length in the
949 // loop will not affect the looping.
Leon Clarkee46be812010-01-19 14:06:41 +0000950 var length = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 for (var i = 0; i < length; i++) {
952 var current = this[i];
953 if (!IS_UNDEFINED(current) || i in this) {
954 f.call(receiver, current, i, this);
955 }
956 }
957}
958
959
960// Executes the function once for each element present in the
961// array until it finds one where callback returns true.
962function ArraySome(f, receiver) {
963 if (!IS_FUNCTION(f)) {
964 throw MakeTypeError('called_non_callable', [ f ]);
965 }
966 // Pull out the length so that modifications to the length in the
967 // loop will not affect the looping.
Leon Clarkee46be812010-01-19 14:06:41 +0000968 var length = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 for (var i = 0; i < length; i++) {
970 var current = this[i];
971 if (!IS_UNDEFINED(current) || i in this) {
972 if (f.call(receiver, current, i, this)) return true;
973 }
974 }
975 return false;
976}
977
978
979function ArrayEvery(f, receiver) {
980 if (!IS_FUNCTION(f)) {
981 throw MakeTypeError('called_non_callable', [ f ]);
982 }
983 // Pull out the length so that modifications to the length in the
984 // loop will not affect the looping.
Leon Clarkee46be812010-01-19 14:06:41 +0000985 var length = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 for (var i = 0; i < length; i++) {
987 var current = this[i];
988 if (!IS_UNDEFINED(current) || i in this) {
989 if (!f.call(receiver, current, i, this)) return false;
990 }
991 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 return true;
993}
994
Steve Blocka7e24c12009-10-30 11:49:00 +0000995function ArrayMap(f, receiver) {
996 if (!IS_FUNCTION(f)) {
997 throw MakeTypeError('called_non_callable', [ f ]);
998 }
999 // Pull out the length so that modifications to the length in the
1000 // loop will not affect the looping.
Leon Clarkee46be812010-01-19 14:06:41 +00001001 var length = TO_UINT32(this.length);
Steve Blocka7e24c12009-10-30 11:49:00 +00001002 var result = new $Array(length);
1003 for (var i = 0; i < length; i++) {
1004 var current = this[i];
1005 if (!IS_UNDEFINED(current) || i in this) {
1006 result[i] = f.call(receiver, current, i, this);
1007 }
1008 }
1009 return result;
1010}
1011
1012
1013function ArrayIndexOf(element, index) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001014 var length = TO_UINT32(this.length);
1015 if (length == 0) return -1;
Steve Block8defd9f2010-07-08 12:39:36 +01001016 if (IS_UNDEFINED(index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001017 index = 0;
1018 } else {
1019 index = TO_INTEGER(index);
1020 // If index is negative, index from the end of the array.
Steve Block1e0659c2011-05-24 12:43:12 +01001021 if (index < 0) {
1022 index = length + index;
1023 // If index is still negative, search the entire array.
1024 if (index < 0) index = 0;
1025 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001026 }
Steve Block59151502010-09-22 15:07:15 +01001027 var min = index;
1028 var max = length;
1029 if (UseSparseVariant(this, length, true)) {
1030 var intervals = %GetArrayKeys(this, length);
1031 if (intervals.length == 2 && intervals[0] < 0) {
1032 // A single interval.
1033 var intervalMin = -(intervals[0] + 1);
1034 var intervalMax = intervalMin + intervals[1];
1035 min = MAX(min, intervalMin);
1036 max = intervalMax; // Capped by length already.
1037 // Fall through to loop below.
1038 } else {
1039 if (intervals.length == 0) return -1;
1040 // Get all the keys in sorted order.
1041 var sortedKeys = GetSortedArrayKeys(this, intervals);
1042 var n = sortedKeys.length;
1043 var i = 0;
1044 while (i < n && sortedKeys[i] < index) i++;
1045 while (i < n) {
1046 var key = sortedKeys[i];
1047 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1048 i++;
1049 }
1050 return -1;
1051 }
1052 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001053 // Lookup through the array.
Steve Block6ded16b2010-05-10 14:33:55 +01001054 if (!IS_UNDEFINED(element)) {
Steve Block59151502010-09-22 15:07:15 +01001055 for (var i = min; i < max; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01001056 if (this[i] === element) return i;
1057 }
1058 return -1;
1059 }
Steve Block59151502010-09-22 15:07:15 +01001060 // Lookup through the array.
1061 for (var i = min; i < max; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01001062 if (IS_UNDEFINED(this[i]) && i in this) {
1063 return i;
Steve Blocka7e24c12009-10-30 11:49:00 +00001064 }
1065 }
1066 return -1;
1067}
1068
1069
1070function ArrayLastIndexOf(element, index) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001071 var length = TO_UINT32(this.length);
1072 if (length == 0) return -1;
Steve Block8defd9f2010-07-08 12:39:36 +01001073 if (%_ArgumentsLength() < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 index = length - 1;
1075 } else {
1076 index = TO_INTEGER(index);
1077 // If index is negative, index from end of the array.
Steve Block59151502010-09-22 15:07:15 +01001078 if (index < 0) index += length;
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 // If index is still negative, do not search the array.
Steve Block59151502010-09-22 15:07:15 +01001080 if (index < 0) return -1;
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 else if (index >= length) index = length - 1;
1082 }
Steve Block59151502010-09-22 15:07:15 +01001083 var min = 0;
1084 var max = index;
1085 if (UseSparseVariant(this, length, true)) {
1086 var intervals = %GetArrayKeys(this, index + 1);
1087 if (intervals.length == 2 && intervals[0] < 0) {
1088 // A single interval.
1089 var intervalMin = -(intervals[0] + 1);
1090 var intervalMax = intervalMin + intervals[1];
1091 min = MAX(min, intervalMin);
1092 max = intervalMax; // Capped by index already.
1093 // Fall through to loop below.
1094 } else {
1095 if (intervals.length == 0) return -1;
1096 // Get all the keys in sorted order.
1097 var sortedKeys = GetSortedArrayKeys(this, intervals);
1098 var i = sortedKeys.length - 1;
1099 while (i >= 0) {
1100 var key = sortedKeys[i];
1101 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1102 i--;
1103 }
1104 return -1;
1105 }
1106 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 // Lookup through the array.
Steve Block6ded16b2010-05-10 14:33:55 +01001108 if (!IS_UNDEFINED(element)) {
Steve Block59151502010-09-22 15:07:15 +01001109 for (var i = max; i >= min; i--) {
Steve Block6ded16b2010-05-10 14:33:55 +01001110 if (this[i] === element) return i;
1111 }
1112 return -1;
1113 }
Steve Block59151502010-09-22 15:07:15 +01001114 for (var i = max; i >= min; i--) {
Steve Block6ded16b2010-05-10 14:33:55 +01001115 if (IS_UNDEFINED(this[i]) && i in this) {
1116 return i;
Steve Blocka7e24c12009-10-30 11:49:00 +00001117 }
1118 }
1119 return -1;
1120}
1121
1122
1123function ArrayReduce(callback, current) {
1124 if (!IS_FUNCTION(callback)) {
1125 throw MakeTypeError('called_non_callable', [callback]);
1126 }
1127 // Pull out the length so that modifications to the length in the
1128 // loop will not affect the looping.
1129 var length = this.length;
1130 var i = 0;
1131
1132 find_initial: if (%_ArgumentsLength() < 2) {
1133 for (; i < length; i++) {
1134 current = this[i];
1135 if (!IS_UNDEFINED(current) || i in this) {
1136 i++;
1137 break find_initial;
1138 }
1139 }
1140 throw MakeTypeError('reduce_no_initial', []);
1141 }
1142
1143 for (; i < length; i++) {
1144 var element = this[i];
1145 if (!IS_UNDEFINED(element) || i in this) {
1146 current = callback.call(null, current, element, i, this);
1147 }
1148 }
1149 return current;
1150}
1151
1152function ArrayReduceRight(callback, current) {
1153 if (!IS_FUNCTION(callback)) {
1154 throw MakeTypeError('called_non_callable', [callback]);
1155 }
1156 var i = this.length - 1;
1157
1158 find_initial: if (%_ArgumentsLength() < 2) {
1159 for (; i >= 0; i--) {
1160 current = this[i];
1161 if (!IS_UNDEFINED(current) || i in this) {
1162 i--;
1163 break find_initial;
1164 }
1165 }
1166 throw MakeTypeError('reduce_no_initial', []);
1167 }
1168
1169 for (; i >= 0; i--) {
1170 var element = this[i];
1171 if (!IS_UNDEFINED(element) || i in this) {
1172 current = callback.call(null, current, element, i, this);
1173 }
1174 }
1175 return current;
1176}
1177
Steve Block3ce2e202009-11-05 08:53:23 +00001178// ES5, 15.4.3.2
1179function ArrayIsArray(obj) {
1180 return IS_ARRAY(obj);
1181}
Steve Blocka7e24c12009-10-30 11:49:00 +00001182
Steve Blocka7e24c12009-10-30 11:49:00 +00001183
1184// -------------------------------------------------------------------
1185function SetupArray() {
1186 // Setup non-enumerable constructor property on the Array.prototype
1187 // object.
1188 %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
1189
Steve Block3ce2e202009-11-05 08:53:23 +00001190 // Setup non-enumerable functions on the Array object.
1191 InstallFunctions($Array, DONT_ENUM, $Array(
1192 "isArray", ArrayIsArray
1193 ));
1194
Steve Block6ded16b2010-05-10 14:33:55 +01001195 var specialFunctions = %SpecialArrayFunctions({});
1196
1197 function getFunction(name, jsBuiltin, len) {
1198 var f = jsBuiltin;
1199 if (specialFunctions.hasOwnProperty(name)) {
1200 f = specialFunctions[name];
1201 }
1202 if (!IS_UNDEFINED(len)) {
1203 %FunctionSetLength(f, len);
1204 }
1205 return f;
1206 }
1207
Steve Blocka7e24c12009-10-30 11:49:00 +00001208 // Setup non-enumerable functions of the Array.prototype object and
1209 // set their names.
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 // Manipulate the length of some of the functions to meet
1211 // expectations set by ECMA-262 or Mozilla.
Steve Block6ded16b2010-05-10 14:33:55 +01001212 InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
1213 "toString", getFunction("toString", ArrayToString),
1214 "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
1215 "join", getFunction("join", ArrayJoin),
1216 "pop", getFunction("pop", ArrayPop),
1217 "push", getFunction("push", ArrayPush, 1),
1218 "concat", getFunction("concat", ArrayConcat, 1),
1219 "reverse", getFunction("reverse", ArrayReverse),
1220 "shift", getFunction("shift", ArrayShift),
1221 "unshift", getFunction("unshift", ArrayUnshift, 1),
1222 "slice", getFunction("slice", ArraySlice, 2),
1223 "splice", getFunction("splice", ArraySplice, 2),
1224 "sort", getFunction("sort", ArraySort),
1225 "filter", getFunction("filter", ArrayFilter, 1),
1226 "forEach", getFunction("forEach", ArrayForEach, 1),
1227 "some", getFunction("some", ArraySome, 1),
1228 "every", getFunction("every", ArrayEvery, 1),
1229 "map", getFunction("map", ArrayMap, 1),
1230 "indexOf", getFunction("indexOf", ArrayIndexOf, 1),
1231 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
1232 "reduce", getFunction("reduce", ArrayReduce, 1),
1233 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1)
1234 ));
1235
1236 %FinishArrayPrototypeSetup($Array.prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00001237}
1238
1239
1240SetupArray();