LCOV - code coverage report
Current view: top level - src/x64 - code-stubs-x64.h (source / functions) Hit Total Coverage
Test: app.info Lines: 72 81 88.9 %
Date: 2017-04-26 Functions: 9 19 47.4 %

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

Generated by: LCOV version 1.10