Home | History | Annotate | Download | only in arm
      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_ARM_CODE_STUBS_ARM_H_
     29 #define V8_ARM_CODE_STUBS_ARM_H_
     30 
     31 #include "ic-inl.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 // Compute a transcendental math function natively, or call the
     38 // TranscendentalCache runtime function.
     39 class TranscendentalCacheStub: public CodeStub {
     40  public:
     41   enum ArgumentType {
     42     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
     43     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
     44   };
     45 
     46   TranscendentalCacheStub(TranscendentalCache::Type type,
     47                           ArgumentType argument_type)
     48       : type_(type), argument_type_(argument_type) { }
     49   void Generate(MacroAssembler* masm);
     50  private:
     51   TranscendentalCache::Type type_;
     52   ArgumentType argument_type_;
     53   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
     54 
     55   Major MajorKey() { return TranscendentalCache; }
     56   int MinorKey() { return type_ | argument_type_; }
     57   Runtime::FunctionId RuntimeFunction();
     58 };
     59 
     60 
     61 class StoreBufferOverflowStub: public CodeStub {
     62  public:
     63   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
     64       : save_doubles_(save_fp) { }
     65 
     66   void Generate(MacroAssembler* masm);
     67 
     68   virtual bool IsPregenerated();
     69   static void GenerateFixedRegStubsAheadOfTime();
     70   virtual bool SometimesSetsUpAFrame() { return false; }
     71 
     72  private:
     73   SaveFPRegsMode save_doubles_;
     74 
     75   Major MajorKey() { return StoreBufferOverflow; }
     76   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
     77 };
     78 
     79 
     80 class UnaryOpStub: public CodeStub {
     81  public:
     82   UnaryOpStub(Token::Value op,
     83               UnaryOverwriteMode mode,
     84               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
     85       : op_(op),
     86         mode_(mode),
     87         operand_type_(operand_type) {
     88   }
     89 
     90  private:
     91   Token::Value op_;
     92   UnaryOverwriteMode mode_;
     93 
     94   // Operand type information determined at runtime.
     95   UnaryOpIC::TypeInfo operand_type_;
     96 
     97   virtual void PrintName(StringStream* stream);
     98 
     99   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
    100   class OpBits: public BitField<Token::Value, 1, 7> {};
    101   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
    102 
    103   Major MajorKey() { return UnaryOp; }
    104   int MinorKey() {
    105     return ModeBits::encode(mode_)
    106            | OpBits::encode(op_)
    107            | OperandTypeInfoBits::encode(operand_type_);
    108   }
    109 
    110   // Note: A lot of the helper functions below will vanish when we use virtual
    111   // function instead of switch more often.
    112   void Generate(MacroAssembler* masm);
    113 
    114   void GenerateTypeTransition(MacroAssembler* masm);
    115 
    116   void GenerateSmiStub(MacroAssembler* masm);
    117   void GenerateSmiStubSub(MacroAssembler* masm);
    118   void GenerateSmiStubBitNot(MacroAssembler* masm);
    119   void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
    120   void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
    121 
    122   void GenerateHeapNumberStub(MacroAssembler* masm);
    123   void GenerateHeapNumberStubSub(MacroAssembler* masm);
    124   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
    125   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
    126   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
    127 
    128   void GenerateGenericStub(MacroAssembler* masm);
    129   void GenerateGenericStubSub(MacroAssembler* masm);
    130   void GenerateGenericStubBitNot(MacroAssembler* masm);
    131   void GenerateGenericCodeFallback(MacroAssembler* masm);
    132 
    133   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
    134 
    135   virtual InlineCacheState GetICState() {
    136     return UnaryOpIC::ToState(operand_type_);
    137   }
    138 
    139   virtual void FinishCode(Handle<Code> code) {
    140     code->set_unary_op_type(operand_type_);
    141   }
    142 };
    143 
    144 
    145 class BinaryOpStub: public CodeStub {
    146  public:
    147   BinaryOpStub(Token::Value op, OverwriteMode mode)
    148       : op_(op),
    149         mode_(mode),
    150         operands_type_(BinaryOpIC::UNINITIALIZED),
    151         result_type_(BinaryOpIC::UNINITIALIZED) {
    152     use_vfp3_ = CpuFeatures::IsSupported(VFP3);
    153     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
    154   }
    155 
    156   BinaryOpStub(
    157       int key,
    158       BinaryOpIC::TypeInfo operands_type,
    159       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
    160       : op_(OpBits::decode(key)),
    161         mode_(ModeBits::decode(key)),
    162         use_vfp3_(VFP3Bits::decode(key)),
    163         operands_type_(operands_type),
    164         result_type_(result_type) { }
    165 
    166  private:
    167   enum SmiCodeGenerateHeapNumberResults {
    168     ALLOW_HEAPNUMBER_RESULTS,
    169     NO_HEAPNUMBER_RESULTS
    170   };
    171 
    172   Token::Value op_;
    173   OverwriteMode mode_;
    174   bool use_vfp3_;
    175 
    176   // Operand type information determined at runtime.
    177   BinaryOpIC::TypeInfo operands_type_;
    178   BinaryOpIC::TypeInfo result_type_;
    179 
    180   virtual void PrintName(StringStream* stream);
    181 
    182   // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
    183   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
    184   class OpBits: public BitField<Token::Value, 2, 7> {};
    185   class VFP3Bits: public BitField<bool, 9, 1> {};
    186   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
    187   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
    188 
    189   Major MajorKey() { return BinaryOp; }
    190   int MinorKey() {
    191     return OpBits::encode(op_)
    192            | ModeBits::encode(mode_)
    193            | VFP3Bits::encode(use_vfp3_)
    194            | OperandTypeInfoBits::encode(operands_type_)
    195            | ResultTypeInfoBits::encode(result_type_);
    196   }
    197 
    198   void Generate(MacroAssembler* masm);
    199   void GenerateGeneric(MacroAssembler* masm);
    200   void GenerateSmiSmiOperation(MacroAssembler* masm);
    201   void GenerateFPOperation(MacroAssembler* masm,
    202                            bool smi_operands,
    203                            Label* not_numbers,
    204                            Label* gc_required);
    205   void GenerateSmiCode(MacroAssembler* masm,
    206                        Label* use_runtime,
    207                        Label* gc_required,
    208                        SmiCodeGenerateHeapNumberResults heapnumber_results);
    209   void GenerateLoadArguments(MacroAssembler* masm);
    210   void GenerateReturn(MacroAssembler* masm);
    211   void GenerateUninitializedStub(MacroAssembler* masm);
    212   void GenerateSmiStub(MacroAssembler* masm);
    213   void GenerateInt32Stub(MacroAssembler* masm);
    214   void GenerateHeapNumberStub(MacroAssembler* masm);
    215   void GenerateOddballStub(MacroAssembler* masm);
    216   void GenerateStringStub(MacroAssembler* masm);
    217   void GenerateBothStringStub(MacroAssembler* masm);
    218   void GenerateGenericStub(MacroAssembler* masm);
    219   void GenerateAddStrings(MacroAssembler* masm);
    220   void GenerateCallRuntime(MacroAssembler* masm);
    221 
    222   void GenerateHeapResultAllocation(MacroAssembler* masm,
    223                                     Register result,
    224                                     Register heap_number_map,
    225                                     Register scratch1,
    226                                     Register scratch2,
    227                                     Label* gc_required);
    228   void GenerateRegisterArgsPush(MacroAssembler* masm);
    229   void GenerateTypeTransition(MacroAssembler* masm);
    230   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
    231 
    232   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
    233 
    234   virtual InlineCacheState GetICState() {
    235     return BinaryOpIC::ToState(operands_type_);
    236   }
    237 
    238   virtual void FinishCode(Handle<Code> code) {
    239     code->set_binary_op_type(operands_type_);
    240     code->set_binary_op_result_type(result_type_);
    241   }
    242 
    243   friend class CodeGenerator;
    244 };
    245 
    246 
    247 class StringHelper : public AllStatic {
    248  public:
    249   // Generate code for copying characters using a simple loop. This should only
    250   // be used in places where the number of characters is small and the
    251   // additional setup and checking in GenerateCopyCharactersLong adds too much
    252   // overhead. Copying of overlapping regions is not supported.
    253   // Dest register ends at the position after the last character written.
    254   static void GenerateCopyCharacters(MacroAssembler* masm,
    255                                      Register dest,
    256                                      Register src,
    257                                      Register count,
    258                                      Register scratch,
    259                                      bool ascii);
    260 
    261   // Generate code for copying a large number of characters. This function
    262   // is allowed to spend extra time setting up conditions to make copying
    263   // faster. Copying of overlapping regions is not supported.
    264   // Dest register ends at the position after the last character written.
    265   static void GenerateCopyCharactersLong(MacroAssembler* masm,
    266                                          Register dest,
    267                                          Register src,
    268                                          Register count,
    269                                          Register scratch1,
    270                                          Register scratch2,
    271                                          Register scratch3,
    272                                          Register scratch4,
    273                                          Register scratch5,
    274                                          int flags);
    275 
    276 
    277   // Probe the symbol table for a two character string. If the string is
    278   // not found by probing a jump to the label not_found is performed. This jump
    279   // does not guarantee that the string is not in the symbol table. If the
    280   // string is found the code falls through with the string in register r0.
    281   // Contents of both c1 and c2 registers are modified. At the exit c1 is
    282   // guaranteed to contain halfword with low and high bytes equal to
    283   // initial contents of c1 and c2 respectively.
    284   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
    285                                                    Register c1,
    286                                                    Register c2,
    287                                                    Register scratch1,
    288                                                    Register scratch2,
    289                                                    Register scratch3,
    290                                                    Register scratch4,
    291                                                    Register scratch5,
    292                                                    Label* not_found);
    293 
    294   // Generate string hash.
    295   static void GenerateHashInit(MacroAssembler* masm,
    296                                Register hash,
    297                                Register character);
    298 
    299   static void GenerateHashAddCharacter(MacroAssembler* masm,
    300                                        Register hash,
    301                                        Register character);
    302 
    303   static void GenerateHashGetHash(MacroAssembler* masm,
    304                                   Register hash);
    305 
    306  private:
    307   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
    308 };
    309 
    310 
    311 // Flag that indicates how to generate code for the stub StringAddStub.
    312 enum StringAddFlags {
    313   NO_STRING_ADD_FLAGS = 0,
    314   // Omit left string check in stub (left is definitely a string).
    315   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
    316   // Omit right string check in stub (right is definitely a string).
    317   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
    318   // Omit both string checks in stub.
    319   NO_STRING_CHECK_IN_STUB =
    320       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
    321 };
    322 
    323 
    324 class StringAddStub: public CodeStub {
    325  public:
    326   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    327 
    328  private:
    329   Major MajorKey() { return StringAdd; }
    330   int MinorKey() { return flags_; }
    331 
    332   void Generate(MacroAssembler* masm);
    333 
    334   void GenerateConvertArgument(MacroAssembler* masm,
    335                                int stack_offset,
    336                                Register arg,
    337                                Register scratch1,
    338                                Register scratch2,
    339                                Register scratch3,
    340                                Register scratch4,
    341                                Label* slow);
    342 
    343   const StringAddFlags flags_;
    344 };
    345 
    346 
    347 class SubStringStub: public CodeStub {
    348  public:
    349   SubStringStub() {}
    350 
    351  private:
    352   Major MajorKey() { return SubString; }
    353   int MinorKey() { return 0; }
    354 
    355   void Generate(MacroAssembler* masm);
    356 };
    357 
    358 
    359 
    360 class StringCompareStub: public CodeStub {
    361  public:
    362   StringCompareStub() { }
    363 
    364   // Compares two flat ASCII strings and returns result in r0.
    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 r0.
    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                                             Label* chars_not_equal);
    394 };
    395 
    396 
    397 // This stub can convert a signed int32 to a heap number (double).  It does
    398 // not work for int32s that are in Smi range!  No GC occurs during this stub
    399 // so you don't have to set up the frame.
    400 class WriteInt32ToHeapNumberStub : public CodeStub {
    401  public:
    402   WriteInt32ToHeapNumberStub(Register the_int,
    403                              Register the_heap_number,
    404                              Register scratch)
    405       : the_int_(the_int),
    406         the_heap_number_(the_heap_number),
    407         scratch_(scratch) { }
    408 
    409   bool IsPregenerated();
    410   static void GenerateFixedRegStubsAheadOfTime();
    411 
    412  private:
    413   Register the_int_;
    414   Register the_heap_number_;
    415   Register scratch_;
    416 
    417   // Minor key encoding in 16 bits.
    418   class IntRegisterBits: public BitField<int, 0, 4> {};
    419   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
    420   class ScratchRegisterBits: public BitField<int, 8, 4> {};
    421 
    422   Major MajorKey() { return WriteInt32ToHeapNumber; }
    423   int MinorKey() {
    424     // Encode the parameters in a unique 16 bit value.
    425     return IntRegisterBits::encode(the_int_.code())
    426            | HeapNumberRegisterBits::encode(the_heap_number_.code())
    427            | ScratchRegisterBits::encode(scratch_.code());
    428   }
    429 
    430   void Generate(MacroAssembler* masm);
    431 };
    432 
    433 
    434 class NumberToStringStub: public CodeStub {
    435  public:
    436   NumberToStringStub() { }
    437 
    438   // Generate code to do a lookup in the number string cache. If the number in
    439   // the register object is found in the cache the generated code falls through
    440   // with the result in the result register. The object and the result register
    441   // can be the same. If the number is not found in the cache the code jumps to
    442   // the label not_found with only the content of register object unchanged.
    443   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
    444                                               Register object,
    445                                               Register result,
    446                                               Register scratch1,
    447                                               Register scratch2,
    448                                               Register scratch3,
    449                                               bool object_is_smi,
    450                                               Label* not_found);
    451 
    452  private:
    453   Major MajorKey() { return NumberToString; }
    454   int MinorKey() { return 0; }
    455 
    456   void Generate(MacroAssembler* masm);
    457 };
    458 
    459 
    460 class RecordWriteStub: public CodeStub {
    461  public:
    462   RecordWriteStub(Register object,
    463                   Register value,
    464                   Register address,
    465                   RememberedSetAction remembered_set_action,
    466                   SaveFPRegsMode fp_mode)
    467       : object_(object),
    468         value_(value),
    469         address_(address),
    470         remembered_set_action_(remembered_set_action),
    471         save_fp_regs_mode_(fp_mode),
    472         regs_(object,   // An input reg.
    473               address,  // An input reg.
    474               value) {  // One scratch reg.
    475   }
    476 
    477   enum Mode {
    478     STORE_BUFFER_ONLY,
    479     INCREMENTAL,
    480     INCREMENTAL_COMPACTION
    481   };
    482 
    483   virtual bool IsPregenerated();
    484   static void GenerateFixedRegStubsAheadOfTime();
    485   virtual bool SometimesSetsUpAFrame() { return false; }
    486 
    487   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    488     masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
    489     ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos)));
    490   }
    491 
    492   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    493     masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
    494     ASSERT(Assembler::IsBranch(masm->instr_at(pos)));
    495   }
    496 
    497   static Mode GetMode(Code* stub) {
    498     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
    499     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    500                                                    Assembler::kInstrSize);
    501 
    502     if (Assembler::IsBranch(first_instruction)) {
    503       return INCREMENTAL;
    504     }
    505 
    506     ASSERT(Assembler::IsTstImmediate(first_instruction));
    507 
    508     if (Assembler::IsBranch(second_instruction)) {
    509       return INCREMENTAL_COMPACTION;
    510     }
    511 
    512     ASSERT(Assembler::IsTstImmediate(second_instruction));
    513 
    514     return STORE_BUFFER_ONLY;
    515   }
    516 
    517   static void Patch(Code* stub, Mode mode) {
    518     MacroAssembler masm(NULL,
    519                         stub->instruction_start(),
    520                         stub->instruction_size());
    521     switch (mode) {
    522       case STORE_BUFFER_ONLY:
    523         ASSERT(GetMode(stub) == INCREMENTAL ||
    524                GetMode(stub) == INCREMENTAL_COMPACTION);
    525         PatchBranchIntoNop(&masm, 0);
    526         PatchBranchIntoNop(&masm, Assembler::kInstrSize);
    527         break;
    528       case INCREMENTAL:
    529         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    530         PatchNopIntoBranch(&masm, 0);
    531         break;
    532       case INCREMENTAL_COMPACTION:
    533         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    534         PatchNopIntoBranch(&masm, Assembler::kInstrSize);
    535         break;
    536     }
    537     ASSERT(GetMode(stub) == mode);
    538     CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize);
    539   }
    540 
    541  private:
    542   // This is a helper class for freeing up 3 scratch registers.  The input is
    543   // two registers that must be preserved and one scratch register provided by
    544   // the caller.
    545   class RegisterAllocation {
    546    public:
    547     RegisterAllocation(Register object,
    548                        Register address,
    549                        Register scratch0)
    550         : object_(object),
    551           address_(address),
    552           scratch0_(scratch0) {
    553       ASSERT(!AreAliased(scratch0, object, address, no_reg));
    554       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
    555     }
    556 
    557     void Save(MacroAssembler* masm) {
    558       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
    559       // We don't have to save scratch0_ because it was given to us as
    560       // a scratch register.
    561       masm->push(scratch1_);
    562     }
    563 
    564     void Restore(MacroAssembler* masm) {
    565       masm->pop(scratch1_);
    566     }
    567 
    568     // If we have to call into C then we need to save and restore all caller-
    569     // saved registers that were not already preserved.  The scratch registers
    570     // will be restored by other means so we don't bother pushing them here.
    571     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    572       masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
    573       if (mode == kSaveFPRegs) {
    574         CpuFeatures::Scope scope(VFP3);
    575         masm->sub(sp,
    576                   sp,
    577                   Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
    578         // Save all VFP registers except d0.
    579         for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
    580           DwVfpRegister reg = DwVfpRegister::from_code(i);
    581           masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
    582         }
    583       }
    584     }
    585 
    586     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    587                                            SaveFPRegsMode mode) {
    588       if (mode == kSaveFPRegs) {
    589         CpuFeatures::Scope scope(VFP3);
    590         // Restore all VFP registers except d0.
    591         for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
    592           DwVfpRegister reg = DwVfpRegister::from_code(i);
    593           masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
    594         }
    595         masm->add(sp,
    596                   sp,
    597                   Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
    598       }
    599       masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
    600     }
    601 
    602     inline Register object() { return object_; }
    603     inline Register address() { return address_; }
    604     inline Register scratch0() { return scratch0_; }
    605     inline Register scratch1() { return scratch1_; }
    606 
    607    private:
    608     Register object_;
    609     Register address_;
    610     Register scratch0_;
    611     Register scratch1_;
    612 
    613     Register GetRegThatIsNotOneOf(Register r1,
    614                                   Register r2,
    615                                   Register r3) {
    616       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
    617         Register candidate = Register::FromAllocationIndex(i);
    618         if (candidate.is(r1)) continue;
    619         if (candidate.is(r2)) continue;
    620         if (candidate.is(r3)) continue;
    621         return candidate;
    622       }
    623       UNREACHABLE();
    624       return no_reg;
    625     }
    626     friend class RecordWriteStub;
    627   };
    628 
    629   enum OnNoNeedToInformIncrementalMarker {
    630     kReturnOnNoNeedToInformIncrementalMarker,
    631     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    632   };
    633 
    634   void Generate(MacroAssembler* masm);
    635   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    636   void CheckNeedsToInformIncrementalMarker(
    637       MacroAssembler* masm,
    638       OnNoNeedToInformIncrementalMarker on_no_need,
    639       Mode mode);
    640   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
    641 
    642   Major MajorKey() { return RecordWrite; }
    643 
    644   int MinorKey() {
    645     return ObjectBits::encode(object_.code()) |
    646         ValueBits::encode(value_.code()) |
    647         AddressBits::encode(address_.code()) |
    648         RememberedSetActionBits::encode(remembered_set_action_) |
    649         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
    650   }
    651 
    652   void Activate(Code* code) {
    653     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    654   }
    655 
    656   class ObjectBits: public BitField<int, 0, 4> {};
    657   class ValueBits: public BitField<int, 4, 4> {};
    658   class AddressBits: public BitField<int, 8, 4> {};
    659   class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
    660   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
    661 
    662   Register object_;
    663   Register value_;
    664   Register address_;
    665   RememberedSetAction remembered_set_action_;
    666   SaveFPRegsMode save_fp_regs_mode_;
    667   Label slow_;
    668   RegisterAllocation regs_;
    669 };
    670 
    671 
    672 // Enter C code from generated RegExp code in a way that allows
    673 // the C code to fix the return address in case of a GC.
    674 // Currently only needed on ARM.
    675 class RegExpCEntryStub: public CodeStub {
    676  public:
    677   RegExpCEntryStub() {}
    678   virtual ~RegExpCEntryStub() {}
    679   void Generate(MacroAssembler* masm);
    680 
    681  private:
    682   Major MajorKey() { return RegExpCEntry; }
    683   int MinorKey() { return 0; }
    684 
    685   bool NeedsImmovableCode() { return true; }
    686 };
    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, ExternalReference function);
    699   void GenerateCall(MacroAssembler* masm, Register target);
    700 
    701  private:
    702   Major MajorKey() { return DirectCEntry; }
    703   int MinorKey() { return 0; }
    704 
    705   bool NeedsImmovableCode() { return true; }
    706 };
    707 
    708 
    709 class FloatingPointHelper : public AllStatic {
    710  public:
    711   enum Destination {
    712     kVFPRegisters,
    713     kCoreRegisters
    714   };
    715 
    716 
    717   // Loads smis from r0 and r1 (right and left in binary operations) into
    718   // floating point registers. Depending on the destination the values ends up
    719   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
    720   // floating point registers VFP3 must be supported. If core registers are
    721   // requested when VFP3 is supported d6 and d7 will be scratched.
    722   static void LoadSmis(MacroAssembler* masm,
    723                        Destination destination,
    724                        Register scratch1,
    725                        Register scratch2);
    726 
    727   // Loads objects from r0 and r1 (right and left in binary operations) into
    728   // floating point registers. Depending on the destination the values ends up
    729   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
    730   // floating point registers VFP3 must be supported. If core registers are
    731   // requested when VFP3 is supported d6 and d7 will still be scratched. If
    732   // either r0 or r1 is not a number (not smi and not heap number object) the
    733   // not_number label is jumped to with r0 and r1 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                                    DwVfpRegister 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                                  DwVfpRegister double_dst,
    762                                  Register dst1,
    763                                  Register dst2,
    764                                  Register scratch2,
    765                                  SwVfpRegister 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                                       DwVfpRegister double_dst,
    776                                       Register dst1,
    777                                       Register dst2,
    778                                       Register heap_number_map,
    779                                       Register scratch1,
    780                                       Register scratch2,
    781                                       SwVfpRegister 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 VFP3 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                                 DwVfpRegister double_scratch,
    798                                 Label* not_int32);
    799 
    800   // Generate non VFP3 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 VFP3 is not supported.)
    823   // This code never falls through, but returns with a heap number containing
    824   // the result in r0.
    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   // r0: Left value (least significant part of mantissa).
    829   // r1: Left value (sign, exponent, top of mantissa).
    830   // r2: Right value (least significant part of mantissa).
    831   // r3: 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                          DwVfpRegister 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_ARM_CODE_STUBS_ARM_H_
    904