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_X87_CODE_STUBS_X87_H_
6#define V8_X87_CODE_STUBS_X87_H_
7
8#include "src/macro-assembler.h"
9#include "src/ic-inl.h"
10
11namespace v8 {
12namespace internal {
13
14
15void ArrayNativeCode(MacroAssembler* masm,
16                     bool construct_call,
17                     Label* call_generic_code);
18
19
20class StoreBufferOverflowStub: public PlatformCodeStub {
21 public:
22  explicit StoreBufferOverflowStub(Isolate* isolate)
23      : PlatformCodeStub(isolate) { }
24
25  void Generate(MacroAssembler* masm);
26
27  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
28  virtual bool SometimesSetsUpAFrame() { return false; }
29
30 private:
31  Major MajorKey() { return StoreBufferOverflow; }
32  int MinorKey() { return 0; }
33};
34
35
36class StringHelper : public AllStatic {
37 public:
38  // Generate code for copying characters using the rep movs instruction.
39  // Copies ecx characters from esi to edi. Copying of overlapping regions is
40  // not supported.
41  static void GenerateCopyCharacters(MacroAssembler* masm,
42                                     Register dest,
43                                     Register src,
44                                     Register count,
45                                     Register scratch,
46                                     String::Encoding encoding);
47
48  // Generate string hash.
49  static void GenerateHashInit(MacroAssembler* masm,
50                               Register hash,
51                               Register character,
52                               Register scratch);
53  static void GenerateHashAddCharacter(MacroAssembler* masm,
54                                       Register hash,
55                                       Register character,
56                                       Register scratch);
57  static void GenerateHashGetHash(MacroAssembler* masm,
58                                  Register hash,
59                                  Register scratch);
60
61 private:
62  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
63};
64
65
66class SubStringStub: public PlatformCodeStub {
67 public:
68  explicit SubStringStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
69
70 private:
71  Major MajorKey() { return SubString; }
72  int MinorKey() { return 0; }
73
74  void Generate(MacroAssembler* masm);
75};
76
77
78class StringCompareStub: public PlatformCodeStub {
79 public:
80  explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) { }
81
82  // Compares two flat ASCII strings and returns result in eax.
83  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
84                                              Register left,
85                                              Register right,
86                                              Register scratch1,
87                                              Register scratch2,
88                                              Register scratch3);
89
90  // Compares two flat ASCII strings for equality and returns result
91  // in eax.
92  static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
93                                            Register left,
94                                            Register right,
95                                            Register scratch1,
96                                            Register scratch2);
97
98 private:
99  virtual Major MajorKey() { return StringCompare; }
100  virtual int MinorKey() { return 0; }
101  virtual void Generate(MacroAssembler* masm);
102
103  static void GenerateAsciiCharsCompareLoop(
104      MacroAssembler* masm,
105      Register left,
106      Register right,
107      Register length,
108      Register scratch,
109      Label* chars_not_equal,
110      Label::Distance chars_not_equal_near = Label::kFar);
111};
112
113
114class NameDictionaryLookupStub: public PlatformCodeStub {
115 public:
116  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
117
118  NameDictionaryLookupStub(Isolate* isolate,
119                           Register dictionary,
120                           Register result,
121                           Register index,
122                           LookupMode mode)
123      : PlatformCodeStub(isolate),
124        dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
125
126  void Generate(MacroAssembler* masm);
127
128  static void GenerateNegativeLookup(MacroAssembler* masm,
129                                     Label* miss,
130                                     Label* done,
131                                     Register properties,
132                                     Handle<Name> name,
133                                     Register r0);
134
135  static void GeneratePositiveLookup(MacroAssembler* masm,
136                                     Label* miss,
137                                     Label* done,
138                                     Register elements,
139                                     Register name,
140                                     Register r0,
141                                     Register r1);
142
143  virtual bool SometimesSetsUpAFrame() { return false; }
144
145 private:
146  static const int kInlinedProbes = 4;
147  static const int kTotalProbes = 20;
148
149  static const int kCapacityOffset =
150      NameDictionary::kHeaderSize +
151      NameDictionary::kCapacityIndex * kPointerSize;
152
153  static const int kElementsStartOffset =
154      NameDictionary::kHeaderSize +
155      NameDictionary::kElementsStartIndex * kPointerSize;
156
157  Major MajorKey() { return NameDictionaryLookup; }
158
159  int MinorKey() {
160    return DictionaryBits::encode(dictionary_.code()) |
161        ResultBits::encode(result_.code()) |
162        IndexBits::encode(index_.code()) |
163        LookupModeBits::encode(mode_);
164  }
165
166  class DictionaryBits: public BitField<int, 0, 3> {};
167  class ResultBits: public BitField<int, 3, 3> {};
168  class IndexBits: public BitField<int, 6, 3> {};
169  class LookupModeBits: public BitField<LookupMode, 9, 1> {};
170
171  Register dictionary_;
172  Register result_;
173  Register index_;
174  LookupMode mode_;
175};
176
177
178class RecordWriteStub: public PlatformCodeStub {
179 public:
180  RecordWriteStub(Isolate* isolate,
181                  Register object,
182                  Register value,
183                  Register address,
184                  RememberedSetAction remembered_set_action)
185      : PlatformCodeStub(isolate),
186        object_(object),
187        value_(value),
188        address_(address),
189        remembered_set_action_(remembered_set_action),
190        regs_(object,   // An input reg.
191              address,  // An input reg.
192              value) {  // One scratch reg.
193  }
194
195  enum Mode {
196    STORE_BUFFER_ONLY,
197    INCREMENTAL,
198    INCREMENTAL_COMPACTION
199  };
200
201  virtual bool SometimesSetsUpAFrame() { return false; }
202
203  static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
204  static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
205
206  static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
207  static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
208
209  static Mode GetMode(Code* stub) {
210    byte first_instruction = stub->instruction_start()[0];
211    byte second_instruction = stub->instruction_start()[2];
212
213    if (first_instruction == kTwoByteJumpInstruction) {
214      return INCREMENTAL;
215    }
216
217    ASSERT(first_instruction == kTwoByteNopInstruction);
218
219    if (second_instruction == kFiveByteJumpInstruction) {
220      return INCREMENTAL_COMPACTION;
221    }
222
223    ASSERT(second_instruction == kFiveByteNopInstruction);
224
225    return STORE_BUFFER_ONLY;
226  }
227
228  static void Patch(Code* stub, Mode mode) {
229    switch (mode) {
230      case STORE_BUFFER_ONLY:
231        ASSERT(GetMode(stub) == INCREMENTAL ||
232               GetMode(stub) == INCREMENTAL_COMPACTION);
233        stub->instruction_start()[0] = kTwoByteNopInstruction;
234        stub->instruction_start()[2] = kFiveByteNopInstruction;
235        break;
236      case INCREMENTAL:
237        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
238        stub->instruction_start()[0] = kTwoByteJumpInstruction;
239        break;
240      case INCREMENTAL_COMPACTION:
241        ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
242        stub->instruction_start()[0] = kTwoByteNopInstruction;
243        stub->instruction_start()[2] = kFiveByteJumpInstruction;
244        break;
245    }
246    ASSERT(GetMode(stub) == mode);
247    CPU::FlushICache(stub->instruction_start(), 7);
248  }
249
250 private:
251  // This is a helper class for freeing up 3 scratch registers, where the third
252  // is always ecx (needed for shift operations).  The input is two registers
253  // that must be preserved and one scratch register provided by the caller.
254  class RegisterAllocation {
255   public:
256    RegisterAllocation(Register object,
257                       Register address,
258                       Register scratch0)
259        : object_orig_(object),
260          address_orig_(address),
261          scratch0_orig_(scratch0),
262          object_(object),
263          address_(address),
264          scratch0_(scratch0) {
265      ASSERT(!AreAliased(scratch0, object, address, no_reg));
266      scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
267      if (scratch0.is(ecx)) {
268        scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
269      }
270      if (object.is(ecx)) {
271        object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
272      }
273      if (address.is(ecx)) {
274        address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
275      }
276      ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
277    }
278
279    void Save(MacroAssembler* masm) {
280      ASSERT(!address_orig_.is(object_));
281      ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
282      ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
283      ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
284      ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
285      // We don't have to save scratch0_orig_ because it was given to us as
286      // a scratch register.  But if we had to switch to a different reg then
287      // we should save the new scratch0_.
288      if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
289      if (!ecx.is(scratch0_orig_) &&
290          !ecx.is(object_orig_) &&
291          !ecx.is(address_orig_)) {
292        masm->push(ecx);
293      }
294      masm->push(scratch1_);
295      if (!address_.is(address_orig_)) {
296        masm->push(address_);
297        masm->mov(address_, address_orig_);
298      }
299      if (!object_.is(object_orig_)) {
300        masm->push(object_);
301        masm->mov(object_, object_orig_);
302      }
303    }
304
305    void Restore(MacroAssembler* masm) {
306      // These will have been preserved the entire time, so we just need to move
307      // them back.  Only in one case is the orig_ reg different from the plain
308      // one, since only one of them can alias with ecx.
309      if (!object_.is(object_orig_)) {
310        masm->mov(object_orig_, object_);
311        masm->pop(object_);
312      }
313      if (!address_.is(address_orig_)) {
314        masm->mov(address_orig_, address_);
315        masm->pop(address_);
316      }
317      masm->pop(scratch1_);
318      if (!ecx.is(scratch0_orig_) &&
319          !ecx.is(object_orig_) &&
320          !ecx.is(address_orig_)) {
321        masm->pop(ecx);
322      }
323      if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
324    }
325
326    // If we have to call into C then we need to save and restore all caller-
327    // saved registers that were not already preserved.  The caller saved
328    // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
329    // will be restored by other means so we don't bother pushing them here.
330    void SaveCallerSaveRegisters(MacroAssembler* masm) {
331      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
332      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
333    }
334
335    inline void RestoreCallerSaveRegisters(MacroAssembler*masm) {
336      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
337      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
338    }
339
340    inline Register object() { return object_; }
341    inline Register address() { return address_; }
342    inline Register scratch0() { return scratch0_; }
343    inline Register scratch1() { return scratch1_; }
344
345   private:
346    Register object_orig_;
347    Register address_orig_;
348    Register scratch0_orig_;
349    Register object_;
350    Register address_;
351    Register scratch0_;
352    Register scratch1_;
353    // Third scratch register is always ecx.
354
355    Register GetRegThatIsNotEcxOr(Register r1,
356                                  Register r2,
357                                  Register r3) {
358      for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
359        Register candidate = Register::FromAllocationIndex(i);
360        if (candidate.is(ecx)) continue;
361        if (candidate.is(r1)) continue;
362        if (candidate.is(r2)) continue;
363        if (candidate.is(r3)) continue;
364        return candidate;
365      }
366      UNREACHABLE();
367      return no_reg;
368    }
369    friend class RecordWriteStub;
370  };
371
372  enum OnNoNeedToInformIncrementalMarker {
373    kReturnOnNoNeedToInformIncrementalMarker,
374    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
375  }
376;
377  void Generate(MacroAssembler* masm);
378  void GenerateIncremental(MacroAssembler* masm, Mode mode);
379  void CheckNeedsToInformIncrementalMarker(
380      MacroAssembler* masm,
381      OnNoNeedToInformIncrementalMarker on_no_need,
382      Mode mode);
383  void InformIncrementalMarker(MacroAssembler* masm);
384
385  Major MajorKey() { return RecordWrite; }
386
387  int MinorKey() {
388    return ObjectBits::encode(object_.code()) |
389        ValueBits::encode(value_.code()) |
390        AddressBits::encode(address_.code()) |
391        RememberedSetActionBits::encode(remembered_set_action_);
392  }
393
394  void Activate(Code* code) {
395    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
396  }
397
398  class ObjectBits: public BitField<int, 0, 3> {};
399  class ValueBits: public BitField<int, 3, 3> {};
400  class AddressBits: public BitField<int, 6, 3> {};
401  class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
402
403  Register object_;
404  Register value_;
405  Register address_;
406  RememberedSetAction remembered_set_action_;
407  RegisterAllocation regs_;
408};
409
410
411} }  // namespace v8::internal
412
413#endif  // V8_X87_CODE_STUBS_X87_H_
414