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