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