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

Side by Side Diff: src/arm/builtins-arm.cc

Issue 8359034: Refactor and clean up array allocation across platforms. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | src/ia32/builtins-ia32.cc » ('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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 79 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
80 __ ldr(result, 80 __ ldr(result,
81 FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); 81 FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
82 // Load the Array function from the global context. 82 // Load the Array function from the global context.
83 __ ldr(result, 83 __ ldr(result,
84 MemOperand(result, 84 MemOperand(result,
85 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); 85 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
86 } 86 }
87 87
88 88
89 // This constant has the same value as JSArray::kPreallocatedArrayElements and
90 // if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding
91 // below should be reconsidered.
92 static const int kLoopUnfoldLimit = 4;
93
94
95 // Allocate an empty JSArray. The allocated array is put into the result 89 // Allocate an empty JSArray. The allocated array is put into the result
96 // register. An elements backing store is allocated with size initial_capacity 90 // register. An elements backing store is allocated with size initial_capacity
97 // and filled with the hole values. 91 // and filled with the hole values.
98 static void AllocateEmptyJSArray(MacroAssembler* masm, 92 static void AllocateEmptyJSArray(MacroAssembler* masm,
99 Register array_function, 93 Register array_function,
100 Register result, 94 Register result,
101 Register scratch1, 95 Register scratch1,
102 Register scratch2, 96 Register scratch2,
103 Register scratch3, 97 Register scratch3,
104 int initial_capacity,
105 Label* gc_required) { 98 Label* gc_required) {
106 ASSERT(initial_capacity > 0); 99 int initial_capacity = JSArray::kPreallocatedArrayElements;
Kevin Millikin (Chromium) 2011/10/24 08:00:38 Drive by: Make this a const, and make the asserts
100 ASSERT(initial_capacity >= 0);
107 // Load the initial map from the array function. 101 // Load the initial map from the array function.
108 __ ldr(scratch1, FieldMemOperand(array_function, 102 __ ldr(scratch1, FieldMemOperand(array_function,
109 JSFunction::kPrototypeOrInitialMapOffset)); 103 JSFunction::kPrototypeOrInitialMapOffset));
110 104
111 // Allocate the JSArray object together with space for a fixed array with the 105 // Allocate the JSArray object together with space for a fixed array with the
112 // requested elements. 106 // requested elements.
113 int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity); 107 int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity);
114 __ AllocateInNewSpace(size, 108 __ AllocateInNewSpace(size,
115 result, 109 result,
116 scratch2, 110 scratch2,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 // scratch2: start of next object 142 // scratch2: start of next object
149 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex); 143 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex);
150 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); 144 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
151 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 145 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
152 __ mov(scratch3, Operand(Smi::FromInt(initial_capacity))); 146 __ mov(scratch3, Operand(Smi::FromInt(initial_capacity)));
153 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 147 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
154 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 148 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
155 149
156 // Fill the FixedArray with the hole value. 150 // Fill the FixedArray with the hole value.
157 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); 151 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
158 ASSERT(initial_capacity <= kLoopUnfoldLimit);
159 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); 152 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
160 for (int i = 0; i < initial_capacity; i++) { 153 for (int i = 0; i < initial_capacity; i++) {
161 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 154 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
162 } 155 }
163 } 156 }
164 157
165 // Allocate a JSArray with the number of elements stored in a register. The 158 // Allocate a JSArray with the number of elements stored in a register. The
166 // register array_function holds the built-in Array function and the register 159 // register array_function holds the built-in Array function and the register
167 // array_size holds the size of the array as a smi. The allocated array is put 160 // array_size holds the size of the array as a smi. The allocated array is put
168 // into the result register and beginning and end of the FixedArray elements 161 // into the result register and beginning and end of the FixedArray elements
169 // storage is put into registers elements_array_storage and elements_array_end 162 // storage is put into registers elements_array_storage and elements_array_end
170 // (see below for when that is not the case). If the parameter fill_with_holes 163 // (see below for when that is not the case). If the parameter fill_with_holes
171 // is true the allocated elements backing store is filled with the hole values 164 // is true the allocated elements backing store is filled with the hole values
172 // otherwise it is left uninitialized. When the backing store is filled the 165 // otherwise it is left uninitialized. When the backing store is filled the
173 // register elements_array_storage is scratched. 166 // register elements_array_storage is scratched.
174 static void AllocateJSArray(MacroAssembler* masm, 167 static void AllocateJSArray(MacroAssembler* masm,
175 Register array_function, // Array function. 168 Register array_function, // Array function.
176 Register array_size, // As a smi. 169 Register array_size, // As a smi, cannot be 0.
177 Register result, 170 Register result,
178 Register elements_array_storage, 171 Register elements_array_storage,
179 Register elements_array_end, 172 Register elements_array_end,
180 Register scratch1, 173 Register scratch1,
181 Register scratch2, 174 Register scratch2,
182 bool fill_with_hole, 175 bool fill_with_hole,
183 Label* gc_required) { 176 Label* gc_required) {
184 Label not_empty, allocated;
185
186 // Load the initial map from the array function. 177 // Load the initial map from the array function.
187 __ ldr(elements_array_storage, 178 __ ldr(elements_array_storage,
188 FieldMemOperand(array_function, 179 FieldMemOperand(array_function,
189 JSFunction::kPrototypeOrInitialMapOffset)); 180 JSFunction::kPrototypeOrInitialMapOffset));
190 181
191 // Check whether an empty sized array is requested. 182 if (FLAG_debug_code) { // Assert that array size is not zero.
192 __ tst(array_size, array_size); 183 Label not_empty;
193 __ b(ne, &not_empty); 184 __ tst(array_size, array_size);
194 185 __ b(ne, &not_empty);
Kevin Millikin (Chromium) 2011/10/24 08:00:38 Drive by: You can replace all this with: if (FLA
195 // If an empty array is requested allocate a small elements array anyway. This 186 __ Abort("array size is unexpectedly 0");
196 // keeps the code below free of special casing for the empty array. 187 __ bind(&not_empty);
197 int size = JSArray::kSize + 188 }
198 FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
199 __ AllocateInNewSpace(size,
200 result,
201 elements_array_end,
202 scratch1,
203 gc_required,
204 TAG_OBJECT);
205 __ jmp(&allocated);
206 189
207 // Allocate the JSArray object together with space for a FixedArray with the 190 // Allocate the JSArray object together with space for a FixedArray with the
208 // requested number of elements. 191 // requested number of elements.
209 __ bind(&not_empty);
210 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 192 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
211 __ mov(elements_array_end, 193 __ mov(elements_array_end,
212 Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); 194 Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
213 __ add(elements_array_end, 195 __ add(elements_array_end,
214 elements_array_end, 196 elements_array_end,
215 Operand(array_size, ASR, kSmiTagSize)); 197 Operand(array_size, ASR, kSmiTagSize));
216 __ AllocateInNewSpace( 198 __ AllocateInNewSpace(
217 elements_array_end, 199 elements_array_end,
218 result, 200 result,
219 scratch1, 201 scratch1,
220 scratch2, 202 scratch2,
221 gc_required, 203 gc_required,
222 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); 204 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
223 205
224 // Allocated the JSArray. Now initialize the fields except for the elements 206 // Allocated the JSArray. Now initialize the fields except for the elements
225 // array. 207 // array.
226 // result: JSObject 208 // result: JSObject
227 // elements_array_storage: initial map 209 // elements_array_storage: initial map
228 // array_size: size of array (smi) 210 // array_size: size of array (smi)
229 __ bind(&allocated);
230 __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); 211 __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
231 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); 212 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
232 __ str(elements_array_storage, 213 __ str(elements_array_storage,
233 FieldMemOperand(result, JSArray::kPropertiesOffset)); 214 FieldMemOperand(result, JSArray::kPropertiesOffset));
234 // Field JSArray::kElementsOffset is initialized later. 215 // Field JSArray::kElementsOffset is initialized later.
235 __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset)); 216 __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset));
236 217
237 // Calculate the location of the elements array and set elements array member 218 // Calculate the location of the elements array and set elements array member
238 // of the JSArray. 219 // of the JSArray.
239 // result: JSObject 220 // result: JSObject
240 // array_size: size of array (smi) 221 // array_size: size of array (smi)
241 __ add(elements_array_storage, result, Operand(JSArray::kSize)); 222 __ add(elements_array_storage, result, Operand(JSArray::kSize));
242 __ str(elements_array_storage, 223 __ str(elements_array_storage,
243 FieldMemOperand(result, JSArray::kElementsOffset)); 224 FieldMemOperand(result, JSArray::kElementsOffset));
244 225
245 // Clear the heap tag on the elements array. 226 // Clear the heap tag on the elements array.
246 STATIC_ASSERT(kSmiTag == 0); 227 STATIC_ASSERT(kSmiTag == 0);
247 __ sub(elements_array_storage, 228 __ sub(elements_array_storage,
248 elements_array_storage, 229 elements_array_storage,
249 Operand(kHeapObjectTag)); 230 Operand(kHeapObjectTag));
250 // Initialize the fixed array and fill it with holes. FixedArray length is 231 // Initialize the fixed array and fill it with holes. FixedArray length is
251 // stored as a smi. 232 // stored as a smi.
252 // result: JSObject 233 // result: JSObject
253 // elements_array_storage: elements array (untagged) 234 // elements_array_storage: elements array (untagged)
254 // array_size: size of array (smi) 235 // array_size: size of array (smi)
255 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); 236 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex);
256 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); 237 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
257 __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); 238 __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
258 STATIC_ASSERT(kSmiTag == 0); 239 STATIC_ASSERT(kSmiTag == 0);
259 __ tst(array_size, array_size);
260 // Length of the FixedArray is the number of pre-allocated elements if
261 // the actual JSArray has length 0 and the size of the JSArray for non-empty
262 // JSArrays. The length of a FixedArray is stored as a smi.
263 __ mov(array_size,
264 Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)),
265 LeaveCC,
266 eq);
267 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 240 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
268 __ str(array_size, 241 __ str(array_size,
269 MemOperand(elements_array_storage, kPointerSize, PostIndex)); 242 MemOperand(elements_array_storage, kPointerSize, PostIndex));
270 243
271 // Calculate elements array and elements array end. 244 // Calculate elements array and elements array end.
272 // result: JSObject 245 // result: JSObject
273 // elements_array_storage: elements array element storage 246 // elements_array_storage: elements array element storage
274 // array_size: smi-tagged size of elements array 247 // array_size: smi-tagged size of elements array
275 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 248 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
276 __ add(elements_array_end, 249 __ add(elements_array_end,
(...skipping 27 matching lines...) Expand all
304 // sp[0]: last argument 277 // sp[0]: last argument
305 // This function is used for both construct and normal calls of Array. The only 278 // This function is used for both construct and normal calls of Array. The only
306 // difference between handling a construct call and a normal call is that for a 279 // difference between handling a construct call and a normal call is that for a
307 // construct call the constructor function in r1 needs to be preserved for 280 // construct call the constructor function in r1 needs to be preserved for
308 // entering the generic code. In both cases argc in r0 needs to be preserved. 281 // entering the generic code. In both cases argc in r0 needs to be preserved.
309 // Both registers are preserved by this code so no need to differentiate between 282 // Both registers are preserved by this code so no need to differentiate between
310 // construct call and normal call. 283 // construct call and normal call.
311 static void ArrayNativeCode(MacroAssembler* masm, 284 static void ArrayNativeCode(MacroAssembler* masm,
312 Label* call_generic_code) { 285 Label* call_generic_code) {
313 Counters* counters = masm->isolate()->counters(); 286 Counters* counters = masm->isolate()->counters();
314 Label argc_one_or_more, argc_two_or_more; 287 Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array;
315 288
316 // Check for array construction with zero arguments or one. 289 // Check for array construction with zero arguments or one.
317 __ cmp(r0, Operand(0, RelocInfo::NONE)); 290 __ cmp(r0, Operand(0, RelocInfo::NONE));
318 __ b(ne, &argc_one_or_more); 291 __ b(ne, &argc_one_or_more);
319 292
320 // Handle construction of an empty array. 293 // Handle construction of an empty array.
294 __ bind(&empty_array);
321 AllocateEmptyJSArray(masm, 295 AllocateEmptyJSArray(masm,
322 r1, 296 r1,
323 r2, 297 r2,
324 r3, 298 r3,
325 r4, 299 r4,
326 r5, 300 r5,
327 JSArray::kPreallocatedArrayElements,
328 call_generic_code); 301 call_generic_code);
329 __ IncrementCounter(counters->array_function_native(), 1, r3, r4); 302 __ IncrementCounter(counters->array_function_native(), 1, r3, r4);
330 // Setup return value, remove receiver from stack and return. 303 // Setup return value, remove receiver from stack and return.
331 __ mov(r0, r2); 304 __ mov(r0, r2);
332 __ add(sp, sp, Operand(kPointerSize)); 305 __ add(sp, sp, Operand(kPointerSize));
333 __ Jump(lr); 306 __ Jump(lr);
334 307
335 // Check for one argument. Bail out if argument is not smi or if it is 308 // Check for one argument. Bail out if argument is not smi or if it is
336 // negative. 309 // negative.
337 __ bind(&argc_one_or_more); 310 __ bind(&argc_one_or_more);
338 __ cmp(r0, Operand(1)); 311 __ cmp(r0, Operand(1));
339 __ b(ne, &argc_two_or_more); 312 __ b(ne, &argc_two_or_more);
340 STATIC_ASSERT(kSmiTag == 0); 313 STATIC_ASSERT(kSmiTag == 0);
341 __ ldr(r2, MemOperand(sp)); // Get the argument from the stack. 314 __ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
315 __ tst(r2, r2);
316 __ b(ne, &not_empty_array);
317 __ Drop(1); // Adjust stack.
318 __ mov(r0, Operand(0)); // Treat this as a call with argc of zero.
319 __ b(&empty_array);
320
321 __ bind(&not_empty_array);
342 __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); 322 __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
343 __ b(ne, call_generic_code); 323 __ b(ne, call_generic_code);
344 324
345 // Handle construction of an empty array of a certain size. Bail out if size 325 // Handle construction of an empty array of a certain size. Bail out if size
346 // is too large to actually allocate an elements array. 326 // is too large to actually allocate an elements array.
347 STATIC_ASSERT(kSmiTag == 0); 327 STATIC_ASSERT(kSmiTag == 0);
348 __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); 328 __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
349 __ b(ge, call_generic_code); 329 __ b(ge, call_generic_code);
350 330
351 // r0: argc 331 // r0: argc
(...skipping 1366 matching lines...) Expand 10 before | Expand all | Expand 10 after
1718 __ bind(&dont_adapt_arguments); 1698 __ bind(&dont_adapt_arguments);
1719 __ Jump(r3); 1699 __ Jump(r3);
1720 } 1700 }
1721 1701
1722 1702
1723 #undef __ 1703 #undef __
1724 1704
1725 } } // namespace v8::internal 1705 } } // namespace v8::internal
1726 1706
1727 #endif // V8_TARGET_ARCH_ARM 1707 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | src/ia32/builtins-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698