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