The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / x64 / code-stubs-x64.h @ f230a1cf

History | View | Annotate | Download (18.4 KB)

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_X64_CODE_STUBS_X64_H_
29
#define V8_X64_CODE_STUBS_X64_H_
30

    
31
#include "ic-inl.h"
32
#include "type-info.h"
33

    
34
namespace v8 {
35
namespace internal {
36

    
37

    
38
void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
39

    
40
// Compute a transcendental math function natively, or call the
41
// TranscendentalCache runtime function.
42
class TranscendentalCacheStub: public PlatformCodeStub {
43
 public:
44
  enum ArgumentType {
45
    TAGGED = 0,
46
    UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
47
  };
48

    
49
  explicit TranscendentalCacheStub(TranscendentalCache::Type type,
50
                                   ArgumentType argument_type)
51
      : type_(type), argument_type_(argument_type) {}
52
  void Generate(MacroAssembler* masm);
53
  static void GenerateOperation(MacroAssembler* masm,
54
                                TranscendentalCache::Type type);
55
 private:
56
  TranscendentalCache::Type type_;
57
  ArgumentType argument_type_;
58

    
59
  Major MajorKey() { return TranscendentalCache; }
60
  int MinorKey() { return type_ | argument_type_; }
61
  Runtime::FunctionId RuntimeFunction();
62
};
63

    
64

    
65
class StoreBufferOverflowStub: public PlatformCodeStub {
66
 public:
67
  explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
68
      : save_doubles_(save_fp) { }
69

    
70
  void Generate(MacroAssembler* masm);
71

    
72
  virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE { return true; }
73
  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
74
  virtual bool SometimesSetsUpAFrame() { return false; }
75

    
76
 private:
77
  SaveFPRegsMode save_doubles_;
78

    
79
  Major MajorKey() { return StoreBufferOverflow; }
80
  int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
81
};
82

    
83

    
84
class StringHelper : public AllStatic {
85
 public:
86
  // Generate code for copying characters using a simple loop. This should only
87
  // be used in places where the number of characters is small and the
88
  // additional setup and checking in GenerateCopyCharactersREP adds too much
89
  // overhead. Copying of overlapping regions is not supported.
90
  static void GenerateCopyCharacters(MacroAssembler* masm,
91
                                     Register dest,
92
                                     Register src,
93
                                     Register count,
94
                                     bool ascii);
95

    
96
  // Generate code for copying characters using the rep movs instruction.
97
  // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
98
  // not supported.
99
  static void GenerateCopyCharactersREP(MacroAssembler* masm,
100
                                        Register dest,     // Must be rdi.
101
                                        Register src,      // Must be rsi.
102
                                        Register count,    // Must be rcx.
103
                                        bool ascii);
104

    
105

    
106
  // Probe the string table for a two character string. If the string is
107
  // not found by probing a jump to the label not_found is performed. This jump
108
  // does not guarantee that the string is not in the string table. If the
109
  // string is found the code falls through with the string in register rax.
110
  static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
111
                                                   Register c1,
112
                                                   Register c2,
113
                                                   Register scratch1,
114
                                                   Register scratch2,
115
                                                   Register scratch3,
116
                                                   Register scratch4,
117
                                                   Label* not_found);
118

    
119
  // Generate string hash.
120
  static void GenerateHashInit(MacroAssembler* masm,
121
                               Register hash,
122
                               Register character,
123
                               Register scratch);
124
  static void GenerateHashAddCharacter(MacroAssembler* masm,
125
                                       Register hash,
126
                                       Register character,
127
                                       Register scratch);
128
  static void GenerateHashGetHash(MacroAssembler* masm,
129
                                  Register hash,
130
                                  Register scratch);
131

    
132
 private:
133
  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
134
};
135

    
136

    
137
class StringAddStub: public PlatformCodeStub {
138
 public:
139
  explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
140

    
141
 private:
142
  Major MajorKey() { return StringAdd; }
143
  int MinorKey() { return flags_; }
144

    
145
  void Generate(MacroAssembler* masm);
146

    
147
  void GenerateConvertArgument(MacroAssembler* masm,
148
                               int stack_offset,
149
                               Register arg,
150
                               Register scratch1,
151
                               Register scratch2,
152
                               Register scratch3,
153
                               Label* slow);
154

    
155
  void GenerateRegisterArgsPush(MacroAssembler* masm);
156
  void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
157

    
158
  const StringAddFlags flags_;
159
};
160

    
161

    
162
class SubStringStub: public PlatformCodeStub {
163
 public:
164
  SubStringStub() {}
165

    
166
 private:
167
  Major MajorKey() { return SubString; }
168
  int MinorKey() { return 0; }
169

    
170
  void Generate(MacroAssembler* masm);
171
};
172

    
173

    
174
class StringCompareStub: public PlatformCodeStub {
175
 public:
176
  StringCompareStub() {}
177

    
178
  // Compares two flat ASCII strings and returns result in rax.
179
  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
180
                                              Register left,
181
                                              Register right,
182
                                              Register scratch1,
183
                                              Register scratch2,
184
                                              Register scratch3,
185
                                              Register scratch4);
186

    
187
  // Compares two flat ASCII strings for equality and returns result
188
  // in rax.
189
  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
190
                                            Register left,
191
                                            Register right,
192
                                            Register scratch1,
193
                                            Register scratch2);
