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   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
     73   virtual bool SometimesSetsUpAFrame() { return false; }
     74 
     75  private:
     76   SaveFPRegsMode save_doubles_;
     77 
     78   Major MajorKey() { return StoreBufferOverflow; }
     79   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
     80 };
     81 
     82 
     83 class StringHelper : public AllStatic {
     84  public:
     85   // Generate code for copying characters using a simple loop. This should only
     86   // be used in places where the number of characters is small and the
     87   // additional setup and checking in GenerateCopyCharactersLong adds too much
     88   // overhead. Copying of overlapping regions is not supported.
     89   // Dest register ends at the position after the last character written.
     90   static void GenerateCopyCharacters(MacroAssembler* masm,
     91                                      Register dest,
     92                                      Register src,
     93                                      Register count,
     94                                      Register scratch,
     95                                      bool ascii);
     96 
     97   // Generate code for copying a large number of characters. This function
     98   // is allowed to spend extra time setting up conditions to make copying
     99   // faster. Copying of overlapping regions is not supported.
    100   // Dest register ends at the position after the last character written.
    101   static void GenerateCopyCharactersLong(MacroAssembler* masm,
    102                                          Register dest,
    103                                          Register src,
    104                                          Register count,
    105                                          Register scratch1,
    106                                          Register scratch2,
    107                                          Register scratch3,
    108                                          Register scratch4,
    109                                          Register scratch5,
    110                                          int flags);
    111 
    112 
    113   // Probe the string table for a two character string. If the string is
    114   // not found by probing a jump to the label not_found is performed. This jump
    115   // does not guarantee that the string is not in the string table. If the
    116   // string is found the code falls through with the string in register r0.
    117   // Contents of both c1 and c2 registers are modified. At the exit c1 is
    118   // guaranteed to contain halfword with low and high bytes equal to
    119   // initial contents of c1 and c2 respectively.
    120   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
    121                                                    Register c1,
    122                                                    Register c2,
    123                                                    Register scratch1,
    124                                                    Register scratch2,
    125                                                    Register scratch3,
    126                                                    Register scratch4,
    127                                                    Register scratch5,
    128                                                    Label* not_found);
    129 
    130   // Generate string hash.
    131   static void GenerateHashInit(MacroAssembler* masm,
    132                                Register hash,
    133                                Register character);
    134 
    135   static void GenerateHashAddCharacter(MacroAssembler* masm,
    136                                        Register hash,
    137                                        Register character);
    138 
    139   static void GenerateHashGetHash(MacroAssembler* masm,
    140                                   Register hash);
    141 
    142  private:
    143   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
    144 };
    145 
    146 
    147 class StringAddStub: public PlatformCodeStub {
    148  public:
    149   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    150 
    151  private:
    152   Major MajorKey() { return StringAdd; }
    153   int MinorKey() { return flags_; }
    154 
    155   void Generate(MacroAssembler* masm);
    156 
    157   void GenerateConvertArgument(MacroAssembler* masm,
    158                                int stack_offset,
    159                                Register arg,
    160                                Register scratch1,
    161                                Register scratch2,
    162                                Register scratch3,
    163                                Register scratch4,
    164                                Label* slow);
    165 
    166   void GenerateRegisterArgsPush(MacroAssembler* masm);
    167   void GenerateRegisterArgsPop(MacroAssembler* masm);
    168 
    169   const StringAddFlags flags_;
    170 };
    171 
    172 
    173 class SubStringStub: public PlatformCodeStub {
    174  public:
    175   SubStringStub() {}
    176 
    177  private:
    178   Major MajorKey() { return SubString; }
    179   int MinorKey() { return 0; }
    180 
    181   void Generate(MacroAssembler* masm);
    182 };
    183 
    184 
    185 class StringCompareStub: public PlatformCodeStub {
    186  public:
    187   StringCompareStub() { }
    188 
    189   // Compare two flat ASCII strings and returns result in v0.
    190   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    191                                               Register left,
    192                                               Register right,
    193                                               Register scratch1,
    194                                               Register scratch2,
    195                                               Register scratch3,
    196                                               Register scratch4);
    197 
    198   // Compares two flat ASCII strings for equality and returns result
    199   // in v0.
    200   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
    201                                             Register left,
    202                                             Register right,
    203                                             Register scratch1,
    204                                             Register scratch2,
    205                                             Register scratch3);
    206 
    207  private:
    208   virtual Major MajorKey() { return StringCompare; }
    209   virtual int MinorKey() { return 0; }
    210   virtual void Generate(MacroAssembler* masm);
    211 
    212   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
    213                                             Register left,
    214                                             Register right,
    215                                             Register length,
    216                                             Register scratch1,
    217                                             Register scratch2,
    218                                             Register scratch3,
    219                                             Label* chars_not_equal);
    220 };
    221 
    222 
    223 // This stub can convert a signed int32 to a heap number (double).  It does
    224 // not work for int32s that are in Smi range!  No GC occurs during this stub
    225 // so you don't have to set up the frame.
    226 class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
    227  public:
    228   WriteInt32ToHeapNumberStub(Register the_int,
    229                              Register the_heap_number,
    230                              Register scratch,
    231                              Register scratch2)
    232       : the_int_(the_int),
    233         the_heap_number_(the_heap_number),
    234         scratch_(scratch),
    235         sign_(scratch2) {
    236     ASSERT(IntRegisterBits::is_valid(the_int_.code()));
    237     ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
    238     ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
    239     ASSERT(SignRegisterBits::is_valid(sign_.code()));
    240   }
    241 
    242   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
    243 
    244  private:
    245   Register the_int_;
    246   Register the_heap_number_;
    247   Register scratch_;
    248   Register sign_;
    249 
    250   // Minor key encoding in 16 bits.
    251   class IntRegisterBits: public BitField<int, 0, 4> {};
    252   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
    253   class ScratchRegisterBits: public BitField<int, 8, 4> {};
    254   class SignRegisterBits: public BitField<int, 12, 4> {};
    255 
    256   Major MajorKey() { return WriteInt32ToHeapNumber; }
    257   int MinorKey() {
    258     // Encode the parameters in a unique 16 bit value.
    259     return IntRegisterBits::encode(the_int_.code())
    260            | HeapNumberRegisterBits::encode(the_heap_number_.code())
    261            | ScratchRegisterBits::encode(scratch_.code())
    262            | SignRegisterBits::encode(sign_.code());
    263   }
    264 
    265   void Generate(MacroAssembler* masm);
    266 };
    267 
    268 
    269 class RecordWriteStub: public PlatformCodeStub {
    270  public:
    271   RecordWriteStub(Register object,
    272                   Register value,
    273                   Register address,
    274                   RememberedSetAction remembered_set_action,
    275                   SaveFPRegsMode fp_mode)
    276       : object_(object),
    277         value_(value),
    278         address_(address),
    279         remembered_set_action_(remembered_set_action),
    280         save_fp_regs_mode_(fp_mode),
    281         regs_(object,   // An input reg.
    282               address,  // An input reg.
    283               value) {  // One scratch reg.
    284   }
    285 
    286   enum Mode {
    287     STORE_BUFFER_ONLY,
    288     INCREMENTAL,
    289     INCREMENTAL_COMPACTION
    290   };
    291 
    292   virtual bool SometimesSetsUpAFrame() { return false; }
    293 
    294   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    295     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    296     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
    297         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    298     ASSERT(Assembler::IsBne(masm->instr_at(pos)));
    299   }
    300 
    301   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    302     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    303     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
    304         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    305     ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
    306   }
    307 
    308   static Mode GetMode(Code* stub) {
    309     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
    310     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    311                                                    2 * Assembler::kInstrSize);
    312 
    313     if (Assembler::IsBeq(first_instruction)) {
    314       return INCREMENTAL;
    315     }
    316 
    317     ASSERT(Assembler::IsBne(first_instruction));
    318 
    319     if (Assembler::IsBeq(second_instruction)) {
    320       return INCREMENTAL_COMPACTION;
    321     }
    322 
    323     ASSERT(Assembler::IsBne(second_instruction));
    324 
    325     return STORE_BUFFER_ONLY;
    326   }
    327 
    328   static void Patch(Code* stub, Mode mode) {
    329     MacroAssembler masm(NULL,
    330                         stub->instruction_start(),
    331                         stub->instruction_size());
    332     switch (mode) {
    333       case STORE_BUFFER_ONLY:
    334         ASSERT(GetMode(stub) == INCREMENTAL ||
    335                GetMode(stub) == INCREMENTAL_COMPACTION);
    336         PatchBranchIntoNop(&masm, 0);
    337         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
    338         break;
    339       case INCREMENTAL:
    340         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    341         PatchNopIntoBranch(&masm, 0);
    342         break;
    343       case INCREMENTAL_COMPACTION:
    344         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    345         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
    346         break;
    347     }
    348     ASSERT(GetMode(stub) == mode);
    349     CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
    350   }
    351 
    352  private:
    353   // This is a helper class for freeing up 3 scratch registers.  The input is
    354   // two registers that must be preserved and one scratch register provided by
    355   // the caller.
    356   class RegisterAllocation {
    357    public:
    358     RegisterAllocation(Register object,
    359                        Register address,
    360                        Register scratch0)
    361         : object_(object),
    362           address_(address),
    363           scratch0_(scratch0) {
    364       ASSERT(!AreAliased(scratch0, object, address, no_reg));
    365       scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
    366     }
    367 
    368     void Save(MacroAssembler* masm) {
    369       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
    370       // We don't have to save scratch0_ because it was given to us as
    371       // a scratch register.
    372       masm->push(scratch1_);
    373     }
    374 
    375     void Restore(MacroAssembler* masm) {
    376       masm->pop(scratch1_);
    377     }
    378 
    379     // If we have to call into C then we need to save and restore all caller-
    380     // saved registers that were not already preserved.  The scratch registers
    381     // will be restored by other means so we don't bother pushing them here.
    382     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    383       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    384       if (mode == kSaveFPRegs) {
    385         masm->MultiPushFPU(kCallerSavedFPU);
    386       }
    387     }
    388 
    389     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    390                                            SaveFPRegsMode mode) {
    391       if (mode == kSaveFPRegs) {
    392         masm->MultiPopFPU(kCallerSavedFPU);
    393       }
    394       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    395     }
    396 
    397     inline Register object() { return object_; }
    398     inline Register address() { return address_; }
    399     inline Register scratch0() { return scratch0_; }
    400     inline Register scratch1() { return scratch1_; }
    401 
    402    private:
    403     Register object_;
    404     Register address_;
    405     Register scratch0_;
    406     Register scratch1_;
    407 
    408     friend class RecordWriteStub;
    409   };
    410 
    411   enum OnNoNeedToInformIncrementalMarker {
    412     kReturnOnNoNeedToInformIncrementalMarker,
    413     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    414   };
    415 
    416   void Generate(MacroAssembler* masm);
    417   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    418   void CheckNeedsToInformIncrementalMarker(
    419       MacroAssembler* masm,
    420       OnNoNeedToInformIncrementalMarker on_no_need,
    421       Mode mode);
    422   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
    423 
    424   Major MajorKey() { return RecordWrite; }
    425 
    426   int MinorKey() {
    427     return ObjectBits::encode(object_.code()) |
    428         ValueBits::encode(value_.code()) |
    429         AddressBits::encode(address_.code()) |
    430         RememberedSetActionBits::encode(remembered_set_action_) |
    431         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
    432   }
    433 
    434   void Activate(Code* code) {
    435     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    436   }
    437 
    438   class ObjectBits: public BitField<int, 0, 5> {};
    439   class ValueBits: public BitField<int, 5, 5> {};
    440   class AddressBits: public BitField<int, 10, 5> {};
    441   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
    442   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
    443 
    444   Register object_;
    445   Register value_;
    446   Register address_;
    447   RememberedSetAction remembered_set_action_;
    448   SaveFPRegsMode save_fp_regs_mode_;
    449   Label slow_;
    450   RegisterAllocation regs_;
    451 };
    452 
    453 
    454 // Trampoline stub to call into native code. To call safely into native code
    455 // in the presence of compacting GC (which can move code objects) we need to
    456 // keep the code which called into native pinned in the memory. Currently the
    457 // simplest approach is to generate such stub early enough so it can never be
    458 // moved by GC
    459 class DirectCEntryStub: public PlatformCodeStub {
    460  public:
    461   DirectCEntryStub() {}
    462   void Generate(MacroAssembler* masm);
    463   void GenerateCall(MacroAssembler* masm, Register target);
    464 
    465  private:
    466   Major MajorKey() { return DirectCEntry; }
    467   int MinorKey() { return 0; }
    468 
    469   bool NeedsImmovableCode() { return true; }
    470 };
    471 
    472 
    473 class NameDictionaryLookupStub: public PlatformCodeStub {
    474  public:
    475   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
    476 
    477   explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
    478 
    479   void Generate(MacroAssembler* masm);
    480 
    481   static void GenerateNegativeLookup(MacroAssembler* masm,
    482                                      Label* miss,
    483                                      Label* done,
    484                                      Register receiver,
    485                                      Register properties,
    486                                      Handle<Name> name,
    487                                      Register scratch0);
    488 
    489   static void GeneratePositiveLookup(MacroAssembler* masm,
    490                                      Label* miss,
    491                                      Label* done,
    492                                      Register elements,
    493                                      Register name,
    494                                      Register r0,
    495                                      Register r1);
    496 
    497   virtual bool SometimesSetsUpAFrame() { return false; }
    498 
    499  private:
    500   static const int kInlinedProbes = 4;
    501   static const int kTotalProbes = 20;
    502 
    503   static const int kCapacityOffset =
    504       NameDictionary::kHeaderSize +
    505       NameDictionary::kCapacityIndex * kPointerSize;
    506 
    507   static const int kElementsStartOffset =
    508       NameDictionary::kHeaderSize +
    509       NameDictionary::kElementsStartIndex * kPointerSize;
    510 
    511   Major MajorKey() { return NameDictionaryLookup; }
    512 
    513   int MinorKey() {
    514     return LookupModeBits::encode(mode_);
    515   }
    516 
    517   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
    518 
    519   LookupMode mode_;
    520 };
    521 
    522 
    523 } }  // namespace v8::internal
    524 
    525 #endif  // V8_MIPS_CODE_STUBS_ARM_H_
    526