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 / ia32 / code-stubs-ia32.h @ f230a1cf

History | View | Annotate | Download (19.8 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_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
  virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE { return true; }
78
  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
79
  virtual bool SometimesSetsUpAFrame() { return false; }
80

    
81
 private:
82
  SaveFPRegsMode save_doubles_;
83

    
84
  Major MajorKey() { return StoreBufferOverflow; }
85
  int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
86
};
87

    
88

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

    
102
  // Generate code for copying characters using the rep movs instruction.
103
  // Copies ecx characters from esi to edi. Copying of overlapping regions is
104
  // not supported.
105
  static void GenerateCopyCharactersREP(MacroAssembler* masm,
106
                                        Register dest,     // Must be edi.
107
                                        Register src,      // Must be esi.
108
                                        Register count,    // Must be ecx.
109
                                        Register scratch,  // Neither of above.
110
                                        bool ascii);
111

    
112
  // Probe the string table for a two character string. If the string
113
  // requires non-standard hashing a jump to the label not_probed is
114
  // performed and registers c1 and c2 are preserved. In all other
115
  // cases they are clobbered. If the string is not found by probing a
116
  // jump to the label not_found is performed. This jump does not
117
  // guarantee that the string is not in the string table. If the
118
  // string is found the code falls through with the string in
119
  // register eax.
120
  static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
121
                                                   Register c1,
122
                                                   Register c2,
123
                                                   Register scratch1,
124
                                                   Register scratch2,
125
                                                   Register scratch3,
126
                                                   Label* not_probed,
127
                                                   Label* not_found);
128

    
129
  // Generate string hash.
130
  static void GenerateHashInit(MacroAssembler* masm,
131
                               Register hash,
132
                               Register character,
133
                               Register scratch);
134
  static void GenerateHashAddCharacter(MacroAssembler* masm,
135
                                       Register hash,
136
                                       Register character,
137
                                       Register scratch);
138
  static void GenerateHashGetHash(MacroAssembler* masm,
139
                                  Register hash,
140
                                  Register scratch);
141

    
142
 private:
143
  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
144
};
145

    
146

    
147
class StringAddStub: public PlatformCodeStub {
148
 public:
149
  explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
150

    
151
 private:
152
  Major MajorKey() { return StringAdd; }
153
  int MinorKey() { return flags_; }
154

    
155
  void Generate(MacroAssembler* masm);
156

    
157
  void GenerateConvertArgument(MacroAssembler* masm,
158
                               int stack_offset,
159
                               Register arg,
160
                               Register scratch1,
161
                               Register scratch2,
162
                               Register scratch3,
163
                               Label* slow);
164

    
165
  void GenerateRegisterArgsPush(MacroAssembler* masm);
166
  void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
167

    
168
  const StringAddFlags flags_;
169
};
170

    
171

    
172
class SubStringStub: public PlatformCodeStub {
173
 public:
174
  SubStringStub() {}
175

    
176
 private:
177
  Major MajorKey() { return SubString; }
178
  int MinorKey() { return 0; }
179

    
180
  void Generate(MacroAssembler* masm);
181
};
182

    
183

    
184
class StringCompareStub: public PlatformCodeStub {
185
 public:
186
  StringCompareStub() { }
187

    
188
  // Compares two flat ASCII strings and returns result in eax.
189
  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
190
                                              Register left,
191
                                              Register right,
192
                                              Register scratch1,
193
                                              Register scratch2,
194
                                              Register scratch3);
195

    
196
  // Compares two flat ASCII strings for equality and returns result
197
  // in eax.
198
  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
199
                                            Register left,
200
                                            Register right,
201
                                            Register scratch1,
202
                                            Register scratch2);
203

    
204
 private:
205
  virtual Major MajorKey() { return StringCompare; }
206
  virtual int MinorKey() { return 0; }
207
  virtual void Generate(MacroAssembler* masm);
208

    
209
  static void GenerateAsciiCharsCompareLoop(
210
      MacroAssembler* masm,
211
      Register left,
212
      Register right,
213
      Register length,
214
      Register scratch,
215
      Label* chars_not_equal,
216
      Label::Distance chars_not_equal_near = Label::kFar);
