code-stubs-x64.h 12.7 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7 8 9 10 11

#ifndef V8_X64_CODE_STUBS_X64_H_
#define V8_X64_CODE_STUBS_X64_H_

namespace v8 {
namespace internal {


12 13
void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);

14

15 16 17 18 19
class StringHelper : public AllStatic {
 public:
  // Generate code for copying characters using the rep movs instruction.
  // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
  // not supported.
20 21 22 23 24
  static void GenerateCopyCharacters(MacroAssembler* masm,
                                     Register dest,
                                     Register src,
                                     Register count,
                                     String::Encoding encoding);
25

26 27
  // Compares two flat one-byte strings and returns result in rax.
  static void GenerateCompareFlatOneByteStrings(
28 29 30
      MacroAssembler* masm, Register left, Register right, Register scratch1,
      Register scratch2, Register scratch3, Register scratch4);

31 32 33 34 35
  // Compares two flat one-byte strings for equality and returns result in rax.
  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
                                              Register left, Register right,
                                              Register scratch1,
                                              Register scratch2);
36

37
 private:
38 39 40
  static void GenerateOneByteCharsCompareLoop(
      MacroAssembler* masm, Register left, Register right, Register length,
      Register scratch, Label* chars_not_equal,
41
      Label::Distance near_jump = Label::kFar);
42 43

  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
44 45 46
};


47
class NameDictionaryLookupStub: public PlatformCodeStub {
48 49 50
 public:
  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };

51 52 53 54 55 56 57
  NameDictionaryLookupStub(Isolate* isolate, Register dictionary,
                           Register result, Register index, LookupMode mode)
      : PlatformCodeStub(isolate) {
    minor_key_ = DictionaryBits::encode(dictionary.code()) |
                 ResultBits::encode(result.code()) |
                 IndexBits::encode(index.code()) | LookupModeBits::encode(mode);
  }
58

59 60 61 62
  static void GenerateNegativeLookup(MacroAssembler* masm,
                                     Label* miss,
                                     Label* done,
                                     Register properties,
63
                                     Handle<Name> name,
64 65
                                     Register r0);

66 67 68 69 70 71 72 73
  static void GeneratePositiveLookup(MacroAssembler* masm,
                                     Label* miss,
                                     Label* done,
                                     Register elements,
                                     Register name,
                                     Register r0,
                                     Register r1);

74
  bool SometimesSetsUpAFrame() override { return false; }
75

76 77 78 79 80
 private:
  static const int kInlinedProbes = 4;
  static const int kTotalProbes = 20;

  static const int kCapacityOffset =
81 82
      NameDictionary::kHeaderSize +
      NameDictionary::kCapacityIndex * kPointerSize;
83 84

  static const int kElementsStartOffset =
85 86
      NameDictionary::kHeaderSize +
      NameDictionary::kElementsStartIndex * kPointerSize;
87

88 89 90 91 92 93 94 95 96 97
  Register dictionary() const {
    return Register::from_code(DictionaryBits::decode(minor_key_));
  }

  Register result() const {
    return Register::from_code(ResultBits::decode(minor_key_));
  }

  Register index() const {
    return Register::from_code(IndexBits::decode(minor_key_));
98 99
  }

100 101
  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }

102 103 104 105 106
  class DictionaryBits: public BitField<int, 0, 4> {};
  class ResultBits: public BitField<int, 4, 4> {};
  class IndexBits: public BitField<int, 8, 4> {};
  class LookupModeBits: public BitField<LookupMode, 12, 1> {};

107
  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
108
  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
109 110 111
};


112
class RecordWriteStub: public PlatformCodeStub {
113
 public:
114 115
  RecordWriteStub(Isolate* isolate, Register object, Register value,
                  Register address, RememberedSetAction remembered_set_action,
116
                  SaveFPRegsMode fp_mode)
117
      : PlatformCodeStub(isolate),
118 119 120
        regs_(object,   // An input reg.
              address,  // An input reg.
              value) {  // One scratch reg.
121 122 123 124 125
    minor_key_ = ObjectBits::encode(object.code()) |
                 ValueBits::encode(value.code()) |
                 AddressBits::encode(address.code()) |
                 RememberedSetActionBits::encode(remembered_set_action) |
                 SaveFPRegsModeBits::encode(fp_mode);
126 127
  }

128 129 130
  RecordWriteStub(uint32_t key, Isolate* isolate)
      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}

