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 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
     39 
     40 
     41 // Compute a transcendental math function natively, or call the
     42 // TranscendentalCache runtime function.
     43 class TranscendentalCacheStub: public PlatformCodeStub {
     44  public:
     45   enum ArgumentType {
     46     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
     47     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
     48   };
     49 
     50   TranscendentalCacheStub(TranscendentalCache::Type type,
     51                           ArgumentType argument_type)
     52       : type_(type), argument_type_(argument_type) { }
     53   void Generate(MacroAssembler* masm);
     54  private:
     55   TranscendentalCache::Type type_;
     56   ArgumentType argument_type_;
     57   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
     58 
     59   Major MajorKey() { return TranscendentalCache; }
     60   int MinorKey() { return type_ | argument_type_; }
     61   Runtime::FunctionId RuntimeFunction();
     62 };
     63 
     64 
     65 class StoreBufferOverflowStub: public PlatformCodeStub {
     66  public:
     67   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
     68       : save_doubles_(save_fp) {}
     69 
     70   void Generate(MacroAssembler* masm);
     71 
     72   virtual bool IsPregenerated() { return true; }
     73   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
     74   virtual bool SometimesSetsUpAFrame() { return false; }
     75 
     76  private:
     77   SaveFPRegsMode save_doubles_;
     78 
     79   Major MajorKey() { return StoreBufferOverflow; }
     80   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
     81 };
     82 
     83 
     84 class StringHelper : public AllStatic {
     85  public:
     86   // Generate code for copying characters using a simple loop. This should only
     87   // be used in places where the number of characters is small and the
     88   // additional setup and checking in GenerateCopyCharactersLong adds too much
     89   // overhead. Copying of overlapping regions is not supported.
     90   // Dest register ends at the position after the last character written.
     91   static void GenerateCopyCharacters(MacroAssembler* masm,
     92                                      Register dest,
     93                                      Register src,
     94                                      Register count,
     95                                      Register scratch,
     96                                      bool ascii);
     97 
     98   // Generate code for copying a large number of characters. This function
     99   // is allowed to spend extra time setting up conditions to make copying
    100   // faster. Copying of overlapping regions is not supported.
    101   // Dest register ends at the position after the last character written.
    102   static void GenerateCopyCharactersLong(MacroAssembler* masm,
    103                                          Register dest,
    104                                          Register src,
    105                                          Register count,
    106                                          Register scratch1,
    107                                          Register scratch2,
    108                                          Register scratch3,
    109                                          Register scratch4,
    110                                          Register scratch5,
    111                                          int flags);
    112 
    113 
    114   // Probe the string table for a two character string. If the string is
    115   // not found by probing a jump to the label not_found is performed. This jump
    116   // does not guarantee that the string is not in the string table. If the
    117   // string is found the code falls through with the string in register r0.
    118   // Contents of both c1 and c2 registers are modified. At the exit c1 is
    119   // guaranteed to contain halfword with low and high bytes equal to
    120   // initial contents of c1 and c2 respectively.
    121   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
    122                                                    Register c1,
    123                                                    Register c2,
    124                                                    Register scratch1,
    125                                                    Register scratch2,
    126                                                    Register scratch3,
    127                                                    Register scratch4,
    128                                                    Register scratch5,
    129                                                    Label* not_found);
    130 
    131   // Generate string hash.
    132   static void GenerateHashInit(MacroAssembler* masm,
    133                                Register hash,
    134                                Register character);
    135 
    136   static void GenerateHashAddCharacter(MacroAssembler* masm,
    137                                        Register hash,
    138                                        Register character);
    139 
    140   static void GenerateHashGetHash(MacroAssembler* masm,
    141                                   Register hash);
    142 
    143  private:
    144   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
    145 };
    146 
    147 
    148 class StringAddStub: public PlatformCodeStub {
    149  public:
    150   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    151 
    152  private:
    153   Major MajorKey() { return StringAdd; }
    154   int MinorKey() { return flags_; }
    155 
    156   void Generate(MacroAssembler* masm);
    157 
    158   void GenerateConvertArgument(MacroAssembler* masm,
    159                                int stack_offset,
    160                                Register arg,
    161                                Register scratch1,
    162                                Register scratch2,
    163                                Register scratch3,
    164                                Register scratch4,
    165                                Label* slow);
    166 
    167   void GenerateRegisterArgsPush(MacroAssembler* masm);
    168   void GenerateRegisterArgsPop(MacroAssembler* masm);
    169 
    170   const StringAddFlags flags_;
    171 };
    172 
    173 
    174 class SubStringStub: public PlatformCodeStub {
    175  public:
    176   SubStringStub() {}
    177 
    178  private:
    179   Major MajorKey() { return SubString; }
    180   int MinorKey() { return 0; }
    181 
    182   void Generate(MacroAssembler* masm);
    183 };
    184 
    185 
    186 class StringCompareStub: public PlatformCodeStub {
    187  public:
    188   StringCompareStub() { }
    189 
    190   // Compare two flat ASCII strings and returns result in v0.
    191   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    192                                               Register left,
    193                                               Register right,
    194                                               Register scratch1,
    195                                               Register scratch2,
    196                                               Register scratch3,
    197                                               Register scratch4);
    198 
    199   // Compares two flat ASCII strings for equality and returns result
    200   // in v0.
    201   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
    202                                             Register left,
    203                                             Register right,
    204                                             Register scratch1,
    205                                             Register scratch2,
    206                                             Register scratch3);
    207 
    208  private:
    209   virtual Major MajorKey() { return StringCompare; }
    210   virtual int MinorKey() { return 0; }
    211   virtual void Generate(MacroAssembler* masm);
    212 
    213   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
    214                                             Register left,
    215                                             Register right,
    216                                             Register length,
    217                                             Register scratch1,
    218                                             Register scratch2,
    219                                             Register scratch3,
    220                                             Label* chars_not_equal);
    221 };
    222 
    223 
    224 // This stub can convert a signed int32 to a heap number (double).  It does
    225 // not work for int32s that are in Smi range!  No GC occurs during this stub
    226 // so you don't have to set up the frame.
    227 class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
    228  public:
    229   WriteInt32ToHeapNumberStub(Register the_int,
    230                              Register the_heap_number,
    231                              Register scratch,
    232                              Register scratch2)
    233       : the_int_(the_int),
    234         the_heap_number_(the_heap_number),
    235         scratch_(scratch),
    236         sign_(scratch2) {
    237     ASSERT(IntRegisterBits::is_valid(the_int_.code()));
    238     ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
    239     ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
    240     ASSERT(SignRegisterBits::is_valid(sign_.code()));
    241   }
    242 
    243   bool IsPregenerated();
    244   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
    245 
    246  private:
    247   Register the_int_;
    248   Register the_heap_number_;
    249   Register scratch_;
    250   Register sign_;
    251 
    252   // Minor key encoding in 16 bits.
    253   class IntRegisterBits: public BitField<int, 0, 4> {};
    254   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
    255   class ScratchRegisterBits: public BitField<int, 8, 4> {};
    256   class SignRegisterBits: public BitField<int, 12, 4> {};
    257 
    258   Major MajorKey() { return WriteInt32ToHeapNumber; }
    259   int MinorKey() {
    260     // Encode the parameters in a unique 16 bit value.
    261     return IntRegisterBits::encode(the_int_.code())
    262            | HeapNumberRegisterBits::encode(the_heap_number_.code())
    263            | ScratchRegisterBits::encode(scratch_.code())
    264            | SignRegisterBits::encode(sign_.code());
    265   }
    266 
    267   void Generate(MacroAssembler* masm);
    268 };
    269 
    270 
    271 class NumberToStringStub: public PlatformCodeStub {
    272  public:
    273   NumberToStringStub() { }
    274 
    275   // Generate code to do a lookup in the number string cache. If the number in
    276   // the register object is found in the cache the generated code falls through
    277   // with the result in the result register. The object and the result register
    278   // can be the same. If the number is not found in the cache the code jumps to
    279   // the label not_found with only the content of register object unchanged.
    280   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
    281                                               Register object,
    282                                               Register result,
    283                                               Register scratch1,
    284                                               Register scratch2,
    285                                               Register scratch3,
    286                                               Label* not_found);
    287 
    288  private:
    289   Major MajorKey() { return NumberToString; }
    290   int MinorKey() { return 0; }
    291 
    292   void Generate(MacroAssembler* masm);
    293 };
    294 
    295 
    296 class RecordWriteStub: public PlatformCodeStub {
    297  public:
    298   RecordWriteStub(Register object,
    299                   Register value,
    300                   Register address,
    301                   RememberedSetAction remembered_set_action,
    302                   SaveFPRegsMode fp_mode)
    303       : object_(object),
    304         value_(value),
    305         address_(address),
    306         remembered_set_action_(remembered_set_action),
    307         save_fp_regs_mode_(fp_mode),
    308         regs_(object,   // An input reg.
    309               address,  // An input reg.
    310               value) {  // One scratch reg.
    311   }
    312 
    313   enum Mode {
    314     STORE_BUFFER_ONLY,
    315     INCREMENTAL,
    316     INCREMENTAL_COMPACTION
    317   };
    318 
    319   virtual bool IsPregenerated();
    320   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
    321   virtual bool SometimesSetsUpAFrame() { return false; }
    322 
    323   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    324     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    325     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
    326         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    327     ASSERT(Assembler::IsBne(masm->instr_at(pos)));
    328   }
    329 
    330   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    331     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    332     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
    333         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    334     ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
    335   }
    336 
    337   static Mode GetMode(Code* stub) {
    338     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
    339     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    340                                                    2 * Assembler::kInstrSize);
    341 
    342     if (Assembler::IsBeq(first_instruction)) {
    343       return INCREMENTAL;
    344     }
    345 
    346     ASSERT(Assembler::IsBne(first_instruction));
    347 
    348     if (Assembler::IsBeq(second_instruction)) {
    349       return INCREMENTAL_COMPACTION;
    350     }
    351 
    352     ASSERT(Assembler::IsBne(second_instruction));
    353 
    354     return STORE_BUFFER_ONLY;
    355   }
    356 
    357   static void Patch(Code* stub, Mode mode) {
    358     MacroAssembler masm(NULL,
    359                         stub->instruction_start(),
    360                         stub->instruction_size());
    361     switch (mode) {
    362       case STORE_BUFFER_ONLY:
    363         ASSERT(GetMode(stub) == INCREMENTAL ||
    364                GetMode(stub) == INCREMENTAL_COMPACTION);
    365         PatchBranchIntoNop(&masm, 0);
    366         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
    367         break;
    368       case INCREMENTAL:
    369         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    370         PatchNopIntoBranch(&masm, 0);
    371         break;
    372       case INCREMENTAL_COMPACTION:
    373         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    374         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
    375         break;
    376     }
    377     ASSERT(GetMode(stub) == mode);
    378     CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
    379   }
    380 
    381  private:
    382   // This is a helper class for freeing up 3 scratch registers.  The input is
    383   // two registers that must be preserved and one scratch register provided by
    384   // the caller.
    385   class RegisterAllocation {
    386    public:
    387     RegisterAllocation(Register object,
    388                        Register address,
    389                        Register scratch0)
    390         : object_(object),
    391           address_(address),
    392           scratch0_(scratch0) {
    393       ASSERT(!AreAliased(scratch0, object, address, no_reg));
    394       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
    395     }
    396 
    397     void Save(MacroAssembler* masm) {
    398       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
    399       // We don't have to save scratch0_ because it was given to us as
    400       // a scratch register.
    401       masm->push(scratch1_);
    402     }
    403 
    404     void Restore(MacroAssembler* masm) {
    405       masm->pop(scratch1_);
    406     }
    407 
    408     // If we have to call into C then we need to save and restore all caller-
    409     // saved registers that were not already preserved.  The scratch registers
    410     // will be restored by other means so we don't bother pushing them here.
    411     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    412       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    413       if (mode == kSaveFPRegs) {
    414         masm->MultiPushFPU(kCallerSavedFPU);
    415       }
    416     }
    417 
    418     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    419                                            SaveFPRegsMode mode) {
    420       if (mode == kSaveFPRegs) {
    421         masm->MultiPopFPU(kCallerSavedFPU);
    422       }
    423       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    424     }
    425 
    426     inline Register object() { return object_; }
    427     inline Register address() { return address_; }
    428     inline Register scratch0() { return scratch0_; }
    429     inline Register scratch1() { return scratch1_; }
    430 
    431    private:
    432     Register object_;
    433     Register address_;
    434     Register scratch0_;
    435     Register scratch1_;
    436 
    437     Register GetRegThatIsNotOneOf(Register r1,
    438                                   Register r2,
    439                                   Register r3) {
    440       for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
    441         Register candidate = Register::FromAllocationIndex(i);
    442         if (candidate.is(r1)) continue;
    443         if (candidate.is(r2)) continue;
    444         if (candidate.is(r3)) continue;
    445         return candidate;
    446       }
    447       UNREACHABLE();
    448       return no_reg;
    449     }
    450     friend class RecordWriteStub;
    451   };
    452 
    453   enum OnNoNeedToInformIncrementalMarker {
    454     kReturnOnNoNeedToInformIncrementalMarker,
    455     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    456   };
    457 
    458   void Generate(MacroAssembler* masm);
    459   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    460   void CheckNeedsToInformIncrementalMarker(
    461       MacroAssembler* masm,
    462       OnNoNeedToInformIncrementalMarker on_no_need,
    463       Mode mode);
    464   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
    465 
    466   Major MajorKey() { return RecordWrite; }
    467 
    468   int MinorKey() {
    469     return ObjectBits::encode(object_.code()) |
    470         ValueBits::encode(value_.code()) |
    471         AddressBits::encode(address_.code()) |
    472         RememberedSetActionBits::encode(remembered_set_action_) |
    473         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
    474   }
    475 
    476   void Activate(Code* code) {
    477     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    478   }
    479 
    480   class ObjectBits: public BitField<int, 0, 5> {};
    481   class ValueBits: public BitField<int, 5, 5> {};
    482   class AddressBits: public BitField<int, 10, 5> {};
    483   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
    484   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
    485 
    486   Register object_;
    487   Register value_;
    488   Register address_;
    489   RememberedSetAction remembered_set_action_;
    490   SaveFPRegsMode save_fp_regs_mode_;
    491   Label slow_;
    492   RegisterAllocation regs_;
    493 };
    494 
    495 
    496 // Enter C code from generated RegExp code in a way that allows
    497 // the C code to fix the return address in case of a GC.
    498 // Currently only needed on ARM and MIPS.
    499 class RegExpCEntryStub: public PlatformCodeStub {
    500  public:
    501   RegExpCEntryStub() {}
    502   virtual ~RegExpCEntryStub() {}
    503   void Generate(MacroAssembler* masm);
    504 
    505  private:
    506   Major MajorKey() { return RegExpCEntry; }
    507   int MinorKey() { return 0; }
    508 
    509   bool NeedsImmovableCode() { return true; }
    510 };
    511 
    512 // Trampoline stub to call into native code. To call safely into native code
    513 // in the presence of compacting GC (which can move code objects) we need to
    514 // keep the code which called into native pinned in the memory. Currently the
    515 // simplest approach is to generate such stub early enough so it can never be
    516 // moved by GC
    517 class DirectCEntryStub: public PlatformCodeStub {
    518  public:
    519   DirectCEntryStub() {}
    520   void Generate(MacroAssembler* masm);
    521   void GenerateCall(MacroAssembler* masm, Register target);
    522 
    523  private:
    524   Major MajorKey() { return DirectCEntry; }
    525   int MinorKey() { return 0; }
    526 
    527   bool NeedsImmovableCode() { return true; }
    528 };
    529 
    530 class FloatingPointHelper : public AllStatic {
    531  public:
    532   enum Destination {
    533     kFPURegisters,
    534     kCoreRegisters
    535   };
    536 
    537 
    538   // Loads smis from a0 and a1 (right and left in binary operations) into
    539   // floating point registers. Depending on the destination the values ends up
    540   // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
    541   // is floating point registers FPU must be supported. If core registers are
    542   // requested when FPU is supported f12 and f14 will be scratched.
    543   static void LoadSmis(MacroAssembler* masm,
    544                        Destination destination,
    545                        Register scratch1,
    546                        Register scratch2);
    547 
    548   // Convert the smi or heap number in object to an int32 using the rules
    549   // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
    550   // and brought into the range -2^31 .. +2^31 - 1.
    551   static void ConvertNumberToInt32(MacroAssembler* masm,
    552                                    Register object,
    553                                    Register dst,
    554                                    Register heap_number_map,
    555                                    Register scratch1,
    556                                    Register scratch2,
    557                                    Register scratch3,
    558                                    FPURegister double_scratch,
    559                                    Label* not_int32);
    560 
    561   // Converts the integer (untagged smi) in |int_scratch| to a double, storing
    562   // the result either in |double_dst| or |dst2:dst1|, depending on
    563   // |destination|.
    564   // Warning: The value in |int_scratch| will be changed in the process!
    565   static void ConvertIntToDouble(MacroAssembler* masm,
    566                                  Register int_scratch,
    567                                  Destination destination,
    568                                  FPURegister double_dst,
    569                                  Register dst1,
    570                                  Register dst2,
    571                                  Register scratch2,
    572                                  FPURegister single_scratch);
    573 
    574   // Load the number from object into double_dst in the double format.
    575   // Control will jump to not_int32 if the value cannot be exactly represented
    576   // by a 32-bit integer.
    577   // Floating point value in the 32-bit integer range that are not exact integer
    578   // won't be loaded.
    579   static void LoadNumberAsInt32Double(MacroAssembler* masm,
    580                                       Register object,
    581                                       Destination destination,
    582                                       FPURegister double_dst,
    583                                       FPURegister double_scratch,
    584                                       Register dst1,
    585                                       Register dst2,
    586                                       Register heap_number_map,
    587                                       Register scratch1,
    588                                       Register scratch2,
    589                                       FPURegister single_scratch,
    590                                       Label* not_int32);
    591 
    592   // Loads the number from object into dst as a 32-bit integer.
    593   // Control will jump to not_int32 if the object cannot be exactly represented
    594   // by a 32-bit integer.
    595   // Floating point value in the 32-bit integer range that are not exact integer
    596   // won't be converted.
    597   // scratch3 is not used when FPU is supported.
    598   static void LoadNumberAsInt32(MacroAssembler* masm,
    599                                 Register object,
    600                                 Register dst,
    601                                 Register heap_number_map,
    602                                 Register scratch1,
    603                                 Register scratch2,
    604                                 Register scratch3,
    605                                 FPURegister double_scratch0,
    606                                 FPURegister double_scratch1,
    607                                 Label* not_int32);
    608 
    609   // Generates code to call a C function to do a double operation using core
    610   // registers. (Used when FPU is not supported.)
    611   // This code never falls through, but returns with a heap number containing
    612   // the result in v0.
    613   // Register heapnumber_result must be a heap number in which the
    614   // result of the operation will be stored.
    615   // Requires the following layout on entry:
    616   // a0: Left value (least significant part of mantissa).
    617   // a1: Left value (sign, exponent, top of mantissa).
    618   // a2: Right value (least significant part of mantissa).
    619   // a3: Right value (sign, exponent, top of mantissa).
    620   static void CallCCodeForDoubleOperation(MacroAssembler* masm,
    621                                           Token::Value op,
    622                                           Register heap_number_result,
    623                                           Register scratch);
    624 
    625   // Loads the objects from |object| into floating point registers.
    626   // Depending on |destination| the value ends up either in |dst| or
    627   // in |dst1|/|dst2|. If |destination| is kFPURegisters, then FPU
    628   // must be supported. If kCoreRegisters are requested and FPU is
    629   // supported, |dst| will be scratched. If |object| is neither smi nor
    630   // heap number, |not_number| is jumped to with |object| still intact.
    631   static void LoadNumber(MacroAssembler* masm,
    632                          FloatingPointHelper::Destination destination,
    633                          Register object,
    634                          FPURegister dst,
    635                          Register dst1,
    636                          Register dst2,
    637                          Register heap_number_map,
    638                          Register scratch1,
    639                          Register scratch2,
    640                          Label* not_number);
    641 };
    642 
    643 
    644 class NameDictionaryLookupStub: public PlatformCodeStub {
    645  public:
    646   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
    647 
    648   explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
    649 
    650   void Generate(MacroAssembler* masm);
    651 
    652   static void GenerateNegativeLookup(MacroAssembler* masm,
    653                                      Label* miss,
    654                                      Label* done,
    655                                      Register receiver,
    656                                      Register properties,
    657                                      Handle<Name> name,
    658                                      Register scratch0);
    659 
    660   static void GeneratePositiveLookup(MacroAssembler* masm,
    661                                      Label* miss,
    662                                      Label* done,
    663                                      Register elements,
    664                                      Register name,
    665                                      Register r0,
    666                                      Register r1);
    667 
    668   virtual bool SometimesSetsUpAFrame() { return false; }
    669 
    670  private:
    671   static const int kInlinedProbes = 4;
    672   static const int kTotalProbes = 20;
    673 
    674   static const int kCapacityOffset =
    675       NameDictionary::kHeaderSize +
    676       NameDictionary::kCapacityIndex * kPointerSize;
    677 
    678   static const int kElementsStartOffset =
    679       NameDictionary::kHeaderSize +
    680       NameDictionary::kElementsStartIndex * kPointerSize;
    681 
    682   Major MajorKey() { return NameDictionaryLookup; }
    683 
    684   int MinorKey() {
    685     return LookupModeBits::encode(mode_);
    686   }
    687 
    688   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
    689 
    690   LookupMode mode_;
    691 };
    692 
    693 
    694 } }  // namespace v8::internal
    695 
    696 #endif  // V8_MIPS_CODE_STUBS_ARM_H_
    697