Home | History | Annotate | Download | only in mips
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_MIPS_CODE_STUBS_ARM_H_
     29 #define V8_MIPS_CODE_STUBS_ARM_H_
     30 
     31 #include "ic-inl.h"
     32 
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 
     38 // Compute a transcendental math function natively, or call the
     39 // TranscendentalCache runtime function.
     40 class TranscendentalCacheStub: public CodeStub {
     41  public:
     42   enum ArgumentType {
     43     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
     44     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
     45   };
     46 
     47   TranscendentalCacheStub(TranscendentalCache::Type type,
     48                           ArgumentType argument_type)
     49       : type_(type), argument_type_(argument_type) { }
     50   void Generate(MacroAssembler* masm);
     51  private:
     52   TranscendentalCache::Type type_;
     53   ArgumentType argument_type_;
     54   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
     55 
     56   Major MajorKey() { return TranscendentalCache; }
     57   int MinorKey() { return type_ | argument_type_; }
     58   Runtime::FunctionId RuntimeFunction();
     59 };
     60 
     61 
     62 class StoreBufferOverflowStub: public CodeStub {
     63  public:
     64   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
     65       : save_doubles_(save_fp) { }
     66 
     67   void Generate(MacroAssembler* masm);
     68 
     69   virtual bool IsPregenerated();
     70   static void GenerateFixedRegStubsAheadOfTime();
     71   virtual bool SometimesSetsUpAFrame() { return false; }
     72 
     73  private:
     74   SaveFPRegsMode save_doubles_;
     75 
     76   Major MajorKey() { return StoreBufferOverflow; }
     77   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
     78 };
     79 
     80 
     81 class UnaryOpStub: public CodeStub {
     82  public:
     83   UnaryOpStub(Token::Value op,
     84               UnaryOverwriteMode mode,
     85               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
     86       : op_(op),
     87         mode_(mode),
     88         operand_type_(operand_type) {
     89   }
     90 
     91  private:
     92   Token::Value op_;
     93   UnaryOverwriteMode mode_;
     94 
     95   // Operand type information determined at runtime.
     96   UnaryOpIC::TypeInfo operand_type_;
     97 
     98   virtual void PrintName(StringStream* stream);
     99 
    100   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
    101   class OpBits: public BitField<Token::Value, 1, 7> {};
    102   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
    103 
    104   Major MajorKey() { return UnaryOp; }
    105   int MinorKey() {
    106     return ModeBits::encode(mode_)
    107            | OpBits::encode(op_)
    108            | OperandTypeInfoBits::encode(operand_type_);
    109   }
    110 
    111   // Note: A lot of the helper functions below will vanish when we use virtual
    112   // function instead of switch more often.
    113   void Generate(MacroAssembler* masm);
    114 
    115   void GenerateTypeTransition(MacroAssembler* masm);
    116 
    117   void GenerateSmiStub(MacroAssembler* masm);
    118   void GenerateSmiStubSub(MacroAssembler* masm);
    119   void GenerateSmiStubBitNot(MacroAssembler* masm);
    120   void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
    121   void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
    122 
    123   void GenerateHeapNumberStub(MacroAssembler* masm);
    124   void GenerateHeapNumberStubSub(MacroAssembler* masm);
    125   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
    126   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
    127   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
    128 
    129   void GenerateGenericStub(MacroAssembler* masm);
    130   void GenerateGenericStubSub(MacroAssembler* masm);
    131   void GenerateGenericStubBitNot(MacroAssembler* masm);
    132   void GenerateGenericCodeFallback(MacroAssembler* masm);
    133 
    134   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
    135 
    136   virtual InlineCacheState GetICState() {
    137     return UnaryOpIC::ToState(operand_type_);
    138   }
    139 
    140   virtual void FinishCode(Handle<Code> code) {
    141     code->set_unary_op_type(operand_type_);
    142   }
    143 };
    144 
    145 
    146 class BinaryOpStub: public CodeStub {
    147  public:
    148   BinaryOpStub(Token::Value op, OverwriteMode mode)
    149       : op_(op),
    150         mode_(mode),
    151         operands_type_(BinaryOpIC::UNINITIALIZED),
    152         result_type_(BinaryOpIC::UNINITIALIZED) {
    153     use_fpu_ = CpuFeatures::IsSupported(FPU);
    154     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
    155   }
    156 
    157   BinaryOpStub(
    158       int key,
    159       BinaryOpIC::TypeInfo operands_type,
    160       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
    161       : op_(OpBits::decode(key)),
    162         mode_(ModeBits::decode(key)),
    163         use_fpu_(FPUBits::decode(key)),
    164         operands_type_(operands_type),
    165         result_type_(result_type) { }
    166 
    167  private:
    168   enum SmiCodeGenerateHeapNumberResults {
    169     ALLOW_HEAPNUMBER_RESULTS,
    170     NO_HEAPNUMBER_RESULTS
    171   };
    172 
    173   Token::Value op_;
    174   OverwriteMode mode_;
    175   bool use_fpu_;
    176 
    177   // Operand type information determined at runtime.
    178   BinaryOpIC::TypeInfo operands_type_;
    179   BinaryOpIC::TypeInfo result_type_;
    180 
    181   virtual void PrintName(StringStream* stream);
    182 
    183   // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
    184   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
    185   class OpBits: public BitField<Token::Value, 2, 7> {};
    186   class FPUBits: public BitField<bool, 9, 1> {};
    187   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
    188   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
    189 
    190   Major MajorKey() { return BinaryOp; }
    191   int MinorKey() {
    192     return OpBits::encode(op_)
    193            | ModeBits::encode(mode_)
    194            | FPUBits::encode(use_fpu_)
    195            | OperandTypeInfoBits::encode(operands_type_)
    196            | ResultTypeInfoBits::encode(result_type_);
    197   }
    198 
    199   void Generate(MacroAssembler* masm);
    200   void GenerateGeneric(MacroAssembler* masm);
    201   void GenerateSmiSmiOperation(MacroAssembler* masm);
    202   void GenerateFPOperation(MacroAssembler* masm,
    203                            bool smi_operands,
    204                            Label* not_numbers,
    205                            Label* gc_required);
    206   void GenerateSmiCode(MacroAssembler* masm,
    207                        Label* use_runtime,
    208                        Label* gc_required,
    209                        SmiCodeGenerateHeapNumberResults heapnumber_results);
    210   void GenerateLoadArguments(MacroAssembler* masm);
    211   void GenerateReturn(MacroAssembler* masm);
    212   void GenerateUninitializedStub(MacroAssembler* masm);
    213   void GenerateSmiStub(MacroAssembler* masm);
    214   void GenerateInt32Stub(MacroAssembler* masm);
    215   void GenerateHeapNumberStub(MacroAssembler* masm);
    216   void GenerateOddballStub(MacroAssembler* masm);
    217   void GenerateStringStub(MacroAssembler* masm);
    218   void GenerateBothStringStub(MacroAssembler* masm);
    219   void GenerateGenericStub(MacroAssembler* masm);
    220   void GenerateAddStrings(MacroAssembler* masm);
    221   void GenerateCallRuntime(MacroAssembler* masm);
    222 
    223   void GenerateHeapResultAllocation(MacroAssembler* masm,
    224                                     Register result,
    225                                     Register heap_number_map,
    226                                     Register scratch1,
    227                                     Register scratch2,
    228                                     Label* gc_required);
    229   void GenerateRegisterArgsPush(MacroAssembler* masm);
    230   void GenerateTypeTransition(MacroAssembler* masm);
    231   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
    232 
    233   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
    234 
    235   virtual InlineCacheState GetICState() {
    236     return BinaryOpIC::ToState(operands_type_);
    237   }
    238 
    239   virtual void FinishCode(Handle<Code> code) {
    240     code->set_binary_op_type(operands_type_);
    241     code->set_binary_op_result_type(result_type_);
    242   }
    243 
    244   friend class CodeGenerator;
    245 };
    246 
    247 
    248 class StringHelper : public AllStatic {
    249  public:
    250   // Generate code for copying characters using a simple loop. This should only
    251   // be used in places where the number of characters is small and the
    252   // additional setup and checking in GenerateCopyCharactersLong adds too much
    253   // overhead. Copying of overlapping regions is not supported.
    254   // Dest register ends at the position after the last character written.
    255   static void GenerateCopyCharacters(MacroAssembler* masm,
    256                                      Register dest,
    257                                      Register src,
    258                                      Register count,
    259                                      Register scratch,
    260                                      bool ascii);
    261 
    262   // Generate code for copying a large number of characters. This function
    263   // is allowed to spend extra time setting up conditions to make copying
    264   // faster. Copying of overlapping regions is not supported.
    265   // Dest register ends at the position after the last character written.
    266   static void GenerateCopyCharactersLong(MacroAssembler* masm,
    267                                          Register dest,
    268                                          Register src,
    269                                          Register count,
    270                                          Register scratch1,
    271                                          Register scratch2,
    272                                          Register scratch3,
    273                                          Register scratch4,
    274                                          Register scratch5,
    275                                          int flags);
    276 
    277 
    278   // Probe the symbol table for a two character string. If the string is
    279   // not found by probing a jump to the label not_found is performed. This jump
    280   // does not guarantee that the string is not in the symbol table. If the
    281   // string is found the code falls through with the string in register r0.
    282   // Contents of both c1 and c2 registers are modified. At the exit c1 is
    283   // guaranteed to contain halfword with low and high bytes equal to
    284   // initial contents of c1 and c2 respectively.
    285   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
    286                                                    Register c1,
    287                                                    Register c2,
    288                                                    Register scratch1,
    289                                                    Register scratch2,
    290                                                    Register scratch3,
    291                                                    Register scratch4,
    292                                                    Register scratch5,
    293                                                    Label* not_found);
    294 
    295   // Generate string hash.
    296   static void GenerateHashInit(MacroAssembler* masm,
    297                                Register hash,
    298                                Register character);
    299 
    300   static void GenerateHashAddCharacter(MacroAssembler* masm,
    301                                        Register hash,
    302                                        Register character);
    303 
    304   static void GenerateHashGetHash(MacroAssembler* masm,
    305                                   Register hash);
    306 
    307  private:
    308   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
    309 };
    310 
    311 
    312 // Flag that indicates how to generate code for the stub StringAddStub.
    313 enum StringAddFlags {
    314   NO_STRING_ADD_FLAGS = 0,
    315   // Omit left string check in stub (left is definitely a string).
    316   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
    317   // Omit right string check in stub (right is definitely a string).
    318   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
    319   // Omit both string checks in stub.
    320   NO_STRING_CHECK_IN_STUB =
    321       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
    322 };
    323 
    324 
    325 class StringAddStub: public CodeStub {
    326  public:
    327   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    328 
    329  private:
    330   Major MajorKey() { return StringAdd; }
    331   int MinorKey() { return flags_; }
    332 
    333   void Generate(MacroAssembler* masm);
    334 
    335   void GenerateConvertArgument(MacroAssembler* masm,
    336                                int stack_offset,
    337                                Register arg,
    338                                Register scratch1,
    339                                Register scratch2,
    340                                Register scratch3,
    341                                Register scratch4,
    342                                Label* slow);
    343 
    344   const StringAddFlags flags_;
    345 };
    346 
    347 
    348 class SubStringStub: public CodeStub {
    349  public:
    350   SubStringStub() {}
    351 
    352  private:
    353   Major MajorKey() { return SubString; }
    354   int MinorKey() { return 0; }
    355 
    356   void Generate(MacroAssembler* masm);
    357 };
    358 
    359 
    360 class StringCompareStub: public CodeStub {
    361  public:
    362   StringCompareStub() { }
    363 
    364   // Compare two flat ASCII strings and returns result in v0.
    365   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    366                                               Register left,
    367                                               Register right,
    368                                               Register scratch1,
    369                                               Register scratch2,
    370                                               Register scratch3,
    371                                               Register scratch4);
    372 
    373   // Compares two flat ASCII strings for equality and returns result
    374   // in v0.
    375   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
    376                                             Register left,
    377                                             Register right,
    378                                             Register scratch1,
    379                                             Register scratch2,
    380                                             Register scratch3);
    381 
    382  private:
    383   virtual Major MajorKey() { return StringCompare; }
    384   virtual int MinorKey() { return 0; }
    385   virtual void Generate(MacroAssembler* masm);
    386 
    387   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
    388                                             Register left,
    389                                             Register right,
    390                                             Register length,
    391                                             Register scratch1,
    392                                             Register scratch2,
    393                                             Register scratch3,
    394                                             Label* chars_not_equal);
    395 };
    396 
    397 
    398 // This stub can convert a signed int32 to a heap number (double).  It does
    399 // not work for int32s that are in Smi range!  No GC occurs during this stub
    400 // so you don't have to set up the frame.
    401 class WriteInt32ToHeapNumberStub : public CodeStub {
    402  public:
    403   WriteInt32ToHeapNumberStub(Register the_int,
    404                              Register the_heap_number,
    405                              Register scratch,
    406                              Register scratch2)
    407       : the_int_(the_int),
    408         the_heap_number_(the_heap_number),
    409         scratch_(scratch),
    410         sign_(scratch2) {
    411     ASSERT(IntRegisterBits::is_valid(the_int_.code()));
    412     ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
    413     ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
    414     ASSERT(SignRegisterBits::is_valid(sign_.code()));
    415   }
    416 
    417   bool IsPregenerated();
    418   static void GenerateFixedRegStubsAheadOfTime();
    419 
    420  private:
    421   Register the_int_;
    422   Register the_heap_number_;
    423   Register scratch_;
    424   Register sign_;
    425 
    426   // Minor key encoding in 16 bits.
    427   class IntRegisterBits: public BitField<int, 0, 4> {};
    428   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
    429   class ScratchRegisterBits: public BitField<int, 8, 4> {};
    430   class SignRegisterBits: public BitField<int, 12, 4> {};
    431 
    432   Major MajorKey() { return WriteInt32ToHeapNumber; }
    433   int MinorKey() {
    434     // Encode the parameters in a unique 16 bit value.
    435     return IntRegisterBits::encode(the_int_.code())
    436            | HeapNumberRegisterBits::encode(the_heap_number_.code())
    437            | ScratchRegisterBits::encode(scratch_.code())
    438            | SignRegisterBits::encode(sign_.code());
    439   }
    440 
    441   void Generate(MacroAssembler* masm);
    442 };
    443 
    444 
    445 class NumberToStringStub: public CodeStub {
    446  public:
    447   NumberToStringStub() { }
    448 
    449   // Generate code to do a lookup in the number string cache. If the number in
    450   // the register object is found in the cache the generated code falls through
    451   // with the result in the result register. The object and the result register
    452   // can be the same. If the number is not found in the cache the code jumps to
    453   // the label not_found with only the content of register object unchanged.
    454   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
    455                                               Register object,
    456                                               Register result,
    457                                               Register scratch1,
    458                                               Register scratch2,
    459                                               Register scratch3,
    460                                               bool object_is_smi,
    461                                               Label* not_found);
    462 
    463  private:
    464   Major MajorKey() { return NumberToString; }
    465   int MinorKey() { return 0; }
    466 
    467   void Generate(MacroAssembler* masm);
    468 };
    469 
    470 
    471 class RecordWriteStub: public CodeStub {
    472  public:
    473   RecordWriteStub(Register object,
    474                   Register value,
    475                   Register address,
    476                   RememberedSetAction remembered_set_action,
    477                   SaveFPRegsMode fp_mode)
    478       : object_(object),
    479         value_(value),
    480         address_(address),
    481         remembered_set_action_(remembered_set_action),
    482         save_fp_regs_mode_(fp_mode),
    483         regs_(object,   // An input reg.
    484               address,  // An input reg.
    485               value) {  // One scratch reg.
    486   }
    487 
    488   enum Mode {
    489     STORE_BUFFER_ONLY,
    490     INCREMENTAL,
    491     INCREMENTAL_COMPACTION
    492   };
    493 
    494   virtual bool IsPregenerated();
    495   static void GenerateFixedRegStubsAheadOfTime();
    496   virtual bool SometimesSetsUpAFrame() { return false; }
    497 
    498   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    499     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    500     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
    501         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    502     ASSERT(Assembler::IsBne(masm->instr_at(pos)));
    503   }
    504 
    505   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    506     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    507     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
    508         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    509     ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
    510   }
    511 
    512   static Mode GetMode(Code* stub) {
    513     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
    514     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    515                                                    2 * Assembler::kInstrSize);
    516 
    517     if (Assembler::IsBeq(first_instruction)) {
    518       return INCREMENTAL;
    519     }
    520 
    521     ASSERT(Assembler::IsBne(first_instruction));
    522 
    523     if (Assembler::IsBeq(second_instruction)) {
    524       return INCREMENTAL_COMPACTION;
    525     }
    526 
    527     ASSERT(Assembler::IsBne(second_instruction));
    528 
    529     return STORE_BUFFER_ONLY;
    530   }
    531 
    532   static void Patch(Code* stub, Mode mode) {
    533     MacroAssembler masm(NULL,
    534                         stub->instruction_start(),
    535                         stub->instruction_size());
    536     switch (mode) {
    537       case STORE_BUFFER_ONLY:
    538         ASSERT(GetMode(stub) == INCREMENTAL ||
    539                GetMode(stub) == INCREMENTAL_COMPACTION);
    540         PatchBranchIntoNop(&masm, 0);
    541         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
    542         break;
    543       case INCREMENTAL:
    544         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    545         PatchNopIntoBranch(&masm, 0);
    546         break;
    547       case INCREMENTAL_COMPACTION:
    548         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    549         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
    550         break;
    551     }
    552     ASSERT(GetMode(stub) == mode);
    553     CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
    554   }
    555 
    556  private:
    557   // This is a helper class for freeing up 3 scratch registers.  The input is
    558   // two registers that must be preserved and one scratch register provided by
    559   // the caller.
    560   class RegisterAllocation {
    561    public:
    562     RegisterAllocation(Register object,
    563                        Register address,
    564                        Register scratch0)
    565         : object_(object),
    566           address_(address),
    567           scratch0_(scratch0) {
    568       ASSERT(!AreAliased(scratch0, object, address, no_reg));
    569       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
    570     }
    571 
    572     void Save(MacroAssembler* masm) {
    573       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
    574       // We don't have to save scratch0_ because it was given to us as
    575       // a scratch register.
    576       masm->push(scratch1_);
    577     }
    578 
    579     void Restore(MacroAssembler* masm) {
    580       masm->pop(scratch1_);
    581     }
    582 
    583     // If we have to call into C then we need to save and restore all caller-
    584     // saved registers that were not already preserved.  The scratch registers
    585     // will be restored by other means so we don't bother pushing them here.
    586     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    587       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    588       if (mode == kSaveFPRegs) {
    589         CpuFeatures::Scope scope(FPU);
    590         masm->MultiPushFPU(kCallerSavedFPU);
    591       }
    592     }
    593 
    594     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    595                                            SaveFPRegsMode mode) {
    596       if (mode == kSaveFPRegs) {
    597         CpuFeatures::Scope scope(FPU);
    598         masm->MultiPopFPU(kCallerSavedFPU);
    599       }
    600       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    601     }
    602 
    603     inline Register object() { return object_; }
    604     inline Register address() { return address_; }
    605     inline Register scratch0() { return scratch0_; }
    606     inline Register scratch1() { return scratch1_; }
    607 
    608    private:
    609     Register object_;
    610     Register address_;
    611     Register scratch0_;
    612     Register scratch1_;
    613 
    614     Register GetRegThatIsNotOneOf(Register r1,
    615                                   Register r2,
    616                                   Register r3) {
    617       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
    618         Register candidate = Register::FromAllocationIndex(i);
    619         if (candidate.is(r1)) continue;
    620         if (candidate.is(r2)) continue;
    621         if (candidate.is(r3)) continue;
    622         return candidate;
    623       }
    624       UNREACHABLE();
    625       return no_reg;
    626     }
    627     friend class RecordWriteStub;
    628   };
    629 
    630   enum OnNoNeedToInformIncrementalMarker {
    631     kReturnOnNoNeedToInformIncrementalMarker,
    632     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    633   };
    634 
    635   void Generate(MacroAssembler* masm);
    636   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    637   void CheckNeedsToInformIncrementalMarker(
    638       MacroAssembler* masm,
    639       OnNoNeedToInformIncrementalMarker on_no_need,
    640       Mode mode);
    641   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
    642 
    643   Major MajorKey() { return RecordWrite; }
    644 
    645   int MinorKey() {
    646     return ObjectBits::encode(object_.code()) |
    647         ValueBits::encode(value_.code()) |
    648         AddressBits::encode(address_.code()) |
    649         RememberedSetActionBits::encode(remembered_set_action_) |
    650         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
    651   }
    652 
    653   void Activate(Code* code) {
    654     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    655   }
    656 
    657   class ObjectBits: public BitField<int, 0, 5> {};
    658   class ValueBits: public BitField<int, 5, 5> {};
    659   class AddressBits: public BitField<int, 10, 5> {};
    660   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
    661   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
    662 
    663   Register object_;
    664   Register value_;
    665   Register address_;
    666   RememberedSetAction remembered_set_action_;
    667   SaveFPRegsMode save_fp_regs_mode_;
    668   Label slow_;
    669   RegisterAllocation regs_;
    670 };
    671 
    672 
    673 // Enter C code from generated RegExp code in a way that allows
    674 // the C code to fix the return address in case of a GC.
    675 // Currently only needed on ARM and MIPS.
    676 class RegExpCEntryStub: public CodeStub {
    677  public:
    678   RegExpCEntryStub() {}
    679   virtual ~RegExpCEntryStub() {}
    680   void Generate(MacroAssembler* masm);
    681 
    682  private:
    683   Major MajorKey() { return RegExpCEntry; }
    684   int MinorKey() { return 0; }
    685 
    686   bool NeedsImmovableCode() { return true; }
    687 };
    688 
    689 // Trampoline stub to call into native code. To call safely into native code
    690 // in the presence of compacting GC (which can move code objects) we need to
    691 // keep the code which called into native pinned in the memory. Currently the
    692 // simplest approach is to generate such stub early enough so it can never be
    693 // moved by GC
    694 class DirectCEntryStub: public CodeStub {
    695  public:
    696   DirectCEntryStub() {}
    697   void Generate(MacroAssembler* masm);
    698   void GenerateCall(MacroAssembler* masm,
    699                                 ExternalReference function);
    700   void GenerateCall(MacroAssembler* masm, Register target);
    701 
    702  private:
    703   Major MajorKey() { return DirectCEntry; }
    704   int MinorKey() { return 0; }
    705 
    706   bool NeedsImmovableCode() { return true; }
    707 };
    708 
    709 class FloatingPointHelper : public AllStatic {
    710  public:
    711   enum Destination {
    712     kFPURegisters,
    713     kCoreRegisters
    714   };
    715 
    716 
    717   // Loads smis from a0 and a1 (right and left in binary operations) into
    718   // floating point registers. Depending on the destination the values ends up
    719   // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
    720   // is floating point registers FPU must be supported. If core registers are
    721   // requested when FPU is supported f12 and f14 will be scratched.
    722   static void LoadSmis(MacroAssembler* masm,
    723                        Destination destination,
    724                        Register scratch1,
    725                        Register scratch2);
    726 
    727   // Loads objects from a0 and a1 (right and left in binary operations) into
    728   // floating point registers. Depending on the destination the values ends up
    729   // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
    730   // is floating point registers FPU must be supported. If core registers are
    731   // requested when FPU is supported f12 and f14 will still be scratched. If
    732   // either a0 or a1 is not a number (not smi and not heap number object) the
    733   // not_number label is jumped to with a0 and a1 intact.
    734   static void LoadOperands(MacroAssembler* masm,
    735                            FloatingPointHelper::Destination destination,
    736                            Register heap_number_map,
    737                            Register scratch1,
    738                            Register scratch2,
    739                            Label* not_number);
    740 
    741   // Convert the smi or heap number in object to an int32 using the rules
    742   // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
    743   // and brought into the range -2^31 .. +2^31 - 1.
    744   static void ConvertNumberToInt32(MacroAssembler* masm,
    745                                    Register object,
    746                                    Register dst,
    747                                    Register heap_number_map,
    748                                    Register scratch1,
    749                                    Register scratch2,
    750                                    Register scratch3,
    751                                    FPURegister double_scratch,
    752                                    Label* not_int32);
    753 
    754   // Converts the integer (untagged smi) in |int_scratch| to a double, storing
    755   // the result either in |double_dst| or |dst2:dst1|, depending on
    756   // |destination|.
    757   // Warning: The value in |int_scratch| will be changed in the process!
    758   static void ConvertIntToDouble(MacroAssembler* masm,
    759                                  Register int_scratch,
    760                                  Destination destination,
    761                                  FPURegister double_dst,
    762                                  Register dst1,
    763                                  Register dst2,
    764                                  Register scratch2,
    765                                  FPURegister single_scratch);
    766 
    767   // Load the number from object into double_dst in the double format.
    768   // Control will jump to not_int32 if the value cannot be exactly represented
    769   // by a 32-bit integer.
    770   // Floating point value in the 32-bit integer range that are not exact integer
    771   // won't be loaded.
    772   static void LoadNumberAsInt32Double(MacroAssembler* masm,
    773                                       Register object,
    774                                       Destination destination,
    775                                       FPURegister double_dst,
    776                                       Register dst1,
    777                                       Register dst2,
    778                                       Register heap_number_map,
    779                                       Register scratch1,
    780                                       Register scratch2,
    781                                       FPURegister single_scratch,
    782                                       Label* not_int32);
    783 
    784   // Loads the number from object into dst as a 32-bit integer.
    785   // Control will jump to not_int32 if the object cannot be exactly represented
    786   // by a 32-bit integer.
    787   // Floating point value in the 32-bit integer range that are not exact integer
    788   // won't be converted.
    789   // scratch3 is not used when FPU is supported.
    790   static void LoadNumberAsInt32(MacroAssembler* masm,
    791                                 Register object,
    792                                 Register dst,
    793                                 Register heap_number_map,
    794                                 Register scratch1,
    795                                 Register scratch2,
    796                                 Register scratch3,
    797                                 FPURegister double_scratch,
    798                                 Label* not_int32);
    799 
    800   // Generate non FPU code to check if a double can be exactly represented by a
    801   // 32-bit integer. This does not check for 0 or -0, which need
    802   // to be checked for separately.
    803   // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
    804   // through otherwise.
    805   // src1 and src2 will be cloberred.
    806   //
    807   // Expected input:
    808   // - src1: higher (exponent) part of the double value.
    809   // - src2: lower (mantissa) part of the double value.
    810   // Output status:
    811   // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
    812   // - src2: contains 1.
    813   // - other registers are clobbered.
    814   static void DoubleIs32BitInteger(MacroAssembler* masm,
    815                                    Register src1,
    816                                    Register src2,
    817                                    Register dst,
    818                                    Register scratch,
    819                                    Label* not_int32);
    820 
    821   // Generates code to call a C function to do a double operation using core
    822   // registers. (Used when FPU is not supported.)
    823   // This code never falls through, but returns with a heap number containing
    824   // the result in v0.
    825   // Register heapnumber_result must be a heap number in which the
    826   // result of the operation will be stored.
    827   // Requires the following layout on entry:
    828   // a0: Left value (least significant part of mantissa).
    829   // a1: Left value (sign, exponent, top of mantissa).
    830   // a2: Right value (least significant part of mantissa).
    831   // a3: Right value (sign, exponent, top of mantissa).
    832   static void CallCCodeForDoubleOperation(MacroAssembler* masm,
    833                                           Token::Value op,
    834                                           Register heap_number_result,
    835                                           Register scratch);
    836 
    837  private:
    838   static void LoadNumber(MacroAssembler* masm,
    839                          FloatingPointHelper::Destination destination,
    840                          Register object,
    841                          FPURegister dst,
    842                          Register dst1,
    843                          Register dst2,
    844                          Register heap_number_map,
    845                          Register scratch1,
    846                          Register scratch2,
    847                          Label* not_number);
    848 };
    849 
    850 
    851 class StringDictionaryLookupStub: public CodeStub {
    852  public:
    853   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
    854 
    855   explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
    856 
    857   void Generate(MacroAssembler* masm);
    858 
    859   static void GenerateNegativeLookup(MacroAssembler* masm,
    860                                      Label* miss,
    861                                      Label* done,
    862                                      Register receiver,
    863                                      Register properties,
    864                                      Handle<String> name,
    865                                      Register scratch0);
    866 
    867   static void GeneratePositiveLookup(MacroAssembler* masm,
    868                                      Label* miss,
    869                                      Label* done,
    870                                      Register elements,
    871                                      Register name,
    872                                      Register r0,
    873                                      Register r1);
    874 
    875   virtual bool SometimesSetsUpAFrame() { return false; }
    876 
    877  private:
    878   static const int kInlinedProbes = 4;
    879   static const int kTotalProbes = 20;
    880 
    881   static const int kCapacityOffset =
    882       StringDictionary::kHeaderSize +
    883       StringDictionary::kCapacityIndex * kPointerSize;
    884 
    885   static const int kElementsStartOffset =
    886       StringDictionary::kHeaderSize +
    887       StringDictionary::kElementsStartIndex * kPointerSize;
    888 
    889   Major MajorKey() { return StringDictionaryLookup; }
    890 
    891   int MinorKey() {
    892     return LookupModeBits::encode(mode_);
    893   }
    894 
    895   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
    896 
    897   LookupMode mode_;
    898 };
    899 
    900 
    901 } }  // namespace v8::internal
    902 
    903 #endif  // V8_MIPS_CODE_STUBS_ARM_H_
    904