131 132 133 134 135 136
  enum Mode {
    STORE_BUFFER_ONLY,
    INCREMENTAL,
    INCREMENTAL_COMPACTION
  };

137
  bool SometimesSetsUpAFrame() override { return false; }
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

  static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
  static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.

  static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
  static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.

  static Mode GetMode(Code* stub) {
    byte first_instruction = stub->instruction_start()[0];
    byte second_instruction = stub->instruction_start()[2];

    if (first_instruction == kTwoByteJumpInstruction) {
      return INCREMENTAL;
    }

153
    DCHECK(first_instruction == kTwoByteNopInstruction);
154 155 156 157 158

    if (second_instruction == kFiveByteJumpInstruction) {
      return INCREMENTAL_COMPACTION;
    }

159
    DCHECK(second_instruction == kFiveByteNopInstruction);
160 161 162 163 164 165 166

    return STORE_BUFFER_ONLY;
  }

  static void Patch(Code* stub, Mode mode) {
    switch (mode) {
      case STORE_BUFFER_ONLY:
167
        DCHECK(GetMode(stub) == INCREMENTAL ||
168 169 170 171 172
               GetMode(stub) == INCREMENTAL_COMPACTION);
        stub->instruction_start()[0] = kTwoByteNopInstruction;
        stub->instruction_start()[2] = kFiveByteNopInstruction;
        break;
      case INCREMENTAL:
173
        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
174 175 176
        stub->instruction_start()[0] = kTwoByteJumpInstruction;
        break;
      case INCREMENTAL_COMPACTION:
177
        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
178 179 180 181
        stub->instruction_start()[0] = kTwoByteNopInstruction;
        stub->instruction_start()[2] = kFiveByteJumpInstruction;
        break;
    }
182
    DCHECK(GetMode(stub) == mode);
183
    Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 7);
184 185
  }

