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

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

Issue 217014: Handle array construction in native code (ARM version) (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 3 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/builtins.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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 __ str(r1, MemOperand(ip, 0)); 44 __ str(r1, MemOperand(ip, 0));
45 45
46 // The actual argument count has already been loaded into register 46 // The actual argument count has already been loaded into register
47 // r0, but JumpToBuiltin expects r0 to contain the number of 47 // r0, but JumpToBuiltin expects r0 to contain the number of
48 // arguments including the receiver. 48 // arguments including the receiver.
49 __ add(r0, r0, Operand(1)); 49 __ add(r0, r0, Operand(1));
50 __ JumpToBuiltin(ExternalReference(id)); 50 __ JumpToBuiltin(ExternalReference(id));
51 } 51 }
52 52
53 53
54 // Load the built-in Array function from the current context.
55 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
56 // Load the global context.
57
58 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
59 __ ldr(result,
60 FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
61 // Load the Array function from the global context.
62 __ ldr(result,
63 MemOperand(result,
64 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
65 }
66
67
68 // This constant has the same value as JSArray::kPreallocatedArrayElements and
69 // if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding
70 // below should be reconsidered.
71 static const int kLoopUnfoldLimit = 4;
72
73
74 // Allocate an empty JSArray. The allocated array is put into the result
75 // register. An elements backing store is allocated with size initial_capacity
76 // and filled with the hole values.
77 static void AllocateEmptyJSArray(MacroAssembler* masm,
78 Register array_function,
79 Register result,
80 Register scratch1,
81 Register scratch2,
82 Register scratch3,
83 int initial_capacity,
84 Label* gc_required) {
85 ASSERT(initial_capacity > 0);
86 // Load the initial map from the array function.
87 __ ldr(scratch1, FieldMemOperand(array_function,
88 JSFunction::kPrototypeOrInitialMapOffset));
89
90 // Allocate the JSArray object together with space for a fixed array with the
91 // requested elements.
92 int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity);
93 __ AllocateObjectInNewSpace(size / kPointerSize,
94 result,
95 scratch2,
96 scratch3,
97 gc_required,
98 TAG_OBJECT);
99
100 // Allocated the JSArray. Now initialize the fields except for the elements
101 // array.
102 // result: JSObject
103 // scratch1: initial map
104 // scratch2: start of next object
105 __ str(scratch1, FieldMemOperand(result, JSObject::kMapOffset));
106 __ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
107 __ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset));
108 // Field JSArray::kElementsOffset is initialized later.
109 __ mov(scratch3, Operand(0));
110 __ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset));
111
112 // Calculate the location of the elements array and set elements array member
113 // of the JSArray.
114 // result: JSObject
115 // scratch2: start of next object
116 __ lea(scratch1, MemOperand(result, JSArray::kSize));
117 __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset));
118
119 // Clear the heap tag on the elements array.
120 __ and_(scratch1, scratch1, Operand(~kHeapObjectTagMask));
121
122 // Initialize the FixedArray and fill it with holes. FixedArray length is not
123 // stored as a smi.
124 // result: JSObject
125 // scratch1: elements array (untagged)
126 // scratch2: start of next object
127 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex);
128 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
129 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
130 __ mov(scratch3, Operand(initial_capacity));
131 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
132 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
133
134 // Fill the FixedArray with the hole value.
135 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
136 ASSERT(initial_capacity <= kLoopUnfoldLimit);
137 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
138 for (int i = 0; i < initial_capacity; i++) {
139 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
140 }
141 }
142
143 // Allocate a JSArray with the number of elements stored in a register. The
144 // register array_function holds the built-in Array function and the register
145 // array_size holds the size of the array as a smi. The allocated array is put
146 // into the result register and beginning and end of the FixedArray elements
147 // storage is put into registers elements_array_storage and elements_array_end
148 // (see below for when that is not the case). If the parameter fill_with_holes
149 // is true the allocated elements backing store is filled with the hole values
150 // otherwise it is left uninitialized. When the backing store is filled the
151 // register elements_array_storage is scratched.
152 static void AllocateJSArray(MacroAssembler* masm,
153 Register array_function, // Array function.
154 Register array_size, // As a smi.
155 Register result,
156 Register elements_array_storage,
157 Register elements_array_end,
158 Register scratch1,
159 Register scratch2,
160 bool fill_with_hole,
161 Label* gc_required) {
162 Label not_empty, allocated;
163
164 // Load the initial map from the array function.
165 __ ldr(elements_array_storage,
166 FieldMemOperand(array_function,
167 JSFunction::kPrototypeOrInitialMapOffset));
168
169 // Check whether an empty sized array is requested.
170 __ tst(array_size, array_size);
171 __ b(nz, &not_empty);
172
173 // If an empty array is requested allocate a small elements array anyway. This
174 // keeps the code below free of special casing for the empty array.
175 int size = JSArray::kSize +
176 FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
177 __ AllocateObjectInNewSpace(size / kPointerSize,
178 result,
179 elements_array_end,
180 scratch1,
181 gc_required,
182 TAG_OBJECT);
183 __ jmp(&allocated);
184
185 // Allocate the JSArray object together with space for a FixedArray with the
186 // requested number of elements.
187 __ bind(&not_empty);
188 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
189 __ mov(elements_array_end,
190 Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
191 __ add(elements_array_end,
192 elements_array_end,
193 Operand(array_size, ASR, kSmiTagSize));
194 __ AllocateObjectInNewSpace(elements_array_end,
195 result,
196 scratch1,
197 scratch2,
198 gc_required,
199 TAG_OBJECT);
200
201 // Allocated the JSArray. Now initialize the fields except for the elements
202 // array.
203 // result: JSObject
204 // elements_array_storage: initial map
205 // array_size: size of array (smi)
206 __ bind(&allocated);
207 __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
208 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
209 __ str(elements_array_storage,
210 FieldMemOperand(result, JSArray::kPropertiesOffset));
211 // Field JSArray::kElementsOffset is initialized later.
212 __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset));
213
214 // Calculate the location of the elements array and set elements array member
215 // of the JSArray.
216 // result: JSObject
217 // array_size: size of array (smi)
218 __ add(elements_array_storage, result, Operand(JSArray::kSize));
219 __ str(elements_array_storage,
220 FieldMemOperand(result, JSArray::kElementsOffset));
221
222 // Clear the heap tag on the elements array.
223 __ and_(elements_array_storage,
224 elements_array_storage,
225 Operand(~kHeapObjectTagMask));
226 // Initialize the fixed array and fill it with holes. FixedArray length is not
227 // stored as a smi.
228 // result: JSObject
229 // elements_array_storage: elements array (untagged)
230 // array_size: size of array (smi)
231 ASSERT(kSmiTag == 0);
232 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex);
233 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
234 __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
235 // Convert array_size from smi to value.
236 __ mov(array_size,
237 Operand(array_size, ASR, kSmiTagSize));
238 __ tst(array_size, array_size);
239 // Length of the FixedArray is the number of pre-allocated elements if
240 // the actual JSArray has length 0 and the size of the JSArray for non-empty
241 // JSArrays. The length of a FixedArray is not stored as a smi.
242 __ mov(array_size, Operand(JSArray::kPreallocatedArrayElements), LeaveCC, eq);
243 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
244 __ str(array_size,
245 MemOperand(elements_array_storage, kPointerSize, PostIndex));
246
247 // Calculate elements array and elements array end.
248 // result: JSObject
249 // elements_array_storage: elements array element storage
250 // array_size: size of elements array
251 __ add(elements_array_end,
252 elements_array_storage,
253 Operand(array_size, LSL, kPointerSizeLog2));
254
255 // Fill the allocated FixedArray with the hole value if requested.
256 // result: JSObject
257 // elements_array_storage: elements array element storage
258 // elements_array_end: start of next object
259 if (fill_with_hole) {
260 Label loop, entry;
261 __ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex);
262 __ jmp(&entry);
263 __ bind(&loop);
264 __ str(scratch1,
265 MemOperand(elements_array_storage, kPointerSize, PostIndex));
266 __ bind(&entry);
267 __ cmp(elements_array_storage, elements_array_end);
268 __ b(lt, &loop);
269 }
270 }
271
272 // Create a new array for the built-in Array function. This function allocates
273 // the JSArray object and the FixedArray elements array and initializes these.
274 // If the Array cannot be constructed in native code the runtime is called. This
275 // function assumes the following state:
276 // r0: argc
277 // r1: constructor (built-in Array function)
278 // lr: return address
279 // sp[0]: last argument
280 // This function is used for both construct and normal calls of Array. The only
281 // difference between handling a construct call and a normal call is that for a
282 // construct call the constructor function in r1 needs to be preserved for
283 // entering the generic code. In both cases argc in r0 needs to be preserved.
284 // Both registers are preserved by this code so no need to differentiate between
285 // construct call and normal call.
286 static void ArrayNativeCode(MacroAssembler* masm,
287 Label *call_generic_code) {
288 Label argc_one_or_more, argc_two_or_more;
289
290 // Check for array construction with zero arguments or one.
291 __ cmp(r0, Operand(0));
292 __ b(ne, &argc_one_or_more);
293
294 // Handle construction of an empty array.
295 AllocateEmptyJSArray(masm,
296 r1,
297 r2,
298 r3,
299 r4,
300 r5,
301 JSArray::kPreallocatedArrayElements,
302 call_generic_code);
303 __ IncrementCounter(&Counters::array_function_native, 1, r3, r4);
304 // Setup return value, remove receiver from stack and return.
305 __ mov(r0, r2);
306 __ add(sp, sp, Operand(kPointerSize));
307 __ Jump(lr);
308
309 // Check for one argument. Bail out if argument is not smi or if it is
310 // negative.
311 __ bind(&argc_one_or_more);
312 __ cmp(r0, Operand(1));
313 __ b(ne, &argc_two_or_more);
314 ASSERT(kSmiTag == 0);
315 __ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
316 __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
317 __ b(ne, call_generic_code);
318
319 // Handle construction of an empty array of a certain size. Bail out if size
320 // is too large to actually allocate an elements array.
321 ASSERT(kSmiTag == 0);
322 __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
323 __ b(ge, call_generic_code);
324
325 // r0: argc
326 // r1: constructor
327 // r2: array_size (smi)
328 // sp[0]: argument
329 AllocateJSArray(masm,
330 r1,
331 r2,
332 r3,
333 r4,
334 r5,
335 r6,
336 r7,
337 true,
338 call_generic_code);
339 __ IncrementCounter(&Counters::array_function_native, 1, r2, r4);
340 // Setup return value, remove receiver and argument from stack and return.
341 __ mov(r0, r3);
342 __ add(sp, sp, Operand(2 * kPointerSize));
343 __ Jump(lr);
344
345 // Handle construction of an array from a list of arguments.
346 __ bind(&argc_two_or_more);
347 __ mov(r2, Operand(r0, LSL, kSmiTagSize)); // Convet argc to a smi.
348
349 // r0: argc
350 // r1: constructor
351 // r2: array_size (smi)
352 // sp[0]: last argument
353 AllocateJSArray(masm,
354 r1,
355 r2,
356 r3,
357 r4,
358 r5,
359 r6,
360 r7,
361 false,
362 call_generic_code);
363 __ IncrementCounter(&Counters::array_function_native, 1, r2, r6);
364
365 // Fill arguments as array elements. Copy from the top of the stack (last
366 // element) to the array backing store filling it backwards. Note:
367 // elements_array_end points after the backing store therefore PreIndex is
368 // used when filling the backing store.
369 // r0: argc
370 // r3: JSArray
371 // r4: elements_array storage start (untagged)
372 // r5: elements_array_end (untagged)
373 // sp[0]: last argument
374 Label loop, entry;
375 __ jmp(&entry);
376 __ bind(&loop);
377 __ ldr(r2, MemOperand(sp, kPointerSize, PostIndex));
378 __ str(r2, MemOperand(r5, -kPointerSize, PreIndex));
379 __ bind(&entry);
380 __ cmp(r4, r5);
381 __ b(lt, &loop);
382
383 // Remove caller arguments and receiver from the stack, setup return value and
384 // return.
385 // r0: argc
386 // r3: JSArray
387 // sp[0]: receiver
388 __ add(sp, sp, Operand(kPointerSize));
389 __ mov(r0, r3);
390 __ Jump(lr);
391 }
392
393
54 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 394 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
55 // Just jump to the generic array code. 395 // ----------- S t a t e -------------
396 // -- r0 : number of arguments
397 // -- lr : return address
398 // -- sp[...]: constructor arguments
399 // -----------------------------------
400 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
401
402 // Get the Array function.
403 GenerateLoadArrayFunction(masm, r1);
404
405 if (FLAG_debug_code) {
406 // Initial map for the builtin Array function shoud be a map.
407 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
408 __ tst(r2, Operand(kSmiTagMask));
409 __ Assert(ne, "Unexpected initial map for Array function");
410 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
411 __ Assert(eq, "Unexpected initial map for Array function");
412 }
413
414 // Run the native code for the Array function called as a normal function.
415 ArrayNativeCode(masm, &generic_array_code);
416
417 // Jump to the generic array code if the specialized code cannot handle
418 // the construction.
419 __ bind(&generic_array_code);
56 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric); 420 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
57 Handle<Code> array_code(code); 421 Handle<Code> array_code(code);
58 __ Jump(array_code, RelocInfo::CODE_TARGET); 422 __ Jump(array_code, RelocInfo::CODE_TARGET);
59 } 423 }
60 424
61 425
62 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 426 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
63 // Just jump to the generic construct code. 427 // ----------- S t a t e -------------
428 // -- r0 : number of arguments
429 // -- r1 : constructor function
430 // -- lr : return address
431 // -- sp[...]: constructor arguments
432 // -----------------------------------
433 Label generic_constructor;
434
435 if (FLAG_debug_code) {
436 // The array construct code is only set for the builtin Array function which
437 // always have a map.
438 GenerateLoadArrayFunction(masm, r2);
439 __ cmp(r1, r2);
440 __ Assert(eq, "Unexpected Array function");
441 // Initial map for the builtin Array function should be a map.
442 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
443 __ tst(r2, Operand(kSmiTagMask));
444 __ Assert(ne, "Unexpected initial map for Array function");
445 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
446 __ Assert(eq, "Unexpected initial map for Array function");
447 }
448
449 // Run the native code for the Array function called as a constructor.
450 ArrayNativeCode(masm, &generic_constructor);
451
452 // Jump to the generic construct code in case the specialized code cannot
453 // handle the construction.
454 __ bind(&generic_constructor);
64 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 455 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
65 Handle<Code> generic_construct_stub(code); 456 Handle<Code> generic_construct_stub(code);
66 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 457 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
67 } 458 }
68 459
69 460
70 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { 461 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
71 // ----------- S t a t e ------------- 462 // ----------- S t a t e -------------
72 // -- r0 : number of arguments 463 // -- r0 : number of arguments
73 // -- r1 : constructor function 464 // -- r1 : constructor function
(...skipping 813 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 // Dont adapt arguments. 1278 // Dont adapt arguments.
888 // ------------------------------------------- 1279 // -------------------------------------------
889 __ bind(&dont_adapt_arguments); 1280 __ bind(&dont_adapt_arguments);
890 __ Jump(r3); 1281 __ Jump(r3);
891 } 1282 }
892 1283
893 1284
894 #undef __ 1285 #undef __
895 1286
896 } } // namespace v8::internal 1287 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/builtins.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698