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