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
11 #include "deoptimizer.h"
12 #include "full-codegen.h"
14 #include "stub-cache.h"
20 #define __ ACCESS_MASM(masm)
23 // Load the built-in Array function from the current context.
24 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
25 // Load the native context.
26 __ Ldr(result, GlobalObjectMemOperand());
28 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
29 // Load the InternalArray function from the native context.
32 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
36 // Load the built-in InternalArray function from the current context.
37 static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
39 // Load the native context.
40 __ Ldr(result, GlobalObjectMemOperand());
42 FieldMemOperand(result, GlobalObject::kNativeContextOffset));
43 // Load the InternalArray function from the native context.
44 __ Ldr(result, ContextMemOperand(result,
45 Context::INTERNAL_ARRAY_FUNCTION_INDEX));
49 void Builtins::Generate_Adaptor(MacroAssembler* masm,
51 BuiltinExtraArguments extra_args) {
52 // ----------- S t a t e -------------
53 // -- x0 : number of arguments excluding receiver
54 // -- x1 : called function (only guaranteed when
55 // extra_args requires it)
57 // -- sp[0] : last argument
59 // -- sp[4 * (argc - 1)] : first argument (argc == x0)
60 // -- sp[4 * argc] : receiver
61 // -----------------------------------
63 // Insert extra arguments.
64 int num_extra_args = 0;
65 if (extra_args == NEEDS_CALLED_FUNCTION) {
69 ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
72 // JumpToExternalReference expects x0 to contain the number of arguments
73 // including the receiver and the extra arguments.
74 __ Add(x0, x0, num_extra_args + 1);
75 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
79 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
80 // ----------- S t a t e -------------
81 // -- x0 : number of arguments
82 // -- lr : return address
83 // -- sp[...]: constructor arguments
84 // -----------------------------------
85 ASM_LOCATION("Builtins::Generate_InternalArrayCode");
86 Label generic_array_code;
88 // Get the InternalArray function.
89 GenerateLoadInternalArrayFunction(masm, x1);
91 if (FLAG_debug_code) {
92 // Initial map for the builtin InternalArray functions should be maps.
93 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
94 __ Tst(x10, kSmiTagMask);
95 __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
96 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
97 __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
100 // Run the native code for the InternalArray function called as a normal
102 InternalArrayConstructorStub stub(masm->isolate());
103 __ TailCallStub(&stub);
107 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
108 // ----------- S t a t e -------------
109 // -- x0 : number of arguments
110 // -- lr : return address
111 // -- sp[...]: constructor arguments
112 // -----------------------------------
113 ASM_LOCATION("Builtins::Generate_ArrayCode");
114 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
116 // Get the Array function.
117 GenerateLoadArrayFunction(masm, x1);
119 if (FLAG_debug_code) {
120 // Initial map for the builtin Array functions should be maps.
121 __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
122 __ Tst(x10, kSmiTagMask);
123 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
124 __ CompareObjectType(x10, x11, x12, MAP_TYPE);
125 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
128 // Run the native code for the Array function called as a normal function.
129 __ 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 __ Claim(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::kHiddenTryInstallOptimizedCode);
298 GenerateTailCallToReturnedCode(masm);
301 GenerateTailCallToSharedCode(masm);
305 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
306 bool is_api_function,
307 bool count_constructions,
308 bool create_memento) {
309 // ----------- S t a t e -------------
310 // -- x0 : number of arguments
311 // -- x1 : constructor function
312 // -- x2 : allocation site or undefined
313 // -- lr : return address
314 // -- sp[...]: constructor arguments
315 // -----------------------------------
317 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
318 // Should never count constructions for api objects.
319 ASSERT(!is_api_function || !count_constructions);
320 // Should never create mementos for api functions.
321 ASSERT(!is_api_function || !create_memento);
322 // Should never create mementos before slack tracking is finished.
323 ASSERT(!count_constructions || !create_memento);
325 Isolate* isolate = masm->isolate();
327 // Enter a construct frame.
329 FrameScope scope(masm, StackFrame::CONSTRUCT);
331 // Preserve the three incoming parameters on the stack.
332 if (create_memento) {
333 __ AssertUndefinedOrAllocationSite(x2, x10);
338 Register constructor = x1;
339 // x1: constructor function
341 __ Push(argc, constructor);
342 // sp[0] : Constructor function.
343 // sp[1]: number of arguments (smi-tagged)
345 // Try to allocate the object without transitioning into C code. If any of
346 // the preconditions is not met, the code bails out to the runtime call.
347 Label rt_call, allocated;
348 if (FLAG_inline_new) {
349 Label undo_allocation;
350 ExternalReference debug_step_in_fp =
351 ExternalReference::debug_step_in_fp_address(isolate);
352 __ Mov(x2, Operand(debug_step_in_fp));
353 __ Ldr(x2, MemOperand(x2));
354 __ Cbnz(x2, &rt_call);
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 if (count_constructions) {
371 // Decrease generous allocation count.
372 __ Ldr(x3, FieldMemOperand(constructor,
373 JSFunction::kSharedFunctionInfoOffset));
374 MemOperand constructor_count =
375 FieldMemOperand(x3, SharedFunctionInfo::kConstructionCountOffset);
376 __ Ldrb(x4, constructor_count);
378 __ Strb(x4, constructor_count);
381 // Push the constructor and map to the stack, and the constructor again
382 // as argument to the runtime call.
383 __ Push(constructor, init_map, constructor);
384 // The call will replace the stub, so the countdown is only done once.
385 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1);
386 __ Pop(init_map, constructor);
390 // Now allocate the JSObject on the heap.
391 Register obj_size = x3;
392 Register new_obj = x4;
393 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
394 if (create_memento) {
396 Operand(AllocationMemento::kSize / kPointerSize));
397 __ Allocate(x7, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
399 __ Allocate(obj_size, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
402 // Allocated the JSObject, now initialize the fields. Map is set to
403 // initial map and properties and elements are set to empty fixed array.
404 // NB. the object pointer is not tagged, so MemOperand is used.
406 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
407 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
408 STATIC_ASSERT(JSObject::kElementsOffset ==
409 (JSObject::kPropertiesOffset + kPointerSize));
410 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
412 Register first_prop = x5;
413 __ Add(first_prop, new_obj, JSObject::kHeaderSize);
415 // Fill all of the in-object properties with the appropriate filler.
417 __ LoadRoot(undef, Heap::kUndefinedValueRootIndex);
419 // Obtain number of pre-allocated property fields and in-object
421 Register prealloc_fields = x10;
422 Register inobject_props = x11;
423 Register inst_sizes = x11;
424 __ Ldr(inst_sizes, FieldMemOperand(init_map, Map::kInstanceSizesOffset));
425 __ Ubfx(prealloc_fields, inst_sizes,
426 Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
428 __ Ubfx(inobject_props, inst_sizes,
429 Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte);
431 // Calculate number of property fields in the object.
432 Register prop_fields = x6;
433 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
435 if (count_constructions) {
436 // Fill the pre-allocated fields with undef.
437 __ FillFields(first_prop, prealloc_fields, undef);
439 // Register first_non_prealloc is the offset of the first field after
440 // pre-allocated fields.
441 Register first_non_prealloc = x12;
442 __ Add(first_non_prealloc, first_prop,
443 Operand(prealloc_fields, LSL, kPointerSizeLog2));
447 if (FLAG_debug_code) {
448 Register obj_end = x5;
449 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
450 __ Cmp(first_non_prealloc, obj_end);
451 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
454 // Fill the remaining fields with one pointer filler map.
455 Register one_pointer_filler = x5;
456 Register non_prealloc_fields = x6;
457 __ LoadRoot(one_pointer_filler, Heap::kOnePointerFillerMapRootIndex);
458 __ Sub(non_prealloc_fields, prop_fields, prealloc_fields);
459 __ FillFields(first_non_prealloc, non_prealloc_fields,
462 } else if (create_memento) {
463 // Fill the pre-allocated fields with undef.
464 __ FillFields(first_prop, prop_fields, undef);
465 __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
466 __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex);
467 ASSERT_EQ(0 * kPointerSize, AllocationMemento::kMapOffset);
468 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
469 // Load the AllocationSite
470 __ Peek(x14, 2 * kXRegSize);
471 ASSERT_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset);
472 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
475 // Fill all of the property fields with undef.
476 __ FillFields(first_prop, prop_fields, undef);
481 // Add the object tag to make the JSObject real, so that we can continue
482 // and jump into the continuation code at any time from now on. Any
483 // failures need to undo the allocation, so that the heap is in a
484 // consistent state and verifiable.
485 __ Add(new_obj, new_obj, kHeapObjectTag);
487 // Check if a non-empty properties array is needed. Continue with
488 // allocated object if not, or fall through to runtime call if it is.
489 Register element_count = x3;
490 __ Ldrb(element_count,
491 FieldMemOperand(init_map, Map::kUnusedPropertyFieldsOffset));
492 // The field instance sizes contains both pre-allocated property fields
493 // and in-object properties.
494 __ Add(element_count, element_count, prealloc_fields);
495 __ Subs(element_count, element_count, inobject_props);
497 // Done if no extra properties are to be allocated.
498 __ B(eq, &allocated);
499 __ Assert(pl, kPropertyAllocationCountFailed);
501 // Scale the number of elements by pointer size and add the header for
502 // FixedArrays to the start of the next object calculation from above.
503 Register new_array = x5;
504 Register array_size = x6;
505 __ Add(array_size, element_count, FixedArray::kHeaderSize / kPointerSize);
506 __ Allocate(array_size, new_array, x11, x12, &undo_allocation,
507 static_cast<AllocationFlags>(RESULT_CONTAINS_TOP |
510 Register array_map = x10;
511 __ LoadRoot(array_map, Heap::kFixedArrayMapRootIndex);
512 __ Str(array_map, MemOperand(new_array, FixedArray::kMapOffset));
513 __ SmiTag(x0, element_count);
514 __ Str(x0, MemOperand(new_array, FixedArray::kLengthOffset));
516 // Initialize the fields to undefined.
517 Register elements = x10;
518 __ Add(elements, new_array, FixedArray::kHeaderSize);
519 __ FillFields(elements, element_count, undef);
521 // Store the initialized FixedArray into the properties field of the
523 __ Add(new_array, new_array, kHeapObjectTag);
524 __ Str(new_array, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
526 // Continue with JSObject being successfully allocated.
529 // Undo the setting of the new top so that the heap is verifiable. For
530 // example, the map's unused properties potentially do not match the
531 // allocated objects unused properties.
532 __ Bind(&undo_allocation);
533 __ UndoAllocationInNewSpace(new_obj, x14);
536 // Allocate the new receiver object using the runtime call.
538 Label count_incremented;
539 if (create_memento) {
540 // Get the cell or allocation site.
541 __ Peek(x4, 2 * kXRegSize);
543 __ Push(constructor); // Argument for Runtime_NewObject.
544 __ CallRuntime(Runtime::kHiddenNewObjectWithAllocationSite, 2);
546 // If we ended up using the runtime, and we want a memento, then the
547 // runtime call made it for us, and we shouldn't do create count
549 __ jmp(&count_incremented);
551 __ Push(constructor); // Argument for Runtime_NewObject.
552 __ CallRuntime(Runtime::kHiddenNewObject, 1);
556 // Receiver for constructor call allocated.
560 if (create_memento) {
561 __ Peek(x10, 2 * kXRegSize);
562 __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
563 // r2 is an AllocationSite. We are creating a memento from it, so we
564 // need to increment the memento create count.
565 __ Ldr(x5, FieldMemOperand(x10,
566 AllocationSite::kPretenureCreateCountOffset));
567 __ Add(x5, x5, Operand(Smi::FromInt(1)));
568 __ Str(x5, FieldMemOperand(x10,
569 AllocationSite::kPretenureCreateCountOffset));
570 __ bind(&count_incremented);
575 // Reload the number of arguments from the stack.
576 // Set it up in x0 for the function call below.
579 // jssp[2]: constructor function
580 // jssp[3]: number of arguments (smi-tagged)
581 __ Peek(constructor, 2 * kXRegSize); // Load constructor.
582 __ Peek(argc, 3 * kXRegSize); // Load number of arguments.
585 // Set up pointer to last argument.
586 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
588 // Copy arguments and receiver to the expression stack.
589 // Copy 2 values every loop to use ldp/stp.
590 // x0: number of arguments
591 // x1: constructor function
592 // x2: address of last argument (caller sp)
595 // jssp[2]: constructor function
596 // jssp[3]: number of arguments (smi-tagged)
597 // Compute the start address of the copy in x3.
598 __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
599 Label loop, entry, done_copying_arguments;
602 __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
607 // Because we copied values 2 by 2 we may have copied one extra value.
608 // Drop it if that is the case.
609 __ B(eq, &done_copying_arguments);
611 __ Bind(&done_copying_arguments);
613 // Call the function.
614 // x0: number of arguments
615 // x1: constructor function
616 if (is_api_function) {
617 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
619 masm->isolate()->builtins()->HandleApiCallConstruct();
620 __ Call(code, RelocInfo::CODE_TARGET);
622 ParameterCount actual(argc);
623 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
626 // Store offset of return address for deoptimizer.
627 if (!is_api_function && !count_constructions) {
628 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
631 // Restore the context from the frame.
634 // jssp[1]: constructor function
635 // jssp[2]: number of arguments (smi-tagged)
636 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
638 // If the result is an object (in the ECMA sense), we should get rid
639 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
641 Label use_receiver, exit;
643 // If the result is a smi, it is *not* an object in the ECMA sense.
645 // jssp[0]: receiver (newly allocated object)
646 // jssp[1]: constructor function
647 // jssp[2]: number of arguments (smi-tagged)
648 __ JumpIfSmi(x0, &use_receiver);
650 // If the type of the result (stored in its map) is less than
651 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
652 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
654 // Throw away the result of the constructor invocation and use the
655 // on-stack receiver as the result.
656 __ Bind(&use_receiver);
659 // Remove the receiver from the stack, remove caller arguments, and
663 // jssp[0]: receiver (newly allocated object)
664 // jssp[1]: constructor function
665 // jssp[2]: number of arguments (smi-tagged)
666 __ Peek(x1, 2 * kXRegSize);
668 // Leave construct frame.
673 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
678 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
679 Generate_JSConstructStubHelper(masm, false, true, false);
683 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
684 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
688 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
689 Generate_JSConstructStubHelper(masm, true, false, false);
701 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
703 // Called from JSEntryStub::GenerateBody().
704 Register function = x1;
705 Register receiver = x2;
709 ProfileEntryHookStub::MaybeCallEntryHook(masm);
711 // Clear the context before we push it when entering the internal frame.
715 // Enter an internal frame.
716 FrameScope scope(masm, StackFrame::INTERNAL);
718 // Set up the context from the function argument.
719 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
721 __ InitializeRootRegister();
723 // Push the function and the receiver onto the stack.
724 __ Push(function, receiver);
726 // Copy arguments to the stack in a loop, in reverse order.
730 // Compute the copy end address.
731 __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
735 __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
736 __ Ldr(x12, MemOperand(x11)); // Dereference the handle.
737 __ Push(x12); // Push the argument.
742 // Initialize all JavaScript callee-saved registers, since they will be seen
743 // by the garbage collector as part of handlers.
744 // The original values have been saved in JSEntryStub::GenerateBody().
745 __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
752 // Don't initialize the reserved registers.
753 // x26 : root register (root).
754 // x27 : context pointer (cp).
755 // x28 : JS stack pointer (jssp).
756 // x29 : frame pointer (fp).
760 // No type feedback cell is available.
761 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
763 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
766 ParameterCount actual(x0);
767 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
769 // Exit the JS internal frame and remove the parameters (except function),
773 // Result is in x0. Return.
778 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
779 Generate_JSEntryTrampolineHelper(masm, false);
783 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
784 Generate_JSEntryTrampolineHelper(masm, true);
788 void Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
789 CallRuntimePassFunction(masm, Runtime::kHiddenCompileUnoptimized);
790 GenerateTailCallToReturnedCode(masm);
794 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
795 FrameScope scope(masm, StackFrame::INTERNAL);
796 Register function = x1;
798 // Preserve function. At the same time, push arguments for
799 // kHiddenCompileOptimized.
800 __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
801 __ Push(function, function, x10);
803 __ CallRuntime(Runtime::kHiddenCompileOptimized, 2);
810 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
811 CallCompileOptimized(masm, false);
812 GenerateTailCallToReturnedCode(masm);
816 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
817 CallCompileOptimized(masm, true);
818 GenerateTailCallToReturnedCode(masm);
822 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
823 // For now, we are relying on the fact that make_code_young doesn't do any
824 // garbage collection which allows us to save/restore the registers without
825 // worrying about which of them contain pointers. We also don't build an
826 // internal frame to make the code fast, since we shouldn't have to do stack
827 // crawls in MakeCodeYoung. This seems a bit fragile.
829 // The following caller-saved registers must be saved and restored when
830 // calling through to the runtime:
831 // x0 - The address from which to resume execution.
833 // lr - The return address for the JSFunction itself. It has not yet been
834 // preserved on the stack because the frame setup code was replaced
835 // with a call to this stub, to handle code ageing.
837 FrameScope scope(masm, StackFrame::MANUAL);
838 __ Push(x0, x1, fp, lr);
839 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
841 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
842 __ Pop(lr, fp, x1, x0);
845 // The calling function has been made young again, so return to execute the
846 // real frame set-up code.
850 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
851 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
852 MacroAssembler* masm) { \
853 GenerateMakeCodeYoungAgainCommon(masm); \
855 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
856 MacroAssembler* masm) { \
857 GenerateMakeCodeYoungAgainCommon(masm); \
859 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
860 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
863 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
864 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
865 // that make_code_young doesn't do any garbage collection which allows us to
866 // save/restore the registers without worrying about which of them contain
869 // The following caller-saved registers must be saved and restored when
870 // calling through to the runtime:
871 // x0 - The address from which to resume execution.
873 // lr - The return address for the JSFunction itself. It has not yet been
874 // preserved on the stack because the frame setup code was replaced
875 // with a call to this stub, to handle code ageing.
877 FrameScope scope(masm, StackFrame::MANUAL);
878 __ Push(x0, x1, fp, lr);
879 __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
881 ExternalReference::get_mark_code_as_executed_function(
882 masm->isolate()), 2);
883 __ Pop(lr, fp, x1, x0);
885 // Perform prologue operations usually performed by the young code stub.
886 __ EmitFrameSetupForCodeAgePatching(masm);
889 // Jump to point after the code-age stub.
890 __ Add(x0, x0, kCodeAgeSequenceSize);
895 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
896 GenerateMakeCodeYoungAgainCommon(masm);
900 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
901 SaveFPRegsMode save_doubles) {
903 FrameScope scope(masm, StackFrame::INTERNAL);
905 // Preserve registers across notification, this is important for compiled
906 // stubs that tail call the runtime on deopts passing their parameters in
908 // TODO(jbramley): Is it correct (and appropriate) to use safepoint
909 // registers here? According to the comment above, we should only need to
910 // preserve the registers with parameters.
911 __ PushXRegList(kSafepointSavedRegisters);
912 // Pass the function and deoptimization type to the runtime system.
913 __ CallRuntime(Runtime::kHiddenNotifyStubFailure, 0, save_doubles);
914 __ PopXRegList(kSafepointSavedRegisters);
917 // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
920 // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
921 // into lr before it jumps here.
926 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
927 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
931 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
932 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
936 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
937 Deoptimizer::BailoutType type) {
939 FrameScope scope(masm, StackFrame::INTERNAL);
940 // Pass the deoptimization type to the runtime system.
941 __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
943 __ CallRuntime(Runtime::kHiddenNotifyDeoptimized, 1);
946 // Get the full codegen state from the stack and untag it.
951 // Switch on the state.
952 Label with_tos_register, unknown_state;
954 state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
955 __ Drop(1); // Remove state.
958 __ Bind(&with_tos_register);
959 // Reload TOS register.
960 __ Peek(x0, kPointerSize);
961 __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
962 __ Drop(2); // Remove state and TOS.
965 __ Bind(&unknown_state);
966 __ Abort(kInvalidFullCodegenState);
970 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
971 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
975 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
976 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
980 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
981 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
985 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
986 // Lookup the function in the JavaScript frame.
987 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
989 FrameScope scope(masm, StackFrame::INTERNAL);
990 // Pass function as argument.
992 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
995 // If the code object is null, just return to the unoptimized code.
997 __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
1002 // Load deoptimization data from the code object.
1003 // <deopt_data> = <code>[#deoptimization_data_offset]
1004 __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1006 // Load the OSR entrypoint offset from the deoptimization data.
1007 // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
1008 __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
1009 DeoptimizationInputData::kOsrPcOffsetIndex)));
1011 // Compute the target address = code_obj + header_size + osr_offset
1012 // <entry_addr> = <code_obj> + #header_size + <osr_offset>
1014 __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
1016 // And "return" to the OSR entry point of the function.
1021 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1022 // We check the stack limit as indicator that recompilation might be done.
1024 __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
1027 FrameScope scope(masm, StackFrame::INTERNAL);
1028 __ CallRuntime(Runtime::kHiddenStackGuard, 0);
1030 __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
1031 RelocInfo::CODE_TARGET);
1038 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1040 call_type_JS_func = 0,
1041 call_type_func_proxy = 1,
1042 call_type_non_func = 2
1045 Register function = x1;
1046 Register call_type = x4;
1047 Register scratch1 = x10;
1048 Register scratch2 = x11;
1049 Register receiver_type = x13;
1051 ASM_LOCATION("Builtins::Generate_FunctionCall");
1052 // 1. Make sure we have at least one argument.
1054 __ Cbnz(argc, &done);
1055 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1061 // 2. Get the function to call (passed as receiver) from the stack, check
1062 // if it is a function.
1063 Label slow, non_function;
1064 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1065 __ JumpIfSmi(function, &non_function);
1066 __ JumpIfNotObjectType(function, scratch1, receiver_type,
1067 JS_FUNCTION_TYPE, &slow);
1069 // 3a. Patch the first argument if necessary when calling a function.
1070 Label shift_arguments;
1071 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1072 { Label convert_to_object, use_global_receiver, patch_receiver;
1073 // Change context eagerly in case we need the global receiver.
1074 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1076 // Do not transform the receiver for strict mode functions.
1077 // Also do not transform the receiver for native (Compilerhints already in
1080 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1081 __ Ldr(scratch2.W(),
1082 FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
1083 __ TestAndBranchIfAnySet(
1085 (1 << SharedFunctionInfo::kStrictModeFunction) |
1086 (1 << SharedFunctionInfo::kNative),
1089 // Compute the receiver in sloppy mode.
1090 Register receiver = x2;
1091 __ Sub(scratch1, argc, 1);
1092 __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1093 __ JumpIfSmi(receiver, &convert_to_object);
1095 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1096 &use_global_receiver);
1097 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_receiver);
1099 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1100 __ JumpIfObjectType(receiver, scratch1, scratch2,
1101 FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
1103 __ Bind(&convert_to_object);
1106 // Enter an internal frame in order to preserve argument count.
1107 FrameScope scope(masm, StackFrame::INTERNAL);
1110 __ Push(argc, receiver);
1111 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1112 __ Mov(receiver, x0);
1117 // Exit the internal frame.
1120 // Restore the function and flag in the registers.
1121 __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1122 __ Mov(call_type, static_cast<int>(call_type_JS_func));
1123 __ B(&patch_receiver);
1125 __ Bind(&use_global_receiver);
1126 __ Ldr(receiver, GlobalObjectMemOperand());
1128 FieldMemOperand(receiver, GlobalObject::kGlobalReceiverOffset));
1131 __ Bind(&patch_receiver);
1132 __ Sub(scratch1, argc, 1);
1133 __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
1135 __ B(&shift_arguments);
1138 // 3b. Check for function proxy.
1140 __ Mov(call_type, static_cast<int>(call_type_func_proxy));
1141 __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
1142 __ B(eq, &shift_arguments);
1143 __ Bind(&non_function);
1144 __ Mov(call_type, static_cast<int>(call_type_non_func));
1146 // 3c. Patch the first argument when calling a non-function. The
1147 // CALL_NON_FUNCTION builtin expects the non-function callee as
1148 // receiver, so overwrite the first argument which will ultimately
1149 // become the receiver.
1150 // call type (0: JS function, 1: function proxy, 2: non-function)
1151 __ Sub(scratch1, argc, 1);
1152 __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
1154 // 4. Shift arguments and return address one slot down on the stack
1155 // (overwriting the original receiver). Adjust argument count to make
1156 // the original first argument the new receiver.
1157 // call type (0: JS function, 1: function proxy, 2: non-function)
1158 __ Bind(&shift_arguments);
1160 // Calculate the copy start address (destination). Copy end address is jssp.
1161 __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1162 __ Sub(scratch1, scratch2, kPointerSize);
1165 __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1166 __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1167 __ Cmp(scratch1, jssp);
1169 // Adjust the actual number of arguments and remove the top element
1170 // (which is a copy of the last argument).
1171 __ Sub(argc, argc, 1);
1175 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1176 // or a function proxy via CALL_FUNCTION_PROXY.
1177 // call type (0: JS function, 1: function proxy, 2: non-function)
1178 { Label js_function, non_proxy;
1179 __ Cbz(call_type, &js_function);
1180 // Expected number of arguments is 0 for CALL_NON_FUNCTION.
1182 __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
1183 __ B(ne, &non_proxy);
1185 __ Push(function); // Re-add proxy object as additional argument.
1186 __ Add(argc, argc, 1);
1187 __ GetBuiltinFunction(function, Builtins::CALL_FUNCTION_PROXY);
1188 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1189 RelocInfo::CODE_TARGET);
1191 __ Bind(&non_proxy);
1192 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
1193 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1194 RelocInfo::CODE_TARGET);
1195 __ Bind(&js_function);
1198 // 5b. Get the code to call from the function and check that the number of
1199 // expected arguments matches what we're providing. If so, jump
1200 // (tail-call) to the code in register edx without checking arguments.
1201 __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
1204 SharedFunctionInfo::kFormalParameterCountOffset));
1205 Label dont_adapt_args;
1206 __ Cmp(x2, argc); // Check formal and actual parameter counts.
1207 __ B(eq, &dont_adapt_args);
1208 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1209 RelocInfo::CODE_TARGET);
1210 __ Bind(&dont_adapt_args);
1212 __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1213 ParameterCount expected(0);
1214 __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
1218 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1219 ASM_LOCATION("Builtins::Generate_FunctionApply");
1220 const int kIndexOffset =
1221 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
1222 const int kLimitOffset =
1223 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
1224 const int kArgsOffset = 2 * kPointerSize;
1225 const int kReceiverOffset = 3 * kPointerSize;
1226 const int kFunctionOffset = 4 * kPointerSize;
1229 FrameScope frame_scope(masm, StackFrame::INTERNAL);
1231 Register args = x12;
1232 Register receiver = x14;
1233 Register function = x15;
1235 // Get the length of the arguments via a builtin call.
1236 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1237 __ Ldr(args, MemOperand(fp, kArgsOffset));
1238 __ Push(function, args);
1239 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
1242 // Check the stack for overflow.
1243 // We are not trying to catch interruptions (e.g. debug break and
1244 // preemption) here, so the "real stack limit" is checked.
1245 Label enough_stack_space;
1246 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1247 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1248 // Make x10 the space we have left. The stack might already be overflowed
1249 // here which will cause x10 to become negative.
1250 // TODO(jbramley): Check that the stack usage here is safe.
1251 __ Sub(x10, jssp, x10);
1252 // Check if the arguments will overflow the stack.
1253 __ Cmp(x10, Operand(argc, LSR, kSmiShift - kPointerSizeLog2));
1254 __ B(gt, &enough_stack_space);
1255 // There is not enough stack space, so use a builtin to throw an appropriate
1257 __ Push(function, argc);
1258 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1259 // We should never return from the APPLY_OVERFLOW builtin.
1260 if (__ emit_debug_code()) {
1264 __ Bind(&enough_stack_space);
1265 // Push current limit and index.
1266 __ Mov(x1, 0); // Initial index.
1269 Label push_receiver;
1270 __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
1272 // Check that the function is a JS function. Otherwise it must be a proxy.
1273 // When it is not the function proxy will be invoked later.
1274 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
1277 // Change context eagerly to get the right global object if necessary.
1278 __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
1279 // Load the shared function info.
1280 __ Ldr(x2, FieldMemOperand(function,
1281 JSFunction::kSharedFunctionInfoOffset));
1283 // Compute and push the receiver.
1284 // Do not transform the receiver for strict mode functions.
1285 Label convert_receiver_to_object, use_global_receiver;
1286 __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
1287 __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
1288 // Do not transform the receiver for native functions.
1289 __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
1291 // Compute the receiver in sloppy mode.
1292 __ JumpIfSmi(receiver, &convert_receiver_to_object);
1293 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_receiver);
1294 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
1295 &use_global_receiver);
1297 // Check if the receiver is already a JavaScript object.
1298 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1299 __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
1300 &push_receiver, ge);
1302 // Call a builtin to convert the receiver to a regular object.
1303 __ Bind(&convert_receiver_to_object);
1305 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1306 __ Mov(receiver, x0);
1307 __ B(&push_receiver);
1309 __ Bind(&use_global_receiver);
1310 __ Ldr(x10, GlobalObjectMemOperand());
1311 __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalReceiverOffset));
1313 // Push the receiver
1314 __ Bind(&push_receiver);
1317 // Copy all arguments from the array to the stack.
1319 Register current = x0;
1320 __ Ldr(current, MemOperand(fp, kIndexOffset));
1324 // Load the current argument from the arguments array and push it.
1325 // TODO(all): Couldn't we optimize this for JS arrays?
1327 __ Ldr(x1, MemOperand(fp, kArgsOffset));
1328 __ Push(x1, current);
1330 // Call the runtime to access the property in the arguments array.
1331 __ CallRuntime(Runtime::kGetProperty, 2);
1334 // Use inline caching to access the arguments.
1335 __ Ldr(current, MemOperand(fp, kIndexOffset));
1336 __ Add(current, current, Smi::FromInt(1));
1337 __ Str(current, MemOperand(fp, kIndexOffset));
1339 // Test if the copy loop has finished copying all the elements from the
1340 // arguments object.
1342 __ Ldr(x1, MemOperand(fp, kLimitOffset));
1343 __ Cmp(current, x1);
1346 // At the end of the loop, the number of arguments is stored in 'current',
1347 // represented as a smi.
1349 function = x1; // From now on we want the function to be kept in x1;
1350 __ Ldr(function, MemOperand(fp, kFunctionOffset));
1352 // Call the function.
1354 ParameterCount actual(current);
1355 __ SmiUntag(current);
1356 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
1357 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
1358 frame_scope.GenerateLeaveFrame();
1362 // Call the function proxy.
1363 __ Bind(&call_proxy);
1366 __ Push(function); // Add function proxy as last argument.
1369 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
1370 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1371 RelocInfo::CODE_TARGET);
1378 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
1379 Label* stack_overflow) {
1380 // ----------- S t a t e -------------
1381 // -- x0 : actual number of arguments
1382 // -- x1 : function (passed through to callee)
1383 // -- x2 : expected number of arguments
1384 // -----------------------------------
1385 // Check the stack for overflow.
1386 // We are not trying to catch interruptions (e.g. debug break and
1387 // preemption) here, so the "real stack limit" is checked.
1388 Label enough_stack_space;
1389 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
1390 // Make x10 the space we have left. The stack might already be overflowed
1391 // here which will cause x10 to become negative.
1392 __ Sub(x10, jssp, x10);
1393 // Check if the arguments will overflow the stack.
1394 __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
1395 __ B(le, stack_overflow);
1399 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1401 __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1403 __ Push(x11, x1, x10);
1405 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
1409 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1410 // ----------- S t a t e -------------
1411 // -- x0 : result being passed through
1412 // -----------------------------------
1413 // Get the number of arguments passed (as a smi), tear down the frame and
1414 // then drop the parameters and the receiver.
1415 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
1419 __ DropBySMI(x10, kXRegSize);
1424 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1425 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
1426 // ----------- S t a t e -------------
1427 // -- x0 : actual number of arguments
1428 // -- x1 : function (passed through to callee)
1429 // -- x2 : expected number of arguments
1430 // -----------------------------------
1432 Label stack_overflow;
1433 ArgumentAdaptorStackCheck(masm, &stack_overflow);
1435 Register argc_actual = x0; // Excluding the receiver.
1436 Register argc_expected = x2; // Excluding the receiver.
1437 Register function = x1;
1438 Register code_entry = x3;
1440 Label invoke, dont_adapt_arguments;
1442 Label enough, too_few;
1443 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1444 __ Cmp(argc_actual, argc_expected);
1446 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1447 __ B(eq, &dont_adapt_arguments);
1449 { // Enough parameters: actual >= expected
1450 EnterArgumentsAdaptorFrame(masm);
1452 Register copy_start = x10;
1453 Register copy_end = x11;
1454 Register copy_to = x12;
1455 Register scratch1 = x13, scratch2 = x14;
1457 __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1459 // Adjust for fp, lr, and the receiver.
1460 __ Add(copy_start, fp, 3 * kPointerSize);
1461 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
1462 __ Sub(copy_end, copy_start, argc_expected);
1463 __ Sub(copy_end, copy_end, kPointerSize);
1464 __ Mov(copy_to, jssp);
1466 // Claim space for the arguments, the receiver, and one extra slot.
1467 // The extra slot ensures we do not write under jssp. It will be popped
1469 __ Add(scratch1, argc_expected, 2 * kPointerSize);
1470 __ Claim(scratch1, 1);
1472 // Copy the arguments (including the receiver) to the new stack frame.
1474 __ Bind(©_2_by_2);
1475 __ Ldp(scratch1, scratch2,
1476 MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
1477 __ Stp(scratch1, scratch2,
1478 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1479 __ Cmp(copy_start, copy_end);
1480 __ B(hi, ©_2_by_2);
1482 // Correct the space allocated for the extra slot.
1488 { // Too few parameters: Actual < expected
1490 EnterArgumentsAdaptorFrame(masm);
1492 Register copy_from = x10;
1493 Register copy_end = x11;
1494 Register copy_to = x12;
1495 Register scratch1 = x13, scratch2 = x14;
1497 __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
1498 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
1500 // Adjust for fp, lr, and the receiver.
1501 __ Add(copy_from, fp, 3 * kPointerSize);
1502 __ Add(copy_from, copy_from, argc_actual);
1503 __ Mov(copy_to, jssp);
1504 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver.
1505 __ Sub(copy_end, copy_end, argc_actual);
1507 // Claim space for the arguments, the receiver, and one extra slot.
1508 // The extra slot ensures we do not write under jssp. It will be popped
1510 __ Add(scratch1, argc_expected, 2 * kPointerSize);
1511 __ Claim(scratch1, 1);
1513 // Copy the arguments (including the receiver) to the new stack frame.
1515 __ Bind(©_2_by_2);
1516 __ Ldp(scratch1, scratch2,
1517 MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
1518 __ Stp(scratch1, scratch2,
1519 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1520 __ Cmp(copy_to, copy_end);
1521 __ B(hi, ©_2_by_2);
1523 __ Mov(copy_to, copy_end);
1525 // Fill the remaining expected arguments with undefined.
1526 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1527 __ Add(copy_end, jssp, kPointerSize);
1531 __ Stp(scratch1, scratch1,
1532 MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
1533 __ Cmp(copy_to, copy_end);
1536 // Correct the space allocated for the extra slot.
1540 // Arguments have been adapted. Now call the entry point.
1542 __ Call(code_entry);
1544 // Store offset of return address for deoptimizer.
1545 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1547 // Exit frame and return.
1548 LeaveArgumentsAdaptorFrame(masm);
1551 // Call the entry point without adapting the arguments.
1552 __ Bind(&dont_adapt_arguments);
1553 __ Jump(code_entry);
1555 __ Bind(&stack_overflow);
1557 FrameScope frame(masm, StackFrame::MANUAL);
1558 EnterArgumentsAdaptorFrame(masm);
1559 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1567 } } // namespace v8::internal
1569 #endif // V8_TARGET_ARCH_ARM