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