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