blob: e6c13d9547c5f114480706f46ebd2a6d3c2bdd69 [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.org4f693d62011-07-04 14:01:31 +0000745 var receiver =
746 %_IsNativeOrStrictMode(comparefn) ? void 0 : %GetGlobalReceiver();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000747
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000748 function InsertionSort(a, from, to) {
749 for (var i = from + 1; i < to; i++) {
750 var element = a[i];
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000751 for (var j = i - 1; j >= from; j--) {
752 var tmp = a[j];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000753 var order = %_CallFunction(receiver, tmp, element, comparefn);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000754 if (order > 0) {
755 a[j + 1] = tmp;
756 } else {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000757 break;
758 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000759 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000760 a[j + 1] = element;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000761 }
762 }
763
764 function QuickSort(a, from, to) {
765 // Insertion sort is faster for short arrays.
whesse@chromium.org023421e2010-12-21 12:19:12 +0000766 if (to - from <= 10) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000767 InsertionSort(a, from, to);
768 return;
769 }
whesse@chromium.org023421e2010-12-21 12:19:12 +0000770 // Find a pivot as the median of first, last and middle element.
771 var v0 = a[from];
772 var v1 = a[to - 1];
773 var middle_index = from + ((to - from) >> 1);
774 var v2 = a[middle_index];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000775 var c01 = %_CallFunction(receiver, v0, v1, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000776 if (c01 > 0) {
777 // v1 < v0, so swap them.
778 var tmp = v0;
779 v0 = v1;
780 v1 = tmp;
781 } // v0 <= v1.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000782 var c02 = %_CallFunction(receiver, v0, v2, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000783 if (c02 >= 0) {
784 // v2 <= v0 <= v1.
785 var tmp = v0;
786 v0 = v2;
787 v2 = v1;
788 v1 = tmp;
789 } else {
790 // v0 <= v1 && v0 < v2
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000791 var c12 = %_CallFunction(receiver, v1, v2, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000792 if (c12 > 0) {
793 // v0 <= v2 < v1
794 var tmp = v1;
795 v1 = v2;
796 v2 = tmp;
797 }
798 }
799 // v0 <= v1 <= v2
800 a[from] = v0;
801 a[to - 1] = v2;
802 var pivot = v1;
803 var low_end = from + 1; // Upper bound of elements lower than pivot.
804 var high_start = to - 1; // Lower bound of elements greater than pivot.
805 a[middle_index] = a[low_end];
806 a[low_end] = pivot;
807
ager@chromium.org381abbb2009-02-25 13:23:22 +0000808 // From low_end to i are elements equal to pivot.
809 // From i to high_start are elements that haven't been compared yet.
whesse@chromium.org023421e2010-12-21 12:19:12 +0000810 partition: for (var i = low_end + 1; i < high_start; i++) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000811 var element = a[i];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000812 var order = %_CallFunction(receiver, element, pivot, comparefn);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000813 if (order < 0) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000814 %_SwapElements(a, i, low_end);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000815 low_end++;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000816 } else if (order > 0) {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000817 do {
818 high_start--;
819 if (high_start == i) break partition;
820 var top_elem = a[high_start];
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000821 order = %_CallFunction(receiver, top_elem, pivot, comparefn);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000822 } while (order > 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000823 %_SwapElements(a, i, high_start);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000824 if (order < 0) {
825 %_SwapElements(a, i, low_end);
826 low_end++;
827 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000828 }
829 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000830 QuickSort(a, from, low_end);
831 QuickSort(a, high_start, to);
832 }
833
whesse@chromium.org023421e2010-12-21 12:19:12 +0000834 // Copy elements in the range 0..length from obj's prototype chain
835 // to obj itself, if obj has holes. Return one more than the maximal index
ager@chromium.org5ec48922009-05-05 07:25:34 +0000836 // of a prototype property.
837 function CopyFromPrototype(obj, length) {
838 var max = 0;
839 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
840 var indices = %GetArrayKeys(proto, length);
841 if (indices.length > 0) {
842 if (indices[0] == -1) {
843 // It's an interval.
844 var proto_length = indices[1];
845 for (var i = 0; i < proto_length; i++) {
846 if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
847 obj[i] = proto[i];
848 if (i >= max) { max = i + 1; }
849 }
850 }
851 } else {
852 for (var i = 0; i < indices.length; i++) {
853 var index = indices[i];
854 if (!IS_UNDEFINED(index) &&
855 !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
856 obj[index] = proto[index];
857 if (index >= max) { max = index + 1; }
858 }
859 }
860 }
861 }
862 }
863 return max;
864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865
ager@chromium.org5ec48922009-05-05 07:25:34 +0000866 // Set a value of "undefined" on all indices in the range from..to
867 // where a prototype of obj has an element. I.e., shadow all prototype
868 // elements in that range.
869 function ShadowPrototypeElements(obj, from, to) {
870 for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
871 var indices = %GetArrayKeys(proto, to);
872 if (indices.length > 0) {
873 if (indices[0] == -1) {
874 // It's an interval.
875 var proto_length = indices[1];
876 for (var i = from; i < proto_length; i++) {
877 if (proto.hasOwnProperty(i)) {
878 obj[i] = void 0;
879 }
880 }
881 } else {
882 for (var i = 0; i < indices.length; i++) {
883 var index = indices[i];
884 if (!IS_UNDEFINED(index) && from <= index &&
885 proto.hasOwnProperty(index)) {
886 obj[index] = void 0;
887 }
888 }
889 }
890 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 }
892 }
893
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000894 function SafeRemoveArrayHoles(obj) {
895 // Copy defined elements from the end to fill in all holes and undefineds
896 // in the beginning of the array. Write undefineds and holes at the end
897 // after loop is finished.
898 var first_undefined = 0;
899 var last_defined = length - 1;
900 var num_holes = 0;
901 while (first_undefined < last_defined) {
902 // Find first undefined element.
903 while (first_undefined < last_defined &&
904 !IS_UNDEFINED(obj[first_undefined])) {
905 first_undefined++;
906 }
907 // Maintain the invariant num_holes = the number of holes in the original
908 // array with indices <= first_undefined or > last_defined.
909 if (!obj.hasOwnProperty(first_undefined)) {
910 num_holes++;
911 }
912
913 // Find last defined element.
914 while (first_undefined < last_defined &&
915 IS_UNDEFINED(obj[last_defined])) {
916 if (!obj.hasOwnProperty(last_defined)) {
917 num_holes++;
918 }
919 last_defined--;
920 }
921 if (first_undefined < last_defined) {
922 // Fill in hole or undefined.
923 obj[first_undefined] = obj[last_defined];
924 obj[last_defined] = void 0;
925 }
926 }
927 // If there were any undefineds in the entire array, first_undefined
928 // points to one past the last defined element. Make this true if
929 // there were no undefineds, as well, so that first_undefined == number
930 // of defined elements.
931 if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++;
932 // Fill in the undefineds and the holes. There may be a hole where
933 // an undefined should be and vice versa.
934 var i;
935 for (i = first_undefined; i < length - num_holes; i++) {
936 obj[i] = void 0;
937 }
938 for (i = length - num_holes; i < length; i++) {
939 // For compatability with Webkit, do not expose elements in the prototype.
940 if (i in obj.__proto__) {
941 obj[i] = void 0;
942 } else {
943 delete obj[i];
944 }
945 }
946
947 // Return the number of defined elements.
948 return first_undefined;
949 }
950
ager@chromium.org357bf652010-04-12 11:30:10 +0000951 var length = TO_UINT32(this.length);
ager@chromium.org5ec48922009-05-05 07:25:34 +0000952 if (length < 2) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953
ager@chromium.org5ec48922009-05-05 07:25:34 +0000954 var is_array = IS_ARRAY(this);
955 var max_prototype_element;
956 if (!is_array) {
957 // For compatibility with JSC, we also sort elements inherited from
958 // the prototype chain on non-Array objects.
959 // We do this by copying them to this object and sorting only
960 // local elements. This is not very efficient, but sorting with
961 // inherited elements happens very, very rarely, if at all.
962 // The specification allows "implementation dependent" behavior
963 // if an element on the prototype chain has an element that
964 // might interact with sorting.
965 max_prototype_element = CopyFromPrototype(this, length);
966 }
967
968 var num_non_undefined = %RemoveArrayHoles(this, length);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000969 if (num_non_undefined == -1) {
970 // There were indexed accessors in the array. Move array holes and
971 // undefineds to the end using a Javascript function that is safe
972 // in the presence of accessors.
973 num_non_undefined = SafeRemoveArrayHoles(this);
974 }
ager@chromium.org5ec48922009-05-05 07:25:34 +0000975
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000976 QuickSort(this, 0, num_non_undefined);
ager@chromium.org5ec48922009-05-05 07:25:34 +0000977
978 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {
979 // For compatibility with JSC, we shadow any elements in the prototype
980 // chain that has become exposed by sort moving a hole to its position.
981 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 }
983
984 return this;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000985}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000986
987
988// The following functions cannot be made efficient on sparse arrays while
989// preserving the semantics, since the calls to the receiver function can add
990// or delete elements from the array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991function ArrayFilter(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000992 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
993 throw MakeTypeError("called_on_null_or_undefined",
994 ["Array.prototype.filter"]);
995 }
996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 if (!IS_FUNCTION(f)) {
998 throw MakeTypeError('called_non_callable', [ f ]);
999 }
1000 // Pull out the length so that modifications to the length in the
1001 // loop will not affect the looping.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001002 var length = ToUint32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 var result = [];
ager@chromium.org381abbb2009-02-25 13:23:22 +00001004 var result_length = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005 for (var i = 0; i < length; i++) {
1006 var current = this[i];
1007 if (!IS_UNDEFINED(current) || i in this) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001008 if (f.call(receiver, current, i, this)) {
1009 result[result_length++] = current;
1010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 }
1012 }
1013 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001014}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
1016
1017function ArrayForEach(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001018 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1019 throw MakeTypeError("called_on_null_or_undefined",
1020 ["Array.prototype.forEach"]);
1021 }
1022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 if (!IS_FUNCTION(f)) {
1024 throw MakeTypeError('called_non_callable', [ f ]);
1025 }
1026 // Pull out the length so that modifications to the length in the
1027 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001028 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 for (var i = 0; i < length; i++) {
1030 var current = this[i];
1031 if (!IS_UNDEFINED(current) || i in this) {
1032 f.call(receiver, current, i, this);
1033 }
1034 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001035}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036
1037
1038// Executes the function once for each element present in the
1039// array until it finds one where callback returns true.
1040function ArraySome(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001041 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1042 throw MakeTypeError("called_on_null_or_undefined",
1043 ["Array.prototype.some"]);
1044 }
1045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 if (!IS_FUNCTION(f)) {
1047 throw MakeTypeError('called_non_callable', [ f ]);
1048 }
1049 // Pull out the length so that modifications to the length in the
1050 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001051 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 for (var i = 0; i < length; i++) {
1053 var current = this[i];
1054 if (!IS_UNDEFINED(current) || i in this) {
1055 if (f.call(receiver, current, i, this)) return true;
1056 }
1057 }
1058 return false;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001059}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060
1061
1062function ArrayEvery(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001063 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1064 throw MakeTypeError("called_on_null_or_undefined",
1065 ["Array.prototype.every"]);
1066 }
1067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 if (!IS_FUNCTION(f)) {
1069 throw MakeTypeError('called_non_callable', [ f ]);
1070 }
1071 // Pull out the length so that modifications to the length in the
1072 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001073 var length = TO_UINT32(this.length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074 for (var i = 0; i < length; i++) {
1075 var current = this[i];
1076 if (!IS_UNDEFINED(current) || i in this) {
1077 if (!f.call(receiver, current, i, this)) return false;
1078 }
1079 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 return true;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001081}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083function ArrayMap(f, receiver) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001084 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1085 throw MakeTypeError("called_on_null_or_undefined",
1086 ["Array.prototype.map"]);
1087 }
1088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 if (!IS_FUNCTION(f)) {
1090 throw MakeTypeError('called_non_callable', [ f ]);
1091 }
1092 // Pull out the length so that modifications to the length in the
1093 // loop will not affect the looping.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001094 var length = TO_UINT32(this.length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001095 var result = new $Array();
1096 var accumulator = new InternalArray(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 for (var i = 0; i < length; i++) {
1098 var current = this[i];
1099 if (!IS_UNDEFINED(current) || i in this) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001100 accumulator[i] = f.call(receiver, current, i, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 }
1102 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001103 %MoveArrayContents(accumulator, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001105}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106
1107
1108function ArrayIndexOf(element, index) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001109 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1110 throw MakeTypeError("called_on_null_or_undefined",
1111 ["Array.prototype.indexOf"]);
1112 }
1113
ricow@chromium.org65fae842010-08-25 15:26:24 +00001114 var length = TO_UINT32(this.length);
1115 if (length == 0) return -1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001116 if (IS_UNDEFINED(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 index = 0;
1118 } else {
1119 index = TO_INTEGER(index);
1120 // If index is negative, index from the end of the array.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001121 if (index < 0) {
1122 index = length + index;
1123 // If index is still negative, search the entire array.
1124 if (index < 0) index = 0;
1125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001127 var min = index;
1128 var max = length;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001129 if (UseSparseVariant(this, length, IS_ARRAY(this))) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001130 var intervals = %GetArrayKeys(this, length);
1131 if (intervals.length == 2 && intervals[0] < 0) {
1132 // A single interval.
1133 var intervalMin = -(intervals[0] + 1);
1134 var intervalMax = intervalMin + intervals[1];
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001135 if (min < intervalMin) min = intervalMin;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001136 max = intervalMax; // Capped by length already.
1137 // Fall through to loop below.
1138 } else {
1139 if (intervals.length == 0) return -1;
1140 // Get all the keys in sorted order.
1141 var sortedKeys = GetSortedArrayKeys(this, intervals);
1142 var n = sortedKeys.length;
1143 var i = 0;
1144 while (i < n && sortedKeys[i] < index) i++;
1145 while (i < n) {
1146 var key = sortedKeys[i];
1147 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1148 i++;
1149 }
1150 return -1;
1151 }
1152 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001153 // Lookup through the array.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001154 if (!IS_UNDEFINED(element)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001155 for (var i = min; i < max; i++) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001156 if (this[i] === element) return i;
1157 }
1158 return -1;
1159 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001160 // Lookup through the array.
1161 for (var i = min; i < max; i++) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001162 if (IS_UNDEFINED(this[i]) && i in this) {
1163 return i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 }
1165 }
1166 return -1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001167}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169
1170function ArrayLastIndexOf(element, index) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001171 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1172 throw MakeTypeError("called_on_null_or_undefined",
1173 ["Array.prototype.lastIndexOf"]);
1174 }
1175
ricow@chromium.org65fae842010-08-25 15:26:24 +00001176 var length = TO_UINT32(this.length);
1177 if (length == 0) return -1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001178 if (%_ArgumentsLength() < 2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 index = length - 1;
1180 } else {
1181 index = TO_INTEGER(index);
1182 // If index is negative, index from end of the array.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001183 if (index < 0) index += length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 // If index is still negative, do not search the array.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001185 if (index < 0) return -1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 else if (index >= length) index = length - 1;
1187 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001188 var min = 0;
1189 var max = index;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001190 if (UseSparseVariant(this, length, IS_ARRAY(this))) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001191 var intervals = %GetArrayKeys(this, index + 1);
1192 if (intervals.length == 2 && intervals[0] < 0) {
1193 // A single interval.
1194 var intervalMin = -(intervals[0] + 1);
1195 var intervalMax = intervalMin + intervals[1];
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001196 if (min < intervalMin) min = intervalMin;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001197 max = intervalMax; // Capped by index already.
1198 // Fall through to loop below.
1199 } else {
1200 if (intervals.length == 0) return -1;
1201 // Get all the keys in sorted order.
1202 var sortedKeys = GetSortedArrayKeys(this, intervals);
1203 var i = sortedKeys.length - 1;
1204 while (i >= 0) {
1205 var key = sortedKeys[i];
1206 if (!IS_UNDEFINED(key) && this[key] === element) return key;
1207 i--;
1208 }
1209 return -1;
1210 }
1211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 // Lookup through the array.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001213 if (!IS_UNDEFINED(element)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001214 for (var i = max; i >= min; i--) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001215 if (this[i] === element) return i;
1216 }
1217 return -1;
1218 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001219 for (var i = max; i >= min; i--) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001220 if (IS_UNDEFINED(this[i]) && i in this) {
1221 return i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 }
1224 return -1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001225}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226
1227
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001228function ArrayReduce(callback, current) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001229 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1230 throw MakeTypeError("called_on_null_or_undefined",
1231 ["Array.prototype.reduce"]);
1232 }
1233
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001234 if (!IS_FUNCTION(callback)) {
1235 throw MakeTypeError('called_non_callable', [callback]);
1236 }
1237 // Pull out the length so that modifications to the length in the
1238 // loop will not affect the looping.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001239 var length = ToUint32(this.length);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001240 var i = 0;
1241
1242 find_initial: if (%_ArgumentsLength() < 2) {
1243 for (; i < length; i++) {
1244 current = this[i];
1245 if (!IS_UNDEFINED(current) || i in this) {
1246 i++;
1247 break find_initial;
1248 }
1249 }
1250 throw MakeTypeError('reduce_no_initial', []);
1251 }
1252
1253 for (; i < length; i++) {
1254 var element = this[i];
1255 if (!IS_UNDEFINED(element) || i in this) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001256 current = callback.call(void 0, current, element, i, this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001257 }
1258 }
1259 return current;
1260}
1261
1262function ArrayReduceRight(callback, current) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001263 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1264 throw MakeTypeError("called_on_null_or_undefined",
1265 ["Array.prototype.reduceRight"]);
1266 }
1267
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001268 if (!IS_FUNCTION(callback)) {
1269 throw MakeTypeError('called_non_callable', [callback]);
1270 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001271 var i = ToUint32(this.length) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001272
1273 find_initial: if (%_ArgumentsLength() < 2) {
1274 for (; i >= 0; i--) {
1275 current = this[i];
1276 if (!IS_UNDEFINED(current) || i in this) {
1277 i--;
1278 break find_initial;
1279 }
1280 }
1281 throw MakeTypeError('reduce_no_initial', []);
1282 }
1283
1284 for (; i >= 0; i--) {
1285 var element = this[i];
1286 if (!IS_UNDEFINED(element) || i in this) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001287 current = callback.call(void 0, current, element, i, this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001288 }
1289 }
1290 return current;
1291}
1292
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001293// ES5, 15.4.3.2
1294function ArrayIsArray(obj) {
1295 return IS_ARRAY(obj);
1296}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001297
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
1299// -------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300function SetupArray() {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001301 // Setup non-enumerable constructor property on the Array.prototype
1302 // object.
1303 %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
1304
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001305 // Setup non-enumerable functions on the Array object.
1306 InstallFunctions($Array, DONT_ENUM, $Array(
1307 "isArray", ArrayIsArray
1308 ));
1309
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001310 var specialFunctions = %SpecialArrayFunctions({});
1311
1312 function getFunction(name, jsBuiltin, len) {
1313 var f = jsBuiltin;
1314 if (specialFunctions.hasOwnProperty(name)) {
1315 f = specialFunctions[name];
1316 }
1317 if (!IS_UNDEFINED(len)) {
1318 %FunctionSetLength(f, len);
1319 }
1320 return f;
1321 }
1322
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001323 // Setup non-enumerable functions of the Array.prototype object and
1324 // set their names.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // Manipulate the length of some of the functions to meet
1326 // expectations set by ECMA-262 or Mozilla.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001327 InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
1328 "toString", getFunction("toString", ArrayToString),
1329 "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
1330 "join", getFunction("join", ArrayJoin),
1331 "pop", getFunction("pop", ArrayPop),
1332 "push", getFunction("push", ArrayPush, 1),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001333 "concat", getFunction("concat", ArrayConcat, 1),
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001334 "reverse", getFunction("reverse", ArrayReverse),
1335 "shift", getFunction("shift", ArrayShift),
1336 "unshift", getFunction("unshift", ArrayUnshift, 1),
1337 "slice", getFunction("slice", ArraySlice, 2),
1338 "splice", getFunction("splice", ArraySplice, 2),
1339 "sort", getFunction("sort", ArraySort),
1340 "filter", getFunction("filter", ArrayFilter, 1),
1341 "forEach", getFunction("forEach", ArrayForEach, 1),
1342 "some", getFunction("some", ArraySome, 1),
1343 "every", getFunction("every", ArrayEvery, 1),
1344 "map", getFunction("map", ArrayMap, 1),
1345 "indexOf", getFunction("indexOf", ArrayIndexOf, 1),
1346 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
1347 "reduce", getFunction("reduce", ArrayReduce, 1),
1348 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1)
1349 ));
lrn@chromium.org25156de2010-04-06 13:10:27 +00001350
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001351 %FinishArrayPrototypeSetup($Array.prototype);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001352
1353 // The internal Array prototype doesn't need to be fancy, since it's never
1354 // exposed to user code, so no hidden prototypes or DONT_ENUM attributes
1355 // are necessary.
1356 // The null __proto__ ensures that we never inherit any user created
1357 // getters or setters from, e.g., Object.prototype.
1358 InternalArray.prototype.__proto__ = null;
1359 // Adding only the functions that are actually used, and a toString.
1360 InternalArray.prototype.join = getFunction("join", ArrayJoin);
1361 InternalArray.prototype.pop = getFunction("pop", ArrayPop);
1362 InternalArray.prototype.push = getFunction("push", ArrayPush);
1363 InternalArray.prototype.toString = function() {
1364 return "Internal Array, length " + this.length;
1365 };
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001366}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367
1368
1369SetupArray();