186 187
  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
 private:
  // This is a helper class for freeing up 3 scratch registers, where the third
  // is always rcx (needed for shift operations).  The input is two registers
  // that must be preserved and one scratch register provided by the caller.
  class RegisterAllocation {
   public:
    RegisterAllocation(Register object,
                       Register address,
                       Register scratch0)
        : object_orig_(object),
          address_orig_(address),
          scratch0_orig_(scratch0),
          object_(object),
          address_(address),
          scratch0_(scratch0) {
203
      DCHECK(!AreAliased(scratch0, object, address, no_reg));
204 205 206 207 208 209 210 211 212 213
      scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
      if (scratch0.is(rcx)) {
        scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
      }
      if (object.is(rcx)) {
        object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
      }
      if (address.is(rcx)) {
        address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
      }
214
      DCHECK(!AreAliased(scratch0_, object_, address_, rcx));
215 216 217
    }

    void Save(MacroAssembler* masm) {
218 219 220 221 222
      DCHECK(!address_orig_.is(object_));
      DCHECK(object_.is(object_orig_) || address_.is(address_orig_));
      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
      DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
      DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
223 224 225
      // We don't have to save scratch0_orig_ because it was given to us as
      // a scratch register.  But if we had to switch to a different reg then
      // we should save the new scratch0_.
226
      if (!scratch0_.is(scratch0_orig_)) masm->Push(scratch0_);
227 228 229
      if (!rcx.is(scratch0_orig_) &&
          !rcx.is(object_orig_) &&
          !rcx.is(address_orig_)) {
230
        masm->Push(rcx);
231
      }
232
      masm->Push(scratch1_);
233
      if (!address_.is(address_orig_)) {
234
        masm->Push(address_);
235
        masm->movp(address_, address_orig_);
236 237
      }
      if (!object_.is(object_orig_)) {
238
        masm->Push(object_);
239
        masm->movp(object_, object_orig_);
240 241 242 243 244 245 246 247
      }
    }

    void Restore(MacroAssembler* masm) {
      // These will have been preserved the entire time, so we just need to move
      // them back.  Only in one case is the orig_ reg different from the plain
      // one, since only one of them can alias with rcx.
      if (!object_.is(object_orig_)) {
248
        masm->movp(object_orig_, object_);
249
        masm->Pop(object_);
250 251
      }
      if (!address_.is(address_orig_)) {
252
        masm->movp(address_orig_, address_);
253
        masm->Pop(address_);
254
      }
255
      masm->Pop(scratch1_);
256 257 258
      if (!rcx.is(scratch0_orig_) &&
          !rcx.is(object_orig_) &&
          !rcx.is(address_orig_)) {
259
        masm->Pop(rcx);
260
      }
261
      if (!scratch0_.is(scratch0_orig_)) masm->Pop(scratch0_);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    }

    // If we have to call into C then we need to save and restore all caller-
    // saved registers that were not already preserved.

    // The three scratch registers (incl. rcx) will be restored by other means
    // so we don't bother pushing them here.  Rbx, rbp and r12-15 are callee
    // save and don't need to be preserved.
    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
      masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
    }

    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
                                           SaveFPRegsMode mode) {
      masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
    }

    inline Register object() { return object_; }
    inline Register address() { return address_; }
    inline Register scratch0() { return scratch0_; }
    inline Register scratch1() { return scratch1_; }

   private:
    Register object_orig_;
    Register address_orig_;
    Register scratch0_orig_;
    Register object_;
    Register address_;
    Register scratch0_;
    Register scratch1_;
    // Third scratch register is always rcx.

    Register GetRegThatIsNotRcxOr(Register r1,
                                  Register r2,
                                  Register r3) {
297 298 299 300 301 302 303 304 305
      for (int i = 0; i < Register::kNumRegisters; i++) {
        Register candidate = Register::from_code(i);
        if (candidate.IsAllocatable()) {
          if (candidate.is(rcx)) continue;
          if (candidate.is(r1)) continue;
          if (candidate.is(r2)) continue;
          if (candidate.is(r3)) continue;
          return candidate;
        }
306 307 308 309 310 311 312 313 314 315 316 317
      }
      UNREACHABLE();
      return no_reg;
    }
    friend class RecordWriteStub;
  };

  enum OnNoNeedToInformIncrementalMarker {
    kReturnOnNoNeedToInformIncrementalMarker,
    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
  };

318
  Major MajorKey() const final { return RecordWrite; }
319

320
  void Generate(MacroAssembler* masm) override;
321 322 323 324 325
  void GenerateIncremental(MacroAssembler* masm, Mode mode);
  void CheckNeedsToInformIncrementalMarker(
      MacroAssembler* masm,
      OnNoNeedToInformIncrementalMarker on_no_need,
      Mode mode);
326
  void InformIncrementalMarker(MacroAssembler* masm);
327

328
  void Activate(Code* code) override {
329 330
    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
  }
331

332 333
  Register object() const {
    return Register::from_code(ObjectBits::decode(minor_key_));
334 335
  }

336 337 338 339 340 341 342 343 344 345 346 347 348 349
  Register value() const {
    return Register::from_code(ValueBits::decode(minor_key_));
  }

  Register address() const {
    return Register::from_code(AddressBits::decode(minor_key_));
  }

  RememberedSetAction remembered_set_action() const {
    return RememberedSetActionBits::decode(minor_key_);
  }

  SaveFPRegsMode save_fp_regs_mode() const {
    return SaveFPRegsModeBits::decode(minor_key_);
350 351 352 353 354 355 356 357 358 359
  }

  class ObjectBits: public BitField<int, 0, 4> {};
  class ValueBits: public BitField<int, 4, 4> {};
  class AddressBits: public BitField<int, 8, 4> {};
  class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
  class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};

  Label slow_;
  RegisterAllocation regs_;
360 361

  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
362 363 364
};


365 366
}  // namespace internal
}  // namespace v8
367 368

#endif  // V8_X64_CODE_STUBS_X64_H_