Home | History | Annotate | Download | only in ia32
      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_IA32_CODE_STUBS_IA32_H_
      6 #define V8_IA32_CODE_STUBS_IA32_H_
      7 
      8 namespace v8 {
      9 namespace internal {
     10 
     11 
     12 void ArrayNativeCode(MacroAssembler* masm,
     13                      bool construct_call,
     14                      Label* call_generic_code);
     15 
     16 
     17 class StringHelper : public AllStatic {
     18  public:
     19   // Generate code for copying characters using the rep movs instruction.
     20   // Copies ecx characters from esi to edi. Copying of overlapping regions is
     21   // not supported.
     22   static void GenerateCopyCharacters(MacroAssembler* masm,
     23                                      Register dest,
     24                                      Register src,
     25                                      Register count,
     26                                      Register scratch,
     27                                      String::Encoding encoding);
     28 
     29   // Compares two flat one byte strings and returns result in eax.
     30   static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm,
     31                                                 Register left, Register right,
     32                                                 Register scratch1,
     33                                                 Register scratch2,
     34                                                 Register scratch3);
     35 
     36   // Compares two flat one byte strings for equality and returns result in eax.
     37   static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
     38                                               Register left, Register right,
     39                                               Register scratch1,
     40                                               Register scratch2);
     41 
     42  private:
     43   static void GenerateOneByteCharsCompareLoop(
     44       MacroAssembler* masm, Register left, Register right, Register length,
     45       Register scratch, Label* chars_not_equal,
     46       Label::Distance chars_not_equal_near = Label::kFar);
     47 
     48   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
     49 };
     50 
     51 
     52 class NameDictionaryLookupStub: public PlatformCodeStub {
     53  public:
     54   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
     55 
     56   NameDictionaryLookupStub(Isolate* isolate, Register dictionary,
     57                            Register result, Register index, LookupMode mode)
     58       : PlatformCodeStub(isolate) {
     59     minor_key_ = DictionaryBits::encode(dictionary.code()) |
     60                  ResultBits::encode(result.code()) |
     61                  IndexBits::encode(index.code()) | LookupModeBits::encode(mode);
     62   }
     63 
     64   static void GenerateNegativeLookup(MacroAssembler* masm,
     65                                      Label* miss,
     66                                      Label* done,
     67                                      Register properties,
     68                                      Handle<Name> name,
     69                                      Register r0);
     70 
     71   static void GeneratePositiveLookup(MacroAssembler* masm,
     72                                      Label* miss,
     73                                      Label* done,
     74                                      Register elements,
     75                                      Register name,
     76                                      Register r0,
     77                                      Register r1);
     78 
     79   bool SometimesSetsUpAFrame() override { return false; }
     80 
     81  private:
     82   static const int kInlinedProbes = 4;
     83   static const int kTotalProbes = 20;
     84 
     85   static const int kCapacityOffset =
     86       NameDictionary::kHeaderSize +
     87       NameDictionary::kCapacityIndex * kPointerSize;
     88 
     89   static const int kElementsStartOffset =
     90       NameDictionary::kHeaderSize +
     91       NameDictionary::kElementsStartIndex * kPointerSize;
     92 
     93   Register dictionary() const {
     94     return Register::from_code(DictionaryBits::decode(minor_key_));
     95   }
     96 
     97   Register result() const {
     98     return Register::from_code(ResultBits::decode(minor_key_));
     99   }
    100 
    101   Register index() const {
    102     return Register::from_code(IndexBits::decode(minor_key_));
    103   }
    104 
    105   LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
    106 
    107   class DictionaryBits: public BitField<int, 0, 3> {};
    108   class ResultBits: public BitField<int, 3, 3> {};
    109   class IndexBits: public BitField<int, 6, 3> {};
    110   class LookupModeBits: public BitField<LookupMode, 9, 1> {};
    111 
    112   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    113   DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
    114 };
    115 
    116 
    117 class RecordWriteStub: public PlatformCodeStub {
    118  public:
    119   RecordWriteStub(Isolate* isolate,
    120                   Register object,
    121                   Register value,
    122                   Register address,
    123                   RememberedSetAction remembered_set_action,
    124                   SaveFPRegsMode fp_mode)
    125       : PlatformCodeStub(isolate),
    126         regs_(object,   // An input reg.
    127               address,  // An input reg.
    128               value) {  // One scratch reg.
    129     minor_key_ = ObjectBits::encode(object.code()) |
    130                  ValueBits::encode(value.code()) |
    131                  AddressBits::encode(address.code()) |
    132                  RememberedSetActionBits::encode(remembered_set_action) |
    133                  SaveFPRegsModeBits::encode(fp_mode);
    134   }
    135 
    136   RecordWriteStub(uint32_t key, Isolate* isolate)
    137       : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
    138 
    139   enum Mode {
    140     STORE_BUFFER_ONLY,
    141     INCREMENTAL,
    142     INCREMENTAL_COMPACTION
    143   };
    144 
    145   bool SometimesSetsUpAFrame() override { return false; }
    146 
    147   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
    148   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
    149 
    150   static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
    151   static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
    152 
    153   static Mode GetMode(Code* stub) {
    154     byte first_instruction = stub->instruction_start()[0];
    155     byte second_instruction = stub->instruction_start()[2];
    156 
    157     if (first_instruction == kTwoByteJumpInstruction) {
    158       return INCREMENTAL;
    159     }
    160 
    161     DCHECK(first_instruction == kTwoByteNopInstruction);
    162 
    163     if (second_instruction == kFiveByteJumpInstruction) {
    164       return INCREMENTAL_COMPACTION;
    165     }
    166 
    167     DCHECK(second_instruction == kFiveByteNopInstruction);
    168 
    169     return STORE_BUFFER_ONLY;
    170   }
    171 
    172   static void Patch(Code* stub, Mode mode) {
    173     switch (mode) {
    174       case STORE_BUFFER_ONLY:
    175         DCHECK(GetMode(stub) == INCREMENTAL ||
    176                GetMode(stub) == INCREMENTAL_COMPACTION);
    177         stub->instruction_start()[0] = kTwoByteNopInstruction;
    178         stub->instruction_start()[2] = kFiveByteNopInstruction;
    179         break;
    180       case INCREMENTAL:
    181         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    182         stub->instruction_start()[0] = kTwoByteJumpInstruction;
    183         break;
    184       case INCREMENTAL_COMPACTION:
    185         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
    186         stub->instruction_start()[0] = kTwoByteNopInstruction;
    187         stub->instruction_start()[2] = kFiveByteJumpInstruction;
    188         break;
    189     }
    190     DCHECK(GetMode(stub) == mode);
    191     Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 7);
    192   }
    193 
    194   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
    195 
    196  private:
    197   // This is a helper class for freeing up 3 scratch registers, where the third
    198   // is always ecx (needed for shift operations).  The input is two registers
    199   // that must be preserved and one scratch register provided by the caller.
    200   class RegisterAllocation {
    201    public:
    202     RegisterAllocation(Register object,
    203                        Register address,
    204                        Register scratch0)
    205         : object_orig_(object),
    206           address_orig_(address),
    207           scratch0_orig_(scratch0),
    208           object_(object),
    209           address_(address),
    210           scratch0_(scratch0) {
    211       DCHECK(!AreAliased(scratch0, object, address, no_reg));
    212       scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
    213       if (scratch0.is(ecx)) {
    214         scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
    215       }
    216       if (object.is(ecx)) {
    217         object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
    218       }
    219       if (address.is(ecx)) {
    220         address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
    221       }
    222       DCHECK(!AreAliased(scratch0_, object_, address_, ecx));
    223     }
    224 
    225     void Save(MacroAssembler* masm) {
    226       DCHECK(!address_orig_.is(object_));
    227       DCHECK(object_.is(object_orig_) || address_.is(address_orig_));
    228       DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
    229       DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
    230       DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
    231       // We don't have to save scratch0_orig_ because it was given to us as
    232       // a scratch register.  But if we had to switch to a different reg then
    233       // we should save the new scratch0_.
    234       if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
    235       if (!ecx.is(scratch0_orig_) &&
    236           !ecx.is(object_orig_) &&
    237           !ecx.is(address_orig_)) {
    238         masm->push(ecx);
    239       }
    240       masm->push(scratch1_);
    241       if (!address_.is(address_orig_)) {
    242         masm->push(address_);
    243         masm->mov(address_, address_orig_);
    244       }
    245       if (!object_.is(object_orig_)) {
    246         masm->push(object_);
    247         masm->mov(object_, object_orig_);
    248       }
    249     }
    250 
    251     void Restore(MacroAssembler* masm) {
    252       // These will have been preserved the entire time, so we just need to move
    253       // them back.  Only in one case is the orig_ reg different from the plain
    254       // one, since only one of them can alias with ecx.
    255       if (!object_.is(object_orig_)) {
    256         masm->mov(object_orig_, object_);
    257         masm->pop(object_);
    258       }
    259       if (!address_.is(address_orig_)) {
    260         masm->mov(address_orig_, address_);
    261         masm->pop(address_);
    262       }
    263       masm->pop(scratch1_);
    264       if (!ecx.is(scratch0_orig_) &&
    265           !ecx.is(object_orig_) &&
    266           !ecx.is(address_orig_)) {
    267         masm->pop(ecx);
    268       }
    269       if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
    270     }
    271 
    272     // If we have to call into C then we need to save and restore all caller-
    273     // saved registers that were not already preserved.  The caller saved
    274     // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
    275     // will be restored by other means so we don't bother pushing them here.
    276     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    277       masm->PushCallerSaved(mode, ecx, scratch0_, scratch1_);
    278     }
    279 
    280     inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
    281                                            SaveFPRegsMode mode) {
    282       masm->PopCallerSaved(mode, ecx, scratch0_, scratch1_);
    283     }
    284 
    285     inline Register object() { return object_; }
    286     inline Register address() { return address_; }
    287     inline Register scratch0() { return scratch0_; }
    288     inline Register scratch1() { return scratch1_; }
    289 
    290    private:
    291     Register object_orig_;
    292     Register address_orig_;
    293     Register scratch0_orig_;
    294     Register object_;
    295     Register address_;
    296     Register scratch0_;
    297     Register scratch1_;
    298     // Third scratch register is always ecx.
    299 
    300     Register GetRegThatIsNotEcxOr(Register r1,
    301                                   Register r2,
    302                                   Register r3) {
    303       for (int i = 0; i < Register::kNumRegisters; i++) {
    304         if (RegisterConfiguration::Crankshaft()->IsAllocatableGeneralCode(i)) {
    305           Register candidate = Register::from_code(i);
    306           if (candidate.is(ecx)) continue;
    307           if (candidate.is(r1)) continue;
    308           if (candidate.is(r2)) continue;
    309           if (candidate.is(r3)) continue;
    310           return candidate;
    311         }
    312       }
    313       UNREACHABLE();
    314       return no_reg;
    315     }
    316     friend class RecordWriteStub;
    317   };
    318 
    319   enum OnNoNeedToInformIncrementalMarker {
    320     kReturnOnNoNeedToInformIncrementalMarker,
    321     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    322   };
    323 
    324   inline Major MajorKey() const final { return RecordWrite; }
    325 
    326   void Generate(MacroAssembler* masm) override;
    327   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    328   void CheckNeedsToInformIncrementalMarker(
    329       MacroAssembler* masm,
    330       OnNoNeedToInformIncrementalMarker on_no_need,
    331       Mode mode);
    332   void InformIncrementalMarker(MacroAssembler* masm);
    333 
    334   void Activate(Code* code) override {
    335     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    336   }
    337 
    338   Register object() const {
    339     return Register::from_code(ObjectBits::decode(minor_key_));
    340   }
    341 
    342   Register value() const {
    343     return Register::from_code(ValueBits::decode(minor_key_));
    344   }
    345 
    346   Register address() const {
    347     return Register::from_code(AddressBits::decode(minor_key_));
    348   }
    349 
    350   RememberedSetAction remembered_set_action() const {
    351     return RememberedSetActionBits::decode(minor_key_);
    352   }
    353 
    354   SaveFPRegsMode save_fp_regs_mode() const {
    355     return SaveFPRegsModeBits::decode(minor_key_);
    356   }
    357 
    358   class ObjectBits: public BitField<int, 0, 3> {};
    359   class ValueBits: public BitField<int, 3, 3> {};
    360   class AddressBits: public BitField<int, 6, 3> {};
    361   class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
    362   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
    363 
    364   RegisterAllocation regs_;
    365 
    366   DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
    367 };
    368 
    369 
    370 }  // namespace internal
    371 }  // namespace v8
    372 
    373 #endif  // V8_IA32_CODE_STUBS_IA32_H_
    374