217
};
218

    
219

    
220
class NameDictionaryLookupStub: public PlatformCodeStub {
221
 public:
222
  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
223

    
224
  NameDictionaryLookupStub(Register dictionary,
225
                           Register result,
226
                           Register index,
227
                           LookupMode mode)
228
      : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
229

    
230
  void Generate(MacroAssembler* masm);
231

    
232
  static void GenerateNegativeLookup(MacroAssembler* masm,
233
                                     Label* miss,
234
                                     Label* done,
235
                                     Register properties,
236
                                     Handle<Name> name,
237
                                     Register r0);
238

    
239
  static void GeneratePositiveLookup(MacroAssembler* masm,
240
                                     Label* miss,
241
                                     Label* done,
242
                                     Register elements,
243
                                     Register name,
244
                                     Register r0,
245
                                     Register r1);
246

    
247
  virtual bool SometimesSetsUpAFrame() { return false; }
248

    
249
 private:
250
  static const int kInlinedProbes = 4;
251
  static const int kTotalProbes = 20;
252

    
253
  static const int kCapacityOffset =
254
      NameDictionary::kHeaderSize +
255
      NameDictionary::kCapacityIndex * kPointerSize;
256

    
257
  static const int kElementsStartOffset =
258
      NameDictionary::kHeaderSize +
259
      NameDictionary::kElementsStartIndex * kPointerSize;
260

    
261
  Major MajorKey() { return NameDictionaryLookup; }
262

    
263
  int MinorKey() {
264
    return DictionaryBits::encode(dictionary_.code()) |
265
        ResultBits::encode(result_.code()) |
266
        IndexBits::encode(index_.code()) |
267
        LookupModeBits::encode(mode_);
268
  }
269

    
270
  class DictionaryBits: public BitField<int, 0, 3> {};
271
  class ResultBits: public BitField<int, 3, 3> {};
272
  class IndexBits: public BitField<int, 6, 3> {};
273
  class LookupModeBits: public BitField<LookupMode, 9, 1> {};
274

    
275
  Register dictionary_;
276
  Register result_;
277
  Register index_;
278
  LookupMode mode_;
279
};
280

    
281

    
282
class RecordWriteStub: public PlatformCodeStub {
283
 public:
284
  RecordWriteStub(Register object,
285
                  Register value,
286
                  Register address,
287
                  RememberedSetAction remembered_set_action,
288
                  SaveFPRegsMode fp_mode)
289
      : object_(object),
290
        value_(value),
291
        address_(address),
292
        remembered_set_action_(remembered_set_action),
293
        save_fp_regs_mode_(fp_mode),
294
        regs_(object,   // An input reg.
295
              address,  // An input reg.
296
              value) {  // One scratch reg.
297
    ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || fp_mode == kDontSaveFPRegs);
298
  }
299

    
300
  enum Mode {
301
    STORE_BUFFER_ONLY,
302
    INCREMENTAL,
303
    INCREMENTAL_COMPACTION
304
  };
305

    
306
  virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE;
307
  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
308
  virtual bool SometimesSetsUpAFrame() { return false; }
309

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

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

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

    
320
    if (first_instruction == kTwoByteJumpInstruction) {
321
      return INCREMENTAL;
322
    }
323

    
324
    ASSERT(first_instruction == kTwoByteNopInstruction);
325

    
326
    if (second_instruction == kFiveByteJumpInstruction) {
327
      return INCREMENTAL_COMPACTION;
328
    }
329

    
330
    ASSERT(second_instruction == kFiveByteNopInstruction);
331

    
332
    return STORE_BUFFER_ONLY;
333
  }
334

    
335
  static void Patch(Code* stub, Mode mode) {
336
    switch (mode) {
337
      case STORE_BUFFER_ONLY:
338
        ASSERT(GetMode(stub) == INCREMENTAL ||
339
               GetMode(stub) == INCREMENTAL_COMPACTION);
340
        stub->instruction_start()[0] = kTwoByteNopInstruction;
341
        stub->instruction_start()[2] = kFiveByteNopInstruction;
342
        break;
343
      case INCREMENTAL:
344
        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
345
        stub->instruction_start()[0] = kTwoByteJumpInstruction;
346
        break;
347
      case INCREMENTAL_COMPACTION:
348
        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
349
        stub->instruction_start()[0] = kTwoByteNopInstruction;
350
        stub->instruction_start()[2] = kFiveByteJumpInstruction;
351
        break;
352
    }
353
    ASSERT(GetMode(stub) == mode);
354
    CPU::FlushICache(stub->instruction_start(), 7);
355
  }
356

    
357
 private:
358
  // This is a helper class for freeing up 3 scratch registers, where the third
359
  // is always ecx (needed for shift operations).  The input is two registers
360
  // that must be preserved and one scratch register provided by the caller.
