builtins-arm.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen-inl.h"
31#include "debug.h"
32#include "runtime.h"
33
34namespace v8 {
35namespace internal {
36
37
38#define __ ACCESS_MASM(masm)
39
40
41void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
42  // TODO(428): Don't pass the function in a static variable.
43  __ mov(ip, Operand(ExternalReference::builtin_passed_function()));
44  __ str(r1, MemOperand(ip, 0));
45
46  // The actual argument count has already been loaded into register
47  // r0, but JumpToRuntime expects r0 to contain the number of
48  // arguments including the receiver.
49  __ add(r0, r0, Operand(1));
50  __ JumpToRuntime(ExternalReference(id));
51}
52
53
54// Load the built-in Array function from the current context.
55static 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.
71static 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.
77static 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  __ AllocateInNewSpace(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.
152static 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  __ AllocateInNewSpace(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  __ AllocateInNewSpace(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.
286static 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
394void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
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);
420  Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
421  Handle<Code> array_code(code);
422  __ Jump(array_code, RelocInfo::CODE_TARGET);
423}
424
425
426void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
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);
455  Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
456  Handle<Code> generic_construct_stub(code);
457  __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
458}
459
460
461void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
462  // ----------- S t a t e -------------
463  //  -- r0     : number of arguments
464  //  -- r1     : constructor function
465  //  -- lr     : return address
466  //  -- sp[...]: constructor arguments
467  // -----------------------------------
468
469  Label non_function_call;
470  // Check that the function is not a smi.
471  __ tst(r1, Operand(kSmiTagMask));
472  __ b(eq, &non_function_call);
473  // Check that the function is a JSFunction.
474  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
475  __ b(ne, &non_function_call);
476
477  // Jump to the function-specific construct stub.
478  __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
479  __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset));
480  __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
481
482  // r0: number of arguments
483  // r1: called object
484  __ bind(&non_function_call);
485
486  // Set expected number of arguments to zero (not changing r0).
487  __ mov(r2, Operand(0));
488  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
489  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
490          RelocInfo::CODE_TARGET);
491}
492
493
494void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
495  // Enter a construct frame.
496  __ EnterConstructFrame();
497
498  // Preserve the two incoming parameters on the stack.
499  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
500  __ push(r0);  // Smi-tagged arguments count.
501  __ push(r1);  // Constructor function.
502
503  // Use r7 for holding undefined which is used in several places below.
504  __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
505
506  // Try to allocate the object without transitioning into C code. If any of the
507  // preconditions is not met, the code bails out to the runtime call.
508  Label rt_call, allocated;
509  if (FLAG_inline_new) {
510    Label undo_allocation;
511#ifdef ENABLE_DEBUGGER_SUPPORT
512    ExternalReference debug_step_in_fp =
513        ExternalReference::debug_step_in_fp_address();
514    __ mov(r2, Operand(debug_step_in_fp));
515    __ ldr(r2, MemOperand(r2));
516    __ tst(r2, r2);
517    __ b(nz, &rt_call);
518#endif
519
520    // Load the initial map and verify that it is in fact a map.
521    // r1: constructor function
522    // r7: undefined
523    __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
524    __ tst(r2, Operand(kSmiTagMask));
525    __ b(eq, &rt_call);
526    __ CompareObjectType(r2, r3, r4, MAP_TYPE);
527    __ b(ne, &rt_call);
528
529    // Check that the constructor is not constructing a JSFunction (see comments
530    // in Runtime_NewObject in runtime.cc). In which case the initial map's
531    // instance type would be JS_FUNCTION_TYPE.
532    // r1: constructor function
533    // r2: initial map
534    // r7: undefined
535    __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
536    __ b(eq, &rt_call);
537
538    // Now allocate the JSObject on the heap.
539    // r1: constructor function
540    // r2: initial map
541    // r7: undefined
542    __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
543    __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, NO_ALLOCATION_FLAGS);
544
545    // Allocated the JSObject, now initialize the fields. Map is set to initial
546    // map and properties and elements are set to empty fixed array.
547    // r1: constructor function
548    // r2: initial map
549    // r3: object size
550    // r4: JSObject (not tagged)
551    // r7: undefined
552    __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
553    __ mov(r5, r4);
554    ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
555    __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
556    ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
557    __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
558    ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
559    __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
560
561    // Fill all the in-object properties with undefined.
562    // r1: constructor function
563    // r2: initial map
564    // r3: object size (in words)
565    // r4: JSObject (not tagged)
566    // r5: First in-object property of JSObject (not tagged)
567    // r7: undefined
568    __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2));  // End of object.
569    ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize);
570    { Label loop, entry;
571      __ b(&entry);
572      __ bind(&loop);
573      __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
574      __ bind(&entry);
575      __ cmp(r5, Operand(r6));
576      __ b(lt, &loop);
577    }
578
579    // Add the object tag to make the JSObject real, so that we can continue and
580    // jump into the continuation code at any time from now on. Any failures
581    // need to undo the allocation, so that the heap is in a consistent state
582    // and verifiable.
583    __ add(r4, r4, Operand(kHeapObjectTag));
584
585    // Check if a non-empty properties array is needed. Continue with allocated
586    // object if not fall through to runtime call if it is.
587    // r1: constructor function
588    // r4: JSObject
589    // r5: start of next object (not tagged)
590    // r7: undefined
591    __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset));
592    // The field instance sizes contains both pre-allocated property fields and
593    // in-object properties.
594    __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
595    __ and_(r6,
596            r0,
597            Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8));
598    __ add(r3, r3, Operand(r6, LSR, Map::kPreAllocatedPropertyFieldsByte * 8));
599    __ and_(r6, r0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8));
600    __ sub(r3, r3, Operand(r6, LSR, Map::kInObjectPropertiesByte * 8), SetCC);
601
602    // Done if no extra properties are to be allocated.
603    __ b(eq, &allocated);
604    __ Assert(pl, "Property allocation count failed.");
605
606    // Scale the number of elements by pointer size and add the header for
607    // FixedArrays to the start of the next object calculation from above.
608    // r1: constructor
609    // r3: number of elements in properties array
610    // r4: JSObject
611    // r5: start of next object
612    // r7: undefined
613    __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize));
614    __ AllocateInNewSpace(r0,
615                          r5,
616                          r6,
617                          r2,
618                          &undo_allocation,
619                          RESULT_CONTAINS_TOP);
620
621    // Initialize the FixedArray.
622    // r1: constructor
623    // r3: number of elements in properties array
624    // r4: JSObject
625    // r5: FixedArray (not tagged)
626    // r7: undefined
627    __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex);
628    __ mov(r2, r5);
629    ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
630    __ str(r6, MemOperand(r2, kPointerSize, PostIndex));
631    ASSERT_EQ(1 * kPointerSize, Array::kLengthOffset);
632    __ str(r3, MemOperand(r2, kPointerSize, PostIndex));
633
634    // Initialize the fields to undefined.
635    // r1: constructor function
636    // r2: First element of FixedArray (not tagged)
637    // r3: number of elements in properties array
638    // r4: JSObject
639    // r5: FixedArray (not tagged)
640    // r7: undefined
641    __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2));  // End of object.
642    ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
643    { Label loop, entry;
644      __ b(&entry);
645      __ bind(&loop);
646      __ str(r7, MemOperand(r2, kPointerSize, PostIndex));
647      __ bind(&entry);
648      __ cmp(r2, Operand(r6));
649      __ b(lt, &loop);
650    }
651
652    // Store the initialized FixedArray into the properties field of
653    // the JSObject
654    // r1: constructor function
655    // r4: JSObject
656    // r5: FixedArray (not tagged)
657    __ add(r5, r5, Operand(kHeapObjectTag));  // Add the heap tag.
658    __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset));
659
660    // Continue with JSObject being successfully allocated
661    // r1: constructor function
662    // r4: JSObject
663    __ jmp(&allocated);
664
665    // Undo the setting of the new top so that the heap is verifiable. For
666    // example, the map's unused properties potentially do not match the
667    // allocated objects unused properties.
668    // r4: JSObject (previous new top)
669    __ bind(&undo_allocation);
670    __ UndoAllocationInNewSpace(r4, r5);
671  }
672
673  // Allocate the new receiver object using the runtime call.
674  // r1: constructor function
675  __ bind(&rt_call);
676  __ push(r1);  // argument for Runtime_NewObject
677  __ CallRuntime(Runtime::kNewObject, 1);
678  __ mov(r4, r0);
679
680  // Receiver for constructor call allocated.
681  // r4: JSObject
682  __ bind(&allocated);
683  __ push(r4);
684
685  // Push the function and the allocated receiver from the stack.
686  // sp[0]: receiver (newly allocated object)
687  // sp[1]: constructor function
688  // sp[2]: number of arguments (smi-tagged)
689  __ ldr(r1, MemOperand(sp, kPointerSize));
690  __ push(r1);  // Constructor function.
691  __ push(r4);  // Receiver.
692
693  // Reload the number of arguments from the stack.
694  // r1: constructor function
695  // sp[0]: receiver
696  // sp[1]: constructor function
697  // sp[2]: receiver
698  // sp[3]: constructor function
699  // sp[4]: number of arguments (smi-tagged)
700  __ ldr(r3, MemOperand(sp, 4 * kPointerSize));
701
702  // Setup pointer to last argument.
703  __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
704
705  // Setup number of arguments for function call below
706  __ mov(r0, Operand(r3, LSR, kSmiTagSize));
707
708  // Copy arguments and receiver to the expression stack.
709  // r0: number of arguments
710  // r2: address of last argument (caller sp)
711  // r1: constructor function
712  // r3: number of arguments (smi-tagged)
713  // sp[0]: receiver
714  // sp[1]: constructor function
715  // sp[2]: receiver
716  // sp[3]: constructor function
717  // sp[4]: number of arguments (smi-tagged)
718  Label loop, entry;
719  __ b(&entry);
720  __ bind(&loop);
721  __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
722  __ push(ip);
723  __ bind(&entry);
724  __ sub(r3, r3, Operand(2), SetCC);
725  __ b(ge, &loop);
726
727  // Call the function.
728  // r0: number of arguments
729  // r1: constructor function
730  ParameterCount actual(r0);
731  __ InvokeFunction(r1, actual, CALL_FUNCTION);
732
733  // Pop the function from the stack.
734  // sp[0]: constructor function
735  // sp[2]: receiver
736  // sp[3]: constructor function
737  // sp[4]: number of arguments (smi-tagged)
738  __ pop();
739
740  // Restore context from the frame.
741  // r0: result
742  // sp[0]: receiver
743  // sp[1]: constructor function
744  // sp[2]: number of arguments (smi-tagged)
745  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
746
747  // If the result is an object (in the ECMA sense), we should get rid
748  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
749  // on page 74.
750  Label use_receiver, exit;
751
752  // If the result is a smi, it is *not* an object in the ECMA sense.
753  // r0: result
754  // sp[0]: receiver (newly allocated object)
755  // sp[1]: constructor function
756  // sp[2]: number of arguments (smi-tagged)
757  __ tst(r0, Operand(kSmiTagMask));
758  __ b(eq, &use_receiver);
759
760  // If the type of the result (stored in its map) is less than
761  // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
762  __ CompareObjectType(r0, r3, r3, FIRST_JS_OBJECT_TYPE);
763  __ b(ge, &exit);
764
765  // Throw away the result of the constructor invocation and use the
766  // on-stack receiver as the result.
767  __ bind(&use_receiver);
768  __ ldr(r0, MemOperand(sp));
769
770  // Remove receiver from the stack, remove caller arguments, and
771  // return.
772  __ bind(&exit);
773  // r0: result
774  // sp[0]: receiver (newly allocated object)
775  // sp[1]: constructor function
776  // sp[2]: number of arguments (smi-tagged)
777  __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
778  __ LeaveConstructFrame();
779  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
780  __ add(sp, sp, Operand(kPointerSize));
781  __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
782  __ Jump(lr);
783}
784
785
786static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
787                                             bool is_construct) {
788  // Called from Generate_JS_Entry
789  // r0: code entry
790  // r1: function
791  // r2: receiver
792  // r3: argc
793  // r4: argv
794  // r5-r7, cp may be clobbered
795
796  // Clear the context before we push it when entering the JS frame.
797  __ mov(cp, Operand(0));
798
799  // Enter an internal frame.
800  __ EnterInternalFrame();
801
802  // Set up the context from the function argument.
803  __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
804
805  // Set up the roots register.
806  ExternalReference roots_address = ExternalReference::roots_address();
807  __ mov(r10, Operand(roots_address));
808
809  // Push the function and the receiver onto the stack.
810  __ push(r1);
811  __ push(r2);
812
813  // Copy arguments to the stack in a loop.
814  // r1: function
815  // r3: argc
816  // r4: argv, i.e. points to first arg
817  Label loop, entry;
818  __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2));
819  // r2 points past last arg.
820  __ b(&entry);
821  __ bind(&loop);
822  __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex));  // read next parameter
823  __ ldr(r0, MemOperand(r0));  // dereference handle
824  __ push(r0);  // push parameter
825  __ bind(&entry);
826  __ cmp(r4, Operand(r2));
827  __ b(ne, &loop);
828
829  // Initialize all JavaScript callee-saved registers, since they will be seen
830  // by the garbage collector as part of handlers.
831  __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
832  __ mov(r5, Operand(r4));
833  __ mov(r6, Operand(r4));
834  __ mov(r7, Operand(r4));
835  if (kR9Available == 1) {
836    __ mov(r9, Operand(r4));
837  }
838
839  // Invoke the code and pass argc as r0.
840  __ mov(r0, Operand(r3));
841  if (is_construct) {
842    __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
843            RelocInfo::CODE_TARGET);
844  } else {
845    ParameterCount actual(r0);
846    __ InvokeFunction(r1, actual, CALL_FUNCTION);
847  }
848
849  // Exit the JS frame and remove the parameters (except function), and return.
850  // Respect ABI stack constraint.
851  __ LeaveInternalFrame();
852  __ Jump(lr);
853
854  // r0: result
855}
856
857
858void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
859  Generate_JSEntryTrampolineHelper(masm, false);
860}
861
862
863void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
864  Generate_JSEntryTrampolineHelper(masm, true);
865}
866
867
868void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
869  // 1. Make sure we have at least one argument.
870  // r0: actual number of argument
871  { Label done;
872    __ tst(r0, Operand(r0));
873    __ b(ne, &done);
874    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
875    __ push(r2);
876    __ add(r0, r0, Operand(1));
877    __ bind(&done);
878  }
879
880  // 2. Get the function to call from the stack.
881  // r0: actual number of argument
882  { Label done, non_function, function;
883    __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
884    __ tst(r1, Operand(kSmiTagMask));
885    __ b(eq, &non_function);
886    __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
887    __ b(eq, &function);
888
889    // Non-function called: Clear the function to force exception.
890    __ bind(&non_function);
891    __ mov(r1, Operand(0));
892    __ b(&done);
893
894    // Change the context eagerly because it will be used below to get the
895    // right global object.
896    __ bind(&function);
897    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
898
899    __ bind(&done);
900  }
901
902  // 3. Make sure first argument is an object; convert if necessary.
903  // r0: actual number of arguments
904  // r1: function
905  { Label call_to_object, use_global_receiver, patch_receiver, done;
906    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
907    __ ldr(r2, MemOperand(r2, -kPointerSize));
908
909    // r0: actual number of arguments
910    // r1: function
911    // r2: first argument
912    __ tst(r2, Operand(kSmiTagMask));
913    __ b(eq, &call_to_object);
914
915    __ LoadRoot(r3, Heap::kNullValueRootIndex);
916    __ cmp(r2, r3);
917    __ b(eq, &use_global_receiver);
918    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
919    __ cmp(r2, r3);
920    __ b(eq, &use_global_receiver);
921
922    __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE);
923    __ b(lt, &call_to_object);
924    __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
925    __ b(le, &done);
926
927    __ bind(&call_to_object);
928    __ EnterInternalFrame();
929
930    // Store number of arguments and function across the call into the runtime.
931    __ mov(r0, Operand(r0, LSL, kSmiTagSize));
932    __ push(r0);
933    __ push(r1);
934
935    __ push(r2);
936    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
937    __ mov(r2, r0);
938
939    // Restore number of arguments and function.
940    __ pop(r1);
941    __ pop(r0);
942    __ mov(r0, Operand(r0, ASR, kSmiTagSize));
943
944    __ LeaveInternalFrame();
945    __ b(&patch_receiver);
946
947    // Use the global receiver object from the called function as the receiver.
948    __ bind(&use_global_receiver);
949    const int kGlobalIndex =
950        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
951    __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
952    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
953
954    __ bind(&patch_receiver);
955    __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
956    __ str(r2, MemOperand(r3, -kPointerSize));
957
958    __ bind(&done);
959  }
960
961  // 4. Shift stuff one slot down the stack
962  // r0: actual number of arguments (including call() receiver)
963  // r1: function
964  { Label loop;
965    // Calculate the copy start address (destination). Copy end address is sp.
966    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
967    __ add(r2, r2, Operand(kPointerSize));  // copy receiver too
968
969    __ bind(&loop);
970    __ ldr(ip, MemOperand(r2, -kPointerSize));
971    __ str(ip, MemOperand(r2));
972    __ sub(r2, r2, Operand(kPointerSize));
973    __ cmp(r2, sp);
974    __ b(ne, &loop);
975  }
976
977  // 5. Adjust the actual number of arguments and remove the top element.
978  // r0: actual number of arguments (including call() receiver)
979  // r1: function
980  __ sub(r0, r0, Operand(1));
981  __ add(sp, sp, Operand(kPointerSize));
982
983  // 6. Get the code for the function or the non-function builtin.
984  //    If number of expected arguments matches, then call. Otherwise restart
985  //    the arguments adaptor stub.
986  // r0: actual number of arguments
987  // r1: function
988  { Label invoke;
989    __ tst(r1, r1);
990    __ b(ne, &invoke);
991    __ mov(r2, Operand(0));  // expected arguments is 0 for CALL_NON_FUNCTION
992    __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
993    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
994                         RelocInfo::CODE_TARGET);
995
996    __ bind(&invoke);
997    __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
998    __ ldr(r2,
999           FieldMemOperand(r3,
1000                           SharedFunctionInfo::kFormalParameterCountOffset));
1001    __ ldr(r3,
1002           MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
1003    __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
1004    __ cmp(r2, r0);  // Check formal and actual parameter counts.
1005    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1006                         RelocInfo::CODE_TARGET, ne);
1007
1008    // 7. Jump to the code in r3 without checking arguments.
1009    ParameterCount expected(0);
1010    __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
1011  }
1012}
1013
1014
1015void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1016  const int kIndexOffset    = -5 * kPointerSize;
1017  const int kLimitOffset    = -4 * kPointerSize;
1018  const int kArgsOffset     =  2 * kPointerSize;
1019  const int kRecvOffset     =  3 * kPointerSize;
1020  const int kFunctionOffset =  4 * kPointerSize;
1021
1022  __ EnterInternalFrame();
1023
1024  __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
1025  __ push(r0);
1026  __ ldr(r0, MemOperand(fp, kArgsOffset));  // get the args array
1027  __ push(r0);
1028  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
1029
1030  Label no_preemption, retry_preemption;
1031  __ bind(&retry_preemption);
1032  ExternalReference stack_guard_limit_address =
1033      ExternalReference::address_of_stack_guard_limit();
1034  __ mov(r2, Operand(stack_guard_limit_address));
1035  __ ldr(r2, MemOperand(r2));
1036  __ cmp(sp, r2);
1037  __ b(hi, &no_preemption);
1038
1039  // We have encountered a preemption or stack overflow already before we push
1040  // the array contents.  Save r0 which is the Smi-tagged length of the array.
1041  __ push(r0);
1042
1043  // Runtime routines expect at least one argument, so give it a Smi.
1044  __ mov(r0, Operand(Smi::FromInt(0)));
1045  __ push(r0);
1046  __ CallRuntime(Runtime::kStackGuard, 1);
1047
1048  // Since we returned, it wasn't a stack overflow.  Restore r0 and try again.
1049  __ pop(r0);
1050  __ b(&retry_preemption);
1051
1052  __ bind(&no_preemption);
1053
1054  // Eagerly check for stack-overflow before starting to push the arguments.
1055  // r0: number of arguments.
1056  // r2: stack limit.
1057  Label okay;
1058  __ sub(r2, sp, r2);
1059
1060  __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1061  __ b(hi, &okay);
1062
1063  // Out of stack space.
1064  __ ldr(r1, MemOperand(fp, kFunctionOffset));
1065  __ push(r1);
1066  __ push(r0);
1067  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
1068
1069  // Push current limit and index.
1070  __ bind(&okay);
1071  __ push(r0);  // limit
1072  __ mov(r1, Operand(0));  // initial index
1073  __ push(r1);
1074
1075  // Change context eagerly to get the right global object if necessary.
1076  __ ldr(r0, MemOperand(fp, kFunctionOffset));
1077  __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
1078
1079  // Compute the receiver.
1080  Label call_to_object, use_global_receiver, push_receiver;
1081  __ ldr(r0, MemOperand(fp, kRecvOffset));
1082  __ tst(r0, Operand(kSmiTagMask));
1083  __ b(eq, &call_to_object);
1084  __ LoadRoot(r1, Heap::kNullValueRootIndex);
1085  __ cmp(r0, r1);
1086  __ b(eq, &use_global_receiver);
1087  __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
1088  __ cmp(r0, r1);
1089  __ b(eq, &use_global_receiver);
1090
1091  // Check if the receiver is already a JavaScript object.
1092  // r0: receiver
1093  __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
1094  __ b(lt, &call_to_object);
1095  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
1096  __ b(le, &push_receiver);
1097
1098  // Convert the receiver to a regular object.
1099  // r0: receiver
1100  __ bind(&call_to_object);
1101  __ push(r0);
1102  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
1103  __ b(&push_receiver);
1104
1105  // Use the current global receiver object as the receiver.
1106  __ bind(&use_global_receiver);
1107  const int kGlobalOffset =
1108      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
1109  __ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
1110  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1111
1112  // Push the receiver.
1113  // r0: receiver
1114  __ bind(&push_receiver);
1115  __ push(r0);
1116
1117  // Copy all arguments from the array to the stack.
1118  Label entry, loop;
1119  __ ldr(r0, MemOperand(fp, kIndexOffset));
1120  __ b(&entry);
1121
1122  // Load the current argument from the arguments array and push it to the
1123  // stack.
1124  // r0: current argument index
1125  __ bind(&loop);
1126  __ ldr(r1, MemOperand(fp, kArgsOffset));
1127  __ push(r1);
1128  __ push(r0);
1129
1130  // Call the runtime to access the property in the arguments array.
1131  __ CallRuntime(Runtime::kGetProperty, 2);
1132  __ push(r0);
1133
1134  // Use inline caching to access the arguments.
1135  __ ldr(r0, MemOperand(fp, kIndexOffset));
1136  __ add(r0, r0, Operand(1 << kSmiTagSize));
1137  __ str(r0, MemOperand(fp, kIndexOffset));
1138
1139  // Test if the copy loop has finished copying all the elements from the
1140  // arguments object.
1141  __ bind(&entry);
1142  __ ldr(r1, MemOperand(fp, kLimitOffset));
1143  __ cmp(r0, r1);
1144  __ b(ne, &loop);
1145
1146  // Invoke the function.
1147  ParameterCount actual(r0);
1148  __ mov(r0, Operand(r0, ASR, kSmiTagSize));
1149  __ ldr(r1, MemOperand(fp, kFunctionOffset));
1150  __ InvokeFunction(r1, actual, CALL_FUNCTION);
1151
1152  // Tear down the internal frame and remove function, receiver and args.
1153  __ LeaveInternalFrame();
1154  __ add(sp, sp, Operand(3 * kPointerSize));
1155  __ Jump(lr);
1156}
1157
1158
1159static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1160  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1161  __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1162  __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit());
1163  __ add(fp, sp, Operand(3 * kPointerSize));
1164}
1165
1166
1167static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1168  // ----------- S t a t e -------------
1169  //  -- r0 : result being passed through
1170  // -----------------------------------
1171  // Get the number of arguments passed (as a smi), tear down the frame and
1172  // then tear down the parameters.
1173  __ ldr(r1, MemOperand(fp, -3 * kPointerSize));
1174  __ mov(sp, fp);
1175  __ ldm(ia_w, sp, fp.bit() | lr.bit());
1176  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
1177  __ add(sp, sp, Operand(kPointerSize));  // adjust for receiver
1178}
1179
1180
1181void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1182  // ----------- S t a t e -------------
1183  //  -- r0 : actual number of arguments
1184  //  -- r1 : function (passed through to callee)
1185  //  -- r2 : expected number of arguments
1186  //  -- r3 : code entry to call
1187  // -----------------------------------
1188
1189  Label invoke, dont_adapt_arguments;
1190
1191  Label enough, too_few;
1192  __ cmp(r0, Operand(r2));
1193  __ b(lt, &too_few);
1194  __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
1195  __ b(eq, &dont_adapt_arguments);
1196
1197  {  // Enough parameters: actual >= expected
1198    __ bind(&enough);
1199    EnterArgumentsAdaptorFrame(masm);
1200
1201    // Calculate copy start address into r0 and copy end address into r2.
1202    // r0: actual number of arguments as a smi
1203    // r1: function
1204    // r2: expected number of arguments
1205    // r3: code entry to call
1206    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1207    // adjust for return address and receiver
1208    __ add(r0, r0, Operand(2 * kPointerSize));
1209    __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
1210
1211    // Copy the arguments (including the receiver) to the new stack frame.
1212    // r0: copy start address
1213    // r1: function
1214    // r2: copy end address
1215    // r3: code entry to call
1216
1217    Label copy;
1218    __ bind(&copy);
1219    __ ldr(ip, MemOperand(r0, 0));
1220    __ push(ip);
1221    __ cmp(r0, r2);  // Compare before moving to next argument.
1222    __ sub(r0, r0, Operand(kPointerSize));
1223    __ b(ne, &copy);
1224
1225    __ b(&invoke);
1226  }
1227
1228  {  // Too few parameters: Actual < expected
1229    __ bind(&too_few);
1230    EnterArgumentsAdaptorFrame(masm);
1231
1232    // Calculate copy start address into r0 and copy end address is fp.
1233    // r0: actual number of arguments as a smi
1234    // r1: function
1235    // r2: expected number of arguments
1236    // r3: code entry to call
1237    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1238
1239    // Copy the arguments (including the receiver) to the new stack frame.
1240    // r0: copy start address
1241    // r1: function
1242    // r2: expected number of arguments
1243    // r3: code entry to call
1244    Label copy;
1245    __ bind(&copy);
1246    // Adjust load for return address and receiver.
1247    __ ldr(ip, MemOperand(r0, 2 * kPointerSize));
1248    __ push(ip);
1249    __ cmp(r0, fp);  // Compare before moving to next argument.
1250    __ sub(r0, r0, Operand(kPointerSize));
1251    __ b(ne, &copy);
1252
1253    // Fill the remaining expected arguments with undefined.
1254    // r1: function
1255    // r2: expected number of arguments
1256    // r3: code entry to call
1257    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1258    __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
1259    __ sub(r2, r2, Operand(4 * kPointerSize));  // Adjust for frame.
1260
1261    Label fill;
1262    __ bind(&fill);
1263    __ push(ip);
1264    __ cmp(sp, r2);
1265    __ b(ne, &fill);
1266  }
1267
1268  // Call the entry point.
1269  __ bind(&invoke);
1270  __ Call(r3);
1271
1272  // Exit frame and return.
1273  LeaveArgumentsAdaptorFrame(masm);
1274  __ Jump(lr);
1275
1276
1277  // -------------------------------------------
1278  // Dont adapt arguments.
1279  // -------------------------------------------
1280  __ bind(&dont_adapt_arguments);
1281  __ Jump(r3);
1282}
1283
1284
1285#undef __
1286
1287} }  // namespace v8::internal
1288