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