361
  class RegisterAllocation {
362
   public:
363
    RegisterAllocation(Register object,
364
                       Register address,
365
                       Register scratch0)
366
        : object_orig_(object),
367
          address_orig_(address),
368
          scratch0_orig_(scratch0),
369
          object_(object),
370
          address_(address),
371
          scratch0_(scratch0) {
372
      ASSERT(!AreAliased(scratch0, object, address, no_reg));
373
      scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
374
      if (scratch0.is(ecx)) {
375
        scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
376
      }
377
      if (object.is(ecx)) {
378
        object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
379
      }
380
      if (address.is(ecx)) {
381
        address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
382
      }
383
      ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
384
    }
385

    
386
    void Save(MacroAssembler* masm) {
387
      ASSERT(!address_orig_.is(object_));
388
      ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
389
      ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
390
      ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
391
      ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
392
      // We don't have to save scratch0_orig_ because it was given to us as
393
      // a scratch register.  But if we had to switch to a different reg then
394
      // we should save the new scratch0_.
395
      if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
396
      if (!ecx.is(scratch0_orig_) &&
397
          !ecx.is(object_orig_) &&
398
          !ecx.is(address_orig_)) {
399
        masm->push(ecx);
400
      }
401
      masm->push(scratch1_);
402
      if (!address_.is(address_orig_)) {
403
        masm->push(address_);
404
        masm->mov(address_, address_orig_);
405
      }
406
      if (!object_.is(object_orig_)) {
407
        masm->push(object_);
408
        masm->mov(object_, object_orig_);
409
      }
410
    }
411

    
412
    void Restore(MacroAssembler* masm) {
413
      // These will have been preserved the entire time, so we just need to move
414
      // them back.  Only in one case is the orig_ reg different from the plain
415
      // one, since only one of them can alias with ecx.
416
      if (!object_.is(object_orig_)) {
417
        masm->mov(object_orig_, object_);
418
        masm->pop(object_);
419
      }
420
      if (!address_.is(address_orig_)) {
421
        masm->mov(address_orig_, address_);
422
        masm->pop(address_);
423
      }
424
      masm->pop(scratch1_);
425
      if (!ecx.is(scratch0_orig_) &&
426
          !ecx.is(object_orig_) &&
427
          !ecx.is(address_orig_)) {
428
        masm->pop(ecx);
429
      }
430
      if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
431
    }
432

    
433
    // If we have to call into C then we need to save and restore all caller-
434
    // saved registers that were not already preserved.  The caller saved
435
    // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
436
    // will be restored by other means so we don't bother pushing them here.
437
    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
438
      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
439
      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
440
      if (mode == kSaveFPRegs) {
441
        CpuFeatureScope scope(masm, SSE2);
442
        masm->sub(esp,
443
                  Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
444
        // Save all XMM registers except XMM0.
445
        for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
446
          XMMRegister reg = XMMRegister::from_code(i);
447
          masm->movsd(Operand(esp, (i - 1) * kDoubleSize), reg);
448
        }
449
      }
450
    }
451

    
452
    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
453
                                           SaveFPRegsMode mode) {
454
      if (mode == kSaveFPRegs) {
455
        CpuFeatureScope scope(masm, SSE2);
456
        // Restore all XMM registers except XMM0.
457
        for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
458
          XMMRegister reg = XMMRegister::from_code(i);
459
          masm->movsd(reg, Operand(esp, (i - 1) * kDoubleSize));
460
        }
461
        masm->add(esp,
462
                  Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
463
      }
464
      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
465
      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
466
    }
467

    
468
    inline Register object() { return object_; }
469
    inline Register address() { return address_; }
470
    inline Register scratch0() { return scratch0_; }
471
    inline Register scratch1() { return scratch1_; }
472

    
473
   private:
474
    Register object_orig_;
475
    Register address_orig_;
476
    Register scratch0_orig_;
477
    Register object_;
478
    Register address_;
479
    Register scratch0_;
480
    Register scratch1_;
481
    // Third scratch register is always ecx.
482

    
483
    Register GetRegThatIsNotEcxOr(Register r1,
484
                                  Register r2,
485
                                  Register r3) {
486
      for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
487
        Register candidate = Register::FromAllocationIndex(i);
488
        if (candidate.is(ecx)) continue;
489
        if (candidate.is(r1)) continue;
490
        if (candidate.is(r2)) continue;
491
        if (candidate.is(r3)) continue;
492
        return candidate;
493
      }
494
      UNREACHABLE();
495
      return no_reg;
496
    }
497
    friend class RecordWriteStub;
498
  };
499

    
500
  enum OnNoNeedToInformIncrementalMarker {
501
    kReturnOnNoNeedToInformIncrementalMarker,
502
    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
503
  }
504
;
505
  void Generate(MacroAssembler* masm);
506
  void GenerateIncremental(MacroAssembler* masm, Mode mode);
507
  void CheckNeedsToInformIncrementalMarker(
508
      MacroAssembler* masm,
509
      OnNoNeedToInformIncrementalMarker on_no_need,
510
      Mode mode);
511
  void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
512

    
513
  Major MajorKey() { return RecordWrite; }
514

    
515
  int MinorKey() {
516
    return ObjectBits::encode(object_.code()) |
517
        ValueBits::encode(value_.code()) |
518
        AddressBits::encode(address_.code()) |
519
        RememberedSetActionBits::encode(remembered_set_action_) |
520
        SaveFPRegsModeBits::encode(save_fp_regs_mode_);
521
  }
522

    
523
  void Activate(Code* code) {
524
    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
525
  }
526

    
527
  class ObjectBits: public BitField<int, 0, 3> {};
528
  class ValueBits: public BitField<int, 3, 3> {};
529
  class AddressBits: public BitField<int, 6, 3> {};
530
  class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
531
  class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
532

    
533
  Register object_;
534
  Register value_;
535
  Register address_;
536
  RememberedSetAction remembered_set_action_;
537
  SaveFPRegsMode save_fp_regs_mode_;
538
  RegisterAllocation regs_;
539
};
540

    
541

    
542
} }  // namespace v8::internal
543

    
544
#endif  // V8_IA32_CODE_STUBS_IA32_H_