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