builtins-arm.cc revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2009 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_ARM)
31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "runtime.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
43e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid Builtins::Generate_Adaptor(MacroAssembler* masm,
44e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                CFunctionId id,
45e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                BuiltinExtraArguments extra_args) {
46e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
47e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- r0                 : number of arguments excluding receiver
48e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- r1                 : called function (only guaranteed when
49e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //                          extra_args requires it)
50e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- cp                 : context
51e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- sp[0]              : last argument
52e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
53e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- sp[4 * (argc - 1)] : first argument (argc == r0)
54e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- sp[4 * argc]       : receiver
55e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
56e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
57e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Insert extra arguments.
58e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  int num_extra_args = 0;
59e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (extra_args == NEEDS_CALLED_FUNCTION) {
60e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    num_extra_args = 1;
61e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ push(r1);
62e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
63e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
64e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
65e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // JumpToExternalReference expects r0 to contain the number of arguments
67e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // including the receiver and the extra arguments.
68e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ add(r0, r0, Operand(num_extra_args + 1));
696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ JumpToExternalReference(ExternalReference(id));
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Load the built-in Array function from the current context.
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the global context.
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(result,
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the Array function from the global context.
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(result,
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         MemOperand(result,
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This constant has the same value as JSArray::kPreallocatedArrayElements and
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// below should be reconsidered.
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kLoopUnfoldLimit = 4;
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Allocate an empty JSArray. The allocated array is put into the result
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// register. An elements backing store is allocated with size initial_capacity
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and filled with the hole values.
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void AllocateEmptyJSArray(MacroAssembler* masm,
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register array_function,
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register result,
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register scratch1,
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register scratch2,
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register scratch3,
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 int initial_capacity,
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Label* gc_required) {
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(initial_capacity > 0);
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the initial map from the array function.
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(scratch1, FieldMemOperand(array_function,
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   JSFunction::kPrototypeOrInitialMapOffset));
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate the JSArray object together with space for a fixed array with the
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // requested elements.
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity);
11225f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ AllocateInNewSpace(size,
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        result,
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        scratch2,
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        scratch3,
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        gc_required,
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        TAG_OBJECT);
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocated the JSArray. Now initialize the fields except for the elements
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array.
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch1: initial map
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch2: start of next object
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch1, FieldMemOperand(result, JSObject::kMapOffset));
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset));
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Field JSArray::kElementsOffset is initialized later.
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(scratch3,  Operand(0));
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset));
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate the location of the elements array and set elements array member
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the JSArray.
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch2: start of next object
135f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  __ add(scratch1, result, Operand(JSArray::kSize));
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset));
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear the heap tag on the elements array.
1399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  ASSERT(kSmiTag == 0);
1409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ sub(scratch1, scratch1, Operand(kHeapObjectTag));
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Initialize the FixedArray and fill it with holes. FixedArray length is
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stored as a smi.
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch1: elements array (untagged)
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch2: start of next object
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex);
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
1507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(scratch3,  Operand(Smi::FromInt(initial_capacity)));
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the FixedArray with the hole value.
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(initial_capacity <= kLoopUnfoldLimit);
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < initial_capacity; i++) {
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Allocate a JSArray with the number of elements stored in a register. The
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// register array_function holds the built-in Array function and the register
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// array_size holds the size of the array as a smi. The allocated array is put
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// into the result register and beginning and end of the FixedArray elements
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// storage is put into registers elements_array_storage and elements_array_end
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (see  below for when that is not the case). If the parameter fill_with_holes
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// is true the allocated elements backing store is filled with the hole values
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// otherwise it is left uninitialized. When the backing store is filled the
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// register elements_array_storage is scratched.
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void AllocateJSArray(MacroAssembler* masm,
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register array_function,  // Array function.
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register array_size,  // As a smi.
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register result,
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register elements_array_storage,
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register elements_array_end,
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register scratch1,
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Register scratch2,
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            bool fill_with_hole,
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                            Label* gc_required) {
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label not_empty, allocated;
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the initial map from the array function.
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(elements_array_storage,
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         FieldMemOperand(array_function,
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         JSFunction::kPrototypeOrInitialMapOffset));
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether an empty sized array is requested.
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ tst(array_size, array_size);
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(nz, &not_empty);
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If an empty array is requested allocate a small elements array anyway. This
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // keeps the code below free of special casing for the empty array.
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size = JSArray::kSize +
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
19725f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ AllocateInNewSpace(size,
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        result,
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        elements_array_end,
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        scratch1,
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        gc_required,
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        TAG_OBJECT);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&allocated);
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate the JSArray object together with space for a FixedArray with the
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // requested number of elements.
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&not_empty);
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(elements_array_end,
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(elements_array_end,
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         elements_array_end,
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Operand(array_size, ASR, kSmiTagSize));
21425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ AllocateInNewSpace(
21525f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      elements_array_end,
21625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      result,
21725f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      scratch1,
21825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      scratch2,
21925f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      gc_required,
22025f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocated the JSArray. Now initialize the fields except for the elements
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array.
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_storage: initial map
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array_size: size of array (smi)
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&allocated);
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(elements_array_storage,
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         FieldMemOperand(result, JSArray::kPropertiesOffset));
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Field JSArray::kElementsOffset is initialized later.
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset));
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate the location of the elements array and set elements array member
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the JSArray.
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array_size: size of array (smi)
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(elements_array_storage, result, Operand(JSArray::kSize));
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(elements_array_storage,
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         FieldMemOperand(result, JSArray::kElementsOffset));
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear the heap tag on the elements array.
2449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  ASSERT(kSmiTag == 0);
2459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ sub(elements_array_storage,
2469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen         elements_array_storage,
2479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen         Operand(kHeapObjectTag));
2487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Initialize the fixed array and fill it with holes. FixedArray length is
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stored as a smi.
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_storage: elements array (untagged)
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array_size: size of array (smi)
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex);
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
2567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(kSmiTag == 0);
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ tst(array_size, array_size);
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Length of the FixedArray is the number of pre-allocated elements if
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the actual JSArray has length 0 and the size of the JSArray for non-empty
2607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // JSArrays. The length of a FixedArray is stored as a smi.
2617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(array_size,
2627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)),
2637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         LeaveCC,
2647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         eq);
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(array_size,
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         MemOperand(elements_array_storage, kPointerSize, PostIndex));
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate elements array and elements array end.
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_storage: elements array element storage
2727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // array_size: smi-tagged size of elements array
2737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(elements_array_end,
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         elements_array_storage,
2767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         Operand(array_size, LSL, kPointerSizeLog2 - kSmiTagSize));
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the allocated FixedArray with the hole value if requested.
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result: JSObject
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_storage: elements array element storage
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_end: start of next object
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (fill_with_hole) {
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label loop, entry;
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(&entry);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&loop);
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(scratch1,
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           MemOperand(elements_array_storage, kPointerSize, PostIndex));
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&entry);
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(elements_array_storage, elements_array_end);
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(lt, &loop);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Create a new array for the built-in Array function. This function allocates
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the JSArray object and the FixedArray elements array and initializes these.
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If the Array cannot be constructed in native code the runtime is called. This
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// function assumes the following state:
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//   r0: argc
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//   r1: constructor (built-in Array function)
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//   lr: return address
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//   sp[0]: last argument
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This function is used for both construct and normal calls of Array. The only
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// difference between handling a construct call and a normal call is that for a
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// construct call the constructor function in r1 needs to be preserved for
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// entering the generic code. In both cases argc in r0 needs to be preserved.
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Both registers are preserved by this code so no need to differentiate between
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// construct call and normal call.
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ArrayNativeCode(MacroAssembler* masm,
310d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                            Label* call_generic_code) {
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label argc_one_or_more, argc_two_or_more;
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for array construction with zero arguments or one.
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, Operand(0));
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, &argc_one_or_more);
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle construction of an empty array.
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AllocateEmptyJSArray(masm,
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       r1,
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       r2,
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       r3,
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       r4,
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       r5,
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       JSArray::kPreallocatedArrayElements,
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       call_generic_code);
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::array_function_native, 1, r3, r4);
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup return value, remove receiver from stack and return.
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, r2);
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(kPointerSize));
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for one argument. Bail out if argument is not smi or if it is
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // negative.
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&argc_one_or_more);
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, Operand(1));
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, &argc_two_or_more);
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kSmiTag == 0);
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r2, MemOperand(sp));  // Get the argument from the stack.
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, call_generic_code);
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle construction of an empty array of a certain size. Bail out if size
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is too large to actually allocate an elements array.
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kSmiTag == 0);
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ge, call_generic_code);
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: argc
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2: array_size (smi)
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: argument
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AllocateJSArray(masm,
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r1,
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r2,
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r3,
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r4,
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r5,
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r6,
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r7,
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  true,
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  call_generic_code);
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::array_function_native, 1, r2, r4);
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup return value, remove receiver and argument from stack and return.
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, r3);
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(2 * kPointerSize));
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle construction of an array from a list of arguments.
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&argc_two_or_more);
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r2, Operand(r0, LSL, kSmiTagSize));  // Convet argc to a smi.
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: argc
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2: array_size (smi)
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: last argument
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AllocateJSArray(masm,
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r1,
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r2,
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r3,
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r4,
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r5,
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r6,
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  r7,
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  false,
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  call_generic_code);
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::array_function_native, 1, r2, r6);
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill arguments as array elements. Copy from the top of the stack (last
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // element) to the array backing store filling it backwards. Note:
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // elements_array_end points after the backing store therefore PreIndex is
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // used when filling the backing store.
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: argc
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r3: JSArray
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r4: elements_array storage start (untagged)
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r5: elements_array_end (untagged)
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: last argument
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label loop, entry;
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&entry);
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r2, MemOperand(sp, kPointerSize, PostIndex));
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(r2, MemOperand(r5, -kPointerSize, PreIndex));
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&entry);
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r4, r5);
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(lt, &loop);
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove caller arguments and receiver from the stack, setup return value and
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // return.
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: argc
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r3: JSArray
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(kPointerSize));
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, r3);
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_ArrayCode(MacroAssembler* masm) {
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r0     : number of arguments
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- lr     : return address
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- sp[...]: constructor arguments
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the Array function.
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadArrayFunction(masm, r1);
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Initial map for the builtin Array function shoud be a map.
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r2, Operand(kSmiTagMask));
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(ne, "Unexpected initial map for Array function");
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareObjectType(r2, r3, r4, MAP_TYPE);
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(eq, "Unexpected initial map for Array function");
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run the native code for the Array function called as a normal function.
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ArrayNativeCode(masm, &generic_array_code);
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the generic array code if the specialized code cannot handle
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the construction.
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&generic_array_code);
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> array_code(code);
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(array_code, RelocInfo::CODE_TARGET);
446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r0     : number of arguments
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r1     : constructor function
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- lr     : return address
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- sp[...]: constructor arguments
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label generic_constructor;
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The array construct code is only set for the builtin Array function which
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // always have a map.
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GenerateLoadArrayFunction(masm, r2);
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r1, r2);
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(eq, "Unexpected Array function");
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Initial map for the builtin Array function should be a map.
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r2, Operand(kSmiTagMask));
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(ne, "Unexpected initial map for Array function");
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareObjectType(r2, r3, r4, MAP_TYPE);
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(eq, "Unexpected initial map for Array function");
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run the native code for the Array function called as a constructor.
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ArrayNativeCode(masm, &generic_constructor);
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the generic construct code in case the specialized code cannot
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // handle the construction.
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&generic_constructor);
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> generic_construct_stub(code);
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
48480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
48580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(849): implement custom construct stub.
48680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate a copy of the generic stub for now.
48780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Generate_JSConstructStubGeneric(masm);
48880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
48980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
49080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r0     : number of arguments
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r1     : constructor function
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- lr     : return address
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- sp[...]: constructor arguments
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label non_function_call;
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function is not a smi.
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ tst(r1, Operand(kSmiTagMask));
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &non_function_call);
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function is a JSFunction.
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, &non_function_call);
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the function-specific construct stub.
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset));
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: number of arguments
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: called object
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_function_call);
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set expected number of arguments to zero (not changing r0).
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r2, Operand(0));
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          RelocInfo::CODE_TARGET);
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
523e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkestatic void Generate_JSConstructStubHelper(MacroAssembler* masm,
524e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                           bool is_api_function) {
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter a construct frame.
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterConstructFrame();
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Preserve the two incoming parameters on the stack.
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);  // Smi-tagged arguments count.
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);  // Constructor function.
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use r7 for holding undefined which is used in several places below.
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Try to allocate the object without transitioning into C code. If any of the
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // preconditions is not met, the code bails out to the runtime call.
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label rt_call, allocated;
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_inline_new) {
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label undo_allocation;
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ExternalReference debug_step_in_fp =
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ExternalReference::debug_step_in_fp_address();
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r2, Operand(debug_step_in_fp));
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, MemOperand(r2));
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r2, r2);
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(nz, &rt_call);
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the initial map and verify that it is in fact a map.
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
5527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r2, Operand(kSmiTagMask));
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(eq, &rt_call);
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareObjectType(r2, r3, r4, MAP_TYPE);
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &rt_call);
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that the constructor is not constructing a JSFunction (see comments
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // in Runtime_NewObject in runtime.cc). In which case the initial map's
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // instance type would be JS_FUNCTION_TYPE.
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: initial map
5647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(eq, &rt_call);
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Now allocate the JSObject on the heap.
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: initial map
5717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
57325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen    __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS);
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Allocated the JSObject, now initialize the fields. Map is set to initial
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // map and properties and elements are set to empty fixed array.
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: initial map
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: object size
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject (not tagged)
5817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r5, r4);
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Fill all the in-object properties with undefined.
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: initial map
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: object size (in words)
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject (not tagged)
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: First in-object property of JSObject (not tagged)
5977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2));  // End of object.
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize);
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    { Label loop, entry;
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ b(&entry);
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&loop);
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&entry);
6056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ cmp(r5, r6);
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ b(lt, &loop);
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Add the object tag to make the JSObject real, so that we can continue and
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // jump into the continuation code at any time from now on. Any failures
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // need to undo the allocation, so that the heap is in a consistent state
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // and verifiable.
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r4, r4, Operand(kHeapObjectTag));
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if a non-empty properties array is needed. Continue with allocated
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // object if not fall through to runtime call if it is.
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: start of next object (not tagged)
6207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset));
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The field instance sizes contains both pre-allocated property fields and
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // in-object properties.
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
6259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    __ Ubfx(r6, r0, Map::kPreAllocatedPropertyFieldsByte * 8, 8);
6269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    __ add(r3, r3, Operand(r6));
6279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    __ Ubfx(r6, r0, Map::kInObjectPropertiesByte * 8, 8);
6289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    __ sub(r3, r3, Operand(r6), SetCC);
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Done if no extra properties are to be allocated.
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(eq, &allocated);
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(pl, "Property allocation count failed.");
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Scale the number of elements by pointer size and add the header for
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // FixedArrays to the start of the next object calculation from above.
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: number of elements in properties array
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: start of next object
6407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize));
64225f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen    __ AllocateInNewSpace(
64325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        r0,
64425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        r5,
64525f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        r6,
64625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        r2,
64725f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        &undo_allocation,
64825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen        static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS));
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Initialize the FixedArray.
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: number of elements in properties array
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: FixedArray (not tagged)
6557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // r7: undefined value
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex);
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r2, r5);
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r6, MemOperand(r2, kPointerSize, PostIndex));
6607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
6617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ mov(r0, Operand(r3, LSL, kSmiTagSize));
6627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ str(r0, MemOperand(r2, kPointerSize, PostIndex));
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Initialize the fields to undefined.
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: First element of FixedArray (not tagged)
667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: number of elements in properties array
668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: FixedArray (not tagged)
670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r7: undefined
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2));  // End of object.
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    { Label loop, entry;
674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ b(&entry);
675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&loop);
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ str(r7, MemOperand(r2, kPointerSize, PostIndex));
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&entry);
6786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ cmp(r2, r6);
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ b(lt, &loop);
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Store the initialized FixedArray into the properties field of
683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the JSObject
684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r5: FixedArray (not tagged)
687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r5, r5, Operand(kHeapObjectTag));  // Add the heap tag.
688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset));
689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Continue with JSObject being successfully allocated
691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: constructor function
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(&allocated);
694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Undo the setting of the new top so that the heap is verifiable. For
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // example, the map's unused properties potentially do not match the
697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // allocated objects unused properties.
698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r4: JSObject (previous new top)
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&undo_allocation);
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ UndoAllocationInNewSpace(r4, r5);
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate the new receiver object using the runtime call.
704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor function
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&rt_call);
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);  // argument for Runtime_NewObject
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallRuntime(Runtime::kNewObject, 1);
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r4, r0);
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Receiver for constructor call allocated.
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r4: JSObject
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&allocated);
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r4);
714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the function and the allocated receiver from the stack.
716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver (newly allocated object)
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: number of arguments (smi-tagged)
719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(sp, kPointerSize));
720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);  // Constructor function.
721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r4);  // Receiver.
722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Reload the number of arguments from the stack.
724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor function
725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver
726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: receiver
728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[3]: constructor function
729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[4]: number of arguments (smi-tagged)
730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r3, MemOperand(sp, 4 * kPointerSize));
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup pointer to last argument.
733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup number of arguments for function call below
736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, Operand(r3, LSR, kSmiTagSize));
737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy arguments and receiver to the expression stack.
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: number of arguments
740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2: address of last argument (caller sp)
741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor function
742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r3: number of arguments (smi-tagged)
743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver
744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: receiver
746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[3]: constructor function
747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[4]: number of arguments (smi-tagged)
748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label loop, entry;
749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(&entry);
750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ip);
753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&entry);
754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sub(r3, r3, Operand(2), SetCC);
755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ge, &loop);
756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the function.
758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: number of arguments
759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: constructor function
760e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (is_api_function) {
761e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
762e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Handle<Code> code = Handle<Code>(
763e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Builtins::builtin(Builtins::HandleApiCallConstruct));
764e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    ParameterCount expected(0);
765e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ InvokeCode(code, expected, expected,
766e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                  RelocInfo::CODE_TARGET, CALL_FUNCTION);
767e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
768e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    ParameterCount actual(r0);
769e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ InvokeFunction(r1, actual, CALL_FUNCTION);
770e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop the function from the stack.
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: constructor function
774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: receiver
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[3]: constructor function
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[4]: number of arguments (smi-tagged)
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop();
778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore context from the frame.
780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: result
781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver
782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: number of arguments (smi-tagged)
784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the result is an object (in the ECMA sense), we should get rid
787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // on page 74.
789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label use_receiver, exit;
790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the result is a smi, it is *not* an object in the ECMA sense.
792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: result
793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver (newly allocated object)
794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: number of arguments (smi-tagged)
796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ tst(r0, Operand(kSmiTagMask));
797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &use_receiver);
798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the type of the result (stored in its map) is less than
800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareObjectType(r0, r3, r3, FIRST_JS_OBJECT_TYPE);
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ge, &exit);
803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Throw away the result of the constructor invocation and use the
805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // on-stack receiver as the result.
806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&use_receiver);
807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(sp));
808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove receiver from the stack, remove caller arguments, and
810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // return.
811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&exit);
812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: result
813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[0]: receiver (newly allocated object)
814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[1]: constructor function
815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp[2]: number of arguments (smi-tagged)
816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveConstructFrame();
818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(kPointerSize));
820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
825e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
826e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Generate_JSConstructStubHelper(masm, false);
827e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
828e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
829e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
830e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
831e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Generate_JSConstructStubHelper(masm, true);
832e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
833e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
834e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             bool is_construct) {
837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Called from Generate_JS_Entry
838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: code entry
839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: function
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2: receiver
841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r3: argc
842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r4: argv
843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r5-r7, cp may be clobbered
844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear the context before we push it when entering the JS frame.
846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(cp, Operand(0));
847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter an internal frame.
849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set up the context from the function argument.
852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set up the roots register.
855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference roots_address = ExternalReference::roots_address();
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r10, Operand(roots_address));
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the function and the receiver onto the stack.
859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r2);
861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy arguments to the stack in a loop.
863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: function
864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r3: argc
865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r4: argv, i.e. points to first arg
866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label loop, entry;
867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2));
868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2 points past last arg.
869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(&entry);
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex));  // read next parameter
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(r0));  // dereference handle
873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);  // push parameter
874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&entry);
8756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(r4, r2);
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, &loop);
877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Initialize all JavaScript callee-saved registers, since they will be seen
879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // by the garbage collector as part of handlers.
880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r5, Operand(r4));
882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r6, Operand(r4));
883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r7, Operand(r4));
884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (kR9Available == 1) {
885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r9, Operand(r4));
886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the code and pass argc as r0.
889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, Operand(r3));
890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_construct) {
891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            RelocInfo::CODE_TARGET);
893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ParameterCount actual(r0);
895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ InvokeFunction(r1, actual, CALL_FUNCTION);
896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Exit the JS frame and remove the parameters (except function), and return.
899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Respect ABI stack constraint.
900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: result
904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Generate_JSEntryTrampolineHelper(masm, false);
909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Generate_JSEntryTrampolineHelper(masm, true);
914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
917756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrickvoid Builtins::Generate_LazyCompile(MacroAssembler* masm) {
918756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Enter an internal frame.
919756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ EnterInternalFrame();
920756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
921756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Preserve the function.
922756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ push(r1);
923756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
924756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Push the function on the stack as the argument to the runtime function.
925756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ push(r1);
926756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ CallRuntime(Runtime::kLazyCompile, 1);
927756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Calculate the entry point.
928756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
929756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Restore saved function.
930756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ pop(r1);
931756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
932756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Tear down temporary frame.
933756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ LeaveInternalFrame();
934756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
935756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Do a tail-call of the compiled function.
936756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ Jump(r2);
937756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
938756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
939756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_FunctionCall(MacroAssembler* masm) {
941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 1. Make sure we have at least one argument.
942402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r0: actual number of arguments
943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  { Label done;
944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r0, Operand(r0));
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &done);
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(r2);
948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r0, r0, Operand(1));
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&done);
950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
952402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 2. Get the function to call (passed as receiver) from the stack, check
953402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //    if it is a function.
954402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r0: actual number of arguments
955402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label non_function;
956402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
957402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ tst(r1, Operand(kSmiTagMask));
958402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ b(eq, &non_function);
959402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
960402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ b(ne, &non_function);
961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
962402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 3a. Patch the first argument if necessary when calling a function.
963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: actual number of arguments
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: function
965402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label shift_arguments;
966402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  { Label convert_to_object, use_global_receiver, patch_receiver;
967402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Change context eagerly in case we need the global receiver.
968402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
969402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, MemOperand(r2, -kPointerSize));
972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r0: actual number of arguments
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: first argument
975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r2, Operand(kSmiTagMask));
976402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ b(eq, &convert_to_object);
977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(r3, Heap::kNullValueRootIndex);
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r2, r3);
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(eq, &use_global_receiver);
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r2, r3);
983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(eq, &use_global_receiver);
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE);
986402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ b(lt, &convert_to_object);
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
988402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ b(le, &shift_arguments);
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
990402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ bind(&convert_to_object);
991402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ EnterInternalFrame();  // In order to preserve argument count.
992402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(r0, Operand(r0, LSL, kSmiTagSize));  // Smi-tagged.
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(r0);
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(r2);
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r2, r0);
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ pop(r0);
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r0, Operand(r0, ASR, kSmiTagSize));
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LeaveInternalFrame();
1002402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Restore the function to r1.
1003402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
1004402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ jmp(&patch_receiver);
1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1006402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Use the global receiver object from the called function as the
1007402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // receiver.
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&use_global_receiver);
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const int kGlobalIndex =
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
1012d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset));
1013d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ ldr(r2, FieldMemOperand(r2, kGlobalIndex));
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&patch_receiver);
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(r2, MemOperand(r3, -kPointerSize));
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1020402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ jmp(&shift_arguments);
1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1023402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 3b. Patch the first argument when calling a non-function.  The
1024402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //     CALL_NON_FUNCTION builtin expects the non-function callee as
1025402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //     receiver, so overwrite the first argument which will ultimately
1026402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //     become the receiver.
1027402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r0: actual number of arguments
1028402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r1: function
1029402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&non_function);
1030402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1031402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ str(r1, MemOperand(r2, -kPointerSize));
1032402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Clear r1 to indicate a non-function being called.
1033402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r1, Operand(0));
1034402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1035402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 4. Shift arguments and return address one slot down on the stack
1036402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //    (overwriting the original receiver).  Adjust argument count to make
1037402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //    the original first argument the new receiver.
1038402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r0: actual number of arguments
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: function
1040402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&shift_arguments);
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  { Label loop;
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Calculate the copy start address (destination). Copy end address is sp.
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&loop);
1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(ip, MemOperand(r2, -kPointerSize));
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ str(ip, MemOperand(r2));
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r2, r2, Operand(kPointerSize));
1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r2, sp);
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &loop);
1051402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Adjust the actual number of arguments and remove the top element
1052402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // (which is a copy of the last argument).
1053402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ sub(r0, r0, Operand(1));
1054402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ pop();
1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1057402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: actual number of arguments
1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r1: function
1060402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  { Label function;
1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ tst(r1, r1);
1062402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ b(ne, &function);
1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(r2, Operand(0));  // expected arguments is 0 for CALL_NON_FUNCTION
1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         RelocInfo::CODE_TARGET);
1067402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ bind(&function);
1068402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1070402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // 5b. Get the code to call from the function and check that the number of
1071402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //     expected arguments matches what we're providing.  If so, jump
1072402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //     (tail-call) to the code in register edx without checking arguments.
1073402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r0: actual number of arguments
1074402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r1: function
1075402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1076402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ldr(r2,
1077402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu         FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
10787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(r2, Operand(r2, ASR, kSmiTagSize));
1079791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
1080402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(r2, r0);  // Check formal and actual parameter counts.
1081402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1082402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          RelocInfo::CODE_TARGET, ne);
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1084402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ParameterCount expected(0);
1085402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kIndexOffset    = -5 * kPointerSize;
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kLimitOffset    = -4 * kPointerSize;
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kArgsOffset     =  2 * kPointerSize;
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kRecvOffset     =  3 * kPointerSize;
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kFunctionOffset =  4 * kPointerSize;
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kArgsOffset));  // get the args array
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
1103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1104d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check the stack for overflow. We are not trying need to catch
1105d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // interruptions (e.g. debug break and preemption) here, so the "real stack
1106d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // limit" is checked.
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label okay;
1108d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
1109d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Make r2 the space we have left. The stack might already be overflowed
1110d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // here which will cause r2 to become negative.
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sub(r2, sp, r2);
1112d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check if the arguments will overflow the stack.
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1114d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ b(gt, &okay);  // Signed comparison.
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Out of stack space.
1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(fp, kFunctionOffset));
1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
1121d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // End of stack check.
1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push current limit and index.
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&okay);
1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);  // limit
1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r1, Operand(0));  // initial index
1127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);
1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Change context eagerly to get the right global object if necessary.
1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kFunctionOffset));
1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the receiver.
1134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label call_to_object, use_global_receiver, push_receiver;
1135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kRecvOffset));
1136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ tst(r0, Operand(kSmiTagMask));
1137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &call_to_object);
1138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(r1, Heap::kNullValueRootIndex);
1139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, r1);
1140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &use_global_receiver);
1141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
1142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, r1);
1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &use_global_receiver);
1144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the receiver is already a JavaScript object.
1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: receiver
1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(lt, &call_to_object);
1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(le, &push_receiver);
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the receiver to a regular object.
1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: receiver
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&call_to_object);
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(&push_receiver);
1158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use the current global receiver object as the receiver.
1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&use_global_receiver);
1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kGlobalOffset =
1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
1164d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset));
1165d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ ldr(r0, FieldMemOperand(r0, kGlobalOffset));
1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the receiver.
1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: receiver
1170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&push_receiver);
1171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy all arguments from the array to the stack.
1174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label entry, loop;
1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kIndexOffset));
1176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(&entry);
1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the current argument from the arguments array and push it to the
1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stack.
1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0: current argument index
1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(fp, kArgsOffset));
1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r1);
1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the runtime to access the property in the arguments array.
1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallRuntime(Runtime::kGetProperty, 2);
1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r0);
1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use inline caching to access the arguments.
1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r0, MemOperand(fp, kIndexOffset));
1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(r0, r0, Operand(1 << kSmiTagSize));
1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ str(r0, MemOperand(fp, kIndexOffset));
1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test if the copy loop has finished copying all the elements from the
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // arguments object.
1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&entry);
1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(fp, kLimitOffset));
1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, r1);
1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(ne, &loop);
1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(r0);
1204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, Operand(r0, ASR, kSmiTagSize));
1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(fp, kFunctionOffset));
1206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(r1, actual, CALL_FUNCTION);
1207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Tear down the internal frame and remove function, receiver and args.
1209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
1210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(3 * kPointerSize));
1211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
1212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit());
1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(fp, sp, Operand(3 * kPointerSize));
1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r0 : result being passed through
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the number of arguments passed (as a smi), tear down the frame and
1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // then tear down the parameters.
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldr(r1, MemOperand(fp, -3 * kPointerSize));
1230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(sp, fp);
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ldm(ia_w, sp, fp.bit() | lr.bit());
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(sp, sp, Operand(kPointerSize));  // adjust for receiver
1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r0 : actual number of arguments
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r1 : function (passed through to callee)
1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r2 : expected number of arguments
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- r3 : code entry to call
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label invoke, dont_adapt_arguments;
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label enough, too_few;
12486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(r0, r2);
1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(lt, &too_few);
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ b(eq, &dont_adapt_arguments);
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Enough parameters: actual >= expected
1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&enough);
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    EnterArgumentsAdaptorFrame(masm);
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Calculate copy start address into r0 and copy end address into r2.
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r0: actual number of arguments as a smi
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: expected number of arguments
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: code entry to call
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // adjust for return address and receiver
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r0, r0, Operand(2 * kPointerSize));
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Copy the arguments (including the receiver) to the new stack frame.
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r0: copy start address
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: copy end address
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: code entry to call
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label copy;
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&copy);
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(ip, MemOperand(r0, 0));
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(ip);
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r0, r2);  // Compare before moving to next argument.
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r0, r0, Operand(kPointerSize));
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &copy);
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(&invoke);
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Too few parameters: Actual < expected
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&too_few);
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    EnterArgumentsAdaptorFrame(masm);
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Calculate copy start address into r0 and copy end address is fp.
1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r0: actual number of arguments as a smi
1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: expected number of arguments
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: code entry to call
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Copy the arguments (including the receiver) to the new stack frame.
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r0: copy start address
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: expected number of arguments
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: code entry to call
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label copy;
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&copy);
1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Adjust load for return address and receiver.
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ldr(ip, MemOperand(r0, 2 * kPointerSize));
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(ip);
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(r0, fp);  // Compare before moving to next argument.
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r0, r0, Operand(kPointerSize));
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &copy);
1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Fill the remaining expected arguments with undefined.
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r1: function
1311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r2: expected number of arguments
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // r3: code entry to call
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ sub(r2, r2, Operand(4 * kPointerSize));  // Adjust for frame.
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label fill;
1318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&fill);
1319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(ip);
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(sp, r2);
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ b(ne, &fill);
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry point.
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
1326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Call(r3);
1327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Exit frame and return.
1329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LeaveArgumentsAdaptorFrame(masm);
1330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(lr);
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -------------------------------------------
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Dont adapt arguments.
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -------------------------------------------
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&dont_adapt_arguments);
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(r3);
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
1342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1344f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
1345f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_ARM
1346