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