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.
7 #if V8_TARGET_ARCH_ARM64
9 #include "src/codegen.h"
10 #include "src/debug/debug.h"
11 #include "src/deoptimizer.h"
12 #include "src/full-codegen/full-codegen.h"
13 #include "src/runtime/runtime.h"
19 #define __ ACCESS_MASM(masm)
22 // Load the built-in Array function from the current context.
23 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
24 // Load the native context.
25 __ Ldr(result, GlobalObjectMemOperand());
27 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
28 // Load the InternalArray function from the native context.
31 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
35 // Load the built-in InternalArray function from the current context.
36 static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
38 // Load the native context.
39 __ Ldr(result, GlobalObjectMemOperand());
41 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
42 // Load the InternalArray function from the native context.
43 __ Ldr(result, ContextMemOperand(result,
44 Context::INTERNAL_ARRAY_FUNCTION_INDEX));
48 void Builtins::Generate_Adaptor(MacroAssembler* masm,
50 BuiltinExtraArguments extra_args) {
51 // ----------- S t a t e -------------
52 // -- x0 : number of arguments excluding receiver
53 // -- x1 : called function (only guaranteed when
54 // extra_args requires it)
56 // -- sp[0] : last argument
58 // -- sp[4 * (argc - 1)] : first argument (argc == x0)
59 // -- sp[4 * argc] : receiver
60 // -----------------------------------
62 // Insert extra arguments.
63 int num_extra_args = 0;
64 if (extra_args == NEEDS_CALLED_FUNCTION) {
68 DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
71 // JumpToExternalReference expects x0 to contain the number of arguments
72 // including the receiver and the extra arguments.
73 __ Add(x0, x0, num_extra_args + 1);
74 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
78 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
79 // ----------- S t a t e -------------
80 // -- x0 : number of arguments
81 // -- lr : return address
82 // -- sp[...]: constructor arguments
83 // -----------------------------------
84 ASM_LOCATION("Builtins::Generate_InternalArrayCode");
85 Label generic_array_code;
87 // Get the InternalArray function.
88 GenerateLoadInternalArrayFunction(masm, x1);
90 if (FLAG_debug_code) {
91 // Initial map for the builtin InternalArray functions should be maps.
92 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
93 __ Tst(x10, kSmiTagMask);
94 __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
95 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
96 __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
99 // Run the native code for the InternalArray function called as a normal
101 InternalArrayConstructorStub stub(masm->isolate());
102 __ TailCallStub(&stub);
106 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
107 // ----------- S t a t e -------------
108 // -- x0 : number of arguments
109 // -- lr : return address
110 // -- sp[...]: constructor arguments
111 // -----------------------------------
112 ASM_LOCATION("Builtins::Generate_ArrayCode");
113 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
115 // Get the Array function.
116 GenerateLoadArrayFunction(masm, x1);
118 if (FLAG_debug_code) {
119 // Initial map for the builtin Array functions should be maps.
120 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
121 __ Tst(x10, kSmiTagMask);
122 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
123 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
124 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
127 // Run the native code for the Array function called as a normal function.
128 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
130 ArrayConstructorStub stub(masm->isolate());
131 __ TailCallStub(&stub);
135 void Builtins::Generate_StringConstructCode(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_StringConstructCode");
144 Counters* counters = masm->isolate()->counters();
145 __ IncrementCounter(counters->string_ctor_calls(), 1, x10, x11);
148 Register function = x1;
149 if (FLAG_debug_code) {
150 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, x10);
151 __ Cmp(function, x10);
152 __ Assert(eq, kUnexpectedStringFunction);
155 // Load the first arguments in x0 and get rid of the rest.
157 __ Cbz(argc, &no_arguments);
158 // First args = sp[(argc - 1) * 8].
159 __ Sub(argc, argc, 1);
160 __ Drop(argc, kXRegSize);
161 // jssp now point to args[0], load and drop args[0] + receiver.
163 __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
166 Register argument = x2;
167 Label not_cached, argument_is_string;
168 __ LookupNumberStringCache(arg, // Input.
174 __ IncrementCounter(counters->string_ctor_cached_number(), 1, x10, x11);
175 __ Bind(&argument_is_string);
177 // ----------- S t a t e -------------
178 // -- x2 : argument converted to string
179 // -- x1 : constructor function
180 // -- lr : return address
181 // -----------------------------------
184 Register new_obj = x0;
185 __ Allocate(JSValue::kSize, new_obj, x10, x11, &gc_required, TAG_OBJECT);
187 // Initialize the String object.
189 __ LoadGlobalFunctionInitialMap(function, map, x10);
190 if (FLAG_debug_code) {
191 __ Ldrb(x4, FieldMemOperand(map, Map::kInstanceSizeOffset));
192 __ Cmp(x4, JSValue::kSize >> kPointerSizeLog2);
193 __ Assert(eq, kUnexpectedStringWrapperInstanceSize);
194 __ Ldrb(x4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
196 __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
198 __ Str(map, FieldMemOperand(new_obj, HeapObject::kMapOffset));
201 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
202 __ Str(empty, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
203 __ Str(empty, FieldMemOperand(new_obj, JSObject::kElementsOffset));
205 __ Str(argument, FieldMemOperand(new_obj, JSValue::kValueOffset));
207 // Ensure the object is fully initialized.
208 STATIC_ASSERT(JSValue::kSize == (4 * kPointerSize));
212 // The argument was not found in the number to string cache. Check
213 // if it's a string already before calling the conversion builtin.
214 Label convert_argument;
215 __ Bind(¬_cached);
216 __ JumpIfSmi(arg, &convert_argument);
219 __ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
220 __ Ldrb(x11, FieldMemOperand(x10, Map::kInstanceTypeOffset));
221 __ Tbnz(x11, MaskToBit(kIsNotStringMask), &convert_argument);
222 __ Mov(argument, arg);
223 __ IncrementCounter(counters->string_ctor_string_value(), 1, x10, x11);
224 __ B(&argument_is_string);
226 // Invoke the conversion builtin and put the result into x2.
227 __ Bind(&convert_argument);
228 __ Push(function); // Preserve the function.
229 __ IncrementCounter(counters->string_ctor_conversions(), 1, x10, x11);
231 FrameScope scope(masm, StackFrame::INTERNAL);
233 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
236 __ Mov(argument, x0);
237 __ B(&argument_is_string);
239 // Load the empty string into x2, remove the receiver from the
240 // stack, and jump back to the case where the argument is a string.
241 __ Bind(&no_arguments);
242 __ LoadRoot(argument, Heap::kempty_stringRootIndex);
244 __ B(&argument_is_string);
246 // At this point the argument is already a string. Call runtime to create a
248 __ Bind(&gc_required);
249 __ IncrementCounter(counters->string_ctor_gc_required(), 1, x10, x11);
251 FrameScope scope(masm, StackFrame::INTERNAL);
253 __ CallRuntime(Runtime::kNewStringWrapper, 1);
259 static void CallRuntimePassFunction(MacroAssembler* masm,
260 Runtime::FunctionId function_id) {
261 FrameScope scope(masm, StackFrame::INTERNAL);
262 // - Push a copy of the function onto the stack.
263 // - Push another copy as a parameter to the runtime call.
266 __ CallRuntime(function_id, 1);
268 // - Restore receiver.
273 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
274 __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
275 __ Ldr(x2, FieldMemOperand(x2, SharedFunctionInfo::kCodeOffset));
276 __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
281 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
282 __ Add(x0, x0, Code::kHeaderSize - kHeapObjectTag);
287 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
288 // Checking whether the queued function is ready for install is optional,
289 // since we come across interrupts and stack checks elsewhere. However, not
290 // checking may delay installing ready functions, and always checking would be
291 // quite expensive. A good compromise is to first check against stack limit as
292 // a cue for an interrupt signal.
294 __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
297 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
298 GenerateTailCallToReturnedCode(masm);
301 GenerateTailCallToSharedCode(masm);
305 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
306 bool is_api_function,
307 bool create_memento) {
308 // ----------- S t a t e -------------
309 // -- x0 : number of arguments
310 // -- x1 : constructor function
311 // -- x2 : allocation site or undefined
312 // -- x3 : original constructor
313 // -- lr : return address
314 // -- sp[...]: constructor arguments
315 // -----------------------------------
317 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
318 // Should never create mementos for api functions.
319 DCHECK(!is_api_function || !create_memento);
321 Isolate* isolate = masm->isolate();
323 // Enter a construct frame.
325 FrameScope scope(masm, StackFrame::CONSTRUCT);
327 // Preserve the four incoming parameters on the stack.
329 Register constructor = x1;
330 Register allocation_site = x2;
331 Register original_constructor = x3;
333 // Preserve the incoming parameters on the stack.
334 __ AssertUndefinedOrAllocationSite(allocation_site, x10);
336 __ Push(allocation_site, argc, constructor, original_constructor);
338 // sp[1]: Constructor function.
339 // sp[2]: number of arguments (smi-tagged)
340 // sp[3]: allocation site
342 // Try to allocate the object without transitioning into C code. If any of
343 // the preconditions is not met, the code bails out to the runtime call.
344 Label rt_call, allocated;
345 if (FLAG_inline_new) {
346 ExternalReference debug_step_in_fp =
347 ExternalReference::debug_step_in_fp_address(isolate);
348 __ Mov(x2, Operand(debug_step_in_fp));
349 __ Ldr(x2, MemOperand(x2));
350 __ Cbnz(x2, &rt_call);
352 // Fall back to runtime if the original constructor and function differ.
353 __ Cmp(constructor, original_constructor);
356 // Load the initial map and verify that it is in fact a map.
357 Register init_map = x2;
359 FieldMemOperand(constructor,
360 JSFunction::kPrototypeOrInitialMapOffset));
361 __ JumpIfSmi(init_map, &rt_call);
362 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
364 // Check that the constructor is not constructing a JSFunction (see
365 // comments in Runtime_NewObject in runtime.cc). In which case the initial
366 // map's instance type would be JS_FUNCTION_TYPE.
367 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
370 Register constructon_count = x14;
371 if (!is_api_function) {
373 MemOperand bit_field3 =
374 FieldMemOperand(init_map, Map::kBitField3Offset);
375 // Check if slack tracking is enabled.
376 __ Ldr(x4, bit_field3);
377 __ DecodeField<Map::Counter>(constructon_count, x4);
378 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
380 // Decrease generous allocation count.
381 __ Subs(x4, x4, Operand(1 << Map::Counter::kShift));
382 __ Str(x4, bit_field3);
383 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
386 // Push the constructor and map to the stack, and the constructor again
387 // as argument to the runtime call.
388 __ Push(constructor, init_map, constructor);
389 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
390 __ Pop(init_map, constructor);
391 __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
395 // Now allocate the JSObject on the heap.
396 Label rt_call_reload_new_target;
397 Register obj_size = x3;
398 Register new_obj = x4;
399 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
400 if (create_memento) {
402 Operand(AllocationMemento::kSize / kPointerSize));
403 __ Allocate(x7, new_obj, x10, x11, &rt_call_reload_new_target,
406 __ Allocate(obj_size, new_obj, x10, x11, &rt_call_reload_new_target,
410 // Allocated the JSObject, now initialize the fields. Map is set to
411 // initial map and properties and elements are set to empty fixed array.
412 // NB. the object pointer is not tagged, so MemOperand is used.
414 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
415 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
416 STATIC_ASSERT(JSObject::kElementsOffset ==
417 (JSObject::kPropertiesOffset + kPointerSize));
418 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
420 Register first_prop = x5;
421 __ Add(first_prop, new_obj, JSObject::kHeaderSize);
423 // Fill all of the in-object properties with the appropriate filler.
424 Register filler = x7;
425 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
427 // Obtain number of pre-allocated property fields and in-object
429 Register unused_props = x10;
430 Register inobject_props = x11;
431 Register inst_sizes_or_attrs = x11;
432 Register prealloc_fields = x10;
433 __ Ldr(inst_sizes_or_attrs,
434 FieldMemOperand(init_map, Map::kInstanceAttributesOffset));
435 __ Ubfx(unused_props, inst_sizes_or_attrs,
436 Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte);
437 __ Ldr(inst_sizes_or_attrs,
438 FieldMemOperand(init_map, Map::kInstanceSizesOffset));
439 __ Ubfx(inobject_props, inst_sizes_or_attrs,
440 Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte);
441 __ Sub(prealloc_fields, inobject_props, unused_props);
443 // Calculate number of property fields in the object.
444 Register prop_fields = x6;
445 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
447 if (!is_api_function) {
448 Label no_inobject_slack_tracking;
450 // Check if slack tracking is enabled.
451 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
452 __ B(lt, &no_inobject_slack_tracking);
453 constructon_count = NoReg;
455 // Fill the pre-allocated fields with undef.
456 __ FillFields(first_prop, prealloc_fields, filler);
458 // Update first_prop register to be the offset of the first field after
459 // pre-allocated fields.
460 __ Add(first_prop, first_prop,
461 Operand(prealloc_fields, LSL, kPointerSizeLog2));
463 if (FLAG_debug_code) {
464 Register obj_end = x14;
465 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
466 __ Cmp(first_prop, obj_end);
467 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
470 // Fill the remaining fields with one pointer filler map.
471 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
472 __ Sub(prop_fields, prop_fields, prealloc_fields);
474 __ bind(&no_inobject_slack_tracking);
476 if (create_memento) {
477 // Fill the pre-allocated fields with undef.
478 __ FillFields(first_prop, prop_fields, filler);
479 __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
480 __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex);
481 DCHECK_EQ(0 * kPointerSize, AllocationMemento::kMapOffset);
482 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
483 // Load the AllocationSite
484 __ Peek(x14, 3 * kXRegSize);
485 __ AssertUndefinedOrAllocationSite(x14, x10);
486 DCHECK_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset);
487 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
490 // Fill all of the property fields with undef.
491 __ FillFields(first_prop, prop_fields, filler);
496 // Add the object tag to make the JSObject real, so that we can continue
497 // and jump into the continuation code at any time from now on.
498 __ Add(new_obj, new_obj, kHeapObjectTag);
500 // Continue with JSObject being successfully allocated.
503 // Reload the original constructor and fall-through.
504 __ Bind(&rt_call_reload_new_target);
505 __ Peek(x3, 0 * kXRegSize);
508 // Allocate the new receiver object using the runtime call.
509 // x1: constructor function
510 // x3: original constructor
512 Label count_incremented;
513 if (create_memento) {
514 // Get the cell or allocation site.
515 __ Peek(x4, 3 * kXRegSize);
516 __ Push(x4, constructor, original_constructor); // arguments 1-3
517 __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
519 // If we ended up using the runtime, and we want a memento, then the
520 // runtime call made it for us, and we shouldn't do create count
522 __ B(&count_incremented);
524 __ Push(constructor, original_constructor); // arguments 1-2
525 __ CallRuntime(Runtime::kNewObject, 2);
529 // Receiver for constructor call allocated.
533 if (create_memento) {
534 __ Peek(x10, 3 * kXRegSize);
535 __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
536 // r2 is an AllocationSite. We are creating a memento from it, so we
537 // need to increment the memento create count.
538 __ Ldr(x5, FieldMemOperand(x10,
539 AllocationSite::kPretenureCreateCountOffset));
540 __ Add(x5, x5, Operand(Smi::FromInt(1)));
541 __ Str(x5, FieldMemOperand(x10,
542 AllocationSite::kPretenureCreateCountOffset));
543 __ bind(&count_incremented);
546 // Restore the parameters.
547 __ Pop(original_constructor);
550 // Reload the number of arguments from the stack.
551 // Set it up in x0 for the function call below.
552 // jssp[0]: number of arguments (smi-tagged)
553 __ Peek(argc, 0); // Load number of arguments.
556 __ Push(original_constructor, x4, x4);
558 // Set up pointer to last argument.
559 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
561 // Copy arguments and receiver to the expression stack.
562 // Copy 2 values every loop to use ldp/stp.
563 // x0: number of arguments
564 // x1: constructor function
565 // x2: address of last argument (caller sp)
568 // jssp[2]: new.target
569 // jssp[3]: number of arguments (smi-tagged)
570 // Compute the start address of the copy in x3.
571 __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
572 Label loop, entry, done_copying_arguments;
575 __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
580 // Because we copied values 2 by 2 we may have copied one extra value.
581 // Drop it if that is the case.
582 __ B(eq, &done_copying_arguments);
584 __ Bind(&done_copying_arguments);
586 // Call the function.
587 // x0: number of arguments
588 // x1: constructor function
589 if (is_api_function) {
590 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
592 masm->isolate()->builtins()->HandleApiCallConstruct();
593 __ Call(code, RelocInfo::CODE_TARGET);
595 ParameterCount actual(argc);
596 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
599 // Store offset of return address for deoptimizer.
600 if (!is_api_function) {
601 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
604 // Restore the context from the frame.
607 // jssp[1]: new.target
608 // jssp[2]: number of arguments (smi-tagged)
609 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
611 // If the result is an object (in the ECMA sense), we should get rid
612 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
614 Label use_receiver, exit;
616 // If the result is a smi, it is *not* an object in the ECMA sense.
618 // jssp[0]: receiver (newly allocated object)
619 // jssp[1]: number of arguments (smi-tagged)
620 __ JumpIfSmi(x0, &use_receiver);
622 // If the type of the result (stored in its map) is less than
623 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
624 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
626 // Throw away the result of the constructor invocation and use the
627 // on-stack receiver as the result.
628 __ Bind(&use_receiver);
631 // Remove the receiver from the stack, remove caller arguments, and
635 // jssp[0]: receiver (newly allocated object)
636 // jssp[1]: new.target (original constructor)
637 // jssp[2]: number of arguments (smi-tagged)
638 __ Peek(x1, 2 * kXRegSize);
640 // Leave construct frame.
645 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
650 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
651 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
655 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
656 Generate_JSConstructStubHelper(masm, true, false);
660 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
661 // ----------- S t a t e -------------
662 // -- x0 : number of arguments
663 // -- x1 : constructor function
664 // -- x2 : allocation site or undefined
665 // -- x3 : original constructor
666 // -- lr : return address
667 // -- sp[...]: constructor arguments
668 // -----------------------------------
669 ASM_LOCATION("Builtins::Generate_JSConstructStubForDerived");
672 FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
674 __ AssertUndefinedOrAllocationSite(x2, x10);
677 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
678 __ Push(x2, x4, x3, x10);
679 // sp[0]: receiver (the hole)
681 // sp[2]: number of arguments
682 // sp[3]: allocation site
684 // Set up pointer to last argument.
685 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
687 // Copy arguments and receiver to the expression stack.
688 // Copy 2 values every loop to use ldp/stp.
689 // x0: number of arguments
690 // x1: constructor function
691 // x2: address of last argument (caller sp)
693 // jssp[1]: new.target
694 // jssp[2]: number of arguments (smi-tagged)
695 // Compute the start address of the copy in x4.
696 __ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2));
697 Label loop, entry, done_copying_arguments;
700 __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex));
705 // Because we copied values 2 by 2 we may have copied one extra value.
706 // Drop it if that is the case.
707 __ B(eq, &done_copying_arguments);
709 __ Bind(&done_copying_arguments);
713 ExternalReference debug_step_in_fp =
714 ExternalReference::debug_step_in_fp_address(masm->isolate());
715 __ Mov(x2, Operand(debug_step_in_fp));
716 __ Ldr(x2, MemOperand(x2));
717 __ Cbz(x2, &skip_step_in);
720 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
723 __ bind(&skip_step_in);
725 // Call the function.
726 // x0: number of arguments
727 // x1: constructor function
728 ParameterCount actual(x0);
729 __ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper());
732 // Restore the context from the frame.
734 // jssp[0]: number of arguments (smi-tagged)
735 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
737 // Load number of arguments (smi), skipping over new.target.
738 __ Peek(x1, kPointerSize);
740 // Leave construct frame
749 enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt };
752 // Clobbers x10, x15; preserves all other registers.
753 static void Generate_CheckStackOverflow(MacroAssembler* masm,
754 const int calleeOffset, Register argc,
755 IsTagged argc_is_tagged) {
756 Register function = x15;
758 // Check the stack for overflow.
759 // We are not trying to catch interruptions (e.g. debug break and
760 // preemption) here, so the "real stack limit" is checked.
761 Label enough_stack_space;
762 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
763 __ Ldr(function, MemOperand(fp, calleeOffset));
764 // Make x10 the space we have left. The stack might already be overflowed
765 // here which will cause x10 to become negative.
766 // TODO(jbramley): Check that the stack usage here is safe.
767 __ Sub(x10, jssp, x10);
768 // Check if the arguments will overflow the stack.
769 if (argc_is_tagged == kArgcIsSmiTagged) {
770 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
772 DCHECK(argc_is_tagged == kArgcIsUntaggedInt);
773 __ Cmp(x10, Operand(argc, LSL, kPointerSizeLog2));
775 __ B(gt, &enough_stack_space);
776 // There is not enough stack space, so use a builtin to throw an appropriate
778 if (argc_is_tagged == kArgcIsUntaggedInt) {
781 __ Push(function, argc);
782 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
783 // We should never return from the APPLY_OVERFLOW builtin.
784 if (__ emit_debug_code()) {
788 __ Bind(&enough_stack_space);
800 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
802 // Called from JSEntryStub::GenerateBody().
803 Register function = x1;
804 Register receiver = x2;
808 ProfileEntryHookStub::MaybeCallEntryHook(masm);
810 // Clear the context before we push it when entering the internal frame.
814 // Enter an internal frame.
815 FrameScope scope(masm, StackFrame::INTERNAL);
817 // Set up the context from the function argument.
818 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
820 __ InitializeRootRegister();
822 // Push the function and the receiver onto the stack.
823 __ Push(function, receiver);
825 // Check if we have enough stack space to push all arguments.
826 // The function is the first thing that was pushed above after entering
827 // the internal frame.
828 const int kFunctionOffset =
829 InternalFrameConstants::kCodeOffset - kPointerSize;
830 // Expects argument count in eax. Clobbers ecx, edx, edi.
831 Generate_CheckStackOverflow(masm, kFunctionOffset, argc,
834 // Copy arguments to the stack in a loop, in reverse order.
838 // Compute the copy end address.
839 __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
843 __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
844 __ Ldr(x12, MemOperand(x11)); // Dereference the handle.
845 __ Push(x12); // Push the argument.
850 // Initialize all JavaScript callee-saved registers, since they will be seen
851 // by the garbage collector as part of handlers.
852 // The original values have been saved in JSEntryStub::GenerateBody().
853 __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
860 // Don't initialize the reserved registers.
861 // x26 : root register (root).
862 // x27 : context pointer (cp).
863 // x28 : JS stack pointer (jssp).
864 // x29 : frame pointer (fp).
868 // No type feedback cell is available.
869 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
871 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
874 ParameterCount actual(x0);
875 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
877 // Exit the JS internal frame and remove the parameters (except function),
881 // Result is in x0. Return.
886 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
887 Generate_JSEntryTrampolineHelper(masm, false);
891 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
892 Generate_JSEntryTrampolineHelper(masm, true);
896 // Generate code for entering a JS function with the interpreter.
897 // On entry to the function the receiver and arguments have been pushed on the
898 // stack left to right. The actual argument count matches the formal parameter
899 // count expected by the function.
901 // The live registers are:
902 // - x1: the JS function object being called.
903 // - cp: our context.
904 // - fp: our caller's frame pointer.
905 // - jssp: stack pointer.
906 // - lr: return address.
908 // The function builds a JS frame. Please see JavaScriptFrameConstants in
909 // frames-arm64.h for its layout.
910 // TODO(rmcilroy): We will need to include the current bytecode pointer in the
912 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
913 // Open a frame scope to indicate that there is a frame on the stack. The
914 // MANUAL indicates that the scope shouldn't actually generate code to set up
915 // the frame (that is done below).
916 FrameScope frame_scope(masm, StackFrame::MANUAL);
917 __ Push(lr, fp, cp, x1);
918 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
920 // Get the bytecode array from the function object and load the pointer to the
921 // first entry into kInterpreterBytecodeRegister.
922 __ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
923 __ Ldr(kInterpreterBytecodeArrayRegister,
924 FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
926 if (FLAG_debug_code) {
927 // Check function data field is actually a BytecodeArray object.
928 __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
929 kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
930 __ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
931 BYTECODE_ARRAY_TYPE);
932 __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
935 // Allocate the local and temporary register file on the stack.
937 // Load frame size from the BytecodeArray object.
938 __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister,
939 BytecodeArray::kFrameSizeOffset));
941 // Do a stack check to ensure we don't go over the limit.
943 DCHECK(jssp.Is(__ StackPointer()));
944 __ Sub(x10, jssp, Operand(x11));
945 __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
947 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
950 // If ok, push undefined as the initial value for all register file entries.
951 // Note: there should always be at least one stack slot for the return
952 // register in the register file.
954 __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
955 // TODO(rmcilroy): Ensure we always have an even number of registers to
956 // allow stack to be 16 bit aligned (and remove need for jssp).
957 __ Lsr(x11, x11, kPointerSizeLog2);
958 __ PushMultipleTimes(x10, x11);
959 __ Bind(&loop_header);
962 // TODO(rmcilroy): List of things not currently dealt with here but done in
963 // fullcodegen's prologue:
964 // - Support profiler (specifically profiling_counter).
965 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
966 // - Allow simulator stop operations if FLAG_stop_at is set.
967 // - Deal with sloppy mode functions which need to replace the
968 // receiver with the global proxy when called as functions (without an
969 // explicit receiver object).
970 // - Code aging of the BytecodeArray object.
971 // - Supporting FLAG_trace.
973 // The following items are also not done here, and will probably be done using
974 // explicit bytecodes instead:
975 // - Allocating a new local context if applicable.
976 // - Setting up a local binding to the this function, which is used in
977 // derived constructors with super calls.
978 // - Setting new.target if required.
979 // - Dealing with REST parameters (only if
980 // https://codereview.chromium.org/1235153006 doesn't land by then).
981 // - Dealing with argument objects.
983 // Perform stack guard check.
986 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
988 __ CallRuntime(Runtime::kStackGuard, 0);
992 // Load bytecode offset and dispatch table into registers.
993 __ Mov(kInterpreterBytecodeOffsetRegister,
994 Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
995 __ LoadRoot(kInterpreterDispatchTableRegister,
996 Heap::kInterpreterTableRootIndex);
997 __ Add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
998 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1000 // Dispatch to the first bytecode handler for the function.
1001 __ Ldrb(x0, MemOperand(kInterpreterBytecodeArrayRegister,
1002 kInterpreterBytecodeOffsetRegister));
1003 __ Mov(x0, Operand(x0, LSL, kPointerSizeLog2));
1004 __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x0));
1005 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
1006 // and header removal.
1007 __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
1012 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
1013 // TODO(rmcilroy): List of things not currently dealt with here but done in
1014 // fullcodegen's EmitReturnSequence.
1015 // - Supporting FLAG_trace for Runtime::TraceExit.
1016 // - Support profiler (specifically decrementing profiling_counter
1017 // appropriately and calling out to HandleInterrupts if necessary).
1019 // Load return value into x0.
1020 __ ldr(x0, MemOperand(fp, -kPointerSize -
1021 StandardFrameConstants::kFixedFrameSizeFromFp));
1022 // Leave the frame (also dropping the register file).
1023 __ LeaveFrame(StackFrame::JAVA_SCRIPT);
1024 // Drop receiver + arguments.
1025 // TODO(rmcilroy): Get number of arguments from BytecodeArray.
1026 __ Drop(1, kXRegSize);
1031 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
1032 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
1033 GenerateTailCallToReturnedCode(masm);
1037 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
1038 FrameScope scope(masm, StackFrame::INTERNAL);
1039 Register function = x1;
1041 // Preserve function. At the same time, push arguments for
1042 // kCompileOptimized.
1043 __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
1044 __ Push(function, function, x10);
1046 __ CallRuntime(Runtime::kCompileOptimized, 2);
1048 // Restore receiver.
1053 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
1054 CallCompileOptimized(masm, false);
1055 GenerateTailCallToReturnedCode(masm);
1059 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
1060 CallCompileOptimized(masm, true);
1061 GenerateTailCallToReturnedCode(masm);
1065 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
1066 // For now, we are relying on the fact that make_code_young doesn't do any
1067 // garbage collection which allows us to save/restore the registers without
1068 // worrying about which of them contain pointers. We also don't build an
1069 // internal frame to make the code fast, since we shouldn't have to do stack
1070 // crawls in MakeCodeYoung. This seems a bit fragile.
1072 // The following caller-saved registers must be saved and restored when
1073 // calling through to the runtime:
1074 // x0 - The address from which to resume execution.
1076 // lr - The return address for the JSFunction itself. It has not yet been
1077 // preserved on the stack because the frame setup code was replaced
1078 // with a call to this stub, to handle code ageing.
1080 FrameScope scope(masm, StackFrame::MANUAL);
1081 __ Push(x0, x1, fp, lr);
1082 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1084 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
1085 __ Pop(lr, fp, x1, x0);
1088 // The calling function has been made young again, so return to execute the
1089 // real frame set-up code.
1093 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
1094 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
1095 MacroAssembler* masm) { \
1096 GenerateMakeCodeYoungAgainCommon(masm); \
1098 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
1099 MacroAssembler* masm) { \
1100 GenerateMakeCodeYoungAgainCommon(masm); \
1102 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
1103 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
1106 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
1107 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
1108 // that make_code_young doesn't do any garbage collection which allows us to
1109 // save/restore the registers without worrying about which of them contain
1112 // The following caller-saved registers must be saved and restored when
1113 // calling through to the runtime:
1114 // x0 - The address from which to resume execution.
1116 // lr - The return address for the JSFunction itself. It has not yet been
1117 // preserved on the stack because the frame setup code was replaced
1118 // with a call to this stub, to handle code ageing.
1120 FrameScope scope(masm, StackFrame::MANUAL);
1121 __ Push(x0, x1, fp, lr);
1122 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
1124 ExternalReference::get_mark_code_as_executed_function(
1125 masm->isolate()), 2);
1126 __ Pop(lr, fp, x1, x0);
1128 // Perform prologue operations usually performed by the young code stub.
1129 __ EmitFrameSetupForCodeAgePatching(masm);
1132 // Jump to point after the code-age stub.
1133 __ Add(x0, x0, kNoCodeAgeSequenceLength);
1138 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
1139 GenerateMakeCodeYoungAgainCommon(masm);
1143 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
1144 Generate_MarkCodeAsExecutedOnce(masm);
1148 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
1149 SaveFPRegsMode save_doubles) {
1151 FrameScope scope(masm, StackFrame::INTERNAL);
1153 // Preserve registers across notification, this is important for compiled
1154 // stubs that tail call the runtime on deopts passing their parameters in
1156 // TODO(jbramley): Is it correct (and appropriate) to use safepoint
1157 // registers here? According to the comment above, we should only need to
1158 // preserve the registers with parameters.
1159 __ PushXRegList(kSafepointSavedRegisters);
1160 // Pass the function and deoptimization type to the runtime system.
1161 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
1162 __ PopXRegList(kSafepointSavedRegisters);
1165 // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
1168 // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
1169 // into lr before it jumps here.
1174 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
1175 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
1179 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
1180 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
1184 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
1185 Deoptimizer::BailoutType type) {
1187 FrameScope scope(masm, StackFrame::INTERNAL);
1188 // Pass the deoptimization type to the runtime system.
1189 __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
1191 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
1194 // Get the full codegen state from the stack and untag it.
1195 Register state = x6;
1199 // Switch on the state.
1200 Label with_tos_register, unknown_state;
1201 __ CompareAndBranch(
1202 state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
1203 __ Drop(1); // Remove state.
1206 __ Bind(&with_tos_register);
1207 // Reload TOS register.
1208 __ Peek(x0, kPointerSize);
1209 __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
1210 __ Drop(2); // Remove state and TOS.
1213 __ Bind(&unknown_state);
1214 __ Abort(kInvalidFullCodegenState);
1218 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
1219 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
1223 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
1224 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1228 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
1229 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
1233 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1234 // Lookup the function in the JavaScript frame.
1235 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1237 FrameScope scope(masm, StackFrame::INTERNAL);
1238 // Pass function as argument.
1240 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1243 // If the code object is null, just return to the unoptimized code.
1245 __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
1250 // Load deoptimization data from the code object.
1251 // <deopt_data> = <code>[#deoptimization_data_offset]
1252 __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1254 // Load the OSR entrypoint offset from the deoptimization data.
1255 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1256 __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1257 DeoptimizationInputData::kOsrPcOffsetIndex)));
1259 // Compute the target address = code_obj + header_size + osr_offset
1260 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1262 __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1264 // And "return" to the OSR entry point of the function.
1269 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1270 // We check the stack limit as indicator that recompilation might be done.
1272 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
1275 FrameScope scope(masm, StackFrame::INTERNAL);
1276 __ CallRuntime(Runtime::kStackGuard, 0);
1278 __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1279 RelocInfo::CODE_TARGET);
1286 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1288 call_type_JS_func = 0,
1289 call_type_func_proxy = 1,
1290 call_type_non_func = 2
1293 Register function = x1;
1294 Register call_type = x4;
1295 Register scratch1 = x10;
1296 Register scratch2 = x11;
1297 Register receiver_type = x13;
1299 ASM_LOCATION("Builtins::Generate_FunctionCall");
1300 // 1. Make sure we have at least one argument.
1302 __ Cbnz(argc, &done);
1303 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1309 // 2. Get the function to call (passed as receiver) from the stack, check
1310 // if it is a function.
1311 Label slow, non_function;
1312 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1313 __ JumpIfSmi(function, &non_function);
1314 __ JumpIfNotObjectType(function, scratch1, receiver_type,
1315 JS_FUNCTION_TYPE, &slow);
1317 // 3a. Patch the first argument if necessary when calling a function.
1318 Label shift_arguments;
1319 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1320 { Label convert_to_object, use_global_proxy, patch_receiver;
1321 // Change context eagerly in case we need the global receiver.
1322 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1324 // Do not transform the receiver for strict mode functions.
1325 // Also do not transform the receiver for native (Compilerhints already in
1328 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1329 __ Ldr(scratch2.W(),
1330 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1331 __ TestAndBranchIfAnySet(
1333 (1 << SharedFunctionInfo::kStrictModeFunction) |
1334 (1 << SharedFunctionInfo::kNative),
1337 // Compute the receiver in sloppy mode.
1338 Register receiver = x2;
1339 __ Sub(scratch1, argc, 1);
1340 __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1341 __ JumpIfSmi(receiver, &convert_to_object);
1343 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1345 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
1347 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1348 __ JumpIfObjectType(receiver, scratch1, scratch2,
1349 FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
1351 __ Bind(&convert_to_object);
1354 // Enter an internal frame in order to preserve argument count.
1355 FrameScope scope(masm, StackFrame::INTERNAL);
1359 __ Mov(x0, receiver);
1360 ToObjectStub stub(masm->isolate());
1362 __ Mov(receiver, x0);
1367 // Exit the internal frame.
1370 // Restore the function and flag in the registers.
1371 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1372 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1373 __ B(&patch_receiver);
1375 __ Bind(&use_global_proxy);
1376 __ Ldr(receiver, GlobalObjectMemOperand());
1378 FieldMemOperand(receiver, GlobalObject::kGlobalProxyOffset));
1381 __ Bind(&patch_receiver);
1382 __ Sub(scratch1, argc, 1);
1383 __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1385 __ B(&shift_arguments);
1388 // 3b. Check for function proxy.
1390 __ Mov(call_type, static_cast<int>(call_type_func_proxy));
1391 __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
1392 __ B(eq, &shift_arguments);
1393 __ Bind(&non_function);
1394 __ Mov(call_type, static_cast<int>(call_type_non_func));
1396 // 3c. Patch the first argument when calling a non-function. The
1397 // CALL_NON_FUNCTION builtin expects the non-function callee as
1398 // receiver, so overwrite the first argument which will ultimately
1399 // become the receiver.
1400 // call type (0: JS function, 1: function proxy, 2: non-function)
1401 __ Sub(scratch1, argc, 1);
1402 __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
1404 // 4. Shift arguments and return address one slot down on the stack
1405 // (overwriting the original receiver). Adjust argument count to make
1406 // the original first argument the new receiver.
1407 // call type (0: JS function, 1: function proxy, 2: non-function)
1408 __ Bind(&shift_arguments);
1410 // Calculate the copy start address (destination). Copy end address is jssp.
1411 __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1412 __ Sub(scratch1, scratch2, kPointerSize);
1415 __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1416 __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1417 __ Cmp(scratch1, jssp);
1419 // Adjust the actual number of arguments and remove the top element
1420 // (which is a copy of the last argument).
1421 __ Sub(argc, argc, 1);
1425 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1426 // or a function proxy via CALL_FUNCTION_PROXY.
1427 // call type (0: JS function, 1: function proxy, 2: non-function)
1428 { Label js_function, non_proxy;
1429 __ Cbz(call_type, &js_function);
1430 // Expected number of arguments is 0 for CALL_NON_FUNCTION.
1432 __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
1433 __ B(ne, &non_proxy);
1435 __ Push(function); // Re-add proxy object as additional argument.
1436 __ Add(argc, argc, 1);
1437 __ GetBuiltinFunction(function, Builtins::CALL_FUNCTION_PROXY);
1438 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1439 RelocInfo::CODE_TARGET);
1441 __ Bind(&non_proxy);
1442 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
1443 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1444 RelocInfo::CODE_TARGET);
1445 __ Bind(&js_function);
1448 // 5b. Get the code to call from the function and check that the number of
1449 // expected arguments matches what we're providing. If so, jump
1450 // (tail-call) to the code in register edx without checking arguments.
1451 __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1454 SharedFunctionInfo::kFormalParameterCountOffset));
1455 Label dont_adapt_args;
1456 __ Cmp(x2, argc); // Check formal and actual parameter counts.
1457 __ B(eq, &dont_adapt_args);
1458 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1459 RelocInfo::CODE_TARGET);
1460 __ Bind(&dont_adapt_args);
1462 __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1463 ParameterCount expected(0);
1464 __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
1468 static void Generate_PushAppliedArguments(MacroAssembler* masm,
1469 const int argumentsOffset,
1470 const int indexOffset,
1471 const int limitOffset) {
1473 Register receiver = LoadDescriptor::ReceiverRegister();
1474 Register key = LoadDescriptor::NameRegister();
1475 Register slot = LoadDescriptor::SlotRegister();
1476 Register vector = LoadWithVectorDescriptor::VectorRegister();
1478 __ Ldr(key, MemOperand(fp, indexOffset));
1481 // Load the current argument from the arguments array.
1483 __ Ldr(receiver, MemOperand(fp, argumentsOffset));
1485 // Use inline caching to speed up access to arguments.
1486 Code::Kind kinds[] = {Code::KEYED_LOAD_IC};
1487 FeedbackVectorSpec spec(0, 1, kinds);
1488 Handle<TypeFeedbackVector> feedback_vector =
1489 masm->isolate()->factory()->NewTypeFeedbackVector(&spec);
1490 int index = feedback_vector->GetIndex(FeedbackVectorICSlot(0));
1491 __ Mov(slot, Smi::FromInt(index));
1492 __ Mov(vector, feedback_vector);
1494 KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode();
1495 __ Call(ic, RelocInfo::CODE_TARGET);
1497 // Push the nth argument.
1500 __ Ldr(key, MemOperand(fp, indexOffset));
1501 __ Add(key, key, Smi::FromInt(1));
1502 __ Str(key, MemOperand(fp, indexOffset));
1504 // Test if the copy loop has finished copying all the elements from the
1505 // arguments object.
1507 __ Ldr(x1, MemOperand(fp, limitOffset));
1511 // On exit, the pushed arguments count is in x0, untagged
1517 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
1518 const int kFormalParameters = targetIsArgument ? 3 : 2;
1519 const int kStackSize = kFormalParameters + 1;
1522 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1524 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
1525 const int kReceiverOffset = kArgumentsOffset + kPointerSize;
1526 const int kFunctionOffset = kReceiverOffset + kPointerSize;
1527 const int kIndexOffset =
1528 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1529 const int kLimitOffset =
1530 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1532 Register args = x12;
1533 Register receiver = x14;
1534 Register function = x15;
1536 // Get the length of the arguments via a builtin call.
1537 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1538 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1539 __ Push(function, args);
1540 if (targetIsArgument) {
1541 __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
1543 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
1547 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1549 // Push current limit and index.
1550 __ Mov(x1, 0); // Initial index.
1553 Label push_receiver;
1554 __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
1556 // Check that the function is a JS function. Otherwise it must be a proxy.
1557 // When it is not the function proxy will be invoked later.
1558 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
1561 // Change context eagerly to get the right global object if necessary.
1562 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1563 // Load the shared function info.
1564 __ Ldr(x2, FieldMemOperand(function,
1565 JSFunction::kSharedFunctionInfoOffset));
1567 // Compute and push the receiver.
1568 // Do not transform the receiver for strict mode functions.
1569 Label convert_receiver_to_object, use_global_proxy;
1570 __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
1571 __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
1572 // Do not transform the receiver for native functions.
1573 __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
1575 // Compute the receiver in sloppy mode.
1576 __ JumpIfSmi(receiver, &convert_receiver_to_object);
1577 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
1578 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1581 // Check if the receiver is already a JavaScript object.
1582 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1583 __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
1584 &push_receiver, ge);
1586 // Call a builtin to convert the receiver to a regular object.
1587 __ Bind(&convert_receiver_to_object);
1588 __ Mov(x0, receiver);
1589 ToObjectStub stub(masm->isolate());
1591 __ Mov(receiver, x0);
1592 __ B(&push_receiver);
1594 __ Bind(&use_global_proxy);
1595 __ Ldr(x10, GlobalObjectMemOperand());
1596 __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
1598 // Push the receiver
1599 __ Bind(&push_receiver);
1602 // Copy all arguments from the array to the stack.
1603 Generate_PushAppliedArguments(
1604 masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1606 // At the end of the loop, the number of arguments is stored in 'current',
1607 // represented as a smi.
1609 function = x1; // From now on we want the function to be kept in x1;
1610 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1612 // Call the function.
1614 ParameterCount actual(x0);
1615 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
1616 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
1617 frame_scope.GenerateLeaveFrame();
1618 __ Drop(kStackSize);
1621 // Call the function proxy.
1622 __ Bind(&call_proxy);
1625 __ Push(function); // Add function proxy as last argument.
1628 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
1629 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1630 RelocInfo::CODE_TARGET);
1632 __ Drop(kStackSize);
1637 static void Generate_ConstructHelper(MacroAssembler* masm) {
1638 const int kFormalParameters = 3;
1639 const int kStackSize = kFormalParameters + 1;
1642 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1644 const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
1645 const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
1646 const int kFunctionOffset = kArgumentsOffset + kPointerSize;
1648 const int kIndexOffset =
1649 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1650 const int kLimitOffset =
1651 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1653 // Is x11 safe to use?
1654 Register newTarget = x11;
1655 Register args = x12;
1656 Register function = x15;
1658 // If newTarget is not supplied, set it to constructor
1659 Label validate_arguments;
1660 __ Ldr(x0, MemOperand(fp, kNewTargetOffset));
1661 __ CompareRoot(x0, Heap::kUndefinedValueRootIndex);
1662 __ B(ne, &validate_arguments);
1663 __ Ldr(x0, MemOperand(fp, kFunctionOffset));
1664 __ Str(x0, MemOperand(fp, kNewTargetOffset));
1666 // Validate arguments
1667 __ Bind(&validate_arguments);
1668 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1669 __ Ldr(args, MemOperand(fp, kArgumentsOffset));
1670 __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset));
1671 __ Push(function, args, newTarget);
1672 __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
1675 Generate_CheckStackOverflow(masm, kFunctionOffset, argc, kArgcIsSmiTagged);
1677 // Push current limit and index & constructor function as callee.
1678 __ Mov(x1, 0); // Initial index.
1679 __ Push(argc, x1, function);
1681 // Copy all arguments from the array to the stack.
1682 Generate_PushAppliedArguments(
1683 masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1685 // Use undefined feedback vector
1686 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
1687 __ Ldr(x1, MemOperand(fp, kFunctionOffset));
1688 __ Ldr(x4, MemOperand(fp, kNewTargetOffset));
1690 // Call the function.
1691 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
1692 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
1694 // Leave internal frame.
1696 __ Drop(kStackSize);
1701 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1702 ASM_LOCATION("Builtins::Generate_FunctionApply");
1703 Generate_ApplyHelper(masm, false);
1707 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1708 ASM_LOCATION("Builtins::Generate_ReflectApply");
1709 Generate_ApplyHelper(masm, true);
1713 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1714 ASM_LOCATION("Builtins::Generate_ReflectConstruct");
1715 Generate_ConstructHelper(masm);
1719 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
1720 Label* stack_overflow) {
1721 // ----------- S t a t e -------------
1722 // -- x0 : actual number of arguments
1723 // -- x1 : function (passed through to callee)
1724 // -- x2 : expected number of arguments
1725 // -----------------------------------
1726 // Check the stack for overflow.
1727 // We are not trying to catch interruptions (e.g. debug break and
1728 // preemption) here, so the "real stack limit" is checked.
1729 Label enough_stack_space;
1730 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1731 // Make x10 the space we have left. The stack might already be overflowed
1732 // here which will cause x10 to become negative.
1733 __ Sub(x10, jssp, x10);
1734 // Check if the arguments will overflow the stack.
1735 __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
1736 __ B(le, stack_overflow);
1740 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1742 __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1744 __ Push(x11, x1, x10);
1746 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
1750 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1751 // ----------- S t a t e -------------
1752 // -- x0 : result being passed through
1753 // -----------------------------------
1754 // Get the number of arguments passed (as a smi), tear down the frame and
1755 // then drop the parameters and the receiver.
1756 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1760 __ DropBySMI(x10, kXRegSize);
1765 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1766 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
1767 // ----------- S t a t e -------------
1768 // -- x0 : actual number of arguments
1769 // -- x1 : function (passed through to callee)
1770 // -- x2 : expected number of arguments
1771 // -----------------------------------
1773 Label stack_overflow;
1774 ArgumentAdaptorStackCheck(masm, &stack_overflow);
1776 Register argc_actual = x0; // Excluding the receiver.
1777 Register argc_expected = x2; // Excluding the receiver.
1778 Register function = x1;
1779 Register code_entry = x3;
1781 Label invoke, dont_adapt_arguments;
1783 Label enough, too_few;
1784 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1785 __ Cmp(argc_actual, argc_expected);
1787 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1788 __ B(eq, &dont_adapt_arguments);
1790 { // Enough parameters: actual >= expected
1791 EnterArgumentsAdaptorFrame(masm);
1793 Register copy_start = x10;
1794 Register copy_end = x11;
1795 Register copy_to = x12;
1796 Register scratch1 = x13, scratch2 = x14;
1798 __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1800 // Adjust for fp, lr, and the receiver.
1801 __ Add(copy_start, fp, 3 * kPointerSize);
1802 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
1803 __ Sub(copy_end, copy_start, argc_expected);
1804 __ Sub(copy_end, copy_end, kPointerSize);
1805 __ Mov(copy_to, jssp);
1807 // Claim space for the arguments, the receiver, and one extra slot.
1808 // The extra slot ensures we do not write under jssp. It will be popped
1810 __ Add(scratch1, argc_expected, 2 * kPointerSize);
1811 __ Claim(scratch1, 1);
1813 // Copy the arguments (including the receiver) to the new stack frame.
1815 __ Bind(©_2_by_2);
1816 __ Ldp(scratch1, scratch2,
1817 MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
1818 __ Stp(scratch1, scratch2,
1819 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1820 __ Cmp(copy_start, copy_end);
1821 __ B(hi, ©_2_by_2);
1823 // Correct the space allocated for the extra slot.
1829 { // Too few parameters: Actual < expected
1832 Register copy_from = x10;
1833 Register copy_end = x11;
1834 Register copy_to = x12;
1835 Register scratch1 = x13, scratch2 = x14;
1837 // If the function is strong we need to throw an error.
1838 Label no_strong_error;
1840 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1841 __ Ldr(scratch2.W(),
1842 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1843 __ TestAndBranchIfAllClear(scratch2.W(),
1844 (1 << SharedFunctionInfo::kStrongModeFunction),
1847 // What we really care about is the required number of arguments.
1848 DCHECK_EQ(kPointerSize, kInt64Size);
1849 __ Ldr(scratch2.W(),
1850 FieldMemOperand(scratch1, SharedFunctionInfo::kLengthOffset));
1851 __ Cmp(argc_actual, Operand(scratch2, LSR, 1));
1852 __ B(ge, &no_strong_error);
1855 FrameScope frame(masm, StackFrame::MANUAL);
1856 EnterArgumentsAdaptorFrame(masm);
1857 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments, 0);
1860 __ Bind(&no_strong_error);
1861 EnterArgumentsAdaptorFrame(masm);
1863 __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1864 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
1866 // Adjust for fp, lr, and the receiver.
1867 __ Add(copy_from, fp, 3 * kPointerSize);
1868 __ Add(copy_from, copy_from, argc_actual);
1869 __ Mov(copy_to, jssp);
1870 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver.
1871 __ Sub(copy_end, copy_end, argc_actual);
1873 // Claim space for the arguments, the receiver, and one extra slot.
1874 // The extra slot ensures we do not write under jssp. It will be popped
1876 __ Add(scratch1, argc_expected, 2 * kPointerSize);
1877 __ Claim(scratch1, 1);
1879 // Copy the arguments (including the receiver) to the new stack frame.
1881 __ Bind(©_2_by_2);
1882 __ Ldp(scratch1, scratch2,
1883 MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
1884 __ Stp(scratch1, scratch2,
1885 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1886 __ Cmp(copy_to, copy_end);
1887 __ B(hi, ©_2_by_2);
1889 __ Mov(copy_to, copy_end);
1891 // Fill the remaining expected arguments with undefined.
1892 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1893 __ Add(copy_end, jssp, kPointerSize);
1897 __ Stp(scratch1, scratch1,
1898 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1899 __ Cmp(copy_to, copy_end);
1902 // Correct the space allocated for the extra slot.
1906 // Arguments have been adapted. Now call the entry point.
1908 __ Call(code_entry);
1910 // Store offset of return address for deoptimizer.
1911 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1913 // Exit frame and return.
1914 LeaveArgumentsAdaptorFrame(masm);
1917 // Call the entry point without adapting the arguments.
1918 __ Bind(&dont_adapt_arguments);
1919 __ Jump(code_entry);
1921 __ Bind(&stack_overflow);
1923 FrameScope frame(masm, StackFrame::MANUAL);
1924 EnterArgumentsAdaptorFrame(masm);
1925 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1933 } // namespace internal
1936 #endif // V8_TARGET_ARCH_ARM