Home | History | Annotate | Download | only in ppc
      1 // Copyright 2014 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_PPC_CODE_STUBS_PPC_H_
      6 #define V8_PPC_CODE_STUBS_PPC_H_
      7 
      8 #include "src/ppc/frames-ppc.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, Register dest,
     24                                      Register src, Register count,
     25                                      Register scratch,
     26                                      String::Encoding encoding);
     27 
     28   // Compares two flat one-byte strings and returns result in r0.
     29   static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm,
     30                                                 Register left, Register right,
     31                                                 Register scratch1,
     32                                                 Register scratch2,
     33                                                 Register scratch3);
     34 
     35   // Compares two flat one-byte strings for equality and returns result in r0.
     36   static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
     37                                               Register left, Register right,
     38                                               Register scratch1,
     39                                               Register scratch2);
     40 
     41  private:
     42   static void GenerateOneByteCharsCompareLoop(MacroAssembler* masm,
     43                                               Register left, Register right,
     44                                               Register length,
     45                                               Register scratch1,
     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, Register object, Register value,
     81                   Register address, RememberedSetAction remembered_set_action,
     82                   SaveFPRegsMode fp_mode)
     83       : PlatformCodeStub(isolate),
     84         regs_(object,   // An input reg.
     85               address,  // An input reg.
     86               value) {  // One scratch reg.
     87     minor_key_ = ObjectBits::encode(object.code()) |
     88                  ValueBits::encode(value.code()) |
     89                  AddressBits::encode(address.code()) |
     90                  RememberedSetActionBits::encode(remembered_set_action) |
     91                  SaveFPRegsModeBits::encode(fp_mode);
     92   }
     93 
     94   RecordWriteStub(uint32_t key, Isolate* isolate)
     95       : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
     96 
     97   enum Mode { STORE_BUFFER_ONLY, INCREMENTAL, INCREMENTAL_COMPACTION };
     98 
     99   bool SometimesSetsUpAFrame() override { return false; }
    100 
    101   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    102     // Consider adding DCHECK here to catch bad patching
    103     masm->instr_at_put(pos, (masm->instr_at(pos) & ~kBOfieldMask) | BT);
    104   }
    105 
    106   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    107     // Consider adding DCHECK here to catch bad patching
    108     masm->instr_at_put(pos, (masm->instr_at(pos) & ~kBOfieldMask) | BF);
    109   }
    110 
    111   static Mode GetMode(Code* stub) {
    112     Instr first_instruction =
    113         Assembler::instr_at(stub->instruction_start() + Assembler::kInstrSize);
    114     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
    115                                                    (Assembler::kInstrSize * 2));
    116 
    117     // Consider adding DCHECK here to catch unexpected instruction sequence
    118     if (BF == (first_instruction & kBOfieldMask)) {
    119       return INCREMENTAL;
    120     }
    121 
    122     if (BF == (second_instruction & kBOfieldMask)) {
    123       return INCREMENTAL_COMPACTION;
    124     }
    125 
    126     return STORE_BUFFER_ONLY;
    127   }
    128 
    129   static void Patch(Code* stub, Mode mode) {
    130     MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
    131                         stub->instruction_size(), CodeObjectRequired::kNo);
    132     switch (mode) {
    133       case STORE_BUFFER_ONLY:
    134         DCHECK(GetMode(stub) == INCREMENTAL ||
    135                GetMode(stub) == INCREMENTAL_COMPACTION);
    136 
    137         PatchBranchIntoNop(&masm, Assembler::kInstrSize);
    138         PatchBranchIntoNop(&masm, Assembler::kInstrSize * 2);
    139         break;
    140       case INCREMENTAL:
    141         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    142         PatchNopIntoBranch(&masm, Assembler::kInstrSize);
    143         break;
    144       case INCREMENTAL_COMPACTION:
    145         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    146         PatchNopIntoBranch(&masm, Assembler::kInstrSize * 2);
    147         break;
    148     }
    149     DCHECK(GetMode(stub) == mode);
    150     Assembler::FlushICache(stub->GetIsolate(),
    151                            stub->instruction_start() + Assembler::kInstrSize,
    152                            2 * 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, Register address, Register scratch0)
    164         : object_(object), address_(address), scratch0_(scratch0) {
    165       DCHECK(!AreAliased(scratch0, object, address, no_reg));
    166       scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
    167     }
    168 
    169     void Save(MacroAssembler* masm) {
    170       DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
    171       // We don't have to save scratch0_ because it was given to us as
    172       // a scratch register.
    173       masm->push(scratch1_);
    174     }
    175 
    176     void Restore(MacroAssembler* masm) { masm->pop(scratch1_); }
    177 
    178     // If we have to call into C then we need to save and restore all caller-
    179     // saved registers that were not already preserved.  The scratch registers
    180     // will be restored by other means so we don't bother pushing them here.
    181     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    182       masm->mflr(r0);
    183       masm->push(r0);
    184       masm->MultiPush(kJSCallerSaved & ~scratch1_.bit());
    185       if (mode == kSaveFPRegs) {
    186         // Save all volatile FP registers except d0.
    187         masm->MultiPushDoubles(kCallerSavedDoubles & ~d0.bit());
    188       }
    189     }
    190 
    191     inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
    192                                            SaveFPRegsMode mode) {
    193       if (mode == kSaveFPRegs) {
    194         // Restore all volatile FP registers except d0.
    195         masm->MultiPopDoubles(kCallerSavedDoubles & ~d0.bit());
    196       }
    197       masm->MultiPop(kJSCallerSaved & ~scratch1_.bit());
    198       masm->pop(r0);
    199       masm->mtlr(r0);
    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, OnNoNeedToInformIncrementalMarker on_no_need,
    227       Mode mode);
    228   void InformIncrementalMarker(MacroAssembler* masm);
    229 
    230   void Activate(Code* code) override {
    231     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    232   }
    233 
    234   Register object() const {
    235     return Register::from_code(ObjectBits::decode(minor_key_));
    236   }
    237 
    238   Register value() const {
    239     return Register::from_code(ValueBits::decode(minor_key_));
    240   }
    241 
    242   Register address() const {
    243     return Register::from_code(AddressBits::decode(minor_key_));
    244   }
    245 
    246   RememberedSetAction remembered_set_action() const {
    247     return RememberedSetActionBits::decode(minor_key_);
    248   }
    249 
    250   SaveFPRegsMode save_fp_regs_mode() const {
    251     return SaveFPRegsModeBits::decode(minor_key_);
    252   }
    253 
    254   class ObjectBits : public BitField<int, 0, 5> {};
    255   class ValueBits : public BitField<int, 5, 5> {};
    256   class AddressBits : public BitField<int, 10, 5> {};
    257   class RememberedSetActionBits : public BitField<RememberedSetAction, 15, 1> {
    258   };
    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, Label* miss,
    296                                      Label* done, Register receiver,
    297                                      Register properties, Handle<Name> name,
    298                                      Register scratch0);
    299 
    300   static void GeneratePositiveLookup(MacroAssembler* masm, Label* miss,
    301                                      Label* done, Register elements,
    302                                      Register name, Register r0, Register r1);
    303 
    304   bool SometimesSetsUpAFrame() override { return false; }
    305 
    306  private:
    307   static const int kInlinedProbes = 4;
    308   static const int kTotalProbes = 20;
    309 
    310   static const int kCapacityOffset =
    311       NameDictionary::kHeaderSize +
    312       NameDictionary::kCapacityIndex * kPointerSize;
    313 
    314   static const int kElementsStartOffset =
    315       NameDictionary::kHeaderSize +
    316       NameDictionary::kElementsStartIndex * kPointerSize;
    317 
    318   LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
    319 
    320   class LookupModeBits : public BitField<LookupMode, 0, 1> {};
    321 
    322   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    323   DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
    324 };
    325 }  // namespace internal
    326 }  // namespace v8
    327 
    328 #endif  // V8_PPC_CODE_STUBS_PPC_H_
    329