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