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 #ifndef V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ 6 #define V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ 7 8 #include "src/assembler.h" 9 #include "src/globals.h" 10 #include "src/mips64/assembler-mips64.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // Forward declaration. 16 class JumpTarget; 17 18 // Reserved Register Usage Summary. 19 // 20 // Registers t8, t9, and at are reserved for use by the MacroAssembler. 21 // 22 // The programmer should know that the MacroAssembler may clobber these three, 23 // but won't touch other registers except in special cases. 24 // 25 // Per the MIPS ABI, register t9 must be used for indirect function call 26 // via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when 27 // trying to update gp register for position-independent-code. Whenever 28 // MIPS generated code calls C code, it must be via t9 register. 29 30 31 // Flags used for LeaveExitFrame function. 32 enum LeaveExitFrameMode { 33 EMIT_RETURN = true, 34 NO_EMIT_RETURN = false 35 }; 36 37 // Flags used for AllocateHeapNumber 38 enum TaggingMode { 39 // Tag the result. 40 TAG_RESULT, 41 // Don't tag 42 DONT_TAG_RESULT 43 }; 44 45 // Flags used for the ObjectToDoubleFPURegister function. 46 enum ObjectToDoubleFlags { 47 // No special flags. 48 NO_OBJECT_TO_DOUBLE_FLAGS = 0, 49 // Object is known to be a non smi. 50 OBJECT_NOT_SMI = 1 << 0, 51 // Don't load NaNs or infinities, branch to the non number case instead. 52 AVOID_NANS_AND_INFINITIES = 1 << 1 53 }; 54 55 // Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls. 56 enum BranchDelaySlot { 57 USE_DELAY_SLOT, 58 PROTECT 59 }; 60 61 // Flags used for the li macro-assembler function. 62 enum LiFlags { 63 // If the constant value can be represented in just 16 bits, then 64 // optimize the li to use a single instruction, rather than lui/ori/dsll 65 // sequence. 66 OPTIMIZE_SIZE = 0, 67 // Always use 6 instructions (lui/ori/dsll sequence), even if the constant 68 // could be loaded with just one, so that this value is patchable later. 69 CONSTANT_SIZE = 1, 70 // For address loads only 4 instruction are required. Used to mark 71 // constant load that will be used as address without relocation 72 // information. It ensures predictable code size, so specific sites 73 // in code are patchable. 74 ADDRESS_LOAD = 2 75 }; 76 77 78 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 79 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 80 enum PointersToHereCheck { 81 kPointersToHereMaybeInteresting, 82 kPointersToHereAreAlwaysInteresting 83 }; 84 enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved }; 85 86 Register GetRegisterThatIsNotOneOf(Register reg1, 87 Register reg2 = no_reg, 88 Register reg3 = no_reg, 89 Register reg4 = no_reg, 90 Register reg5 = no_reg, 91 Register reg6 = no_reg); 92 93 bool AreAliased(Register reg1, 94 Register reg2, 95 Register reg3 = no_reg, 96 Register reg4 = no_reg, 97 Register reg5 = no_reg, 98 Register reg6 = no_reg, 99 Register reg7 = no_reg, 100 Register reg8 = no_reg); 101 102 103 // ----------------------------------------------------------------------------- 104 // Static helper functions. 105 106 inline MemOperand ContextOperand(Register context, int index) { 107 return MemOperand(context, Context::SlotOffset(index)); 108 } 109 110 111 inline MemOperand GlobalObjectOperand() { 112 return ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX); 113 } 114 115 116 // Generate a MemOperand for loading a field from an object. 117 inline MemOperand FieldMemOperand(Register object, int offset) { 118 return MemOperand(object, offset - kHeapObjectTag); 119 } 120 121 122 inline MemOperand UntagSmiMemOperand(Register rm, int offset) { 123 // Assumes that Smis are shifted by 32 bits and little endianness. 124 STATIC_ASSERT(kSmiShift == 32); 125 return MemOperand(rm, offset + (kSmiShift / kBitsPerByte)); 126 } 127 128 129 inline MemOperand UntagSmiFieldMemOperand(Register rm, int offset) { 130 return UntagSmiMemOperand(rm, offset - kHeapObjectTag); 131 } 132 133 134 // Generate a MemOperand for storing arguments 5..N on the stack 135 // when calling CallCFunction(). 136 // TODO(plind): Currently ONLY used for O32. Should be fixed for 137 // n64, and used in RegExp code, and other places 138 // with more than 8 arguments. 139 inline MemOperand CFunctionArgumentOperand(int index) { 140 DCHECK(index > kCArgSlotCount); 141 // Argument 5 takes the slot just past the four Arg-slots. 142 int offset = (index - 5) * kPointerSize + kCArgsSlotsSize; 143 return MemOperand(sp, offset); 144 } 145 146 147 // MacroAssembler implements a collection of frequently used macros. 148 class MacroAssembler: public Assembler { 149 public: 150 // The isolate parameter can be NULL if the macro assembler should 151 // not use isolate-dependent functionality. In this case, it's the 152 // responsibility of the caller to never invoke such function on the 153 // macro assembler. 154 MacroAssembler(Isolate* isolate, void* buffer, int size); 155 156 // Arguments macros. 157 #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2 158 #define COND_ARGS cond, r1, r2 159 160 // Cases when relocation is not needed. 161 #define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \ 162 void Name(target_type target, BranchDelaySlot bd = PROTECT); \ 163 inline void Name(BranchDelaySlot bd, target_type target) { \ 164 Name(target, bd); \ 165 } \ 166 void Name(target_type target, \ 167 COND_TYPED_ARGS, \ 168 BranchDelaySlot bd = PROTECT); \ 169 inline void Name(BranchDelaySlot bd, \ 170 target_type target, \ 171 COND_TYPED_ARGS) { \ 172 Name(target, COND_ARGS, bd); \ 173 } 174 175 #define DECLARE_BRANCH_PROTOTYPES(Name) \ 176 DECLARE_NORELOC_PROTOTYPE(Name, Label*) \ 177 DECLARE_NORELOC_PROTOTYPE(Name, int16_t) 178 179 DECLARE_BRANCH_PROTOTYPES(Branch) 180 DECLARE_BRANCH_PROTOTYPES(BranchAndLink) 181 DECLARE_BRANCH_PROTOTYPES(BranchShort) 182 183 #undef DECLARE_BRANCH_PROTOTYPES 184 #undef COND_TYPED_ARGS 185 #undef COND_ARGS 186 187 188 // Jump, Call, and Ret pseudo instructions implementing inter-working. 189 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \ 190 const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT 191 192 void Jump(Register target, COND_ARGS); 193 void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS); 194 void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS); 195 void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS); 196 static int CallSize(Register target, COND_ARGS); 197 void Call(Register target, COND_ARGS); 198 static int CallSize(Address target, RelocInfo::Mode rmode, COND_ARGS); 199 void Call(Address target, RelocInfo::Mode rmode, COND_ARGS); 200 int CallSize(Handle<Code> code, 201 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 202 TypeFeedbackId ast_id = TypeFeedbackId::None(), 203 COND_ARGS); 204 void Call(Handle<Code> code, 205 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 206 TypeFeedbackId ast_id = TypeFeedbackId::None(), 207 COND_ARGS); 208 void Ret(COND_ARGS); 209 inline void Ret(BranchDelaySlot bd, Condition cond = al, 210 Register rs = zero_reg, const Operand& rt = Operand(zero_reg)) { 211 Ret(cond, rs, rt, bd); 212 } 213 214 void Branch(Label* L, 215 Condition cond, 216 Register rs, 217 Heap::RootListIndex index, 218 BranchDelaySlot bdslot = PROTECT); 219 220 #undef COND_ARGS 221 222 // Emit code to discard a non-negative number of pointer-sized elements 223 // from the stack, clobbering only the sp register. 224 void Drop(int count, 225 Condition cond = cc_always, 226 Register reg = no_reg, 227 const Operand& op = Operand(no_reg)); 228 229 // Trivial case of DropAndRet that utilizes the delay slot and only emits 230 // 2 instructions. 231 void DropAndRet(int drop); 232 233 void DropAndRet(int drop, 234 Condition cond, 235 Register reg, 236 const Operand& op); 237 238 // Swap two registers. If the scratch register is omitted then a slightly 239 // less efficient form using xor instead of mov is emitted. 240 void Swap(Register reg1, Register reg2, Register scratch = no_reg); 241 242 void Call(Label* target); 243 244 inline void Move(Register dst, Register src) { 245 if (!dst.is(src)) { 246 mov(dst, src); 247 } 248 } 249 250 inline void Move(FPURegister dst, FPURegister src) { 251 if (!dst.is(src)) { 252 mov_d(dst, src); 253 } 254 } 255 256 inline void Move(Register dst_low, Register dst_high, FPURegister src) { 257 mfc1(dst_low, src); 258 mfhc1(dst_high, src); 259 } 260 261 inline void FmoveHigh(Register dst_high, FPURegister src) { 262 mfhc1(dst_high, src); 263 } 264 265 inline void FmoveLow(Register dst_low, FPURegister src) { 266 mfc1(dst_low, src); 267 } 268 269 inline void Move(FPURegister dst, Register src_low, Register src_high) { 270 mtc1(src_low, dst); 271 mthc1(src_high, dst); 272 } 273 274 // Conditional move. 275 void Move(FPURegister dst, double imm); 276 void Movz(Register rd, Register rs, Register rt); 277 void Movn(Register rd, Register rs, Register rt); 278 void Movt(Register rd, Register rs, uint16_t cc = 0); 279 void Movf(Register rd, Register rs, uint16_t cc = 0); 280 281 void Clz(Register rd, Register rs); 282 283 // Jump unconditionally to given label. 284 // We NEED a nop in the branch delay slot, as it used by v8, for example in 285 // CodeGenerator::ProcessDeferred(). 286 // Currently the branch delay slot is filled by the MacroAssembler. 287 // Use rather b(Label) for code generation. 288 void jmp(Label* L) { 289 Branch(L); 290 } 291 292 void Load(Register dst, const MemOperand& src, Representation r); 293 void Store(Register src, const MemOperand& dst, Representation r); 294 295 // Load an object from the root table. 296 void LoadRoot(Register destination, 297 Heap::RootListIndex index); 298 void LoadRoot(Register destination, 299 Heap::RootListIndex index, 300 Condition cond, Register src1, const Operand& src2); 301 302 // Store an object to the root table. 303 void StoreRoot(Register source, 304 Heap::RootListIndex index); 305 void StoreRoot(Register source, 306 Heap::RootListIndex index, 307 Condition cond, Register src1, const Operand& src2); 308 309 // --------------------------------------------------------------------------- 310 // GC Support 311 312 void IncrementalMarkingRecordWriteHelper(Register object, 313 Register value, 314 Register address); 315 316 enum RememberedSetFinalAction { 317 kReturnAtEnd, 318 kFallThroughAtEnd 319 }; 320 321 322 // Record in the remembered set the fact that we have a pointer to new space 323 // at the address pointed to by the addr register. Only works if addr is not 324 // in new space. 325 void RememberedSetHelper(Register object, // Used for debug code. 326 Register addr, 327 Register scratch, 328 SaveFPRegsMode save_fp, 329 RememberedSetFinalAction and_then); 330 331 void CheckPageFlag(Register object, 332 Register scratch, 333 int mask, 334 Condition cc, 335 Label* condition_met); 336 337 void CheckMapDeprecated(Handle<Map> map, 338 Register scratch, 339 Label* if_deprecated); 340 341 // Check if object is in new space. Jumps if the object is not in new space. 342 // The register scratch can be object itself, but it will be clobbered. 343 void JumpIfNotInNewSpace(Register object, 344 Register scratch, 345 Label* branch) { 346 InNewSpace(object, scratch, ne, branch); 347 } 348 349 // Check if object is in new space. Jumps if the object is in new space. 350 // The register scratch can be object itself, but scratch will be clobbered. 351 void JumpIfInNewSpace(Register object, 352 Register scratch, 353 Label* branch) { 354 InNewSpace(object, scratch, eq, branch); 355 } 356 357 // Check if an object has a given incremental marking color. 358 void HasColor(Register object, 359 Register scratch0, 360 Register scratch1, 361 Label* has_color, 362 int first_bit, 363 int second_bit); 364 365 void JumpIfBlack(Register object, 366 Register scratch0, 367 Register scratch1, 368 Label* on_black); 369 370 // Checks the color of an object. If the object is already grey or black 371 // then we just fall through, since it is already live. If it is white and 372 // we can determine that it doesn't need to be scanned, then we just mark it 373 // black and fall through. For the rest we jump to the label so the 374 // incremental marker can fix its assumptions. 375 void EnsureNotWhite(Register object, 376 Register scratch1, 377 Register scratch2, 378 Register scratch3, 379 Label* object_is_white_and_not_data); 380 381 // Detects conservatively whether an object is data-only, i.e. it does need to 382 // be scanned by the garbage collector. 383 void JumpIfDataObject(Register value, 384 Register scratch, 385 Label* not_data_object); 386 387 // Notify the garbage collector that we wrote a pointer into an object. 388 // |object| is the object being stored into, |value| is the object being 389 // stored. value and scratch registers are clobbered by the operation. 390 // The offset is the offset from the start of the object, not the offset from 391 // the tagged HeapObject pointer. For use with FieldOperand(reg, off). 392 void RecordWriteField( 393 Register object, 394 int offset, 395 Register value, 396 Register scratch, 397 RAStatus ra_status, 398 SaveFPRegsMode save_fp, 399 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 400 SmiCheck smi_check = INLINE_SMI_CHECK, 401 PointersToHereCheck pointers_to_here_check_for_value = 402 kPointersToHereMaybeInteresting); 403 404 // As above, but the offset has the tag presubtracted. For use with 405 // MemOperand(reg, off). 406 inline void RecordWriteContextSlot( 407 Register context, 408 int offset, 409 Register value, 410 Register scratch, 411 RAStatus ra_status, 412 SaveFPRegsMode save_fp, 413 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 414 SmiCheck smi_check = INLINE_SMI_CHECK, 415 PointersToHereCheck pointers_to_here_check_for_value = 416 kPointersToHereMaybeInteresting) { 417 RecordWriteField(context, 418 offset + kHeapObjectTag, 419 value, 420 scratch, 421 ra_status, 422 save_fp, 423 remembered_set_action, 424 smi_check, 425 pointers_to_here_check_for_value); 426 } 427 428 void RecordWriteForMap( 429 Register object, 430 Register map, 431 Register dst, 432 RAStatus ra_status, 433 SaveFPRegsMode save_fp); 434 435 // For a given |object| notify the garbage collector that the slot |address| 436 // has been written. |value| is the object being stored. The value and 437 // address registers are clobbered by the operation. 438 void RecordWrite( 439 Register object, 440 Register address, 441 Register value, 442 RAStatus ra_status, 443 SaveFPRegsMode save_fp, 444 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 445 SmiCheck smi_check = INLINE_SMI_CHECK, 446 PointersToHereCheck pointers_to_here_check_for_value = 447 kPointersToHereMaybeInteresting); 448 449 450 // --------------------------------------------------------------------------- 451 // Inline caching support. 452 453 // Generate code for checking access rights - used for security checks 454 // on access to global objects across environments. The holder register 455 // is left untouched, whereas both scratch registers are clobbered. 456 void CheckAccessGlobalProxy(Register holder_reg, 457 Register scratch, 458 Label* miss); 459 460 void GetNumberHash(Register reg0, Register scratch); 461 462 void LoadFromNumberDictionary(Label* miss, 463 Register elements, 464 Register key, 465 Register result, 466 Register reg0, 467 Register reg1, 468 Register reg2); 469 470 471 inline void MarkCode(NopMarkerTypes type) { 472 nop(type); 473 } 474 475 // Check if the given instruction is a 'type' marker. 476 // i.e. check if it is a sll zero_reg, zero_reg, <type> (referenced as 477 // nop(type)). These instructions are generated to mark special location in 478 // the code, like some special IC code. 479 static inline bool IsMarkedCode(Instr instr, int type) { 480 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 481 return IsNop(instr, type); 482 } 483 484 485 static inline int GetCodeMarker(Instr instr) { 486 uint32_t opcode = ((instr & kOpcodeMask)); 487 uint32_t rt = ((instr & kRtFieldMask) >> kRtShift); 488 uint32_t rs = ((instr & kRsFieldMask) >> kRsShift); 489 uint32_t sa = ((instr & kSaFieldMask) >> kSaShift); 490 491 // Return <n> if we have a sll zero_reg, zero_reg, n 492 // else return -1. 493 bool sllzz = (opcode == SLL && 494 rt == static_cast<uint32_t>(ToNumber(zero_reg)) && 495 rs == static_cast<uint32_t>(ToNumber(zero_reg))); 496 int type = 497 (sllzz && FIRST_IC_MARKER <= sa && sa < LAST_CODE_MARKER) ? sa : -1; 498 DCHECK((type == -1) || 499 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 500 return type; 501 } 502 503 504 505 // --------------------------------------------------------------------------- 506 // Allocation support. 507 508 // Allocate an object in new space or old pointer space. The object_size is 509 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS 510 // is passed. If the space is exhausted control continues at the gc_required 511 // label. The allocated object is returned in result. If the flag 512 // tag_allocated_object is true the result is tagged as as a heap object. 513 // All registers are clobbered also when control continues at the gc_required 514 // label. 515 void Allocate(int object_size, 516 Register result, 517 Register scratch1, 518 Register scratch2, 519 Label* gc_required, 520 AllocationFlags flags); 521 522 void Allocate(Register object_size, 523 Register result, 524 Register scratch1, 525 Register scratch2, 526 Label* gc_required, 527 AllocationFlags flags); 528 529 // Undo allocation in new space. The object passed and objects allocated after 530 // it will no longer be allocated. The caller must make sure that no pointers 531 // are left to the object(s) no longer allocated as they would be invalid when 532 // allocation is undone. 533 void UndoAllocationInNewSpace(Register object, Register scratch); 534 535 536 void AllocateTwoByteString(Register result, 537 Register length, 538 Register scratch1, 539 Register scratch2, 540 Register scratch3, 541 Label* gc_required); 542 void AllocateOneByteString(Register result, Register length, 543 Register scratch1, Register scratch2, 544 Register scratch3, Label* gc_required); 545 void AllocateTwoByteConsString(Register result, 546 Register length, 547 Register scratch1, 548 Register scratch2, 549 Label* gc_required); 550 void AllocateOneByteConsString(Register result, Register length, 551 Register scratch1, Register scratch2, 552 Label* gc_required); 553 void AllocateTwoByteSlicedString(Register result, 554 Register length, 555 Register scratch1, 556 Register scratch2, 557 Label* gc_required); 558 void AllocateOneByteSlicedString(Register result, Register length, 559 Register scratch1, Register scratch2, 560 Label* gc_required); 561 562 // Allocates a heap number or jumps to the gc_required label if the young 563 // space is full and a scavenge is needed. All registers are clobbered also 564 // when control continues at the gc_required label. 565 void AllocateHeapNumber(Register result, 566 Register scratch1, 567 Register scratch2, 568 Register heap_number_map, 569 Label* gc_required, 570 TaggingMode tagging_mode = TAG_RESULT, 571 MutableMode mode = IMMUTABLE); 572 573 void AllocateHeapNumberWithValue(Register result, 574 FPURegister value, 575 Register scratch1, 576 Register scratch2, 577 Label* gc_required); 578 579 // --------------------------------------------------------------------------- 580 // Instruction macros. 581 582 #define DEFINE_INSTRUCTION(instr) \ 583 void instr(Register rd, Register rs, const Operand& rt); \ 584 void instr(Register rd, Register rs, Register rt) { \ 585 instr(rd, rs, Operand(rt)); \ 586 } \ 587 void instr(Register rs, Register rt, int32_t j) { \ 588 instr(rs, rt, Operand(j)); \ 589 } 590 591 #define DEFINE_INSTRUCTION2(instr) \ 592 void instr(Register rs, const Operand& rt); \ 593 void instr(Register rs, Register rt) { \ 594 instr(rs, Operand(rt)); \ 595 } \ 596 void instr(Register rs, int32_t j) { \ 597 instr(rs, Operand(j)); \ 598 } 599 600 DEFINE_INSTRUCTION(Addu); 601 DEFINE_INSTRUCTION(Daddu); 602 DEFINE_INSTRUCTION(Ddiv); 603 DEFINE_INSTRUCTION(Subu); 604 DEFINE_INSTRUCTION(Dsubu); 605 DEFINE_INSTRUCTION(Dmod); 606 DEFINE_INSTRUCTION(Mul); 607 DEFINE_INSTRUCTION(Mulh); 608 DEFINE_INSTRUCTION(Dmul); 609 DEFINE_INSTRUCTION(Dmulh); 610 DEFINE_INSTRUCTION2(Mult); 611 DEFINE_INSTRUCTION2(Dmult); 612 DEFINE_INSTRUCTION2(Multu); 613 DEFINE_INSTRUCTION2(Dmultu); 614 DEFINE_INSTRUCTION2(Div); 615 DEFINE_INSTRUCTION2(Ddiv); 616 DEFINE_INSTRUCTION2(Divu); 617 DEFINE_INSTRUCTION2(Ddivu); 618 619 DEFINE_INSTRUCTION(And); 620 DEFINE_INSTRUCTION(Or); 621 DEFINE_INSTRUCTION(Xor); 622 DEFINE_INSTRUCTION(Nor); 623 DEFINE_INSTRUCTION2(Neg); 624 625 DEFINE_INSTRUCTION(Slt); 626 DEFINE_INSTRUCTION(Sltu); 627 628 // MIPS32 R2 instruction macro. 629 DEFINE_INSTRUCTION(Ror); 630 DEFINE_INSTRUCTION(Dror); 631 632 #undef DEFINE_INSTRUCTION 633 #undef DEFINE_INSTRUCTION2 634 635 void Pref(int32_t hint, const MemOperand& rs); 636 637 638 // --------------------------------------------------------------------------- 639 // Pseudo-instructions. 640 641 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); } 642 643 void Ulw(Register rd, const MemOperand& rs); 644 void Usw(Register rd, const MemOperand& rs); 645 void Uld(Register rd, const MemOperand& rs, Register scratch = at); 646 void Usd(Register rd, const MemOperand& rs, Register scratch = at); 647 648 // Load int32 in the rd register. 649 void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE); 650 inline void li(Register rd, int64_t j, LiFlags mode = OPTIMIZE_SIZE) { 651 li(rd, Operand(j), mode); 652 } 653 void li(Register dst, Handle<Object> value, LiFlags mode = OPTIMIZE_SIZE); 654 655 // Push multiple registers on the stack. 656 // Registers are saved in numerical order, with higher numbered registers 657 // saved in higher memory addresses. 658 void MultiPush(RegList regs); 659 void MultiPushReversed(RegList regs); 660 661 void MultiPushFPU(RegList regs); 662 void MultiPushReversedFPU(RegList regs); 663 664 void push(Register src) { 665 Daddu(sp, sp, Operand(-kPointerSize)); 666 sd(src, MemOperand(sp, 0)); 667 } 668 void Push(Register src) { push(src); } 669 670 // Push a handle. 671 void Push(Handle<Object> handle); 672 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); } 673 674 // Push two registers. Pushes leftmost register first (to highest address). 675 void Push(Register src1, Register src2) { 676 Dsubu(sp, sp, Operand(2 * kPointerSize)); 677 sd(src1, MemOperand(sp, 1 * kPointerSize)); 678 sd(src2, MemOperand(sp, 0 * kPointerSize)); 679 } 680 681 // Push three registers. Pushes leftmost register first (to highest address). 682 void Push(Register src1, Register src2, Register src3) { 683 Dsubu(sp, sp, Operand(3 * kPointerSize)); 684 sd(src1, MemOperand(sp, 2 * kPointerSize)); 685 sd(src2, MemOperand(sp, 1 * kPointerSize)); 686 sd(src3, MemOperand(sp, 0 * kPointerSize)); 687 } 688 689 // Push four registers. Pushes leftmost register first (to highest address). 690 void Push(Register src1, Register src2, Register src3, Register src4) { 691 Dsubu(sp, sp, Operand(4 * kPointerSize)); 692 sd(src1, MemOperand(sp, 3 * kPointerSize)); 693 sd(src2, MemOperand(sp, 2 * kPointerSize)); 694 sd(src3, MemOperand(sp, 1 * kPointerSize)); 695 sd(src4, MemOperand(sp, 0 * kPointerSize)); 696 } 697 698 void Push(Register src, Condition cond, Register tst1, Register tst2) { 699 // Since we don't have conditional execution we use a Branch. 700 Branch(3, cond, tst1, Operand(tst2)); 701 Dsubu(sp, sp, Operand(kPointerSize)); 702 sd(src, MemOperand(sp, 0)); 703 } 704 705 void PushRegisterAsTwoSmis(Register src, Register scratch = at); 706 void PopRegisterAsTwoSmis(Register dst, Register scratch = at); 707 708 // Pops multiple values from the stack and load them in the 709 // registers specified in regs. Pop order is the opposite as in MultiPush. 710 void MultiPop(RegList regs); 711 void MultiPopReversed(RegList regs); 712 713 void MultiPopFPU(RegList regs); 714 void MultiPopReversedFPU(RegList regs); 715 716 void pop(Register dst) { 717 ld(dst, MemOperand(sp, 0)); 718 Daddu(sp, sp, Operand(kPointerSize)); 719 } 720 void Pop(Register dst) { pop(dst); } 721 722 // Pop two registers. Pops rightmost register first (from lower address). 723 void Pop(Register src1, Register src2) { 724 DCHECK(!src1.is(src2)); 725 ld(src2, MemOperand(sp, 0 * kPointerSize)); 726 ld(src1, MemOperand(sp, 1 * kPointerSize)); 727 Daddu(sp, sp, 2 * kPointerSize); 728 } 729 730 // Pop three registers. Pops rightmost register first (from lower address). 731 void Pop(Register src1, Register src2, Register src3) { 732 ld(src3, MemOperand(sp, 0 * kPointerSize)); 733 ld(src2, MemOperand(sp, 1 * kPointerSize)); 734 ld(src1, MemOperand(sp, 2 * kPointerSize)); 735 Daddu(sp, sp, 3 * kPointerSize); 736 } 737 738 void Pop(uint32_t count = 1) { 739 Daddu(sp, sp, Operand(count * kPointerSize)); 740 } 741 742 // Push and pop the registers that can hold pointers, as defined by the 743 // RegList constant kSafepointSavedRegisters. 744 void PushSafepointRegisters(); 745 void PopSafepointRegisters(); 746 // Store value in register src in the safepoint stack slot for 747 // register dst. 748 void StoreToSafepointRegisterSlot(Register src, Register dst); 749 // Load the value of the src register from its safepoint stack slot 750 // into register dst. 751 void LoadFromSafepointRegisterSlot(Register dst, Register src); 752 753 // Flush the I-cache from asm code. You should use CpuFeatures::FlushICache 754 // from C. 755 // Does not handle errors. 756 void FlushICache(Register address, unsigned instructions); 757 758 // MIPS64 R2 instruction macro. 759 void Ins(Register rt, Register rs, uint16_t pos, uint16_t size); 760 void Ext(Register rt, Register rs, uint16_t pos, uint16_t size); 761 762 // --------------------------------------------------------------------------- 763 // FPU macros. These do not handle special cases like NaN or +- inf. 764 765 // Convert unsigned word to double. 766 void Cvt_d_uw(FPURegister fd, FPURegister fs, FPURegister scratch); 767 void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch); 768 769 // Convert double to unsigned long. 770 void Trunc_l_ud(FPURegister fd, FPURegister fs, FPURegister scratch); 771 772 void Trunc_l_d(FPURegister fd, FPURegister fs); 773 void Round_l_d(FPURegister fd, FPURegister fs); 774 void Floor_l_d(FPURegister fd, FPURegister fs); 775 void Ceil_l_d(FPURegister fd, FPURegister fs); 776 777 // Convert double to unsigned word. 778 void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch); 779 void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch); 780 781 void Trunc_w_d(FPURegister fd, FPURegister fs); 782 void Round_w_d(FPURegister fd, FPURegister fs); 783 void Floor_w_d(FPURegister fd, FPURegister fs); 784 void Ceil_w_d(FPURegister fd, FPURegister fs); 785 786 void Madd_d(FPURegister fd, 787 FPURegister fr, 788 FPURegister fs, 789 FPURegister ft, 790 FPURegister scratch); 791 792 // Wrapper function for the different cmp/branch types. 793 void BranchF(Label* target, 794 Label* nan, 795 Condition cc, 796 FPURegister cmp1, 797 FPURegister cmp2, 798 BranchDelaySlot bd = PROTECT); 799 800 // Alternate (inline) version for better readability with USE_DELAY_SLOT. 801 inline void BranchF(BranchDelaySlot bd, 802 Label* target, 803 Label* nan, 804 Condition cc, 805 FPURegister cmp1, 806 FPURegister cmp2) { 807 BranchF(target, nan, cc, cmp1, cmp2, bd); 808 } 809 810 // Truncates a double using a specific rounding mode, and writes the value 811 // to the result register. 812 // The except_flag will contain any exceptions caused by the instruction. 813 // If check_inexact is kDontCheckForInexactConversion, then the inexact 814 // exception is masked. 815 void EmitFPUTruncate(FPURoundingMode rounding_mode, 816 Register result, 817 DoubleRegister double_input, 818 Register scratch, 819 DoubleRegister double_scratch, 820 Register except_flag, 821 CheckForInexactConversion check_inexact 822 = kDontCheckForInexactConversion); 823 824 // Performs a truncating conversion of a floating point number as used by 825 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it 826 // succeeds, otherwise falls through if result is saturated. On return 827 // 'result' either holds answer, or is clobbered on fall through. 828 // 829 // Only public for the test code in test-code-stubs-arm.cc. 830 void TryInlineTruncateDoubleToI(Register result, 831 DoubleRegister input, 832 Label* done); 833 834 // Performs a truncating conversion of a floating point number as used by 835 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 836 // Exits with 'result' holding the answer. 837 void TruncateDoubleToI(Register result, DoubleRegister double_input); 838 839 // Performs a truncating conversion of a heap number as used by 840 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' 841 // must be different registers. Exits with 'result' holding the answer. 842 void TruncateHeapNumberToI(Register result, Register object); 843 844 // Converts the smi or heap number in object to an int32 using the rules 845 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 846 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be 847 // different registers. 848 void TruncateNumberToI(Register object, 849 Register result, 850 Register heap_number_map, 851 Register scratch, 852 Label* not_int32); 853 854 // Loads the number from object into dst register. 855 // If |object| is neither smi nor heap number, |not_number| is jumped to 856 // with |object| still intact. 857 void LoadNumber(Register object, 858 FPURegister dst, 859 Register heap_number_map, 860 Register scratch, 861 Label* not_number); 862 863 // Loads the number from object into double_dst in the double format. 864 // Control will jump to not_int32 if the value cannot be exactly represented 865 // by a 32-bit integer. 866 // Floating point value in the 32-bit integer range that are not exact integer 867 // won't be loaded. 868 void LoadNumberAsInt32Double(Register object, 869 DoubleRegister double_dst, 870 Register heap_number_map, 871 Register scratch1, 872 Register scratch2, 873 FPURegister double_scratch, 874 Label* not_int32); 875 876 // Loads the number from object into dst as a 32-bit integer. 877 // Control will jump to not_int32 if the object cannot be exactly represented 878 // by a 32-bit integer. 879 // Floating point value in the 32-bit integer range that are not exact integer 880 // won't be converted. 881 void LoadNumberAsInt32(Register object, 882 Register dst, 883 Register heap_number_map, 884 Register scratch1, 885 Register scratch2, 886 FPURegister double_scratch0, 887 FPURegister double_scratch1, 888 Label* not_int32); 889 890 // Enter exit frame. 891 // argc - argument count to be dropped by LeaveExitFrame. 892 // save_doubles - saves FPU registers on stack, currently disabled. 893 // stack_space - extra stack space. 894 void EnterExitFrame(bool save_doubles, 895 int stack_space = 0); 896 897 // Leave the current exit frame. 898 void LeaveExitFrame(bool save_doubles, 899 Register arg_count, 900 bool restore_context, 901 bool do_return = NO_EMIT_RETURN); 902 903 // Get the actual activation frame alignment for target environment. 904 static int ActivationFrameAlignment(); 905 906 // Make sure the stack is aligned. Only emits code in debug mode. 907 void AssertStackIsAligned(); 908 909 void LoadContext(Register dst, int context_chain_length); 910 911 // Conditionally load the cached Array transitioned map of type 912 // transitioned_kind from the native context if the map in register 913 // map_in_out is the cached Array map in the native context of 914 // expected_kind. 915 void LoadTransitionedArrayMapConditional( 916 ElementsKind expected_kind, 917 ElementsKind transitioned_kind, 918 Register map_in_out, 919 Register scratch, 920 Label* no_map_match); 921 922 void LoadGlobalFunction(int index, Register function); 923 924 // Load the initial map from the global function. The registers 925 // function and map can be the same, function is then overwritten. 926 void LoadGlobalFunctionInitialMap(Register function, 927 Register map, 928 Register scratch); 929 930 void InitializeRootRegister() { 931 ExternalReference roots_array_start = 932 ExternalReference::roots_array_start(isolate()); 933 li(kRootRegister, Operand(roots_array_start)); 934 } 935 936 // ------------------------------------------------------------------------- 937 // JavaScript invokes. 938 939 // Invoke the JavaScript function code by either calling or jumping. 940 void InvokeCode(Register code, 941 const ParameterCount& expected, 942 const ParameterCount& actual, 943 InvokeFlag flag, 944 const CallWrapper& call_wrapper); 945 946 // Invoke the JavaScript function in the given register. Changes the 947 // current context to the context in the function before invoking. 948 void InvokeFunction(Register function, 949 const ParameterCount& actual, 950 InvokeFlag flag, 951 const CallWrapper& call_wrapper); 952 953 void InvokeFunction(Register function, 954 const ParameterCount& expected, 955 const ParameterCount& actual, 956 InvokeFlag flag, 957 const CallWrapper& call_wrapper); 958 959 void InvokeFunction(Handle<JSFunction> function, 960 const ParameterCount& expected, 961 const ParameterCount& actual, 962 InvokeFlag flag, 963 const CallWrapper& call_wrapper); 964 965 966 void IsObjectJSObjectType(Register heap_object, 967 Register map, 968 Register scratch, 969 Label* fail); 970 971 void IsInstanceJSObjectType(Register map, 972 Register scratch, 973 Label* fail); 974 975 void IsObjectJSStringType(Register object, 976 Register scratch, 977 Label* fail); 978 979 void IsObjectNameType(Register object, 980 Register scratch, 981 Label* fail); 982 983 // ------------------------------------------------------------------------- 984 // Debugger Support. 985 986 void DebugBreak(); 987 988 // ------------------------------------------------------------------------- 989 // Exception handling. 990 991 // Push a new try handler and link into try handler chain. 992 void PushTryHandler(StackHandler::Kind kind, int handler_index); 993 994 // Unlink the stack handler on top of the stack from the try handler chain. 995 // Must preserve the result register. 996 void PopTryHandler(); 997 998 // Passes thrown value to the handler of top of the try handler chain. 999 void Throw(Register value); 1000 1001 // Propagates an uncatchable exception to the top of the current JS stack's 1002 // handler chain. 1003 void ThrowUncatchable(Register value); 1004 1005 // Copies a fixed number of fields of heap objects from src to dst. 1006 void CopyFields(Register dst, Register src, RegList temps, int field_count); 1007 1008 // Copies a number of bytes from src to dst. All registers are clobbered. On 1009 // exit src and dst will point to the place just after where the last byte was 1010 // read or written and length will be zero. 1011 void CopyBytes(Register src, 1012 Register dst, 1013 Register length, 1014 Register scratch); 1015 1016 // Initialize fields with filler values. Fields starting at |start_offset| 1017 // not including end_offset are overwritten with the value in |filler|. At 1018 // the end the loop, |start_offset| takes the value of |end_offset|. 1019 void InitializeFieldsWithFiller(Register start_offset, 1020 Register end_offset, 1021 Register filler); 1022 1023 // ------------------------------------------------------------------------- 1024 // Support functions. 1025 1026 // Try to get function prototype of a function and puts the value in 1027 // the result register. Checks that the function really is a 1028 // function and jumps to the miss label if the fast checks fail. The 1029 // function register will be untouched; the other registers may be 1030 // clobbered. 1031 void TryGetFunctionPrototype(Register function, 1032 Register result, 1033 Register scratch, 1034 Label* miss, 1035 bool miss_on_bound_function = false); 1036 1037 void GetObjectType(Register function, 1038 Register map, 1039 Register type_reg); 1040 1041 // Check if a map for a JSObject indicates that the object has fast elements. 1042 // Jump to the specified label if it does not. 1043 void CheckFastElements(Register map, 1044 Register scratch, 1045 Label* fail); 1046 1047 // Check if a map for a JSObject indicates that the object can have both smi 1048 // and HeapObject elements. Jump to the specified label if it does not. 1049 void CheckFastObjectElements(Register map, 1050 Register scratch, 1051 Label* fail); 1052 1053 // Check if a map for a JSObject indicates that the object has fast smi only 1054 // elements. Jump to the specified label if it does not. 1055 void CheckFastSmiElements(Register map, 1056 Register scratch, 1057 Label* fail); 1058 1059 // Check to see if maybe_number can be stored as a double in 1060 // FastDoubleElements. If it can, store it at the index specified by key in 1061 // the FastDoubleElements array elements. Otherwise jump to fail. 1062 void StoreNumberToDoubleElements(Register value_reg, 1063 Register key_reg, 1064 Register elements_reg, 1065 Register scratch1, 1066 Register scratch2, 1067 Register scratch3, 1068 Label* fail, 1069 int elements_offset = 0); 1070 1071 // Compare an object's map with the specified map and its transitioned 1072 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to 1073 // "branch_to" if the result of the comparison is "cond". If multiple map 1074 // compares are required, the compare sequences branches to early_success. 1075 void CompareMapAndBranch(Register obj, 1076 Register scratch, 1077 Handle<Map> map, 1078 Label* early_success, 1079 Condition cond, 1080 Label* branch_to); 1081 1082 // As above, but the map of the object is already loaded into the register 1083 // which is preserved by the code generated. 1084 void CompareMapAndBranch(Register obj_map, 1085 Handle<Map> map, 1086 Label* early_success, 1087 Condition cond, 1088 Label* branch_to); 1089 1090 // Check if the map of an object is equal to a specified map and branch to 1091 // label if not. Skip the smi check if not required (object is known to be a 1092 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 1093 // against maps that are ElementsKind transition maps of the specificed map. 1094 void CheckMap(Register obj, 1095 Register scratch, 1096 Handle<Map> map, 1097 Label* fail, 1098 SmiCheckType smi_check_type); 1099 1100 1101 void CheckMap(Register obj, 1102 Register scratch, 1103 Heap::RootListIndex index, 1104 Label* fail, 1105 SmiCheckType smi_check_type); 1106 1107 // Check if the map of an object is equal to a specified map and branch to a 1108 // specified target if equal. Skip the smi check if not required (object is 1109 // known to be a heap object) 1110 void DispatchMap(Register obj, 1111 Register scratch, 1112 Handle<Map> map, 1113 Handle<Code> success, 1114 SmiCheckType smi_check_type); 1115 1116 1117 // Load and check the instance type of an object for being a string. 1118 // Loads the type into the second argument register. 1119 // Returns a condition that will be enabled if the object was a string. 1120 Condition IsObjectStringType(Register obj, 1121 Register type, 1122 Register result) { 1123 ld(type, FieldMemOperand(obj, HeapObject::kMapOffset)); 1124 lbu(type, FieldMemOperand(type, Map::kInstanceTypeOffset)); 1125 And(type, type, Operand(kIsNotStringMask)); 1126 DCHECK_EQ(0, kStringTag); 1127 return eq; 1128 } 1129 1130 1131 // Picks out an array index from the hash field. 1132 // Register use: 1133 // hash - holds the index's hash. Clobbered. 1134 // index - holds the overwritten index on exit. 1135 void IndexFromHash(Register hash, Register index); 1136 1137 // Get the number of least significant bits from a register. 1138 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 1139 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 1140 1141 // Load the value of a number object into a FPU double register. If the 1142 // object is not a number a jump to the label not_number is performed 1143 // and the FPU double register is unchanged. 1144 void ObjectToDoubleFPURegister( 1145 Register object, 1146 FPURegister value, 1147 Register scratch1, 1148 Register scratch2, 1149 Register heap_number_map, 1150 Label* not_number, 1151 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS); 1152 1153 // Load the value of a smi object into a FPU double register. The register 1154 // scratch1 can be the same register as smi in which case smi will hold the 1155 // untagged value afterwards. 1156 void SmiToDoubleFPURegister(Register smi, 1157 FPURegister value, 1158 Register scratch1); 1159 1160 // ------------------------------------------------------------------------- 1161 // Overflow handling functions. 1162 // Usage: first call the appropriate arithmetic function, then call one of the 1163 // jump functions with the overflow_dst register as the second parameter. 1164 1165 void AdduAndCheckForOverflow(Register dst, 1166 Register left, 1167 Register right, 1168 Register overflow_dst, 1169 Register scratch = at); 1170 1171 void SubuAndCheckForOverflow(Register dst, 1172 Register left, 1173 Register right, 1174 Register overflow_dst, 1175 Register scratch = at); 1176 1177 void BranchOnOverflow(Label* label, 1178 Register overflow_check, 1179 BranchDelaySlot bd = PROTECT) { 1180 Branch(label, lt, overflow_check, Operand(zero_reg), bd); 1181 } 1182 1183 void BranchOnNoOverflow(Label* label, 1184 Register overflow_check, 1185 BranchDelaySlot bd = PROTECT) { 1186 Branch(label, ge, overflow_check, Operand(zero_reg), bd); 1187 } 1188 1189 void RetOnOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) { 1190 Ret(lt, overflow_check, Operand(zero_reg), bd); 1191 } 1192 1193 void RetOnNoOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) { 1194 Ret(ge, overflow_check, Operand(zero_reg), bd); 1195 } 1196 1197 // ------------------------------------------------------------------------- 1198 // Runtime calls. 1199 1200 // See comments at the beginning of CEntryStub::Generate. 1201 inline void PrepareCEntryArgs(int num_args) { 1202 li(s0, num_args); 1203 li(s1, (num_args - 1) * kPointerSize); 1204 } 1205 1206 inline void PrepareCEntryFunction(const ExternalReference& ref) { 1207 li(s2, Operand(ref)); 1208 } 1209 1210 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \ 1211 const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT 1212 1213 // Call a code stub. 1214 void CallStub(CodeStub* stub, 1215 TypeFeedbackId ast_id = TypeFeedbackId::None(), 1216 COND_ARGS); 1217 1218 // Tail call a code stub (jump). 1219 void TailCallStub(CodeStub* stub, COND_ARGS); 1220 1221 #undef COND_ARGS 1222 1223 void CallJSExitStub(CodeStub* stub); 1224 1225 // Call a runtime routine. 1226 void CallRuntime(const Runtime::Function* f, 1227 int num_arguments, 1228 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 1229 void CallRuntimeSaveDoubles(Runtime::FunctionId id) { 1230 const Runtime::Function* function = Runtime::FunctionForId(id); 1231 CallRuntime(function, function->nargs, kSaveFPRegs); 1232 } 1233 1234 // Convenience function: Same as above, but takes the fid instead. 1235 void CallRuntime(Runtime::FunctionId id, 1236 int num_arguments, 1237 SaveFPRegsMode save_doubles = kDontSaveFPRegs) { 1238 CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles); 1239 } 1240 1241 // Convenience function: call an external reference. 1242 void CallExternalReference(const ExternalReference& ext, 1243 int num_arguments, 1244 BranchDelaySlot bd = PROTECT); 1245 1246 // Tail call of a runtime routine (jump). 1247 // Like JumpToExternalReference, but also takes care of passing the number 1248 // of parameters. 1249 void TailCallExternalReference(const ExternalReference& ext, 1250 int num_arguments, 1251 int result_size); 1252 1253 // Convenience function: tail call a runtime routine (jump). 1254 void TailCallRuntime(Runtime::FunctionId fid, 1255 int num_arguments, 1256 int result_size); 1257 1258 int CalculateStackPassedWords(int num_reg_arguments, 1259 int num_double_arguments); 1260 1261 // Before calling a C-function from generated code, align arguments on stack 1262 // and add space for the four mips argument slots. 1263 // After aligning the frame, non-register arguments must be stored on the 1264 // stack, after the argument-slots using helper: CFunctionArgumentOperand(). 1265 // The argument count assumes all arguments are word sized. 1266 // Some compilers/platforms require the stack to be aligned when calling 1267 // C++ code. 1268 // Needs a scratch register to do some arithmetic. This register will be 1269 // trashed. 1270 void PrepareCallCFunction(int num_reg_arguments, 1271 int num_double_registers, 1272 Register scratch); 1273 void PrepareCallCFunction(int num_reg_arguments, 1274 Register scratch); 1275 1276 // Arguments 1-4 are placed in registers a0 thru a3 respectively. 1277 // Arguments 5..n are stored to stack using following: 1278 // sw(a4, CFunctionArgumentOperand(5)); 1279 1280 // Calls a C function and cleans up the space for arguments allocated 1281 // by PrepareCallCFunction. The called function is not allowed to trigger a 1282 // garbage collection, since that might move the code and invalidate the 1283 // return address (unless this is somehow accounted for by the called 1284 // function). 1285 void CallCFunction(ExternalReference function, int num_arguments); 1286 void CallCFunction(Register function, int num_arguments); 1287 void CallCFunction(ExternalReference function, 1288 int num_reg_arguments, 1289 int num_double_arguments); 1290 void CallCFunction(Register function, 1291 int num_reg_arguments, 1292 int num_double_arguments); 1293 void MovFromFloatResult(DoubleRegister dst); 1294 void MovFromFloatParameter(DoubleRegister dst); 1295 1296 // There are two ways of passing double arguments on MIPS, depending on 1297 // whether soft or hard floating point ABI is used. These functions 1298 // abstract parameter passing for the three different ways we call 1299 // C functions from generated code. 1300 void MovToFloatParameter(DoubleRegister src); 1301 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2); 1302 void MovToFloatResult(DoubleRegister src); 1303 1304 // Calls an API function. Allocates HandleScope, extracts returned value 1305 // from handle and propagates exceptions. Restores context. stack_space 1306 // - space to be unwound on exit (includes the call JS arguments space and 1307 // the additional space allocated for the fast call). 1308 void CallApiFunctionAndReturn(Register function_address, 1309 ExternalReference thunk_ref, 1310 int stack_space, 1311 MemOperand return_value_operand, 1312 MemOperand* context_restore_operand); 1313 1314 // Jump to the builtin routine. 1315 void JumpToExternalReference(const ExternalReference& builtin, 1316 BranchDelaySlot bd = PROTECT); 1317 1318 // Invoke specified builtin JavaScript function. Adds an entry to 1319 // the unresolved list if the name does not resolve. 1320 void InvokeBuiltin(Builtins::JavaScript id, 1321 InvokeFlag flag, 1322 const CallWrapper& call_wrapper = NullCallWrapper()); 1323 1324 // Store the code object for the given builtin in the target register and 1325 // setup the function in a1. 1326 void GetBuiltinEntry(Register target, Builtins::JavaScript id); 1327 1328 // Store the function for the given builtin in the target register. 1329 void GetBuiltinFunction(Register target, Builtins::JavaScript id); 1330 1331 struct Unresolved { 1332 int pc; 1333 uint32_t flags; // See Bootstrapper::FixupFlags decoders/encoders. 1334 const char* name; 1335 }; 1336 1337 Handle<Object> CodeObject() { 1338 DCHECK(!code_object_.is_null()); 1339 return code_object_; 1340 } 1341 1342 // Emit code for a truncating division by a constant. The dividend register is 1343 // unchanged and at gets clobbered. Dividend and result must be different. 1344 void TruncatingDiv(Register result, Register dividend, int32_t divisor); 1345 1346 // ------------------------------------------------------------------------- 1347 // StatsCounter support. 1348 1349 void SetCounter(StatsCounter* counter, int value, 1350 Register scratch1, Register scratch2); 1351 void IncrementCounter(StatsCounter* counter, int value, 1352 Register scratch1, Register scratch2); 1353 void DecrementCounter(StatsCounter* counter, int value, 1354 Register scratch1, Register scratch2); 1355 1356 1357 // ------------------------------------------------------------------------- 1358 // Debugging. 1359 1360 // Calls Abort(msg) if the condition cc is not satisfied. 1361 // Use --debug_code to enable. 1362 void Assert(Condition cc, BailoutReason reason, Register rs, Operand rt); 1363 void AssertFastElements(Register elements); 1364 1365 // Like Assert(), but always enabled. 1366 void Check(Condition cc, BailoutReason reason, Register rs, Operand rt); 1367 1368 // Print a message to stdout and abort execution. 1369 void Abort(BailoutReason msg); 1370 1371 // Verify restrictions about code generated in stubs. 1372 void set_generating_stub(bool value) { generating_stub_ = value; } 1373 bool generating_stub() { return generating_stub_; } 1374 void set_has_frame(bool value) { has_frame_ = value; } 1375 bool has_frame() { return has_frame_; } 1376 inline bool AllowThisStubCall(CodeStub* stub); 1377 1378 // --------------------------------------------------------------------------- 1379 // Number utilities. 1380 1381 // Check whether the value of reg is a power of two and not zero. If not 1382 // control continues at the label not_power_of_two. If reg is a power of two 1383 // the register scratch contains the value of (reg - 1) when control falls 1384 // through. 1385 void JumpIfNotPowerOfTwoOrZero(Register reg, 1386 Register scratch, 1387 Label* not_power_of_two_or_zero); 1388 1389 // ------------------------------------------------------------------------- 1390 // Smi utilities. 1391 1392 // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow(). 1393 void SmiTagCheckOverflow(Register reg, Register overflow); 1394 void SmiTagCheckOverflow(Register dst, Register src, Register overflow); 1395 1396 void SmiTag(Register dst, Register src) { 1397 STATIC_ASSERT(kSmiTag == 0); 1398 if (SmiValuesAre32Bits()) { 1399 STATIC_ASSERT(kSmiShift == 32); 1400 dsll32(dst, src, 0); 1401 } else { 1402 Addu(dst, src, src); 1403 } 1404 } 1405 1406 void SmiTag(Register reg) { 1407 SmiTag(reg, reg); 1408 } 1409 1410 // Try to convert int32 to smi. If the value is to large, preserve 1411 // the original value and jump to not_a_smi. Destroys scratch and 1412 // sets flags. 1413 void TrySmiTag(Register reg, Register scratch, Label* not_a_smi) { 1414 TrySmiTag(reg, reg, scratch, not_a_smi); 1415 } 1416 1417 void TrySmiTag(Register dst, 1418 Register src, 1419 Register scratch, 1420 Label* not_a_smi) { 1421 if (SmiValuesAre32Bits()) { 1422 SmiTag(dst, src); 1423 } else { 1424 SmiTagCheckOverflow(at, src, scratch); 1425 BranchOnOverflow(not_a_smi, scratch); 1426 mov(dst, at); 1427 } 1428 } 1429 1430 void SmiUntag(Register dst, Register src) { 1431 if (SmiValuesAre32Bits()) { 1432 STATIC_ASSERT(kSmiShift == 32); 1433 dsra32(dst, src, 0); 1434 } else { 1435 sra(dst, src, kSmiTagSize); 1436 } 1437 } 1438 1439 void SmiUntag(Register reg) { 1440 SmiUntag(reg, reg); 1441 } 1442 1443 // Left-shifted from int32 equivalent of Smi. 1444 void SmiScale(Register dst, Register src, int scale) { 1445 if (SmiValuesAre32Bits()) { 1446 // The int portion is upper 32-bits of 64-bit word. 1447 dsra(dst, src, kSmiShift - scale); 1448 } else { 1449 DCHECK(scale >= kSmiTagSize); 1450 sll(dst, src, scale - kSmiTagSize); 1451 } 1452 } 1453 1454 // Combine load with untagging or scaling. 1455 void SmiLoadUntag(Register dst, MemOperand src); 1456 1457 void SmiLoadScale(Register dst, MemOperand src, int scale); 1458 1459 // Returns 2 values: the Smi and a scaled version of the int within the Smi. 1460 void SmiLoadWithScale(Register d_smi, 1461 Register d_scaled, 1462 MemOperand src, 1463 int scale); 1464 1465 // Returns 2 values: the untagged Smi (int32) and scaled version of that int. 1466 void SmiLoadUntagWithScale(Register d_int, 1467 Register d_scaled, 1468 MemOperand src, 1469 int scale); 1470 1471 1472 // Test if the register contains a smi. 1473 inline void SmiTst(Register value, Register scratch) { 1474 And(scratch, value, Operand(kSmiTagMask)); 1475 } 1476 inline void NonNegativeSmiTst(Register value, Register scratch) { 1477 And(scratch, value, Operand(kSmiTagMask | kSmiSignMask)); 1478 } 1479 1480 // Untag the source value into destination and jump if source is a smi. 1481 // Source and destination can be the same register. 1482 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1483 1484 // Untag the source value into destination and jump if source is not a smi. 1485 // Source and destination can be the same register. 1486 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); 1487 1488 // Jump the register contains a smi. 1489 void JumpIfSmi(Register value, 1490 Label* smi_label, 1491 Register scratch = at, 1492 BranchDelaySlot bd = PROTECT); 1493 1494 // Jump if the register contains a non-smi. 1495 void JumpIfNotSmi(Register value, 1496 Label* not_smi_label, 1497 Register scratch = at, 1498 BranchDelaySlot bd = PROTECT); 1499 1500 // Jump if either of the registers contain a non-smi. 1501 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1502 // Jump if either of the registers contain a smi. 1503 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1504 1505 // Abort execution if argument is a smi, enabled via --debug-code. 1506 void AssertNotSmi(Register object); 1507 void AssertSmi(Register object); 1508 1509 // Abort execution if argument is not a string, enabled via --debug-code. 1510 void AssertString(Register object); 1511 1512 // Abort execution if argument is not a name, enabled via --debug-code. 1513 void AssertName(Register object); 1514 1515 // Abort execution if argument is not undefined or an AllocationSite, enabled 1516 // via --debug-code. 1517 void AssertUndefinedOrAllocationSite(Register object, Register scratch); 1518 1519 // Abort execution if reg is not the root value with the given index, 1520 // enabled via --debug-code. 1521 void AssertIsRoot(Register reg, Heap::RootListIndex index); 1522 1523 // --------------------------------------------------------------------------- 1524 // HeapNumber utilities. 1525 1526 void JumpIfNotHeapNumber(Register object, 1527 Register heap_number_map, 1528 Register scratch, 1529 Label* on_not_heap_number); 1530 1531 // ------------------------------------------------------------------------- 1532 // String utilities. 1533 1534 // Generate code to do a lookup in the number string cache. If the number in 1535 // the register object is found in the cache the generated code falls through 1536 // with the result in the result register. The object and the result register 1537 // can be the same. If the number is not found in the cache the code jumps to 1538 // the label not_found with only the content of register object unchanged. 1539 void LookupNumberStringCache(Register object, 1540 Register result, 1541 Register scratch1, 1542 Register scratch2, 1543 Register scratch3, 1544 Label* not_found); 1545 1546 // Checks if both instance types are sequential one-byte strings and jumps to 1547 // label if either is not. 1548 void JumpIfBothInstanceTypesAreNotSequentialOneByte( 1549 Register first_object_instance_type, Register second_object_instance_type, 1550 Register scratch1, Register scratch2, Label* failure); 1551 1552 // Check if instance type is sequential one-byte string and jump to label if 1553 // it is not. 1554 void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch, 1555 Label* failure); 1556 1557 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name); 1558 1559 void EmitSeqStringSetCharCheck(Register string, 1560 Register index, 1561 Register value, 1562 Register scratch, 1563 uint32_t encoding_mask); 1564 1565 // Checks if both objects are sequential one-byte strings and jumps to label 1566 // if either is not. Assumes that neither object is a smi. 1567 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register first, 1568 Register second, 1569 Register scratch1, 1570 Register scratch2, 1571 Label* failure); 1572 1573 // Checks if both objects are sequential one-byte strings and jumps to label 1574 // if either is not. 1575 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second, 1576 Register scratch1, 1577 Register scratch2, 1578 Label* not_flat_one_byte_strings); 1579 1580 void ClampUint8(Register output_reg, Register input_reg); 1581 1582 void ClampDoubleToUint8(Register result_reg, 1583 DoubleRegister input_reg, 1584 DoubleRegister temp_double_reg); 1585 1586 1587 void LoadInstanceDescriptors(Register map, Register descriptors); 1588 void EnumLength(Register dst, Register map); 1589 void NumberOfOwnDescriptors(Register dst, Register map); 1590 1591 template<typename Field> 1592 void DecodeField(Register dst, Register src) { 1593 Ext(dst, src, Field::kShift, Field::kSize); 1594 } 1595 1596 template<typename Field> 1597 void DecodeField(Register reg) { 1598 DecodeField<Field>(reg, reg); 1599 } 1600 1601 template<typename Field> 1602 void DecodeFieldToSmi(Register dst, Register src) { 1603 static const int shift = Field::kShift; 1604 static const int mask = Field::kMask >> shift; 1605 dsrl(dst, src, shift); 1606 And(dst, dst, Operand(mask)); 1607 dsll32(dst, dst, 0); 1608 } 1609 1610 template<typename Field> 1611 void DecodeFieldToSmi(Register reg) { 1612 DecodeField<Field>(reg, reg); 1613 } 1614 // Generates function and stub prologue code. 1615 void StubPrologue(); 1616 void Prologue(bool code_pre_aging); 1617 1618 // Activation support. 1619 void EnterFrame(StackFrame::Type type); 1620 void LeaveFrame(StackFrame::Type type); 1621 1622 // Patch the relocated value (lui/ori pair). 1623 void PatchRelocatedValue(Register li_location, 1624 Register scratch, 1625 Register new_value); 1626 // Get the relocatad value (loaded data) from the lui/ori pair. 1627 void GetRelocatedValue(Register li_location, 1628 Register value, 1629 Register scratch); 1630 1631 // Expects object in a0 and returns map with validated enum cache 1632 // in a0. Assumes that any other register can be used as a scratch. 1633 void CheckEnumCache(Register null_value, Label* call_runtime); 1634 1635 // AllocationMemento support. Arrays may have an associated 1636 // AllocationMemento object that can be checked for in order to pretransition 1637 // to another type. 1638 // On entry, receiver_reg should point to the array object. 1639 // scratch_reg gets clobbered. 1640 // If allocation info is present, jump to allocation_memento_present. 1641 void TestJSArrayForAllocationMemento( 1642 Register receiver_reg, 1643 Register scratch_reg, 1644 Label* no_memento_found, 1645 Condition cond = al, 1646 Label* allocation_memento_present = NULL); 1647 1648 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg, 1649 Register scratch_reg, 1650 Label* memento_found) { 1651 Label no_memento_found; 1652 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg, 1653 &no_memento_found, eq, memento_found); 1654 bind(&no_memento_found); 1655 } 1656 1657 // Jumps to found label if a prototype map has dictionary elements. 1658 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0, 1659 Register scratch1, Label* found); 1660 1661 private: 1662 void CallCFunctionHelper(Register function, 1663 int num_reg_arguments, 1664 int num_double_arguments); 1665 1666 void BranchAndLinkShort(int16_t offset, BranchDelaySlot bdslot = PROTECT); 1667 void BranchAndLinkShort(int16_t offset, Condition cond, Register rs, 1668 const Operand& rt, 1669 BranchDelaySlot bdslot = PROTECT); 1670 void BranchAndLinkShort(Label* L, BranchDelaySlot bdslot = PROTECT); 1671 void BranchAndLinkShort(Label* L, Condition cond, Register rs, 1672 const Operand& rt, 1673 BranchDelaySlot bdslot = PROTECT); 1674 void J(Label* L, BranchDelaySlot bdslot); 1675 void Jr(Label* L, BranchDelaySlot bdslot); 1676 void Jalr(Label* L, BranchDelaySlot bdslot); 1677 1678 // Helper functions for generating invokes. 1679 void InvokePrologue(const ParameterCount& expected, 1680 const ParameterCount& actual, 1681 Handle<Code> code_constant, 1682 Register code_reg, 1683 Label* done, 1684 bool* definitely_mismatches, 1685 InvokeFlag flag, 1686 const CallWrapper& call_wrapper); 1687 1688 // Get the code for the given builtin. Returns if able to resolve 1689 // the function in the 'resolved' flag. 1690 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved); 1691 1692 void InitializeNewString(Register string, 1693 Register length, 1694 Heap::RootListIndex map_index, 1695 Register scratch1, 1696 Register scratch2); 1697 1698 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1699 void InNewSpace(Register object, 1700 Register scratch, 1701 Condition cond, // eq for new space, ne otherwise. 1702 Label* branch); 1703 1704 // Helper for finding the mark bits for an address. Afterwards, the 1705 // bitmap register points at the word with the mark bits and the mask 1706 // the position of the first bit. Leaves addr_reg unchanged. 1707 inline void GetMarkBits(Register addr_reg, 1708 Register bitmap_reg, 1709 Register mask_reg); 1710 1711 // Helper for throwing exceptions. Compute a handler address and jump to 1712 // it. See the implementation for register usage. 1713 void JumpToHandlerEntry(); 1714 1715 // Compute memory operands for safepoint stack slots. 1716 static int SafepointRegisterStackIndex(int reg_code); 1717 MemOperand SafepointRegisterSlot(Register reg); 1718 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1719 1720 bool generating_stub_; 1721 bool has_frame_; 1722 // This handle will be patched with the code object on installation. 1723 Handle<Object> code_object_; 1724 1725 // Needs access to SafepointRegisterStackIndex for compiled frame 1726 // traversal. 1727 friend class StandardFrame; 1728 }; 1729 1730 1731 // The code patcher is used to patch (typically) small parts of code e.g. for 1732 // debugging and other types of instrumentation. When using the code patcher 1733 // the exact number of bytes specified must be emitted. It is not legal to emit 1734 // relocation information. If any of these constraints are violated it causes 1735 // an assertion to fail. 1736 class CodePatcher { 1737 public: 1738 enum FlushICache { 1739 FLUSH, 1740 DONT_FLUSH 1741 }; 1742 1743 CodePatcher(byte* address, 1744 int instructions, 1745 FlushICache flush_cache = FLUSH); 1746 virtual ~CodePatcher(); 1747 1748 // Macro assembler to emit code. 1749 MacroAssembler* masm() { return &masm_; } 1750 1751 // Emit an instruction directly. 1752 void Emit(Instr instr); 1753 1754 // Emit an address directly. 1755 void Emit(Address addr); 1756 1757 // Change the condition part of an instruction leaving the rest of the current 1758 // instruction unchanged. 1759 void ChangeBranchCondition(Condition cond); 1760 1761 private: 1762 byte* address_; // The address of the code being patched. 1763 int size_; // Number of bytes of the expected patch size. 1764 MacroAssembler masm_; // Macro assembler used to generate the code. 1765 FlushICache flush_cache_; // Whether to flush the I cache after patching. 1766 }; 1767 1768 1769 1770 #ifdef GENERATED_CODE_COVERAGE 1771 #define CODE_COVERAGE_STRINGIFY(x) #x 1772 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) 1773 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) 1774 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> 1775 #else 1776 #define ACCESS_MASM(masm) masm-> 1777 #endif 1778 1779 } } // namespace v8::internal 1780 1781 #endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ 1782