blob: 6c374b3914330fc0d15075e103fbefd1eb8d13c0 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_ARM
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "deoptimizer.h"
35#include "full-codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "runtime.h"
rossberg@chromium.org9ed27462014-01-07 14:16:41 +000037#include "stub-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
kasperl@chromium.org71affb52009-05-26 05:44:31 +000039namespace v8 {
40namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42
ager@chromium.org65dad4b2009-04-23 08:48:43 +000043#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
45
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000046void Builtins::Generate_Adaptor(MacroAssembler* masm,
47 CFunctionId id,
48 BuiltinExtraArguments extra_args) {
49 // ----------- S t a t e -------------
50 // -- r0 : number of arguments excluding receiver
51 // -- r1 : called function (only guaranteed when
52 // extra_args requires it)
53 // -- cp : context
54 // -- sp[0] : last argument
55 // -- ...
56 // -- sp[4 * (argc - 1)] : first argument (argc == r0)
57 // -- sp[4 * argc] : receiver
58 // -----------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000059
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000060 // Insert extra arguments.
61 int num_extra_args = 0;
62 if (extra_args == NEEDS_CALLED_FUNCTION) {
63 num_extra_args = 1;
64 __ push(r1);
65 } else {
66 ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
67 }
68
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000069 // JumpToExternalReference expects r0 to contain the number of arguments
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000070 // including the receiver and the extra arguments.
71 __ add(r0, r0, Operand(num_extra_args + 1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000072 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000073}
74
75
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000076// Load the built-in InternalArray function from the current context.
77static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
78 Register result) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000079 // Load the native context.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000080
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000081 __ ldr(result,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000082 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
83 __ ldr(result,
84 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
85 // Load the InternalArray function from the native context.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000086 __ ldr(result,
87 MemOperand(result,
88 Context::SlotOffset(
89 Context::INTERNAL_ARRAY_FUNCTION_INDEX)));
90}
91
92
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000093// Load the built-in Array function from the current context.
94static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000095 // Load the native context.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000096
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000097 __ ldr(result,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000098 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
99 __ ldr(result,
100 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
101 // Load the Array function from the native context.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000102 __ ldr(result,
103 MemOperand(result,
104 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
105}
106
107
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000108void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
109 // ----------- S t a t e -------------
110 // -- r0 : number of arguments
111 // -- lr : return address
112 // -- sp[...]: constructor arguments
113 // -----------------------------------
114 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
115
116 // Get the InternalArray function.
117 GenerateLoadInternalArrayFunction(masm, r1);
118
119 if (FLAG_debug_code) {
120 // Initial map for the builtin InternalArray functions should be maps.
121 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000122 __ SmiTst(r2);
danno@chromium.org59400602013-08-13 17:09:37 +0000123 __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000124 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +0000125 __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000126 }
127
128 // Run the native code for the InternalArray function called as a normal
129 // function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000130 // tail call a stub
131 InternalArrayConstructorStub stub(masm->isolate());
132 __ TailCallStub(&stub);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000133}
134
135
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000136void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000137 // ----------- S t a t e -------------
138 // -- r0 : number of arguments
139 // -- lr : return address
140 // -- sp[...]: constructor arguments
141 // -----------------------------------
142 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
143
144 // Get the Array function.
145 GenerateLoadArrayFunction(masm, r1);
146
147 if (FLAG_debug_code) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000148 // Initial map for the builtin Array functions should be maps.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000149 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000150 __ SmiTst(r2);
danno@chromium.org59400602013-08-13 17:09:37 +0000151 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000152 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +0000153 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000154 }
155
156 // Run the native code for the Array function called as a normal function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000157 // tail call a stub
158 Handle<Object> undefined_sentinel(
159 masm->isolate()->heap()->undefined_value(),
160 masm->isolate());
161 __ mov(r2, Operand(undefined_sentinel));
162 ArrayConstructorStub stub(masm->isolate());
163 __ TailCallStub(&stub);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000164}
165
166
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000167void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000168 // ----------- S t a t e -------------
169 // -- r0 : number of arguments
170 // -- r1 : constructor function
171 // -- lr : return address
172 // -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
173 // -- sp[argc * 4] : receiver
174 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000175 Counters* counters = masm->isolate()->counters();
176 __ IncrementCounter(counters->string_ctor_calls(), 1, r2, r3);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000177
178 Register function = r1;
179 if (FLAG_debug_code) {
180 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r2);
181 __ cmp(function, Operand(r2));
danno@chromium.org59400602013-08-13 17:09:37 +0000182 __ Assert(eq, kUnexpectedStringFunction);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000183 }
184
185 // Load the first arguments in r0 and get rid of the rest.
186 Label no_arguments;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000187 __ cmp(r0, Operand::Zero());
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000188 __ b(eq, &no_arguments);
189 // First args = sp[(argc - 1) * 4].
190 __ sub(r0, r0, Operand(1));
191 __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
192 // sp now point to args[0], drop args[0] + receiver.
193 __ Drop(2);
194
195 Register argument = r2;
196 Label not_cached, argument_is_string;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000197 __ LookupNumberStringCache(r0, // Input.
198 argument, // Result.
199 r3, // Scratch.
200 r4, // Scratch.
201 r5, // Scratch.
202 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000203 __ IncrementCounter(counters->string_ctor_cached_number(), 1, r3, r4);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000204 __ bind(&argument_is_string);
205
206 // ----------- S t a t e -------------
207 // -- r2 : argument converted to string
208 // -- r1 : constructor function
209 // -- lr : return address
210 // -----------------------------------
211
212 Label gc_required;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000213 __ Allocate(JSValue::kSize,
214 r0, // Result.
215 r3, // Scratch.
216 r4, // Scratch.
217 &gc_required,
218 TAG_OBJECT);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000219
220 // Initialising the String Object.
221 Register map = r3;
222 __ LoadGlobalFunctionInitialMap(function, map, r4);
223 if (FLAG_debug_code) {
224 __ ldrb(r4, FieldMemOperand(map, Map::kInstanceSizeOffset));
225 __ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2));
danno@chromium.org59400602013-08-13 17:09:37 +0000226 __ Assert(eq, kUnexpectedStringWrapperInstanceSize);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000227 __ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000228 __ cmp(r4, Operand::Zero());
danno@chromium.org59400602013-08-13 17:09:37 +0000229 __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000230 }
231 __ str(map, FieldMemOperand(r0, HeapObject::kMapOffset));
232
233 __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex);
234 __ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset));
235 __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
236
237 __ str(argument, FieldMemOperand(r0, JSValue::kValueOffset));
238
239 // Ensure the object is fully initialized.
240 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
241
242 __ Ret();
243
244 // The argument was not found in the number to string cache. Check
245 // if it's a string already before calling the conversion builtin.
246 Label convert_argument;
247 __ bind(&not_cached);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000248 __ JumpIfSmi(r0, &convert_argument);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000249
250 // Is it a String?
251 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
252 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000253 STATIC_ASSERT(kNotStringTag != 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000254 __ tst(r3, Operand(kIsNotStringMask));
255 __ b(ne, &convert_argument);
256 __ mov(argument, r0);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000257 __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000258 __ b(&argument_is_string);
259
260 // Invoke the conversion builtin and put the result into r2.
261 __ bind(&convert_argument);
262 __ push(function); // Preserve the function.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000263 __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000264 {
265 FrameScope scope(masm, StackFrame::INTERNAL);
266 __ push(r0);
267 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
268 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000269 __ pop(function);
270 __ mov(argument, r0);
271 __ b(&argument_is_string);
272
273 // Load the empty string into r2, remove the receiver from the
274 // stack, and jump back to the case where the argument is a string.
275 __ bind(&no_arguments);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000276 __ LoadRoot(argument, Heap::kempty_stringRootIndex);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000277 __ Drop(1);
278 __ b(&argument_is_string);
279
280 // At this point the argument is already a string. Call runtime to
281 // create a string wrapper.
282 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000283 __ IncrementCounter(counters->string_ctor_gc_required(), 1, r3, r4);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000284 {
285 FrameScope scope(masm, StackFrame::INTERNAL);
286 __ push(argument);
287 __ CallRuntime(Runtime::kNewStringWrapper, 1);
288 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000289 __ Ret();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000290}
291
292
yangguo@chromium.org49546742013-12-23 16:17:49 +0000293static void CallRuntimePassFunction(
294 MacroAssembler* masm, Runtime::FunctionId function_id) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000295 FrameScope scope(masm, StackFrame::INTERNAL);
296 // Push a copy of the function onto the stack.
297 __ push(r1);
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000298 // Push call kind information and function as parameter to the runtime call.
299 __ Push(r5, r1);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000300
301 __ CallRuntime(function_id, 1);
302 // Restore call kind information.
303 __ pop(r5);
304 // Restore receiver.
305 __ pop(r1);
306}
307
308
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000309static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
310 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
311 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset));
312 __ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000313 __ Jump(r2);
314}
315
316
yangguo@chromium.org49546742013-12-23 16:17:49 +0000317static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
318 __ add(r0, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
319 __ Jump(r0);
320}
321
322
323void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000324 // Checking whether the queued function is ready for install is optional,
325 // since we come across interrupts and stack checks elsewhere. However,
326 // not checking may delay installing ready functions, and always checking
327 // would be quite expensive. A good compromise is to first check against
328 // stack limit as a cue for an interrupt signal.
329 Label ok;
330 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
331 __ cmp(sp, Operand(ip));
332 __ b(hs, &ok);
333
yangguo@chromium.org49546742013-12-23 16:17:49 +0000334 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
335 GenerateTailCallToReturnedCode(masm);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000336
337 __ bind(&ok);
338 GenerateTailCallToSharedCode(masm);
339}
340
341
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000342static void Generate_JSConstructStubHelper(MacroAssembler* masm,
343 bool is_api_function,
344 bool count_constructions) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000345 // ----------- S t a t e -------------
346 // -- r0 : number of arguments
347 // -- r1 : constructor function
348 // -- lr : return address
349 // -- sp[...]: constructor arguments
350 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000352 // Should never count constructions for api objects.
353 ASSERT(!is_api_function || !count_constructions);
354
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000355 Isolate* isolate = masm->isolate();
356
ager@chromium.org7c537e22008-10-16 08:43:32 +0000357 // Enter a construct frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000358 {
359 FrameScope scope(masm, StackFrame::CONSTRUCT);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000360
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000361 // Preserve the two incoming parameters on the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000362 __ SmiTag(r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000363 __ push(r0); // Smi-tagged arguments count.
364 __ push(r1); // Constructor function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000366 // Try to allocate the object without transitioning into C code. If any of
367 // the preconditions is not met, the code bails out to the runtime call.
368 Label rt_call, allocated;
369 if (FLAG_inline_new) {
370 Label undo_allocation;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000371#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000372 ExternalReference debug_step_in_fp =
373 ExternalReference::debug_step_in_fp_address(isolate);
374 __ mov(r2, Operand(debug_step_in_fp));
375 __ ldr(r2, MemOperand(r2));
376 __ tst(r2, r2);
377 __ b(ne, &rt_call);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000378#endif
379
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000380 // Load the initial map and verify that it is in fact a map.
381 // r1: constructor function
382 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
383 __ JumpIfSmi(r2, &rt_call);
384 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
385 __ b(ne, &rt_call);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000386
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000387 // Check that the constructor is not constructing a JSFunction (see
388 // comments in Runtime_NewObject in runtime.cc). In which case the
389 // initial map's instance type would be JS_FUNCTION_TYPE.
390 // r1: constructor function
391 // r2: initial map
392 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
393 __ b(eq, &rt_call);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000394
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000395 if (count_constructions) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000396 Label allocate;
397 // Decrease generous allocation count.
398 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
399 MemOperand constructor_count =
400 FieldMemOperand(r3, SharedFunctionInfo::kConstructionCountOffset);
401 __ ldrb(r4, constructor_count);
402 __ sub(r4, r4, Operand(1), SetCC);
403 __ strb(r4, constructor_count);
404 __ b(ne, &allocate);
405
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000406 __ push(r1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000407
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000408 __ Push(r2, r1); // r1 = constructor
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000409 // The call will replace the stub, so the countdown is only done once.
410 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
411
412 __ pop(r2);
413 __ pop(r1);
414
415 __ bind(&allocate);
416 }
417
418 // Now allocate the JSObject on the heap.
419 // r1: constructor function
420 // r2: initial map
421 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000422 __ Allocate(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000423
424 // Allocated the JSObject, now initialize the fields. Map is set to
425 // initial map and properties and elements are set to empty fixed array.
426 // r1: constructor function
427 // r2: initial map
428 // r3: object size
429 // r4: JSObject (not tagged)
430 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
431 __ mov(r5, r4);
432 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
433 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
434 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
435 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
436 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
437 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
438
439 // Fill all the in-object properties with the appropriate filler.
440 // r1: constructor function
441 // r2: initial map
442 // r3: object size (in words)
443 // r4: JSObject (not tagged)
444 // r5: First in-object property of JSObject (not tagged)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000445 ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000446 __ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 if (count_constructions) {
448 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
449 __ Ubfx(r0, r0, Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
450 kBitsPerByte);
451 __ add(r0, r5, Operand(r0, LSL, kPointerSizeLog2));
452 // r0: offset of first field after pre-allocated fields
453 if (FLAG_debug_code) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000454 __ add(ip, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object.
455 __ cmp(r0, ip);
danno@chromium.org59400602013-08-13 17:09:37 +0000456 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000458 __ InitializeFieldsWithFiller(r5, r0, r6);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000459 // To allow for truncation.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000460 __ LoadRoot(r6, Heap::kOnePointerFillerMapRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000461 }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000462 __ add(r0, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object.
463 __ InitializeFieldsWithFiller(r5, r0, r6);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000464
465 // Add the object tag to make the JSObject real, so that we can continue
466 // and jump into the continuation code at any time from now on. Any
467 // failures need to undo the allocation, so that the heap is in a
468 // consistent state and verifiable.
469 __ add(r4, r4, Operand(kHeapObjectTag));
470
471 // Check if a non-empty properties array is needed. Continue with
472 // allocated object if not fall through to runtime call if it is.
473 // r1: constructor function
474 // r4: JSObject
475 // r5: start of next object (not tagged)
476 __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset));
477 // The field instance sizes contains both pre-allocated property fields
478 // and in-object properties.
479 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
480 __ Ubfx(r6, r0, Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
481 kBitsPerByte);
482 __ add(r3, r3, Operand(r6));
483 __ Ubfx(r6, r0, Map::kInObjectPropertiesByte * kBitsPerByte,
484 kBitsPerByte);
485 __ sub(r3, r3, Operand(r6), SetCC);
486
487 // Done if no extra properties are to be allocated.
488 __ b(eq, &allocated);
danno@chromium.org59400602013-08-13 17:09:37 +0000489 __ Assert(pl, kPropertyAllocationCountFailed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000490
491 // Scale the number of elements by pointer size and add the header for
492 // FixedArrays to the start of the next object calculation from above.
493 // r1: constructor
494 // r3: number of elements in properties array
495 // r4: JSObject
496 // r5: start of next object
497 __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000498 __ Allocate(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000499 r0,
500 r5,
501 r6,
502 r2,
503 &undo_allocation,
504 static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS));
505
506 // Initialize the FixedArray.
507 // r1: constructor
508 // r3: number of elements in properties array
509 // r4: JSObject
510 // r5: FixedArray (not tagged)
511 __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex);
512 __ mov(r2, r5);
513 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
514 __ str(r6, MemOperand(r2, kPointerSize, PostIndex));
515 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000516 __ SmiTag(r0, r3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 __ str(r0, MemOperand(r2, kPointerSize, PostIndex));
518
519 // Initialize the fields to undefined.
520 // r1: constructor function
521 // r2: First element of FixedArray (not tagged)
522 // r3: number of elements in properties array
523 // r4: JSObject
524 // r5: FixedArray (not tagged)
525 __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2)); // End of object.
526 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
527 { Label loop, entry;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000528 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000529 __ b(&entry);
530 __ bind(&loop);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000531 __ str(r0, MemOperand(r2, kPointerSize, PostIndex));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000532 __ bind(&entry);
533 __ cmp(r2, r6);
534 __ b(lt, &loop);
535 }
536
537 // Store the initialized FixedArray into the properties field of
538 // the JSObject
539 // r1: constructor function
540 // r4: JSObject
541 // r5: FixedArray (not tagged)
542 __ add(r5, r5, Operand(kHeapObjectTag)); // Add the heap tag.
543 __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset));
544
545 // Continue with JSObject being successfully allocated
546 // r1: constructor function
547 // r4: JSObject
548 __ jmp(&allocated);
549
550 // Undo the setting of the new top so that the heap is verifiable. For
551 // example, the map's unused properties potentially do not match the
552 // allocated objects unused properties.
553 // r4: JSObject (previous new top)
554 __ bind(&undo_allocation);
555 __ UndoAllocationInNewSpace(r4, r5);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000556 }
557
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000558 // Allocate the new receiver object using the runtime call.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000559 // r1: constructor function
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 __ bind(&rt_call);
561 __ push(r1); // argument for Runtime_NewObject
562 __ CallRuntime(Runtime::kNewObject, 1);
563 __ mov(r4, r0);
564
565 // Receiver for constructor call allocated.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000566 // r4: JSObject
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000567 __ bind(&allocated);
568 __ push(r4);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000569 __ push(r4);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000570
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000571 // Reload the number of arguments and the constructor from the stack.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000572 // sp[0]: receiver
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000573 // sp[1]: receiver
574 // sp[2]: constructor function
575 // sp[3]: number of arguments (smi-tagged)
576 __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
577 __ ldr(r3, MemOperand(sp, 3 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000578
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000579 // Set up pointer to last argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000580 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
581
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000582 // Set up number of arguments for function call below
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000583 __ SmiUntag(r0, r3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000584
585 // Copy arguments and receiver to the expression stack.
586 // r0: number of arguments
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 // r1: constructor function
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000588 // r2: address of last argument (caller sp)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000589 // r3: number of arguments (smi-tagged)
590 // sp[0]: receiver
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000591 // sp[1]: receiver
592 // sp[2]: constructor function
593 // sp[3]: number of arguments (smi-tagged)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000594 Label loop, entry;
595 __ b(&entry);
596 __ bind(&loop);
597 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
598 __ push(ip);
599 __ bind(&entry);
600 __ sub(r3, r3, Operand(2), SetCC);
601 __ b(ge, &loop);
602
603 // Call the function.
604 // r0: number of arguments
605 // r1: constructor function
606 if (is_api_function) {
607 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
608 Handle<Code> code =
609 masm->isolate()->builtins()->HandleApiCallConstruct();
610 ParameterCount expected(0);
611 __ InvokeCode(code, expected, expected,
612 RelocInfo::CODE_TARGET, CALL_FUNCTION, CALL_AS_METHOD);
613 } else {
614 ParameterCount actual(r0);
615 __ InvokeFunction(r1, actual, CALL_FUNCTION,
616 NullCallWrapper(), CALL_AS_METHOD);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000617 }
618
ulan@chromium.org967e2702012-02-28 09:49:15 +0000619 // Store offset of return address for deoptimizer.
620 if (!is_api_function && !count_constructions) {
621 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
622 }
623
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000624 // Restore context from the frame.
625 // r0: result
626 // sp[0]: receiver
627 // sp[1]: constructor function
628 // sp[2]: number of arguments (smi-tagged)
629 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000630
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000631 // If the result is an object (in the ECMA sense), we should get rid
632 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
633 // on page 74.
634 Label use_receiver, exit;
635
636 // If the result is a smi, it is *not* an object in the ECMA sense.
637 // r0: result
638 // sp[0]: receiver (newly allocated object)
639 // sp[1]: constructor function
640 // sp[2]: number of arguments (smi-tagged)
641 __ JumpIfSmi(r0, &use_receiver);
642
643 // If the type of the result (stored in its map) is less than
644 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000645 __ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000646 __ b(ge, &exit);
647
648 // Throw away the result of the constructor invocation and use the
649 // on-stack receiver as the result.
650 __ bind(&use_receiver);
651 __ ldr(r0, MemOperand(sp));
652
653 // Remove receiver from the stack, remove caller arguments, and
654 // return.
655 __ bind(&exit);
656 // r0: result
657 // sp[0]: receiver (newly allocated object)
658 // sp[1]: constructor function
659 // sp[2]: number of arguments (smi-tagged)
660 __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
661
662 // Leave construct frame.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000663 }
664
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000665 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
666 __ add(sp, sp, Operand(kPointerSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000667 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, r1, r2);
ager@chromium.org9085a012009-05-11 19:22:57 +0000668 __ Jump(lr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669}
670
671
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
673 Generate_JSConstructStubHelper(masm, false, true);
674}
675
676
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000677void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000678 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000679}
680
681
682void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000683 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000684}
685
686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
688 bool is_construct) {
689 // Called from Generate_JS_Entry
690 // r0: code entry
691 // r1: function
692 // r2: receiver
693 // r3: argc
694 // r4: argv
yangguo@chromium.orgcc536052013-11-29 11:43:20 +0000695 // r5-r6, r8 (if not FLAG_enable_ool_constant_pool) and cp may be clobbered
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000696 ProfileEntryHookStub::MaybeCallEntryHook(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000698 // Clear the context before we push it when entering the internal frame.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000699 __ mov(cp, Operand::Zero());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000701 // Enter an internal frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000702 {
703 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000705 // Set up the context from the function argument.
706 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000708 __ InitializeRootRegister();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000709
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000710 // Push the function and the receiver onto the stack.
711 __ push(r1);
712 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000714 // Copy arguments to the stack in a loop.
715 // r1: function
716 // r3: argc
717 // r4: argv, i.e. points to first arg
718 Label loop, entry;
719 __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2));
720 // r2 points past last arg.
721 __ b(&entry);
722 __ bind(&loop);
723 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter
724 __ ldr(r0, MemOperand(r0)); // dereference handle
725 __ push(r0); // push parameter
726 __ bind(&entry);
727 __ cmp(r4, r2);
728 __ b(ne, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730 // Initialize all JavaScript callee-saved registers, since they will be seen
731 // by the garbage collector as part of handlers.
732 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
733 __ mov(r5, Operand(r4));
734 __ mov(r6, Operand(r4));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000735 if (!FLAG_enable_ool_constant_pool) {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +0000736 __ mov(r8, Operand(r4));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000737 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000738 if (kR9Available == 1) {
739 __ mov(r9, Operand(r4));
740 }
741
742 // Invoke the code and pass argc as r0.
743 __ mov(r0, Operand(r3));
744 if (is_construct) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000745 // No type feedback cell is available
746 Handle<Object> undefined_sentinel(
747 masm->isolate()->heap()->undefined_value(), masm->isolate());
748 __ mov(r2, Operand(undefined_sentinel));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000749 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
750 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 } else {
752 ParameterCount actual(r0);
753 __ InvokeFunction(r1, actual, CALL_FUNCTION,
754 NullCallWrapper(), CALL_AS_METHOD);
755 }
756 // Exit the JS frame and remove the parameters (except function), and
757 // return.
758 // Respect ABI stack constraint.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000759 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000760 __ Jump(lr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761
762 // r0: result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763}
764
765
766void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
767 Generate_JSEntryTrampolineHelper(masm, false);
768}
769
770
771void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
772 Generate_JSEntryTrampolineHelper(masm, true);
773}
774
775
yangguo@chromium.org49546742013-12-23 16:17:49 +0000776void Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
777 CallRuntimePassFunction(masm, Runtime::kCompileUnoptimized);
778 GenerateTailCallToReturnedCode(masm);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000779}
780
781
yangguo@chromium.org49546742013-12-23 16:17:49 +0000782static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
783 FrameScope scope(masm, StackFrame::INTERNAL);
784 // Push a copy of the function onto the stack.
785 __ push(r1);
786 // Push call kind information and function as parameter to the runtime call.
787 __ Push(r5, r1);
788 // Whether to compile in a background thread.
789 __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
790
791 __ CallRuntime(Runtime::kCompileOptimized, 2);
792 // Restore call kind information.
793 __ pop(r5);
794 // Restore receiver.
795 __ pop(r1);
796}
797
798
799void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
800 CallCompileOptimized(masm, false);
801 GenerateTailCallToReturnedCode(masm);
802}
803
804
805void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
806 CallCompileOptimized(masm, true);
807 GenerateTailCallToReturnedCode(masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000808}
809
810
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000811static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
812 // For now, we are relying on the fact that make_code_young doesn't do any
813 // garbage collection which allows us to save/restore the registers without
814 // worrying about which of them contain pointers. We also don't build an
815 // internal frame to make the code faster, since we shouldn't have to do stack
816 // crawls in MakeCodeYoung. This seems a bit fragile.
817
818 // The following registers must be saved and restored when calling through to
819 // the runtime:
820 // r0 - contains return address (beginning of patch sequence)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000821 // r1 - isolate
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000822 FrameScope scope(masm, StackFrame::MANUAL);
823 __ stm(db_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
hpayer@chromium.orgea9b8ba2013-12-20 19:22:39 +0000824 __ PrepareCallCFunction(2, 0, r2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000825 __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate())));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000826 __ CallCFunction(
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000827 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000828 __ ldm(ia_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
829 __ mov(pc, r0);
830}
831
832#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
833void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
834 MacroAssembler* masm) { \
835 GenerateMakeCodeYoungAgainCommon(masm); \
836} \
837void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
838 MacroAssembler* masm) { \
839 GenerateMakeCodeYoungAgainCommon(masm); \
840}
841CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
842#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
843
844
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000845void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
846 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
847 // that make_code_young doesn't do any garbage collection which allows us to
848 // save/restore the registers without worrying about which of them contain
849 // pointers.
850
851 // The following registers must be saved and restored when calling through to
852 // the runtime:
853 // r0 - contains return address (beginning of patch sequence)
854 // r1 - isolate
855 FrameScope scope(masm, StackFrame::MANUAL);
856 __ stm(db_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
hpayer@chromium.orgea9b8ba2013-12-20 19:22:39 +0000857 __ PrepareCallCFunction(2, 0, r2);
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000858 __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate())));
859 __ CallCFunction(ExternalReference::get_mark_code_as_executed_function(
860 masm->isolate()), 2);
861 __ ldm(ia_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
862
863 // Perform prologue operations usually performed by the young code stub.
ulan@chromium.org9ca30172014-01-02 12:10:54 +0000864 __ PushFixedFrame(r1);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000865 __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000866
867 // Jump to point after the code-age stub.
868 __ add(r0, r0, Operand(kNoCodeAgeSequenceLength * Assembler::kInstrSize));
869 __ mov(pc, r0);
870}
871
872
873void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
874 GenerateMakeCodeYoungAgainCommon(masm);
875}
876
877
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000878static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
879 SaveFPRegsMode save_doubles) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000880 {
881 FrameScope scope(masm, StackFrame::INTERNAL);
882
883 // Preserve registers across notification, this is important for compiled
884 // stubs that tail call the runtime on deopts passing their parameters in
885 // registers.
886 __ stm(db_w, sp, kJSCallerSaved | kCalleeSaved);
887 // Pass the function and deoptimization type to the runtime system.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000888 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000889 __ ldm(ia_w, sp, kJSCallerSaved | kCalleeSaved);
890 }
891
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000892 __ add(sp, sp, Operand(kPointerSize)); // Ignore state
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000893 __ mov(pc, lr); // Jump to miss handler
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000894}
895
896
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000897void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
898 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
899}
900
901
902void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
903 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
904}
905
906
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000907static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
908 Deoptimizer::BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000909 {
910 FrameScope scope(masm, StackFrame::INTERNAL);
911 // Pass the function and deoptimization type to the runtime system.
912 __ mov(r0, Operand(Smi::FromInt(static_cast<int>(type))));
913 __ push(r0);
914 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
915 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000916
917 // Get the full codegen state from the stack and untag it -> r6.
918 __ ldr(r6, MemOperand(sp, 0 * kPointerSize));
919 __ SmiUntag(r6);
920 // Switch on the state.
921 Label with_tos_register, unknown_state;
922 __ cmp(r6, Operand(FullCodeGenerator::NO_REGISTERS));
923 __ b(ne, &with_tos_register);
924 __ add(sp, sp, Operand(1 * kPointerSize)); // Remove state.
925 __ Ret();
926
927 __ bind(&with_tos_register);
928 __ ldr(r0, MemOperand(sp, 1 * kPointerSize));
929 __ cmp(r6, Operand(FullCodeGenerator::TOS_REG));
930 __ b(ne, &unknown_state);
931 __ add(sp, sp, Operand(2 * kPointerSize)); // Remove state.
932 __ Ret();
933
934 __ bind(&unknown_state);
935 __ stop("no cases left");
936}
937
938
939void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
940 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
941}
942
943
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000944void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
945 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
946}
947
948
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000949void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
950 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
951}
952
953
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000954void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000955 // Lookup the function in the JavaScript frame.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000956 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000957 {
958 FrameScope scope(masm, StackFrame::INTERNAL);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000959 // Pass function as argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000960 __ push(r0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000961 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000962 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000963
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000964 // If the code object is null, just return to the unoptimized code.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000965 Label skip;
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000966 __ cmp(r0, Operand(Smi::FromInt(0)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000967 __ b(ne, &skip);
968 __ Ret();
969
970 __ bind(&skip);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000971
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000972 // Load deoptimization data from the code object.
973 // <deopt_data> = <code>[#deoptimization_data_offset]
974 __ ldr(r1, MemOperand(r0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
975
976 // Load the OSR entrypoint offset from the deoptimization data.
977 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
978 __ ldr(r1, MemOperand(r1, FixedArray::OffsetOfElementAt(
979 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
980
981 // Compute the target address = code_obj + header_size + osr_offset
982 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
983 __ add(r0, r0, Operand::SmiUntag(r1));
984 __ add(lr, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
985
986 // And "return" to the OSR entry point of the function.
987 __ Ret();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000988}
989
990
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000991void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
992 // We check the stack limit as indicator that recompilation might be done.
993 Label ok;
994 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
995 __ cmp(sp, Operand(ip));
996 __ b(hs, &ok);
997 {
998 FrameScope scope(masm, StackFrame::INTERNAL);
999 __ CallRuntime(Runtime::kStackGuard, 0);
1000 }
1001 __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1002 RelocInfo::CODE_TARGET);
1003
1004 __ bind(&ok);
1005 __ Ret();
1006}
1007
1008
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001009void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1010 // 1. Make sure we have at least one argument.
ager@chromium.org5c838252010-02-19 08:53:10 +00001011 // r0: actual number of arguments
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001012 { Label done;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001013 __ cmp(r0, Operand::Zero());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001014 __ b(ne, &done);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001015 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001016 __ push(r2);
1017 __ add(r0, r0, Operand(1));
1018 __ bind(&done);
1019 }
1020
ager@chromium.org5c838252010-02-19 08:53:10 +00001021 // 2. Get the function to call (passed as receiver) from the stack, check
1022 // if it is a function.
1023 // r0: actual number of arguments
lrn@chromium.org34e60782011-09-15 07:25:40 +00001024 Label slow, non_function;
ager@chromium.org5c838252010-02-19 08:53:10 +00001025 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001026 __ JumpIfSmi(r1, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001027 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001028 __ b(ne, &slow);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001029
ager@chromium.org5c838252010-02-19 08:53:10 +00001030 // 3a. Patch the first argument if necessary when calling a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001031 // r0: actual number of arguments
1032 // r1: function
ager@chromium.org5c838252010-02-19 08:53:10 +00001033 Label shift_arguments;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001034 __ mov(r4, Operand::Zero()); // indicate regular JS_FUNCTION
ager@chromium.org5c838252010-02-19 08:53:10 +00001035 { Label convert_to_object, use_global_receiver, patch_receiver;
1036 // Change context eagerly in case we need the global receiver.
1037 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1038
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001039 // Do not transform the receiver for strict mode functions.
1040 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00001041 __ ldr(r3, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
1042 __ tst(r3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001043 kSmiTagSize)));
1044 __ b(ne, &shift_arguments);
1045
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00001046 // Do not transform the receiver for native (Compilerhints already in r3).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001047 __ tst(r3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00001048 __ b(ne, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001049
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001050 // Compute the receiver in non-strict mode.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001051 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1052 __ ldr(r2, MemOperand(r2, -kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001053 // r0: actual number of arguments
1054 // r1: function
1055 // r2: first argument
whesse@chromium.org7b260152011-06-20 15:33:18 +00001056 __ JumpIfSmi(r2, &convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001057
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00001058 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001059 __ cmp(r2, r3);
1060 __ b(eq, &use_global_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001061 __ LoadRoot(r3, Heap::kNullValueRootIndex);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001062 __ cmp(r2, r3);
1063 __ b(eq, &use_global_receiver);
1064
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001065 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1066 __ CompareObjectType(r2, r3, r3, FIRST_SPEC_OBJECT_TYPE);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001067 __ b(ge, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001068
ager@chromium.org5c838252010-02-19 08:53:10 +00001069 __ bind(&convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001070
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001071 {
1072 // Enter an internal frame in order to preserve argument count.
1073 FrameScope scope(masm, StackFrame::INTERNAL);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001074 __ SmiTag(r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001075 __ push(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001076
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001077 __ push(r2);
1078 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1079 __ mov(r2, r0);
1080
1081 __ pop(r0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001082 __ SmiUntag(r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001083
1084 // Exit the internal frame.
1085 }
1086
lrn@chromium.org34e60782011-09-15 07:25:40 +00001087 // Restore the function to r1, and the flag to r4.
ager@chromium.org5c838252010-02-19 08:53:10 +00001088 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001089 __ mov(r4, Operand::Zero());
ager@chromium.org5c838252010-02-19 08:53:10 +00001090 __ jmp(&patch_receiver);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001091
ager@chromium.org5c838252010-02-19 08:53:10 +00001092 // Use the global receiver object from the called function as the
1093 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001094 __ bind(&use_global_receiver);
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00001095 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
1096 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001097
1098 __ bind(&patch_receiver);
1099 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
1100 __ str(r2, MemOperand(r3, -kPointerSize));
1101
ager@chromium.org5c838252010-02-19 08:53:10 +00001102 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001103 }
1104
lrn@chromium.org34e60782011-09-15 07:25:40 +00001105 // 3b. Check for function proxy.
1106 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001107 __ mov(r4, Operand(1, RelocInfo::NONE32)); // indicate function proxy
lrn@chromium.org34e60782011-09-15 07:25:40 +00001108 __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
1109 __ b(eq, &shift_arguments);
1110 __ bind(&non_function);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001111 __ mov(r4, Operand(2, RelocInfo::NONE32)); // indicate non-function
lrn@chromium.org34e60782011-09-15 07:25:40 +00001112
1113 // 3c. Patch the first argument when calling a non-function. The
ager@chromium.org5c838252010-02-19 08:53:10 +00001114 // CALL_NON_FUNCTION builtin expects the non-function callee as
1115 // receiver, so overwrite the first argument which will ultimately
1116 // become the receiver.
1117 // r0: actual number of arguments
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001118 // r1: function
lrn@chromium.org34e60782011-09-15 07:25:40 +00001119 // r4: call type (0: JS function, 1: function proxy, 2: non-function)
ager@chromium.org5c838252010-02-19 08:53:10 +00001120 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1121 __ str(r1, MemOperand(r2, -kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +00001122
1123 // 4. Shift arguments and return address one slot down on the stack
1124 // (overwriting the original receiver). Adjust argument count to make
1125 // the original first argument the new receiver.
1126 // r0: actual number of arguments
1127 // r1: function
lrn@chromium.org34e60782011-09-15 07:25:40 +00001128 // r4: call type (0: JS function, 1: function proxy, 2: non-function)
ager@chromium.org5c838252010-02-19 08:53:10 +00001129 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001130 { Label loop;
1131 // Calculate the copy start address (destination). Copy end address is sp.
1132 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001133
1134 __ bind(&loop);
1135 __ ldr(ip, MemOperand(r2, -kPointerSize));
1136 __ str(ip, MemOperand(r2));
1137 __ sub(r2, r2, Operand(kPointerSize));
1138 __ cmp(r2, sp);
1139 __ b(ne, &loop);
ager@chromium.org5c838252010-02-19 08:53:10 +00001140 // Adjust the actual number of arguments and remove the top element
1141 // (which is a copy of the last argument).
1142 __ sub(r0, r0, Operand(1));
1143 __ pop();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001144 }
1145
lrn@chromium.org34e60782011-09-15 07:25:40 +00001146 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1147 // or a function proxy via CALL_FUNCTION_PROXY.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001148 // r0: actual number of arguments
1149 // r1: function
lrn@chromium.org34e60782011-09-15 07:25:40 +00001150 // r4: call type (0: JS function, 1: function proxy, 2: non-function)
1151 { Label function, non_proxy;
1152 __ tst(r4, r4);
1153 __ b(eq, &function);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00001154 // Expected number of arguments is 0 for CALL_NON_FUNCTION.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001155 __ mov(r2, Operand::Zero());
danno@chromium.org40cb8782011-05-25 07:58:50 +00001156 __ SetCallKind(r5, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001157 __ cmp(r4, Operand(1));
1158 __ b(ne, &non_proxy);
1159
1160 __ push(r1); // re-add proxy object as additional argument
1161 __ add(r0, r0, Operand(1));
1162 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
1163 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1164 RelocInfo::CODE_TARGET);
1165
1166 __ bind(&non_proxy);
1167 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001168 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1169 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +00001170 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001171 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001172
1173 // 5b. Get the code to call from the function and check that the number of
1174 // expected arguments matches what we're providing. If so, jump
1175 // (tail-call) to the code in register edx without checking arguments.
1176 // r0: actual number of arguments
1177 // r1: function
1178 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1179 __ ldr(r2,
1180 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001181 __ SmiUntag(r2);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001182 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001183 __ SetCallKind(r5, CALL_AS_METHOD);
ager@chromium.org5c838252010-02-19 08:53:10 +00001184 __ cmp(r2, r0); // Check formal and actual parameter counts.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001185 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1186 RelocInfo::CODE_TARGET,
1187 ne);
ager@chromium.org5c838252010-02-19 08:53:10 +00001188
1189 ParameterCount expected(0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001190 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION,
1191 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001192}
1193
1194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001196 const int kIndexOffset =
1197 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1198 const int kLimitOffset =
1199 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1200 const int kArgsOffset = 2 * kPointerSize;
1201 const int kRecvOffset = 3 * kPointerSize;
1202 const int kFunctionOffset = 4 * kPointerSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001203
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001204 {
1205 FrameScope frame_scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001206
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001207 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function
1208 __ push(r0);
1209 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array
1210 __ push(r0);
1211 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001212
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001213 // Check the stack for overflow. We are not trying to catch
1214 // interruptions (e.g. debug break and preemption) here, so the "real stack
1215 // limit" is checked.
1216 Label okay;
1217 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
1218 // Make r2 the space we have left. The stack might already be overflowed
1219 // here which will cause r2 to become negative.
1220 __ sub(r2, sp, r2);
1221 // Check if the arguments will overflow the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001222 __ cmp(r2, Operand::PointerOffsetFromSmiKey(r0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001223 __ b(gt, &okay); // Signed comparison.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001224
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001225 // Out of stack space.
1226 __ ldr(r1, MemOperand(fp, kFunctionOffset));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001227 __ Push(r1, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001228 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
1229 // End of stack check.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001230
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001231 // Push current limit and index.
1232 __ bind(&okay);
1233 __ push(r0); // limit
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001234 __ mov(r1, Operand::Zero()); // initial index
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001235 __ push(r1);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001236
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001237 // Get the receiver.
1238 __ ldr(r0, MemOperand(fp, kRecvOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001239
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001240 // Check that the function is a JS function (otherwise it must be a proxy).
1241 Label push_receiver;
1242 __ ldr(r1, MemOperand(fp, kFunctionOffset));
1243 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
1244 __ b(ne, &push_receiver);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001245
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 // Change context eagerly to get the right global object if necessary.
1247 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1248 // Load the shared function info while the function is still in r1.
1249 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
lrn@chromium.org34e60782011-09-15 07:25:40 +00001250
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001251 // Compute the receiver.
1252 // Do not transform the receiver for strict mode functions.
1253 Label call_to_object, use_global_receiver;
1254 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
1255 __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
1256 kSmiTagSize)));
1257 __ b(ne, &push_receiver);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001258
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001259 // Do not transform the receiver for strict mode functions.
1260 __ tst(r2, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
1261 __ b(ne, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001262
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001263 // Compute the receiver in non-strict mode.
1264 __ JumpIfSmi(r0, &call_to_object);
1265 __ LoadRoot(r1, Heap::kNullValueRootIndex);
1266 __ cmp(r0, r1);
1267 __ b(eq, &use_global_receiver);
1268 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
1269 __ cmp(r0, r1);
1270 __ b(eq, &use_global_receiver);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001271
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001272 // Check if the receiver is already a JavaScript object.
1273 // r0: receiver
1274 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1275 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
1276 __ b(ge, &push_receiver);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001277
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001278 // Convert the receiver to a regular object.
1279 // r0: receiver
1280 __ bind(&call_to_object);
1281 __ push(r0);
1282 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1283 __ b(&push_receiver);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001284
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 // Use the current global receiver object as the receiver.
1286 __ bind(&use_global_receiver);
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00001287 __ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001288 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001289
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001290 // Push the receiver.
1291 // r0: receiver
1292 __ bind(&push_receiver);
1293 __ push(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001294
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 // Copy all arguments from the array to the stack.
1296 Label entry, loop;
1297 __ ldr(r0, MemOperand(fp, kIndexOffset));
1298 __ b(&entry);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001299
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // Load the current argument from the arguments array and push it to the
1301 // stack.
1302 // r0: current argument index
1303 __ bind(&loop);
1304 __ ldr(r1, MemOperand(fp, kArgsOffset));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001305 __ Push(r1, r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001306
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 // Call the runtime to access the property in the arguments array.
1308 __ CallRuntime(Runtime::kGetProperty, 2);
1309 __ push(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001310
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001311 // Use inline caching to access the arguments.
1312 __ ldr(r0, MemOperand(fp, kIndexOffset));
1313 __ add(r0, r0, Operand(1 << kSmiTagSize));
1314 __ str(r0, MemOperand(fp, kIndexOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001315
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001316 // Test if the copy loop has finished copying all the elements from the
1317 // arguments object.
1318 __ bind(&entry);
1319 __ ldr(r1, MemOperand(fp, kLimitOffset));
1320 __ cmp(r0, r1);
1321 __ b(ne, &loop);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001322
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001323 // Invoke the function.
1324 Label call_proxy;
1325 ParameterCount actual(r0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001326 __ SmiUntag(r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 __ ldr(r1, MemOperand(fp, kFunctionOffset));
1328 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
1329 __ b(ne, &call_proxy);
1330 __ InvokeFunction(r1, actual, CALL_FUNCTION,
1331 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001332
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001333 frame_scope.GenerateLeaveFrame();
1334 __ add(sp, sp, Operand(3 * kPointerSize));
1335 __ Jump(lr);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001336
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001337 // Invoke the function proxy.
1338 __ bind(&call_proxy);
1339 __ push(r1); // add function proxy as last argument
1340 __ add(r0, r0, Operand(1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001341 __ mov(r2, Operand::Zero());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001342 __ SetCallKind(r5, CALL_AS_METHOD);
1343 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
1344 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1345 RelocInfo::CODE_TARGET);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001346
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001347 // Tear down the internal frame and remove function, receiver and args.
1348 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001349 __ add(sp, sp, Operand(3 * kPointerSize));
1350 __ Jump(lr);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001351}
1352
1353
1354static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001355 __ SmiTag(r0);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001356 __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
ulan@chromium.org9ca30172014-01-02 12:10:54 +00001357 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() |
1358 (FLAG_enable_ool_constant_pool ? pp.bit() : 0) |
1359 fp.bit() | lr.bit());
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001360 __ add(fp, sp,
1361 Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001362}
1363
1364
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001366 // ----------- S t a t e -------------
1367 // -- r0 : result being passed through
1368 // -----------------------------------
1369 // Get the number of arguments passed (as a smi), tear down the frame and
1370 // then tear down the parameters.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001371 __ ldr(r1, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1372 kPointerSize)));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001373 __ mov(sp, fp);
1374 __ ldm(ia_w, sp, fp.bit() | lr.bit());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001375 __ add(sp, sp, Operand::PointerOffsetFromSmiKey(r1));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001376 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377}
1378
1379
1380void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001381 // ----------- S t a t e -------------
1382 // -- r0 : actual number of arguments
1383 // -- r1 : function (passed through to callee)
1384 // -- r2 : expected number of arguments
1385 // -- r3 : code entry to call
danno@chromium.org40cb8782011-05-25 07:58:50 +00001386 // -- r5 : call kind information
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001387 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001389 Label invoke, dont_adapt_arguments;
1390
1391 Label enough, too_few;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001392 __ cmp(r0, r2);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001393 __ b(lt, &too_few);
1394 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
1395 __ b(eq, &dont_adapt_arguments);
1396
ager@chromium.org32912102009-01-16 10:38:43 +00001397 { // Enough parameters: actual >= expected
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001398 __ bind(&enough);
1399 EnterArgumentsAdaptorFrame(masm);
1400
1401 // Calculate copy start address into r0 and copy end address into r2.
1402 // r0: actual number of arguments as a smi
1403 // r1: function
1404 // r2: expected number of arguments
1405 // r3: code entry to call
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001406 __ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001407 // adjust for return address and receiver
1408 __ add(r0, r0, Operand(2 * kPointerSize));
1409 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
1410
1411 // Copy the arguments (including the receiver) to the new stack frame.
1412 // r0: copy start address
1413 // r1: function
1414 // r2: copy end address
1415 // r3: code entry to call
1416
1417 Label copy;
1418 __ bind(&copy);
1419 __ ldr(ip, MemOperand(r0, 0));
1420 __ push(ip);
1421 __ cmp(r0, r2); // Compare before moving to next argument.
1422 __ sub(r0, r0, Operand(kPointerSize));
1423 __ b(ne, &copy);
1424
1425 __ b(&invoke);
1426 }
1427
1428 { // Too few parameters: Actual < expected
1429 __ bind(&too_few);
1430 EnterArgumentsAdaptorFrame(masm);
1431
1432 // Calculate copy start address into r0 and copy end address is fp.
1433 // r0: actual number of arguments as a smi
1434 // r1: function
1435 // r2: expected number of arguments
1436 // r3: code entry to call
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001437 __ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001438
1439 // Copy the arguments (including the receiver) to the new stack frame.
1440 // r0: copy start address
1441 // r1: function
1442 // r2: expected number of arguments
1443 // r3: code entry to call
1444 Label copy;
1445 __ bind(&copy);
1446 // Adjust load for return address and receiver.
1447 __ ldr(ip, MemOperand(r0, 2 * kPointerSize));
1448 __ push(ip);
1449 __ cmp(r0, fp); // Compare before moving to next argument.
1450 __ sub(r0, r0, Operand(kPointerSize));
1451 __ b(ne, &copy);
1452
1453 // Fill the remaining expected arguments with undefined.
1454 // r1: function
1455 // r2: expected number of arguments
1456 // r3: code entry to call
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001457 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001458 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001459 // Adjust for frame.
1460 __ sub(r2, r2, Operand(StandardFrameConstants::kFixedFrameSizeFromFp +
1461 2 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001462
1463 Label fill;
1464 __ bind(&fill);
1465 __ push(ip);
1466 __ cmp(sp, r2);
1467 __ b(ne, &fill);
1468 }
1469
1470 // Call the entry point.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001471 __ bind(&invoke);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001472 __ Call(r3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
ulan@chromium.org967e2702012-02-28 09:49:15 +00001474 // Store offset of return address for deoptimizer.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001475 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001476
ager@chromium.org7c537e22008-10-16 08:43:32 +00001477 // Exit frame and return.
1478 LeaveArgumentsAdaptorFrame(masm);
ager@chromium.org9085a012009-05-11 19:22:57 +00001479 __ Jump(lr);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001480
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001481
1482 // -------------------------------------------
1483 // Dont adapt arguments.
1484 // -------------------------------------------
1485 __ bind(&dont_adapt_arguments);
ager@chromium.org9085a012009-05-11 19:22:57 +00001486 __ Jump(r3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487}
1488
1489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490#undef __
1491
1492} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001493
1494#endif // V8_TARGET_ARCH_ARM