blob: e16897a2d28f14cf1a07d7b11f1491b103fc60ee [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_ARM64
6
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/arm64/frames-arm64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/full-codegen/full-codegen.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013
14namespace v8 {
15namespace internal {
16
17
18#define __ ACCESS_MASM(masm)
19
20
21// Load the built-in Array function from the current context.
22static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 // Load the InternalArray function from the native context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025}
26
27
28// Load the built-in InternalArray function from the current context.
29static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
30 Register result) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 // Load the InternalArray function from the native context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 __ LoadNativeContextSlot(Context::INTERNAL_ARRAY_FUNCTION_INDEX, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033}
34
Ben Murdoch61f157c2016-09-16 13:49:30 +010035void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 // ----------- S t a t e -------------
37 // -- x0 : number of arguments excluding receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 // -- x1 : target
39 // -- x3 : new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 // -- sp[0] : last argument
41 // -- ...
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 // -- sp[4 * (argc - 1)] : first argument
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 // -- sp[4 * argc] : receiver
44 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 __ AssertFunction(x1);
46
47 // Make sure we operate in the context of the called function (for example
48 // ConstructStubs implemented in C++ will be run in the context of the caller
49 // instead of the callee, due to the way that [[Construct]] is defined for
50 // ordinary functions).
51 __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052
53 // Insert extra arguments.
Ben Murdoch61f157c2016-09-16 13:49:30 +010054 const int num_extra_args = 2;
55 __ Push(x1, x3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056
57 // JumpToExternalReference expects x0 to contain the number of arguments
58 // including the receiver and the extra arguments.
59 __ Add(x0, x0, num_extra_args + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
62}
63
64
65void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
66 // ----------- S t a t e -------------
67 // -- x0 : number of arguments
68 // -- lr : return address
69 // -- sp[...]: constructor arguments
70 // -----------------------------------
71 ASM_LOCATION("Builtins::Generate_InternalArrayCode");
72 Label generic_array_code;
73
74 // Get the InternalArray function.
75 GenerateLoadInternalArrayFunction(masm, x1);
76
77 if (FLAG_debug_code) {
78 // Initial map for the builtin InternalArray functions should be maps.
79 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
80 __ Tst(x10, kSmiTagMask);
81 __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
82 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
83 __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
84 }
85
86 // Run the native code for the InternalArray function called as a normal
87 // function.
88 InternalArrayConstructorStub stub(masm->isolate());
89 __ TailCallStub(&stub);
90}
91
92
93void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
94 // ----------- S t a t e -------------
95 // -- x0 : number of arguments
96 // -- lr : return address
97 // -- sp[...]: constructor arguments
98 // -----------------------------------
99 ASM_LOCATION("Builtins::Generate_ArrayCode");
100 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
101
102 // Get the Array function.
103 GenerateLoadArrayFunction(masm, x1);
104
105 if (FLAG_debug_code) {
106 // Initial map for the builtin Array functions should be maps.
107 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
108 __ Tst(x10, kSmiTagMask);
109 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
110 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
111 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
112 }
113
114 // Run the native code for the Array function called as a normal function.
115 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 __ Mov(x3, x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 ArrayConstructorStub stub(masm->isolate());
118 __ TailCallStub(&stub);
119}
120
121
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122// static
Ben Murdoch097c5b22016-05-18 11:27:45 +0100123void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
124 // ----------- S t a t e -------------
125 // -- x0 : number of arguments
Ben Murdoch61f157c2016-09-16 13:49:30 +0100126 // -- x1 : function
127 // -- cp : context
Ben Murdoch097c5b22016-05-18 11:27:45 +0100128 // -- lr : return address
129 // -- sp[(argc - n) * 8] : arg[n] (zero-based)
130 // -- sp[(argc + 1) * 8] : receiver
131 // -----------------------------------
132 ASM_LOCATION("Builtins::Generate_MathMaxMin");
133
134 Heap::RootListIndex const root_index =
135 (kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
136 : Heap::kMinusInfinityValueRootIndex;
137
138 // Load the accumulator with the default return value (either -Infinity or
Ben Murdoch61f157c2016-09-16 13:49:30 +0100139 // +Infinity), with the tagged value in x5 and the double value in d5.
140 __ LoadRoot(x5, root_index);
141 __ Ldr(d5, FieldMemOperand(x5, HeapNumber::kValueOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142
143 // Remember how many slots to drop (including the receiver).
144 __ Add(x4, x0, 1);
145
146 Label done_loop, loop;
147 __ Bind(&loop);
148 {
149 // Check if all parameters done.
150 __ Subs(x0, x0, 1);
151 __ B(lt, &done_loop);
152
153 // Load the next parameter tagged value into x2.
154 __ Peek(x2, Operand(x0, LSL, kPointerSizeLog2));
155
156 // Load the double value of the parameter into d2, maybe converting the
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157 // parameter to a number first using the ToNumber builtin if necessary.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 Label convert_smi, convert_number, done_convert;
159 __ JumpIfSmi(x2, &convert_smi);
160 __ JumpIfHeapNumber(x2, &convert_number);
161 {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100162 // Parameter is not a Number, use the ToNumber builtin to convert it.
163 FrameScope scope(masm, StackFrame::MANUAL);
164 __ Push(lr, fp);
165 __ Move(fp, jssp);
166 __ Push(cp, x1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 __ SmiTag(x0);
168 __ SmiTag(x4);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100169 __ Push(x0, x5, x4);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100170 __ Mov(x0, x2);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100171 __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100172 __ Mov(x2, x0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100173 __ Pop(x4, x5, x0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100174 {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100175 // Restore the double accumulator value (d5).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100176 Label done_restore;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100177 __ SmiUntagToDouble(d5, x5, kSpeculativeUntag);
178 __ JumpIfSmi(x5, &done_restore);
179 __ Ldr(d5, FieldMemOperand(x5, HeapNumber::kValueOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100180 __ Bind(&done_restore);
181 }
182 __ SmiUntag(x4);
183 __ SmiUntag(x0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100184 __ Pop(x1, cp, fp, lr);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100185 }
186 __ AssertNumber(x2);
187 __ JumpIfSmi(x2, &convert_smi);
188
189 __ Bind(&convert_number);
190 __ Ldr(d2, FieldMemOperand(x2, HeapNumber::kValueOffset));
191 __ B(&done_convert);
192
193 __ Bind(&convert_smi);
194 __ SmiUntagToDouble(d2, x2);
195 __ Bind(&done_convert);
196
197 // We can use a single fmin/fmax for the operation itself, but we then need
198 // to work out which HeapNumber (or smi) the result came from.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100199 __ Fmov(x11, d5);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100200 if (kind == MathMaxMinKind::kMin) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100201 __ Fmin(d5, d5, d2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100202 } else {
203 DCHECK(kind == MathMaxMinKind::kMax);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100204 __ Fmax(d5, d5, d2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100205 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100206 __ Fmov(x10, d5);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 __ Cmp(x10, x11);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100208 __ Csel(x5, x5, x2, eq);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209 __ B(&loop);
210 }
211
212 __ Bind(&done_loop);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100213 __ Drop(x4);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100214 __ Mov(x0, x5);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100215 __ Ret();
216}
217
218// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 // ----------- S t a t e -------------
221 // -- x0 : number of arguments
222 // -- x1 : constructor function
223 // -- lr : return address
224 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
225 // -- sp[argc * 8] : receiver
226 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 ASM_LOCATION("Builtins::Generate_NumberConstructor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 // 1. Load the first argument into x0 and get rid of the rest (including the
230 // receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 Label no_arguments;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 {
233 __ Cbz(x0, &no_arguments);
234 __ Sub(x0, x0, 1);
235 __ Drop(x0);
236 __ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 // 2a. Convert first argument to number.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100240 __ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 // 2b. No arguments, return +0 (already in x0).
243 __ Bind(&no_arguments);
244 __ Drop(1);
245 __ Ret();
246}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249// static
250void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
251 // ----------- S t a t e -------------
252 // -- x0 : number of arguments
253 // -- x1 : constructor function
254 // -- x3 : new target
255 // -- lr : return address
256 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
257 // -- sp[argc * 8] : receiver
258 // -----------------------------------
259 ASM_LOCATION("Builtins::Generate_NumberConstructor_ConstructStub");
260
261 // 1. Make sure we operate in the context of the called function.
262 __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
263
264 // 2. Load the first argument into x2 and get rid of the rest (including the
265 // receiver).
266 {
267 Label no_arguments, done;
268 __ Cbz(x0, &no_arguments);
269 __ Sub(x0, x0, 1);
270 __ Drop(x0);
271 __ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
272 __ B(&done);
273 __ Bind(&no_arguments);
274 __ Drop(1);
275 __ Mov(x2, Smi::FromInt(0));
276 __ Bind(&done);
277 }
278
279 // 3. Make sure x2 is a number.
280 {
281 Label done_convert;
282 __ JumpIfSmi(x2, &done_convert);
283 __ JumpIfObjectType(x2, x4, x4, HEAP_NUMBER_TYPE, &done_convert, eq);
284 {
285 FrameScope scope(masm, StackFrame::INTERNAL);
286 __ Push(x1, x3);
287 __ Move(x0, x2);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100288 __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 __ Move(x2, x0);
290 __ Pop(x3, x1);
291 }
292 __ Bind(&done_convert);
293 }
294
295 // 4. Check if new target and constructor differ.
296 Label new_object;
297 __ Cmp(x1, x3);
298 __ B(ne, &new_object);
299
300 // 5. Allocate a JSValue wrapper for the number.
301 __ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 __ Ret();
303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 // 6. Fallback to the runtime to create new object.
305 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 {
307 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100308 __ Push(x2); // first argument
309 FastNewObjectStub stub(masm->isolate());
310 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 __ Pop(x2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
314 __ Ret();
315}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317
318// static
319void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
320 // ----------- S t a t e -------------
321 // -- x0 : number of arguments
322 // -- x1 : constructor function
323 // -- lr : return address
324 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
325 // -- sp[argc * 8] : receiver
326 // -----------------------------------
327 ASM_LOCATION("Builtins::Generate_StringConstructor");
328
329 // 1. Load the first argument into x0 and get rid of the rest (including the
330 // receiver).
331 Label no_arguments;
332 {
333 __ Cbz(x0, &no_arguments);
334 __ Sub(x0, x0, 1);
335 __ Drop(x0);
336 __ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
337 }
338
339 // 2a. At least one argument, return x0 if it's a string, otherwise
340 // dispatch to appropriate conversion.
341 Label to_string, symbol_descriptive_string;
342 {
343 __ JumpIfSmi(x0, &to_string);
344 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
345 __ CompareObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE);
346 __ B(hi, &to_string);
347 __ B(eq, &symbol_descriptive_string);
348 __ Ret();
349 }
350
351 // 2b. No arguments, return the empty string (and pop the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 __ Bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 {
354 __ LoadRoot(x0, Heap::kempty_stringRootIndex);
355 __ Drop(1);
356 __ Ret();
357 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 // 3a. Convert x0 to a string.
360 __ Bind(&to_string);
361 {
362 ToStringStub stub(masm->isolate());
363 __ TailCallStub(&stub);
364 }
365
366 // 3b. Convert symbol in x0 to a string.
367 __ Bind(&symbol_descriptive_string);
368 {
369 __ Push(x0);
370 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
371 }
372}
373
374
375// static
376void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
377 // ----------- S t a t e -------------
378 // -- x0 : number of arguments
379 // -- x1 : constructor function
380 // -- x3 : new target
381 // -- lr : return address
382 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
383 // -- sp[argc * 8] : receiver
384 // -----------------------------------
385 ASM_LOCATION("Builtins::Generate_StringConstructor_ConstructStub");
386
387 // 1. Make sure we operate in the context of the called function.
388 __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
389
390 // 2. Load the first argument into x2 and get rid of the rest (including the
391 // receiver).
392 {
393 Label no_arguments, done;
394 __ Cbz(x0, &no_arguments);
395 __ Sub(x0, x0, 1);
396 __ Drop(x0);
397 __ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
398 __ B(&done);
399 __ Bind(&no_arguments);
400 __ Drop(1);
401 __ LoadRoot(x2, Heap::kempty_stringRootIndex);
402 __ Bind(&done);
403 }
404
405 // 3. Make sure x2 is a string.
406 {
407 Label convert, done_convert;
408 __ JumpIfSmi(x2, &convert);
409 __ JumpIfObjectType(x2, x4, x4, FIRST_NONSTRING_TYPE, &done_convert, lo);
410 __ Bind(&convert);
411 {
412 FrameScope scope(masm, StackFrame::INTERNAL);
413 ToStringStub stub(masm->isolate());
414 __ Push(x1, x3);
415 __ Move(x0, x2);
416 __ CallStub(&stub);
417 __ Move(x2, x0);
418 __ Pop(x3, x1);
419 }
420 __ Bind(&done_convert);
421 }
422
423 // 4. Check if new target and constructor differ.
424 Label new_object;
425 __ Cmp(x1, x3);
426 __ B(ne, &new_object);
427
428 // 5. Allocate a JSValue wrapper for the string.
429 __ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
430 __ Ret();
431
432 // 6. Fallback to the runtime to create new object.
433 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 {
435 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100436 __ Push(x2); // first argument
437 FastNewObjectStub stub(masm->isolate());
438 __ CallStub(&stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 __ Pop(x2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 __ Ret();
443}
444
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
446 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
447 __ Ldr(x2, FieldMemOperand(x2, SharedFunctionInfo::kCodeOffset));
448 __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
449 __ Br(x2);
450}
451
Ben Murdoch097c5b22016-05-18 11:27:45 +0100452static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
453 Runtime::FunctionId function_id) {
454 // ----------- S t a t e -------------
455 // -- x0 : argument count (preserved for callee)
456 // -- x1 : target function (preserved for callee)
457 // -- x3 : new target (preserved for callee)
458 // -----------------------------------
459 {
460 FrameScope scope(masm, StackFrame::INTERNAL);
461 // Push a copy of the target function and the new target.
462 // Push another copy as a parameter to the runtime call.
463 __ SmiTag(x0);
464 __ Push(x0, x1, x3, x1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465
Ben Murdoch097c5b22016-05-18 11:27:45 +0100466 __ CallRuntime(function_id, 1);
467 __ Move(x2, x0);
468
469 // Restore target function and new target.
470 __ Pop(x3, x1, x0);
471 __ SmiUntag(x0);
472 }
473
474 __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
475 __ Br(x2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476}
477
478
479void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
480 // Checking whether the queued function is ready for install is optional,
481 // since we come across interrupts and stack checks elsewhere. However, not
482 // checking may delay installing ready functions, and always checking would be
483 // quite expensive. A good compromise is to first check against stack limit as
484 // a cue for an interrupt signal.
485 Label ok;
486 __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
487 __ B(hs, &ok);
488
Ben Murdoch097c5b22016-05-18 11:27:45 +0100489 GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490
491 __ Bind(&ok);
492 GenerateTailCallToSharedCode(masm);
493}
494
495
496static void Generate_JSConstructStubHelper(MacroAssembler* masm,
497 bool is_api_function,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100498 bool create_implicit_receiver,
499 bool check_derived_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 // ----------- S t a t e -------------
501 // -- x0 : number of arguments
502 // -- x1 : constructor function
503 // -- x2 : allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504 // -- x3 : new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505 // -- lr : return address
Ben Murdochda12d292016-06-02 14:46:10 +0100506 // -- cp : context pointer
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000507 // -- sp[...]: constructor arguments
508 // -----------------------------------
509
510 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511
512 Isolate* isolate = masm->isolate();
513
514 // Enter a construct frame.
515 {
516 FrameScope scope(masm, StackFrame::CONSTRUCT);
517
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 // Preserve the four incoming parameters on the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 Register argc = x0;
520 Register constructor = x1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 Register allocation_site = x2;
522 Register new_target = x3;
523
524 // Preserve the incoming parameters on the stack.
525 __ AssertUndefinedOrAllocationSite(allocation_site, x10);
Ben Murdochda12d292016-06-02 14:46:10 +0100526 __ Push(cp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 __ SmiTag(argc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 __ Push(allocation_site, argc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 if (create_implicit_receiver) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100531 // Allocate the new receiver object.
532 __ Push(constructor, new_target);
533 FastNewObjectStub stub(masm->isolate());
534 __ CallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 __ Mov(x4, x0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 __ Pop(new_target, constructor);
537
Ben Murdoch097c5b22016-05-18 11:27:45 +0100538 // ----------- S t a t e -------------
539 // -- x1: constructor function
540 // -- x3: new target
541 // -- x4: newly allocated object
542 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543
544 // Reload the number of arguments from the stack.
545 // Set it up in x0 for the function call below.
546 // jssp[0]: number of arguments (smi-tagged)
547 __ Peek(argc, 0); // Load number of arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 }
549
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 __ SmiUntag(argc);
551
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 if (create_implicit_receiver) {
553 // Push the allocated receiver to the stack. We need two copies
554 // because we may have to return the original one and the calling
555 // conventions dictate that the called function pops the receiver.
556 __ Push(x4, x4);
557 } else {
558 __ PushRoot(Heap::kTheHoleValueRootIndex);
559 }
560
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 // Set up pointer to last argument.
562 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
563
564 // Copy arguments and receiver to the expression stack.
565 // Copy 2 values every loop to use ldp/stp.
566 // x0: number of arguments
567 // x1: constructor function
568 // x2: address of last argument (caller sp)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 // x3: new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 // jssp[0]: receiver
571 // jssp[1]: receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000572 // jssp[2]: number of arguments (smi-tagged)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 // Compute the start address of the copy in x3.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 __ Add(x4, x2, Operand(argc, LSL, kPointerSizeLog2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 Label loop, entry, done_copying_arguments;
576 __ B(&entry);
577 __ Bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578 __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 __ Push(x11, x10);
580 __ Bind(&entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 __ Cmp(x4, x2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 __ B(gt, &loop);
583 // Because we copied values 2 by 2 we may have copied one extra value.
584 // Drop it if that is the case.
585 __ B(eq, &done_copying_arguments);
586 __ Drop(1);
587 __ Bind(&done_copying_arguments);
588
589 // Call the function.
590 // x0: number of arguments
591 // x1: constructor function
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 // x3: new target
Ben Murdochc5610432016-08-08 18:44:38 +0100593 ParameterCount actual(argc);
594 __ InvokeFunction(constructor, new_target, actual, CALL_FUNCTION,
595 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596
597 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 if (create_implicit_receiver && !is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
600 }
601
602 // Restore the context from the frame.
603 // x0: result
604 // jssp[0]: receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 // jssp[1]: number of arguments (smi-tagged)
Ben Murdochda12d292016-06-02 14:46:10 +0100606 __ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 if (create_implicit_receiver) {
609 // If the result is an object (in the ECMA sense), we should get rid
610 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
611 // on page 74.
612 Label use_receiver, exit;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 // If the result is a smi, it is *not* an object in the ECMA sense.
615 // x0: result
616 // jssp[0]: receiver (newly allocated object)
617 // jssp[1]: number of arguments (smi-tagged)
618 __ JumpIfSmi(x0, &use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 // If the type of the result (stored in its map) is less than
621 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
622 __ JumpIfObjectType(x0, x1, x3, FIRST_JS_RECEIVER_TYPE, &exit, ge);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000624 // Throw away the result of the constructor invocation and use the
625 // on-stack receiver as the result.
626 __ Bind(&use_receiver);
627 __ Peek(x0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 // Remove the receiver from the stack, remove caller arguments, and
630 // return.
631 __ Bind(&exit);
632 // x0: result
633 // jssp[0]: receiver (newly allocated object)
634 // jssp[1]: number of arguments (smi-tagged)
635 __ Peek(x1, 1 * kXRegSize);
636 } else {
637 __ Peek(x1, 0);
638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639
640 // Leave construct frame.
641 }
642
Ben Murdoch097c5b22016-05-18 11:27:45 +0100643 // ES6 9.2.2. Step 13+
644 // Check that the result is not a Smi, indicating that the constructor result
645 // from a derived class is neither undefined nor an Object.
646 if (check_derived_construct) {
647 Label dont_throw;
648 __ JumpIfNotSmi(x0, &dont_throw);
649 {
650 FrameScope scope(masm, StackFrame::INTERNAL);
651 __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
652 }
653 __ Bind(&dont_throw);
654 }
655
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 __ DropBySMI(x1);
657 __ Drop(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 if (create_implicit_receiver) {
659 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661 __ Ret();
662}
663
664
665void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100666 Generate_JSConstructStubHelper(masm, false, true, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667}
668
669
670void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100671 Generate_JSConstructStubHelper(masm, true, false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672}
673
674
675void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100676 Generate_JSConstructStubHelper(masm, false, false, false);
677}
678
679
680void Builtins::Generate_JSBuiltinsConstructStubForDerived(
681 MacroAssembler* masm) {
682 Generate_JSConstructStubHelper(masm, false, false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683}
684
685
686void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
687 FrameScope scope(masm, StackFrame::INTERNAL);
688 __ Push(x1);
689 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
690}
691
Ben Murdochc5610432016-08-08 18:44:38 +0100692// static
693void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
694 // ----------- S t a t e -------------
695 // -- x0 : the value to pass to the generator
696 // -- x1 : the JSGeneratorObject to resume
697 // -- x2 : the resume mode (tagged)
698 // -- lr : return address
699 // -----------------------------------
700 __ AssertGeneratorObject(x1);
701
702 // Store input value into generator object.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100703 __ Str(x0, FieldMemOperand(x1, JSGeneratorObject::kInputOrDebugPosOffset));
704 __ RecordWriteField(x1, JSGeneratorObject::kInputOrDebugPosOffset, x0, x3,
Ben Murdochc5610432016-08-08 18:44:38 +0100705 kLRHasNotBeenSaved, kDontSaveFPRegs);
706
707 // Store resume mode into generator object.
708 __ Str(x2, FieldMemOperand(x1, JSGeneratorObject::kResumeModeOffset));
709
710 // Load suspended function and context.
711 __ Ldr(cp, FieldMemOperand(x1, JSGeneratorObject::kContextOffset));
712 __ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
713
714 // Flood function if we are stepping.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100715 Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator;
716 Label stepping_prepared;
717 ExternalReference last_step_action =
718 ExternalReference::debug_last_step_action_address(masm->isolate());
719 STATIC_ASSERT(StepFrame > StepIn);
720 __ Mov(x10, Operand(last_step_action));
721 __ Ldrsb(x10, MemOperand(x10));
722 __ CompareAndBranch(x10, Operand(StepIn), ge, &prepare_step_in_if_stepping);
723
724 // Flood function if we need to continue stepping in the suspended generator.
725 ExternalReference debug_suspended_generator =
726 ExternalReference::debug_suspended_generator_address(masm->isolate());
727 __ Mov(x10, Operand(debug_suspended_generator));
728 __ Ldr(x10, MemOperand(x10));
729 __ CompareAndBranch(x10, Operand(x1), eq,
730 &prepare_step_in_suspended_generator);
731 __ Bind(&stepping_prepared);
Ben Murdochc5610432016-08-08 18:44:38 +0100732
733 // Push receiver.
734 __ Ldr(x5, FieldMemOperand(x1, JSGeneratorObject::kReceiverOffset));
735 __ Push(x5);
736
737 // ----------- S t a t e -------------
738 // -- x1 : the JSGeneratorObject to resume
739 // -- x2 : the resume mode (tagged)
740 // -- x4 : generator function
741 // -- cp : generator context
742 // -- lr : return address
743 // -- jssp[0] : generator receiver
744 // -----------------------------------
745
746 // Push holes for arguments to generator function. Since the parser forced
747 // context allocation for any variables in generators, the actual argument
748 // values have already been copied into the context and these dummy values
749 // will never be used.
750 __ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
751 __ Ldr(w10,
752 FieldMemOperand(x10, SharedFunctionInfo::kFormalParameterCountOffset));
753 __ LoadRoot(x11, Heap::kTheHoleValueRootIndex);
754 __ PushMultipleTimes(x11, w10);
755
756 // Dispatch on the kind of generator object.
757 Label old_generator;
758 __ Ldr(x3, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
759 __ Ldr(x3, FieldMemOperand(x3, SharedFunctionInfo::kFunctionDataOffset));
760 __ CompareObjectType(x3, x3, x3, BYTECODE_ARRAY_TYPE);
761 __ B(ne, &old_generator);
762
763 // New-style (ignition/turbofan) generator object
764 {
765 __ Ldr(x0, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100766 __ Ldr(w0,
Ben Murdochc5610432016-08-08 18:44:38 +0100767 FieldMemOperand(x0, SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochc5610432016-08-08 18:44:38 +0100768 // We abuse new.target both to indicate that this is a resume call and to
769 // pass in the generator object. In ordinary calls, new.target is always
770 // undefined because generator functions are non-constructable.
771 __ Move(x3, x1);
772 __ Move(x1, x4);
773 __ Ldr(x5, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
774 __ Jump(x5);
775 }
776
777 // Old-style (full-codegen) generator object
778 __ bind(&old_generator);
779 {
780 // Enter a new JavaScript frame, and initialize its slots as they were when
781 // the generator was suspended.
782 FrameScope scope(masm, StackFrame::MANUAL);
783 __ Push(lr, fp);
784 __ Move(fp, jssp);
785 __ Push(cp, x4);
786
787 // Restore the operand stack.
788 __ Ldr(x0, FieldMemOperand(x1, JSGeneratorObject::kOperandStackOffset));
789 __ Ldr(w3, UntagSmiFieldMemOperand(x0, FixedArray::kLengthOffset));
790 __ Add(x0, x0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
791 __ Add(x3, x0, Operand(x3, LSL, kPointerSizeLog2));
792 {
793 Label done_loop, loop;
794 __ Bind(&loop);
795 __ Cmp(x0, x3);
796 __ B(eq, &done_loop);
797 __ Ldr(x10, MemOperand(x0, kPointerSize, PostIndex));
798 __ Push(x10);
799 __ B(&loop);
800 __ Bind(&done_loop);
801 }
802
803 // Reset operand stack so we don't leak.
804 __ LoadRoot(x10, Heap::kEmptyFixedArrayRootIndex);
805 __ Str(x10, FieldMemOperand(x1, JSGeneratorObject::kOperandStackOffset));
806
807 // Resume the generator function at the continuation.
808 __ Ldr(x10, FieldMemOperand(x4, JSFunction::kSharedFunctionInfoOffset));
809 __ Ldr(x10, FieldMemOperand(x10, SharedFunctionInfo::kCodeOffset));
810 __ Add(x10, x10, Code::kHeaderSize - kHeapObjectTag);
811 __ Ldrsw(x11,
812 UntagSmiFieldMemOperand(x1, JSGeneratorObject::kContinuationOffset));
813 __ Add(x10, x10, x11);
814 __ Mov(x12, Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
815 __ Str(x12, FieldMemOperand(x1, JSGeneratorObject::kContinuationOffset));
816 __ Move(x0, x1); // Continuation expects generator object in x0.
817 __ Br(x10);
818 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100819
820 __ Bind(&prepare_step_in_if_stepping);
821 {
822 FrameScope scope(masm, StackFrame::INTERNAL);
823 __ Push(x1, x2, x4);
824 __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
825 __ Pop(x2, x1);
826 __ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
827 }
828 __ B(&stepping_prepared);
829
830 __ Bind(&prepare_step_in_suspended_generator);
831 {
832 FrameScope scope(masm, StackFrame::INTERNAL);
833 __ Push(x1, x2);
834 __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator);
835 __ Pop(x2, x1);
836 __ Ldr(x4, FieldMemOperand(x1, JSGeneratorObject::kFunctionOffset));
837 }
838 __ B(&stepping_prepared);
Ben Murdochc5610432016-08-08 18:44:38 +0100839}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000840
841enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt };
842
843
844// Clobbers x10, x15; preserves all other registers.
845static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
846 IsTagged argc_is_tagged) {
847 // Check the stack for overflow.
848 // We are not trying to catch interruptions (e.g. debug break and
849 // preemption) here, so the "real stack limit" is checked.
850 Label enough_stack_space;
851 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
852 // Make x10 the space we have left. The stack might already be overflowed
853 // here which will cause x10 to become negative.
854 // TODO(jbramley): Check that the stack usage here is safe.
855 __ Sub(x10, jssp, x10);
856 // Check if the arguments will overflow the stack.
857 if (argc_is_tagged == kArgcIsSmiTagged) {
858 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
859 } else {
860 DCHECK(argc_is_tagged == kArgcIsUntaggedInt);
861 __ Cmp(x10, Operand(argc, LSL, kPointerSizeLog2));
862 }
863 __ B(gt, &enough_stack_space);
864 __ CallRuntime(Runtime::kThrowStackOverflow);
865 // We should never return from the APPLY_OVERFLOW builtin.
866 if (__ emit_debug_code()) {
867 __ Unreachable();
868 }
869
870 __ Bind(&enough_stack_space);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871}
872
873
874// Input:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875// x0: new.target.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000876// x1: function.
877// x2: receiver.
878// x3: argc.
879// x4: argv.
880// Output:
881// x0: result.
882static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
883 bool is_construct) {
884 // Called from JSEntryStub::GenerateBody().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885 Register new_target = x0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000886 Register function = x1;
887 Register receiver = x2;
888 Register argc = x3;
889 Register argv = x4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 Register scratch = x10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891
892 ProfileEntryHookStub::MaybeCallEntryHook(masm);
893
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000894 {
895 // Enter an internal frame.
896 FrameScope scope(masm, StackFrame::INTERNAL);
897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 // Setup the context (we need to use the caller context from the isolate).
899 __ Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
900 masm->isolate())));
901 __ Ldr(cp, MemOperand(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902
903 __ InitializeRootRegister();
904
905 // Push the function and the receiver onto the stack.
906 __ Push(function, receiver);
907
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 // Check if we have enough stack space to push all arguments.
909 // Expects argument count in eax. Clobbers ecx, edx, edi.
910 Generate_CheckStackOverflow(masm, argc, kArgcIsUntaggedInt);
911
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 // Copy arguments to the stack in a loop, in reverse order.
913 // x3: argc.
914 // x4: argv.
915 Label loop, entry;
916 // Compute the copy end address.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917 __ Add(scratch, argv, Operand(argc, LSL, kPointerSizeLog2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918
919 __ B(&entry);
920 __ Bind(&loop);
921 __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
922 __ Ldr(x12, MemOperand(x11)); // Dereference the handle.
923 __ Push(x12); // Push the argument.
924 __ Bind(&entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000925 __ Cmp(scratch, argv);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926 __ B(ne, &loop);
927
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000928 __ Mov(scratch, argc);
929 __ Mov(argc, new_target);
930 __ Mov(new_target, scratch);
931 // x0: argc.
932 // x3: new.target.
933
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 // Initialize all JavaScript callee-saved registers, since they will be seen
935 // by the garbage collector as part of handlers.
936 // The original values have been saved in JSEntryStub::GenerateBody().
937 __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
938 __ Mov(x20, x19);
939 __ Mov(x21, x19);
940 __ Mov(x22, x19);
941 __ Mov(x23, x19);
942 __ Mov(x24, x19);
943 __ Mov(x25, x19);
944 // Don't initialize the reserved registers.
945 // x26 : root register (root).
946 // x27 : context pointer (cp).
947 // x28 : JS stack pointer (jssp).
948 // x29 : frame pointer (fp).
949
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000950 Handle<Code> builtin = is_construct
951 ? masm->isolate()->builtins()->Construct()
952 : masm->isolate()->builtins()->Call();
953 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000954
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 // Exit the JS internal frame and remove the parameters (except function),
956 // and return.
957 }
958
959 // Result is in x0. Return.
960 __ Ret();
961}
962
963
964void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
965 Generate_JSEntryTrampolineHelper(masm, false);
966}
967
968
969void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
970 Generate_JSEntryTrampolineHelper(masm, true);
971}
972
Ben Murdoch61f157c2016-09-16 13:49:30 +0100973static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) {
974 Register args_count = scratch;
975
976 // Get the arguments + receiver count.
977 __ ldr(args_count,
978 MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
979 __ Ldr(args_count.W(),
980 FieldMemOperand(args_count, BytecodeArray::kParameterSizeOffset));
981
982 // Leave the frame (also dropping the register file).
983 __ LeaveFrame(StackFrame::JAVA_SCRIPT);
984
985 // Drop receiver + arguments.
986 __ Drop(args_count, 1);
987}
988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989// Generate code for entering a JS function with the interpreter.
990// On entry to the function the receiver and arguments have been pushed on the
991// stack left to right. The actual argument count matches the formal parameter
992// count expected by the function.
993//
994// The live registers are:
995// - x1: the JS function object being called.
996// - x3: the new target
997// - cp: our context.
998// - fp: our caller's frame pointer.
999// - jssp: stack pointer.
1000// - lr: return address.
1001//
Ben Murdoch097c5b22016-05-18 11:27:45 +01001002// The function builds an interpreter frame. See InterpreterFrameConstants in
1003// frames.h for its layout.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001004void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
Ben Murdochc5610432016-08-08 18:44:38 +01001005 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001007 // Open a frame scope to indicate that there is a frame on the stack. The
1008 // MANUAL indicates that the scope shouldn't actually generate code to set up
1009 // the frame (that is done below).
1010 FrameScope frame_scope(masm, StackFrame::MANUAL);
1011 __ Push(lr, fp, cp, x1);
1012 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001013
Ben Murdochc5610432016-08-08 18:44:38 +01001014 // Get the bytecode array from the function object (or from the DebugInfo if
1015 // it is present) and load it into kInterpreterBytecodeArrayRegister.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001016 __ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001017 Register debug_info = kInterpreterBytecodeArrayRegister;
1018 Label load_debug_bytecode_array, bytecode_array_loaded;
1019 DCHECK(!debug_info.is(x0));
1020 __ Ldr(debug_info, FieldMemOperand(x0, SharedFunctionInfo::kDebugInfoOffset));
1021 __ Cmp(debug_info, Operand(DebugInfo::uninitialized()));
1022 __ B(ne, &load_debug_bytecode_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001023 __ Ldr(kInterpreterBytecodeArrayRegister,
1024 FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001025 __ Bind(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001026
Ben Murdochc5610432016-08-08 18:44:38 +01001027 // Check function data field is actually a BytecodeArray object.
1028 Label bytecode_array_not_present;
1029 __ CompareRoot(kInterpreterBytecodeArrayRegister,
1030 Heap::kUndefinedValueRootIndex);
1031 __ B(eq, &bytecode_array_not_present);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001032 if (FLAG_debug_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001033 __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
1034 kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
1035 __ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
1036 BYTECODE_ARRAY_TYPE);
1037 __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
1038 }
1039
Ben Murdochc5610432016-08-08 18:44:38 +01001040 // Load the initial bytecode offset.
1041 __ Mov(kInterpreterBytecodeOffsetRegister,
1042 Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
1043
1044 // Push new.target, bytecode array and Smi tagged bytecode array offset.
1045 __ SmiTag(x0, kInterpreterBytecodeOffsetRegister);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001046 __ Push(x3, kInterpreterBytecodeArrayRegister, x0);
1047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048 // Allocate the local and temporary register file on the stack.
1049 {
1050 // Load frame size from the BytecodeArray object.
1051 __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister,
1052 BytecodeArray::kFrameSizeOffset));
1053
1054 // Do a stack check to ensure we don't go over the limit.
1055 Label ok;
1056 DCHECK(jssp.Is(__ StackPointer()));
1057 __ Sub(x10, jssp, Operand(x11));
1058 __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
1059 __ B(hs, &ok);
1060 __ CallRuntime(Runtime::kThrowStackOverflow);
1061 __ Bind(&ok);
1062
1063 // If ok, push undefined as the initial value for all register file entries.
1064 // Note: there should always be at least one stack slot for the return
1065 // register in the register file.
1066 Label loop_header;
1067 __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
1068 // TODO(rmcilroy): Ensure we always have an even number of registers to
1069 // allow stack to be 16 bit aligned (and remove need for jssp).
1070 __ Lsr(x11, x11, kPointerSizeLog2);
1071 __ PushMultipleTimes(x10, x11);
1072 __ Bind(&loop_header);
1073 }
1074
Ben Murdochc5610432016-08-08 18:44:38 +01001075 // Load accumulator and dispatch table into registers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001077 __ Mov(kInterpreterDispatchTableRegister,
1078 Operand(ExternalReference::interpreter_dispatch_table_address(
1079 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080
1081 // Dispatch to the first bytecode handler for the function.
1082 __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
1083 kInterpreterBytecodeOffsetRegister));
1084 __ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
1085 __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001086 __ Call(ip0);
Ben Murdochc5610432016-08-08 18:44:38 +01001087 masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001088
Ben Murdochc5610432016-08-08 18:44:38 +01001089 // The return value is in x0.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001090 LeaveInterpreterFrame(masm, x2);
Ben Murdochc5610432016-08-08 18:44:38 +01001091 __ Ret();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001092
1093 // Load debug copy of the bytecode array.
1094 __ Bind(&load_debug_bytecode_array);
1095 __ Ldr(kInterpreterBytecodeArrayRegister,
1096 FieldMemOperand(debug_info, DebugInfo::kAbstractCodeIndex));
1097 __ B(&bytecode_array_loaded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098
Ben Murdochc5610432016-08-08 18:44:38 +01001099 // If the bytecode array is no longer present, then the underlying function
1100 // has been switched to a different kind of code and we heal the closure by
1101 // switching the code entry field over to the new code object as well.
1102 __ Bind(&bytecode_array_not_present);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103 __ LeaveFrame(StackFrame::JAVA_SCRIPT);
Ben Murdochc5610432016-08-08 18:44:38 +01001104 __ Ldr(x7, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
1105 __ Ldr(x7, FieldMemOperand(x7, SharedFunctionInfo::kCodeOffset));
1106 __ Add(x7, x7, Operand(Code::kHeaderSize - kHeapObjectTag));
1107 __ Str(x7, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
1108 __ RecordWriteCodeEntryField(x1, x7, x5);
1109 __ Jump(x7);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110}
1111
Ben Murdoch61f157c2016-09-16 13:49:30 +01001112void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
1113 // Save the function and context for call to CompileBaseline.
1114 __ ldr(x1, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
1115 __ ldr(kContextRegister,
1116 MemOperand(fp, StandardFrameConstants::kContextOffset));
1117
1118 // Leave the frame before recompiling for baseline so that we don't count as
1119 // an activation on the stack.
1120 LeaveInterpreterFrame(masm, x2);
1121
1122 {
1123 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1124 // Push return value.
1125 __ push(x0);
1126
1127 // Push function as argument and compile for baseline.
1128 __ push(x1);
1129 __ CallRuntime(Runtime::kCompileBaseline);
1130
1131 // Restore return value.
1132 __ pop(x0);
1133 }
1134 __ Ret();
1135}
1136
Ben Murdochc5610432016-08-08 18:44:38 +01001137// static
1138void Builtins::Generate_InterpreterPushArgsAndCallImpl(
1139 MacroAssembler* masm, TailCallMode tail_call_mode) {
1140 // ----------- S t a t e -------------
1141 // -- x0 : the number of arguments (not including the receiver)
1142 // -- x2 : the address of the first argument to be pushed. Subsequent
1143 // arguments should be consecutive above this, in the same order as
1144 // they are to be pushed onto the stack.
1145 // -- x1 : the target to call (can be any Object).
1146 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001147
Ben Murdochc5610432016-08-08 18:44:38 +01001148 // Find the address of the last argument.
1149 __ add(x3, x0, Operand(1)); // Add one for receiver.
1150 __ lsl(x3, x3, kPointerSizeLog2);
1151 __ sub(x4, x2, x3);
1152
1153 // Push the arguments.
1154 Label loop_header, loop_check;
1155 __ Mov(x5, jssp);
1156 __ Claim(x3, 1);
1157 __ B(&loop_check);
1158 __ Bind(&loop_header);
1159 // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
1160 __ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
1161 __ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
1162 __ Bind(&loop_check);
1163 __ Cmp(x2, x4);
1164 __ B(gt, &loop_header);
1165
1166 // Call the target.
1167 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
1168 tail_call_mode),
1169 RelocInfo::CODE_TARGET);
1170}
1171
1172// static
1173void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
1174 // ----------- S t a t e -------------
1175 // -- x0 : argument count (not including receiver)
1176 // -- x3 : new target
1177 // -- x1 : constructor to call
1178 // -- x2 : address of the first argument
1179 // -----------------------------------
1180
1181 // Find the address of the last argument.
1182 __ add(x5, x0, Operand(1)); // Add one for receiver (to be constructed).
1183 __ lsl(x5, x5, kPointerSizeLog2);
1184
1185 // Set stack pointer and where to stop.
1186 __ Mov(x6, jssp);
1187 __ Claim(x5, 1);
1188 __ sub(x4, x6, x5);
1189
1190 // Push a slot for the receiver.
1191 __ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
1192
1193 Label loop_header, loop_check;
1194 // Push the arguments.
1195 __ B(&loop_check);
1196 __ Bind(&loop_header);
1197 // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
1198 __ Ldr(x5, MemOperand(x2, -kPointerSize, PostIndex));
1199 __ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
1200 __ Bind(&loop_check);
1201 __ Cmp(x6, x4);
1202 __ B(gt, &loop_header);
1203
1204 // Call the constructor with x0, x1, and x3 unmodified.
1205 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1206}
1207
1208void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
1209 // Set the return address to the correct point in the interpreter entry
1210 // trampoline.
1211 Smi* interpreter_entry_return_pc_offset(
1212 masm->isolate()->heap()->interpreter_entry_return_pc_offset());
1213 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0));
1214 __ LoadObject(x1, masm->isolate()->builtins()->InterpreterEntryTrampoline());
1215 __ Add(lr, x1, Operand(interpreter_entry_return_pc_offset->value() +
1216 Code::kHeaderSize - kHeapObjectTag));
1217
1218 // Initialize the dispatch table register.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001219 __ Mov(kInterpreterDispatchTableRegister,
1220 Operand(ExternalReference::interpreter_dispatch_table_address(
1221 masm->isolate())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 // Get the bytecode array pointer from the frame.
Ben Murdochc5610432016-08-08 18:44:38 +01001224 __ Ldr(kInterpreterBytecodeArrayRegister,
1225 MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001226
1227 if (FLAG_debug_code) {
1228 // Check function data field is actually a BytecodeArray object.
1229 __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
1230 kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
1231 __ CompareObjectType(kInterpreterBytecodeArrayRegister, x1, x1,
1232 BYTECODE_ARRAY_TYPE);
1233 __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
1234 }
1235
1236 // Get the target bytecode offset from the frame.
1237 __ Ldr(kInterpreterBytecodeOffsetRegister,
Ben Murdochc5610432016-08-08 18:44:38 +01001238 MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
1240
1241 // Dispatch to the target bytecode.
1242 __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
1243 kInterpreterBytecodeOffsetRegister));
1244 __ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
1245 __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 __ Jump(ip0);
1247}
1248
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
Ben Murdochc5610432016-08-08 18:44:38 +01001250 // ----------- S t a t e -------------
1251 // -- x0 : argument count (preserved for callee)
1252 // -- x3 : new target (preserved for callee)
1253 // -- x1 : target function (preserved for callee)
1254 // -----------------------------------
1255 // First lookup code, maybe we don't need to compile!
1256 Label gotta_call_runtime;
1257 Label maybe_call_runtime;
1258 Label try_shared;
1259 Label loop_top, loop_bottom;
1260
1261 Register closure = x1;
1262 Register map = x13;
1263 Register index = x2;
1264 __ Ldr(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1265 __ Ldr(map,
1266 FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
1267 __ Ldrsw(index, UntagSmiFieldMemOperand(map, FixedArray::kLengthOffset));
1268 __ Cmp(index, Operand(2));
1269 __ B(lt, &gotta_call_runtime);
1270
1271 // Find literals.
1272 // x3 : native context
1273 // x2 : length / index
1274 // x13 : optimized code map
1275 // stack[0] : new target
1276 // stack[4] : closure
1277 Register native_context = x4;
1278 __ Ldr(native_context, NativeContextMemOperand());
1279
1280 __ Bind(&loop_top);
1281 Register temp = x5;
1282 Register array_pointer = x6;
1283
1284 // Does the native context match?
1285 __ Add(array_pointer, map, Operand(index, LSL, kPointerSizeLog2));
1286 __ Ldr(temp, FieldMemOperand(array_pointer,
1287 SharedFunctionInfo::kOffsetToPreviousContext));
1288 __ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
1289 __ Cmp(temp, native_context);
1290 __ B(ne, &loop_bottom);
1291 // OSR id set to none?
1292 __ Ldr(temp, FieldMemOperand(array_pointer,
1293 SharedFunctionInfo::kOffsetToPreviousOsrAstId));
1294 const int bailout_id = BailoutId::None().ToInt();
1295 __ Cmp(temp, Operand(Smi::FromInt(bailout_id)));
1296 __ B(ne, &loop_bottom);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001297
Ben Murdochc5610432016-08-08 18:44:38 +01001298 // Literals available?
Ben Murdoch61f157c2016-09-16 13:49:30 +01001299 Label got_literals, maybe_cleared_weakcell;
1300 Register temp2 = x7;
Ben Murdochc5610432016-08-08 18:44:38 +01001301 __ Ldr(temp, FieldMemOperand(array_pointer,
1302 SharedFunctionInfo::kOffsetToPreviousLiterals));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001303 // temp contains either a WeakCell pointing to the literals array or the
1304 // literals array directly.
1305 STATIC_ASSERT(WeakCell::kValueOffset == FixedArray::kLengthOffset);
1306 __ Ldr(temp2, FieldMemOperand(temp, WeakCell::kValueOffset));
1307 __ JumpIfSmi(temp2, &maybe_cleared_weakcell);
1308 // temp2 is a pointer, therefore temp is a WeakCell pointing to a literals
1309 // array.
Ben Murdochc5610432016-08-08 18:44:38 +01001310 __ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001311 __ jmp(&got_literals);
1312
1313 // r4 is a smi. If it's 0, then we are looking at a cleared WeakCell
1314 // around the literals array, and we should visit the runtime. If it's > 0,
1315 // then temp already contains the literals array.
1316 __ bind(&maybe_cleared_weakcell);
1317 __ Cmp(temp2, Operand(Smi::FromInt(0)));
1318 __ B(eq, &gotta_call_runtime);
Ben Murdochc5610432016-08-08 18:44:38 +01001319
1320 // Save the literals in the closure.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001321 __ bind(&got_literals);
Ben Murdochc5610432016-08-08 18:44:38 +01001322 __ Str(temp, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
1323 __ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, x7,
1324 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
1325 OMIT_SMI_CHECK);
1326
1327 // Code available?
1328 Register entry = x7;
1329 __ Ldr(entry,
1330 FieldMemOperand(array_pointer,
1331 SharedFunctionInfo::kOffsetToPreviousCachedCode));
1332 __ Ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
1333 __ JumpIfSmi(entry, &maybe_call_runtime);
1334
1335 // Found literals and code. Get them into the closure and return.
1336 __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
1337
1338 Label install_optimized_code_and_tailcall;
1339 __ Bind(&install_optimized_code_and_tailcall);
1340 __ Str(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
1341 __ RecordWriteCodeEntryField(closure, entry, x5);
1342
1343 // Link the closure into the optimized function list.
1344 // x7 : code entry
1345 // x4 : native context
1346 // x1 : closure
1347 __ Ldr(x8,
1348 ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
1349 __ Str(x8, FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset));
1350 __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, x8, x13,
1351 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
1352 OMIT_SMI_CHECK);
1353 const int function_list_offset =
1354 Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
1355 __ Str(closure,
1356 ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
1357 __ Mov(x5, closure);
1358 __ RecordWriteContextSlot(native_context, function_list_offset, x5, x13,
1359 kLRHasNotBeenSaved, kDontSaveFPRegs);
1360 __ Jump(entry);
1361
1362 __ Bind(&loop_bottom);
1363 __ Sub(index, index, Operand(SharedFunctionInfo::kEntryLength));
1364 __ Cmp(index, Operand(1));
1365 __ B(gt, &loop_top);
1366
1367 // We found neither literals nor code.
1368 __ B(&gotta_call_runtime);
1369
1370 __ Bind(&maybe_call_runtime);
1371
1372 // Last possibility. Check the context free optimized code map entry.
1373 __ Ldr(entry, FieldMemOperand(map, FixedArray::kHeaderSize +
1374 SharedFunctionInfo::kSharedCodeIndex));
1375 __ Ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
1376 __ JumpIfSmi(entry, &try_shared);
1377
1378 // Store code entry in the closure.
1379 __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
1380 __ B(&install_optimized_code_and_tailcall);
1381
1382 __ Bind(&try_shared);
1383 // Is the full code valid?
1384 __ Ldr(entry,
1385 FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
1386 __ Ldr(entry, FieldMemOperand(entry, SharedFunctionInfo::kCodeOffset));
1387 __ Ldr(x5, FieldMemOperand(entry, Code::kFlagsOffset));
1388 __ and_(x5, x5, Operand(Code::KindField::kMask));
1389 __ Mov(x5, Operand(x5, LSR, Code::KindField::kShift));
1390 __ Cmp(x5, Operand(Code::BUILTIN));
1391 __ B(eq, &gotta_call_runtime);
1392 // Yes, install the full code.
1393 __ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
1394 __ Str(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
1395 __ RecordWriteCodeEntryField(closure, entry, x5);
1396 __ Jump(entry);
1397
1398 __ Bind(&gotta_call_runtime);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001399 GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001400}
1401
Ben Murdochc5610432016-08-08 18:44:38 +01001402void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
1403 GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
1404}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001407 GenerateTailCallToReturnedCode(masm,
1408 Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409}
1410
1411
1412void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001413 GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414}
1415
1416
1417static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1418 // For now, we are relying on the fact that make_code_young doesn't do any
1419 // garbage collection which allows us to save/restore the registers without
1420 // worrying about which of them contain pointers. We also don't build an
1421 // internal frame to make the code fast, since we shouldn't have to do stack
1422 // crawls in MakeCodeYoung. This seems a bit fragile.
1423
1424 // The following caller-saved registers must be saved and restored when
1425 // calling through to the runtime:
1426 // x0 - The address from which to resume execution.
1427 // x1 - isolate
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 // x3 - new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001429 // lr - The return address for the JSFunction itself. It has not yet been
1430 // preserved on the stack because the frame setup code was replaced
1431 // with a call to this stub, to handle code ageing.
1432 {
1433 FrameScope scope(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 __ Push(x0, x1, x3, fp, lr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1436 __ CallCFunction(
1437 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001438 __ Pop(lr, fp, x3, x1, x0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001439 }
1440
1441 // The calling function has been made young again, so return to execute the
1442 // real frame set-up code.
1443 __ Br(x0);
1444}
1445
1446#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
1447void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
1448 MacroAssembler* masm) { \
1449 GenerateMakeCodeYoungAgainCommon(masm); \
1450} \
1451void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
1452 MacroAssembler* masm) { \
1453 GenerateMakeCodeYoungAgainCommon(masm); \
1454}
1455CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1456#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1457
1458
1459void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1460 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1461 // that make_code_young doesn't do any garbage collection which allows us to
1462 // save/restore the registers without worrying about which of them contain
1463 // pointers.
1464
1465 // The following caller-saved registers must be saved and restored when
1466 // calling through to the runtime:
1467 // x0 - The address from which to resume execution.
1468 // x1 - isolate
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001469 // x3 - new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 // lr - The return address for the JSFunction itself. It has not yet been
1471 // preserved on the stack because the frame setup code was replaced
1472 // with a call to this stub, to handle code ageing.
1473 {
1474 FrameScope scope(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475 __ Push(x0, x1, x3, fp, lr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1477 __ CallCFunction(
1478 ExternalReference::get_mark_code_as_executed_function(
1479 masm->isolate()), 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 __ Pop(lr, fp, x3, x1, x0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481
1482 // Perform prologue operations usually performed by the young code stub.
1483 __ EmitFrameSetupForCodeAgePatching(masm);
1484 }
1485
1486 // Jump to point after the code-age stub.
1487 __ Add(x0, x0, kNoCodeAgeSequenceLength);
1488 __ Br(x0);
1489}
1490
1491
1492void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1493 GenerateMakeCodeYoungAgainCommon(masm);
1494}
1495
1496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1498 Generate_MarkCodeAsExecutedOnce(masm);
1499}
1500
1501
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1503 SaveFPRegsMode save_doubles) {
1504 {
1505 FrameScope scope(masm, StackFrame::INTERNAL);
1506
1507 // Preserve registers across notification, this is important for compiled
1508 // stubs that tail call the runtime on deopts passing their parameters in
1509 // registers.
1510 // TODO(jbramley): Is it correct (and appropriate) to use safepoint
1511 // registers here? According to the comment above, we should only need to
1512 // preserve the registers with parameters.
1513 __ PushXRegList(kSafepointSavedRegisters);
1514 // Pass the function and deoptimization type to the runtime system.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001515 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516 __ PopXRegList(kSafepointSavedRegisters);
1517 }
1518
1519 // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
1520 __ Drop(1);
1521
1522 // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
1523 // into lr before it jumps here.
1524 __ Br(lr);
1525}
1526
1527
1528void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1529 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1530}
1531
1532
1533void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1534 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1535}
1536
1537
1538static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1539 Deoptimizer::BailoutType type) {
1540 {
1541 FrameScope scope(masm, StackFrame::INTERNAL);
1542 // Pass the deoptimization type to the runtime system.
1543 __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
1544 __ Push(x0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546 }
1547
1548 // Get the full codegen state from the stack and untag it.
1549 Register state = x6;
1550 __ Peek(state, 0);
1551 __ SmiUntag(state);
1552
1553 // Switch on the state.
1554 Label with_tos_register, unknown_state;
Ben Murdochc5610432016-08-08 18:44:38 +01001555 __ CompareAndBranch(state,
1556 static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS),
1557 ne, &with_tos_register);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558 __ Drop(1); // Remove state.
1559 __ Ret();
1560
1561 __ Bind(&with_tos_register);
1562 // Reload TOS register.
Ben Murdochc5610432016-08-08 18:44:38 +01001563 DCHECK_EQ(kInterpreterAccumulatorRegister.code(), x0.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 __ Peek(x0, kPointerSize);
Ben Murdochc5610432016-08-08 18:44:38 +01001565 __ CompareAndBranch(state,
1566 static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER),
1567 ne, &unknown_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568 __ Drop(2); // Remove state and TOS.
1569 __ Ret();
1570
1571 __ Bind(&unknown_state);
1572 __ Abort(kInvalidFullCodegenState);
1573}
1574
1575
1576void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1577 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1578}
1579
1580
1581void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1582 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1583}
1584
1585
1586void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1587 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1588}
1589
1590
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001591static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
1592 Register function_template_info,
1593 Register scratch0, Register scratch1,
1594 Register scratch2,
1595 Label* receiver_check_failed) {
1596 Register signature = scratch0;
1597 Register map = scratch1;
1598 Register constructor = scratch2;
1599
1600 // If there is no signature, return the holder.
1601 __ Ldr(signature, FieldMemOperand(function_template_info,
1602 FunctionTemplateInfo::kSignatureOffset));
1603 __ CompareRoot(signature, Heap::kUndefinedValueRootIndex);
1604 Label receiver_check_passed;
1605 __ B(eq, &receiver_check_passed);
1606
1607 // Walk the prototype chain.
1608 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1609 Label prototype_loop_start;
1610 __ Bind(&prototype_loop_start);
1611
1612 // Get the constructor, if any
1613 __ GetMapConstructor(constructor, map, x16, x16);
1614 __ cmp(x16, Operand(JS_FUNCTION_TYPE));
1615 Label next_prototype;
1616 __ B(ne, &next_prototype);
1617 Register type = constructor;
1618 __ Ldr(type,
1619 FieldMemOperand(constructor, JSFunction::kSharedFunctionInfoOffset));
1620 __ Ldr(type, FieldMemOperand(type, SharedFunctionInfo::kFunctionDataOffset));
1621
1622 // Loop through the chain of inheriting function templates.
1623 Label function_template_loop;
1624 __ Bind(&function_template_loop);
1625
1626 // If the signatures match, we have a compatible receiver.
1627 __ Cmp(signature, type);
1628 __ B(eq, &receiver_check_passed);
1629
1630 // If the current type is not a FunctionTemplateInfo, load the next prototype
1631 // in the chain.
1632 __ JumpIfSmi(type, &next_prototype);
1633 __ CompareObjectType(type, x16, x17, FUNCTION_TEMPLATE_INFO_TYPE);
1634 __ B(ne, &next_prototype);
1635
1636 // Otherwise load the parent function template and iterate.
1637 __ Ldr(type,
1638 FieldMemOperand(type, FunctionTemplateInfo::kParentTemplateOffset));
1639 __ B(&function_template_loop);
1640
1641 // Load the next prototype.
1642 __ Bind(&next_prototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001643 __ Ldr(x16, FieldMemOperand(map, Map::kBitField3Offset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001644 __ Tst(x16, Operand(Map::HasHiddenPrototype::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 __ B(eq, receiver_check_failed);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001646 __ Ldr(receiver, FieldMemOperand(map, Map::kPrototypeOffset));
1647 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 // Iterate.
1649 __ B(&prototype_loop_start);
1650
1651 __ Bind(&receiver_check_passed);
1652}
1653
1654
1655void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
1656 // ----------- S t a t e -------------
1657 // -- x0 : number of arguments excluding receiver
1658 // -- x1 : callee
1659 // -- lr : return address
1660 // -- sp[0] : last argument
1661 // -- ...
1662 // -- sp[8 * (argc - 1)] : first argument
1663 // -- sp[8 * argc] : receiver
1664 // -----------------------------------
1665
1666 // Load the FunctionTemplateInfo.
1667 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
1668 __ Ldr(x3, FieldMemOperand(x3, SharedFunctionInfo::kFunctionDataOffset));
1669
1670 // Do the compatible receiver check.
1671 Label receiver_check_failed;
1672 __ Ldr(x2, MemOperand(jssp, x0, LSL, kPointerSizeLog2));
1673 CompatibleReceiverCheck(masm, x2, x3, x4, x5, x6, &receiver_check_failed);
1674
1675 // Get the callback offset from the FunctionTemplateInfo, and jump to the
1676 // beginning of the code.
1677 __ Ldr(x4, FieldMemOperand(x3, FunctionTemplateInfo::kCallCodeOffset));
1678 __ Ldr(x4, FieldMemOperand(x4, CallHandlerInfo::kFastHandlerOffset));
1679 __ Add(x4, x4, Operand(Code::kHeaderSize - kHeapObjectTag));
1680 __ Jump(x4);
1681
1682 // Compatible receiver check failed: throw an Illegal Invocation exception.
1683 __ Bind(&receiver_check_failed);
1684 // Drop the arguments (including the receiver)
1685 __ add(x0, x0, Operand(1));
1686 __ Drop(x0);
1687 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
1688}
1689
1690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1692 // Lookup the function in the JavaScript frame.
1693 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1694 {
1695 FrameScope scope(masm, StackFrame::INTERNAL);
1696 // Pass function as argument.
1697 __ Push(x0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001698 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 }
1700
1701 // If the code object is null, just return to the unoptimized code.
1702 Label skip;
1703 __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
1704 __ Ret();
1705
1706 __ Bind(&skip);
1707
1708 // Load deoptimization data from the code object.
1709 // <deopt_data> = <code>[#deoptimization_data_offset]
1710 __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1711
1712 // Load the OSR entrypoint offset from the deoptimization data.
1713 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1714 __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1715 DeoptimizationInputData::kOsrPcOffsetIndex)));
1716
1717 // Compute the target address = code_obj + header_size + osr_offset
1718 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1719 __ Add(x0, x0, x1);
1720 __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1721
1722 // And "return" to the OSR entry point of the function.
1723 __ Ret();
1724}
1725
1726
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001727// static
1728void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
1729 int field_index) {
1730 // ----------- S t a t e -------------
Ben Murdoch61f157c2016-09-16 13:49:30 +01001731 // -- x0 : number of arguments
1732 // -- x1 : function
1733 // -- cp : context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001734 // -- lr : return address
1735 // -- jssp[0] : receiver
1736 // -----------------------------------
1737 ASM_LOCATION("Builtins::Generate_DatePrototype_GetField");
1738
1739 // 1. Pop receiver into x0 and check that it's actually a JSDate object.
1740 Label receiver_not_date;
1741 {
1742 __ Pop(x0);
1743 __ JumpIfSmi(x0, &receiver_not_date);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001744 __ JumpIfNotObjectType(x0, x2, x3, JS_DATE_TYPE, &receiver_not_date);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001745 }
1746
1747 // 2. Load the specified date field, falling back to the runtime as necessary.
1748 if (field_index == JSDate::kDateValue) {
1749 __ Ldr(x0, FieldMemOperand(x0, JSDate::kValueOffset));
1750 } else {
1751 if (field_index < JSDate::kFirstUncachedField) {
1752 Label stamp_mismatch;
1753 __ Mov(x1, ExternalReference::date_cache_stamp(masm->isolate()));
1754 __ Ldr(x1, MemOperand(x1));
1755 __ Ldr(x2, FieldMemOperand(x0, JSDate::kCacheStampOffset));
1756 __ Cmp(x1, x2);
1757 __ B(ne, &stamp_mismatch);
1758 __ Ldr(x0, FieldMemOperand(
1759 x0, JSDate::kValueOffset + field_index * kPointerSize));
1760 __ Ret();
1761 __ Bind(&stamp_mismatch);
1762 }
1763 FrameScope scope(masm, StackFrame::INTERNAL);
1764 __ Mov(x1, Smi::FromInt(field_index));
1765 __ CallCFunction(
1766 ExternalReference::get_date_field_function(masm->isolate()), 2);
1767 }
1768 __ Ret();
1769
1770 // 3. Raise a TypeError if the receiver is not a date.
1771 __ Bind(&receiver_not_date);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001772 {
1773 FrameScope scope(masm, StackFrame::MANUAL);
1774 __ Push(x0, lr, fp);
1775 __ Move(fp, jssp);
1776 __ Push(cp, x1);
1777 __ Push(Smi::FromInt(0));
1778 __ CallRuntime(Runtime::kThrowNotDateError);
1779 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001780}
1781
Ben Murdochda12d292016-06-02 14:46:10 +01001782// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001783void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
1784 // ----------- S t a t e -------------
1785 // -- x0 : argc
1786 // -- jssp[0] : argArray (if argc == 2)
1787 // -- jssp[8] : thisArg (if argc >= 1)
1788 // -- jssp[16] : receiver
1789 // -----------------------------------
1790 ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply");
1791
1792 Register argc = x0;
1793 Register arg_array = x0;
1794 Register receiver = x1;
1795 Register this_arg = x2;
1796 Register undefined_value = x3;
1797 Register null_value = x4;
1798
1799 __ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
1800 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1801
1802 // 1. Load receiver into x1, argArray into x0 (if present), remove all
1803 // arguments from the stack (including the receiver), and push thisArg (if
1804 // present) instead.
1805 {
1806 // Claim (2 - argc) dummy arguments from the stack, to put the stack in a
1807 // consistent state for a simple pop operation.
1808 __ Claim(2);
1809 __ Drop(argc);
1810
1811 // ----------- S t a t e -------------
1812 // -- x0 : argc
1813 // -- jssp[0] : argArray (dummy value if argc <= 1)
1814 // -- jssp[8] : thisArg (dummy value if argc == 0)
1815 // -- jssp[16] : receiver
1816 // -----------------------------------
1817 __ Cmp(argc, 1);
1818 __ Pop(arg_array, this_arg); // Overwrites argc.
1819 __ CmovX(this_arg, undefined_value, lo); // undefined if argc == 0.
1820 __ CmovX(arg_array, undefined_value, ls); // undefined if argc <= 1.
1821
1822 __ Peek(receiver, 0);
1823 __ Poke(this_arg, 0);
1824 }
1825
1826 // ----------- S t a t e -------------
1827 // -- x0 : argArray
1828 // -- x1 : receiver
1829 // -- x3 : undefined root value
1830 // -- jssp[0] : thisArg
1831 // -----------------------------------
1832
1833 // 2. Make sure the receiver is actually callable.
1834 Label receiver_not_callable;
1835 __ JumpIfSmi(receiver, &receiver_not_callable);
1836 __ Ldr(x10, FieldMemOperand(receiver, HeapObject::kMapOffset));
1837 __ Ldrb(w10, FieldMemOperand(x10, Map::kBitFieldOffset));
1838 __ TestAndBranchIfAllClear(x10, 1 << Map::kIsCallable,
1839 &receiver_not_callable);
1840
1841 // 3. Tail call with no arguments if argArray is null or undefined.
1842 Label no_arguments;
1843 __ Cmp(arg_array, null_value);
1844 __ Ccmp(arg_array, undefined_value, ZFlag, ne);
1845 __ B(eq, &no_arguments);
1846
1847 // 4a. Apply the receiver to the given argArray (passing undefined for
1848 // new.target in x3).
1849 DCHECK(undefined_value.Is(x3));
1850 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1851
1852 // 4b. The argArray is either null or undefined, so we tail call without any
1853 // arguments to the receiver.
1854 __ Bind(&no_arguments);
1855 {
1856 __ Mov(x0, 0);
1857 DCHECK(receiver.Is(x1));
1858 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1859 }
1860
1861 // 4c. The receiver is not callable, throw an appropriate TypeError.
1862 __ Bind(&receiver_not_callable);
1863 {
1864 __ Poke(receiver, 0);
1865 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1866 }
1867}
1868
1869
1870// static
1871void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872 Register argc = x0;
1873 Register function = x1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001874 Register scratch1 = x10;
1875 Register scratch2 = x11;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001876
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001877 ASM_LOCATION("Builtins::Generate_FunctionPrototypeCall");
1878
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 // 1. Make sure we have at least one argument.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001880 {
1881 Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 __ Cbnz(argc, &done);
1883 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1884 __ Push(scratch1);
1885 __ Mov(argc, 1);
1886 __ Bind(&done);
1887 }
1888
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889 // 2. Get the callable to call (passed as receiver) from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001891
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001892 // 3. Shift arguments and return address one slot down on the stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001893 // (overwriting the original receiver). Adjust argument count to make
1894 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001895 {
1896 Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001897 // Calculate the copy start address (destination). Copy end address is jssp.
1898 __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1899 __ Sub(scratch1, scratch2, kPointerSize);
1900
1901 __ Bind(&loop);
1902 __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1903 __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1904 __ Cmp(scratch1, jssp);
1905 __ B(ge, &loop);
1906 // Adjust the actual number of arguments and remove the top element
1907 // (which is a copy of the last argument).
1908 __ Sub(argc, argc, 1);
1909 __ Drop(1);
1910 }
1911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 // 4. Call the callable.
1913 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914}
1915
1916
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001917void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1918 // ----------- S t a t e -------------
1919 // -- x0 : argc
1920 // -- jssp[0] : argumentsList (if argc == 3)
1921 // -- jssp[8] : thisArgument (if argc >= 2)
1922 // -- jssp[16] : target (if argc >= 1)
1923 // -- jssp[24] : receiver
1924 // -----------------------------------
1925 ASM_LOCATION("Builtins::Generate_ReflectApply");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001927 Register argc = x0;
1928 Register arguments_list = x0;
1929 Register target = x1;
1930 Register this_argument = x2;
1931 Register undefined_value = x3;
1932
1933 __ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
1934
1935 // 1. Load target into x1 (if present), argumentsList into x0 (if present),
1936 // remove all arguments from the stack (including the receiver), and push
1937 // thisArgument (if present) instead.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001938 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001939 // Claim (3 - argc) dummy arguments from the stack, to put the stack in a
1940 // consistent state for a simple pop operation.
1941 __ Claim(3);
1942 __ Drop(argc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944 // ----------- S t a t e -------------
1945 // -- x0 : argc
1946 // -- jssp[0] : argumentsList (dummy value if argc <= 2)
1947 // -- jssp[8] : thisArgument (dummy value if argc <= 1)
1948 // -- jssp[16] : target (dummy value if argc == 0)
1949 // -- jssp[24] : receiver
1950 // -----------------------------------
1951 __ Adds(x10, argc, 0); // Preserve argc, and set the Z flag if it is zero.
1952 __ Pop(arguments_list, this_argument, target); // Overwrites argc.
1953 __ CmovX(target, undefined_value, eq); // undefined if argc == 0.
1954 __ Cmp(x10, 2);
1955 __ CmovX(this_argument, undefined_value, lo); // undefined if argc <= 1.
1956 __ CmovX(arguments_list, undefined_value, ls); // undefined if argc <= 2.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001957
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001958 __ Poke(this_argument, 0); // Overwrite receiver.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001960
1961 // ----------- S t a t e -------------
1962 // -- x0 : argumentsList
1963 // -- x1 : target
1964 // -- jssp[0] : thisArgument
1965 // -----------------------------------
1966
1967 // 2. Make sure the target is actually callable.
1968 Label target_not_callable;
1969 __ JumpIfSmi(target, &target_not_callable);
1970 __ Ldr(x10, FieldMemOperand(target, HeapObject::kMapOffset));
1971 __ Ldr(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
1972 __ TestAndBranchIfAllClear(x10, 1 << Map::kIsCallable, &target_not_callable);
1973
1974 // 3a. Apply the target to the given argumentsList (passing undefined for
1975 // new.target in x3).
1976 DCHECK(undefined_value.Is(x3));
1977 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1978
1979 // 3b. The target is not callable, throw an appropriate TypeError.
1980 __ Bind(&target_not_callable);
1981 {
1982 __ Poke(target, 0);
1983 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1984 }
1985}
1986
1987
1988void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1989 // ----------- S t a t e -------------
1990 // -- x0 : argc
1991 // -- jssp[0] : new.target (optional)
1992 // -- jssp[8] : argumentsList
1993 // -- jssp[16] : target
1994 // -- jssp[24] : receiver
1995 // -----------------------------------
1996 ASM_LOCATION("Builtins::Generate_ReflectConstruct");
1997
1998 Register argc = x0;
1999 Register arguments_list = x0;
2000 Register target = x1;
2001 Register new_target = x3;
2002 Register undefined_value = x4;
2003
2004 __ LoadRoot(undefined_value, Heap::kUndefinedValueRootIndex);
2005
2006 // 1. Load target into x1 (if present), argumentsList into x0 (if present),
2007 // new.target into x3 (if present, otherwise use target), remove all
2008 // arguments from the stack (including the receiver), and push thisArgument
2009 // (if present) instead.
2010 {
2011 // Claim (3 - argc) dummy arguments from the stack, to put the stack in a
2012 // consistent state for a simple pop operation.
2013 __ Claim(3);
2014 __ Drop(argc);
2015
2016 // ----------- S t a t e -------------
2017 // -- x0 : argc
2018 // -- jssp[0] : new.target (dummy value if argc <= 2)
2019 // -- jssp[8] : argumentsList (dummy value if argc <= 1)
2020 // -- jssp[16] : target (dummy value if argc == 0)
2021 // -- jssp[24] : receiver
2022 // -----------------------------------
2023 __ Adds(x10, argc, 0); // Preserve argc, and set the Z flag if it is zero.
2024 __ Pop(new_target, arguments_list, target); // Overwrites argc.
2025 __ CmovX(target, undefined_value, eq); // undefined if argc == 0.
2026 __ Cmp(x10, 2);
2027 __ CmovX(arguments_list, undefined_value, lo); // undefined if argc <= 1.
2028 __ CmovX(new_target, target, ls); // target if argc <= 2.
2029
2030 __ Poke(undefined_value, 0); // Overwrite receiver.
2031 }
2032
2033 // ----------- S t a t e -------------
2034 // -- x0 : argumentsList
2035 // -- x1 : target
2036 // -- x3 : new.target
2037 // -- jssp[0] : receiver (undefined)
2038 // -----------------------------------
2039
2040 // 2. Make sure the target is actually a constructor.
2041 Label target_not_constructor;
2042 __ JumpIfSmi(target, &target_not_constructor);
2043 __ Ldr(x10, FieldMemOperand(target, HeapObject::kMapOffset));
2044 __ Ldrb(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
2045 __ TestAndBranchIfAllClear(x10, 1 << Map::kIsConstructor,
2046 &target_not_constructor);
2047
2048 // 3. Make sure the new.target is actually a constructor.
2049 Label new_target_not_constructor;
2050 __ JumpIfSmi(new_target, &new_target_not_constructor);
2051 __ Ldr(x10, FieldMemOperand(new_target, HeapObject::kMapOffset));
2052 __ Ldrb(x10, FieldMemOperand(x10, Map::kBitFieldOffset));
2053 __ TestAndBranchIfAllClear(x10, 1 << Map::kIsConstructor,
2054 &new_target_not_constructor);
2055
2056 // 4a. Construct the target with the given new.target and argumentsList.
2057 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
2058
2059 // 4b. The target is not a constructor, throw an appropriate TypeError.
2060 __ Bind(&target_not_constructor);
2061 {
2062 __ Poke(target, 0);
2063 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
2064 }
2065
2066 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
2067 __ Bind(&new_target_not_constructor);
2068 {
2069 __ Poke(new_target, 0);
2070 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
2071 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002072}
2073
2074
2075static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
2076 Label* stack_overflow) {
2077 // ----------- S t a t e -------------
2078 // -- x0 : actual number of arguments
2079 // -- x1 : function (passed through to callee)
2080 // -- x2 : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002081 // -- x3 : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002082 // -----------------------------------
2083 // Check the stack for overflow.
2084 // We are not trying to catch interruptions (e.g. debug break and
2085 // preemption) here, so the "real stack limit" is checked.
2086 Label enough_stack_space;
2087 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
2088 // Make x10 the space we have left. The stack might already be overflowed
2089 // here which will cause x10 to become negative.
2090 __ Sub(x10, jssp, x10);
2091 // Check if the arguments will overflow the stack.
2092 __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
2093 __ B(le, stack_overflow);
2094}
2095
2096
2097static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
2098 __ SmiTag(x10, x0);
2099 __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2100 __ Push(lr, fp);
2101 __ Push(x11, x1, x10);
2102 __ Add(fp, jssp,
2103 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
2104}
2105
2106
2107static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
2108 // ----------- S t a t e -------------
2109 // -- x0 : result being passed through
2110 // -----------------------------------
2111 // Get the number of arguments passed (as a smi), tear down the frame and
2112 // then drop the parameters and the receiver.
2113 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
2114 kPointerSize)));
2115 __ Mov(jssp, fp);
2116 __ Pop(fp, lr);
2117 __ DropBySMI(x10, kXRegSize);
2118 __ Drop(1);
2119}
2120
2121
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002122// static
2123void Builtins::Generate_Apply(MacroAssembler* masm) {
2124 // ----------- S t a t e -------------
2125 // -- x0 : argumentsList
2126 // -- x1 : target
2127 // -- x3 : new.target (checked to be constructor or undefined)
2128 // -- jssp[0] : thisArgument
2129 // -----------------------------------
2130
2131 Register arguments_list = x0;
2132 Register target = x1;
2133 Register new_target = x3;
2134
2135 Register args = x0;
2136 Register len = x2;
2137
2138 // Create the list of arguments from the array-like argumentsList.
2139 {
2140 Label create_arguments, create_array, create_runtime, done_create;
2141 __ JumpIfSmi(arguments_list, &create_runtime);
2142
2143 // Load native context.
2144 Register native_context = x4;
2145 __ Ldr(native_context, NativeContextMemOperand());
2146
2147 // Load the map of argumentsList.
2148 Register arguments_list_map = x2;
2149 __ Ldr(arguments_list_map,
2150 FieldMemOperand(arguments_list, HeapObject::kMapOffset));
2151
2152 // Check if argumentsList is an (unmodified) arguments object.
2153 __ Ldr(x10, ContextMemOperand(native_context,
2154 Context::SLOPPY_ARGUMENTS_MAP_INDEX));
2155 __ Ldr(x11, ContextMemOperand(native_context,
2156 Context::STRICT_ARGUMENTS_MAP_INDEX));
2157 __ Cmp(arguments_list_map, x10);
2158 __ Ccmp(arguments_list_map, x11, ZFlag, ne);
2159 __ B(eq, &create_arguments);
2160
2161 // Check if argumentsList is a fast JSArray.
2162 __ CompareInstanceType(arguments_list_map, native_context, JS_ARRAY_TYPE);
2163 __ B(eq, &create_array);
2164
2165 // Ask the runtime to create the list (actually a FixedArray).
2166 __ Bind(&create_runtime);
2167 {
2168 FrameScope scope(masm, StackFrame::INTERNAL);
2169 __ Push(target, new_target, arguments_list);
2170 __ CallRuntime(Runtime::kCreateListFromArrayLike);
2171 __ Pop(new_target, target);
2172 __ Ldrsw(len, UntagSmiFieldMemOperand(arguments_list,
2173 FixedArray::kLengthOffset));
2174 }
2175 __ B(&done_create);
2176
2177 // Try to create the list from an arguments object.
2178 __ Bind(&create_arguments);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002179 __ Ldrsw(len, UntagSmiFieldMemOperand(arguments_list,
2180 JSArgumentsObject::kLengthOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002181 __ Ldr(x10, FieldMemOperand(arguments_list, JSObject::kElementsOffset));
2182 __ Ldrsw(x11, UntagSmiFieldMemOperand(x10, FixedArray::kLengthOffset));
2183 __ CompareAndBranch(len, x11, ne, &create_runtime);
2184 __ Mov(args, x10);
2185 __ B(&done_create);
2186
2187 // Try to create the list from a JSArray object.
2188 __ Bind(&create_array);
2189 __ Ldr(x10, FieldMemOperand(arguments_list_map, Map::kBitField2Offset));
2190 __ DecodeField<Map::ElementsKindBits>(x10);
2191 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2192 STATIC_ASSERT(FAST_ELEMENTS == 2);
2193 // Branch for anything that's not FAST_{SMI_}ELEMENTS.
2194 __ TestAndBranchIfAnySet(x10, ~FAST_ELEMENTS, &create_runtime);
2195 __ Ldrsw(len,
2196 UntagSmiFieldMemOperand(arguments_list, JSArray::kLengthOffset));
2197 __ Ldr(args, FieldMemOperand(arguments_list, JSArray::kElementsOffset));
2198
2199 __ Bind(&done_create);
2200 }
2201
2202 // Check for stack overflow.
2203 {
2204 // Check the stack for overflow. We are not trying to catch interruptions
2205 // (i.e. debug break and preemption) here, so check the "real stack limit".
2206 Label done;
2207 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
2208 // Make x10 the space we have left. The stack might already be overflowed
2209 // here which will cause x10 to become negative.
2210 __ Sub(x10, masm->StackPointer(), x10);
2211 // Check if the arguments will overflow the stack.
2212 __ Cmp(x10, Operand(len, LSL, kPointerSizeLog2));
2213 __ B(gt, &done); // Signed comparison.
2214 __ TailCallRuntime(Runtime::kThrowStackOverflow);
2215 __ Bind(&done);
2216 }
2217
2218 // ----------- S t a t e -------------
2219 // -- x0 : args (a FixedArray built from argumentsList)
2220 // -- x1 : target
2221 // -- x2 : len (number of elements to push from args)
2222 // -- x3 : new.target (checked to be constructor or undefined)
2223 // -- jssp[0] : thisArgument
2224 // -----------------------------------
2225
2226 // Push arguments onto the stack (thisArgument is already on the stack).
2227 {
2228 Label done, loop;
2229 Register src = x4;
2230
2231 __ Add(src, args, FixedArray::kHeaderSize - kHeapObjectTag);
2232 __ Mov(x0, len); // The 'len' argument for Call() or Construct().
2233 __ Cbz(len, &done);
2234 __ Claim(len);
2235 __ Bind(&loop);
2236 __ Sub(len, len, 1);
2237 __ Ldr(x10, MemOperand(src, kPointerSize, PostIndex));
2238 __ Poke(x10, Operand(len, LSL, kPointerSizeLog2));
2239 __ Cbnz(len, &loop);
2240 __ Bind(&done);
2241 }
2242
2243 // ----------- S t a t e -------------
2244 // -- x0 : argument count (len)
2245 // -- x1 : target
2246 // -- x3 : new.target (checked to be constructor or undefined)
2247 // -- jssp[0] : args[len-1]
2248 // -- jssp[8] : args[len-2]
2249 // ... : ...
2250 // -- jssp[8*(len-2)] : args[1]
2251 // -- jssp[8*(len-1)] : args[0]
2252 // -----------------------------------
2253
2254 // Dispatch to Call or Construct depending on whether new.target is undefined.
2255 {
2256 __ CompareRoot(new_target, Heap::kUndefinedValueRootIndex);
2257 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq);
2258 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2259 }
2260}
2261
Ben Murdoch097c5b22016-05-18 11:27:45 +01002262namespace {
2263
2264// Drops top JavaScript frame and an arguments adaptor frame below it (if
2265// present) preserving all the arguments prepared for current call.
2266// Does nothing if debugger is currently active.
2267// ES6 14.6.3. PrepareForTailCall
2268//
2269// Stack structure for the function g() tail calling f():
2270//
2271// ------- Caller frame: -------
2272// | ...
2273// | g()'s arg M
2274// | ...
2275// | g()'s arg 1
2276// | g()'s receiver arg
2277// | g()'s caller pc
2278// ------- g()'s frame: -------
2279// | g()'s caller fp <- fp
2280// | g()'s context
2281// | function pointer: g
2282// | -------------------------
2283// | ...
2284// | ...
2285// | f()'s arg N
2286// | ...
2287// | f()'s arg 1
2288// | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!)
2289// ----------------------
2290//
2291void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
2292 Register scratch1, Register scratch2,
2293 Register scratch3) {
2294 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
2295 Comment cmnt(masm, "[ PrepareForTailCall");
2296
Ben Murdochda12d292016-06-02 14:46:10 +01002297 // Prepare for tail call only if ES2015 tail call elimination is enabled.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002298 Label done;
Ben Murdochda12d292016-06-02 14:46:10 +01002299 ExternalReference is_tail_call_elimination_enabled =
2300 ExternalReference::is_tail_call_elimination_enabled_address(
2301 masm->isolate());
2302 __ Mov(scratch1, Operand(is_tail_call_elimination_enabled));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002303 __ Ldrb(scratch1, MemOperand(scratch1));
2304 __ Cmp(scratch1, Operand(0));
Ben Murdochda12d292016-06-02 14:46:10 +01002305 __ B(eq, &done);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002306
2307 // Drop possible interpreter handler/stub frame.
2308 {
2309 Label no_interpreter_frame;
Ben Murdochda12d292016-06-02 14:46:10 +01002310 __ Ldr(scratch3,
2311 MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002312 __ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::STUB)));
2313 __ B(ne, &no_interpreter_frame);
2314 __ Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2315 __ bind(&no_interpreter_frame);
2316 }
2317
2318 // Check if next frame is an arguments adaptor frame.
Ben Murdochda12d292016-06-02 14:46:10 +01002319 Register caller_args_count_reg = scratch1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002320 Label no_arguments_adaptor, formal_parameter_count_loaded;
2321 __ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2322 __ Ldr(scratch3,
Ben Murdochda12d292016-06-02 14:46:10 +01002323 MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002324 __ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2325 __ B(ne, &no_arguments_adaptor);
2326
Ben Murdochda12d292016-06-02 14:46:10 +01002327 // Drop current frame and load arguments count from arguments adaptor frame.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002328 __ mov(fp, scratch2);
Ben Murdochda12d292016-06-02 14:46:10 +01002329 __ Ldr(caller_args_count_reg,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002330 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01002331 __ SmiUntag(caller_args_count_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002332 __ B(&formal_parameter_count_loaded);
2333
2334 __ bind(&no_arguments_adaptor);
2335 // Load caller's formal parameter count
2336 __ Ldr(scratch1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
2337 __ Ldr(scratch1,
2338 FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01002339 __ Ldrsw(caller_args_count_reg,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002340 FieldMemOperand(scratch1,
2341 SharedFunctionInfo::kFormalParameterCountOffset));
2342 __ bind(&formal_parameter_count_loaded);
2343
Ben Murdochda12d292016-06-02 14:46:10 +01002344 ParameterCount callee_args_count(args_reg);
2345 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
2346 scratch3);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002347 __ bind(&done);
2348}
2349} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002350
2351// static
2352void Builtins::Generate_CallFunction(MacroAssembler* masm,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002353 ConvertReceiverMode mode,
2354 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002355 ASM_LOCATION("Builtins::Generate_CallFunction");
2356 // ----------- S t a t e -------------
2357 // -- x0 : the number of arguments (not including the receiver)
2358 // -- x1 : the function to call (checked to be a JSFunction)
2359 // -----------------------------------
2360 __ AssertFunction(x1);
2361
2362 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
2363 // Check that function is not a "classConstructor".
2364 Label class_constructor;
2365 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
2366 __ Ldr(w3, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
2367 __ TestAndBranchIfAnySet(
2368 w3, (1 << SharedFunctionInfo::kIsDefaultConstructor) |
2369 (1 << SharedFunctionInfo::kIsSubclassConstructor) |
2370 (1 << SharedFunctionInfo::kIsBaseConstructor),
2371 &class_constructor);
2372
2373 // Enter the context of the function; ToObject has to run in the function
2374 // context, and we also need to take the global proxy from the function
2375 // context in case of conversion.
2376 __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
2377 // We need to convert the receiver for non-native sloppy mode functions.
2378 Label done_convert;
2379 __ TestAndBranchIfAnySet(w3,
2380 (1 << SharedFunctionInfo::kNative) |
2381 (1 << SharedFunctionInfo::kStrictModeFunction),
2382 &done_convert);
2383 {
2384 // ----------- S t a t e -------------
2385 // -- x0 : the number of arguments (not including the receiver)
2386 // -- x1 : the function to call (checked to be a JSFunction)
2387 // -- x2 : the shared function info.
2388 // -- cp : the function context.
2389 // -----------------------------------
2390
2391 if (mode == ConvertReceiverMode::kNullOrUndefined) {
2392 // Patch receiver to global proxy.
2393 __ LoadGlobalProxy(x3);
2394 } else {
2395 Label convert_to_object, convert_receiver;
2396 __ Peek(x3, Operand(x0, LSL, kXRegSizeLog2));
2397 __ JumpIfSmi(x3, &convert_to_object);
2398 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2399 __ CompareObjectType(x3, x4, x4, FIRST_JS_RECEIVER_TYPE);
2400 __ B(hs, &done_convert);
2401 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
2402 Label convert_global_proxy;
2403 __ JumpIfRoot(x3, Heap::kUndefinedValueRootIndex,
2404 &convert_global_proxy);
2405 __ JumpIfNotRoot(x3, Heap::kNullValueRootIndex, &convert_to_object);
2406 __ Bind(&convert_global_proxy);
2407 {
2408 // Patch receiver to global proxy.
2409 __ LoadGlobalProxy(x3);
2410 }
2411 __ B(&convert_receiver);
2412 }
2413 __ Bind(&convert_to_object);
2414 {
2415 // Convert receiver using ToObject.
2416 // TODO(bmeurer): Inline the allocation here to avoid building the frame
2417 // in the fast case? (fall back to AllocateInNewSpace?)
2418 FrameScope scope(masm, StackFrame::INTERNAL);
2419 __ SmiTag(x0);
2420 __ Push(x0, x1);
2421 __ Mov(x0, x3);
2422 ToObjectStub stub(masm->isolate());
2423 __ CallStub(&stub);
2424 __ Mov(x3, x0);
2425 __ Pop(x1, x0);
2426 __ SmiUntag(x0);
2427 }
2428 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
2429 __ Bind(&convert_receiver);
2430 }
2431 __ Poke(x3, Operand(x0, LSL, kXRegSizeLog2));
2432 }
2433 __ Bind(&done_convert);
2434
2435 // ----------- S t a t e -------------
2436 // -- x0 : the number of arguments (not including the receiver)
2437 // -- x1 : the function to call (checked to be a JSFunction)
2438 // -- x2 : the shared function info.
2439 // -- cp : the function context.
2440 // -----------------------------------
2441
Ben Murdoch097c5b22016-05-18 11:27:45 +01002442 if (tail_call_mode == TailCallMode::kAllow) {
2443 PrepareForTailCall(masm, x0, x3, x4, x5);
2444 }
2445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002446 __ Ldrsw(
2447 x2, FieldMemOperand(x2, SharedFunctionInfo::kFormalParameterCountOffset));
2448 ParameterCount actual(x0);
2449 ParameterCount expected(x2);
2450 __ InvokeFunctionCode(x1, no_reg, expected, actual, JUMP_FUNCTION,
2451 CheckDebugStepCallWrapper());
2452
2453 // The function is a "classConstructor", need to raise an exception.
2454 __ bind(&class_constructor);
2455 {
2456 FrameScope frame(masm, StackFrame::INTERNAL);
2457 __ Push(x1);
2458 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
2459 }
2460}
2461
2462
2463namespace {
2464
2465void Generate_PushBoundArguments(MacroAssembler* masm) {
2466 // ----------- S t a t e -------------
2467 // -- x0 : the number of arguments (not including the receiver)
2468 // -- x1 : target (checked to be a JSBoundFunction)
2469 // -- x3 : new.target (only in case of [[Construct]])
2470 // -----------------------------------
2471
2472 // Load [[BoundArguments]] into x2 and length of that into x4.
2473 Label no_bound_arguments;
2474 __ Ldr(x2, FieldMemOperand(x1, JSBoundFunction::kBoundArgumentsOffset));
2475 __ Ldrsw(x4, UntagSmiFieldMemOperand(x2, FixedArray::kLengthOffset));
2476 __ Cmp(x4, 0);
2477 __ B(eq, &no_bound_arguments);
2478 {
2479 // ----------- S t a t e -------------
2480 // -- x0 : the number of arguments (not including the receiver)
2481 // -- x1 : target (checked to be a JSBoundFunction)
2482 // -- x2 : the [[BoundArguments]] (implemented as FixedArray)
2483 // -- x3 : new.target (only in case of [[Construct]])
2484 // -- x4 : the number of [[BoundArguments]]
2485 // -----------------------------------
2486
2487 // Reserve stack space for the [[BoundArguments]].
2488 {
2489 Label done;
2490 __ Claim(x4);
2491 // Check the stack for overflow. We are not trying to catch interruptions
2492 // (i.e. debug break and preemption) here, so check the "real stack
2493 // limit".
2494 __ CompareRoot(jssp, Heap::kRealStackLimitRootIndex);
2495 __ B(gt, &done); // Signed comparison.
2496 // Restore the stack pointer.
2497 __ Drop(x4);
2498 {
2499 FrameScope scope(masm, StackFrame::MANUAL);
2500 __ EnterFrame(StackFrame::INTERNAL);
2501 __ CallRuntime(Runtime::kThrowStackOverflow);
2502 }
2503 __ Bind(&done);
2504 }
2505
2506 // Relocate arguments down the stack.
2507 {
2508 Label loop, done_loop;
2509 __ Mov(x5, 0);
2510 __ Bind(&loop);
2511 __ Cmp(x5, x0);
2512 __ B(gt, &done_loop);
2513 __ Peek(x10, Operand(x4, LSL, kPointerSizeLog2));
2514 __ Poke(x10, Operand(x5, LSL, kPointerSizeLog2));
2515 __ Add(x4, x4, 1);
2516 __ Add(x5, x5, 1);
2517 __ B(&loop);
2518 __ Bind(&done_loop);
2519 }
2520
2521 // Copy [[BoundArguments]] to the stack (below the arguments).
2522 {
2523 Label loop;
2524 __ Ldrsw(x4, UntagSmiFieldMemOperand(x2, FixedArray::kLengthOffset));
2525 __ Add(x2, x2, FixedArray::kHeaderSize - kHeapObjectTag);
2526 __ Bind(&loop);
2527 __ Sub(x4, x4, 1);
2528 __ Ldr(x10, MemOperand(x2, x4, LSL, kPointerSizeLog2));
2529 __ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
2530 __ Add(x0, x0, 1);
2531 __ Cmp(x4, 0);
2532 __ B(gt, &loop);
2533 }
2534 }
2535 __ Bind(&no_bound_arguments);
2536}
2537
2538} // namespace
2539
2540
2541// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002542void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2543 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002544 // ----------- S t a t e -------------
2545 // -- x0 : the number of arguments (not including the receiver)
2546 // -- x1 : the function to call (checked to be a JSBoundFunction)
2547 // -----------------------------------
2548 __ AssertBoundFunction(x1);
2549
Ben Murdoch097c5b22016-05-18 11:27:45 +01002550 if (tail_call_mode == TailCallMode::kAllow) {
2551 PrepareForTailCall(masm, x0, x3, x4, x5);
2552 }
2553
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002554 // Patch the receiver to [[BoundThis]].
2555 __ Ldr(x10, FieldMemOperand(x1, JSBoundFunction::kBoundThisOffset));
2556 __ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
2557
2558 // Push the [[BoundArguments]] onto the stack.
2559 Generate_PushBoundArguments(masm);
2560
2561 // Call the [[BoundTargetFunction]] via the Call builtin.
2562 __ Ldr(x1, FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
2563 __ Mov(x10,
2564 ExternalReference(Builtins::kCall_ReceiverIsAny, masm->isolate()));
2565 __ Ldr(x11, MemOperand(x10));
2566 __ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
2567 __ Br(x12);
2568}
2569
2570
2571// static
Ben Murdoch097c5b22016-05-18 11:27:45 +01002572void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2573 TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002574 // ----------- S t a t e -------------
2575 // -- x0 : the number of arguments (not including the receiver)
2576 // -- x1 : the target to call (can be any Object).
2577 // -----------------------------------
2578
2579 Label non_callable, non_function, non_smi;
2580 __ JumpIfSmi(x1, &non_callable);
2581 __ Bind(&non_smi);
2582 __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002583 __ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002584 RelocInfo::CODE_TARGET, eq);
2585 __ Cmp(x5, JS_BOUND_FUNCTION_TYPE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002586 __ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002587 RelocInfo::CODE_TARGET, eq);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002588
2589 // Check if target has a [[Call]] internal method.
2590 __ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
2591 __ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
2592
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002593 __ Cmp(x5, JS_PROXY_TYPE);
2594 __ B(ne, &non_function);
2595
Ben Murdoch097c5b22016-05-18 11:27:45 +01002596 // 0. Prepare for tail call if necessary.
2597 if (tail_call_mode == TailCallMode::kAllow) {
2598 PrepareForTailCall(masm, x0, x3, x4, x5);
2599 }
2600
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002601 // 1. Runtime fallback for Proxy [[Call]].
2602 __ Push(x1);
2603 // Increase the arguments size to include the pushed function and the
2604 // existing receiver on the stack.
2605 __ Add(x0, x0, Operand(2));
2606 // Tail-call to the runtime.
2607 __ JumpToExternalReference(
2608 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2609
2610 // 2. Call to something else, which might have a [[Call]] internal method (if
2611 // not we raise an exception).
2612 __ Bind(&non_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002613 // Overwrite the original receiver with the (original) target.
2614 __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
2615 // Let the "call_as_function_delegate" take care of the rest.
2616 __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, x1);
2617 __ Jump(masm->isolate()->builtins()->CallFunction(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002618 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002619 RelocInfo::CODE_TARGET);
2620
2621 // 3. Call to something that is not callable.
2622 __ bind(&non_callable);
2623 {
2624 FrameScope scope(masm, StackFrame::INTERNAL);
2625 __ Push(x1);
2626 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2627 }
2628}
2629
2630
2631// static
2632void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2633 // ----------- S t a t e -------------
2634 // -- x0 : the number of arguments (not including the receiver)
2635 // -- x1 : the constructor to call (checked to be a JSFunction)
2636 // -- x3 : the new target (checked to be a constructor)
2637 // -----------------------------------
2638 __ AssertFunction(x1);
2639
2640 // Calling convention for function specific ConstructStubs require
2641 // x2 to contain either an AllocationSite or undefined.
2642 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
2643
2644 // Tail call to the function-specific construct stub (still in the caller
2645 // context at this point).
2646 __ Ldr(x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
2647 __ Ldr(x4, FieldMemOperand(x4, SharedFunctionInfo::kConstructStubOffset));
2648 __ Add(x4, x4, Code::kHeaderSize - kHeapObjectTag);
2649 __ Br(x4);
2650}
2651
2652
2653// static
2654void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2655 // ----------- S t a t e -------------
2656 // -- x0 : the number of arguments (not including the receiver)
2657 // -- x1 : the function to call (checked to be a JSBoundFunction)
2658 // -- x3 : the new target (checked to be a constructor)
2659 // -----------------------------------
2660 __ AssertBoundFunction(x1);
2661
2662 // Push the [[BoundArguments]] onto the stack.
2663 Generate_PushBoundArguments(masm);
2664
2665 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2666 {
2667 Label done;
2668 __ Cmp(x1, x3);
2669 __ B(ne, &done);
2670 __ Ldr(x3,
2671 FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
2672 __ Bind(&done);
2673 }
2674
2675 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2676 __ Ldr(x1, FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
2677 __ Mov(x10, ExternalReference(Builtins::kConstruct, masm->isolate()));
2678 __ Ldr(x11, MemOperand(x10));
2679 __ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
2680 __ Br(x12);
2681}
2682
2683
2684// static
2685void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2686 // ----------- S t a t e -------------
2687 // -- x0 : the number of arguments (not including the receiver)
2688 // -- x1 : the constructor to call (checked to be a JSProxy)
2689 // -- x3 : the new target (either the same as the constructor or
2690 // the JSFunction on which new was invoked initially)
2691 // -----------------------------------
2692
2693 // Call into the Runtime for Proxy [[Construct]].
2694 __ Push(x1);
2695 __ Push(x3);
2696 // Include the pushed new_target, constructor and the receiver.
2697 __ Add(x0, x0, 3);
2698 // Tail-call to the runtime.
2699 __ JumpToExternalReference(
2700 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2701}
2702
2703
2704// static
2705void Builtins::Generate_Construct(MacroAssembler* masm) {
2706 // ----------- S t a t e -------------
2707 // -- x0 : the number of arguments (not including the receiver)
2708 // -- x1 : the constructor to call (can be any Object)
2709 // -- x3 : the new target (either the same as the constructor or
2710 // the JSFunction on which new was invoked initially)
2711 // -----------------------------------
2712
2713 // Check if target is a Smi.
2714 Label non_constructor;
2715 __ JumpIfSmi(x1, &non_constructor);
2716
2717 // Dispatch based on instance type.
2718 __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
2719 __ Jump(masm->isolate()->builtins()->ConstructFunction(),
2720 RelocInfo::CODE_TARGET, eq);
2721
2722 // Check if target has a [[Construct]] internal method.
2723 __ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
2724 __ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
2725
2726 // Only dispatch to bound functions after checking whether they are
2727 // constructors.
2728 __ Cmp(x5, JS_BOUND_FUNCTION_TYPE);
2729 __ Jump(masm->isolate()->builtins()->ConstructBoundFunction(),
2730 RelocInfo::CODE_TARGET, eq);
2731
2732 // Only dispatch to proxies after checking whether they are constructors.
2733 __ Cmp(x5, JS_PROXY_TYPE);
2734 __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
2735 eq);
2736
2737 // Called Construct on an exotic Object with a [[Construct]] internal method.
2738 {
2739 // Overwrite the original receiver with the (original) target.
2740 __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
2741 // Let the "call_as_constructor_delegate" take care of the rest.
2742 __ LoadNativeContextSlot(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
2743 __ Jump(masm->isolate()->builtins()->CallFunction(),
2744 RelocInfo::CODE_TARGET);
2745 }
2746
2747 // Called Construct on an Object that doesn't have a [[Construct]] internal
2748 // method.
2749 __ bind(&non_constructor);
2750 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2751 RelocInfo::CODE_TARGET);
2752}
2753
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002754// static
Ben Murdochc5610432016-08-08 18:44:38 +01002755void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
2756 ASM_LOCATION("Builtins::Generate_AllocateInNewSpace");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002757 // ----------- S t a t e -------------
Ben Murdochc5610432016-08-08 18:44:38 +01002758 // -- x1 : requested object size (untagged)
2759 // -- lr : return address
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002760 // -----------------------------------
Ben Murdochc5610432016-08-08 18:44:38 +01002761 __ SmiTag(x1);
2762 __ Push(x1);
2763 __ Move(cp, Smi::FromInt(0));
2764 __ TailCallRuntime(Runtime::kAllocateInNewSpace);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002765}
2766
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002767// static
Ben Murdochc5610432016-08-08 18:44:38 +01002768void Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
2769 ASM_LOCATION("Builtins::Generate_AllocateInOldSpace");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002770 // ----------- S t a t e -------------
Ben Murdochc5610432016-08-08 18:44:38 +01002771 // -- x1 : requested object size (untagged)
2772 // -- lr : return address
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002773 // -----------------------------------
Ben Murdochc5610432016-08-08 18:44:38 +01002774 __ SmiTag(x1);
2775 __ Move(x2, Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
2776 __ Push(x1, x2);
2777 __ Move(cp, Smi::FromInt(0));
2778 __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002779}
2780
Ben Murdoch61f157c2016-09-16 13:49:30 +01002781// static
2782void Builtins::Generate_StringToNumber(MacroAssembler* masm) {
2783 // The StringToNumber stub takes one argument in x0.
2784 __ AssertString(x0);
2785
2786 // Check if string has a cached array index.
2787 Label runtime;
2788 __ Ldr(x2, FieldMemOperand(x0, String::kHashFieldOffset));
2789 __ Tst(x2, Operand(String::kContainsCachedArrayIndexMask));
2790 __ B(ne, &runtime);
2791 __ IndexFromHash(x2, x0);
2792 __ Ret();
2793
2794 __ Bind(&runtime);
2795 {
2796 FrameScope frame(masm, StackFrame::INTERNAL);
2797 // Push argument.
2798 __ Push(x0);
2799 // We cannot use a tail call here because this builtin can also be called
2800 // from wasm.
2801 __ CallRuntime(Runtime::kStringToNumber);
2802 }
2803 __ Ret();
2804}
2805
2806// static
2807void Builtins::Generate_ToNumber(MacroAssembler* masm) {
2808 // The ToNumber stub takes one argument in x0.
2809 Label not_smi;
2810 __ JumpIfNotSmi(x0, &not_smi);
2811 __ Ret();
2812 __ Bind(&not_smi);
2813
2814 Label not_heap_number;
2815 __ CompareObjectType(x0, x1, x1, HEAP_NUMBER_TYPE);
2816 // x0: receiver
2817 // x1: receiver instance type
2818 __ B(ne, &not_heap_number);
2819 __ Ret();
2820 __ Bind(&not_heap_number);
2821
2822 __ Jump(masm->isolate()->builtins()->NonNumberToNumber(),
2823 RelocInfo::CODE_TARGET);
2824}
2825
2826// static
2827void Builtins::Generate_NonNumberToNumber(MacroAssembler* masm) {
2828 // The NonNumberToNumber stub takes one argument in x0.
2829 __ AssertNotNumber(x0);
2830
2831 Label not_string;
2832 __ CompareObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE);
2833 // x0: receiver
2834 // x1: receiver instance type
2835 __ B(hs, &not_string);
2836 __ Jump(masm->isolate()->builtins()->StringToNumber(),
2837 RelocInfo::CODE_TARGET);
2838 __ Bind(&not_string);
2839
2840 Label not_oddball;
2841 __ Cmp(x1, ODDBALL_TYPE);
2842 __ B(ne, &not_oddball);
2843 __ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset));
2844 __ Ret();
2845 __ Bind(&not_oddball);
2846 {
2847 FrameScope frame(masm, StackFrame::INTERNAL);
2848 // Push argument.
2849 __ Push(x0);
2850 // We cannot use a tail call here because this builtin can also be called
2851 // from wasm.
2852 __ CallRuntime(Runtime::kToNumber);
2853 }
2854 __ Ret();
2855}
2856
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002857void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2858 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
2859 // ----------- S t a t e -------------
2860 // -- x0 : actual number of arguments
2861 // -- x1 : function (passed through to callee)
2862 // -- x2 : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002863 // -- x3 : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002864 // -----------------------------------
2865
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002866 Register argc_actual = x0; // Excluding the receiver.
2867 Register argc_expected = x2; // Excluding the receiver.
2868 Register function = x1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002869 Register code_entry = x10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002870
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002871 Label invoke, dont_adapt_arguments, stack_overflow;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872
2873 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002874 __ Cmp(argc_actual, argc_expected);
2875 __ B(lt, &too_few);
2876 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2877 __ B(eq, &dont_adapt_arguments);
2878
2879 { // Enough parameters: actual >= expected
2880 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002881 ArgumentAdaptorStackCheck(masm, &stack_overflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002882
2883 Register copy_start = x10;
2884 Register copy_end = x11;
2885 Register copy_to = x12;
2886 Register scratch1 = x13, scratch2 = x14;
2887
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002888 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002889
2890 // Adjust for fp, lr, and the receiver.
2891 __ Add(copy_start, fp, 3 * kPointerSize);
2892 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002893 __ Sub(copy_end, copy_start, scratch2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894 __ Sub(copy_end, copy_end, kPointerSize);
2895 __ Mov(copy_to, jssp);
2896
2897 // Claim space for the arguments, the receiver, and one extra slot.
2898 // The extra slot ensures we do not write under jssp. It will be popped
2899 // later.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002900 __ Add(scratch1, scratch2, 2 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002901 __ Claim(scratch1, 1);
2902
2903 // Copy the arguments (including the receiver) to the new stack frame.
2904 Label copy_2_by_2;
2905 __ Bind(&copy_2_by_2);
2906 __ Ldp(scratch1, scratch2,
2907 MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
2908 __ Stp(scratch1, scratch2,
2909 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
2910 __ Cmp(copy_start, copy_end);
2911 __ B(hi, &copy_2_by_2);
2912
2913 // Correct the space allocated for the extra slot.
2914 __ Drop(1);
2915
2916 __ B(&invoke);
2917 }
2918
2919 { // Too few parameters: Actual < expected
2920 __ Bind(&too_few);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002921
2922 Register copy_from = x10;
2923 Register copy_end = x11;
2924 Register copy_to = x12;
2925 Register scratch1 = x13, scratch2 = x14;
2926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002927 EnterArgumentsAdaptorFrame(masm);
2928 ArgumentAdaptorStackCheck(masm, &stack_overflow);
2929
2930 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002931 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
2932
2933 // Adjust for fp, lr, and the receiver.
2934 __ Add(copy_from, fp, 3 * kPointerSize);
2935 __ Add(copy_from, copy_from, argc_actual);
2936 __ Mov(copy_to, jssp);
2937 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver.
2938 __ Sub(copy_end, copy_end, argc_actual);
2939
2940 // Claim space for the arguments, the receiver, and one extra slot.
2941 // The extra slot ensures we do not write under jssp. It will be popped
2942 // later.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002943 __ Add(scratch1, scratch2, 2 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002944 __ Claim(scratch1, 1);
2945
2946 // Copy the arguments (including the receiver) to the new stack frame.
2947 Label copy_2_by_2;
2948 __ Bind(&copy_2_by_2);
2949 __ Ldp(scratch1, scratch2,
2950 MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
2951 __ Stp(scratch1, scratch2,
2952 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
2953 __ Cmp(copy_to, copy_end);
2954 __ B(hi, &copy_2_by_2);
2955
2956 __ Mov(copy_to, copy_end);
2957
2958 // Fill the remaining expected arguments with undefined.
2959 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
2960 __ Add(copy_end, jssp, kPointerSize);
2961
2962 Label fill;
2963 __ Bind(&fill);
2964 __ Stp(scratch1, scratch1,
2965 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
2966 __ Cmp(copy_to, copy_end);
2967 __ B(hi, &fill);
2968
2969 // Correct the space allocated for the extra slot.
2970 __ Drop(1);
2971 }
2972
2973 // Arguments have been adapted. Now call the entry point.
2974 __ Bind(&invoke);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002975 __ Mov(argc_actual, argc_expected);
2976 // x0 : expected number of arguments
2977 // x1 : function (passed through to callee)
2978 // x3 : new target (passed through to callee)
2979 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002980 __ Call(code_entry);
2981
2982 // Store offset of return address for deoptimizer.
2983 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2984
2985 // Exit frame and return.
2986 LeaveArgumentsAdaptorFrame(masm);
2987 __ Ret();
2988
2989 // Call the entry point without adapting the arguments.
2990 __ Bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002991 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002992 __ Jump(code_entry);
2993
2994 __ Bind(&stack_overflow);
2995 {
2996 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002997 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002998 __ Unreachable();
2999 }
3000}
3001
3002
3003#undef __
3004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003005} // namespace internal
3006} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003007
3008#endif // V8_TARGET_ARCH_ARM