OLD | NEW |
---|---|
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 } | 63 } |
64 } | 64 } |
65 keys.sort(function(a, b) { return a - b; }); | 65 keys.sort(function(a, b) { return a - b; }); |
66 return keys; | 66 return keys; |
67 } | 67 } |
68 | 68 |
69 | 69 |
70 // Optimized for sparse arrays if separator is ''. | 70 // Optimized for sparse arrays if separator is ''. |
71 function SparseJoin(array, len, convert) { | 71 function SparseJoin(array, len, convert) { |
72 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); | 72 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); |
73 var builder = new StringBuilder(); | |
74 var last_key = -1; | 73 var last_key = -1; |
75 var keys_length = keys.length; | 74 var keys_length = keys.length; |
75 | |
76 var elements = new $Array(keys_length); | |
77 var elements_length = 0; | |
78 | |
76 for (var i = 0; i < keys_length; i++) { | 79 for (var i = 0; i < keys_length; i++) { |
77 var key = keys[i]; | 80 var key = keys[i]; |
78 if (key != last_key) { | 81 if (key != last_key) { |
79 var e = array[key]; | 82 var e = array[key]; |
80 if (typeof(e) !== 'string') e = convert(e); | 83 if (!IS_STRING(e)) e = convert(e); |
81 builder.add(e); | 84 elements[elements_length++] = e; |
82 last_key = key; | 85 last_key = key; |
83 } | 86 } |
84 } | 87 } |
85 return builder.generate(); | 88 return %StringBuilderConcat(elements, elements_length, ''); |
86 } | 89 } |
87 | 90 |
88 | 91 |
89 function UseSparseVariant(object, length, is_array) { | 92 function UseSparseVariant(object, length, is_array) { |
90 return is_array && | 93 return is_array && |
91 length > 1000 && | 94 length > 1000 && |
92 (!%_IsSmi(length) || | 95 (!%_IsSmi(length) || |
93 %EstimateNumberOfElements(object) < (length >> 2)); | 96 %EstimateNumberOfElements(object) < (length >> 2)); |
94 } | 97 } |
95 | 98 |
96 | 99 |
97 function Join(array, length, separator, convert) { | 100 function Join(array, length, separator, convert) { |
98 if (length == 0) return ''; | 101 if (length == 0) return ''; |
99 | 102 |
100 var is_array = IS_ARRAY(array); | 103 var is_array = IS_ARRAY(array); |
101 | 104 |
102 if (is_array) { | 105 if (is_array) { |
103 // If the array is cyclic, return the empty string for already | 106 // If the array is cyclic, return the empty string for already |
104 // visited arrays. | 107 // visited arrays. |
105 if (!%PushIfAbsent(visited_arrays, array)) return ''; | 108 if (!%PushIfAbsent(visited_arrays, array)) return ''; |
106 } | 109 } |
107 | 110 |
108 // Attempt to convert the elements. | 111 // Attempt to convert the elements. |
109 try { | 112 try { |
110 if (UseSparseVariant(array, length, is_array) && separator === '') { | 113 if (UseSparseVariant(array, length, is_array) && (separator.length == 0)) { |
Erik Corry
2010/01/06 14:03:57
I don't think the extra () around separator.length
| |
111 return SparseJoin(array, length, convert); | 114 return SparseJoin(array, length, convert); |
112 } | 115 } |
113 | 116 |
114 // Fast case for one-element arrays. | 117 // Fast case for one-element arrays. |
115 if (length == 1) { | 118 if (length == 1) { |
116 var e = array[0]; | 119 var e = array[0]; |
117 if (!IS_UNDEFINED(e) || (0 in array)) { | 120 if (!IS_UNDEFINED(e) || (0 in array)) { |
118 if (typeof(e) === 'string') return e; | 121 if (IS_STRING(e)) return e; |
119 return convert(e); | 122 return convert(e); |
120 } | 123 } |
121 } | 124 } |
122 | 125 |
123 var builder = new StringBuilder(); | 126 // Construct an array for the elements. |
127 var elements; | |
128 var elements_length = 0; | |
124 | 129 |
125 // We pull the empty separator check outside the loop for speed! | 130 // We pull the empty separator check outside the loop for speed! |
126 if (separator.length == 0) { | 131 if (separator.length == 0) { |
132 elements = new $Array(length); | |
127 for (var i = 0; i < length; i++) { | 133 for (var i = 0; i < length; i++) { |
128 var e = array[i]; | 134 var e = array[i]; |
129 if (!IS_UNDEFINED(e) || (i in array)) { | 135 if (!IS_UNDEFINED(e) || (i in array)) { |
130 if (typeof(e) !== 'string') e = convert(e); | 136 if (!IS_STRING(e)) e = convert(e); |
131 if (e.length > 0) { | 137 elements[elements_length++] = e; |
132 var elements = builder.elements; | |
133 elements[elements.length] = e; | |
134 } | |
135 } | 138 } |
136 } | 139 } |
137 } else { | 140 } else { |
141 elements = new $Array(length << 1); | |
138 for (var i = 0; i < length; i++) { | 142 for (var i = 0; i < length; i++) { |
139 var e = array[i]; | 143 var e = array[i]; |
140 if (i != 0) builder.add(separator); | 144 if (i != 0) elements[elements_length++] = separator; |
141 if (!IS_UNDEFINED(e) || (i in array)) { | 145 if (!IS_UNDEFINED(e) || (i in array)) { |
142 if (typeof(e) !== 'string') e = convert(e); | 146 if (!IS_STRING(e)) e = convert(e); |
143 if (e.length > 0) { | 147 elements[elements_length++] = e; |
144 var elements = builder.elements; | |
145 elements[elements.length] = e; | |
146 } | |
147 } | 148 } |
148 } | 149 } |
149 } | 150 } |
150 return builder.generate(); | 151 return %StringBuilderConcat(elements, elements_length, ''); |
151 } finally { | 152 } finally { |
152 // Make sure to pop the visited array no matter what happens. | 153 // Make sure to pop the visited array no matter what happens. |
153 if (is_array) visited_arrays.pop(); | 154 if (is_array) visited_arrays.pop(); |
154 } | 155 } |
155 } | 156 } |
156 | 157 |
157 | 158 |
158 function ConvertToString(e) { | 159 function ConvertToString(e) { |
159 if (typeof(e) === 'string') return e; | |
160 if (e == null) return ''; | 160 if (e == null) return ''; |
161 else return ToString(e); | 161 else return ToString(e); |
162 } | 162 } |
163 | 163 |
164 | 164 |
165 function ConvertToLocaleString(e) { | 165 function ConvertToLocaleString(e) { |
166 if (typeof(e) === 'string') return e; | 166 if (e == null) { |
167 if (e == null) return ''; | 167 return ''; |
168 else { | 168 } else { |
169 // e_obj's toLocaleString might be overwritten, check if it is a function. | 169 // e_obj's toLocaleString might be overwritten, check if it is a function. |
170 // Call ToString if toLocaleString is not a function. | 170 // Call ToString if toLocaleString is not a function. |
171 // See issue 877615. | 171 // See issue 877615. |
172 var e_obj = ToObject(e); | 172 var e_obj = ToObject(e); |
173 if (IS_FUNCTION(e_obj.toLocaleString)) | 173 if (IS_FUNCTION(e_obj.toLocaleString)) |
174 return ToString(e_obj.toLocaleString()); | 174 return ToString(e_obj.toLocaleString()); |
175 else | 175 else |
176 return ToString(e); | 176 return ToString(e); |
177 } | 177 } |
178 } | 178 } |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
352 | 352 |
353 function ArrayToLocaleString() { | 353 function ArrayToLocaleString() { |
354 if (!IS_ARRAY(this)) { | 354 if (!IS_ARRAY(this)) { |
355 throw new $TypeError('Array.prototype.toString is not generic'); | 355 throw new $TypeError('Array.prototype.toString is not generic'); |
356 } | 356 } |
357 return Join(this, this.length, ',', ConvertToLocaleString); | 357 return Join(this, this.length, ',', ConvertToLocaleString); |
358 } | 358 } |
359 | 359 |
360 | 360 |
361 function ArrayJoin(separator) { | 361 function ArrayJoin(separator) { |
362 if (IS_UNDEFINED(separator)) separator = ','; | 362 if (IS_UNDEFINED(separator)) { |
363 else separator = ToString(separator); | 363 separator = ','; |
364 return Join(this, ToUint32(this.length), separator, ConvertToString); | 364 } else if (!IS_STRING(separator)) { |
365 separator = ToString(separator); | |
366 } | |
367 var length = TO_UINT32(this.length); | |
368 return Join(this, length, separator, ConvertToString); | |
365 } | 369 } |
366 | 370 |
367 | 371 |
368 // Removes the last element from the array and returns it. See | 372 // Removes the last element from the array and returns it. See |
369 // ECMA-262, section 15.4.4.6. | 373 // ECMA-262, section 15.4.4.6. |
370 function ArrayPop() { | 374 function ArrayPop() { |
371 var n = ToUint32(this.length); | 375 var n = TO_UINT32(this.length); |
372 if (n == 0) { | 376 if (n == 0) { |
373 this.length = n; | 377 this.length = n; |
374 return; | 378 return; |
375 } | 379 } |
376 n--; | 380 n--; |
377 var value = this[n]; | 381 var value = this[n]; |
378 this.length = n; | 382 this.length = n; |
379 delete this[n]; | 383 delete this[n]; |
380 return value; | 384 return value; |
381 } | 385 } |
382 | 386 |
383 | 387 |
384 // Appends the arguments to the end of the array and returns the new | 388 // Appends the arguments to the end of the array and returns the new |
385 // length of the array. See ECMA-262, section 15.4.4.7. | 389 // length of the array. See ECMA-262, section 15.4.4.7. |
386 function ArrayPush() { | 390 function ArrayPush() { |
387 var n = ToUint32(this.length); | 391 var n = TO_UINT32(this.length); |
388 var m = %_ArgumentsLength(); | 392 var m = %_ArgumentsLength(); |
389 for (var i = 0; i < m; i++) { | 393 for (var i = 0; i < m; i++) { |
390 this[i+n] = %_Arguments(i); | 394 this[i+n] = %_Arguments(i); |
391 } | 395 } |
392 this.length = n + m; | 396 this.length = n + m; |
393 return this.length; | 397 return this.length; |
394 } | 398 } |
395 | 399 |
396 | 400 |
397 function ArrayConcat(arg1) { // length == 1 | 401 function ArrayConcat(arg1) { // length == 1 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
445 if (!IS_UNDEFINED(current_j) || high in array) { | 449 if (!IS_UNDEFINED(current_j) || high in array) { |
446 array[low] = current_j; | 450 array[low] = current_j; |
447 delete array[high]; | 451 delete array[high]; |
448 } | 452 } |
449 } | 453 } |
450 } | 454 } |
451 } | 455 } |
452 | 456 |
453 | 457 |
454 function ArrayReverse() { | 458 function ArrayReverse() { |
455 var j = ToUint32(this.length) - 1; | 459 var j = TO_UINT32(this.length) - 1; |
456 | 460 |
457 if (UseSparseVariant(this, j, IS_ARRAY(this))) { | 461 if (UseSparseVariant(this, j, IS_ARRAY(this))) { |
458 SparseReverse(this, j+1); | 462 SparseReverse(this, j+1); |
459 return this; | 463 return this; |
460 } | 464 } |
461 | 465 |
462 for (var i = 0; i < j; i++, j--) { | 466 for (var i = 0; i < j; i++, j--) { |
463 var current_i = this[i]; | 467 var current_i = this[i]; |
464 if (!IS_UNDEFINED(current_i) || i in this) { | 468 if (!IS_UNDEFINED(current_i) || i in this) { |
465 var current_j = this[j]; | 469 var current_j = this[j]; |
(...skipping 10 matching lines...) Expand all Loading... | |
476 this[i] = current_j; | 480 this[i] = current_j; |
477 delete this[j]; | 481 delete this[j]; |
478 } | 482 } |
479 } | 483 } |
480 } | 484 } |
481 return this; | 485 return this; |
482 } | 486 } |
483 | 487 |
484 | 488 |
485 function ArrayShift() { | 489 function ArrayShift() { |
486 var len = ToUint32(this.length); | 490 var len = TO_UINT32(this.length); |
487 | 491 |
488 if (len === 0) { | 492 if (len === 0) { |
489 this.length = 0; | 493 this.length = 0; |
490 return; | 494 return; |
491 } | 495 } |
492 | 496 |
493 var first = this[0]; | 497 var first = this[0]; |
494 | 498 |
495 if (IS_ARRAY(this)) | 499 if (IS_ARRAY(this)) |
496 SmartMove(this, 0, 1, len, 0); | 500 SmartMove(this, 0, 1, len, 0); |
497 else | 501 else |
498 SimpleMove(this, 0, 1, len, 0); | 502 SimpleMove(this, 0, 1, len, 0); |
499 | 503 |
500 this.length = len - 1; | 504 this.length = len - 1; |
501 | 505 |
502 return first; | 506 return first; |
503 } | 507 } |
504 | 508 |
505 | 509 |
506 function ArrayUnshift(arg1) { // length == 1 | 510 function ArrayUnshift(arg1) { // length == 1 |
507 var len = ToUint32(this.length); | 511 var len = TO_UINT32(this.length); |
508 var num_arguments = %_ArgumentsLength(); | 512 var num_arguments = %_ArgumentsLength(); |
509 | 513 |
510 if (IS_ARRAY(this)) | 514 if (IS_ARRAY(this)) |
511 SmartMove(this, 0, 0, len, num_arguments); | 515 SmartMove(this, 0, 0, len, num_arguments); |
512 else | 516 else |
513 SimpleMove(this, 0, 0, len, num_arguments); | 517 SimpleMove(this, 0, 0, len, num_arguments); |
514 | 518 |
515 for (var i = 0; i < num_arguments; i++) { | 519 for (var i = 0; i < num_arguments; i++) { |
516 this[i] = %_Arguments(i); | 520 this[i] = %_Arguments(i); |
517 } | 521 } |
518 | 522 |
519 this.length = len + num_arguments; | 523 this.length = len + num_arguments; |
520 | 524 |
521 return len + num_arguments; | 525 return len + num_arguments; |
522 } | 526 } |
523 | 527 |
524 | 528 |
525 function ArraySlice(start, end) { | 529 function ArraySlice(start, end) { |
526 var len = ToUint32(this.length); | 530 var len = TO_UINT32(this.length); |
527 var start_i = TO_INTEGER(start); | 531 var start_i = TO_INTEGER(start); |
528 var end_i = len; | 532 var end_i = len; |
529 | 533 |
530 if (end !== void 0) end_i = TO_INTEGER(end); | 534 if (end !== void 0) end_i = TO_INTEGER(end); |
531 | 535 |
532 if (start_i < 0) { | 536 if (start_i < 0) { |
533 start_i += len; | 537 start_i += len; |
534 if (start_i < 0) start_i = 0; | 538 if (start_i < 0) start_i = 0; |
535 } else { | 539 } else { |
536 if (start_i > len) start_i = len; | 540 if (start_i > len) start_i = len; |
(...skipping 24 matching lines...) Expand all Loading... | |
561 | 565 |
562 function ArraySplice(start, delete_count) { | 566 function ArraySplice(start, delete_count) { |
563 var num_arguments = %_ArgumentsLength(); | 567 var num_arguments = %_ArgumentsLength(); |
564 | 568 |
565 // SpiderMonkey and KJS return undefined in the case where no | 569 // SpiderMonkey and KJS return undefined in the case where no |
566 // arguments are given instead of using the implicit undefined | 570 // arguments are given instead of using the implicit undefined |
567 // arguments. This does not follow ECMA-262, but we do the same for | 571 // arguments. This does not follow ECMA-262, but we do the same for |
568 // compatibility. | 572 // compatibility. |
569 if (num_arguments == 0) return; | 573 if (num_arguments == 0) return; |
570 | 574 |
571 var len = ToUint32(this.length); | 575 var len = TO_UINT32(this.length); |
572 var start_i = TO_INTEGER(start); | 576 var start_i = TO_INTEGER(start); |
573 | 577 |
574 if (start_i < 0) { | 578 if (start_i < 0) { |
575 start_i += len; | 579 start_i += len; |
576 if (start_i < 0) start_i = 0; | 580 if (start_i < 0) start_i = 0; |
577 } else { | 581 } else { |
578 if (start_i > len) start_i = len; | 582 if (start_i > len) start_i = len; |
579 } | 583 } |
580 | 584 |
581 // SpiderMonkey and KJS treat the case where no delete count is | 585 // SpiderMonkey and KJS treat the case where no delete count is |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
843 obj[i] = void 0; | 847 obj[i] = void 0; |
844 } else { | 848 } else { |
845 delete obj[i]; | 849 delete obj[i]; |
846 } | 850 } |
847 } | 851 } |
848 | 852 |
849 // Return the number of defined elements. | 853 // Return the number of defined elements. |
850 return first_undefined; | 854 return first_undefined; |
851 } | 855 } |
852 | 856 |
853 length = ToUint32(this.length); | 857 length = TO_UINT32(this.length); |
854 if (length < 2) return this; | 858 if (length < 2) return this; |
855 | 859 |
856 var is_array = IS_ARRAY(this); | 860 var is_array = IS_ARRAY(this); |
857 var max_prototype_element; | 861 var max_prototype_element; |
858 if (!is_array) { | 862 if (!is_array) { |
859 // For compatibility with JSC, we also sort elements inherited from | 863 // For compatibility with JSC, we also sort elements inherited from |
860 // the prototype chain on non-Array objects. | 864 // the prototype chain on non-Array objects. |
861 // We do this by copying them to this object and sorting only | 865 // We do this by copying them to this object and sorting only |
862 // local elements. This is not very efficient, but sorting with | 866 // local elements. This is not very efficient, but sorting with |
863 // inherited elements happens very, very rarely, if at all. | 867 // inherited elements happens very, very rarely, if at all. |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1143 ArrayIndexOf: 1, | 1147 ArrayIndexOf: 1, |
1144 ArrayLastIndexOf: 1, | 1148 ArrayLastIndexOf: 1, |
1145 ArrayPush: 1, | 1149 ArrayPush: 1, |
1146 ArrayReduce: 1, | 1150 ArrayReduce: 1, |
1147 ArrayReduceRight: 1 | 1151 ArrayReduceRight: 1 |
1148 }); | 1152 }); |
1149 } | 1153 } |
1150 | 1154 |
1151 | 1155 |
1152 SetupArray(); | 1156 SetupArray(); |
OLD | NEW |