194

    
195
 private:
196
  virtual Major MajorKey() { return StringCompare; }
197
  virtual int MinorKey() { return 0; }
198
  virtual void Generate(MacroAssembler* masm);
199

    
200
  static void GenerateAsciiCharsCompareLoop(
201
      MacroAssembler* masm,
202
      Register left,
203
      Register right,
204
      Register length,
205
      Register scratch,
206
      Label* chars_not_equal,
207
      Label::Distance near_jump = Label::kFar);
208
};
209

    
210

    
211
class NameDictionaryLookupStub: public PlatformCodeStub {
212
 public:
213
  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
214

    
215
  NameDictionaryLookupStub(Register dictionary,
216
                           Register result,
217
                           Register index,
218
                           LookupMode mode)
219
      : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
220

    
221
  void Generate(MacroAssembler* masm);
222

    
223
  static void GenerateNegativeLookup(MacroAssembler* masm,
224
                                     Label* miss,
225
                                     Label* done,
226
                                     Register properties,
227
                                     Handle<Name> name,
228
                                     Register r0);
229

    
230
  static void GeneratePositiveLookup(MacroAssembler* masm,
231
                                     Label* miss,
232
                                     Label* done,
233
                                     Register elements,
234
                                     Register name,
235
                                     Register r0,
236
                                     Register r1);
237

    
238
  virtual bool SometimesSetsUpAFrame() { return false; }
239

    
240
 private:
241
  static const int kInlinedProbes = 4;
242
  static const int kTotalProbes = 20;
243

    
244
  static const int kCapacityOffset =
245
      NameDictionary::kHeaderSize +
246
      NameDictionary::kCapacityIndex * kPointerSize;
247

    
248
  static const int kElementsStartOffset =
249
      NameDictionary::kHeaderSize +
250
      NameDictionary::kElementsStartIndex * kPointerSize;
251

    
252
  Major MajorKey() { return NameDictionaryLookup; }
253

    
254
  int MinorKey() {
255
    return DictionaryBits::encode(dictionary_.code()) |
256
        ResultBits::encode(result_.code()) |
257
        IndexBits::encode(index_.code()) |
258
        LookupModeBits::encode(mode_);
259
  }
260

    
261
  class DictionaryBits: public BitField<int, 0, 4> {};
262
  class ResultBits: public BitField<int, 4, 4> {};
263
  class IndexBits: public BitField<int, 8, 4> {};
264
  class LookupModeBits: public BitField<LookupMode, 12, 1> {};
265

    
266
  Register dictionary_;
267
  Register result_;
268
  Register index_;
269
  LookupMode mode_;
270
};
271

    
272

    
273
class RecordWriteStub: public PlatformCodeStub {
274
 public:
275
  RecordWriteStub(Register object,
276
                  Register value,
277
                  Register address,
278
                  RememberedSetAction remembered_set_action,
279
                  SaveFPRegsMode fp_mode)
280
      : object_(object),
281
        value_(value),
282
        address_(address),
283
        remembered_set_action_(remembered_set_action),
284
        save_fp_regs_mode_(fp_mode),
285
        regs_(object,   // An input reg.
286
              address,  // An input reg.
287
              value) {  // One scratch reg.
288
  }
289

    
290
  enum Mode {
291
    STORE_BUFFER_ONLY,
292
    INCREMENTAL,
293
    INCREMENTAL_COMPACTION
294
  };
295

    
296
  virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE;
297
  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
298
  virtual bool SometimesSetsUpAFrame() { return false; }
299

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

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

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

    
310
    if (first_instruction == kTwoByteJumpInstruction) {
311
      return INCREMENTAL;
312
    }
313

    
314
    ASSERT(first_instruction == kTwoByteNopInstruction);
315

    
316
    if (second_instruction == kFiveByteJumpInstruction) {
317
      return INCREMENTAL_COMPACTION;
318
    }
319

    
320
    ASSERT(second_instruction == kFiveByteNopInstruction);
321

    
322
    return STORE_BUFFER_ONLY;
323
  }
