| 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 |