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