324

    
325
  static void Patch(Code* stub, Mode mode) {
326
    switch (mode) {
327
      case STORE_BUFFER_ONLY:
328
        ASSERT(GetMode(stub) == INCREMENTAL ||
329
               GetMode(stub) == INCREMENTAL_COMPACTION);
330
        stub->instruction_start()[0] = kTwoByteNopInstruction;
331
        stub->instruction_start()[2] = kFiveByteNopInstruction;
332
        break;
333
      case INCREMENTAL:
334
        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
335
        stub->instruction_start()[0] = kTwoByteJumpInstruction;
336
        break;
337
      case INCREMENTAL_COMPACTION:
338
        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
339
        stub->instruction_start()[0] = kTwoByteNopInstruction;
340
        stub->instruction_start()[2] = kFiveByteJumpInstruction;
341
        break;
342
    }
343
    ASSERT(GetMode(stub) == mode);
344
    CPU::FlushICache(stub->instruction_start(), 7);
345
  }
346

    
347
 private:
348
  // This is a helper class for freeing up 3 scratch registers, where the third
349
  // is always rcx (needed for shift operations).  The input is two registers
350
  // that must be preserved and one scratch register provided by the caller.
351
  class RegisterAllocation {
352
   public:
353
    RegisterAllocation(Register object,
354
                       Register address,
355
                       Register scratch0)
356
        : object_orig_(object),
357
          address_orig_(address),
358
          scratch0_orig_(scratch0),
359
          object_(object),
360
          address_(address),
361
          scratch0_(scratch0) {
362
      ASSERT(!AreAliased(scratch0, object, address, no_reg));
363
      scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
364
      if (scratch0.is(rcx)) {
365
        scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
366
      }
367
      if (object.is(rcx)) {
368
        object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
369
      }
370
      if (address.is(rcx)) {
371
        address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
372
      }
373
      ASSERT(!AreAliased(scratch0_, object_, address_, rcx));
374
    }
375

    
376
    void Save(MacroAssembler* masm) {
377
      ASSERT(!address_orig_.is(object_));
378
      ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
379
      ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
380
      ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
381
      ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
382
      // We don't have to save scratch0_orig_ because it was given to us as
383
      // a scratch register.  But if we had to switch to a different reg then
384
      // we should save the new scratch0_.
385
      if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
386
      if (!rcx.is(scratch0_orig_) &&
387
          !rcx.is(object_orig_) &&
388
          !rcx.is(address_orig_)) {
389
        masm->push(rcx);
390
      }
391
      masm->push(scratch1_);
392
      if (!address_.is(address_orig_)) {
393
        masm->push(address_);
394
        masm->movq(address_, address_orig_);
395
      }
396
      if (!object_.is(object_orig_)) {
397
        masm->push(object_);
398
        masm->movq(object_, object_orig_);
399
      }
400
    }
401

    
402
    void Restore(MacroAssembler* masm) {
403
      // These will have been preserved the entire time, so we just need to move
404
      // them back.  Only in one case is the orig_ reg different from the plain
405
      // one, since only one of them can alias with rcx.
406
      if (!object_.is(object_orig_)) {
407
        masm->movq(object_orig_, object_);
408
        masm->pop(object_);
409
      }
410
      if (!address_.is(address_orig_)) {
411
        masm->movq(address_orig_, address_);
412
        masm->pop(address_);
413
      }
414
      masm->pop(scratch1_);
415
      if (!rcx.is(scratch0_orig_) &&
416
          !rcx.is(object_orig_) &&
417
          !rcx.is(address_orig_)) {
418
        masm->pop(rcx);
419
      }
420
      if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
421
    }
422

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

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

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

    
438
    inline Register object() { return object_; }
439
    inline Register address() { return address_; }
440
    inline Register scratch0() { return scratch0_; }
441
    inline Register scratch1() { return scratch1_; }
442

    
443
   private:
444
    Register object_orig_;
445
    Register address_orig_;
446
    Register scratch0_orig_;
447
    Register object_;
448
    Register address_;
449
    Register scratch0_;
450
    Register scratch1_;
451
    // Third scratch register is always rcx.
452

    
453
    Register GetRegThatIsNotRcxOr(Register r1,
454
                                  Register r2,
455
                                  Register r3) {
456
      for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
457
        Register candidate = Register::FromAllocationIndex(i);
458
        if (candidate.is(rcx)) continue;
459
        if (candidate.is(r1)) continue;
460
        if (candidate.is(r2)) continue;
461
        if (candidate.is(r3)) continue;
462
        return candidate;
463
      }
464
      UNREACHABLE();
465
      return no_reg;
466
    }
