1f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org// Copyright 2013 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
4f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
5196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/v8.h"
6f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
7fa0c3c69b9d632e5730bdd9c745c375beef5e54dmachenbach@chromium.org#if V8_TARGET_ARCH_ARM64
8f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
9196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/codegen.h"
10196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/debug.h"
11196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/deoptimizer.h"
12196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/full-codegen.h"
13196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/runtime.h"
14196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/stub-cache.h"
15f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
16f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgnamespace v8 {
17f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgnamespace internal {
18f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
19f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
20f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org#define __ ACCESS_MASM(masm)
21f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
22f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
23f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org// Load the built-in Array function from the current context.
24f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
25f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the native context.
26f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result, GlobalObjectMemOperand());
27f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result,
28f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org         FieldMemOperand(result, GlobalObject::kNativeContextOffset));
29f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the InternalArray function from the native context.
30f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result,
31f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org         MemOperand(result,
32f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                    Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
33f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
34f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
35f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
36f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org// Load the built-in InternalArray function from the current context.
37f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
38f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                              Register result) {
39f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the native context.
40f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result, GlobalObjectMemOperand());
41f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result,
42f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org         FieldMemOperand(result, GlobalObject::kNativeContextOffset));
43f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the InternalArray function from the native context.
44f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(result, ContextMemOperand(result,
45f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                   Context::INTERNAL_ARRAY_FUNCTION_INDEX));
46f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
47f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
48f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
49f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_Adaptor(MacroAssembler* masm,
50f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                CFunctionId id,
51f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                BuiltinExtraArguments extra_args) {
52f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
53f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0                 : number of arguments excluding receiver
54f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x1                 : called function (only guaranteed when
55f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //                          extra_args requires it)
56f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- cp                 : context
57f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[0]              : last argument
58f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- ...
59f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[4 * (argc - 1)] : first argument (argc == x0)
60f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[4 * argc]       : receiver
61f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
62f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
63f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Insert extra arguments.
64f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  int num_extra_args = 0;
65f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  if (extra_args == NEEDS_CALLED_FUNCTION) {
66f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    num_extra_args = 1;
67f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x1);
68f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  } else {
69f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
70f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
71f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
72f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // JumpToExternalReference expects x0 to contain the number of arguments
73f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // including the receiver and the extra arguments.
74f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(x0, x0, num_extra_args + 1);
75f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
76f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
77f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
78f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
79f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
80f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
81f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0     : number of arguments
82f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- lr     : return address
83f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[...]: constructor arguments
84f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
85f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_InternalArrayCode");
86f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label generic_array_code;
87f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
88f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Get the InternalArray function.
89f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateLoadInternalArrayFunction(masm, x1);
90f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
91f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  if (FLAG_debug_code) {
92f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Initial map for the builtin InternalArray functions should be maps.
93f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
94f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Tst(x10, kSmiTagMask);
95f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
96f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CompareObjectType(x10, x11, x12, MAP_TYPE);
97f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
98f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
99f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
100f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Run the native code for the InternalArray function called as a normal
101f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // function.
102f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  InternalArrayConstructorStub stub(masm->isolate());
103f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ TailCallStub(&stub);
104f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
105f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
106f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
107f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_ArrayCode(MacroAssembler* masm) {
108f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
109f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0     : number of arguments
110f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- lr     : return address
111f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[...]: constructor arguments
112f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
113f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_ArrayCode");
114f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
115f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
116f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Get the Array function.
117f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateLoadArrayFunction(masm, x1);
118f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
119f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  if (FLAG_debug_code) {
120f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Initial map for the builtin Array functions should be maps.
121f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
122f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Tst(x10, kSmiTagMask);
123f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
124f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CompareObjectType(x10, x11, x12, MAP_TYPE);
125f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
126f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
127f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
128f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Run the native code for the Array function called as a normal function.
1295697144afb43181fed170b81c194fe1cc0fce3b6machenbach@chromium.org  __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
130f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ArrayConstructorStub stub(masm->isolate());
131f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ TailCallStub(&stub);
132f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
133f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
134f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
135f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
136f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
137f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0                     : number of arguments
138f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x1                     : constructor function
139f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- lr                     : return address
140f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
141f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[argc * 8]           : receiver
142f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
143f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_StringConstructCode");
144f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Counters* counters = masm->isolate()->counters();
145f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(counters->string_ctor_calls(), 1, x10, x11);
146f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
147f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register argc = x0;
148f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register function = x1;
149f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  if (FLAG_debug_code) {
150f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, x10);
151f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(function, x10);
152f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(eq, kUnexpectedStringFunction);
153f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
154f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
155f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the first arguments in x0 and get rid of the rest.
156f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label no_arguments;
157f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Cbz(argc, &no_arguments);
158f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // First args = sp[(argc - 1) * 8].
159f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Sub(argc, argc, 1);
16097b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org  __ Claim(argc, kXRegSize);
161f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // jssp now point to args[0], load and drop args[0] + receiver.
162ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  Register arg = argc;
163ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
164ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  argc = NoReg;
165f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
166f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register argument = x2;
167f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label not_cached, argument_is_string;
168ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ LookupNumberStringCache(arg,        // Input.
169f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             argument,   // Result.
170f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             x10,        // Scratch.
171f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             x11,        // Scratch.
172f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             x12,        // Scratch.
173f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             &not_cached);
174f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(counters->string_ctor_cached_number(), 1, x10, x11);
175f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&argument_is_string);
176f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
177f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
178f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x2     : argument converted to string
179f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x1     : constructor function
180f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- lr     : return address
181f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
182f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
183f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label gc_required;
184f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register new_obj = x0;
185f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Allocate(JSValue::kSize, new_obj, x10, x11, &gc_required, TAG_OBJECT);
186f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
187f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Initialize the String object.
188f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register map = x3;
189f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ LoadGlobalFunctionInitialMap(function, map, x10);
190f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  if (FLAG_debug_code) {
191f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldrb(x4, FieldMemOperand(map, Map::kInstanceSizeOffset));
192f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(x4, JSValue::kSize >> kPointerSizeLog2);
193f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(eq, kUnexpectedStringWrapperInstanceSize);
194f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldrb(x4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
195f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(x4, 0);
196f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
197f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
198f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Str(map, FieldMemOperand(new_obj, HeapObject::kMapOffset));
199f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
200f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register empty = x3;
201f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
202f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Str(empty, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
203f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Str(empty, FieldMemOperand(new_obj, JSObject::kElementsOffset));
204f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
205f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Str(argument, FieldMemOperand(new_obj, JSValue::kValueOffset));
206f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
207f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Ensure the object is fully initialized.
208f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  STATIC_ASSERT(JSValue::kSize == (4 * kPointerSize));
209f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
210f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
211f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
212f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // The argument was not found in the number to string cache. Check
213f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // if it's a string already before calling the conversion builtin.
214f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label convert_argument;
215f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&not_cached);
216ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ JumpIfSmi(arg, &convert_argument);
217f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
218f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Is it a String?
219f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
220f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldrb(x11, FieldMemOperand(x10, Map::kInstanceTypeOffset));
221f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Tbnz(x11, MaskToBit(kIsNotStringMask), &convert_argument);
222ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Mov(argument, arg);
223f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(counters->string_ctor_string_value(), 1, x10, x11);
224f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(&argument_is_string);
225f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
226f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Invoke the conversion builtin and put the result into x2.
227f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&convert_argument);
228f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Push(function);  // Preserve the function.
229f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(counters->string_ctor_conversions(), 1, x10, x11);
230f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
231f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
232ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Push(arg);
233f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
234f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
235f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Pop(function);
236f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(argument, x0);
237f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(&argument_is_string);
238f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
239f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the empty string into x2, remove the receiver from the
240f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // stack, and jump back to the case where the argument is a string.
241f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&no_arguments);
242f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ LoadRoot(argument, Heap::kempty_stringRootIndex);
243f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(1);
244f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(&argument_is_string);
245f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
246f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // At this point the argument is already a string. Call runtime to create a
247f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // string wrapper.
248f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&gc_required);
249f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(counters->string_ctor_gc_required(), 1, x10, x11);
250f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
251f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
252f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(argument);
253f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CallRuntime(Runtime::kNewStringWrapper, 1);
254f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
255f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
256f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
257f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
258f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
259f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void CallRuntimePassFunction(MacroAssembler* masm,
260f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                    Runtime::FunctionId function_id) {
261f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  FrameScope scope(masm, StackFrame::INTERNAL);
262f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   - Push a copy of the function onto the stack.
263f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   - Push another copy as a parameter to the runtime call.
264f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Push(x1, x1);
265f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
266f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ CallRuntime(function_id, 1);
267f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
268f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   - Restore receiver.
269f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Pop(x1);
270f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
271f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
272f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
273f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void GenerateTailCallToSharedCode(MacroAssembler* masm) {
274f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
275f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x2, FieldMemOperand(x2, SharedFunctionInfo::kCodeOffset));
276f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
277f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Br(x2);
278f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
279f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
280f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
281f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
282f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(x0, x0, Code::kHeaderSize - kHeapObjectTag);
283f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Br(x0);
284f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
285f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
286f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
287f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
288f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Checking whether the queued function is ready for install is optional,
289f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // since we come across interrupts and stack checks elsewhere. However, not
290f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // checking may delay installing ready functions, and always checking would be
291f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // quite expensive. A good compromise is to first check against stack limit as
292f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // a cue for an interrupt signal.
293f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label ok;
294f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
295f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(hs, &ok);
296f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
297895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org  CallRuntimePassFunction(masm, Runtime::kHiddenTryInstallOptimizedCode);
298f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateTailCallToReturnedCode(masm);
299f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
300f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&ok);
301f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateTailCallToSharedCode(masm);
302f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
303f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
304f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
305f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void Generate_JSConstructStubHelper(MacroAssembler* masm,
306f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                           bool is_api_function,
30769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org                                           bool create_memento) {
308f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
309f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0     : number of arguments
310f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x1     : constructor function
31169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org  //  -- x2     : allocation site or undefined
312f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- lr     : return address
313f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- sp[...]: constructor arguments
314f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
315f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
316f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
31769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org  // Should never create mementos for api functions.
31869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org  ASSERT(!is_api_function || !create_memento);
319f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
320f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Isolate* isolate = masm->isolate();
321f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
322f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Enter a construct frame.
323f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
324f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::CONSTRUCT);
325f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
32669f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    // Preserve the three incoming parameters on the stack.
32769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    if (create_memento) {
32869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ AssertUndefinedOrAllocationSite(x2, x10);
32969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Push(x2);
33069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    }
33169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org
332f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register argc = x0;
333f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register constructor = x1;
334f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x1: constructor function
335f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ SmiTag(argc);
336f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(argc, constructor);
337f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // sp[0] : Constructor function.
338f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // sp[1]: number of arguments (smi-tagged)
339f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
340f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Try to allocate the object without transitioning into C code. If any of
341f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // the preconditions is not met, the code bails out to the runtime call.
342f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label rt_call, allocated;
343f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    if (FLAG_inline_new) {
344f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Label undo_allocation;
345f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      ExternalReference debug_step_in_fp =
346f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org          ExternalReference::debug_step_in_fp_address(isolate);
347f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Mov(x2, Operand(debug_step_in_fp));
348f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ldr(x2, MemOperand(x2));
349f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Cbnz(x2, &rt_call);
350f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Load the initial map and verify that it is in fact a map.
351f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register init_map = x2;
352f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ldr(init_map,
353f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org             FieldMemOperand(constructor,
354f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                             JSFunction::kPrototypeOrInitialMapOffset));
355f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ JumpIfSmi(init_map, &rt_call);
356f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
357f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
358f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Check that the constructor is not constructing a JSFunction (see
359f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // comments in Runtime_NewObject in runtime.cc). In which case the initial
360f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // map's instance type would be JS_FUNCTION_TYPE.
361f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
362f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ B(eq, &rt_call);
363f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
364011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      Register constructon_count = x14;
365011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      if (!is_api_function) {
366f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        Label allocate;
367011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        MemOperand bit_field3 =
368011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org            FieldMemOperand(init_map, Map::kBitField3Offset);
369011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        // Check if slack tracking is enabled.
370011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Ldr(x4, bit_field3);
371011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ DecodeField<Map::ConstructionCount>(constructon_count, x4);
372011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
373011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ B(eq, &allocate);
374f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        // Decrease generous allocation count.
375011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Subs(x4, x4, Operand(1 << Map::ConstructionCount::kShift));
376011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Str(x4, bit_field3);
377011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Cmp(constructon_count, Operand(JSFunction::kFinishSlackTracking));
378f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        __ B(ne, &allocate);
379f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
380f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        // Push the constructor and map to the stack, and the constructor again
381f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        // as argument to the runtime call.
382f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        __ Push(constructor, init_map, constructor);
383895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org        __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1);
384f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        __ Pop(init_map, constructor);
385011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Mov(constructon_count, Operand(JSFunction::kNoSlackTracking));
386f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        __ Bind(&allocate);
387f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      }
388f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
389f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Now allocate the JSObject on the heap.
390f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register obj_size = x3;
391f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register new_obj = x4;
392f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
39369f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      if (create_memento) {
39469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Add(x7, obj_size,
39569f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org               Operand(AllocationMemento::kSize / kPointerSize));
39669f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Allocate(x7, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
39769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      } else {
39869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Allocate(obj_size, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
39969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      }
400f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
401f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Allocated the JSObject, now initialize the fields. Map is set to
402f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // initial map and properties and elements are set to empty fixed array.
403f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // NB. the object pointer is not tagged, so MemOperand is used.
404f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register empty = x5;
405f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
406f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
407381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      STATIC_ASSERT(JSObject::kElementsOffset ==
408381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org          (JSObject::kPropertiesOffset + kPointerSize));
409381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
410f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
411f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register first_prop = x5;
412f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Add(first_prop, new_obj, JSObject::kHeaderSize);
413f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
414f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Fill all of the in-object properties with the appropriate filler.
415011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      Register filler = x7;
416011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      __ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
417f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
418f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Obtain number of pre-allocated property fields and in-object
419f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // properties.
420f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register prealloc_fields = x10;
421f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register inobject_props = x11;
422f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register inst_sizes = x11;
423f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ldr(inst_sizes, FieldMemOperand(init_map, Map::kInstanceSizesOffset));
424f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ubfx(prealloc_fields, inst_sizes,
425f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org              Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
426f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org              kBitsPerByte);
427f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ubfx(inobject_props, inst_sizes,
428f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org              Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte);
429f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
430381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      // Calculate number of property fields in the object.
431381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      Register prop_fields = x6;
432381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
433381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org
434011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      if (!is_api_function) {
435011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        Label no_inobject_slack_tracking;
436011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org
437011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        // Check if slack tracking is enabled.
438011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
439011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ B(eq, &no_inobject_slack_tracking);
440011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        constructon_count = NoReg;
441011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org
442381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org        // Fill the pre-allocated fields with undef.
443011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ FillFields(first_prop, prealloc_fields, filler);
444381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org
445011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        // Update first_prop register to be the offset of the first field after
446f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        // pre-allocated fields.
447011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Add(first_prop, first_prop,
448f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org               Operand(prealloc_fields, LSL, kPointerSizeLog2));
449f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
450f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        if (FLAG_debug_code) {
451011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org          Register obj_end = x14;
452381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org          __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
453011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org          __ Cmp(first_prop, obj_end);
454f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org          __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
455f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        }
456381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org
457381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org        // Fill the remaining fields with one pointer filler map.
458011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
459011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ Sub(prop_fields, prop_fields, prealloc_fields);
460011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org
461011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ bind(&no_inobject_slack_tracking);
462011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      }
463011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      if (create_memento) {
46469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        // Fill the pre-allocated fields with undef.
465011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ FillFields(first_prop, prop_fields, filler);
46669f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
46769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex);
46869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        ASSERT_EQ(0 * kPointerSize, AllocationMemento::kMapOffset);
46969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
47069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        // Load the AllocationSite
47169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Peek(x14, 2 * kXRegSize);
47269f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        ASSERT_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset);
47369f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
47469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org        first_prop = NoReg;
475f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      } else {
476381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org        // Fill all of the property fields with undef.
477011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org        __ FillFields(first_prop, prop_fields, filler);
478381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org        first_prop = NoReg;
479381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org        prop_fields = NoReg;
480f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      }
481f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
482f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Add the object tag to make the JSObject real, so that we can continue
483f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // and jump into the continuation code at any time from now on. Any
484f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // failures need to undo the allocation, so that the heap is in a
485f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // consistent state and verifiable.
486f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Add(new_obj, new_obj, kHeapObjectTag);
487f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
488f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Check if a non-empty properties array is needed. Continue with
489f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // allocated object if not, or fall through to runtime call if it is.
490f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register element_count = x3;
491381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      __ Ldrb(element_count,
492381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org              FieldMemOperand(init_map, Map::kUnusedPropertyFieldsOffset));
493f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // The field instance sizes contains both pre-allocated property fields
494f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // and in-object properties.
495381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      __ Add(element_count, element_count, prealloc_fields);
496381adef828187e237e8758ab730dee1c2834a0b3machenbach@chromium.org      __ Subs(element_count, element_count, inobject_props);
497f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
498f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Done if no extra properties are to be allocated.
499f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ B(eq, &allocated);
500f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Assert(pl, kPropertyAllocationCountFailed);
501f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
502f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Scale the number of elements by pointer size and add the header for
503f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // FixedArrays to the start of the next object calculation from above.
504f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register new_array = x5;
505f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register array_size = x6;
506f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Add(array_size, element_count, FixedArray::kHeaderSize / kPointerSize);
507f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Allocate(array_size, new_array, x11, x12, &undo_allocation,
508f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                  static_cast<AllocationFlags>(RESULT_CONTAINS_TOP |
509f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                               SIZE_IN_WORDS));
510f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
511f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register array_map = x10;
512f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ LoadRoot(array_map, Heap::kFixedArrayMapRootIndex);
513f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Str(array_map, MemOperand(new_array, FixedArray::kMapOffset));
514f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ SmiTag(x0, element_count);
515f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Str(x0, MemOperand(new_array, FixedArray::kLengthOffset));
516f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
517f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Initialize the fields to undefined.
518f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Register elements = x10;
519f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Add(elements, new_array, FixedArray::kHeaderSize);
520011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org      __ FillFields(elements, element_count, filler);
521f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
522f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Store the initialized FixedArray into the properties field of the
523f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // JSObject.
524f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Add(new_array, new_array, kHeapObjectTag);
525f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Str(new_array, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
526f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
527f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Continue with JSObject being successfully allocated.
528f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ B(&allocated);
529f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
530f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Undo the setting of the new top so that the heap is verifiable. For
531f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // example, the map's unused properties potentially do not match the
532f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // allocated objects unused properties.
533f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Bind(&undo_allocation);
534f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ UndoAllocationInNewSpace(new_obj, x14);
535f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
536f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
537f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Allocate the new receiver object using the runtime call.
538f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&rt_call);
53969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    Label count_incremented;
54069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    if (create_memento) {
54169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // Get the cell or allocation site.
54269f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Peek(x4, 2 * kXRegSize);
54369f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Push(x4);
54469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Push(constructor);  // Argument for Runtime_NewObject.
545895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org      __ CallRuntime(Runtime::kHiddenNewObjectWithAllocationSite, 2);
54669f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Mov(x4, x0);
54769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // If we ended up using the runtime, and we want a memento, then the
54869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // runtime call made it for us, and we shouldn't do create count
54969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // increment.
55069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ jmp(&count_incremented);
55169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    } else {
55269f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Push(constructor);  // Argument for Runtime_NewObject.
553895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org      __ CallRuntime(Runtime::kHiddenNewObject, 1);
55469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Mov(x4, x0);
55569f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    }
556f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
557f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Receiver for constructor call allocated.
558f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x4: JSObject
559f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&allocated);
56069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org
56169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    if (create_memento) {
56269f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Peek(x10, 2 * kXRegSize);
56369f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
56469f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // r2 is an AllocationSite. We are creating a memento from it, so we
56569f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      // need to increment the memento create count.
56669f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Ldr(x5, FieldMemOperand(x10,
56769f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org                                 AllocationSite::kPretenureCreateCountOffset));
56869f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Add(x5, x5, Operand(Smi::FromInt(1)));
56969f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ Str(x5, FieldMemOperand(x10,
57069f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org                                 AllocationSite::kPretenureCreateCountOffset));
57169f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org      __ bind(&count_incremented);
57269f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org    }
57369f64b1a8bfa6f5418b7c1f71d4e0833f76e93edmachenbach@chromium.org
574f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x4, x4);
575f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
576f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Reload the number of arguments from the stack.
577f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Set it up in x0 for the function call below.
578f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[0]: receiver
579f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[1]: receiver
580f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[2]: constructor function
581f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[3]: number of arguments (smi-tagged)
58297b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Peek(constructor, 2 * kXRegSize);  // Load constructor.
58397b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Peek(argc, 3 * kXRegSize);  // Load number of arguments.
584f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ SmiUntag(argc);
585f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
586f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Set up pointer to last argument.
587f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
588f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
589f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy arguments and receiver to the expression stack.
590f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy 2 values every loop to use ldp/stp.
591f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0: number of arguments
592f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x1: constructor function
593f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x2: address of last argument (caller sp)
594f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[0]: receiver
595f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[1]: receiver
596f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[2]: constructor function
597f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[3]: number of arguments (smi-tagged)
598f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Compute the start address of the copy in x3.
599f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
600f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label loop, entry, done_copying_arguments;
601f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&entry);
602f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&loop);
603f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
604f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x11, x10);
605f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&entry);
606f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(x3, x2);
607f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(gt, &loop);
608f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Because we copied values 2 by 2 we may have copied one extra value.
609f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Drop it if that is the case.
610f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(eq, &done_copying_arguments);
611f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Drop(1);
612f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&done_copying_arguments);
613f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
614f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Call the function.
615f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0: number of arguments
616f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x1: constructor function
617f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    if (is_api_function) {
618f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
619f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      Handle<Code> code =
620f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org          masm->isolate()->builtins()->HandleApiCallConstruct();
621f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Call(code, RelocInfo::CODE_TARGET);
622f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    } else {
623f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      ParameterCount actual(argc);
624f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
625f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
626f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
627f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Store offset of return address for deoptimizer.
628011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org    if (!is_api_function) {
629f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
630f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
631f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
632f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Restore the context from the frame.
633f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0: result
634f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[0]: receiver
635f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[1]: constructor function
636f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[2]: number of arguments (smi-tagged)
637f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
638f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
639f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // If the result is an object (in the ECMA sense), we should get rid
640f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // of the receiver and use the result; see ECMA-262 section 13.2.2-7
641f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // on page 74.
642f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label use_receiver, exit;
643f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
644f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // If the result is a smi, it is *not* an object in the ECMA sense.
645f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0: result
646f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[0]: receiver (newly allocated object)
647f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[1]: constructor function
648f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[2]: number of arguments (smi-tagged)
649f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfSmi(x0, &use_receiver);
650f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
651f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // If the type of the result (stored in its map) is less than
652f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
653f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
654f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
655f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Throw away the result of the constructor invocation and use the
656f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // on-stack receiver as the result.
657f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&use_receiver);
658f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Peek(x0, 0);
659f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
660f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Remove the receiver from the stack, remove caller arguments, and
661f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // return.
662f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&exit);
663f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0: result
664f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[0]: receiver (newly allocated object)
665f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[1]: constructor function
666f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // jssp[2]: number of arguments (smi-tagged)
66797b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Peek(x1, 2 * kXRegSize);
668f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
669f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Leave construct frame.
670f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
671f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
672f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ DropBySMI(x1);
673f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(1);
674f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
675f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
676f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
677f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
678f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
679f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
680011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org  Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
681f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
682f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
683f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
684f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
685011a81ffd5df0e081e7c00ef430b2fec5079bf2amachenbach@chromium.org  Generate_JSConstructStubHelper(masm, true, false);
686f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
687f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
688f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
689f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org// Input:
690f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x0: code entry.
691f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x1: function.
692f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x2: receiver.
693f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x3: argc.
694f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x4: argv.
695f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org// Output:
696f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org//   x0: result.
697f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
698f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                             bool is_construct) {
699f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Called from JSEntryStub::GenerateBody().
700f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register function = x1;
701f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register receiver = x2;
702f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register argc = x3;
703f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register argv = x4;
704f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
705f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ProfileEntryHookStub::MaybeCallEntryHook(masm);
706f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
707f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Clear the context before we push it when entering the internal frame.
708f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(cp, 0);
709f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
710f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
711f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Enter an internal frame.
712f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
713f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
714f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Set up the context from the function argument.
715f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
716f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
717f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ InitializeRootRegister();
718f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
719f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Push the function and the receiver onto the stack.
720f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(function, receiver);
721f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
722f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy arguments to the stack in a loop, in reverse order.
723f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x3: argc.
724f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x4: argv.
725f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label loop, entry;
726f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Compute the copy end address.
727f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
728f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
729f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&entry);
730f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&loop);
731f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
732f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x12, MemOperand(x11));  // Dereference the handle.
733f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x12);  // Push the argument.
734f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&entry);
735f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(x10, argv);
736f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(ne, &loop);
737f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
738f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Initialize all JavaScript callee-saved registers, since they will be seen
739f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // by the garbage collector as part of handlers.
740f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // The original values have been saved in JSEntryStub::GenerateBody().
741f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
742f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x20, x19);
743f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x21, x19);
744f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x22, x19);
745f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x23, x19);
746f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x24, x19);
747f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x25, x19);
748f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Don't initialize the reserved registers.
749f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x26 : root register (root).
750f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x27 : context pointer (cp).
751f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x28 : JS stack pointer (jssp).
752f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x29 : frame pointer (fp).
753f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
754f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x0, argc);
755f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    if (is_construct) {
756f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // No type feedback cell is available.
7575697144afb43181fed170b81c194fe1cc0fce3b6machenbach@chromium.org      __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
758f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
759a86d416fb652b1936026eee315eccd4f17ca1002machenbach@chromium.org      CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
760f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ CallStub(&stub);
761f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    } else {
762f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      ParameterCount actual(x0);
763f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
764f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
765f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Exit the JS internal frame and remove the parameters (except function),
766f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // and return.
767f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
768f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
769f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Result is in x0. Return.
770f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
771f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
772f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
773f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
774f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
775f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_JSEntryTrampolineHelper(masm, false);
776f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
777f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
778f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
779f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
780f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_JSEntryTrampolineHelper(masm, true);
781f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
782f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
783f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
784f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
785895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org  CallRuntimePassFunction(masm, Runtime::kHiddenCompileUnoptimized);
786f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateTailCallToReturnedCode(masm);
787f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
788f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
789f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
790f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
791f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  FrameScope scope(masm, StackFrame::INTERNAL);
792f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register function = x1;
793f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
794f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Preserve function. At the same time, push arguments for
795895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org  // kHiddenCompileOptimized.
796f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
797f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Push(function, function, x10);
798f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
799895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org  __ CallRuntime(Runtime::kHiddenCompileOptimized, 2);
800f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
801f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Restore receiver.
802f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Pop(function);
803f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
804f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
805f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
806f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
807f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  CallCompileOptimized(masm, false);
808f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateTailCallToReturnedCode(masm);
809f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
810f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
811f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
812f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
813f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  CallCompileOptimized(masm, true);
814f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateTailCallToReturnedCode(masm);
815f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
816f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
817f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
818f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
819f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // For now, we are relying on the fact that make_code_young doesn't do any
820f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // garbage collection which allows us to save/restore the registers without
821f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // worrying about which of them contain pointers. We also don't build an
822f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // internal frame to make the code fast, since we shouldn't have to do stack
823f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // crawls in MakeCodeYoung. This seems a bit fragile.
824f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
825f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // The following caller-saved registers must be saved and restored when
826f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // calling through to the runtime:
827f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   x0 - The address from which to resume execution.
828f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   x1 - isolate
829f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   lr - The return address for the JSFunction itself. It has not yet been
830f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //        preserved on the stack because the frame setup code was replaced
831f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //        with a call to this stub, to handle code ageing.
832f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
833f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::MANUAL);
834f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x0, x1, fp, lr);
8357010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org    __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
836f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CallCFunction(
837f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        ExternalReference::get_make_code_young_function(masm->isolate()), 2);
838f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Pop(lr, fp, x1, x0);
839f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
840f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
841f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // The calling function has been made young again, so return to execute the
842f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // real frame set-up code.
843f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Br(x0);
844f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
845f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
846f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                 \
847f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_Make##C##CodeYoungAgainEvenMarking(  \
848f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    MacroAssembler* masm) {                                  \
849f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateMakeCodeYoungAgainCommon(masm);                    \
850f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}                                                            \
851f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_Make##C##CodeYoungAgainOddMarking(   \
852f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    MacroAssembler* masm) {                                  \
853f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateMakeCodeYoungAgainCommon(masm);                    \
854f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
855f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgCODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
856f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
857f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
858f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
859f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
860f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
861f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // that make_code_young doesn't do any garbage collection which allows us to
862f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // save/restore the registers without worrying about which of them contain
863f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // pointers.
864f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
865f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // The following caller-saved registers must be saved and restored when
866f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // calling through to the runtime:
867f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   x0 - The address from which to resume execution.
868f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   x1 - isolate
869f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //   lr - The return address for the JSFunction itself. It has not yet been
870f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //        preserved on the stack because the frame setup code was replaced
871f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //        with a call to this stub, to handle code ageing.
872f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
873f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::MANUAL);
874f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x0, x1, fp, lr);
8757010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org    __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
876f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CallCFunction(
877f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        ExternalReference::get_mark_code_as_executed_function(
878f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org            masm->isolate()), 2);
879f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Pop(lr, fp, x1, x0);
880f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
881f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Perform prologue operations usually performed by the young code stub.
882f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ EmitFrameSetupForCodeAgePatching(masm);
883f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
884f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
885f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Jump to point after the code-age stub.
8865924917d324a643d00a8aefee030bd4acea0de0bmachenbach@chromium.org  __ Add(x0, x0, kNoCodeAgeSequenceLength);
887f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Br(x0);
888f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
889f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
890f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
891f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
892f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  GenerateMakeCodeYoungAgainCommon(masm);
893f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
894f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
895f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
896f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
897f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                             SaveFPRegsMode save_doubles) {
898f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
899f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
900f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
901f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Preserve registers across notification, this is important for compiled
902f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // stubs that tail call the runtime on deopts passing their parameters in
903f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // registers.
904f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // TODO(jbramley): Is it correct (and appropriate) to use safepoint
905f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // registers here? According to the comment above, we should only need to
906f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // preserve the registers with parameters.
907f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ PushXRegList(kSafepointSavedRegisters);
908f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Pass the function and deoptimization type to the runtime system.
909895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org    __ CallRuntime(Runtime::kHiddenNotifyStubFailure, 0, save_doubles);
910f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ PopXRegList(kSafepointSavedRegisters);
911f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
912f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
913f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
914f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(1);
915f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
916f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
917f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // into lr before it jumps here.
918f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Br(lr);
919f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
920f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
921f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
922f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
923f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
924f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
925f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
926f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
927f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
928f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
929f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
930f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
931f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
932f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
933f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                                             Deoptimizer::BailoutType type) {
934f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
935f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
936f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Pass the deoptimization type to the runtime system.
9377010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org    __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
938f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x0);
939895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org    __ CallRuntime(Runtime::kHiddenNotifyDeoptimized, 1);
940f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
941f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
942f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Get the full codegen state from the stack and untag it.
943f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register state = x6;
944f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Peek(state, 0);
945f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ SmiUntag(state);
946f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
947f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Switch on the state.
948f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label with_tos_register, unknown_state;
949f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ CompareAndBranch(
950f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
951f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(1);  // Remove state.
952f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
953f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
954f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&with_tos_register);
955f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Reload TOS register.
956f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Peek(x0, kPointerSize);
957f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
958f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(2);  // Remove state and TOS.
959f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
960f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
961f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&unknown_state);
962f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Abort(kInvalidFullCodegenState);
963f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
964f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
965f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
966f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
967f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
968f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
969f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
970f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
971f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
972f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
973f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
974f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
975f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
976f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
977f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
978f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
979f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
980f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
981f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
982f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Lookup the function in the JavaScript frame.
983f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
984f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
985f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
986f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Pass function as argument.
987f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x0);
988f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
989f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
990f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
991f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // If the code object is null, just return to the unoptimized code.
992f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label skip;
9937010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org  __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
994f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
995f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
996f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&skip);
997f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
998f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load deoptimization data from the code object.
999f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // <deopt_data> = <code>[#deoptimization_data_offset]
1000f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1001f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1002f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Load the OSR entrypoint offset from the deoptimization data.
1003f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1004f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1005f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      DeoptimizationInputData::kOsrPcOffsetIndex)));
1006f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1007f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Compute the target address = code_obj + header_size + osr_offset
1008f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1009f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(x0, x0, x1);
1010f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1011f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1012f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // And "return" to the OSR entry point of the function.
1013f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
1014f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1015f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1016f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1017f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1018f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // We check the stack limit as indicator that recompilation might be done.
1019f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label ok;
1020f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
1021f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(hs, &ok);
1022f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
1023f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope scope(masm, StackFrame::INTERNAL);
1024895f00d1d8c5a7a7209c36d690688e3552de3df4machenbach@chromium.org    __ CallRuntime(Runtime::kHiddenStackGuard, 0);
1025f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1026f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1027f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org          RelocInfo::CODE_TARGET);
1028f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1029f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&ok);
1030f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
1031f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1032f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1033f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1034f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1035f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  enum {
1036f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    call_type_JS_func = 0,
1037f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    call_type_func_proxy = 1,
1038f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    call_type_non_func = 2
1039f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  };
1040f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register argc = x0;
1041f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register function = x1;
1042f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register call_type = x4;
1043f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register scratch1 = x10;
1044f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register scratch2 = x11;
1045f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Register receiver_type = x13;
1046f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1047f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_FunctionCall");
1048f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 1. Make sure we have at least one argument.
1049f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  { Label done;
1050f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cbnz(argc, &done);
1051f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1052f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(scratch1);
1053f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(argc, 1);
1054f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&done);
1055f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1056f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1057f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 2. Get the function to call (passed as receiver) from the stack, check
1058f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //    if it is a function.
1059f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label slow, non_function;
106097b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org  __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1061f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ JumpIfSmi(function, &non_function);
1062f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ JumpIfNotObjectType(function, scratch1, receiver_type,
1063f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                         JS_FUNCTION_TYPE, &slow);
1064f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1065f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 3a. Patch the first argument if necessary when calling a function.
1066f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label shift_arguments;
1067f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(call_type, static_cast<int>(call_type_JS_func));
1068f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  { Label convert_to_object, use_global_receiver, patch_receiver;
1069f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Change context eagerly in case we need the global receiver.
1070f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1071f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1072f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Do not transform the receiver for strict mode functions.
1073f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Also do not transform the receiver for native (Compilerhints already in
1074f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x3).
1075f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(scratch1,
1076f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org           FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1077f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(scratch2.W(),
1078f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org           FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1079f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ TestAndBranchIfAnySet(
1080f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        scratch2.W(),
1081f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        (1 << SharedFunctionInfo::kStrictModeFunction) |
1082f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        (1 << SharedFunctionInfo::kNative),
1083f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org        &shift_arguments);
1084f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1085486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org    // Compute the receiver in sloppy mode.
1086f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register receiver = x2;
1087f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Sub(scratch1, argc, 1);
108897b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1089f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfSmi(receiver, &convert_to_object);
1090f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1091f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1092f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                  &use_global_receiver);
1093f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_receiver);
1094f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1095f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1096f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfObjectType(receiver, scratch1, scratch2,
1097f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                        FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
1098f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1099f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&convert_to_object);
1100f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1101f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    {
1102f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Enter an internal frame in order to preserve argument count.
1103f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      FrameScope scope(masm, StackFrame::INTERNAL);
1104f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ SmiTag(argc);
1105f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1106f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Push(argc, receiver);
1107f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1108f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Mov(receiver, x0);
1109f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1110f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Pop(argc);
1111f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ SmiUntag(argc);
1112f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1113f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      // Exit the internal frame.
1114f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
1115f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1116f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Restore the function and flag in the registers.
111797b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1118f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(call_type, static_cast<int>(call_type_JS_func));
1119f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&patch_receiver);
1120f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1121f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&use_global_receiver);
1122f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(receiver, GlobalObjectMemOperand());
1123f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(receiver,
1124f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org           FieldMemOperand(receiver, GlobalObject::kGlobalReceiverOffset));
1125f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1126f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1127f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&patch_receiver);
1128f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Sub(scratch1, argc, 1);
112997b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org    __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1130f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1131f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&shift_arguments);
1132f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1133f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1134f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 3b. Check for function proxy.
1135f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&slow);
1136f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(call_type, static_cast<int>(call_type_func_proxy));
1137f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
1138f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(eq, &shift_arguments);
1139f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&non_function);
1140f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(call_type, static_cast<int>(call_type_non_func));
1141f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1142f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 3c. Patch the first argument when calling a non-function.  The
1143f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     CALL_NON_FUNCTION builtin expects the non-function callee as
1144f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     receiver, so overwrite the first argument which will ultimately
1145f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     become the receiver.
1146f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // call type (0: JS function, 1: function proxy, 2: non-function)
1147f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Sub(scratch1, argc, 1);
114897b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org  __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
1149f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1150f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 4. Shift arguments and return address one slot down on the stack
1151f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //    (overwriting the original receiver).  Adjust argument count to make
1152f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //    the original first argument the new receiver.
1153f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // call type (0: JS function, 1: function proxy, 2: non-function)
1154f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&shift_arguments);
1155f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  { Label loop;
1156f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Calculate the copy start address (destination). Copy end address is jssp.
1157f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1158f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Sub(scratch1, scratch2, kPointerSize);
1159f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1160f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&loop);
1161f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1162f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1163f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(scratch1, jssp);
1164f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(ge, &loop);
1165f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Adjust the actual number of arguments and remove the top element
1166f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // (which is a copy of the last argument).
1167f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Sub(argc, argc, 1);
1168f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Drop(1);
1169f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1170f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1171f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1172f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     or a function proxy via CALL_FUNCTION_PROXY.
1173f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // call type (0: JS function, 1: function proxy, 2: non-function)
1174f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  { Label js_function, non_proxy;
1175f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cbz(call_type, &js_function);
1176f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
1177f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x2, 0);
1178f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
1179f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(ne, &non_proxy);
1180f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1181f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(function);  // Re-add proxy object as additional argument.
1182f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(argc, argc, 1);
1183f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ GetBuiltinFunction(function, Builtins::CALL_FUNCTION_PROXY);
1184f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1185f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org            RelocInfo::CODE_TARGET);
1186f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1187f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&non_proxy);
1188f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
1189f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1190f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org            RelocInfo::CODE_TARGET);
1191f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&js_function);
1192f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1193f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1194f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // 5b. Get the code to call from the function and check that the number of
1195f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     expected arguments matches what we're providing.  If so, jump
1196f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //     (tail-call) to the code in register edx without checking arguments.
1197f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1198f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldrsw(x2,
1199f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org           FieldMemOperand(x3,
1200f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org             SharedFunctionInfo::kFormalParameterCountOffset));
1201f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label dont_adapt_args;
1202f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Cmp(x2, argc);  // Check formal and actual parameter counts.
1203f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(eq, &dont_adapt_args);
1204f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1205f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org          RelocInfo::CODE_TARGET);
1206f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&dont_adapt_args);
1207f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1208f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1209f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ParameterCount expected(0);
1210f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
1211f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1212f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1213f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1214f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1215f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_FunctionApply");
1216f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  const int kIndexOffset    =
1217f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1218f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  const int kLimitOffset    =
1219f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1220f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  const int kArgsOffset     =  2 * kPointerSize;
1221f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  const int kReceiverOffset =  3 * kPointerSize;
1222f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  const int kFunctionOffset =  4 * kPointerSize;
1223f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1224f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {
1225f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    FrameScope frame_scope(masm, StackFrame::INTERNAL);
1226f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1227f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register args = x12;
1228f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register receiver = x14;
1229f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register function = x15;
1230f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1231f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Get the length of the arguments via a builtin call.
1232f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(function, MemOperand(fp, kFunctionOffset));
1233f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(args, MemOperand(fp, kArgsOffset));
1234f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(function, args);
1235f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
1236f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register argc = x0;
1237f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1238f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Check the stack for overflow.
1239f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // We are not trying to catch interruptions (e.g. debug break and
1240f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // preemption) here, so the "real stack limit" is checked.
1241f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label enough_stack_space;
1242f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1243f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(function, MemOperand(fp, kFunctionOffset));
1244f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Make x10 the space we have left. The stack might already be overflowed
1245f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // here which will cause x10 to become negative.
1246f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // TODO(jbramley): Check that the stack usage here is safe.
1247f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Sub(x10, jssp, x10);
1248f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Check if the arguments will overflow the stack.
1249f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(x10, Operand(argc, LSR, kSmiShift - kPointerSizeLog2));
1250f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(gt, &enough_stack_space);
1251f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // There is not enough stack space, so use a builtin to throw an appropriate
1252f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // error.
1253f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(function, argc);
1254e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1255f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // We should never return from the APPLY_OVERFLOW builtin.
1256f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    if (__ emit_debug_code()) {
1257f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org      __ Unreachable();
1258f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    }
1259f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1260f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&enough_stack_space);
1261f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Push current limit and index.
1262f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x1, 0);  // Initial index.
1263f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(argc, x1);
1264f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1265f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label push_receiver;
1266f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
1267f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1268f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Check that the function is a JS function. Otherwise it must be a proxy.
1269f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // When it is not the function proxy will be invoked later.
1270f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
1271f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                           &push_receiver);
1272f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1273f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Change context eagerly to get the right global object if necessary.
1274f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1275f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Load the shared function info.
1276f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x2, FieldMemOperand(function,
1277f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                               JSFunction::kSharedFunctionInfoOffset));
1278f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1279f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Compute and push the receiver.
1280f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Do not transform the receiver for strict mode functions.
1281f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label convert_receiver_to_object, use_global_receiver;
1282f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
1283f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
1284f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Do not transform the receiver for native functions.
1285f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
1286f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1287486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org    // Compute the receiver in sloppy mode.
1288f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfSmi(receiver, &convert_receiver_to_object);
1289f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_receiver);
1290f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1291f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                  &use_global_receiver);
1292f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1293f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Check if the receiver is already a JavaScript object.
1294f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1295f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
1296f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                        &push_receiver, ge);
1297f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1298f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Call a builtin to convert the receiver to a regular object.
1299f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&convert_receiver_to_object);
1300f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(receiver);
1301f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1302f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(receiver, x0);
1303f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&push_receiver);
1304f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1305f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&use_global_receiver);
1306f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x10, GlobalObjectMemOperand());
1307f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalReceiverOffset));
1308f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1309f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Push the receiver
1310f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&push_receiver);
1311f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(receiver);
1312f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1313f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy all arguments from the array to the stack.
1314f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label entry, loop;
1315f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Register current = x0;
1316f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(current, MemOperand(fp, kIndexOffset));
1317f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&entry);
1318f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1319f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&loop);
1320f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Load the current argument from the arguments array and push it.
1321f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // TODO(all): Couldn't we optimize this for JS arrays?
1322f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1323f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x1, MemOperand(fp, kArgsOffset));
1324f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x1, current);
1325f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1326f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Call the runtime to access the property in the arguments array.
1327f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ CallRuntime(Runtime::kGetProperty, 2);
1328f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(x0);
1329f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1330f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Use inline caching to access the arguments.
1331f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(current, MemOperand(fp, kIndexOffset));
13327010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org    __ Add(current, current, Smi::FromInt(1));
1333f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Str(current, MemOperand(fp, kIndexOffset));
1334f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1335f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Test if the copy loop has finished copying all the elements from the
1336f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // arguments object.
1337f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&entry);
1338f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(x1, MemOperand(fp, kLimitOffset));
1339f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Cmp(current, x1);
1340f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(ne, &loop);
1341f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1342f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // At the end of the loop, the number of arguments is stored in 'current',
1343f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // represented as a smi.
1344f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1345f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    function = x1;  // From now on we want the function to be kept in x1;
1346f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ldr(function, MemOperand(fp, kFunctionOffset));
1347f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1348f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Call the function.
1349f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label call_proxy;
1350f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    ParameterCount actual(current);
1351f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ SmiUntag(current);
1352f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
1353f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
1354f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    frame_scope.GenerateLeaveFrame();
1355f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Drop(3);
1356f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Ret();
1357f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1358f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Call the function proxy.
1359f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&call_proxy);
1360f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x0 : argc
1361f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // x1 : function
1362f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Push(function);  // Add function proxy as last argument.
1363f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Add(x0, x0, 1);
1364f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Mov(x2, 0);
1365f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
1366f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1367f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org            RelocInfo::CODE_TARGET);
1368f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1369f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(3);
1370f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
1371f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1372f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1373f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1374e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.orgstatic void ArgumentAdaptorStackCheck(MacroAssembler* masm,
1375e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org                                      Label* stack_overflow) {
1376e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // ----------- S t a t e -------------
1377e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  //  -- x0 : actual number of arguments
1378e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  //  -- x1 : function (passed through to callee)
1379e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  //  -- x2 : expected number of arguments
1380e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // -----------------------------------
1381e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // Check the stack for overflow.
1382e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // We are not trying to catch interruptions (e.g. debug break and
1383e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // preemption) here, so the "real stack limit" is checked.
1384e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  Label enough_stack_space;
1385e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1386e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // Make x10 the space we have left. The stack might already be overflowed
1387e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // here which will cause x10 to become negative.
1388e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  __ Sub(x10, jssp, x10);
1389e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  // Check if the arguments will overflow the stack.
1390e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
1391e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  __ B(le, stack_overflow);
1392e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org}
1393e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org
1394e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org
1395f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1396f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ SmiTag(x10, x0);
13977010a2d84de67daace72568ffcde315a3e510ab5machenbach@chromium.org  __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1398f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Push(lr, fp);
1399f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Push(x11, x1, x10);
1400f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Add(fp, jssp,
1401f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org         StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
1402f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1403f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1404f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1405f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgstatic void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1406f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
1407f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0 : result being passed through
1408f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
1409f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Get the number of arguments passed (as a smi), tear down the frame and
1410f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // then drop the parameters and the receiver.
1411f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1412f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org                               kPointerSize)));
1413f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Mov(jssp, fp);
1414f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Pop(fp, lr);
141597b98c9169c85693801d4d59089450695ad82e2dmachenbach@chromium.org  __ DropBySMI(x10, kXRegSize);
1416f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Drop(1);
1417f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1418f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1419f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1420f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgvoid Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1421f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
1422f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // ----------- S t a t e -------------
1423f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x0 : actual number of arguments
1424f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x1 : function (passed through to callee)
1425f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  //  -- x2 : expected number of arguments
1426f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // -----------------------------------
1427f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1428e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  Label stack_overflow;
1429e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  ArgumentAdaptorStackCheck(masm, &stack_overflow);
1430e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org
1431ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  Register argc_actual = x0;  // Excluding the receiver.
1432ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  Register argc_expected = x2;  // Excluding the receiver.
1433ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  Register function = x1;
1434ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  Register code_entry = x3;
1435ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1436f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label invoke, dont_adapt_arguments;
1437f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1438f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  Label enough, too_few;
1439ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1440ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Cmp(argc_actual, argc_expected);
1441f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(lt, &too_few);
1442ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1443f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ B(eq, &dont_adapt_arguments);
1444f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1445f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {  // Enough parameters: actual >= expected
1446f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    EnterArgumentsAdaptorFrame(masm);
1447f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1448ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_start = x10;
1449ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_end = x11;
1450ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_to = x12;
1451ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register scratch1 = x13, scratch2 = x14;
1452ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1453ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1454ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1455ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Adjust for fp, lr, and the receiver.
1456ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(copy_start, fp, 3 * kPointerSize);
1457ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
1458ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Sub(copy_end, copy_start, argc_expected);
1459ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Sub(copy_end, copy_end, kPointerSize);
1460ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Mov(copy_to, jssp);
1461ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1462ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Claim space for the arguments, the receiver, and one extra slot.
1463ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // The extra slot ensures we do not write under jssp. It will be popped
1464ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // later.
1465ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(scratch1, argc_expected, 2 * kPointerSize);
1466ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Claim(scratch1, 1);
1467f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1468f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy the arguments (including the receiver) to the new stack frame.
1469ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Label copy_2_by_2;
1470ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Bind(&copy_2_by_2);
1471ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Ldp(scratch1, scratch2,
1472ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org           MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
1473ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Stp(scratch1, scratch2,
1474ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1475ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Cmp(copy_start, copy_end);
1476ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ B(hi, &copy_2_by_2);
1477ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1478ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Correct the space allocated for the extra slot.
1479ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Drop(1);
1480f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1481f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ B(&invoke);
1482f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1483f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1484f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  {  // Too few parameters: Actual < expected
1485f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&too_few);
1486f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    EnterArgumentsAdaptorFrame(masm);
1487f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1488ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_from = x10;
1489ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_end = x11;
1490ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register copy_to = x12;
1491ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Register scratch1 = x13, scratch2 = x14;
1492ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1493ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1494ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
1495ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1496ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Adjust for fp, lr, and the receiver.
1497ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(copy_from, fp, 3 * kPointerSize);
1498ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(copy_from, copy_from, argc_actual);
1499ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Mov(copy_to, jssp);
1500ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Sub(copy_end, copy_to, 1 * kPointerSize);   // Adjust for the receiver.
1501ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Sub(copy_end, copy_end, argc_actual);
1502ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1503ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Claim space for the arguments, the receiver, and one extra slot.
1504ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // The extra slot ensures we do not write under jssp. It will be popped
1505ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // later.
1506ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(scratch1, argc_expected, 2 * kPointerSize);
1507ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Claim(scratch1, 1);
1508f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1509f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Copy the arguments (including the receiver) to the new stack frame.
1510ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    Label copy_2_by_2;
1511ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Bind(&copy_2_by_2);
1512ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Ldp(scratch1, scratch2,
1513ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org           MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
1514ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Stp(scratch1, scratch2,
1515ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1516ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Cmp(copy_to, copy_end);
1517ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ B(hi, &copy_2_by_2);
1518ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1519ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Mov(copy_to, copy_end);
1520f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1521f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    // Fill the remaining expected arguments with undefined.
1522ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1523ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Add(copy_end, jssp, kPointerSize);
1524ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1525f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    Label fill;
1526f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org    __ Bind(&fill);
1527ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Stp(scratch1, scratch1,
1528ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1529ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Cmp(copy_to, copy_end);
1530ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ B(hi, &fill);
1531ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org
1532ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    // Correct the space allocated for the extra slot.
1533ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org    __ Drop(1);
1534f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  }
1535f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1536f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Arguments have been adapted. Now call the entry point.
1537f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&invoke);
1538ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Call(code_entry);
1539f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1540f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Store offset of return address for deoptimizer.
1541f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1542f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1543f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Exit frame and return.
1544f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  LeaveArgumentsAdaptorFrame(masm);
1545f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Ret();
1546f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1547f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  // Call the entry point without adapting the arguments.
1548f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org  __ Bind(&dont_adapt_arguments);
1549ca2f2040e0e1a10df95bec18e69499f85f4c1316machenbach@chromium.org  __ Jump(code_entry);
1550e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org
1551e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  __ Bind(&stack_overflow);
1552e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  {
1553e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org    FrameScope frame(masm, StackFrame::MANUAL);
1554e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org    EnterArgumentsAdaptorFrame(masm);
1555e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1556f2f0489407bbb5e50d16ae791442df29513b53b5machenbach@chromium.org    __ Unreachable();
1557e9fd6580f52407c94d77bfcb4be04207f2ebb2f1machenbach@chromium.org  }
1558f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org}
1559f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1560f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1561f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org#undef __
1562f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1563f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org} }  // namespace v8::internal
1564f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org
1565f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org#endif  // V8_TARGET_ARCH_ARM
1566