1 // 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.
5 #if V8_TARGET_ARCH_ARM64
7 #include "src/arm64/frames-arm64.h"
8 #include "src/codegen.h"
9 #include "src/debug/debug.h"
10 #include "src/deoptimizer.h"
11 #include "src/full-codegen/full-codegen.h"
12 #include "src/runtime/runtime.h"
18 #define __ ACCESS_MASM(masm)
21 // Load the built-in Array function from the current context.
22 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
23 // Load the native context.
24 __ Ldr(result, GlobalObjectMemOperand());
26 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
27 // Load the InternalArray function from the native context.
30 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
34 // Load the built-in InternalArray function from the current context.
35 static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
37 // Load the native context.
38 __ Ldr(result, GlobalObjectMemOperand());
40 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
41 // Load the InternalArray function from the native context.
42 __ Ldr(result, ContextMemOperand(result,
43 Context::INTERNAL_ARRAY_FUNCTION_INDEX));
47 void Builtins::Generate_Adaptor(MacroAssembler* masm,
49 BuiltinExtraArguments extra_args) {
50 // ----------- S t a t e -------------
51 // -- x0 : number of arguments excluding receiver
52 // -- x1 : called function (only guaranteed when
53 // extra_args requires it)
55 // -- sp[0] : last argument
57 // -- sp[4 * (argc - 1)] : first argument (argc == x0)
58 // -- sp[4 * argc] : receiver
59 // -----------------------------------
61 // Insert extra arguments.
62 int num_extra_args = 0;
63 if (extra_args == NEEDS_CALLED_FUNCTION) {
67 DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
70 // JumpToExternalReference expects x0 to contain the number of arguments
71 // including the receiver and the extra arguments.
72 __ Add(x0, x0, num_extra_args + 1);
73 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
77 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
78 // ----------- S t a t e -------------
79 // -- x0 : number of arguments
80 // -- lr : return address
81 // -- sp[...]: constructor arguments
82 // -----------------------------------
83 ASM_LOCATION("Builtins::Generate_InternalArrayCode");
84 Label generic_array_code;
86 // Get the InternalArray function.
87 GenerateLoadInternalArrayFunction(masm, x1);
89 if (FLAG_debug_code) {
90 // Initial map for the builtin InternalArray functions should be maps.
91 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
92 __ Tst(x10, kSmiTagMask);
93 __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
94 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
95 __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
98 // Run the native code for the InternalArray function called as a normal
100 InternalArrayConstructorStub stub(masm->isolate());
101 __ TailCallStub(&stub);
105 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
106 // ----------- S t a t e -------------
107 // -- x0 : number of arguments
108 // -- lr : return address
109 // -- sp[...]: constructor arguments
110 // -----------------------------------
111 ASM_LOCATION("Builtins::Generate_ArrayCode");
112 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
114 // Get the Array function.
115 GenerateLoadArrayFunction(masm, x1);
117 if (FLAG_debug_code) {
118 // Initial map for the builtin Array functions should be maps.
119 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
120 __ Tst(x10, kSmiTagMask);
121 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
122 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
123 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
126 // Run the native code for the Array function called as a normal function.
127 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
129 ArrayConstructorStub stub(masm->isolate());
130 __ TailCallStub(&stub);
135 void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
136 // ----------- S t a t e -------------
137 // -- x0 : number of arguments
138 // -- x1 : constructor function
139 // -- lr : return address
140 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
141 // -- sp[argc * 8] : receiver
142 // -----------------------------------
143 ASM_LOCATION("Builtins::Generate_StringConstructor");
145 // 1. Load the first argument into x0 and get rid of the rest (including the
149 __ Cbz(x0, &no_arguments);
152 __ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
155 // 2a. At least one argument, return x0 if it's a string, otherwise
156 // dispatch to appropriate conversion.
157 Label to_string, symbol_descriptive_string;
159 __ JumpIfSmi(x0, &to_string);
160 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
161 __ CompareObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE);
162 __ B(hi, &to_string);
163 __ B(eq, &symbol_descriptive_string);
167 // 2b. No arguments, return the empty string (and pop the receiver).
168 __ Bind(&no_arguments);
170 __ LoadRoot(x0, Heap::kempty_stringRootIndex);
175 // 3a. Convert x0 to a string.
178 ToStringStub stub(masm->isolate());
179 __ TailCallStub(&stub);
182 // 3b. Convert symbol in x0 to a string.
183 __ Bind(&symbol_descriptive_string);
186 __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1);
192 void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
193 // ----------- S t a t e -------------
194 // -- x0 : number of arguments
195 // -- x1 : constructor function
196 // -- lr : return address
197 // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
198 // -- sp[argc * 8] : receiver
199 // -----------------------------------
200 ASM_LOCATION("Builtins::Generate_StringConstructor_ConstructStub");
202 // 1. Load the first argument into x2 and get rid of the rest (including the
205 Label no_arguments, done;
206 __ Cbz(x0, &no_arguments);
209 __ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
211 __ Bind(&no_arguments);
213 __ LoadRoot(x2, Heap::kempty_stringRootIndex);
217 // 2. Make sure x2 is a string.
219 Label convert, done_convert;
220 __ JumpIfSmi(x2, &convert);
221 __ JumpIfObjectType(x2, x3, x3, FIRST_NONSTRING_TYPE, &done_convert, lo);
224 FrameScope scope(masm, StackFrame::INTERNAL);
225 ToStringStub stub(masm->isolate());
232 __ Bind(&done_convert);
235 // 3. Allocate a JSValue wrapper for the string.
237 // ----------- S t a t e -------------
238 // -- x1 : constructor function
239 // -- x2 : the first argument
240 // -- lr : return address
241 // -----------------------------------
243 Label allocate, done_allocate;
244 __ Allocate(JSValue::kSize, x0, x3, x4, &allocate, TAG_OBJECT);
245 __ Bind(&done_allocate);
247 // Initialize the JSValue in eax.
248 __ LoadGlobalFunctionInitialMap(x1, x3, x4);
249 __ Str(x3, FieldMemOperand(x0, HeapObject::kMapOffset));
250 __ LoadRoot(x3, Heap::kEmptyFixedArrayRootIndex);
251 __ Str(x3, FieldMemOperand(x0, JSObject::kPropertiesOffset));
252 __ Str(x3, FieldMemOperand(x0, JSObject::kElementsOffset));
253 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
254 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
257 // Fallback to the runtime to allocate in new space.
260 FrameScope scope(masm, StackFrame::INTERNAL);
262 __ Push(Smi::FromInt(JSValue::kSize));
263 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
266 __ B(&done_allocate);
271 static void CallRuntimePassFunction(MacroAssembler* masm,
272 Runtime::FunctionId function_id) {
273 FrameScope scope(masm, StackFrame::INTERNAL);
274 // - Push a copy of the function onto the stack.
275 // - Push another copy as a parameter to the runtime call.
278 __ CallRuntime(function_id, 1);
280 // - Restore receiver.
285 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
286 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
287 __ Ldr(x2, FieldMemOperand(x2, SharedFunctionInfo::kCodeOffset));
288 __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
293 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
294 __ Add(x0, x0, Code::kHeaderSize - kHeapObjectTag);
299 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
300 // Checking whether the queued function is ready for install is optional,
301 // since we come across interrupts and stack checks elsewhere. However, not
302 // checking may delay installing ready functions, and always checking would be
303 // quite expensive. A good compromise is to first check against stack limit as
304 // a cue for an interrupt signal.
306 __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
309 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
310 GenerateTailCallToReturnedCode(masm);
313 GenerateTailCallToSharedCode(masm);
317 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
318 bool is_api_function) {
319 // ----------- S t a t e -------------
320 // -- x0 : number of arguments
321 // -- x1 : constructor function
322 // -- x2 : allocation site or undefined
323 // -- x3 : original constructor
324 // -- lr : return address
325 // -- sp[...]: constructor arguments
326 // -----------------------------------
328 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
330 Isolate* isolate = masm->isolate();
332 // Enter a construct frame.
334 FrameScope scope(masm, StackFrame::CONSTRUCT);
336 // Preserve the four incoming parameters on the stack.
338 Register constructor = x1;
339 Register allocation_site = x2;
340 Register original_constructor = x3;
342 // Preserve the incoming parameters on the stack.
343 __ AssertUndefinedOrAllocationSite(allocation_site, x10);
345 __ Push(allocation_site, argc, constructor, original_constructor);
347 // sp[1]: Constructor function.
348 // sp[2]: number of arguments (smi-tagged)
349 // sp[3]: allocation site
351 // Try to allocate the object without transitioning into C code. If any of
352 // the preconditions is not met, the code bails out to the runtime call.
353 Label rt_call, allocated;
354 if (FLAG_inline_new) {
355 ExternalReference debug_step_in_fp =
356 ExternalReference::debug_step_in_fp_address(isolate);
357 __ Mov(x2, Operand(debug_step_in_fp));
358 __ Ldr(x2, MemOperand(x2));
359 __ Cbnz(x2, &rt_call);
361 // Fall back to runtime if the original constructor and function differ.
362 __ Cmp(constructor, original_constructor);
365 // Load the initial map and verify that it is in fact a map.
366 Register init_map = x2;
368 FieldMemOperand(constructor,
369 JSFunction::kPrototypeOrInitialMapOffset));
370 __ JumpIfSmi(init_map, &rt_call);
371 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
373 // Check that the constructor is not constructing a JSFunction (see
374 // comments in Runtime_NewObject in runtime.cc). In which case the initial
375 // map's instance type would be JS_FUNCTION_TYPE.
376 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
379 Register constructon_count = x14;
380 if (!is_api_function) {
382 MemOperand bit_field3 =
383 FieldMemOperand(init_map, Map::kBitField3Offset);
384 // Check if slack tracking is enabled.
385 __ Ldr(x4, bit_field3);
386 __ DecodeField<Map::Counter>(constructon_count, x4);
387 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
389 // Decrease generous allocation count.
390 __ Subs(x4, x4, Operand(1 << Map::Counter::kShift));
391 __ Str(x4, bit_field3);
392 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
395 // Push the constructor and map to the stack, and the constructor again
396 // as argument to the runtime call.
397 __ Push(constructor, init_map, constructor);
398 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
399 __ Pop(init_map, constructor);
400 __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
404 // Now allocate the JSObject on the heap.
405 Label rt_call_reload_new_target;
406 Register obj_size = x3;
407 Register new_obj = x4;
408 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
409 __ Allocate(obj_size, new_obj, x10, x11, &rt_call_reload_new_target,
412 // Allocated the JSObject, now initialize the fields. Map is set to
413 // initial map and properties and elements are set to empty fixed array.
414 // NB. the object pointer is not tagged, so MemOperand is used.
416 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
417 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
418 STATIC_ASSERT(JSObject::kElementsOffset ==
419 (JSObject::kPropertiesOffset + kPointerSize));
420 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
422 Register first_prop = x5;
423 __ Add(first_prop, new_obj, JSObject::kHeaderSize);
425 // Fill all of the in-object properties with the appropriate filler.
426 Register filler = x7;
427 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
429 // Obtain number of pre-allocated property fields and in-object
431 Register unused_props = x10;
432 Register inobject_props = x11;
433 Register inst_sizes_or_attrs = x11;
434 Register prealloc_fields = x10;
435 __ Ldr(inst_sizes_or_attrs,
436 FieldMemOperand(init_map, Map::kInstanceAttributesOffset));
437 __ Ubfx(unused_props, inst_sizes_or_attrs,
438 Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte);
439 __ Ldr(inst_sizes_or_attrs,
440 FieldMemOperand(init_map, Map::kInstanceSizesOffset));
442 inobject_props, inst_sizes_or_attrs,
443 Map::kInObjectPropertiesOrConstructorFunctionIndexByte * kBitsPerByte,
445 __ Sub(prealloc_fields, inobject_props, unused_props);
447 // Calculate number of property fields in the object.
448 Register prop_fields = x6;
449 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
451 if (!is_api_function) {
452 Label no_inobject_slack_tracking;
454 // Check if slack tracking is enabled.
455 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
456 __ B(lt, &no_inobject_slack_tracking);
457 constructon_count = NoReg;
459 // Fill the pre-allocated fields with undef.
460 __ FillFields(first_prop, prealloc_fields, filler);
462 // Update first_prop register to be the offset of the first field after
463 // pre-allocated fields.
464 __ Add(first_prop, first_prop,
465 Operand(prealloc_fields, LSL, kPointerSizeLog2));
467 if (FLAG_debug_code) {
468 Register obj_end = x14;
469 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
470 __ Cmp(first_prop, obj_end);
471 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
474 // Fill the remaining fields with one pointer filler map.
475 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
476 __ Sub(prop_fields, prop_fields, prealloc_fields);
478 __ bind(&no_inobject_slack_tracking);
481 // Fill all of the property fields with undef.
482 __ FillFields(first_prop, prop_fields, filler);
486 // Add the object tag to make the JSObject real, so that we can continue
487 // and jump into the continuation code at any time from now on.
488 __ Add(new_obj, new_obj, kHeapObjectTag);
490 // Continue with JSObject being successfully allocated.
493 // Reload the original constructor and fall-through.
494 __ Bind(&rt_call_reload_new_target);
495 __ Peek(x3, 0 * kXRegSize);
498 // Allocate the new receiver object using the runtime call.
499 // x1: constructor function
500 // x3: original constructor
502 __ Push(constructor, original_constructor); // arguments 1-2
503 __ CallRuntime(Runtime::kNewObject, 2);
506 // Receiver for constructor call allocated.
510 // Restore the parameters.
511 __ Pop(original_constructor);
514 // Reload the number of arguments from the stack.
515 // Set it up in x0 for the function call below.
516 // jssp[0]: number of arguments (smi-tagged)
517 __ Peek(argc, 0); // Load number of arguments.
520 __ Push(original_constructor, x4, x4);
522 // Set up pointer to last argument.
523 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
525 // Copy arguments and receiver to the expression stack.
526 // Copy 2 values every loop to use ldp/stp.
527 // x0: number of arguments
528 // x1: constructor function
529 // x2: address of last argument (caller sp)
532 // jssp[2]: new.target
533 // jssp[3]: number of arguments (smi-tagged)
534 // Compute the start address of the copy in x3.
535 __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
536 Label loop, entry, done_copying_arguments;
539 __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
544 // Because we copied values 2 by 2 we may have copied one extra value.
545 // Drop it if that is the case.
546 __ B(eq, &done_copying_arguments);
548 __ Bind(&done_copying_arguments);
550 // Call the function.
551 // x0: number of arguments
552 // x1: constructor function
553 if (is_api_function) {
554 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
556 masm->isolate()->builtins()->HandleApiCallConstruct();
557 __ Call(code, RelocInfo::CODE_TARGET);
559 ParameterCount actual(argc);
560 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
563 // Store offset of return address for deoptimizer.
564 if (!is_api_function) {
565 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
568 // Restore the context from the frame.
571 // jssp[1]: new.target
572 // jssp[2]: number of arguments (smi-tagged)
573 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
575 // If the result is an object (in the ECMA sense), we should get rid
576 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
578 Label use_receiver, exit;
580 // If the result is a smi, it is *not* an object in the ECMA sense.
582 // jssp[0]: receiver (newly allocated object)
583 // jssp[1]: number of arguments (smi-tagged)
584 __ JumpIfSmi(x0, &use_receiver);
586 // If the type of the result (stored in its map) is less than
587 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
588 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
590 // Throw away the result of the constructor invocation and use the
591 // on-stack receiver as the result.
592 __ Bind(&use_receiver);
595 // Remove the receiver from the stack, remove caller arguments, and
599 // jssp[0]: receiver (newly allocated object)
600 // jssp[1]: new.target (original constructor)
601 // jssp[2]: number of arguments (smi-tagged)
602 __ Peek(x1, 2 * kXRegSize);
604 // Leave construct frame.
609 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
614 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
615 Generate_JSConstructStubHelper(masm, false);
619 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
620 Generate_JSConstructStubHelper(masm, true);
624 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
625 // ----------- S t a t e -------------
626 // -- x0 : number of arguments
627 // -- x1 : constructor function
628 // -- x2 : allocation site or undefined
629 // -- x3 : original constructor
630 // -- lr : return address
631 // -- sp[...]: constructor arguments
632 // -----------------------------------
633 ASM_LOCATION("Builtins::Generate_JSConstructStubForDerived");
636 FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
638 __ AssertUndefinedOrAllocationSite(x2, x10);
641 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
642 __ Push(x2, x4, x3, x10);
643 // sp[0]: receiver (the hole)
645 // sp[2]: number of arguments
646 // sp[3]: allocation site
648 // Set up pointer to last argument.
649 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
651 // Copy arguments and receiver to the expression stack.
652 // Copy 2 values every loop to use ldp/stp.
653 // x0: number of arguments
654 // x1: constructor function
655 // x2: address of last argument (caller sp)
657 // jssp[1]: new.target
658 // jssp[2]: number of arguments (smi-tagged)
659 // Compute the start address of the copy in x4.
660 __ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2));
661 Label loop, entry, done_copying_arguments;
664 __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex));
669 // Because we copied values 2 by 2 we may have copied one extra value.
670 // Drop it if that is the case.
671 __ B(eq, &done_copying_arguments);
673 __ Bind(&done_copying_arguments);
677 ExternalReference debug_step_in_fp =
678 ExternalReference::debug_step_in_fp_address(masm->isolate());
679 __ Mov(x2, Operand(debug_step_in_fp));
680 __ Ldr(x2, MemOperand(x2));
681 __ Cbz(x2, &skip_step_in);
684 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
687 __ bind(&skip_step_in);
689 // Call the function.
690 // x0: number of arguments
691 // x1: constructor function
692 ParameterCount actual(x0);
693 __ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper());
696 // Restore the context from the frame.
698 // jssp[0]: number of arguments (smi-tagged)
699 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
701 // Load number of arguments (smi), skipping over new.target.
702 __ Peek(x1, kPointerSize);
704 // Leave construct frame
713 enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt };
716 // Clobbers x10, x15; preserves all other registers.
717 static void Generate_CheckStackOverflow(MacroAssembler* masm,
718 const int calleeOffset, Register argc,
719 IsTagged argc_is_tagged) {
720 Register function = x15;
722 // Check the stack for overflow.
723 // We are not trying to catch interruptions (e.g. debug break and
724 // preemption) here, so the "real stack limit" is checked.
725 Label enough_stack_space;
726 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
727 __ Ldr(function, MemOperand(fp, calleeOffset));
728 // Make x10 the space we have left. The stack might already be overflowed
729 // here which will cause x10 to become negative.
730 // TODO(jbramley): Check that the stack usage here is safe.
731 __ Sub(x10, jssp, x10);
732 // Check if the arguments will overflow the stack.
733 if (argc_is_tagged == kArgcIsSmiTagged) {
734 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
736 DCHECK(argc_is_tagged == kArgcIsUntaggedInt);
737 __ Cmp(x10, Operand(argc, LSL, kPointerSizeLog2));
739 __ B(gt, &enough_stack_space);
740 // There is not enough stack space, so use a builtin to throw an appropriate
742 if (argc_is_tagged == kArgcIsUntaggedInt) {
745 __ Push(function, argc);
746 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
747 // We should never return from the APPLY_OVERFLOW builtin.
748 if (__ emit_debug_code()) {
752 __ Bind(&enough_stack_space);
764 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
766 // Called from JSEntryStub::GenerateBody().
767 Register function = x1;
768 Register receiver = x2;
772 ProfileEntryHookStub::MaybeCallEntryHook(masm);
774 // Clear the context before we push it when entering the internal frame.
778 // Enter an internal frame.
779 FrameScope scope(masm, StackFrame::INTERNAL);
781 // Set up the context from the function argument.
782 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
784 __ InitializeRootRegister();
786 // Push the function and the receiver onto the stack.
787 __ Push(function, receiver);
789 // Check if we have enough stack space to push all arguments.
790 // The function is the first thing that was pushed above after entering
791 // the internal frame.
792 const int kFunctionOffset =
793 InternalFrameConstants::kCodeOffset - kPointerSize;
794 // Expects argument count in eax. Clobbers ecx, edx, edi.
795 Generate_CheckStackOverflow(masm, kFunctionOffset, argc,
798 // Copy arguments to the stack in a loop, in reverse order.
802 // Compute the copy end address.
803 __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
807 __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
808 __ Ldr(x12, MemOperand(x11)); // Dereference the handle.
809 __ Push(x12); // Push the argument.
814 // Initialize all JavaScript callee-saved registers, since they will be seen
815 // by the garbage collector as part of handlers.
816 // The original values have been saved in JSEntryStub::GenerateBody().
817 __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
824 // Don't initialize the reserved registers.
825 // x26 : root register (root).
826 // x27 : context pointer (cp).
827 // x28 : JS stack pointer (jssp).
828 // x29 : frame pointer (fp).
832 // No type feedback cell is available.
833 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
835 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
838 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
840 // Exit the JS internal frame and remove the parameters (except function),
844 // Result is in x0. Return.
849 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
850 Generate_JSEntryTrampolineHelper(masm, false);
854 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
855 Generate_JSEntryTrampolineHelper(masm, true);
859 // Generate code for entering a JS function with the interpreter.
860 // On entry to the function the receiver and arguments have been pushed on the
861 // stack left to right. The actual argument count matches the formal parameter
862 // count expected by the function.
864 // The live registers are:
865 // - x1: the JS function object being called.
866 // - cp: our context.
867 // - fp: our caller's frame pointer.
868 // - jssp: stack pointer.
869 // - lr: return address.
871 // The function builds a JS frame. Please see JavaScriptFrameConstants in
872 // frames-arm64.h for its layout.
873 // TODO(rmcilroy): We will need to include the current bytecode pointer in the
875 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
876 // Open a frame scope to indicate that there is a frame on the stack. The
877 // MANUAL indicates that the scope shouldn't actually generate code to set up
878 // the frame (that is done below).
879 FrameScope frame_scope(masm, StackFrame::MANUAL);
880 __ Push(lr, fp, cp, x1);
881 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
883 // Get the bytecode array from the function object and load the pointer to the
884 // first entry into kInterpreterBytecodeRegister.
885 __ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
886 __ Ldr(kInterpreterBytecodeArrayRegister,
887 FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
889 if (FLAG_debug_code) {
890 // Check function data field is actually a BytecodeArray object.
891 __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
892 kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
893 __ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
894 BYTECODE_ARRAY_TYPE);
895 __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
898 // Allocate the local and temporary register file on the stack.
900 // Load frame size from the BytecodeArray object.
901 __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister,
902 BytecodeArray::kFrameSizeOffset));
904 // Do a stack check to ensure we don't go over the limit.
906 DCHECK(jssp.Is(__ StackPointer()));
907 __ Sub(x10, jssp, Operand(x11));
908 __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
910 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
913 // If ok, push undefined as the initial value for all register file entries.
914 // Note: there should always be at least one stack slot for the return
915 // register in the register file.
917 __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
918 // TODO(rmcilroy): Ensure we always have an even number of registers to
919 // allow stack to be 16 bit aligned (and remove need for jssp).
920 __ Lsr(x11, x11, kPointerSizeLog2);
921 __ PushMultipleTimes(x10, x11);
922 __ Bind(&loop_header);
925 // TODO(rmcilroy): List of things not currently dealt with here but done in
926 // fullcodegen's prologue:
927 // - Support profiler (specifically profiling_counter).
928 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
929 // - Allow simulator stop operations if FLAG_stop_at is set.
930 // - Deal with sloppy mode functions which need to replace the
931 // receiver with the global proxy when called as functions (without an
932 // explicit receiver object).
933 // - Code aging of the BytecodeArray object.
934 // - Supporting FLAG_trace.
936 // The following items are also not done here, and will probably be done using
937 // explicit bytecodes instead:
938 // - Allocating a new local context if applicable.
939 // - Setting up a local binding to the this function, which is used in
940 // derived constructors with super calls.
941 // - Setting new.target if required.
942 // - Dealing with REST parameters (only if
943 // https://codereview.chromium.org/1235153006 doesn't land by then).
944 // - Dealing with argument objects.
946 // Perform stack guard check.
949 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
951 __ CallRuntime(Runtime::kStackGuard, 0);
955 // Load accumulator, register file, bytecode offset, dispatch table into
957 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
958 __ Sub(kInterpreterRegisterFileRegister, fp,
959 Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
960 __ Mov(kInterpreterBytecodeOffsetRegister,
961 Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
962 __ LoadRoot(kInterpreterDispatchTableRegister,
963 Heap::kInterpreterTableRootIndex);
964 __ Add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
965 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
967 // Dispatch to the first bytecode handler for the function.
968 __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
969 kInterpreterBytecodeOffsetRegister));
970 __ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
971 __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
972 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
973 // and header removal.
974 __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
979 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
980 // TODO(rmcilroy): List of things not currently dealt with here but done in
981 // fullcodegen's EmitReturnSequence.
982 // - Supporting FLAG_trace for Runtime::TraceExit.
983 // - Support profiler (specifically decrementing profiling_counter
984 // appropriately and calling out to HandleInterrupts if necessary).
986 // The return value is in accumulator, which is already in x0.
988 // Leave the frame (also dropping the register file).
989 __ LeaveFrame(StackFrame::JAVA_SCRIPT);
991 // Drop receiver + arguments and return.
992 __ Ldr(w1, FieldMemOperand(kInterpreterBytecodeArrayRegister,
993 BytecodeArray::kParameterSizeOffset));
999 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
1000 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
1001 GenerateTailCallToReturnedCode(masm);
1005 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
1006 FrameScope scope(masm, StackFrame::INTERNAL);
1007 Register function = x1;
1009 // Preserve function. At the same time, push arguments for
1010 // kCompileOptimized.
1011 __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
1012 __ Push(function, function, x10);
1014 __ CallRuntime(Runtime::kCompileOptimized, 2);
1016 // Restore receiver.
1021 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
1022 CallCompileOptimized(masm, false);
1023 GenerateTailCallToReturnedCode(masm);
1027 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
1028 CallCompileOptimized(masm, true);
1029 GenerateTailCallToReturnedCode(masm);
1033 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1034 // For now, we are relying on the fact that make_code_young doesn't do any
1035 // garbage collection which allows us to save/restore the registers without
1036 // worrying about which of them contain pointers. We also don't build an
1037 // internal frame to make the code fast, since we shouldn't have to do stack
1038 // crawls in MakeCodeYoung. This seems a bit fragile.
1040 // The following caller-saved registers must be saved and restored when
1041 // calling through to the runtime:
1042 // x0 - The address from which to resume execution.
1044 // lr - The return address for the JSFunction itself. It has not yet been
1045 // preserved on the stack because the frame setup code was replaced
1046 // with a call to this stub, to handle code ageing.
1048 FrameScope scope(masm, StackFrame::MANUAL);
1049 __ Push(x0, x1, fp, lr);
1050 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1052 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
1053 __ Pop(lr, fp, x1, x0);
1056 // The calling function has been made young again, so return to execute the
1057 // real frame set-up code.
1061 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
1062 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
1063 MacroAssembler* masm) { \
1064 GenerateMakeCodeYoungAgainCommon(masm); \
1066 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
1067 MacroAssembler* masm) { \
1068 GenerateMakeCodeYoungAgainCommon(masm); \
1070 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1071 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1074 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1075 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1076 // that make_code_young doesn't do any garbage collection which allows us to
1077 // save/restore the registers without worrying about which of them contain
1080 // The following caller-saved registers must be saved and restored when
1081 // calling through to the runtime:
1082 // x0 - The address from which to resume execution.
1084 // lr - The return address for the JSFunction itself. It has not yet been
1085 // preserved on the stack because the frame setup code was replaced
1086 // with a call to this stub, to handle code ageing.
1088 FrameScope scope(masm, StackFrame::MANUAL);
1089 __ Push(x0, x1, fp, lr);
1090 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1092 ExternalReference::get_mark_code_as_executed_function(
1093 masm->isolate()), 2);
1094 __ Pop(lr, fp, x1, x0);
1096 // Perform prologue operations usually performed by the young code stub.
1097 __ EmitFrameSetupForCodeAgePatching(masm);
1100 // Jump to point after the code-age stub.
1101 __ Add(x0, x0, kNoCodeAgeSequenceLength);
1106 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1107 GenerateMakeCodeYoungAgainCommon(masm);
1111 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1112 Generate_MarkCodeAsExecutedOnce(masm);
1116 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1117 SaveFPRegsMode save_doubles) {
1119 FrameScope scope(masm, StackFrame::INTERNAL);
1121 // Preserve registers across notification, this is important for compiled
1122 // stubs that tail call the runtime on deopts passing their parameters in
1124 // TODO(jbramley): Is it correct (and appropriate) to use safepoint
1125 // registers here? According to the comment above, we should only need to
1126 // preserve the registers with parameters.
1127 __ PushXRegList(kSafepointSavedRegisters);
1128 // Pass the function and deoptimization type to the runtime system.
1129 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
1130 __ PopXRegList(kSafepointSavedRegisters);
1133 // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
1136 // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
1137 // into lr before it jumps here.
1142 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1143 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1147 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1148 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1152 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1153 Deoptimizer::BailoutType type) {
1155 FrameScope scope(masm, StackFrame::INTERNAL);
1156 // Pass the deoptimization type to the runtime system.
1157 __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
1159 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
1162 // Get the full codegen state from the stack and untag it.
1163 Register state = x6;
1167 // Switch on the state.
1168 Label with_tos_register, unknown_state;
1169 __ CompareAndBranch(
1170 state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
1171 __ Drop(1); // Remove state.
1174 __ Bind(&with_tos_register);
1175 // Reload TOS register.
1176 __ Peek(x0, kPointerSize);
1177 __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
1178 __ Drop(2); // Remove state and TOS.
1181 __ Bind(&unknown_state);
1182 __ Abort(kInvalidFullCodegenState);
1186 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1187 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1191 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1192 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1196 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1197 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1201 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1202 // Lookup the function in the JavaScript frame.
1203 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1205 FrameScope scope(masm, StackFrame::INTERNAL);
1206 // Pass function as argument.
1208 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1211 // If the code object is null, just return to the unoptimized code.
1213 __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
1218 // Load deoptimization data from the code object.
1219 // <deopt_data> = <code>[#deoptimization_data_offset]
1220 __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1222 // Load the OSR entrypoint offset from the deoptimization data.
1223 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1224 __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1225 DeoptimizationInputData::kOsrPcOffsetIndex)));
1227 // Compute the target address = code_obj + header_size + osr_offset
1228 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1230 __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1232 // And "return" to the OSR entry point of the function.
1237 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1238 // We check the stack limit as indicator that recompilation might be done.
1240 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
1243 FrameScope scope(masm, StackFrame::INTERNAL);
1244 __ CallRuntime(Runtime::kStackGuard, 0);
1246 __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1247 RelocInfo::CODE_TARGET);
1254 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1256 Register function = x1;
1257 Register scratch1 = x10;
1258 Register scratch2 = x11;
1260 ASM_LOCATION("Builtins::Generate_FunctionCall");
1261 // 1. Make sure we have at least one argument.
1264 __ Cbnz(argc, &done);
1265 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1271 // 2. Get the callable to call (passed as receiver) from the stack.
1272 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1274 // 3. Shift arguments and return address one slot down on the stack
1275 // (overwriting the original receiver). Adjust argument count to make
1276 // the original first argument the new receiver.
1279 // Calculate the copy start address (destination). Copy end address is jssp.
1280 __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1281 __ Sub(scratch1, scratch2, kPointerSize);
1284 __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1285 __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1286 __ Cmp(scratch1, jssp);
1288 // Adjust the actual number of arguments and remove the top element
1289 // (which is a copy of the last argument).
1290 __ Sub(argc, argc, 1);
1294 // 4. Call the callable.
1295 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1299 static void Generate_PushAppliedArguments(MacroAssembler* masm,
1300 const int vectorOffset,
1301 const int argumentsOffset,
1302 const int indexOffset,
1303 const int limitOffset) {
1305 Register receiver = LoadDescriptor::ReceiverRegister();
1306 Register key = LoadDescriptor::NameRegister();
1307 Register slot = LoadDescriptor::SlotRegister();
1308 Register vector = LoadWithVectorDescriptor::VectorRegister();
1310 __ Ldr(key, MemOperand(fp, indexOffset));
1313 // Load the current argument from the arguments array.
1315 __ Ldr(receiver, MemOperand(fp, argumentsOffset));
1317 // Use inline caching to speed up access to arguments.
1318 int slot_index = TypeFeedbackVector::PushAppliedArgumentsIndex();
1319 __ Mov(slot, Operand(Smi::FromInt(slot_index)));
1320 __ Ldr(vector, MemOperand(fp, vectorOffset));
1322 KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode();
1323 __ Call(ic, RelocInfo::CODE_TARGET);
1325 // Push the nth argument.
1328 __ Ldr(key, MemOperand(fp, indexOffset));
1329 __ Add(key, key, Smi::FromInt(1));
1330 __ Str(key, MemOperand(fp, indexOffset));
1332 // Test if the copy loop has finished copying all the elements from the
1333 // arguments object.
1335 __ Ldr(x1, MemOperand(fp, limitOffset));
1339 // On exit, the pushed arguments count is in x0, untagged
1345 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
1346 const int kFormalParameters = targetIsArgument ? 3 : 2;
1347 const int kStackSize = kFormalParameters + 1;
1350 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1352 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
1353 const int kReceiverOffset = kArgumentsOffset + kPointerSize;
1354 const int kFunctionOffset = kReceiverOffset + kPointerSize;
1355 const int kVectorOffset =
1356 InternalFrameConstants::kCodeOffset - 1 * kPointerSize;
1357 const int kIndexOffset = kVectorOffset - (2 * kPointerSize);
1358 const int kLimitOffset = kVectorOffset - (1 * kPointerSize);
1360 Register args = x12;
1361 Register receiver = x14;
1362 Register function = x15;
1363 Register apply_function = x1;
1368 FieldMemOperand(apply_function, JSFunction::kSharedFunctionInfoOffset));
1369 __ Ldr(apply_function,
1370 FieldMemOperand(apply_function,
1371 SharedFunctionInfo::kFeedbackVectorOffset));
1372 __ Push(apply_function);
1374 // Get the length of the arguments via a builtin call.
1375 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1376 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1377 __ Push(function, args);
1378 if (targetIsArgument) {
1379 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
1382 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION);
1386 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1388 // Push current limit, index and receiver.
1389 __ Mov(x1, 0); // Initial index.
1390 __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
1391 __ Push(argc, x1, receiver);
1393 // Copy all arguments from the array to the stack.
1394 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset,
1395 kIndexOffset, kLimitOffset);
1397 // At the end of the loop, the number of arguments is stored in x0, untagged
1399 // Call the callable.
1400 // TODO(bmeurer): This should be a tail call according to ES6.
1401 __ Ldr(x1, MemOperand(fp, kFunctionOffset));
1402 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1404 __ Drop(kStackSize);
1409 static void Generate_ConstructHelper(MacroAssembler* masm) {
1410 const int kFormalParameters = 3;
1411 const int kStackSize = kFormalParameters + 1;
1414 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1416 const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
1417 const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
1418 const int kFunctionOffset = kArgumentsOffset + kPointerSize;
1419 const int kVectorOffset =
1420 InternalFrameConstants::kCodeOffset - 1 * kPointerSize;
1421 const int kIndexOffset = kVectorOffset - (2 * kPointerSize);
1422 const int kLimitOffset = kVectorOffset - (1 * kPointerSize);
1424 // Is x11 safe to use?
1425 Register newTarget = x11;
1426 Register args = x12;
1427 Register function = x15;
1428 Register construct_function = x1;
1431 __ Ldr(construct_function,
1432 FieldMemOperand(construct_function,
1433 JSFunction::kSharedFunctionInfoOffset));
1434 __ Ldr(construct_function,
1435 FieldMemOperand(construct_function,
1436 SharedFunctionInfo::kFeedbackVectorOffset));
1437 __ Push(construct_function);
1439 // If newTarget is not supplied, set it to constructor
1440 Label validate_arguments;
1441 __ Ldr(x0, MemOperand(fp, kNewTargetOffset));
1442 __ CompareRoot(x0, Heap::kUndefinedValueRootIndex);
1443 __ B(ne, &validate_arguments);
1444 __ Ldr(x0, MemOperand(fp, kFunctionOffset));
1445 __ Str(x0, MemOperand(fp, kNewTargetOffset));
1447 // Validate arguments
1448 __ Bind(&validate_arguments);
1449 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1450 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1451 __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset));
1452 __ Push(function, args, newTarget);
1453 __ InvokeBuiltin(Context::REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX,
1457 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1459 // Push current limit and index & constructor function as callee.
1460 __ Mov(x1, 0); // Initial index.
1461 __ Push(argc, x1, function);
1463 // Copy all arguments from the array to the stack.
1464 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset,
1465 kIndexOffset, kLimitOffset);
1467 // Use undefined feedback vector
1468 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
1469 __ Ldr(x1, MemOperand(fp, kFunctionOffset));
1470 __ Ldr(x4, MemOperand(fp, kNewTargetOffset));
1472 // Call the function.
1473 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
1474 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
1476 // Leave internal frame.
1478 __ Drop(kStackSize);
1483 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1484 ASM_LOCATION("Builtins::Generate_FunctionApply");
1485 Generate_ApplyHelper(masm, false);
1489 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1490 ASM_LOCATION("Builtins::Generate_ReflectApply");
1491 Generate_ApplyHelper(masm, true);
1495 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1496 ASM_LOCATION("Builtins::Generate_ReflectConstruct");
1497 Generate_ConstructHelper(masm);
1501 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
1502 Label* stack_overflow) {
1503 // ----------- S t a t e -------------
1504 // -- x0 : actual number of arguments
1505 // -- x1 : function (passed through to callee)
1506 // -- x2 : expected number of arguments
1507 // -----------------------------------
1508 // Check the stack for overflow.
1509 // We are not trying to catch interruptions (e.g. debug break and
1510 // preemption) here, so the "real stack limit" is checked.
1511 Label enough_stack_space;
1512 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1513 // Make x10 the space we have left. The stack might already be overflowed
1514 // here which will cause x10 to become negative.
1515 __ Sub(x10, jssp, x10);
1516 // Check if the arguments will overflow the stack.
1517 __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
1518 __ B(le, stack_overflow);
1522 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1524 __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1526 __ Push(x11, x1, x10);
1528 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
1532 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1533 // ----------- S t a t e -------------
1534 // -- x0 : result being passed through
1535 // -----------------------------------
1536 // Get the number of arguments passed (as a smi), tear down the frame and
1537 // then drop the parameters and the receiver.
1538 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1542 __ DropBySMI(x10, kXRegSize);
1548 void Builtins::Generate_CallFunction(MacroAssembler* masm) {
1549 // ----------- S t a t e -------------
1550 // -- x0 : the number of arguments (not including the receiver)
1551 // -- x1 : the function to call (checked to be a JSFunction)
1552 // -----------------------------------
1554 Label convert, convert_global_proxy, convert_to_object, done_convert;
1555 __ AssertFunction(x1);
1556 // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
1557 // slot is "classConstructor".
1558 // Enter the context of the function; ToObject has to run in the function
1559 // context, and we also need to take the global proxy from the function
1560 // context in case of conversion.
1561 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1562 __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
1563 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
1564 // We need to convert the receiver for non-native sloppy mode functions.
1565 __ Ldr(w3, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
1566 __ TestAndBranchIfAnySet(w3,
1567 (1 << SharedFunctionInfo::kNative) |
1568 (1 << SharedFunctionInfo::kStrictModeFunction),
1571 __ Peek(x3, Operand(x0, LSL, kXRegSizeLog2));
1573 // ----------- S t a t e -------------
1574 // -- x0 : the number of arguments (not including the receiver)
1575 // -- x1 : the function to call (checked to be a JSFunction)
1576 // -- x2 : the shared function info.
1577 // -- x3 : the receiver
1578 // -- cp : the function context.
1579 // -----------------------------------
1581 Label convert_receiver;
1582 __ JumpIfSmi(x3, &convert_to_object);
1583 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1584 __ CompareObjectType(x3, x4, x4, FIRST_JS_RECEIVER_TYPE);
1585 __ B(hs, &done_convert);
1586 __ JumpIfRoot(x3, Heap::kUndefinedValueRootIndex, &convert_global_proxy);
1587 __ JumpIfNotRoot(x3, Heap::kNullValueRootIndex, &convert_to_object);
1588 __ Bind(&convert_global_proxy);
1590 // Patch receiver to global proxy.
1591 __ LoadGlobalProxy(x3);
1593 __ B(&convert_receiver);
1594 __ Bind(&convert_to_object);
1596 // Convert receiver using ToObject.
1597 // TODO(bmeurer): Inline the allocation here to avoid building the frame
1598 // in the fast case? (fall back to AllocateInNewSpace?)
1599 FrameScope scope(masm, StackFrame::INTERNAL);
1603 ToObjectStub stub(masm->isolate());
1609 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
1610 __ Bind(&convert_receiver);
1611 __ Poke(x3, Operand(x0, LSL, kXRegSizeLog2));
1613 __ Bind(&done_convert);
1615 // ----------- S t a t e -------------
1616 // -- x0 : the number of arguments (not including the receiver)
1617 // -- x1 : the function to call (checked to be a JSFunction)
1618 // -- x2 : the shared function info.
1619 // -- cp : the function context.
1620 // -----------------------------------
1623 x2, FieldMemOperand(x2, SharedFunctionInfo::kFormalParameterCountOffset));
1624 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
1625 ParameterCount actual(x0);
1626 ParameterCount expected(x2);
1627 __ InvokeCode(x3, expected, actual, JUMP_FUNCTION, NullCallWrapper());
1632 void Builtins::Generate_Call(MacroAssembler* masm) {
1633 // ----------- S t a t e -------------
1634 // -- x0 : the number of arguments (not including the receiver)
1635 // -- x1 : the target to call (can be any Object).
1636 // -----------------------------------
1638 Label non_smi, non_jsfunction, non_function;
1639 __ JumpIfSmi(x1, &non_function);
1641 __ CompareObjectType(x1, x2, x2, JS_FUNCTION_TYPE);
1642 __ B(ne, &non_jsfunction);
1643 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
1644 __ Bind(&non_jsfunction);
1645 __ Cmp(x2, JS_FUNCTION_PROXY_TYPE);
1646 __ B(ne, &non_function);
1648 // 1. Call to function proxy.
1649 // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
1650 __ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kCallTrapOffset));
1651 __ AssertNotSmi(x1);
1654 // 2. Call to something else, which might have a [[Call]] internal method (if
1655 // not we raise an exception).
1656 __ Bind(&non_function);
1657 // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
1658 // be awesome instead; i.e. a trivial improvement would be to call into the
1659 // runtime and just deal with the API function there instead of returning a
1660 // delegate from a runtime call that just jumps back to the runtime once
1661 // called. Or, bonus points, call directly into the C API function here, as
1662 // we do in some Crankshaft fast cases.
1663 // Overwrite the original receiver with the (original) target.
1664 __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
1666 // Determine the delegate for the target (if any).
1667 FrameScope scope(masm, StackFrame::INTERNAL);
1670 __ CallRuntime(Runtime::kGetFunctionDelegate, 1);
1675 // The delegate is always a regular function.
1676 __ AssertFunction(x1);
1677 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
1682 void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) {
1683 // ----------- S t a t e -------------
1684 // -- x0 : the number of arguments (not including the receiver)
1685 // -- x2 : the address of the first argument to be pushed. Subsequent
1686 // arguments should be consecutive above this, in the same order as
1687 // they are to be pushed onto the stack.
1688 // -- x1 : the target to call (can be any Object).
1690 // Find the address of the last argument.
1691 __ add(x3, x0, Operand(1)); // Add one for receiver.
1692 __ lsl(x3, x3, kPointerSizeLog2);
1695 // Push the arguments.
1696 Label loop_header, loop_check;
1700 __ Bind(&loop_header);
1701 // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
1702 __ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
1703 __ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
1704 __ Bind(&loop_check);
1706 __ B(gt, &loop_header);
1709 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1713 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1714 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
1715 // ----------- S t a t e -------------
1716 // -- x0 : actual number of arguments
1717 // -- x1 : function (passed through to callee)
1718 // -- x2 : expected number of arguments
1719 // -----------------------------------
1721 Label stack_overflow;
1722 ArgumentAdaptorStackCheck(masm, &stack_overflow);
1724 Register argc_actual = x0; // Excluding the receiver.
1725 Register argc_expected = x2; // Excluding the receiver.
1726 Register function = x1;
1727 Register code_entry = x3;
1729 Label invoke, dont_adapt_arguments;
1731 Label enough, too_few;
1732 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1733 __ Cmp(argc_actual, argc_expected);
1735 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1736 __ B(eq, &dont_adapt_arguments);
1738 { // Enough parameters: actual >= expected
1739 EnterArgumentsAdaptorFrame(masm);
1741 Register copy_start = x10;
1742 Register copy_end = x11;
1743 Register copy_to = x12;
1744 Register scratch1 = x13, scratch2 = x14;
1746 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
1748 // Adjust for fp, lr, and the receiver.
1749 __ Add(copy_start, fp, 3 * kPointerSize);
1750 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
1751 __ Sub(copy_end, copy_start, scratch2);
1752 __ Sub(copy_end, copy_end, kPointerSize);
1753 __ Mov(copy_to, jssp);
1755 // Claim space for the arguments, the receiver, and one extra slot.
1756 // The extra slot ensures we do not write under jssp. It will be popped
1758 __ Add(scratch1, scratch2, 2 * kPointerSize);
1759 __ Claim(scratch1, 1);
1761 // Copy the arguments (including the receiver) to the new stack frame.
1763 __ Bind(©_2_by_2);
1764 __ Ldp(scratch1, scratch2,
1765 MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
1766 __ Stp(scratch1, scratch2,
1767 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1768 __ Cmp(copy_start, copy_end);
1769 __ B(hi, ©_2_by_2);
1771 // Correct the space allocated for the extra slot.
1777 { // Too few parameters: Actual < expected
1780 Register copy_from = x10;
1781 Register copy_end = x11;
1782 Register copy_to = x12;
1783 Register scratch1 = x13, scratch2 = x14;
1785 // If the function is strong we need to throw an error.
1786 Label no_strong_error;
1788 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1789 __ Ldr(scratch2.W(),
1790 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1791 __ TestAndBranchIfAllClear(scratch2.W(),
1792 (1 << SharedFunctionInfo::kStrongModeFunction),
1795 // What we really care about is the required number of arguments.
1796 DCHECK_EQ(kPointerSize, kInt64Size);
1797 __ Ldr(scratch2.W(),
1798 FieldMemOperand(scratch1, SharedFunctionInfo::kLengthOffset));
1799 __ Cmp(argc_actual, Operand(scratch2, LSR, 1));
1800 __ B(ge, &no_strong_error);
1803 FrameScope frame(masm, StackFrame::MANUAL);
1804 EnterArgumentsAdaptorFrame(masm);
1805 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments, 0);
1808 __ Bind(&no_strong_error);
1809 EnterArgumentsAdaptorFrame(masm);
1811 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
1812 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
1814 // Adjust for fp, lr, and the receiver.
1815 __ Add(copy_from, fp, 3 * kPointerSize);
1816 __ Add(copy_from, copy_from, argc_actual);
1817 __ Mov(copy_to, jssp);
1818 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver.
1819 __ Sub(copy_end, copy_end, argc_actual);
1821 // Claim space for the arguments, the receiver, and one extra slot.
1822 // The extra slot ensures we do not write under jssp. It will be popped
1824 __ Add(scratch1, scratch2, 2 * kPointerSize);
1825 __ Claim(scratch1, 1);
1827 // Copy the arguments (including the receiver) to the new stack frame.
1829 __ Bind(©_2_by_2);
1830 __ Ldp(scratch1, scratch2,
1831 MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
1832 __ Stp(scratch1, scratch2,
1833 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1834 __ Cmp(copy_to, copy_end);
1835 __ B(hi, ©_2_by_2);
1837 __ Mov(copy_to, copy_end);
1839 // Fill the remaining expected arguments with undefined.
1840 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1841 __ Add(copy_end, jssp, kPointerSize);
1845 __ Stp(scratch1, scratch1,
1846 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1847 __ Cmp(copy_to, copy_end);
1850 // Correct the space allocated for the extra slot.
1854 // Arguments have been adapted. Now call the entry point.
1856 __ Mov(argc_actual, argc_expected);
1857 // x0 : expected number of arguments
1858 // x1 : function (passed through to callee)
1859 __ Call(code_entry);
1861 // Store offset of return address for deoptimizer.
1862 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1864 // Exit frame and return.
1865 LeaveArgumentsAdaptorFrame(masm);
1868 // Call the entry point without adapting the arguments.
1869 __ Bind(&dont_adapt_arguments);
1870 __ Jump(code_entry);
1872 __ Bind(&stack_overflow);
1874 FrameScope frame(masm, StackFrame::MANUAL);
1875 EnterArgumentsAdaptorFrame(masm);
1876 __ CallRuntime(Runtime::kThrowStackOverflow, 0);
1884 } // namespace internal
1887 #endif // V8_TARGET_ARCH_ARM