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);
134 void 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);
147 Register function = x1;
148 if (FLAG_debug_code) {
149 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, x10);
150 __ Cmp(function, x10);
151 __ Assert(eq, kUnexpectedStringFunction);
154 // Load the first arguments in x0 and get rid of the rest.
156 __ Cbz(argc, &no_arguments);
157 // First args = sp[(argc - 1) * 8].
158 __ Sub(argc, argc, 1);
159 __ Drop(argc, kXRegSize);
160 // jssp now point to args[0], load and drop args[0] + receiver.
162 __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
165 Register argument = x2;
166 Label not_cached, argument_is_string;
167 __ LookupNumberStringCache(arg, // Input.
173 __ IncrementCounter(counters->string_ctor_cached_number(), 1, x10, x11);
174 __ Bind(&argument_is_string);
176 // ----------- S t a t e -------------
177 // -- x2 : argument converted to string
178 // -- x1 : constructor function
179 // -- lr : return address
180 // -----------------------------------
183 Register new_obj = x0;
184 __ Allocate(JSValue::kSize, new_obj, x10, x11, &gc_required, TAG_OBJECT);
186 // Initialize the String object.
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));
195 __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
197 __ Str(map, FieldMemOperand(new_obj, HeapObject::kMapOffset));
200 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
201 __ Str(empty, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
202 __ Str(empty, FieldMemOperand(new_obj, JSObject::kElementsOffset));
204 __ Str(argument, FieldMemOperand(new_obj, JSValue::kValueOffset));
206 // Ensure the object is fully initialized.
207 STATIC_ASSERT(JSValue::kSize == (4 * kPointerSize));
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(¬_cached);
215 __ JumpIfSmi(arg, &convert_argument);
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);
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);
230 FrameScope scope(masm, StackFrame::INTERNAL);
231 ToStringStub stub(masm->isolate());
235 __ Mov(argument, x0);
236 __ B(&argument_is_string);
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);
243 __ B(&argument_is_string);
245 // At this point the argument is already a string. Call runtime to create a
247 __ Bind(&gc_required);
248 __ IncrementCounter(counters->string_ctor_gc_required(), 1, x10, x11);
250 FrameScope scope(masm, StackFrame::INTERNAL);
252 __ CallRuntime(Runtime::kNewStringWrapper, 1);
258 static 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.
265 __ CallRuntime(function_id, 1);
267 // - Restore receiver.
272 static 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);
280 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
281 __ Add(x0, x0, Code::kHeaderSize - kHeapObjectTag);
286 void 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.
293 __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
296 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
297 GenerateTailCallToReturnedCode(masm);
300 GenerateTailCallToSharedCode(masm);
304 static 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 // -- x3 : original constructor
312 // -- lr : return address
313 // -- sp[...]: constructor arguments
314 // -----------------------------------
316 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
317 // Should never create mementos for api functions.
318 DCHECK(!is_api_function || !create_memento);
320 Isolate* isolate = masm->isolate();
322 // Enter a construct frame.
324 FrameScope scope(masm, StackFrame::CONSTRUCT);
326 // Preserve the four incoming parameters on the stack.
328 Register constructor = x1;
329 Register allocation_site = x2;
330 Register original_constructor = x3;
332 // Preserve the incoming parameters on the stack.
333 __ AssertUndefinedOrAllocationSite(allocation_site, x10);
335 __ Push(allocation_site, argc, constructor, original_constructor);
337 // sp[1]: Constructor function.
338 // sp[2]: number of arguments (smi-tagged)
339 // sp[3]: allocation site
341 // Try to allocate the object without transitioning into C code. If any of
342 // the preconditions is not met, the code bails out to the runtime call.
343 Label rt_call, allocated;
344 if (FLAG_inline_new) {
345 ExternalReference debug_step_in_fp =
346 ExternalReference::debug_step_in_fp_address(isolate);
347 __ Mov(x2, Operand(debug_step_in_fp));
348 __ Ldr(x2, MemOperand(x2));
349 __ Cbnz(x2, &rt_call);
351 // Fall back to runtime if the original constructor and function differ.
352 __ Cmp(constructor, original_constructor);
355 // Load the initial map and verify that it is in fact a map.
356 Register init_map = x2;
358 FieldMemOperand(constructor,
359 JSFunction::kPrototypeOrInitialMapOffset));
360 __ JumpIfSmi(init_map, &rt_call);
361 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
363 // Check that the constructor is not constructing a JSFunction (see
364 // comments in Runtime_NewObject in runtime.cc). In which case the initial
365 // map's instance type would be JS_FUNCTION_TYPE.
366 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
369 Register constructon_count = x14;
370 if (!is_api_function) {
372 MemOperand bit_field3 =
373 FieldMemOperand(init_map, Map::kBitField3Offset);
374 // Check if slack tracking is enabled.
375 __ Ldr(x4, bit_field3);
376 __ DecodeField<Map::Counter>(constructon_count, x4);
377 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
379 // Decrease generous allocation count.
380 __ Subs(x4, x4, Operand(1 << Map::Counter::kShift));
381 __ Str(x4, bit_field3);
382 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
385 // Push the constructor and map to the stack, and the constructor again
386 // as argument to the runtime call.
387 __ Push(constructor, init_map, constructor);
388 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
389 __ Pop(init_map, constructor);
390 __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
394 // Now allocate the JSObject on the heap.
395 Label rt_call_reload_new_target;
396 Register obj_size = x3;
397 Register new_obj = x4;
398 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
399 if (create_memento) {
401 Operand(AllocationMemento::kSize / kPointerSize));
402 __ Allocate(x7, new_obj, x10, x11, &rt_call_reload_new_target,
405 __ Allocate(obj_size, new_obj, x10, x11, &rt_call_reload_new_target,
409 // Allocated the JSObject, now initialize the fields. Map is set to
410 // initial map and properties and elements are set to empty fixed array.
411 // NB. the object pointer is not tagged, so MemOperand is used.
413 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
414 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
415 STATIC_ASSERT(JSObject::kElementsOffset ==
416 (JSObject::kPropertiesOffset + kPointerSize));
417 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
419 Register first_prop = x5;
420 __ Add(first_prop, new_obj, JSObject::kHeaderSize);
422 // Fill all of the in-object properties with the appropriate filler.
423 Register filler = x7;
424 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
426 // Obtain number of pre-allocated property fields and in-object
428 Register unused_props = x10;
429 Register inobject_props = x11;
430 Register inst_sizes_or_attrs = x11;
431 Register prealloc_fields = x10;
432 __ Ldr(inst_sizes_or_attrs,
433 FieldMemOperand(init_map, Map::kInstanceAttributesOffset));
434 __ Ubfx(unused_props, inst_sizes_or_attrs,
435 Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte);
436 __ Ldr(inst_sizes_or_attrs,
437 FieldMemOperand(init_map, Map::kInstanceSizesOffset));
439 inobject_props, inst_sizes_or_attrs,
440 Map::kInObjectPropertiesOrConstructorFunctionIndexByte * kBitsPerByte,
442 __ Sub(prealloc_fields, inobject_props, unused_props);
444 // Calculate number of property fields in the object.
445 Register prop_fields = x6;
446 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
448 if (!is_api_function) {
449 Label no_inobject_slack_tracking;
451 // Check if slack tracking is enabled.
452 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
453 __ B(lt, &no_inobject_slack_tracking);
454 constructon_count = NoReg;
456 // Fill the pre-allocated fields with undef.
457 __ FillFields(first_prop, prealloc_fields, filler);
459 // Update first_prop register to be the offset of the first field after
460 // pre-allocated fields.
461 __ Add(first_prop, first_prop,
462 Operand(prealloc_fields, LSL, kPointerSizeLog2));
464 if (FLAG_debug_code) {
465 Register obj_end = x14;
466 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
467 __ Cmp(first_prop, obj_end);
468 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
471 // Fill the remaining fields with one pointer filler map.
472 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
473 __ Sub(prop_fields, prop_fields, prealloc_fields);
475 __ bind(&no_inobject_slack_tracking);
477 if (create_memento) {
478 // Fill the pre-allocated fields with undef.
479 __ FillFields(first_prop, prop_fields, filler);
480 __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
481 __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex);
482 DCHECK_EQ(0 * kPointerSize, AllocationMemento::kMapOffset);
483 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
484 // Load the AllocationSite
485 __ Peek(x14, 3 * kXRegSize);
486 __ AssertUndefinedOrAllocationSite(x14, x10);
487 DCHECK_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset);
488 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
491 // Fill all of the property fields with undef.
492 __ FillFields(first_prop, prop_fields, filler);
497 // Add the object tag to make the JSObject real, so that we can continue
498 // and jump into the continuation code at any time from now on.
499 __ Add(new_obj, new_obj, kHeapObjectTag);
501 // Continue with JSObject being successfully allocated.
504 // Reload the original constructor and fall-through.
505 __ Bind(&rt_call_reload_new_target);
506 __ Peek(x3, 0 * kXRegSize);
509 // Allocate the new receiver object using the runtime call.
510 // x1: constructor function
511 // x3: original constructor
513 Label count_incremented;
514 if (create_memento) {
515 // Get the cell or allocation site.
516 __ Peek(x4, 3 * kXRegSize);
517 __ Push(x4, constructor, original_constructor); // arguments 1-3
518 __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
520 // If we ended up using the runtime, and we want a memento, then the
521 // runtime call made it for us, and we shouldn't do create count
523 __ B(&count_incremented);
525 __ Push(constructor, original_constructor); // arguments 1-2
526 __ CallRuntime(Runtime::kNewObject, 2);
530 // Receiver for constructor call allocated.
534 if (create_memento) {
535 __ Peek(x10, 3 * kXRegSize);
536 __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
537 // r2 is an AllocationSite. We are creating a memento from it, so we
538 // need to increment the memento create count.
539 __ Ldr(x5, FieldMemOperand(x10,
540 AllocationSite::kPretenureCreateCountOffset));
541 __ Add(x5, x5, Operand(Smi::FromInt(1)));
542 __ Str(x5, FieldMemOperand(x10,
543 AllocationSite::kPretenureCreateCountOffset));
544 __ bind(&count_incremented);
547 // Restore the parameters.
548 __ Pop(original_constructor);
551 // Reload the number of arguments from the stack.
552 // Set it up in x0 for the function call below.
553 // jssp[0]: number of arguments (smi-tagged)
554 __ Peek(argc, 0); // Load number of arguments.
557 __ Push(original_constructor, x4, x4);
559 // Set up pointer to last argument.
560 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
562 // Copy arguments and receiver to the expression stack.
563 // Copy 2 values every loop to use ldp/stp.
564 // x0: number of arguments
565 // x1: constructor function
566 // x2: address of last argument (caller sp)
569 // jssp[2]: new.target
570 // jssp[3]: number of arguments (smi-tagged)
571 // Compute the start address of the copy in x3.
572 __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
573 Label loop, entry, done_copying_arguments;
576 __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
581 // Because we copied values 2 by 2 we may have copied one extra value.
582 // Drop it if that is the case.
583 __ B(eq, &done_copying_arguments);
585 __ Bind(&done_copying_arguments);
587 // Call the function.
588 // x0: number of arguments
589 // x1: constructor function
590 if (is_api_function) {
591 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
593 masm->isolate()->builtins()->HandleApiCallConstruct();
594 __ Call(code, RelocInfo::CODE_TARGET);
596 ParameterCount actual(argc);
597 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
600 // Store offset of return address for deoptimizer.
601 if (!is_api_function) {
602 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
605 // Restore the context from the frame.
608 // jssp[1]: new.target
609 // jssp[2]: number of arguments (smi-tagged)
610 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
612 // If the result is an object (in the ECMA sense), we should get rid
613 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
615 Label use_receiver, exit;
617 // If the result is a smi, it is *not* an object in the ECMA sense.
619 // jssp[0]: receiver (newly allocated object)
620 // jssp[1]: number of arguments (smi-tagged)
621 __ JumpIfSmi(x0, &use_receiver);
623 // If the type of the result (stored in its map) is less than
624 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
625 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
627 // Throw away the result of the constructor invocation and use the
628 // on-stack receiver as the result.
629 __ Bind(&use_receiver);
632 // Remove the receiver from the stack, remove caller arguments, and
636 // jssp[0]: receiver (newly allocated object)
637 // jssp[1]: new.target (original constructor)
638 // jssp[2]: number of arguments (smi-tagged)
639 __ Peek(x1, 2 * kXRegSize);
641 // Leave construct frame.
646 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
651 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
652 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
656 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
657 Generate_JSConstructStubHelper(masm, true, false);
661 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
662 // ----------- S t a t e -------------
663 // -- x0 : number of arguments
664 // -- x1 : constructor function
665 // -- x2 : allocation site or undefined
666 // -- x3 : original constructor
667 // -- lr : return address
668 // -- sp[...]: constructor arguments
669 // -----------------------------------
670 ASM_LOCATION("Builtins::Generate_JSConstructStubForDerived");
673 FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
675 __ AssertUndefinedOrAllocationSite(x2, x10);
678 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
679 __ Push(x2, x4, x3, x10);
680 // sp[0]: receiver (the hole)
682 // sp[2]: number of arguments
683 // sp[3]: allocation site
685 // Set up pointer to last argument.
686 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
688 // Copy arguments and receiver to the expression stack.
689 // Copy 2 values every loop to use ldp/stp.
690 // x0: number of arguments
691 // x1: constructor function
692 // x2: address of last argument (caller sp)
694 // jssp[1]: new.target
695 // jssp[2]: number of arguments (smi-tagged)
696 // Compute the start address of the copy in x4.
697 __ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2));
698 Label loop, entry, done_copying_arguments;
701 __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex));
706 // Because we copied values 2 by 2 we may have copied one extra value.
707 // Drop it if that is the case.
708 __ B(eq, &done_copying_arguments);
710 __ Bind(&done_copying_arguments);
714 ExternalReference debug_step_in_fp =
715 ExternalReference::debug_step_in_fp_address(masm->isolate());
716 __ Mov(x2, Operand(debug_step_in_fp));
717 __ Ldr(x2, MemOperand(x2));
718 __ Cbz(x2, &skip_step_in);
721 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
724 __ bind(&skip_step_in);
726 // Call the function.
727 // x0: number of arguments
728 // x1: constructor function
729 ParameterCount actual(x0);
730 __ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper());
733 // Restore the context from the frame.
735 // jssp[0]: number of arguments (smi-tagged)
736 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
738 // Load number of arguments (smi), skipping over new.target.
739 __ Peek(x1, kPointerSize);
741 // Leave construct frame
750 enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt };
753 // Clobbers x10, x15; preserves all other registers.
754 static void Generate_CheckStackOverflow(MacroAssembler* masm,
755 const int calleeOffset, Register argc,
756 IsTagged argc_is_tagged) {
757 Register function = x15;
759 // Check the stack for overflow.
760 // We are not trying to catch interruptions (e.g. debug break and
761 // preemption) here, so the "real stack limit" is checked.
762 Label enough_stack_space;
763 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
764 __ Ldr(function, MemOperand(fp, calleeOffset));
765 // Make x10 the space we have left. The stack might already be overflowed
766 // here which will cause x10 to become negative.
767 // TODO(jbramley): Check that the stack usage here is safe.
768 __ Sub(x10, jssp, x10);
769 // Check if the arguments will overflow the stack.
770 if (argc_is_tagged == kArgcIsSmiTagged) {
771 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
773 DCHECK(argc_is_tagged == kArgcIsUntaggedInt);
774 __ Cmp(x10, Operand(argc, LSL, kPointerSizeLog2));
776 __ B(gt, &enough_stack_space);
777 // There is not enough stack space, so use a builtin to throw an appropriate
779 if (argc_is_tagged == kArgcIsUntaggedInt) {
782 __ Push(function, argc);
783 __ InvokeBuiltin(Context::STACK_OVERFLOW_BUILTIN_INDEX, CALL_FUNCTION);
784 // We should never return from the APPLY_OVERFLOW builtin.
785 if (__ emit_debug_code()) {
789 __ Bind(&enough_stack_space);
801 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
803 // Called from JSEntryStub::GenerateBody().
804 Register function = x1;
805 Register receiver = x2;
809 ProfileEntryHookStub::MaybeCallEntryHook(masm);
811 // Clear the context before we push it when entering the internal frame.
815 // Enter an internal frame.
816 FrameScope scope(masm, StackFrame::INTERNAL);
818 // Set up the context from the function argument.
819 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
821 __ InitializeRootRegister();
823 // Push the function and the receiver onto the stack.
824 __ Push(function, receiver);
826 // Check if we have enough stack space to push all arguments.
827 // The function is the first thing that was pushed above after entering
828 // the internal frame.
829 const int kFunctionOffset =
830 InternalFrameConstants::kCodeOffset - kPointerSize;
831 // Expects argument count in eax. Clobbers ecx, edx, edi.
832 Generate_CheckStackOverflow(masm, kFunctionOffset, argc,
835 // Copy arguments to the stack in a loop, in reverse order.
839 // Compute the copy end address.
840 __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
844 __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
845 __ Ldr(x12, MemOperand(x11)); // Dereference the handle.
846 __ Push(x12); // Push the argument.
851 // Initialize all JavaScript callee-saved registers, since they will be seen
852 // by the garbage collector as part of handlers.
853 // The original values have been saved in JSEntryStub::GenerateBody().
854 __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
861 // Don't initialize the reserved registers.
862 // x26 : root register (root).
863 // x27 : context pointer (cp).
864 // x28 : JS stack pointer (jssp).
865 // x29 : frame pointer (fp).
869 // No type feedback cell is available.
870 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
872 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
875 ParameterCount actual(x0);
876 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
878 // Exit the JS internal frame and remove the parameters (except function),
882 // Result is in x0. Return.
887 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
888 Generate_JSEntryTrampolineHelper(masm, false);
892 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
893 Generate_JSEntryTrampolineHelper(masm, true);
897 // Generate code for entering a JS function with the interpreter.
898 // On entry to the function the receiver and arguments have been pushed on the
899 // stack left to right. The actual argument count matches the formal parameter
900 // count expected by the function.
902 // The live registers are:
903 // - x1: the JS function object being called.
904 // - cp: our context.
905 // - fp: our caller's frame pointer.
906 // - jssp: stack pointer.
907 // - lr: return address.
909 // The function builds a JS frame. Please see JavaScriptFrameConstants in
910 // frames-arm64.h for its layout.
911 // TODO(rmcilroy): We will need to include the current bytecode pointer in the
913 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
914 // Open a frame scope to indicate that there is a frame on the stack. The
915 // MANUAL indicates that the scope shouldn't actually generate code to set up
916 // the frame (that is done below).
917 FrameScope frame_scope(masm, StackFrame::MANUAL);
918 __ Push(lr, fp, cp, x1);
919 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
921 // Get the bytecode array from the function object and load the pointer to the
922 // first entry into kInterpreterBytecodeRegister.
923 __ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
924 __ Ldr(kInterpreterBytecodeArrayRegister,
925 FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
927 if (FLAG_debug_code) {
928 // Check function data field is actually a BytecodeArray object.
929 __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
930 kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
931 __ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
932 BYTECODE_ARRAY_TYPE);
933 __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
936 // Allocate the local and temporary register file on the stack.
938 // Load frame size from the BytecodeArray object.
939 __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister,
940 BytecodeArray::kFrameSizeOffset));
942 // Do a stack check to ensure we don't go over the limit.
944 DCHECK(jssp.Is(__ StackPointer()));
945 __ Sub(x10, jssp, Operand(x11));
946 __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
948 __ InvokeBuiltin(Context::STACK_OVERFLOW_BUILTIN_INDEX, CALL_FUNCTION);
951 // If ok, push undefined as the initial value for all register file entries.
952 // Note: there should always be at least one stack slot for the return
953 // register in the register file.
955 __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
956 // TODO(rmcilroy): Ensure we always have an even number of registers to
957 // allow stack to be 16 bit aligned (and remove need for jssp).
958 __ Lsr(x11, x11, kPointerSizeLog2);
959 __ PushMultipleTimes(x10, x11);
960 __ Bind(&loop_header);
963 // TODO(rmcilroy): List of things not currently dealt with here but done in
964 // fullcodegen's prologue:
965 // - Support profiler (specifically profiling_counter).
966 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
967 // - Allow simulator stop operations if FLAG_stop_at is set.
968 // - Deal with sloppy mode functions which need to replace the
969 // receiver with the global proxy when called as functions (without an
970 // explicit receiver object).
971 // - Code aging of the BytecodeArray object.
972 // - Supporting FLAG_trace.
974 // The following items are also not done here, and will probably be done using
975 // explicit bytecodes instead:
976 // - Allocating a new local context if applicable.
977 // - Setting up a local binding to the this function, which is used in
978 // derived constructors with super calls.
979 // - Setting new.target if required.
980 // - Dealing with REST parameters (only if
981 // https://codereview.chromium.org/1235153006 doesn't land by then).
982 // - Dealing with argument objects.
984 // Perform stack guard check.
987 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
989 __ CallRuntime(Runtime::kStackGuard, 0);
993 // Load accumulator, register file, bytecode offset, dispatch table into
995 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
996 __ Sub(kInterpreterRegisterFileRegister, fp,
997 Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
998 __ Mov(kInterpreterBytecodeOffsetRegister,
999 Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
1000 __ LoadRoot(kInterpreterDispatchTableRegister,
1001 Heap::kInterpreterTableRootIndex);
1002 __ Add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
1003 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1005 // Dispatch to the first bytecode handler for the function.
1006 __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
1007 kInterpreterBytecodeOffsetRegister));
1008 __ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
1009 __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
1010 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
1011 // and header removal.
1012 __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
1017 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
1018 // TODO(rmcilroy): List of things not currently dealt with here but done in
1019 // fullcodegen's EmitReturnSequence.
1020 // - Supporting FLAG_trace for Runtime::TraceExit.
1021 // - Support profiler (specifically decrementing profiling_counter
1022 // appropriately and calling out to HandleInterrupts if necessary).
1024 // The return value is in accumulator, which is already in x0.
1026 // Leave the frame (also dropping the register file).
1027 __ LeaveFrame(StackFrame::JAVA_SCRIPT);
1029 // Drop receiver + arguments and return.
1030 __ Ldr(w1, FieldMemOperand(kInterpreterBytecodeArrayRegister,
1031 BytecodeArray::kParameterSizeOffset));
1037 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
1038 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
1039 GenerateTailCallToReturnedCode(masm);
1043 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
1044 FrameScope scope(masm, StackFrame::INTERNAL);
1045 Register function = x1;
1047 // Preserve function. At the same time, push arguments for
1048 // kCompileOptimized.
1049 __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
1050 __ Push(function, function, x10);
1052 __ CallRuntime(Runtime::kCompileOptimized, 2);
1054 // Restore receiver.
1059 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
1060 CallCompileOptimized(masm, false);
1061 GenerateTailCallToReturnedCode(masm);
1065 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
1066 CallCompileOptimized(masm, true);
1067 GenerateTailCallToReturnedCode(masm);
1071 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1072 // For now, we are relying on the fact that make_code_young doesn't do any
1073 // garbage collection which allows us to save/restore the registers without
1074 // worrying about which of them contain pointers. We also don't build an
1075 // internal frame to make the code fast, since we shouldn't have to do stack
1076 // crawls in MakeCodeYoung. This seems a bit fragile.
1078 // The following caller-saved registers must be saved and restored when
1079 // calling through to the runtime:
1080 // x0 - The address from which to resume execution.
1082 // lr - The return address for the JSFunction itself. It has not yet been
1083 // preserved on the stack because the frame setup code was replaced
1084 // with a call to this stub, to handle code ageing.
1086 FrameScope scope(masm, StackFrame::MANUAL);
1087 __ Push(x0, x1, fp, lr);
1088 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1090 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
1091 __ Pop(lr, fp, x1, x0);
1094 // The calling function has been made young again, so return to execute the
1095 // real frame set-up code.
1099 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
1100 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
1101 MacroAssembler* masm) { \
1102 GenerateMakeCodeYoungAgainCommon(masm); \
1104 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
1105 MacroAssembler* masm) { \
1106 GenerateMakeCodeYoungAgainCommon(masm); \
1108 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1109 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1112 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1113 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1114 // that make_code_young doesn't do any garbage collection which allows us to
1115 // save/restore the registers without worrying about which of them contain
1118 // The following caller-saved registers must be saved and restored when
1119 // calling through to the runtime:
1120 // x0 - The address from which to resume execution.
1122 // lr - The return address for the JSFunction itself. It has not yet been
1123 // preserved on the stack because the frame setup code was replaced
1124 // with a call to this stub, to handle code ageing.
1126 FrameScope scope(masm, StackFrame::MANUAL);
1127 __ Push(x0, x1, fp, lr);
1128 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1130 ExternalReference::get_mark_code_as_executed_function(
1131 masm->isolate()), 2);
1132 __ Pop(lr, fp, x1, x0);
1134 // Perform prologue operations usually performed by the young code stub.
1135 __ EmitFrameSetupForCodeAgePatching(masm);
1138 // Jump to point after the code-age stub.
1139 __ Add(x0, x0, kNoCodeAgeSequenceLength);
1144 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1145 GenerateMakeCodeYoungAgainCommon(masm);
1149 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1150 Generate_MarkCodeAsExecutedOnce(masm);
1154 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1155 SaveFPRegsMode save_doubles) {
1157 FrameScope scope(masm, StackFrame::INTERNAL);
1159 // Preserve registers across notification, this is important for compiled
1160 // stubs that tail call the runtime on deopts passing their parameters in
1162 // TODO(jbramley): Is it correct (and appropriate) to use safepoint
1163 // registers here? According to the comment above, we should only need to
1164 // preserve the registers with parameters.
1165 __ PushXRegList(kSafepointSavedRegisters);
1166 // Pass the function and deoptimization type to the runtime system.
1167 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
1168 __ PopXRegList(kSafepointSavedRegisters);
1171 // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
1174 // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
1175 // into lr before it jumps here.
1180 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1181 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1185 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1186 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1190 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1191 Deoptimizer::BailoutType type) {
1193 FrameScope scope(masm, StackFrame::INTERNAL);
1194 // Pass the deoptimization type to the runtime system.
1195 __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
1197 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
1200 // Get the full codegen state from the stack and untag it.
1201 Register state = x6;
1205 // Switch on the state.
1206 Label with_tos_register, unknown_state;
1207 __ CompareAndBranch(
1208 state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
1209 __ Drop(1); // Remove state.
1212 __ Bind(&with_tos_register);
1213 // Reload TOS register.
1214 __ Peek(x0, kPointerSize);
1215 __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
1216 __ Drop(2); // Remove state and TOS.
1219 __ Bind(&unknown_state);
1220 __ Abort(kInvalidFullCodegenState);
1224 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1225 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1229 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1230 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1234 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1235 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1239 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1240 // Lookup the function in the JavaScript frame.
1241 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1243 FrameScope scope(masm, StackFrame::INTERNAL);
1244 // Pass function as argument.
1246 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1249 // If the code object is null, just return to the unoptimized code.
1251 __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
1256 // Load deoptimization data from the code object.
1257 // <deopt_data> = <code>[#deoptimization_data_offset]
1258 __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1260 // Load the OSR entrypoint offset from the deoptimization data.
1261 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1262 __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1263 DeoptimizationInputData::kOsrPcOffsetIndex)));
1265 // Compute the target address = code_obj + header_size + osr_offset
1266 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1268 __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1270 // And "return" to the OSR entry point of the function.
1275 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1276 // We check the stack limit as indicator that recompilation might be done.
1278 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
1281 FrameScope scope(masm, StackFrame::INTERNAL);
1282 __ CallRuntime(Runtime::kStackGuard, 0);
1284 __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1285 RelocInfo::CODE_TARGET);
1292 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1294 call_type_JS_func = 0,
1295 call_type_func_proxy = 1,
1296 call_type_non_func = 2
1299 Register function = x1;
1300 Register call_type = x4;
1301 Register scratch1 = x10;
1302 Register scratch2 = x11;
1303 Register receiver_type = x13;
1305 ASM_LOCATION("Builtins::Generate_FunctionCall");
1306 // 1. Make sure we have at least one argument.
1308 __ Cbnz(argc, &done);
1309 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1315 // 2. Get the function to call (passed as receiver) from the stack, check
1316 // if it is a function.
1317 Label slow, non_function;
1318 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1319 __ JumpIfSmi(function, &non_function);
1320 __ JumpIfNotObjectType(function, scratch1, receiver_type,
1321 JS_FUNCTION_TYPE, &slow);
1323 // 3a. Patch the first argument if necessary when calling a function.
1324 Label shift_arguments;
1325 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1326 { Label convert_to_object, use_global_proxy, patch_receiver;
1327 // Change context eagerly in case we need the global receiver.
1328 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1330 // Do not transform the receiver for strict mode functions.
1331 // Also do not transform the receiver for native (Compilerhints already in
1334 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1335 __ Ldr(scratch2.W(),
1336 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1337 __ TestAndBranchIfAnySet(
1339 (1 << SharedFunctionInfo::kStrictModeFunction) |
1340 (1 << SharedFunctionInfo::kNative),
1343 // Compute the receiver in sloppy mode.
1344 Register receiver = x2;
1345 __ Sub(scratch1, argc, 1);
1346 __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1347 __ JumpIfSmi(receiver, &convert_to_object);
1349 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1351 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
1353 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1354 __ JumpIfObjectType(receiver, scratch1, scratch2,
1355 FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
1357 __ Bind(&convert_to_object);
1360 // Enter an internal frame in order to preserve argument count.
1361 FrameScope scope(masm, StackFrame::INTERNAL);
1365 __ Mov(x0, receiver);
1366 ToObjectStub stub(masm->isolate());
1368 __ Mov(receiver, x0);
1373 // Exit the internal frame.
1376 // Restore the function and flag in the registers.
1377 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1378 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1379 __ B(&patch_receiver);
1381 __ Bind(&use_global_proxy);
1382 __ Ldr(receiver, GlobalObjectMemOperand());
1384 FieldMemOperand(receiver, GlobalObject::kGlobalProxyOffset));
1387 __ Bind(&patch_receiver);
1388 __ Sub(scratch1, argc, 1);
1389 __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1391 __ B(&shift_arguments);
1394 // 3b. Check for function proxy.
1396 __ Mov(call_type, static_cast<int>(call_type_func_proxy));
1397 __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
1398 __ B(eq, &shift_arguments);
1399 __ Bind(&non_function);
1400 __ Mov(call_type, static_cast<int>(call_type_non_func));
1402 // 3c. Patch the first argument when calling a non-function. The
1403 // CALL_NON_FUNCTION builtin expects the non-function callee as
1404 // receiver, so overwrite the first argument which will ultimately
1405 // become the receiver.
1406 // call type (0: JS function, 1: function proxy, 2: non-function)
1407 __ Sub(scratch1, argc, 1);
1408 __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
1410 // 4. Shift arguments and return address one slot down on the stack
1411 // (overwriting the original receiver). Adjust argument count to make
1412 // the original first argument the new receiver.
1413 // call type (0: JS function, 1: function proxy, 2: non-function)
1414 __ Bind(&shift_arguments);
1416 // Calculate the copy start address (destination). Copy end address is jssp.
1417 __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1418 __ Sub(scratch1, scratch2, kPointerSize);
1421 __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1422 __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1423 __ Cmp(scratch1, jssp);
1425 // Adjust the actual number of arguments and remove the top element
1426 // (which is a copy of the last argument).
1427 __ Sub(argc, argc, 1);
1431 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1432 // or a function proxy via CALL_FUNCTION_PROXY.
1433 // call type (0: JS function, 1: function proxy, 2: non-function)
1434 { Label js_function, non_proxy;
1435 __ Cbz(call_type, &js_function);
1436 // Expected number of arguments is 0 for CALL_NON_FUNCTION.
1438 __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
1439 __ B(ne, &non_proxy);
1441 __ Push(function); // Re-add proxy object as additional argument.
1442 __ Add(argc, argc, 1);
1443 __ GetBuiltinFunction(function, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
1444 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1445 RelocInfo::CODE_TARGET);
1447 __ Bind(&non_proxy);
1448 __ GetBuiltinFunction(function, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
1449 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1450 RelocInfo::CODE_TARGET);
1451 __ Bind(&js_function);
1454 // 5b. Get the code to call from the function and check that the number of
1455 // expected arguments matches what we're providing. If so, jump
1456 // (tail-call) to the code in register edx without checking arguments.
1457 __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1460 SharedFunctionInfo::kFormalParameterCountOffset));
1461 Label dont_adapt_args;
1462 __ Cmp(x2, argc); // Check formal and actual parameter counts.
1463 __ B(eq, &dont_adapt_args);
1464 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1465 RelocInfo::CODE_TARGET);
1466 __ Bind(&dont_adapt_args);
1468 __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1469 ParameterCount expected(0);
1470 __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
1474 static void Generate_PushAppliedArguments(MacroAssembler* masm,
1475 const int argumentsOffset,
1476 const int indexOffset,
1477 const int limitOffset) {
1479 Register receiver = LoadDescriptor::ReceiverRegister();
1480 Register key = LoadDescriptor::NameRegister();
1481 Register slot = LoadDescriptor::SlotRegister();
1482 Register vector = LoadWithVectorDescriptor::VectorRegister();
1484 __ Ldr(key, MemOperand(fp, indexOffset));
1487 // Load the current argument from the arguments array.
1489 __ Ldr(receiver, MemOperand(fp, argumentsOffset));
1491 // Use inline caching to speed up access to arguments.
1492 Code::Kind kinds[] = {Code::KEYED_LOAD_IC};
1493 FeedbackVectorSpec spec(0, 1, kinds);
1494 Handle<TypeFeedbackVector> feedback_vector =
1495 masm->isolate()->factory()->NewTypeFeedbackVector(&spec);
1496 int index = feedback_vector->GetIndex(FeedbackVectorICSlot(0));
1497 __ Mov(slot, Smi::FromInt(index));
1498 __ Mov(vector, feedback_vector);
1500 KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode();
1501 __ Call(ic, RelocInfo::CODE_TARGET);
1503 // Push the nth argument.
1506 __ Ldr(key, MemOperand(fp, indexOffset));
1507 __ Add(key, key, Smi::FromInt(1));
1508 __ Str(key, MemOperand(fp, indexOffset));
1510 // Test if the copy loop has finished copying all the elements from the
1511 // arguments object.
1513 __ Ldr(x1, MemOperand(fp, limitOffset));
1517 // On exit, the pushed arguments count is in x0, untagged
1523 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
1524 const int kFormalParameters = targetIsArgument ? 3 : 2;
1525 const int kStackSize = kFormalParameters + 1;
1528 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1530 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
1531 const int kReceiverOffset = kArgumentsOffset + kPointerSize;
1532 const int kFunctionOffset = kReceiverOffset + kPointerSize;
1533 const int kIndexOffset =
1534 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1535 const int kLimitOffset =
1536 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1538 Register args = x12;
1539 Register receiver = x14;
1540 Register function = x15;
1542 // Get the length of the arguments via a builtin call.
1543 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1544 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1545 __ Push(function, args);
1546 if (targetIsArgument) {
1547 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX,
1550 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION);
1554 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1556 // Push current limit and index.
1557 __ Mov(x1, 0); // Initial index.
1560 Label push_receiver;
1561 __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
1563 // Check that the function is a JS function. Otherwise it must be a proxy.
1564 // When it is not the function proxy will be invoked later.
1565 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
1568 // Change context eagerly to get the right global object if necessary.
1569 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1570 // Load the shared function info.
1571 __ Ldr(x2, FieldMemOperand(function,
1572 JSFunction::kSharedFunctionInfoOffset));
1574 // Compute and push the receiver.
1575 // Do not transform the receiver for strict mode functions.
1576 Label convert_receiver_to_object, use_global_proxy;
1577 __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
1578 __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
1579 // Do not transform the receiver for native functions.
1580 __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
1582 // Compute the receiver in sloppy mode.
1583 __ JumpIfSmi(receiver, &convert_receiver_to_object);
1584 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
1585 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1588 // Check if the receiver is already a JavaScript object.
1589 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1590 __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
1591 &push_receiver, ge);
1593 // Call a builtin to convert the receiver to a regular object.
1594 __ Bind(&convert_receiver_to_object);
1595 __ Mov(x0, receiver);
1596 ToObjectStub stub(masm->isolate());
1598 __ Mov(receiver, x0);
1599 __ B(&push_receiver);
1601 __ Bind(&use_global_proxy);
1602 __ Ldr(x10, GlobalObjectMemOperand());
1603 __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
1605 // Push the receiver
1606 __ Bind(&push_receiver);
1609 // Copy all arguments from the array to the stack.
1610 Generate_PushAppliedArguments(
1611 masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1613 // At the end of the loop, the number of arguments is stored in 'current',
1614 // represented as a smi.
1616 function = x1; // From now on we want the function to be kept in x1;
1617 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1619 // Call the function.
1621 ParameterCount actual(x0);
1622 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
1623 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
1624 frame_scope.GenerateLeaveFrame();
1625 __ Drop(kStackSize);
1628 // Call the function proxy.
1629 __ Bind(&call_proxy);
1632 __ Push(function); // Add function proxy as last argument.
1635 __ GetBuiltinFunction(x1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
1636 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1637 RelocInfo::CODE_TARGET);
1639 __ Drop(kStackSize);
1644 static void Generate_ConstructHelper(MacroAssembler* masm) {
1645 const int kFormalParameters = 3;
1646 const int kStackSize = kFormalParameters + 1;
1649 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1651 const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
1652 const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
1653 const int kFunctionOffset = kArgumentsOffset + kPointerSize;
1655 const int kIndexOffset =
1656 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1657 const int kLimitOffset =
1658 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1660 // Is x11 safe to use?
1661 Register newTarget = x11;
1662 Register args = x12;
1663 Register function = x15;
1665 // If newTarget is not supplied, set it to constructor
1666 Label validate_arguments;
1667 __ Ldr(x0, MemOperand(fp, kNewTargetOffset));
1668 __ CompareRoot(x0, Heap::kUndefinedValueRootIndex);
1669 __ B(ne, &validate_arguments);
1670 __ Ldr(x0, MemOperand(fp, kFunctionOffset));
1671 __ Str(x0, MemOperand(fp, kNewTargetOffset));
1673 // Validate arguments
1674 __ Bind(&validate_arguments);
1675 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1676 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1677 __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset));
1678 __ Push(function, args, newTarget);
1679 __ InvokeBuiltin(Context::REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX,
1683 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1685 // Push current limit and index & constructor function as callee.
1686 __ Mov(x1, 0); // Initial index.
1687 __ Push(argc, x1, function);
1689 // Copy all arguments from the array to the stack.
1690 Generate_PushAppliedArguments(
1691 masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1693 // Use undefined feedback vector
1694 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
1695 __ Ldr(x1, MemOperand(fp, kFunctionOffset));
1696 __ Ldr(x4, MemOperand(fp, kNewTargetOffset));
1698 // Call the function.
1699 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
1700 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
1702 // Leave internal frame.
1704 __ Drop(kStackSize);
1709 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1710 ASM_LOCATION("Builtins::Generate_FunctionApply");
1711 Generate_ApplyHelper(masm, false);
1715 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1716 ASM_LOCATION("Builtins::Generate_ReflectApply");
1717 Generate_ApplyHelper(masm, true);
1721 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1722 ASM_LOCATION("Builtins::Generate_ReflectConstruct");
1723 Generate_ConstructHelper(masm);
1727 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
1728 Label* stack_overflow) {
1729 // ----------- S t a t e -------------
1730 // -- x0 : actual number of arguments
1731 // -- x1 : function (passed through to callee)
1732 // -- x2 : expected number of arguments
1733 // -----------------------------------
1734 // Check the stack for overflow.
1735 // We are not trying to catch interruptions (e.g. debug break and
1736 // preemption) here, so the "real stack limit" is checked.
1737 Label enough_stack_space;
1738 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1739 // Make x10 the space we have left. The stack might already be overflowed
1740 // here which will cause x10 to become negative.
1741 __ Sub(x10, jssp, x10);
1742 // Check if the arguments will overflow the stack.
1743 __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
1744 __ B(le, stack_overflow);
1748 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1750 __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1752 __ Push(x11, x1, x10);
1754 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
1758 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1759 // ----------- S t a t e -------------
1760 // -- x0 : result being passed through
1761 // -----------------------------------
1762 // Get the number of arguments passed (as a smi), tear down the frame and
1763 // then drop the parameters and the receiver.
1764 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1768 __ DropBySMI(x10, kXRegSize);
1773 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1774 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
1775 // ----------- S t a t e -------------
1776 // -- x0 : actual number of arguments
1777 // -- x1 : function (passed through to callee)
1778 // -- x2 : expected number of arguments
1779 // -----------------------------------
1781 Label stack_overflow;
1782 ArgumentAdaptorStackCheck(masm, &stack_overflow);
1784 Register argc_actual = x0; // Excluding the receiver.
1785 Register argc_expected = x2; // Excluding the receiver.
1786 Register function = x1;
1787 Register code_entry = x3;
1789 Label invoke, dont_adapt_arguments;
1791 Label enough, too_few;
1792 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1793 __ Cmp(argc_actual, argc_expected);
1795 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1796 __ B(eq, &dont_adapt_arguments);
1798 { // Enough parameters: actual >= expected
1799 EnterArgumentsAdaptorFrame(masm);
1801 Register copy_start = x10;
1802 Register copy_end = x11;
1803 Register copy_to = x12;
1804 Register scratch1 = x13, scratch2 = x14;
1806 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
1808 // Adjust for fp, lr, and the receiver.
1809 __ Add(copy_start, fp, 3 * kPointerSize);
1810 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
1811 __ Sub(copy_end, copy_start, scratch2);
1812 __ Sub(copy_end, copy_end, kPointerSize);
1813 __ Mov(copy_to, jssp);
1815 // Claim space for the arguments, the receiver, and one extra slot.
1816 // The extra slot ensures we do not write under jssp. It will be popped
1818 __ Add(scratch1, scratch2, 2 * kPointerSize);
1819 __ Claim(scratch1, 1);
1821 // Copy the arguments (including the receiver) to the new stack frame.
1823 __ Bind(©_2_by_2);
1824 __ Ldp(scratch1, scratch2,
1825 MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
1826 __ Stp(scratch1, scratch2,
1827 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1828 __ Cmp(copy_start, copy_end);
1829 __ B(hi, ©_2_by_2);
1831 // Correct the space allocated for the extra slot.
1837 { // Too few parameters: Actual < expected
1840 Register copy_from = x10;
1841 Register copy_end = x11;
1842 Register copy_to = x12;
1843 Register scratch1 = x13, scratch2 = x14;
1845 // If the function is strong we need to throw an error.
1846 Label no_strong_error;
1848 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1849 __ Ldr(scratch2.W(),
1850 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1851 __ TestAndBranchIfAllClear(scratch2.W(),
1852 (1 << SharedFunctionInfo::kStrongModeFunction),
1855 // What we really care about is the required number of arguments.
1856 DCHECK_EQ(kPointerSize, kInt64Size);
1857 __ Ldr(scratch2.W(),
1858 FieldMemOperand(scratch1, SharedFunctionInfo::kLengthOffset));
1859 __ Cmp(argc_actual, Operand(scratch2, LSR, 1));
1860 __ B(ge, &no_strong_error);
1863 FrameScope frame(masm, StackFrame::MANUAL);
1864 EnterArgumentsAdaptorFrame(masm);
1865 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments, 0);
1868 __ Bind(&no_strong_error);
1869 EnterArgumentsAdaptorFrame(masm);
1871 __ Lsl(scratch2, argc_expected, kPointerSizeLog2);
1872 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
1874 // Adjust for fp, lr, and the receiver.
1875 __ Add(copy_from, fp, 3 * kPointerSize);
1876 __ Add(copy_from, copy_from, argc_actual);
1877 __ Mov(copy_to, jssp);
1878 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver.
1879 __ Sub(copy_end, copy_end, argc_actual);
1881 // Claim space for the arguments, the receiver, and one extra slot.
1882 // The extra slot ensures we do not write under jssp. It will be popped
1884 __ Add(scratch1, scratch2, 2 * kPointerSize);
1885 __ Claim(scratch1, 1);
1887 // Copy the arguments (including the receiver) to the new stack frame.
1889 __ Bind(©_2_by_2);
1890 __ Ldp(scratch1, scratch2,
1891 MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
1892 __ Stp(scratch1, scratch2,
1893 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1894 __ Cmp(copy_to, copy_end);
1895 __ B(hi, ©_2_by_2);
1897 __ Mov(copy_to, copy_end);
1899 // Fill the remaining expected arguments with undefined.
1900 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1901 __ Add(copy_end, jssp, kPointerSize);
1905 __ Stp(scratch1, scratch1,
1906 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1907 __ Cmp(copy_to, copy_end);
1910 // Correct the space allocated for the extra slot.
1914 // Arguments have been adapted. Now call the entry point.
1916 __ Mov(argc_actual, argc_expected);
1917 // x0 : expected number of arguments
1918 // x1 : function (passed through to callee)
1919 __ Call(code_entry);
1921 // Store offset of return address for deoptimizer.
1922 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1924 // Exit frame and return.
1925 LeaveArgumentsAdaptorFrame(masm);
1928 // Call the entry point without adapting the arguments.
1929 __ Bind(&dont_adapt_arguments);
1930 __ Jump(code_entry);
1932 __ Bind(&stack_overflow);
1934 FrameScope frame(masm, StackFrame::MANUAL);
1935 EnterArgumentsAdaptorFrame(masm);
1936 __ InvokeBuiltin(Context::STACK_OVERFLOW_BUILTIN_INDEX, CALL_FUNCTION);
1944 } // namespace internal
1947 #endif // V8_TARGET_ARCH_ARM