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