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