Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(371)

Side by Side Diff: src/js/array.js

Issue 1775403008: Replace PushIfAbsent by a Stack object (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/js/json.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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, '');
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
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 });
OLDNEW
« no previous file with comments | « no previous file | src/js/json.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698