OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function(global, utils, extrasUtils) { | 5 (function(global, utils, extrasUtils) { |
6 | 6 |
7 "use strict"; | 7 "use strict"; |
8 | 8 |
9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
10 | 10 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 return new constructor(length); | 43 return new constructor(length); |
44 } | 44 } |
45 | 45 |
46 | 46 |
47 function KeySortCompare(a, b) { | 47 function KeySortCompare(a, b) { |
48 return a - b; | 48 return a - b; |
49 } | 49 } |
50 | 50 |
51 function GetSortedArrayKeys(array, indices) { | 51 function GetSortedArrayKeys(array, indices) { |
52 if (IS_NUMBER(indices)) { | 52 if (IS_NUMBER(indices)) { |
53 var keys = new InternalArray(); | |
54 // It's an interval | 53 // It's an interval |
55 var limit = indices; | 54 var limit = indices; |
| 55 var keys = new InternalArray(); |
56 for (var i = 0; i < limit; ++i) { | 56 for (var i = 0; i < limit; ++i) { |
57 var e = array[i]; | 57 var e = array[i]; |
58 if (!IS_UNDEFINED(e) || i in array) { | 58 if (!IS_UNDEFINED(e) || i in array) { |
59 keys.push(i); | 59 keys.push(i); |
60 } | 60 } |
61 } | 61 } |
62 return keys; | 62 return keys; |
63 } | 63 } |
64 return InnerArraySort(indices, indices.length, KeySortCompare); | 64 return InnerArraySort(indices, indices.length, KeySortCompare); |
65 } | 65 } |
66 | 66 |
67 | 67 |
68 function SparseJoinWithSeparatorJS(array, keys, length, convert, separator) { | 68 function SparseJoinWithSeparatorJS(array, keys, length, use_locale, separator) { |
69 var keys_length = keys.length; | 69 var keys_length = keys.length; |
70 var elements = new InternalArray(keys_length * 2); | 70 var elements = new InternalArray(keys_length * 2); |
71 for (var i = 0; i < keys_length; i++) { | 71 for (var i = 0; i < keys_length; i++) { |
72 var key = keys[i]; | 72 var key = keys[i]; |
73 var e = array[key]; | |
74 elements[i * 2] = key; | 73 elements[i * 2] = key; |
75 elements[i * 2 + 1] = IS_STRING(e) ? e : convert(e); | 74 elements[i * 2 + 1] = ConvertToString(use_locale, array[key]); |
76 } | 75 } |
77 return %SparseJoinWithSeparator(elements, length, separator); | 76 return %SparseJoinWithSeparator(elements, length, separator); |
78 } | 77 } |
79 | 78 |
80 | 79 |
81 // Optimized for sparse arrays if separator is ''. | 80 // Optimized for sparse arrays if separator is ''. |
82 function SparseJoin(array, keys, convert) { | 81 function SparseJoin(array, keys, use_locale) { |
83 var keys_length = keys.length; | 82 var keys_length = keys.length; |
84 var elements = new InternalArray(keys_length); | 83 var elements = new InternalArray(keys_length); |
85 for (var i = 0; i < keys_length; i++) { | 84 for (var i = 0; i < keys_length; i++) { |
86 var e = array[keys[i]]; | 85 elements[i] = ConvertToString(use_locale, array[keys[i]]); |
87 elements[i] = IS_STRING(e) ? e : convert(e); | |
88 } | 86 } |
89 return %StringBuilderConcat(elements, keys_length, ''); | 87 return %StringBuilderConcat(elements, keys_length, ''); |
90 } | 88 } |
91 | 89 |
92 | 90 |
93 function UseSparseVariant(array, length, is_array, touched) { | 91 function UseSparseVariant(array, length, is_array, touched) { |
94 // Only use the sparse variant on arrays that are likely to be sparse and the | 92 // Only use the sparse variant on arrays that are likely to be sparse and the |
95 // number of elements touched in the operation is relatively small compared to | 93 // number of elements touched in the operation is relatively small compared to |
96 // the overall size of the array. | 94 // the overall size of the array. |
97 if (!is_array || length < 1000 || %HasComplexElements(array)) { | 95 if (!is_array || length < 1000 || %HasComplexElements(array)) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 for (var i = 0; i < length; i++) { | 128 for (var i = 0; i < length; i++) { |
131 if (values[i] === v) return true; | 129 if (values[i] === v) return true; |
132 } | 130 } |
133 return false; | 131 return false; |
134 } | 132 } |
135 | 133 |
136 // Global list of arrays visited during toString, toLocaleString and | 134 // Global list of arrays visited during toString, toLocaleString and |
137 // join invocations. | 135 // join invocations. |
138 var visited_arrays = new Stack(); | 136 var visited_arrays = new Stack(); |
139 | 137 |
140 function DoJoin(array, length, is_array, separator, convert) { | 138 function DoJoin(array, length, is_array, separator, use_locale) { |
141 if (UseSparseVariant(array, length, is_array, length)) { | 139 if (UseSparseVariant(array, length, is_array, length)) { |
142 %NormalizeElements(array); | 140 %NormalizeElements(array); |
143 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length)); | 141 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length)); |
144 if (separator === '') { | 142 if (separator === '') { |
145 if (keys.length === 0) return ''; | 143 if (keys.length === 0) return ''; |
146 return SparseJoin(array, keys, convert); | 144 return SparseJoin(array, keys, use_locale); |
147 } else { | 145 } else { |
148 return SparseJoinWithSeparatorJS(array, keys, length, convert, separator); | 146 return SparseJoinWithSeparatorJS( |
| 147 array, keys, length, use_locale, separator); |
149 } | 148 } |
150 } | 149 } |
151 | 150 |
152 // Fast case for one-element arrays. | 151 // Fast case for one-element arrays. |
153 if (length === 1) { | 152 if (length === 1) { |
154 var e = array[0]; | 153 return ConvertToString(use_locale, array[0]); |
155 return IS_STRING(e) ? e : convert(e); | |
156 } | 154 } |
157 | 155 |
158 // Construct an array for the elements. | 156 // Construct an array for the elements. |
159 var elements = new InternalArray(length); | 157 var elements = new InternalArray(length); |
| 158 for (var i = 0; i < length; i++) { |
| 159 elements[i] = ConvertToString(use_locale, array[i]); |
| 160 } |
160 | 161 |
161 // We pull the empty separator check outside the loop for speed! | |
162 if (separator === '') { | 162 if (separator === '') { |
163 for (var i = 0; i < length; i++) { | |
164 var e = array[i]; | |
165 elements[i] = IS_STRING(e) ? e : convert(e); | |
166 } | |
167 return %StringBuilderConcat(elements, length, ''); | 163 return %StringBuilderConcat(elements, length, ''); |
| 164 } else { |
| 165 return %StringBuilderJoin(elements, length, separator); |
168 } | 166 } |
169 // Non-empty separator case. | |
170 // If the first element is a number then use the heuristic that the | |
171 // remaining elements are also likely to be numbers. | |
172 var e = array[0]; | |
173 if (IS_NUMBER(e)) { | |
174 elements[0] = %_NumberToString(e); | |
175 for (var i = 1; i < length; i++) { | |
176 e = array[i]; | |
177 if (IS_NUMBER(e)) { | |
178 elements[i] = %_NumberToString(e); | |
179 } else { | |
180 elements[i] = IS_STRING(e) ? e : convert(e); | |
181 } | |
182 } | |
183 } else { | |
184 elements[0] = IS_STRING(e) ? e : convert(e); | |
185 for (var i = 1; i < length; i++) { | |
186 e = array[i]; | |
187 elements[i] = IS_STRING(e) ? e : convert(e); | |
188 } | |
189 } | |
190 return %StringBuilderJoin(elements, length, separator); | |
191 } | 167 } |
192 | 168 |
193 function Join(array, length, separator, convert) { | 169 function Join(array, length, separator, use_locale) { |
194 if (length === 0) return ''; | 170 if (length === 0) return ''; |
195 | 171 |
196 var is_array = IS_ARRAY(array); | 172 var is_array = IS_ARRAY(array); |
197 | 173 |
198 if (is_array) { | 174 if (is_array) { |
199 // If the array is cyclic, return the empty string for already | 175 // If the array is cyclic, return the empty string for already |
200 // visited arrays. | 176 // visited arrays. |
201 if (StackHas(visited_arrays, array)) return ''; | 177 if (StackHas(visited_arrays, array)) return ''; |
202 StackPush(visited_arrays, array); | 178 StackPush(visited_arrays, array); |
203 } | 179 } |
204 | 180 |
205 // Attempt to convert the elements. | 181 // Attempt to convert the elements. |
206 try { | 182 try { |
207 return DoJoin(array, length, is_array, separator, convert); | 183 return DoJoin(array, length, is_array, separator, use_locale); |
208 } finally { | 184 } finally { |
209 // Make sure to remove the last element of the visited array no | 185 // Make sure to remove the last element of the visited array no |
210 // matter what happens. | 186 // matter what happens. |
211 if (is_array) StackPop(visited_arrays); | 187 if (is_array) StackPop(visited_arrays); |
212 } | 188 } |
213 } | 189 } |
214 | 190 |
215 | 191 |
216 function ConvertToString(x) { | 192 function ConvertToString(use_locale, x) { |
217 if (IS_NULL_OR_UNDEFINED(x)) return ''; | 193 if (IS_NULL_OR_UNDEFINED(x)) return ''; |
218 return TO_STRING(x); | 194 return TO_STRING(use_locale ? x.toLocaleString() : x); |
219 } | 195 } |
220 | 196 |
221 | 197 |
222 function ConvertToLocaleString(e) { | |
223 if (IS_NULL_OR_UNDEFINED(e)) return ''; | |
224 return TO_STRING(e.toLocaleString()); | |
225 } | |
226 | |
227 | |
228 // This function implements the optimized splice implementation that can use | 198 // This function implements the optimized splice implementation that can use |
229 // special array operations to handle sparse arrays in a sensible fashion. | 199 // special array operations to handle sparse arrays in a sensible fashion. |
230 function SparseSlice(array, start_i, del_count, len, deleted_elements) { | 200 function SparseSlice(array, start_i, del_count, len, deleted_elements) { |
231 // Move deleted elements to a new array (the return value from splice). | 201 // Move deleted elements to a new array (the return value from splice). |
232 var indices = %GetArrayKeys(array, start_i + del_count); | 202 var indices = %GetArrayKeys(array, start_i + del_count); |
233 if (IS_NUMBER(indices)) { | 203 if (IS_NUMBER(indices)) { |
234 var limit = indices; | 204 var limit = indices; |
235 for (var i = start_i; i < limit; ++i) { | 205 for (var i = start_i; i < limit; ++i) { |
236 var current = array[i]; | 206 var current = array[i]; |
237 if (!IS_UNDEFINED(current) || i in array) { | 207 if (!IS_UNDEFINED(current) || i in array) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 | 331 |
362 // ------------------------------------------------------------------- | 332 // ------------------------------------------------------------------- |
363 | 333 |
364 | 334 |
365 function ArrayToString() { | 335 function ArrayToString() { |
366 var array; | 336 var array; |
367 var func; | 337 var func; |
368 if (IS_ARRAY(this)) { | 338 if (IS_ARRAY(this)) { |
369 func = this.join; | 339 func = this.join; |
370 if (func === ArrayJoin) { | 340 if (func === ArrayJoin) { |
371 return Join(this, this.length, ',', ConvertToString); | 341 return Join(this, this.length, ',', false); |
372 } | 342 } |
373 array = this; | 343 array = this; |
374 } else { | 344 } else { |
375 array = TO_OBJECT(this); | 345 array = TO_OBJECT(this); |
376 func = array.join; | 346 func = array.join; |
377 } | 347 } |
378 if (!IS_CALLABLE(func)) { | 348 if (!IS_CALLABLE(func)) { |
379 return %_Call(ObjectToString, array); | 349 return %_Call(ObjectToString, array); |
380 } | 350 } |
381 return %_Call(func, array); | 351 return %_Call(func, array); |
382 } | 352 } |
383 | 353 |
384 | 354 |
385 function InnerArrayToLocaleString(array, length) { | 355 function InnerArrayToLocaleString(array, length) { |
386 var len = TO_LENGTH(length); | 356 return Join(array, TO_LENGTH(length), ',', true); |
387 if (len === 0) return ""; | |
388 return Join(array, len, ',', ConvertToLocaleString); | |
389 } | 357 } |
390 | 358 |
391 | 359 |
392 function ArrayToLocaleString() { | 360 function ArrayToLocaleString() { |
393 var array = TO_OBJECT(this); | 361 var array = TO_OBJECT(this); |
394 var arrayLen = array.length; | 362 var arrayLen = array.length; |
395 return InnerArrayToLocaleString(array, arrayLen); | 363 return InnerArrayToLocaleString(array, arrayLen); |
396 } | 364 } |
397 | 365 |
398 | 366 |
399 function InnerArrayJoin(separator, array, length) { | 367 function InnerArrayJoin(separator, array, length) { |
400 if (IS_UNDEFINED(separator)) { | 368 if (IS_UNDEFINED(separator)) { |
401 separator = ','; | 369 separator = ','; |
402 } else { | 370 } else { |
403 separator = TO_STRING(separator); | 371 separator = TO_STRING(separator); |
404 } | 372 } |
405 | 373 |
406 // Fast case for one-element arrays. | 374 // Fast case for one-element arrays. |
407 if (length === 1) { | 375 if (length === 1) { |
408 var e = array[0]; | 376 var e = array[0]; |
409 if (IS_NULL_OR_UNDEFINED(e)) return ''; | 377 if (IS_NULL_OR_UNDEFINED(e)) return ''; |
410 return TO_STRING(e); | 378 return TO_STRING(e); |
411 } | 379 } |
412 | 380 |
413 return Join(array, length, separator, ConvertToString); | 381 return Join(array, length, separator, false); |
414 } | 382 } |
415 | 383 |
416 | 384 |
417 function ArrayJoin(separator) { | 385 function ArrayJoin(separator) { |
418 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join"); | 386 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join"); |
419 | 387 |
420 var array = TO_OBJECT(this); | 388 var array = TO_OBJECT(this); |
421 var length = TO_LENGTH(array.length); | 389 var length = TO_LENGTH(array.length); |
422 | 390 |
423 return InnerArrayJoin(separator, array, length); | 391 return InnerArrayJoin(separator, array, length); |
(...skipping 1354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1778 %InstallToContext([ | 1746 %InstallToContext([ |
1779 "array_pop", ArrayPop, | 1747 "array_pop", ArrayPop, |
1780 "array_push", ArrayPush, | 1748 "array_push", ArrayPush, |
1781 "array_shift", ArrayShift, | 1749 "array_shift", ArrayShift, |
1782 "array_splice", ArraySplice, | 1750 "array_splice", ArraySplice, |
1783 "array_slice", ArraySlice, | 1751 "array_slice", ArraySlice, |
1784 "array_unshift", ArrayUnshift, | 1752 "array_unshift", ArrayUnshift, |
1785 ]); | 1753 ]); |
1786 | 1754 |
1787 }); | 1755 }); |
OLD | NEW |