blob: 32a370fda862f81c293b3b39f6a075438ae96ec5 [file] [log] [blame]
whesse@chromium.org023421e2010-12-21 12:19:12 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034// Global list of arrays visited during toString, toLocaleString and
35// join invocations.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000036var visited_arrays = new InternalArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000070function SparseJoinWithSeparator(array, len, convert, separator) {
71 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
72 var totalLength = 0;
73 var elements = new InternalArray(keys.length * 2);
74 var previousKey = -1;
75 for (var i = 0; i < keys.length; i++) {
76 var key = keys[i];
77 if (key != previousKey) { // keys may contain duplicates.
78 var e = array[key];
79 if (!IS_STRING(e)) e = convert(e);
80 elements[i * 2] = key;
81 elements[i * 2 + 1] = e;
82 previousKey = key;
83 }
84 }
85 return %SparseJoinWithSeparator(elements, len, separator);
86}
87
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Optimized for sparse arrays if separator is ''.
90function SparseJoin(array, len, convert) {
91 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 var last_key = -1;
93 var keys_length = keys.length;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000094
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000095 var elements = new InternalArray(keys_length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000096 var elements_length = 0;
97
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 for (var i = 0; i < keys_length; i++) {
99 var key = keys[i];
100 if (key != last_key) {
101 var e = array[key];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000102 if (!IS_STRING(e)) e = convert(e);
103 elements[elements_length++] = e;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 last_key = key;
105 }
106 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000107 return %StringBuilderConcat(elements, elements_length, '');
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108}
109
110
111function UseSparseVariant(object, length, is_array) {
112 return is_array &&
113 length > 1000 &&
114 (!%_IsSmi(length) ||
115 %EstimateNumberOfElements(object) < (length >> 2));
116}
117
118
119function Join(array, length, separator, convert) {
120 if (length == 0) return '';
121
122 var is_array = IS_ARRAY(array);
123
124 if (is_array) {
125 // If the array is cyclic, return the empty string for already
126 // visited arrays.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000127 if (!%PushIfAbsent(visited_arrays, array)) return '';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 }
129
130 // Attempt to convert the elements.
131 try {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000132 if (UseSparseVariant(array, length, is_array)) {
133 if (separator.length == 0) {
134 return SparseJoin(array, length, convert);
135 } else {
136 return SparseJoinWithSeparator(array, length, convert, separator);
137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138 }
139
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000140 // Fast case for one-element arrays.
141 if (length == 1) {
142 var e = array[0];
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000143 if (IS_STRING(e)) return e;
144 return convert(e);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000145 }
146
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000147 // Construct an array for the elements.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000148 var elements = new InternalArray(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000150 // We pull the empty separator check outside the loop for speed!
151 if (separator.length == 0) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000152 var elements_length = 0;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000153 for (var i = 0; i < length; i++) {
154 var e = array[i];
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000155 if (!IS_STRING(e)) e = convert(e);
156 elements[elements_length++] = e;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000157 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000158 elements.length = elements_length;
159 var result = %_FastAsciiArrayJoin(elements, '');
160 if (!IS_UNDEFINED(result)) return result;
161 return %StringBuilderConcat(elements, elements_length, '');
162 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000163 // Non-empty separator case.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000164 // If the first element is a number then use the heuristic that the
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000165 // remaining elements are also likely to be numbers.
166 if (!IS_NUMBER(array[0])) {
167 for (var i = 0; i < length; i++) {
168 var e = array[i];
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000169 if (!IS_STRING(e)) e = convert(e);
170 elements[i] = e;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000172 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000173 for (var i = 0; i < length; i++) {
174 var e = array[i];
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000175 if (IS_NUMBER(e)) {
176 e = %_NumberToString(e);
177 } else if (!IS_STRING(e)) {
178 e = convert(e);
179 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000180 elements[i] = e;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000181 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000182 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000183 var result = %_FastAsciiArrayJoin(elements, separator);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000184 if (!IS_UNDEFINED(result)) return result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000185
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000186 return %StringBuilderJoin(elements, length, separator);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187 } finally {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000188 // Make sure to remove the last element of the visited array no
189 // matter what happens.
190 if (is_array) visited_arrays.length = visited_arrays.length - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000192}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
194
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000195function ConvertToString(x) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000196 // Assumes x is a non-string.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000197 if (IS_NUMBER(x)) return %_NumberToString(x);
198 if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
199 return (IS_NULL_OR_UNDEFINED(x)) ? '' : %ToString(%DefaultString(x));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201
202
203function ConvertToLocaleString(e) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000204 if (e == null) {
205 return '';
206 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000207 // e_obj's toLocaleString might be overwritten, check if it is a function.
208 // Call ToString if toLocaleString is not a function.
209 // See issue 877615.
210 var e_obj = ToObject(e);
211 if (IS_FUNCTION(e_obj.toLocaleString))
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000212 return ToString(e_obj.toLocaleString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000213 else
214 return ToString(e);
215 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000216}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218
219// This function implements the optimized splice implementation that can use
220// special array operations to handle sparse arrays in a sensible fashion.
221function SmartSlice(array, start_i, del_count, len, deleted_elements) {
222 // Move deleted elements to a new array (the return value from splice).
223 // Intervals array can contain keys and intervals. See comment in Concat.
224 var intervals = %GetArrayKeys(array, start_i + del_count);
225 var length = intervals.length;
226 for (var k = 0; k < length; k++) {
227 var key = intervals[k];
228 if (key < 0) {
229 var j = -1 - key;
230 var interval_limit = j + intervals[++k];
231 if (j < start_i) {
232 j = start_i;
233 }
234 for (; j < interval_limit; j++) {
235 // ECMA-262 15.4.4.12 line 10. The spec could also be
236 // interpreted such that %HasLocalProperty would be the
237 // appropriate test. We follow KJS in consulting the
238 // prototype.
239 var current = array[j];
240 if (!IS_UNDEFINED(current) || j in array) {
241 deleted_elements[j - start_i] = current;
242 }
243 }
244 } else {
245 if (!IS_UNDEFINED(key)) {
246 if (key >= start_i) {
247 // ECMA-262 15.4.4.12 line 10. The spec could also be
248 // interpreted such that %HasLocalProperty would be the
249 // appropriate test. We follow KJS in consulting the
250 // prototype.
251 var current = array[key];
252 if (!IS_UNDEFINED(current) || key in array) {
253 deleted_elements[key - start_i] = current;
254 }
255 }
256 }
257 }
258 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000259}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260
261
262// This function implements the optimized splice implementation that can use
263// special array operations to handle sparse arrays in a sensible fashion.
264function SmartMove(array, start_i, del_count, len, num_additional_args) {
265 // Move data to new array.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000266 var new_array = new InternalArray(len - del_count + num_additional_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267 var intervals = %GetArrayKeys(array, len);
268 var length = intervals.length;
269 for (var k = 0; k < length; k++) {
270 var key = intervals[k];
271 if (key < 0) {
272 var j = -1 - key;
273 var interval_limit = j + intervals[++k];
274 while (j < start_i && j < interval_limit) {
275 // The spec could also be interpreted such that
276 // %HasLocalProperty would be the appropriate test. We follow
277 // KJS in consulting the prototype.
278 var current = array[j];
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000279 if (!IS_UNDEFINED(current) || j in array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 new_array[j] = current;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282 j++;
283 }
284 j = start_i + del_count;
285 while (j < interval_limit) {
286 // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also be
287 // interpreted such that %HasLocalProperty would be the
288 // appropriate test. We follow KJS in consulting the
289 // prototype.
290 var current = array[j];
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000291 if (!IS_UNDEFINED(current) || j in array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 new_array[j - del_count + num_additional_args] = current;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294 j++;
295 }
296 } else {
297 if (!IS_UNDEFINED(key)) {
298 if (key < start_i) {
299 // The spec could also be interpreted such that
300 // %HasLocalProperty would be the appropriate test. We follow
301 // KJS in consulting the prototype.
302 var current = array[key];
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000303 if (!IS_UNDEFINED(current) || key in array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 new_array[key] = current;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 } else if (key >= start_i + del_count) {
307 // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also
308 // be interpreted such that %HasLocalProperty would be the
309 // appropriate test. We follow KJS in consulting the
310 // prototype.
311 var current = array[key];
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000312 if (!IS_UNDEFINED(current) || key in array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 new_array[key - del_count + num_additional_args] = current;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315 }
316 }
317 }
318 }
319 // Move contents of new_array into this array
320 %MoveArrayContents(new_array, array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322
323
324// This is part of the old simple-minded splice. We are using it either
325// because the receiver is not an array (so we have no choice) or because we
326// know we are not deleting or moving a lot of elements.
327function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
328 for (var i = 0; i < del_count; i++) {
329 var index = start_i + i;
330 // The spec could also be interpreted such that %HasLocalProperty
331 // would be the appropriate test. We follow KJS in consulting the
332 // prototype.
333 var current = array[index];
334 if (!IS_UNDEFINED(current) || index in array)
335 deleted_elements[i] = current;
336 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000337}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
339
340function SimpleMove(array, start_i, del_count, len, num_additional_args) {
341 if (num_additional_args !== del_count) {
342 // Move the existing elements after the elements to be deleted
343 // to the right position in the resulting array.
344 if (num_additional_args > del_count) {
345 for (var i = len - del_count; i > start_i; i--) {
346 var from_index = i + del_count - 1;
347 var to_index = i + num_additional_args - 1;
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 } else {
359 for (var i = start_i; i < len - del_count; i++) {
360 var from_index = i + del_count;
361 var to_index = i + num_additional_args;
362 // The spec could also be interpreted such that
363 // %HasLocalProperty would be the appropriate test. We follow
364 // KJS in consulting the prototype.
365 var current = array[from_index];
366 if (!IS_UNDEFINED(current) || from_index in array) {
367 array[to_index] = current;
368 } else {
369 delete array[to_index];
370 }
371 }
372 for (var i = len; i > len - del_count + num_additional_args; i--) {
373 delete array[i - 1];
374 }
375 }
376 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000377}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378
379
380// -------------------------------------------------------------------
381
382
383function ArrayToString() {
384 if (!IS_ARRAY(this)) {
385 throw new $TypeError('Array.prototype.toString is not generic');
386 }
387 return Join(this, this.length, ',', ConvertToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000388}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389
390
391function ArrayToLocaleString() {
392 if (!IS_ARRAY(this)) {
393 throw new $TypeError('Array.prototype.toString is not generic');
394 }
395 return Join(this, this.length, ',', ConvertToLocaleString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000396}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397
398
399function ArrayJoin(separator) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000400 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
401 throw MakeTypeError("called_on_null_or_undefined",
402 ["Array.prototype.join"]);
403 }
404
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000405 if (IS_UNDEFINED(separator)) {
406 separator = ',';
407 } else if (!IS_STRING(separator)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000408 separator = NonStringToString(separator);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000409 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000410
411 var result = %_FastAsciiArrayJoin(this, separator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000412 if (!IS_UNDEFINED(result)) return result;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000413
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000414 return Join(this, TO_UINT32(this.length), separator, ConvertToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000415}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416
417
418// Removes the last element from the array and returns it. See
419// ECMA-262, section 15.4.4.6.
420function ArrayPop() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000421 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
422 throw MakeTypeError("called_on_null_or_undefined",
423 ["Array.prototype.pop"]);
424 }
425
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000426 var n = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 if (n == 0) {
428 this.length = n;
429 return;
430 }
431 n--;
432 var value = this[n];
433 this.length = n;
434 delete this[n];
435 return value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000436}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
438
439// Appends the arguments to the end of the array and returns the new
440// length of the array. See ECMA-262, section 15.4.4.7.
441function ArrayPush() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000442 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
443 throw MakeTypeError("called_on_null_or_undefined",
444 ["Array.prototype.push"]);
445 }
446
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000447 var n = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448 var m = %_ArgumentsLength();
449 for (var i = 0; i < m; i++) {
450 this[i+n] = %_Arguments(i);
451 }
452 this.length = n + m;
453 return this.length;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000454}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455
456
457function ArrayConcat(arg1) { // length == 1
lrn@chromium.org1c092762011-05-09 09:42:16 +0000458 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
459 throw MakeTypeError("called_on_null_or_undefined",
460 ["Array.prototype.concat"]);
461 }
462
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000463 var arg_count = %_ArgumentsLength();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000464 var arrays = new InternalArray(1 + arg_count);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000465 arrays[0] = this;
466 for (var i = 0; i < arg_count; i++) {
467 arrays[i + 1] = %_Arguments(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468 }
469
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000470 return %ArrayConcat(arrays);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000471}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472
473
474// For implementing reverse() on large, sparse arrays.
475function SparseReverse(array, len) {
476 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
477 var high_counter = keys.length - 1;
478 var low_counter = 0;
479 while (low_counter <= high_counter) {
480 var i = keys[low_counter];
481 var j = keys[high_counter];
482
483 var j_complement = len - j - 1;
484 var low, high;
485
486 if (j_complement <= i) {
487 high = j;
488 while (keys[--high_counter] == j);
489 low = j_complement;
490 }
491 if (j_complement >= i) {
492 low = i;
493 while (keys[++low_counter] == i);
494 high = len - i - 1;
495 }
496
497 var current_i = array[low];
498 if (!IS_UNDEFINED(current_i) || low in array) {
499 var current_j = array[high];
500 if (!IS_UNDEFINED(current_j) || high in array) {
501 array[low] = current_j;
502 array[high] = current_i;
503 } else {
504 array[high] = current_i;
505 delete array[low];
506 }
507 } else {
508 var current_j = array[high];
509 if (!IS_UNDEFINED(current_j) || high in array) {
510 array[low] = current_j;
511 delete array[high];
512 }
513 }
514 }
515}
516
517
518function ArrayReverse() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000519 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
520 throw MakeTypeError("called_on_null_or_undefined",
521 ["Array.prototype.reverse"]);
522 }
523
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000524 var j = TO_UINT32(this.length) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525
526 if (UseSparseVariant(this, j, IS_ARRAY(this))) {
527 SparseReverse(this, j+1);
528 return this;
529 }
530
531 for (var i = 0; i < j; i++, j--) {
532 var current_i = this[i];
533 if (!IS_UNDEFINED(current_i) || i in this) {
534 var current_j = this[j];
535 if (!IS_UNDEFINED(current_j) || j in this) {
536 this[i] = current_j;
537 this[j] = current_i;
538 } else {
539 this[j] = current_i;
540 delete this[i];
541 }
542 } else {
543 var current_j = this[j];
544 if (!IS_UNDEFINED(current_j) || j in this) {
545 this[i] = current_j;
546 delete this[j];
547 }
548 }
549 }
550 return this;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000551}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552
553
554function ArrayShift() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000555 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
556 throw MakeTypeError("called_on_null_or_undefined",
557 ["Array.prototype.shift"]);
558 }
559
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000560 var len = TO_UINT32(this.length);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 if (len === 0) {
563 this.length = 0;
564 return;
565 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567 var first = this[0];
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 if (IS_ARRAY(this))
570 SmartMove(this, 0, 1, len, 0);
571 else
572 SimpleMove(this, 0, 1, len, 0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 this.length = len - 1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576 return first;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000577}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578
579
580function ArrayUnshift(arg1) { // length == 1
lrn@chromium.org1c092762011-05-09 09:42:16 +0000581 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
582 throw MakeTypeError("called_on_null_or_undefined",
583 ["Array.prototype.unshift"]);
584 }
585
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000586 var len = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587 var num_arguments = %_ArgumentsLength();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589 if (IS_ARRAY(this))
590 SmartMove(this, 0, 0, len, num_arguments);
591 else
592 SimpleMove(this, 0, 0, len, num_arguments);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594 for (var i = 0; i < num_arguments; i++) {
595 this[i] = %_Arguments(i);
596 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 this.length = len + num_arguments;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 return len + num_arguments;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000601}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602
603
604function ArraySlice(start, end) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000605 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
606 throw MakeTypeError("called_on_null_or_undefined",
607 ["Array.prototype.slice"]);
608 }
609
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000610 var len = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 var start_i = TO_INTEGER(start);
612 var end_i = len;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000613
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 if (end !== void 0) end_i = TO_INTEGER(end);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 if (start_i < 0) {
617 start_i += len;
618 if (start_i < 0) start_i = 0;
619 } else {
620 if (start_i > len) start_i = len;
621 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 if (end_i < 0) {
624 end_i += len;
625 if (end_i < 0) end_i = 0;
626 } else {
627 if (end_i > len) end_i = len;
628 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 var result = [];
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000631
632 if (end_i < start_i) return result;
633
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000634 if (IS_ARRAY(this) &&
635 (end_i > 1000) &&
636 (%EstimateNumberOfElements(this) < end_i)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 SmartSlice(this, start_i, end_i - start_i, len, result);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000638 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 SimpleSlice(this, start_i, end_i - start_i, len, result);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000640 }
641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642 result.length = end_i - start_i;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000645}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646
647
648function ArraySplice(start, delete_count) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000649 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
650 throw MakeTypeError("called_on_null_or_undefined",
651 ["Array.prototype.splice"]);
652 }
653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 var num_arguments = %_ArgumentsLength();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000655
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000656 var len = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 var start_i = TO_INTEGER(start);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 if (start_i < 0) {
660 start_i += len;
661 if (start_i < 0) start_i = 0;
662 } else {
663 if (start_i > len) start_i = len;
664 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000665
ager@chromium.org5c838252010-02-19 08:53:10 +0000666 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000667 // given as a request to delete all the elements from the start.
668 // And it differs from the case of undefined delete count.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669 // This does not follow ECMA-262, but we do the same for
670 // compatibility.
671 var del_count = 0;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000672 if (num_arguments == 1) {
673 del_count = len - start_i;
674 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 del_count = TO_INTEGER(delete_count);
676 if (del_count < 0) del_count = 0;
677 if (del_count > len - start_i) del_count = len - start_i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000679
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 var deleted_elements = [];
681 deleted_elements.length = del_count;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 // Number of elements to add.
684 var num_additional_args = 0;
685 if (num_arguments > 2) {
686 num_additional_args = num_arguments - 2;
687 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 var use_simple_splice = true;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000690
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 if (IS_ARRAY(this) && num_additional_args !== del_count) {
692 // If we are only deleting/moving a few things near the end of the
693 // array then the simple version is going to be faster, because it
694 // doesn't touch most of the array.
695 var estimated_non_hole_elements = %EstimateNumberOfElements(this);
696 if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) {
697 use_simple_splice = false;
698 }
699 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 if (use_simple_splice) {
702 SimpleSlice(this, start_i, del_count, len, deleted_elements);
703 SimpleMove(this, start_i, del_count, len, num_additional_args);
704 } else {
705 SmartSlice(this, start_i, del_count, len, deleted_elements);
706 SmartMove(this, start_i, del_count, len, num_additional_args);
707 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 // Insert the arguments into the resulting array in
710 // place of the deleted elements.
711 var i = start_i;
712 var arguments_index = 2;
713 var arguments_length = %_ArgumentsLength();
714 while (arguments_index < arguments_length) {
715 this[i++] = %_Arguments(arguments_index++);
716 }
717 this.length = len - del_count + num_additional_args;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 // Return the deleted elements.
720 return deleted_elements;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000721}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722
723
724function ArraySort(comparefn) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000725 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
726 throw MakeTypeError("called_on_null_or_undefined",
727 ["Array.prototype.sort"]);
728 }
729
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000730 // In-place QuickSort algorithm.
731 // For short (length <= 22) arrays, insertion sort is used for efficiency.
732
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000733 if (!IS_FUNCTION(comparefn)) {
734 comparefn = function (x, y) {
735 if (x === y) return 0;
736 if (%_IsSmi(x) && %_IsSmi(y)) {
737 return %SmiLexicographicCompare(x, y);
ager@chromium.org357bf652010-04-12 11:30:10 +0000738 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000739 x = ToString(x);
740 y = ToString(y);
741 if (x == y) return 0;
742 else return x < y ? -1 : 1;
743 };
ager@chromium.org357bf652010-04-12 11:30:10 +0000744 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000745 var receiver = %GetDefaultReceiver(comparefn);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000747 function InsertionSort(a, from, to) {
748 for (var i = from + 1; i < to; i++) {
749 var element = a[i];
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000750 for (var j = i - 1; j >= from; j--) {
751 var tmp = a[j];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000752 var order = %_CallFunction(receiver, tmp, element, comparefn);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000753 if (order > 0) {
754 a[j + 1] = tmp;
755 } else {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000756 break;
757 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000759 a[j + 1] = element;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000760 }
761 }
762
763 function QuickSort(a, from, to) {
764 // Insertion sort is faster for short arrays.
whesse@chromium.org023421e2010-12-21 12:19:12 +0000765 if (to - from <= 10) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000766 InsertionSort(a, from, to);
767 return;
768 }
whesse@chromium.org023421e2010-12-21 12:19:12 +0000769 // Find a pivot as the median of first, last and middle element.
770 var v0 = a[from];
771 var v1 = a[to - 1];
772 var middle_index = from + ((to - from) >> 1);
773 var v2 = a[middle_index];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000774 var c01 = %_CallFunction(receiver, v0, v1, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000775 if (c01 > 0) {
776 // v1 < v0, so swap them.
777 var tmp = v0;
778 v0 = v1;
779 v1 = tmp;
780 } // v0 <= v1.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000781 var c02 = %_CallFunction(receiver, v0, v2, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000782 if (c02 >= 0) {
783 // v2 <= v0 <= v1.
784 var tmp = v0;
785 v0 = v2;
786 v2 = v1;
787 v1 = tmp;
788 } else {
789 // v0 <= v1 && v0 < v2
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000790 var c12 = %_CallFunction(receiver, v1, v2, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000791 if (c12 > 0) {
792 // v0 <= v2 < v1
793 var tmp = v1;
794 v1 = v2;
795 v2 = tmp;
796 }
797 }
798 // v0 <= v1 <= v2
799 a[from] = v0;
800 a[to - 1] = v2;
801 var pivot = v1;
802 var low_end = from + 1; // Upper bound of elements lower than pivot.
803 var high_start = to - 1; // Lower bound of elements greater than pivot.
804 a[middle_index] = a[low_end];
805 a[low_end] = pivot;
806
ager@chromium.org381abbb2009-02-25 13:23:22 +0000807 // From low_end to i are elements equal to pivot.
808 // From i to high_start are elements that haven't been compared yet.
whesse@chromium.org023421e2010-12-21 12:19:12 +0000809 partition: for (var i = low_end + 1; i < high_start; i++) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000810 var element = a[i];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000811 var order = %_CallFunction(receiver, element, pivot, comparefn);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000812 if (order < 0) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000813 %_SwapElements(a, i, low_end);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000814 low_end++;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000815 } else if (order > 0) {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000816 do {
817 high_start--;
818 if (high_start == i) break partition;
819 var top_elem = a[high_start];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000820 order = %_CallFunction(receiver, top_elem, pivot, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000821 } while (order > 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000822 %_SwapElements(a, i, high_start);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000823 if (order < 0) {
824 %_SwapElements(a, i, low_end);
825 low_end++;
826 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000827 }
828 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000829 QuickSort(a, from, low_end);
830 QuickSort(a, high_start, to);
831 }
832
whesse@chromium.org023421e2010-12-21 12:19:12 +0000833 // Copy elements in the range 0..length from obj's prototype chain
834 // to obj itself, if obj has holes. Return one more than the maximal index
ager@chromium.org5ec48922009-05-05 07:25:34 +0000835 // of a prototype property.
836 function CopyFromPrototype(obj, length) {
837 var max = 0;
838 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
839 var indices = %GetArrayKeys(proto, length);
840 if (indices.length > 0) {
841 if (indices[0] == -1) {
842 // It's an interval.
843 var proto_length = indices[1];
844 for (var i = 0; i < proto_length; i++) {
845 if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
846 obj[i] = proto[i];
847 if (i >= max) { max = i + 1; }
848 }
849 }
850 } else {
851 for (var i = 0; i < indices.length; i++) {
852 var index = indices[i];
853 if (!IS_UNDEFINED(index) &&
854 !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
855 obj[index] = proto[index];
856 if (index >= max) { max = index + 1; }
857 }
858 }
859 }
860 }
861 }
862 return max;
863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864
ager@chromium.org5ec48922009-05-05 07:25:34 +0000865 // Set a value of "undefined" on all indices in the range from..to
866 // where a prototype of obj has an element. I.e., shadow all prototype
867 // elements in that range.
868 function ShadowPrototypeElements(obj, from, to) {
869 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
870 var indices = %GetArrayKeys(proto, to);
871 if (indices.length > 0) {
872 if (indices[0] == -1) {
873 // It's an interval.
874 var proto_length = indices[1];
875 for (var i = from; i < proto_length; i++) {
876 if (proto.hasOwnProperty(i)) {
877 obj[i] = void 0;
878 }
879 }
880 } else {
881 for (var i = 0; i < indices.length; i++) {
882 var index = indices[i];
883 if (!IS_UNDEFINED(index) && from <= index &&
884 proto.hasOwnProperty(index)) {
885 obj[index] = void 0;
886 }
887 }
888 }
889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 }
891 }
892
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000893 function SafeRemoveArrayHoles(obj) {
894 // Copy defined elements from the end to fill in all holes and undefineds
895 // in the beginning of the array. Write undefineds and holes at the end
896 // after loop is finished.
897 var first_undefined = 0;
898 var last_defined = length - 1;
899 var num_holes = 0;
900 while (first_undefined < last_defined) {
901 // Find first undefined element.
902 while (first_undefined < last_defined &&
903 !IS_UNDEFINED(obj[first_undefined])) {
904 first_undefined++;
905 }
906 // Maintain the invariant num_holes = the number of holes in the original
907 // array with indices <= first_undefined or > last_defined.
908 if (!obj.hasOwnProperty(first_undefined)) {
909 num_holes++;
910 }
911
912 // Find last defined element.
913 while (first_undefined < last_defined &&
914 IS_UNDEFINED(obj[last_defined])) {
915 if (!obj.hasOwnProperty(last_defined)) {
916 num_holes++;
917 }
918 last_defined--;
919 }
920 if (first_undefined < last_defined) {
921 // Fill in hole or undefined.
922 obj[first_undefined] = obj[last_defined];
923 obj[last_defined] = void 0;
924 }
925 }
926 // If there were any undefineds in the entire array, first_undefined
927 // points to one past the last defined element. Make this true if
928 // there were no undefineds, as well, so that first_undefined == number
929 // of defined elements.
930 if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++;
931 // Fill in the undefineds and the holes. There may be a hole where
932 // an undefined should be and vice versa.
933 var i;
934 for (i = first_undefined; i < length - num_holes; i++) {
935 obj[i] = void 0;
936 }
937 for (i = length - num_holes; i < length; i++) {
938 // For compatability with Webkit, do not expose elements in the prototype.
939 if (i in obj.__proto__) {
940 obj[i] = void 0;
941 } else {
942 delete obj[i];
943 }
944 }
945
946 // Return the number of defined elements.
947 return first_undefined;
948 }
949
ager@chromium.org357bf652010-04-12 11:30:10 +0000950 var length = TO_UINT32(this.length);
ager@chromium.org5ec48922009-05-05 07:25:34 +0000951 if (length < 2) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952
ager@chromium.org5ec48922009-05-05 07:25:34 +0000953 var is_array = IS_ARRAY(this);
954 var max_prototype_element;
955 if (!is_array) {
956 // For compatibility with JSC, we also sort elements inherited from
957 // the prototype chain on non-Array objects.
958 // We do this by copying them to this object and sorting only
959 // local elements. This is not very efficient, but sorting with
960 // inherited elements happens very, very rarely, if at all.
961 // The specification allows "implementation dependent" behavior
962 // if an element on the prototype chain has an element that
963 // might interact with sorting.
964 max_prototype_element = CopyFromPrototype(this, length);
965 }
966
967 var num_non_undefined = %RemoveArrayHoles(this, length);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000968 if (num_non_undefined == -1) {
969 // There were indexed accessors in the array. Move array holes and
970 // undefineds to the end using a Javascript function that is safe
971 // in the presence of accessors.
972 num_non_undefined = SafeRemoveArrayHoles(this);
973 }
ager@chromium.org5ec48922009-05-05 07:25:34 +0000974
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000975 QuickSort(this, 0, num_non_undefined);
ager@chromium.org5ec48922009-05-05 07:25:34 +0000976
977 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {
978 // For compatibility with JSC, we shadow any elements in the prototype
979 // chain that has become exposed by sort moving a hole to its position.
980 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 }
982
983 return this;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000984}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985
986
987// The following functions cannot be made efficient on sparse arrays while
988// preserving the semantics, since the calls to the receiver function can add
989// or delete elements from the array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990function ArrayFilter(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000991 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
992 throw MakeTypeError("called_on_null_or_undefined",
993 ["Array.prototype.filter"]);
994 }
995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 if (!IS_FUNCTION(f)) {
997 throw MakeTypeError('called_non_callable', [ f ]);
998 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000999 if (IS_NULL_OR_UNDEFINED(receiver)) {
1000 receiver = %GetDefaultReceiver(f) || receiver;
1001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 // Pull out the length so that modifications to the length in the
1003 // loop will not affect the looping.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001004 var length = ToUint32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005 var result = [];
ager@chromium.org381abbb2009-02-25 13:23:22 +00001006 var result_length = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 for (var i = 0; i < length; i++) {
1008 var current = this[i];
1009 if (!IS_UNDEFINED(current) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001010 if (%_CallFunction(receiver, current, i, this, f)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001011 result[result_length++] = current;
1012 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013 }
1014 }
1015 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001016}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
1018
1019function ArrayForEach(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001020 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1021 throw MakeTypeError("called_on_null_or_undefined",
1022 ["Array.prototype.forEach"]);
1023 }
1024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 if (!IS_FUNCTION(f)) {
1026 throw MakeTypeError('called_non_callable', [ f ]);
1027 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001028 if (IS_NULL_OR_UNDEFINED(receiver)) {
1029 receiver = %GetDefaultReceiver(f) || receiver;
1030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 // Pull out the length so that modifications to the length in the
1032 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001033 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 for (var i = 0; i < length; i++) {
1035 var current = this[i];
1036 if (!IS_UNDEFINED(current) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001037 %_CallFunction(receiver, current, i, this, f);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 }
1039 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001040}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041
1042
1043// Executes the function once for each element present in the
1044// array until it finds one where callback returns true.
1045function ArraySome(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001046 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1047 throw MakeTypeError("called_on_null_or_undefined",
1048 ["Array.prototype.some"]);
1049 }
1050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 if (!IS_FUNCTION(f)) {
1052 throw MakeTypeError('called_non_callable', [ f ]);
1053 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001054 if (IS_NULL_OR_UNDEFINED(receiver)) {
1055 receiver = %GetDefaultReceiver(f) || receiver;
1056 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 // Pull out the length so that modifications to the length in the
1058 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001059 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 for (var i = 0; i < length; i++) {
1061 var current = this[i];
1062 if (!IS_UNDEFINED(current) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001063 if (%_CallFunction(receiver, current, i, this, f)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064 }
1065 }
1066 return false;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001067}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
1069
1070function ArrayEvery(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001071 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1072 throw MakeTypeError("called_on_null_or_undefined",
1073 ["Array.prototype.every"]);
1074 }
1075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 if (!IS_FUNCTION(f)) {
1077 throw MakeTypeError('called_non_callable', [ f ]);
1078 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001079 if (IS_NULL_OR_UNDEFINED(receiver)) {
1080 receiver = %GetDefaultReceiver(f) || receiver;
1081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 // Pull out the length so that modifications to the length in the
1083 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001084 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 for (var i = 0; i < length; i++) {
1086 var current = this[i];
1087 if (!IS_UNDEFINED(current) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001088 if (!%_CallFunction(receiver, current, i, this, f)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 }
1090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 return true;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001092}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094function ArrayMap(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001095 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1096 throw MakeTypeError("called_on_null_or_undefined",
1097 ["Array.prototype.map"]);
1098 }
1099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 if (!IS_FUNCTION(f)) {
1101 throw MakeTypeError('called_non_callable', [ f ]);
1102 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001103 if (IS_NULL_OR_UNDEFINED(receiver)) {
1104 receiver = %GetDefaultReceiver(f) || receiver;
1105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 // Pull out the length so that modifications to the length in the
1107 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001108 var length = TO_UINT32(this.length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001109 var result = new $Array();
1110 var accumulator = new InternalArray(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 for (var i = 0; i < length; i++) {
1112 var current = this[i];
1113 if (!IS_UNDEFINED(current) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001114 accumulator[i] = %_CallFunction(receiver, current, i, this, f);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115 }
1116 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001117 %MoveArrayContents(accumulator, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001119}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120
1121
1122function ArrayIndexOf(element, index) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001123 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1124 throw MakeTypeError("called_on_null_or_undefined",
1125 ["Array.prototype.indexOf"]);
1126 }
1127
ricow@chromium.org65fae842010-08-25 15:26:24 +00001128 var length = TO_UINT32(this.length);
1129 if (length == 0) return -1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001130 if (IS_UNDEFINED(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 index = 0;
1132 } else {
1133 index = TO_INTEGER(index);
1134 // If index is negative, index from the end of the array.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001135 if (index < 0) {
1136 index = length + index;
1137 // If index is still negative, search the entire array.
1138 if (index < 0) index = 0;
1139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001141 var min = index;
1142 var max = length;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001143 if (UseSparseVariant(this, length, IS_ARRAY(this))) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001144 var intervals = %GetArrayKeys(this, length);
1145 if (intervals.length == 2 && intervals[0] < 0) {
1146 // A single interval.
1147 var intervalMin = -(intervals[0] + 1);
1148 var intervalMax = intervalMin + intervals[1];
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001149 if (min < intervalMin) min = intervalMin;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001150 max = intervalMax; // Capped by length already.
1151 // Fall through to loop below.
1152 } else {
1153 if (intervals.length == 0) return -1;
1154 // Get all the keys in sorted order.
1155 var sortedKeys = GetSortedArrayKeys(this, intervals);
1156 var n = sortedKeys.length;
1157 var i = 0;
1158 while (i < n && sortedKeys[i] < index) i++;
1159 while (i < n) {
1160 var key = sortedKeys[i];
1161 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1162 i++;
1163 }
1164 return -1;
1165 }
1166 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001167 // Lookup through the array.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001168 if (!IS_UNDEFINED(element)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001169 for (var i = min; i < max; i++) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001170 if (this[i] === element) return i;
1171 }
1172 return -1;
1173 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001174 // Lookup through the array.
1175 for (var i = min; i < max; i++) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001176 if (IS_UNDEFINED(this[i]) && i in this) {
1177 return i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179 }
1180 return -1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001181}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182
1183
1184function ArrayLastIndexOf(element, index) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001185 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1186 throw MakeTypeError("called_on_null_or_undefined",
1187 ["Array.prototype.lastIndexOf"]);
1188 }
1189
ricow@chromium.org65fae842010-08-25 15:26:24 +00001190 var length = TO_UINT32(this.length);
1191 if (length == 0) return -1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001192 if (%_ArgumentsLength() < 2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 index = length - 1;
1194 } else {
1195 index = TO_INTEGER(index);
1196 // If index is negative, index from end of the array.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001197 if (index < 0) index += length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 // If index is still negative, do not search the array.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001199 if (index < 0) return -1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 else if (index >= length) index = length - 1;
1201 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001202 var min = 0;
1203 var max = index;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001204 if (UseSparseVariant(this, length, IS_ARRAY(this))) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001205 var intervals = %GetArrayKeys(this, index + 1);
1206 if (intervals.length == 2 && intervals[0] < 0) {
1207 // A single interval.
1208 var intervalMin = -(intervals[0] + 1);
1209 var intervalMax = intervalMin + intervals[1];
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001210 if (min < intervalMin) min = intervalMin;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001211 max = intervalMax; // Capped by index already.
1212 // Fall through to loop below.
1213 } else {
1214 if (intervals.length == 0) return -1;
1215 // Get all the keys in sorted order.
1216 var sortedKeys = GetSortedArrayKeys(this, intervals);
1217 var i = sortedKeys.length - 1;
1218 while (i >= 0) {
1219 var key = sortedKeys[i];
1220 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1221 i--;
1222 }
1223 return -1;
1224 }
1225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 // Lookup through the array.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001227 if (!IS_UNDEFINED(element)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001228 for (var i = max; i >= min; i--) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001229 if (this[i] === element) return i;
1230 }
1231 return -1;
1232 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001233 for (var i = max; i >= min; i--) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001234 if (IS_UNDEFINED(this[i]) && i in this) {
1235 return i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 }
1237 }
1238 return -1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001239}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240
1241
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001242function ArrayReduce(callback, current) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001243 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1244 throw MakeTypeError("called_on_null_or_undefined",
1245 ["Array.prototype.reduce"]);
1246 }
1247
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001248 if (!IS_FUNCTION(callback)) {
1249 throw MakeTypeError('called_non_callable', [callback]);
1250 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001251
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001252 // Pull out the length so that modifications to the length in the
1253 // loop will not affect the looping.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001254 var length = ToUint32(this.length);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001255 var i = 0;
1256
1257 find_initial: if (%_ArgumentsLength() < 2) {
1258 for (; i < length; i++) {
1259 current = this[i];
1260 if (!IS_UNDEFINED(current) || i in this) {
1261 i++;
1262 break find_initial;
1263 }
1264 }
1265 throw MakeTypeError('reduce_no_initial', []);
1266 }
1267
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001268 var receiver = %GetDefaultReceiver(callback);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001269 for (; i < length; i++) {
1270 var element = this[i];
1271 if (!IS_UNDEFINED(element) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001272 current = %_CallFunction(receiver, current, element, i, this, callback);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001273 }
1274 }
1275 return current;
1276}
1277
1278function ArrayReduceRight(callback, current) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001279 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1280 throw MakeTypeError("called_on_null_or_undefined",
1281 ["Array.prototype.reduceRight"]);
1282 }
1283
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001284 if (!IS_FUNCTION(callback)) {
1285 throw MakeTypeError('called_non_callable', [callback]);
1286 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001287 var i = ToUint32(this.length) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001288
1289 find_initial: if (%_ArgumentsLength() < 2) {
1290 for (; i >= 0; i--) {
1291 current = this[i];
1292 if (!IS_UNDEFINED(current) || i in this) {
1293 i--;
1294 break find_initial;
1295 }
1296 }
1297 throw MakeTypeError('reduce_no_initial', []);
1298 }
1299
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001300 var receiver = %GetDefaultReceiver(callback);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001301 for (; i >= 0; i--) {
1302 var element = this[i];
1303 if (!IS_UNDEFINED(element) || i in this) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001304 current = %_CallFunction(receiver, current, element, i, this, callback);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001305 }
1306 }
1307 return current;
1308}
1309
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001310// ES5, 15.4.3.2
1311function ArrayIsArray(obj) {
1312 return IS_ARRAY(obj);
1313}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315
1316// -------------------------------------------------------------------
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001317function SetUpArray() {
1318 %CheckIsBootstrapping();
1319 // Set up non-enumerable constructor property on the Array.prototype
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001320 // object.
1321 %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
1322
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001323 // Set up non-enumerable functions on the Array object.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001324 InstallFunctions($Array, DONT_ENUM, $Array(
1325 "isArray", ArrayIsArray
1326 ));
1327
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001328 var specialFunctions = %SpecialArrayFunctions({});
1329
1330 function getFunction(name, jsBuiltin, len) {
1331 var f = jsBuiltin;
1332 if (specialFunctions.hasOwnProperty(name)) {
1333 f = specialFunctions[name];
1334 }
1335 if (!IS_UNDEFINED(len)) {
1336 %FunctionSetLength(f, len);
1337 }
1338 return f;
1339 }
1340
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001341 // Set up non-enumerable functions of the Array.prototype object and
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001342 // set their names.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 // Manipulate the length of some of the functions to meet
1344 // expectations set by ECMA-262 or Mozilla.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001345 InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
1346 "toString", getFunction("toString", ArrayToString),
1347 "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
1348 "join", getFunction("join", ArrayJoin),
1349 "pop", getFunction("pop", ArrayPop),
1350 "push", getFunction("push", ArrayPush, 1),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001351 "concat", getFunction("concat", ArrayConcat, 1),
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001352 "reverse", getFunction("reverse", ArrayReverse),
1353 "shift", getFunction("shift", ArrayShift),
1354 "unshift", getFunction("unshift", ArrayUnshift, 1),
1355 "slice", getFunction("slice", ArraySlice, 2),
1356 "splice", getFunction("splice", ArraySplice, 2),
1357 "sort", getFunction("sort", ArraySort),
1358 "filter", getFunction("filter", ArrayFilter, 1),
1359 "forEach", getFunction("forEach", ArrayForEach, 1),
1360 "some", getFunction("some", ArraySome, 1),
1361 "every", getFunction("every", ArrayEvery, 1),
1362 "map", getFunction("map", ArrayMap, 1),
1363 "indexOf", getFunction("indexOf", ArrayIndexOf, 1),
1364 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
1365 "reduce", getFunction("reduce", ArrayReduce, 1),
1366 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1)
1367 ));
lrn@chromium.org25156de2010-04-06 13:10:27 +00001368
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001369 %FinishArrayPrototypeSetup($Array.prototype);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001370
1371 // The internal Array prototype doesn't need to be fancy, since it's never
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001372 // exposed to user code.
1373 // Adding only the functions that are actually used.
1374 SetUpLockedPrototype(InternalArray, $Array(), $Array(
1375 "join", getFunction("join", ArrayJoin),
1376 "pop", getFunction("pop", ArrayPop),
1377 "push", getFunction("push", ArrayPush)
1378 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001379}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001381SetUpArray();