Home | History | Annotate | Download | only in mips
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_MIPS_CODE_STUBS_MIPS_H_
      6 #define V8_MIPS_CODE_STUBS_MIPS_H_
      7 
      8 #include "src/mips/frames-mips.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 
     14 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
     15 
     16 
     17 class StringHelper : public AllStatic {
     18  public:
     19   // Compares two flat one-byte strings and returns result in v0.
     20   static void GenerateCompareFlatOneByteStrings(
     21       MacroAssembler* masm, Register left, Register right, Register scratch1,
     22       Register scratch2, Register scratch3, Register scratch4);
     23 
     24   // Compares two flat one-byte strings for equality and returns result in v0.
     25   static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
     26                                               Register left, Register right,
     27                                               Register scratch1,
     28                                               Register scratch2,
     29                                               Register scratch3);
     30 
     31  private:
     32   static void GenerateOneByteCharsCompareLoop(
     33       MacroAssembler* masm, Register left, Register right, Register length,
     34       Register scratch1, Register scratch2, Register scratch3,
     35       Label* chars_not_equal);
     36 
     37   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
     38 };
     39 
     40 
     41 class StoreRegistersStateStub: public PlatformCodeStub {
     42  public:
     43   explicit StoreRegistersStateStub(Isolate* isolate)
     44       : PlatformCodeStub(isolate) {}
     45 
     46   static void GenerateAheadOfTime(Isolate* isolate);
     47 
     48  private:
     49   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
     50   DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
     51 };
     52 
     53 
     54 class RestoreRegistersStateStub: public PlatformCodeStub {
     55  public:
     56   explicit RestoreRegistersStateStub(Isolate* isolate)
     57       : PlatformCodeStub(isolate) {}
     58 
     59   static void GenerateAheadOfTime(Isolate* isolate);
     60 
     61  private:
     62   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
     63   DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
     64 };
     65 
     66 
     67 class RecordWriteStub: public PlatformCodeStub {
     68  public:
     69   RecordWriteStub(Isolate* isolate,
     70                   Register object,
     71                   Register value,
     72                   Register address,
     73                   RememberedSetAction remembered_set_action,
     74                   SaveFPRegsMode fp_mode)
     75       : PlatformCodeStub(isolate),
     76         regs_(object,   // An input reg.
     77               address,  // An input reg.
     78               value) {  // One scratch reg.
     79     minor_key_ = ObjectBits::encode(object.code()) |
     80                  ValueBits::encode(value.code()) |
     81                  AddressBits::encode(address.code()) |
     82                  RememberedSetActionBits::encode(remembered_set_action) |
     83                  SaveFPRegsModeBits::encode(fp_mode);
     84   }
     85 
     86   RecordWriteStub(uint32_t key, Isolate* isolate)
     87       : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
     88 
     89   enum Mode {
     90     STORE_BUFFER_ONLY,
     91     INCREMENTAL,
     92     INCREMENTAL_COMPACTION
     93   };
     94 
     95   bool SometimesSetsUpAFrame() override { return false; }
     96 
     97   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
     98     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
     99     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
    100         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    101     DCHECK(Assembler::IsBne(masm->instr_at(pos)));
    102   }
    103 
    104   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    105     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
    106     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
    107         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
    108     DCHECK(Assembler::IsBeq(masm->instr_at(pos)));
    109   }
    110 
    111   static Mode GetMode(Code* stub) {
    112     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
    113     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    114                                                    2 * Assembler::kInstrSize);
    115 
    116     if (Assembler::IsBeq(first_instruction)) {
    117       return INCREMENTAL;
    118     }
    119 
    120     DCHECK(Assembler::IsBne(first_instruction));
    121 
    122     if (Assembler::IsBeq(second_instruction)) {
    123       return INCREMENTAL_COMPACTION;
    124     }
    125 
    126     DCHECK(Assembler::IsBne(second_instruction));
    127 
    128     return STORE_BUFFER_ONLY;
    129   }
    130 
    131   static void Patch(Code* stub, Mode mode) {
    132     MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
    133                         stub->instruction_size(), CodeObjectRequired::kNo);
    134     switch (mode) {
    135       case STORE_BUFFER_ONLY:
    136         DCHECK(GetMode(stub) == INCREMENTAL ||
    137                GetMode(stub) == INCREMENTAL_COMPACTION);
    138         PatchBranchIntoNop(&masm, 0);
    139         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
    140         break;
    141       case INCREMENTAL:
    142         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    143         PatchNopIntoBranch(&masm, 0);
    144         break;
    145       case INCREMENTAL_COMPACTION:
    146         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    147         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
    148         break;
    149     }
    150     DCHECK(GetMode(stub) == mode);
    151     Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
    152                            4 * Assembler::kInstrSize);
    153   }
    154 
    155   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    156 
    157  private:
    158   // This is a helper class for freeing up 3 scratch registers.  The input is
    159   // two registers that must be preserved and one scratch register provided by
    160   // the caller.
    161   class RegisterAllocation {
    162    public:
    163     RegisterAllocation(Register object,
    164                        Register address,
    165                        Register scratch0)
    166         : object_(object),
    167           address_(address),
    168           scratch0_(scratch0) {
    169       DCHECK(!AreAliased(scratch0, object, address, no_reg));
    170       scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
    171     }
    172 
    173     void Save(MacroAssembler* masm) {
    174       DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
    175       // We don't have to save scratch0_ because it was given to us as
    176       // a scratch register.
    177       masm->push(scratch1_);
    178     }
    179 
    180     void Restore(MacroAssembler* masm) {
    181       masm->pop(scratch1_);
    182     }
    183 
    184     // If we have to call into C then we need to save and restore all caller-
    185     // saved registers that were not already preserved.  The scratch registers
    186     // will be restored by other means so we don't bother pushing them here.
    187     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    188       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    189       if (mode == kSaveFPRegs) {
    190         masm->MultiPushFPU(kCallerSavedFPU);
    191       }
    192     }
    193 
    194     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    195                                            SaveFPRegsMode mode) {
    196       if (mode == kSaveFPRegs) {
    197         masm->MultiPopFPU(kCallerSavedFPU);
    198       }
    199       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
    200     }
    201 
    202     inline Register object() { return object_; }
    203     inline Register address() { return address_; }
    204     inline Register scratch0() { return scratch0_; }
    205     inline Register scratch1() { return scratch1_; }
    206 
    207    private:
    208     Register object_;
    209     Register address_;
    210     Register scratch0_;
    211     Register scratch1_;
    212 
    213     friend class RecordWriteStub;
    214   };
    215 
    216   enum OnNoNeedToInformIncrementalMarker {
    217     kReturnOnNoNeedToInformIncrementalMarker,
    218     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    219   };
    220 
    221   inline Major MajorKey() const final { return RecordWrite; }
    222 
    223   void Generate(MacroAssembler* masm) override;
    224   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    225   void CheckNeedsToInformIncrementalMarker(
    226       MacroAssembler* masm,
    227       OnNoNeedToInformIncrementalMarker on_no_need,
    228       Mode mode);
    229   void InformIncrementalMarker(MacroAssembler* masm);
    230 
    231   void Activate(Code* code) override {
    232     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    233   }
    234 
    235   Register object() const {
    236     return Register::from_code(ObjectBits::decode(minor_key_));
    237   }
    238 
    239   Register value() const {
    240     return Register::from_code(ValueBits::decode(minor_key_));
    241   }
    242 
    243   Register address() const {
    244     return Register::from_code(AddressBits::decode(minor_key_));
    245   }
    246 
    247   RememberedSetAction remembered_set_action() const {
    248     return RememberedSetActionBits::decode(minor_key_);
    249   }
    250 
    251   SaveFPRegsMode save_fp_regs_mode() const {
    252     return SaveFPRegsModeBits::decode(minor_key_);
    253   }
    254 
    255   class ObjectBits: public BitField<int, 0, 5> {};
    256   class ValueBits: public BitField<int, 5, 5> {};
    257   class AddressBits: public BitField<int, 10, 5> {};
    258   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
    259   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
    260 
    261   Label slow_;
    262   RegisterAllocation regs_;
    263 
    264   DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
    265 };
    266 
    267 
    268 // Trampoline stub to call into native code. To call safely into native code
    269 // in the presence of compacting GC (which can move code objects) we need to
    270 // keep the code which called into native pinned in the memory. Currently the
    271 // simplest approach is to generate such stub early enough so it can never be
    272 // moved by GC
    273 class DirectCEntryStub: public PlatformCodeStub {
    274  public:
    275   explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
    276   void GenerateCall(MacroAssembler* masm, Register target);
    277 
    278  private:
    279   bool NeedsImmovableCode() override { return true; }
    280 
    281   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    282   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
    283 };
    284 
    285 
    286 class NameDictionaryLookupStub: public PlatformCodeStub {
    287  public:
    288   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
    289 
    290   NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
    291       : PlatformCodeStub(isolate) {
    292     minor_key_ = LookupModeBits::encode(mode);
    293   }
    294 
    295   static void GenerateNegativeLookup(MacroAssembler* masm,
    296                                      Label* miss,
    297                                      Label* done,
    298                                      Register receiver,
    299                                      Register properties,
    300                                      Handle<Name> name,
    301                                      Register scratch0);
    302 
    303   bool SometimesSetsUpAFrame() override { return false; }
    304 
    305  private:
    306   static const int kInlinedProbes = 4;
    307   static const int kTotalProbes = 20;
    308 
    309   static const int kCapacityOffset =
    310       NameDictionary::kHeaderSize +
    311       NameDictionary::kCapacityIndex * kPointerSize;
    312 
    313   static const int kElementsStartOffset =
    314       NameDictionary::kHeaderSize +
    315       NameDictionary::kElementsStartIndex * kPointerSize;
    316 
    317   LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
    318 
    319   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
    320 
    321   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    322   DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
    323 };
    324 
    325 
    326 }  // namespace internal
    327 }  // namespace v8
    328 
    329 #endif  // V8_MIPS_CODE_STUBS_MIPS_H_
    330