Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / ia32 / code-stubs-ia32.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_IA32_CODE_STUBS_IA32_H_
6 #define V8_IA32_CODE_STUBS_IA32_H_
7
8 #include "src/ic-inl.h"
9 #include "src/macro-assembler.h"
10
11 namespace v8 {
12 namespace internal {
13
14
15 void ArrayNativeCode(MacroAssembler* masm,
16                      bool construct_call,
17                      Label* call_generic_code);
18
19
20 class StoreBufferOverflowStub: public PlatformCodeStub {
21  public:
22   StoreBufferOverflowStub(Isolate* isolate, SaveFPRegsMode save_fp)
23       : PlatformCodeStub(isolate), save_doubles_(save_fp) { }
24
25   void Generate(MacroAssembler* masm);
26
27   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
28   virtual bool SometimesSetsUpAFrame() { return false; }
29
30  private:
31   SaveFPRegsMode save_doubles_;
32
33   Major MajorKey() const { return StoreBufferOverflow; }
34   int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
35 };
36
37
38 class StringHelper : public AllStatic {
39  public:
40   // Generate code for copying characters using the rep movs instruction.
41   // Copies ecx characters from esi to edi. Copying of overlapping regions is
42   // not supported.
43   static void GenerateCopyCharacters(MacroAssembler* masm,
44                                      Register dest,
45                                      Register src,
46                                      Register count,
47                                      Register scratch,
48                                      String::Encoding encoding);
49
50   // Generate string hash.
51   static void GenerateHashInit(MacroAssembler* masm,
52                                Register hash,
53                                Register character,
54                                Register scratch);
55   static void GenerateHashAddCharacter(MacroAssembler* masm,
56                                        Register hash,
57                                        Register character,
58                                        Register scratch);
59   static void GenerateHashGetHash(MacroAssembler* masm,
60                                   Register hash,
61                                   Register scratch);
62
63  private:
64   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
65 };
66
67
68 class SubStringStub: public PlatformCodeStub {
69  public:
70   explicit SubStringStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
71
72  private:
73   Major MajorKey() const { return SubString; }
74   int MinorKey() const { return 0; }
75
76   void Generate(MacroAssembler* masm);
77 };
78
79
80 class StringCompareStub: public PlatformCodeStub {
81  public:
82   explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) { }
83
84   // Compares two flat ASCII strings and returns result in eax.
85   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
86                                               Register left,
87                                               Register right,
88                                               Register scratch1,
89                                               Register scratch2,
90                                               Register scratch3);
91
92   // Compares two flat ASCII strings for equality and returns result
93   // in eax.
94   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
95                                             Register left,
96                                             Register right,
97                                             Register scratch1,
98                                             Register scratch2);
99
100  private:
101   virtual Major MajorKey() const { return StringCompare; }
102   virtual int MinorKey() const { return 0; }
103   virtual void Generate(MacroAssembler* masm);
104
105   static void GenerateAsciiCharsCompareLoop(
106       MacroAssembler* masm,
107       Register left,
108       Register right,
109       Register length,
110       Register scratch,
111       Label* chars_not_equal,
112       Label::Distance chars_not_equal_near = Label::kFar);
113 };
114
115
116 class NameDictionaryLookupStub: public PlatformCodeStub {
117  public:
118   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
119
120   NameDictionaryLookupStub(Isolate* isolate,
121                            Register dictionary,
122                            Register result,
123                            Register index,
124                            LookupMode mode)
125       : PlatformCodeStub(isolate),
126         dictionary_(dictionary), result_(result), index_(index), 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() const { return NameDictionaryLookup; }
160
161   int MinorKey() const {
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, 3> {};
169   class ResultBits: public BitField<int, 3, 3> {};
170   class IndexBits: public BitField<int, 6, 3> {};
171   class LookupModeBits: public BitField<LookupMode, 9, 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     DCHECK(first_instruction == kTwoByteNopInstruction);
222
223     if (second_instruction == kFiveByteJumpInstruction) {
224       return INCREMENTAL_COMPACTION;
225     }
226
227     DCHECK(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         DCHECK(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         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
242         stub->instruction_start()[0] = kTwoByteJumpInstruction;
243         break;
244       case INCREMENTAL_COMPACTION:
245         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
246         stub->instruction_start()[0] = kTwoByteNopInstruction;
247         stub->instruction_start()[2] = kFiveByteJumpInstruction;
248         break;
249     }
250     DCHECK(GetMode(stub) == mode);
251     CpuFeatures::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 ecx (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       DCHECK(!AreAliased(scratch0, object, address, no_reg));
270       scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
271       if (scratch0.is(ecx)) {
272         scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
273       }
274       if (object.is(ecx)) {
275         object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
276       }
277       if (address.is(ecx)) {
278         address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
279       }
280       DCHECK(!AreAliased(scratch0_, object_, address_, ecx));
281     }
282
283     void Save(MacroAssembler* masm) {
284       DCHECK(!address_orig_.is(object_));
285       DCHECK(object_.is(object_orig_) || address_.is(address_orig_));
286       DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
287       DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
288       DCHECK(!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 (!ecx.is(scratch0_orig_) &&
294           !ecx.is(object_orig_) &&
295           !ecx.is(address_orig_)) {
296         masm->push(ecx);
297       }
298       masm->push(scratch1_);
299       if (!address_.is(address_orig_)) {
300         masm->push(address_);
301         masm->mov(address_, address_orig_);
302       }
303       if (!object_.is(object_orig_)) {
304         masm->push(object_);
305         masm->mov(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 ecx.
313       if (!object_.is(object_orig_)) {
314         masm->mov(object_orig_, object_);
315         masm->pop(object_);
316       }
317       if (!address_.is(address_orig_)) {
318         masm->mov(address_orig_, address_);
319         masm->pop(address_);
320       }
321       masm->pop(scratch1_);
322       if (!ecx.is(scratch0_orig_) &&
323           !ecx.is(object_orig_) &&
324           !ecx.is(address_orig_)) {
325         masm->pop(ecx);
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.  The caller saved
332     // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
333     // will be restored by other means so we don't bother pushing them here.
334     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
335       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
336       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
337       if (mode == kSaveFPRegs) {
338         masm->sub(esp,
339                   Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1)));
340         // Save all XMM registers except XMM0.
341         for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) {
342           XMMRegister reg = XMMRegister::from_code(i);
343           masm->movsd(Operand(esp, (i - 1) * kDoubleSize), reg);
344         }
345       }
346     }
347
348     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
349                                            SaveFPRegsMode mode) {
350       if (mode == kSaveFPRegs) {
351         // Restore all XMM registers except XMM0.
352         for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) {
353           XMMRegister reg = XMMRegister::from_code(i);
354           masm->movsd(reg, Operand(esp, (i - 1) * kDoubleSize));
355         }
356         masm->add(esp,
357                   Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1)));
358       }
359       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
360       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
361     }
362
363     inline Register object() { return object_; }
364     inline Register address() { return address_; }
365     inline Register scratch0() { return scratch0_; }
366     inline Register scratch1() { return scratch1_; }
367
368    private:
369     Register object_orig_;
370     Register address_orig_;
371     Register scratch0_orig_;
372     Register object_;
373     Register address_;
374     Register scratch0_;
375     Register scratch1_;
376     // Third scratch register is always ecx.
377
378     Register GetRegThatIsNotEcxOr(Register r1,
379                                   Register r2,
380                                   Register r3) {
381       for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
382         Register candidate = Register::FromAllocationIndex(i);
383         if (candidate.is(ecx)) continue;
384         if (candidate.is(r1)) continue;
385         if (candidate.is(r2)) continue;
386         if (candidate.is(r3)) continue;
387         return candidate;
388       }
389       UNREACHABLE();
390       return no_reg;
391     }
392     friend class RecordWriteStub;
393   };
394
395   enum OnNoNeedToInformIncrementalMarker {
396     kReturnOnNoNeedToInformIncrementalMarker,
397     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
398   }
399 ;
400   void Generate(MacroAssembler* masm);
401   void GenerateIncremental(MacroAssembler* masm, Mode mode);
402   void CheckNeedsToInformIncrementalMarker(
403       MacroAssembler* masm,
404       OnNoNeedToInformIncrementalMarker on_no_need,
405       Mode mode);
406   void InformIncrementalMarker(MacroAssembler* masm);
407
408   Major MajorKey() const { return RecordWrite; }
409
410   int MinorKey() const {
411     return ObjectBits::encode(object_.code()) |
412         ValueBits::encode(value_.code()) |
413         AddressBits::encode(address_.code()) |
414         RememberedSetActionBits::encode(remembered_set_action_) |
415         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
416   }
417
418   void Activate(Code* code) {
419     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
420   }
421
422   class ObjectBits: public BitField<int, 0, 3> {};
423   class ValueBits: public BitField<int, 3, 3> {};
424   class AddressBits: public BitField<int, 6, 3> {};
425   class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
426   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
427
428   Register object_;
429   Register value_;
430   Register address_;
431   RememberedSetAction remembered_set_action_;
432   SaveFPRegsMode save_fp_regs_mode_;
433   RegisterAllocation regs_;
434 };
435
436
437 } }  // namespace v8::internal
438
439 #endif  // V8_IA32_CODE_STUBS_IA32_H_