Chromium Code Reviews| 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 if (FLAG_harmony_species) { | 66 if (FLAG_harmony_species) { |
| 67 var result = ObjectDefineProperty(array, i, { | 67 var result = ObjectDefineProperty(array, i, { |
| 68 value: value, writable: true, configurable: true, enumerable: true | 68 value: value, writable: true, configurable: true, enumerable: true |
| 69 }); | 69 }); |
| 70 if (!result) throw MakeTypeError(kStrictCannotAssign, i); | 70 if (!result) throw MakeTypeError(kStrictCannotAssign, i); |
| 71 } else { | 71 } else { |
| 72 AddIndexedProperty(array, i, value); | 72 AddIndexedProperty(array, i, value); |
| 73 } | 73 } |
| 74 } | 74 } |
| 75 | 75 |
| 76 function KeySortCompare(a, b) { | |
| 77 return a - b; | |
| 78 } | |
| 76 | 79 |
| 77 // Global list of arrays visited during toString, toLocaleString and | |
| 78 // join invocations. | |
| 79 var visited_arrays = new InternalArray(); | |
| 80 | |
| 81 | |
| 82 // Gets a sorted array of array keys. Useful for operations on sparse | |
| 83 // arrays. Dupes have not been removed. | |
| 84 function GetSortedArrayKeys(array, indices) { | 80 function GetSortedArrayKeys(array, indices) { |
| 85 var keys = new InternalArray(); | |
| 86 if (IS_NUMBER(indices)) { | 81 if (IS_NUMBER(indices)) { |
| 82 var keys = new InternalArray(); | |
| 87 // It's an interval | 83 // It's an interval |
| 88 var limit = indices; | 84 var limit = indices; |
| 89 for (var i = 0; i < limit; ++i) { | 85 for (var i = 0; i < limit; ++i) { |
| 90 var e = array[i]; | 86 var e = array[i]; |
| 91 if (!IS_UNDEFINED(e) || i in array) { | 87 if (!IS_UNDEFINED(e) || i in array) { |
| 92 keys.push(i); | 88 keys.push(i); |
| 93 } | 89 } |
| 94 } | 90 } |
| 95 } else { | |
| 96 var length = indices.length; | |
| 97 for (var k = 0; k < length; ++k) { | |
| 98 var key = indices[k]; | |
| 99 if (!IS_UNDEFINED(key)) { | |
| 100 var e = array[key]; | |
| 101 if (!IS_UNDEFINED(e) || key in array) { | |
| 102 keys.push(key); | |
| 103 } | |
| 104 } | |
| 105 } | |
| 106 keys.sort(function(a, b) { return a - b; }); | |
| 107 } | 91 } |
| 108 return keys; | 92 return InnerArraySort(indices, indices.length, KeySortCompare); |
| 109 } | 93 } |
| 110 | 94 |
| 111 | 95 |
| 112 function SparseJoinWithSeparatorJS(array, len, convert, separator) { | 96 function SparseJoinWithSeparatorJS(array, keys, length, convert, separator) { |
| 113 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); | 97 var keys_length = keys.length; |
| 114 var totalLength = 0; | 98 var elements = new InternalArray(keys_length * 2); |
| 115 var elements = new InternalArray(keys.length * 2); | 99 for (var i = 0; i < keys_length; i++) { |
| 116 var previousKey = -1; | |
| 117 for (var i = 0; i < keys.length; i++) { | |
| 118 var key = keys[i]; | 100 var key = keys[i]; |
| 119 if (key != previousKey) { // keys may contain duplicates. | 101 var e = array[key]; |
| 120 var e = array[key]; | 102 elements[i * 2] = key; |
| 121 if (!IS_STRING(e)) e = convert(e); | 103 elements[i * 2 + 1] = IS_STRING(e) ? e : convert(e); |
| 122 elements[i * 2] = key; | |
| 123 elements[i * 2 + 1] = e; | |
| 124 previousKey = key; | |
| 125 } | |
| 126 } | 104 } |
| 127 return %SparseJoinWithSeparator(elements, len, separator); | 105 return %SparseJoinWithSeparator(elements, length, separator); |
| 128 } | 106 } |
| 129 | 107 |
| 130 | 108 |
| 131 // Optimized for sparse arrays if separator is ''. | 109 // Optimized for sparse arrays if separator is ''. |
| 132 function SparseJoin(array, len, convert) { | 110 function SparseJoin(array, keys, convert) { |
| 133 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); | |
| 134 var last_key = -1; | |
| 135 var keys_length = keys.length; | 111 var keys_length = keys.length; |
| 136 | |
| 137 var elements = new InternalArray(keys_length); | 112 var elements = new InternalArray(keys_length); |
| 138 var elements_length = 0; | |
| 139 | |
| 140 for (var i = 0; i < keys_length; i++) { | 113 for (var i = 0; i < keys_length; i++) { |
| 141 var key = keys[i]; | 114 var e = array[keys[i]]; |
| 142 if (key != last_key) { | 115 elements[i] = IS_STRING(e) ? e : convert(e); |
| 143 var e = array[key]; | |
| 144 if (!IS_STRING(e)) e = convert(e); | |
| 145 elements[elements_length++] = e; | |
| 146 last_key = key; | |
| 147 } | |
| 148 } | 116 } |
| 149 return %StringBuilderConcat(elements, elements_length, ''); | 117 return %StringBuilderConcat(elements, keys_length, ''); |
| 150 } | 118 } |
| 151 | 119 |
| 152 | 120 |
| 153 function UseSparseVariant(array, length, is_array, touched) { | 121 function UseSparseVariant(array, length, is_array, touched) { |
| 154 // Only use the sparse variant on arrays that are likely to be sparse and the | 122 // Only use the sparse variant on arrays that are likely to be sparse and the |
| 155 // number of elements touched in the operation is relatively small compared to | 123 // number of elements touched in the operation is relatively small compared to |
| 156 // the overall size of the array. | 124 // the overall size of the array. |
| 157 if (!is_array || length < 1000 || %IsObserved(array) || | 125 if (!is_array || length < 1000 || %IsObserved(array) || |
| 158 %HasComplexElements(array)) { | 126 %HasComplexElements(array)) { |
| 159 return false; | 127 return false; |
| 160 } | 128 } |
| 161 if (!%_IsSmi(length)) { | 129 if (!%_IsSmi(length)) { |
| 162 return true; | 130 return true; |
| 163 } | 131 } |
| 164 var elements_threshold = length >> 2; // No more than 75% holes | 132 var elements_threshold = length >> 2; // No more than 75% holes |
| 165 var estimated_elements = %EstimateNumberOfElements(array); | 133 var estimated_elements = %EstimateNumberOfElements(array); |
| 166 return (estimated_elements < elements_threshold) && | 134 return (estimated_elements < elements_threshold) && |
| 167 (touched > estimated_elements * 4); | 135 (touched > estimated_elements * 4); |
| 168 } | 136 } |
| 169 | 137 |
| 138 function Stack() { | |
| 139 this.length = 0; | |
| 140 this.values = new InternalArray(); | |
| 141 } | |
| 142 | |
| 143 // Predeclare the instance variables on the prototype. Otherwise setting them in | |
| 144 // the constructor will leak the instance through settings on Object.prototype. | |
| 145 Stack.prototype.length = null; | |
| 146 Stack.prototype.values = null; | |
| 147 | |
| 148 function StackPush(stack, value) { | |
| 149 stack.values[stack.length++] = value; | |
| 150 } | |
| 151 | |
| 152 function StackPop(stack) { | |
| 153 stack.values[--stack.length] = null | |
| 154 } | |
| 155 | |
| 156 function StackHas(stack, v) { | |
| 157 var length = stack.length; | |
| 158 var values = stack.values; | |
| 159 for (var i = 0; i < length; i++) { | |
| 160 if (values[i] === v) return true; | |
| 161 } | |
| 162 return false; | |
| 163 } | |
| 164 | |
| 165 // Global list of arrays visited during toString, toLocaleString and | |
| 166 // join invocations. | |
| 167 var visited_arrays = new Stack(); | |
| 168 | |
| 169 function DoJoin(array, length, is_array, separator, convert) { | |
| 170 if (UseSparseVariant(array, length, is_array, length)) { | |
| 171 %NormalizeElements(array); | |
| 172 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length)); | |
| 173 if (separator === '') { | |
| 174 if (keys.length === 0) return ''; | |
| 175 return SparseJoin(array, keys, convert); | |
| 176 } else { | |
| 177 return SparseJoinWithSeparatorJS(array, keys, length, convert, separator); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 // Fast case for one-element arrays. | |
| 182 if (length === 1) { | |
| 183 var e = array[0]; | |
| 184 return IS_STRING(e) ? e : convert(e); | |
| 185 } | |
| 186 | |
| 187 // Construct an array for the elements. | |
| 188 var elements = new InternalArray(length); | |
| 189 | |
| 190 // We pull the empty separator check outside the loop for speed! | |
| 191 if (separator === '') { | |
| 192 for (var i = 0; i < length; i++) { | |
| 193 var e = array[i]; | |
| 194 elements[i] = IS_STRING(e) ? e : convert(e); | |
| 195 } | |
| 196 return %StringBuilderConcat(elements, length, ''); | |
|
Camillo Bruni
2016/03/14 10:09:52
As you said, you could probably still create a sil
| |
| 197 } | |
| 198 // Non-empty separator case. | |
| 199 // If the first element is a number then use the heuristic that the | |
| 200 // remaining elements are also likely to be numbers. | |
| 201 var e = array[0]; | |
| 202 if (IS_NUMBER(e)) { | |
| 203 elements[0] = %_NumberToString(e); | |
| 204 for (var i = 1; i < length; i++) { | |
| 205 e = array[i]; | |
| 206 if (IS_NUMBER(e)) { | |
| 207 elements[i] = %_NumberToString(e); | |
| 208 } else { | |
| 209 elements[i] = IS_STRING(e) ? e : convert(e); | |
| 210 } | |
| 211 } | |
| 212 } else { | |
| 213 elements[0] = IS_STRING(e) ? e : convert(e); | |
| 214 for (var i = 1; i < length; i++) { | |
| 215 e = array[i]; | |
| 216 elements[i] = IS_STRING(e) ? e : convert(e); | |
| 217 } | |
| 218 } | |
| 219 return %StringBuilderJoin(elements, length, separator); | |
| 220 } | |
| 170 | 221 |
| 171 function Join(array, length, separator, convert) { | 222 function Join(array, length, separator, convert) { |
| 172 if (length == 0) return ''; | 223 if (length === 0) return ''; |
| 173 | 224 |
| 174 var is_array = IS_ARRAY(array); | 225 var is_array = IS_ARRAY(array); |
| 175 | 226 |
| 176 if (is_array) { | 227 if (is_array) { |
| 177 // If the array is cyclic, return the empty string for already | 228 // If the array is cyclic, return the empty string for already |
| 178 // visited arrays. | 229 // visited arrays. |
| 179 if (!%PushIfAbsent(visited_arrays, array)) return ''; | 230 if (StackHas(visited_arrays, array)) return ''; |
| 231 StackPush(visited_arrays, array); | |
| 180 } | 232 } |
| 181 | 233 |
| 182 // Attempt to convert the elements. | 234 // Attempt to convert the elements. |
| 183 try { | 235 try { |
| 184 if (UseSparseVariant(array, length, is_array, length)) { | 236 return DoJoin(array, length, is_array, separator, convert); |
| 185 %NormalizeElements(array); | |
| 186 if (separator.length == 0) { | |
| 187 return SparseJoin(array, length, convert); | |
| 188 } else { | |
| 189 return SparseJoinWithSeparatorJS(array, length, convert, separator); | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 // Fast case for one-element arrays. | |
| 194 if (length == 1) { | |
| 195 var e = array[0]; | |
| 196 if (IS_STRING(e)) return e; | |
| 197 return convert(e); | |
| 198 } | |
| 199 | |
| 200 // Construct an array for the elements. | |
| 201 var elements = new InternalArray(length); | |
| 202 | |
| 203 // We pull the empty separator check outside the loop for speed! | |
| 204 if (separator.length == 0) { | |
| 205 var elements_length = 0; | |
| 206 for (var i = 0; i < length; i++) { | |
| 207 var e = array[i]; | |
| 208 if (!IS_STRING(e)) e = convert(e); | |
| 209 elements[elements_length++] = e; | |
| 210 } | |
| 211 elements.length = elements_length; | |
| 212 return %StringBuilderConcat(elements, elements_length, ''); | |
| 213 } | |
| 214 // Non-empty separator case. | |
| 215 // If the first element is a number then use the heuristic that the | |
| 216 // remaining elements are also likely to be numbers. | |
| 217 var e = array[0]; | |
| 218 if (!IS_NUMBER(e)) { | |
| 219 if (!IS_STRING(e)) e = convert(e); | |
| 220 elements[0] = e; | |
| 221 for (var i = 1; i < length; i++) { | |
| 222 e = array[i]; | |
| 223 if (!IS_STRING(e)) e = convert(e); | |
| 224 elements[i] = e; | |
| 225 } | |
| 226 } else { | |
| 227 elements[0] = %_NumberToString(e); | |
| 228 for (var i = 1; i < length; i++) { | |
| 229 e = array[i]; | |
| 230 if (IS_NUMBER(e)) { | |
| 231 e = %_NumberToString(e); | |
| 232 } else if (!IS_STRING(e)) { | |
| 233 e = convert(e); | |
| 234 } | |
| 235 elements[i] = e; | |
| 236 } | |
| 237 } | |
| 238 return %StringBuilderJoin(elements, length, separator); | |
| 239 } finally { | 237 } finally { |
| 240 // Make sure to remove the last element of the visited array no | 238 // Make sure to remove the last element of the visited array no |
| 241 // matter what happens. | 239 // matter what happens. |
| 242 if (is_array) visited_arrays.length = visited_arrays.length - 1; | 240 if (is_array) StackPop(visited_arrays); |
| 243 } | 241 } |
| 244 } | 242 } |
| 245 | 243 |
| 246 | 244 |
| 247 function ConvertToString(x) { | 245 function ConvertToString(x) { |
| 248 if (IS_NULL_OR_UNDEFINED(x)) { | 246 if (IS_NULL_OR_UNDEFINED(x)) return ''; |
| 249 return ''; | 247 return TO_STRING(x); |
| 250 } else { | |
| 251 return TO_STRING(x); | |
| 252 } | |
| 253 } | 248 } |
| 254 | 249 |
| 255 | 250 |
| 256 function ConvertToLocaleString(e) { | 251 function ConvertToLocaleString(e) { |
| 257 if (IS_NULL_OR_UNDEFINED(e)) { | 252 if (IS_NULL_OR_UNDEFINED(e)) return ''; |
| 258 return ''; | 253 return TO_STRING(e.toLocaleString()); |
| 259 } else { | |
| 260 return TO_STRING(e.toLocaleString()); | |
| 261 } | |
| 262 } | 254 } |
| 263 | 255 |
| 264 | 256 |
| 265 // This function implements the optimized splice implementation that can use | 257 // This function implements the optimized splice implementation that can use |
| 266 // special array operations to handle sparse arrays in a sensible fashion. | 258 // special array operations to handle sparse arrays in a sensible fashion. |
| 267 function SparseSlice(array, start_i, del_count, len, deleted_elements) { | 259 function SparseSlice(array, start_i, del_count, len, deleted_elements) { |
| 268 // Move deleted elements to a new array (the return value from splice). | 260 // Move deleted elements to a new array (the return value from splice). |
| 269 var indices = %GetArrayKeys(array, start_i + del_count); | 261 var indices = %GetArrayKeys(array, start_i + del_count); |
| 270 if (IS_NUMBER(indices)) { | 262 if (IS_NUMBER(indices)) { |
| 271 var limit = indices; | 263 var limit = indices; |
| (...skipping 1680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1952 to.InnerArrayIncludes = InnerArrayIncludes; | 1944 to.InnerArrayIncludes = InnerArrayIncludes; |
| 1953 to.InnerArrayIndexOf = InnerArrayIndexOf; | 1945 to.InnerArrayIndexOf = InnerArrayIndexOf; |
| 1954 to.InnerArrayJoin = InnerArrayJoin; | 1946 to.InnerArrayJoin = InnerArrayJoin; |
| 1955 to.InnerArrayLastIndexOf = InnerArrayLastIndexOf; | 1947 to.InnerArrayLastIndexOf = InnerArrayLastIndexOf; |
| 1956 to.InnerArrayReduce = InnerArrayReduce; | 1948 to.InnerArrayReduce = InnerArrayReduce; |
| 1957 to.InnerArrayReduceRight = InnerArrayReduceRight; | 1949 to.InnerArrayReduceRight = InnerArrayReduceRight; |
| 1958 to.InnerArraySome = InnerArraySome; | 1950 to.InnerArraySome = InnerArraySome; |
| 1959 to.InnerArraySort = InnerArraySort; | 1951 to.InnerArraySort = InnerArraySort; |
| 1960 to.InnerArrayToLocaleString = InnerArrayToLocaleString; | 1952 to.InnerArrayToLocaleString = InnerArrayToLocaleString; |
| 1961 to.PackedArrayReverse = PackedArrayReverse; | 1953 to.PackedArrayReverse = PackedArrayReverse; |
| 1954 to.Stack = Stack; | |
| 1955 to.StackHas = StackHas; | |
| 1956 to.StackPush = StackPush; | |
| 1957 to.StackPop = StackPop; | |
| 1962 }); | 1958 }); |
| 1963 | 1959 |
| 1964 %InstallToContext([ | 1960 %InstallToContext([ |
| 1965 "array_pop", ArrayPop, | 1961 "array_pop", ArrayPop, |
| 1966 "array_push", ArrayPush, | 1962 "array_push", ArrayPush, |
| 1967 "array_shift", ArrayShift, | 1963 "array_shift", ArrayShift, |
| 1968 "array_splice", ArraySplice, | 1964 "array_splice", ArraySplice, |
| 1969 "array_slice", ArraySlice, | 1965 "array_slice", ArraySlice, |
| 1970 "array_unshift", ArrayUnshift, | 1966 "array_unshift", ArrayUnshift, |
| 1971 ]); | 1967 ]); |
| 1972 | 1968 |
| 1973 }); | 1969 }); |
| OLD | NEW |