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