Home | History | Annotate | Download | only in ia32
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_IA32_CODE_STUBS_IA32_H_
     29 #define V8_IA32_CODE_STUBS_IA32_H_
     30 
     31 #include "macro-assembler.h"
     32 #include "code-stubs.h"
     33 #include "ic-inl.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 
     39 void ArrayNativeCode(MacroAssembler* masm,
     40                      bool construct_call,
     41                      Label* call_generic_code);
     42 
     43 // Compute a transcendental math function natively, or call the
     44 // TranscendentalCache runtime function.
     45 class TranscendentalCacheStub: public PlatformCodeStub {
     46  public:
     47   enum ArgumentType {
     48     TAGGED = 0,
     49     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
     50   };
     51 
     52   TranscendentalCacheStub(TranscendentalCache::Type type,
     53                           ArgumentType argument_type)
     54       : type_(type), argument_type_(argument_type) {}
     55   void Generate(MacroAssembler* masm);
     56   static void GenerateOperation(MacroAssembler* masm,
     57                                 TranscendentalCache::Type type);
     58  private:
     59   TranscendentalCache::Type type_;
     60   ArgumentType argument_type_;
     61 
     62   Major MajorKey() { return TranscendentalCache; }
     63   int MinorKey() { return type_ | argument_type_; }
     64   Runtime::FunctionId RuntimeFunction();
     65 };
     66 
     67 
     68 class StoreBufferOverflowStub: public PlatformCodeStub {
     69  public:
     70   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
     71       : save_doubles_(save_fp) {
     72     ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || save_fp == kDontSaveFPRegs);
     73   }
     74 
     75   void Generate(MacroAssembler* masm);
     76 
     77   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
     78   virtual bool SometimesSetsUpAFrame() { return false; }
     79 
     80  private:
     81   SaveFPRegsMode save_doubles_;
     82 
     83   Major MajorKey() { return StoreBufferOverflow; }
     84   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
     85 };
     86 
     87 
     88 class StringHelper : public AllStatic {
     89  public:
     90   // Generate code for copying characters using a simple loop. This should only
     91   // be used in places where the number of characters is small and the
     92   // additional setup and checking in GenerateCopyCharactersREP adds too much
     93   // overhead. Copying of overlapping regions is not supported.
     94   static void GenerateCopyCharacters(MacroAssembler* masm,
     95                                      Register dest,
     96                                      Register src,
     97                                      Register count,
     98                                      Register scratch,
     99                                      bool ascii);
    100 
    101   // Generate code for copying characters using the rep movs instruction.
    102   // Copies ecx characters from esi to edi. Copying of overlapping regions is
    103   // not supported.
    104   static void GenerateCopyCharactersREP(MacroAssembler* masm,
    105                                         Register dest,     // Must be edi.
    106                                         Register src,      // Must be esi.
    107                                         Register count,    // Must be ecx.
    108                                         Register scratch,  // Neither of above.
    109                                         bool ascii);
    110 
    111   // Probe the string table for a two character string. If the string
    112   // requires non-standard hashing a jump to the label not_probed is
    113   // performed and registers c1 and c2 are preserved. In all other
    114   // cases they are clobbered. If the string is not found by probing a
    115   // jump to the label not_found is performed. This jump does not
    116   // guarantee that the string is not in the string table. If the
    117   // string is found the code falls through with the string in
    118   // register eax.
    119   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
    120                                                    Register c1,
    121                                                    Register c2,
    122                                                    Register scratch1,
    123                                                    Register scratch2,
    124                                                    Register scratch3,
    125                                                    Label* not_probed,
    126                                                    Label* not_found);
    127 
    128   // Generate string hash.
    129   static void GenerateHashInit(MacroAssembler* masm,
    130                                Register hash,
    131                                Register character,
    132                                Register scratch);
    133   static void GenerateHashAddCharacter(MacroAssembler* masm,
    134                                        Register hash,
    135                                        Register character,
    136                                        Register scratch);
    137   static void GenerateHashGetHash(MacroAssembler* masm,
    138                                   Register hash,
    139                                   Register scratch);
    140 
    141  private:
    142   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
    143 };
    144 
    145 
    146 class StringAddStub: public PlatformCodeStub {
    147  public:
    148   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    149 
    150  private:
    151   Major MajorKey() { return StringAdd; }
    152   int MinorKey() { return flags_; }
    153 
    154   void Generate(MacroAssembler* masm);
    155 
    156   void GenerateConvertArgument(MacroAssembler* masm,
    157                                int stack_offset,
    158                                Register arg,
    159                                Register scratch1,
    160                                Register scratch2,
    161                                Register scratch3,
    162                                Label* slow);
    163 
    164   void GenerateRegisterArgsPush(MacroAssembler* masm);
    165   void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
    166 
    167   const StringAddFlags flags_;
    168 };
    169 
    170 
    171 class SubStringStub: public PlatformCodeStub {
    172  public:
    173   SubStringStub() {}
    174 
    175  private:
    176   Major MajorKey() { return SubString; }
    177   int MinorKey() { return 0; }
    178 
    179   void Generate(MacroAssembler* masm);
    180 };
    181 
    182 
    183 class StringCompareStub: public PlatformCodeStub {
    184  public:
    185   StringCompareStub() { }
    186 
    187   // Compares two flat ASCII strings and returns result in eax.
    188   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    189                                               Register left,
    190                                               Register right,
    191                                               Register scratch1,
    192                                               Register scratch2,
    193                                               Register scratch3);
    194 
    195   // Compares two flat ASCII strings for equality and returns result
    196   // in eax.
    197   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
    198                                             Register left,
    199                                             Register right,
    200                                             Register scratch1,
    201                                             Register scratch2);
    202 
    203  private:
    204   virtual Major MajorKey() { return StringCompare; }
    205   virtual int MinorKey() { return 0; }
    206   virtual void Generate(MacroAssembler* masm);
    207 
    208   static void GenerateAsciiCharsCompareLoop(
    209       MacroAssembler* masm,
    210       Register left,
    211       Register right,
    212       Register length,
    213       Register scratch,
    214       Label* chars_not_equal,
    215       Label::Distance chars_not_equal_near = Label::kFar);
    216 };
    217 
    218 
    219 class NameDictionaryLookupStub: public PlatformCodeStub {
    220  public:
    221   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
    222 
    223   NameDictionaryLookupStub(Register dictionary,
    224                            Register result,
    225                            Register index,
    226                            LookupMode mode)
    227       : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
    228 
    229   void Generate(MacroAssembler* masm);
    230 
    231   static void GenerateNegativeLookup(MacroAssembler* masm,
    232                                      Label* miss,
    233                                      Label* done,
    234                                      Register properties,
    235                                      Handle<Name> name,
    236                                      Register r0);
    237 
    238   static void GeneratePositiveLookup(MacroAssembler* masm,
    239                                      Label* miss,
    240                                      Label* done,
    241                                      Register elements,
    242                                      Register name,
    243                                      Register r0,
    244                                      Register r1);
    245 
    246   virtual bool SometimesSetsUpAFrame() { return false; }
    247 
    248  private:
    249   static const int kInlinedProbes = 4;
    250   static const int kTotalProbes = 20;
    251 
    252   static const int kCapacityOffset =
    253       NameDictionary::kHeaderSize +
    254       NameDictionary::kCapacityIndex * kPointerSize;
    255 
    256   static const int kElementsStartOffset =
    257       NameDictionary::kHeaderSize +
    258       NameDictionary::kElementsStartIndex * kPointerSize;
    259 
    260   Major MajorKey() { return NameDictionaryLookup; }
    261 
    262   int MinorKey() {
    263     return DictionaryBits::encode(dictionary_.code()) |
    264         ResultBits::encode(result_.code()) |
    265         IndexBits::encode(index_.code()) |
    266         LookupModeBits::encode(mode_);
    267   }
    268 
    269   class DictionaryBits: public BitField<int, 0, 3> {};
    270   class ResultBits: public BitField<int, 3, 3> {};
    271   class IndexBits: public BitField<int, 6, 3> {};
    272   class LookupModeBits: public BitField<LookupMode, 9, 1> {};
    273 
    274   Register dictionary_;
    275   Register result_;
    276   Register index_;
    277   LookupMode mode_;
    278 };
    279 
    280 
    281 class RecordWriteStub: public PlatformCodeStub {
    282  public:
    283   RecordWriteStub(Register object,
    284                   Register value,
    285                   Register address,
    286                   RememberedSetAction remembered_set_action,
    287                   SaveFPRegsMode fp_mode)
    288       : object_(object),
    289         value_(value),
    290         address_(address),
    291         remembered_set_action_(remembered_set_action),
    292         save_fp_regs_mode_(fp_mode),
    293         regs_(object,   // An input reg.
    294               address,  // An input reg.
    295               value) {  // One scratch reg.
    296     ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || fp_mode == kDontSaveFPRegs);
    297   }
    298 
    299   enum Mode {
    300     STORE_BUFFER_ONLY,
    301     INCREMENTAL,
    302     INCREMENTAL_COMPACTION
    303   };
    304 
    305   virtual bool SometimesSetsUpAFrame() { return false; }
    306 
    307   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
    308   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
    309 
    310   static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
    311   static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
    312 
    313   static Mode GetMode(Code* stub) {
    314     byte first_instruction = stub->instruction_start()[0];
    315     byte second_instruction = stub->instruction_start()[2];
    316 
    317     if (first_instruction == kTwoByteJumpInstruction) {
    318       return INCREMENTAL;
    319     }
    320 
    321     ASSERT(first_instruction == kTwoByteNopInstruction);
    322 
    323     if (second_instruction == kFiveByteJumpInstruction) {
    324       return INCREMENTAL_COMPACTION;
    325     }
    326 
    327     ASSERT(second_instruction == kFiveByteNopInstruction);
    328 
    329     return STORE_BUFFER_ONLY;
    330   }
    331 
    332   static void Patch(Code* stub, Mode mode) {
    333     switch (mode) {
    334       case STORE_BUFFER_ONLY:
    335         ASSERT(GetMode(stub) == INCREMENTAL ||
    336                GetMode(stub) == INCREMENTAL_COMPACTION);
    337         stub->instruction_start()[0] = kTwoByteNopInstruction;
    338         stub->instruction_start()[2] = kFiveByteNopInstruction;
    339         break;
    340       case INCREMENTAL:
    341         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    342         stub->instruction_start()[0] = kTwoByteJumpInstruction;
    343         break;
    344       case INCREMENTAL_COMPACTION:
    345         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
    346         stub->instruction_start()[0] = kTwoByteNopInstruction;
    347         stub->instruction_start()[2] = kFiveByteJumpInstruction;
    348         break;
    349     }
    350     ASSERT(GetMode(stub) == mode);
    351     CPU::FlushICache(stub->instruction_start(), 7);
    352   }
    353 
    354  private:
    355   // This is a helper class for freeing up 3 scratch registers, where the third
    356   // is always ecx (needed for shift operations).  The input is two registers
    357   // that must be preserved and one scratch register provided by the caller.
    358   class RegisterAllocation {
    359    public:
    360     RegisterAllocation(Register object,
    361                        Register address,
    362                        Register scratch0)
    363         : object_orig_(object),
    364           address_orig_(address),
    365           scratch0_orig_(scratch0),
    366           object_(object),
    367           address_(address),
    368           scratch0_(scratch0) {
    369       ASSERT(!AreAliased(scratch0, object, address, no_reg));
    370       scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
    371       if (scratch0.is(ecx)) {
    372         scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
    373       }
    374       if (object.is(ecx)) {
    375         object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
    376       }
    377       if (address.is(ecx)) {
    378         address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
    379       }
    380       ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
    381     }
    382 
    383     void Save(MacroAssembler* masm) {
    384       ASSERT(!address_orig_.is(object_));
    385       ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
    386       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
    387       ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
    388       ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
    389       // We don't have to save scratch0_orig_ because it was given to us as
    390       // a scratch register.  But if we had to switch to a different reg then
    391       // we should save the new scratch0_.
    392       if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
    393       if (!ecx.is(scratch0_orig_) &&
    394           !ecx.is(object_orig_) &&
    395           !ecx.is(address_orig_)) {
    396         masm->push(ecx);
    397       }
    398       masm->push(scratch1_);
    399       if (!address_.is(address_orig_)) {
    400         masm->push(address_);
    401         masm->mov(address_, address_orig_);
    402       }
    403       if (!object_.is(object_orig_)) {
    404         masm->push(object_);
    405         masm->mov(object_, object_orig_);
    406       }
    407     }
    408 
    409     void Restore(MacroAssembler* masm) {
    410       // These will have been preserved the entire time, so we just need to move
    411       // them back.  Only in one case is the orig_ reg different from the plain
    412       // one, since only one of them can alias with ecx.
    413       if (!object_.is(object_orig_)) {
    414         masm->mov(object_orig_, object_);
    415         masm->pop(object_);
    416       }
    417       if (!address_.is(address_orig_)) {
    418         masm->mov(address_orig_, address_);
    419         masm->pop(address_);
    420       }
    421       masm->pop(scratch1_);
    422       if (!ecx.is(scratch0_orig_) &&
    423           !ecx.is(object_orig_) &&
    424           !ecx.is(address_orig_)) {
    425         masm->pop(ecx);
    426       }
    427       if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
    428     }
    429 
    430     // If we have to call into C then we need to save and restore all caller-
    431     // saved registers that were not already preserved.  The caller saved
    432     // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
    433     // will be restored by other means so we don't bother pushing them here.
    434     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    435       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
    436       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
    437       if (mode == kSaveFPRegs) {
    438         CpuFeatureScope scope(masm, SSE2);
    439         masm->sub(esp,
    440                   Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
    441         // Save all XMM registers except XMM0.
    442         for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
    443           XMMRegister reg = XMMRegister::from_code(i);
    444           masm->movsd(Operand(esp, (i - 1) * kDoubleSize), reg);
    445         }
    446       }
    447     }
    448 
    449     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    450                                            SaveFPRegsMode mode) {
    451       if (mode == kSaveFPRegs) {
    452         CpuFeatureScope scope(masm, SSE2);
    453         // Restore all XMM registers except XMM0.
    454         for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
    455           XMMRegister reg = XMMRegister::from_code(i);
    456           masm->movsd(reg, Operand(esp, (i - 1) * kDoubleSize));
    457         }
    458         masm->add(esp,
    459                   Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
    460       }
    461       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
    462       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
    463     }
    464 
    465     inline Register object() { return object_; }
    466     inline Register address() { return address_; }
    467     inline Register scratch0() { return scratch0_; }
    468     inline Register scratch1() { return scratch1_; }
    469 
    470    private:
    471     Register object_orig_;
    472     Register address_orig_;
    473     Register scratch0_orig_;
    474     Register object_;
    475     Register address_;
    476     Register scratch0_;
    477     Register scratch1_;
    478     // Third scratch register is always ecx.
    479 
    480     Register GetRegThatIsNotEcxOr(Register r1,
    481                                   Register r2,
    482                                   Register r3) {
    483       for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
    484         Register candidate = Register::FromAllocationIndex(i);
    485         if (candidate.is(ecx)) continue;
    486         if (candidate.is(r1)) continue;
    487         if (candidate.is(r2)) continue;
    488         if (candidate.is(r3)) continue;
    489         return candidate;
    490       }
    491       UNREACHABLE();
    492       return no_reg;
    493     }
    494     friend class RecordWriteStub;
    495   };
    496 
    497   enum OnNoNeedToInformIncrementalMarker {
    498     kReturnOnNoNeedToInformIncrementalMarker,
    499     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
    500   }
    501 ;
    502   void Generate(MacroAssembler* masm);
    503   void GenerateIncremental(MacroAssembler* masm, Mode mode);
    504   void CheckNeedsToInformIncrementalMarker(
    505       MacroAssembler* masm,
    506       OnNoNeedToInformIncrementalMarker on_no_need,
    507       Mode mode);
    508   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
    509 
    510   Major MajorKey() { return RecordWrite; }
    511 
    512   int MinorKey() {
    513     return ObjectBits::encode(object_.code()) |
    514         ValueBits::encode(value_.code()) |
    515         AddressBits::encode(address_.code()) |
    516         RememberedSetActionBits::encode(remembered_set_action_) |
    517         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
    518   }
    519 
    520   void Activate(Code* code) {
    521     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
    522   }
    523 
    524   class ObjectBits: public BitField<int, 0, 3> {};
    525   class ValueBits: public BitField<int, 3, 3> {};
    526   class AddressBits: public BitField<int, 6, 3> {};
    527   class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
    528   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
    529 
    530   Register object_;
    531   Register value_;
    532   Register address_;
    533   RememberedSetAction remembered_set_action_;
    534   SaveFPRegsMode save_fp_regs_mode_;
    535   RegisterAllocation regs_;
    536 };
    537 
    538 
    539 } }  // namespace v8::internal
    540 
    541 #endif  // V8_IA32_CODE_STUBS_IA32_H_
    542