467
    friend class RecordWriteStub;
468
  };
469

    
470
  enum OnNoNeedToInformIncrementalMarker {
471
    kReturnOnNoNeedToInformIncrementalMarker,
472
    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
473
  };
474

    
475
  void Generate(MacroAssembler* masm);
476
  void GenerateIncremental(MacroAssembler* masm, Mode mode);
477
  void CheckNeedsToInformIncrementalMarker(
478
      MacroAssembler* masm,
479
      OnNoNeedToInformIncrementalMarker on_no_need,
480
      Mode mode);
481
  void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
482

    
483
  Major MajorKey() { return RecordWrite; }
484

    
485
  int MinorKey() {
486
    return ObjectBits::encode(object_.code()) |
487
        ValueBits::encode(value_.code()) |
488
        AddressBits::encode(address_.code()) |
489
        RememberedSetActionBits::encode(remembered_set_action_) |
490
        SaveFPRegsModeBits::encode(save_fp_regs_mode_);
491
  }
492

    
493
  void Activate(Code* code) {
494
    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
495
  }
496

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

    
503
  Register object_;
504
  Register value_;
505
  Register address_;
506
  RememberedSetAction remembered_set_action_;
507
  SaveFPRegsMode save_fp_regs_mode_;
508
  Label slow_;
509
  RegisterAllocation regs_;
510
};
511

    
512

    
513
} }  // namespace v8::internal
514

    
515
#endif  // V8_X64_CODE_STUBS_X64_H_