• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_X64_CODE_STUBS_X64_H_
29 #define V8_X64_CODE_STUBS_X64_H_
30 
31 #include "ic-inl.h"
32 #include "type-info.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 
38 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
39 
40 // Compute a transcendental math function natively, or call the
41 // TranscendentalCache runtime function.
42 class TranscendentalCacheStub: public PlatformCodeStub {
43  public:
44   enum ArgumentType {
45     TAGGED = 0,
46     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
47   };
48 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)49   explicit TranscendentalCacheStub(TranscendentalCache::Type type,
50                                    ArgumentType argument_type)
51       : type_(type), argument_type_(argument_type) {}
52   void Generate(MacroAssembler* masm);
53   static void GenerateOperation(MacroAssembler* masm,
54                                 TranscendentalCache::Type type);
55  private:
56   TranscendentalCache::Type type_;
57   ArgumentType argument_type_;
58 
MajorKey()59   Major MajorKey() { return TranscendentalCache; }
MinorKey()60   int MinorKey() { return type_ | argument_type_; }
61   Runtime::FunctionId RuntimeFunction();
62 };
63 
64 
65 class StoreBufferOverflowStub: public PlatformCodeStub {
66  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)67   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
68       : save_doubles_(save_fp) { }
69 
70   void Generate(MacroAssembler* masm);
71 
72   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
SometimesSetsUpAFrame()73   virtual bool SometimesSetsUpAFrame() { return false; }
74 
75  private:
76   SaveFPRegsMode save_doubles_;
77 
MajorKey()78   Major MajorKey() { return StoreBufferOverflow; }
MinorKey()79   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
80 };
81 
82 
83 class StringHelper : public AllStatic {
84  public:
85   // Generate code for copying characters using a simple loop. This should only
86   // be used in places where the number of characters is small and the
87   // additional setup and checking in GenerateCopyCharactersREP adds too much
88   // overhead. Copying of overlapping regions is not supported.
89   static void GenerateCopyCharacters(MacroAssembler* masm,
90                                      Register dest,
91                                      Register src,
92                                      Register count,
93                                      bool ascii);
94 
95   // Generate code for copying characters using the rep movs instruction.
96   // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
97   // not supported.
98   static void GenerateCopyCharactersREP(MacroAssembler* masm,
99                                         Register dest,     // Must be rdi.
100                                         Register src,      // Must be rsi.
101                                         Register count,    // Must be rcx.
102                                         bool ascii);
103 
104 
105   // Probe the string table for a two character string. If the string is
106   // not found by probing a jump to the label not_found is performed. This jump
107   // does not guarantee that the string is not in the string table. If the
108   // string is found the code falls through with the string in register rax.
109   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
110                                                    Register c1,
111                                                    Register c2,
112                                                    Register scratch1,
113                                                    Register scratch2,
114                                                    Register scratch3,
115                                                    Register scratch4,
116                                                    Label* not_found);
117 
118   // Generate string hash.
119   static void GenerateHashInit(MacroAssembler* masm,
120                                Register hash,
121                                Register character,
122                                Register scratch);
123   static void GenerateHashAddCharacter(MacroAssembler* masm,
124                                        Register hash,
125                                        Register character,
126                                        Register scratch);
127   static void GenerateHashGetHash(MacroAssembler* masm,
128                                   Register hash,
129                                   Register scratch);
130 
131  private:
132   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
133 };
134 
135 
136 class StringAddStub: public PlatformCodeStub {
137  public:
StringAddStub(StringAddFlags flags)138   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
139 
140  private:
MajorKey()141   Major MajorKey() { return StringAdd; }
MinorKey()142   int MinorKey() { return flags_; }
143 
144   void Generate(MacroAssembler* masm);
145 
146   void GenerateConvertArgument(MacroAssembler* masm,
147                                int stack_offset,
148                                Register arg,
149                                Register scratch1,
150                                Register scratch2,
151                                Register scratch3,
152                                Label* slow);
153 
154   void GenerateRegisterArgsPush(MacroAssembler* masm);
155   void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
156 
157   const StringAddFlags flags_;
158 };
159 
160 
161 class SubStringStub: public PlatformCodeStub {
162  public:
SubStringStub()163   SubStringStub() {}
164 
165  private:
MajorKey()166   Major MajorKey() { return SubString; }
MinorKey()167   int MinorKey() { return 0; }
168 
169   void Generate(MacroAssembler* masm);
170 };
171 
172 
173 class StringCompareStub: public PlatformCodeStub {
174  public:
StringCompareStub()175   StringCompareStub() {}
176 
177   // Compares two flat ASCII strings and returns result in rax.
178   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
179                                               Register left,
180                                               Register right,
181                                               Register scratch1,
182                                               Register scratch2,
183                                               Register scratch3,
184                                               Register scratch4);
185 
186   // Compares two flat ASCII strings for equality and returns result
187   // in rax.
188   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
189                                             Register left,
190                                             Register right,
191                                             Register scratch1,
192                                             Register scratch2);
193 
194  private:
MajorKey()195   virtual Major MajorKey() { return StringCompare; }
MinorKey()196   virtual int MinorKey() { return 0; }
197   virtual void Generate(MacroAssembler* masm);
198 
199   static void GenerateAsciiCharsCompareLoop(
200       MacroAssembler* masm,
201       Register left,
202       Register right,
203       Register length,
204       Register scratch,
205       Label* chars_not_equal,
206       Label::Distance near_jump = Label::kFar);
207 };
208 
209 
210 class NameDictionaryLookupStub: public PlatformCodeStub {
211  public:
212   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
213 
NameDictionaryLookupStub(Register dictionary,Register result,Register index,LookupMode mode)214   NameDictionaryLookupStub(Register dictionary,
215                            Register result,
216                            Register index,
217                            LookupMode mode)
218       : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
219 
220   void Generate(MacroAssembler* masm);
221 
222   static void GenerateNegativeLookup(MacroAssembler* masm,
223                                      Label* miss,
224                                      Label* done,
225                                      Register properties,
226                                      Handle<Name> name,
227                                      Register r0);
228 
229   static void GeneratePositiveLookup(MacroAssembler* masm,
230                                      Label* miss,
231                                      Label* done,
232                                      Register elements,
233                                      Register name,
234                                      Register r0,
235                                      Register r1);
236 
SometimesSetsUpAFrame()237   virtual bool SometimesSetsUpAFrame() { return false; }
238 
239  private:
240   static const int kInlinedProbes = 4;
241   static const int kTotalProbes = 20;
242 
243   static const int kCapacityOffset =
244       NameDictionary::kHeaderSize +
245       NameDictionary::kCapacityIndex * kPointerSize;
246 
247   static const int kElementsStartOffset =
248       NameDictionary::kHeaderSize +
249       NameDictionary::kElementsStartIndex * kPointerSize;
250 
MajorKey()251   Major MajorKey() { return NameDictionaryLookup; }
252 
MinorKey()253   int MinorKey() {
254     return DictionaryBits::encode(dictionary_.code()) |
255         ResultBits::encode(result_.code()) |
256         IndexBits::encode(index_.code()) |
257         LookupModeBits::encode(mode_);
258   }
259 
260   class DictionaryBits: public BitField<int, 0, 4> {};
261   class ResultBits: public BitField<int, 4, 4> {};
262   class IndexBits: public BitField<int, 8, 4> {};
263   class LookupModeBits: public BitField<LookupMode, 12, 1> {};
264 
265   Register dictionary_;
266   Register result_;
267   Register index_;
268   LookupMode mode_;
269 };
270 
271 
272 class RecordWriteStub: public PlatformCodeStub {
273  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)274   RecordWriteStub(Register object,
275                   Register value,
276                   Register address,
277                   RememberedSetAction remembered_set_action,
278                   SaveFPRegsMode fp_mode)
279       : object_(object),
280         value_(value),
281         address_(address),
282         remembered_set_action_(remembered_set_action),
283         save_fp_regs_mode_(fp_mode),
284         regs_(object,   // An input reg.
285               address,  // An input reg.
286               value) {  // One scratch reg.
287   }
288 
289   enum Mode {
290     STORE_BUFFER_ONLY,
291     INCREMENTAL,
292     INCREMENTAL_COMPACTION
293   };
294 
SometimesSetsUpAFrame()295   virtual bool SometimesSetsUpAFrame() { return false; }
296 
297   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
298   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
299 
300   static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
301   static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
302 
GetMode(Code * stub)303   static Mode GetMode(Code* stub) {
304     byte first_instruction = stub->instruction_start()[0];
305     byte second_instruction = stub->instruction_start()[2];
306 
307     if (first_instruction == kTwoByteJumpInstruction) {
308       return INCREMENTAL;
309     }
310 
311     ASSERT(first_instruction == kTwoByteNopInstruction);
312 
313     if (second_instruction == kFiveByteJumpInstruction) {
314       return INCREMENTAL_COMPACTION;
315     }
316 
317     ASSERT(second_instruction == kFiveByteNopInstruction);
318 
319     return STORE_BUFFER_ONLY;
320   }
321 
Patch(Code * stub,Mode mode)322   static void Patch(Code* stub, Mode mode) {
323     switch (mode) {
324       case STORE_BUFFER_ONLY:
325         ASSERT(GetMode(stub) == INCREMENTAL ||
326                GetMode(stub) == INCREMENTAL_COMPACTION);
327         stub->instruction_start()[0] = kTwoByteNopInstruction;
328         stub->instruction_start()[2] = kFiveByteNopInstruction;
329         break;
330       case INCREMENTAL:
331         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
332         stub->instruction_start()[0] = kTwoByteJumpInstruction;
333         break;
334       case INCREMENTAL_COMPACTION:
335         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
336         stub->instruction_start()[0] = kTwoByteNopInstruction;
337         stub->instruction_start()[2] = kFiveByteJumpInstruction;
338         break;
339     }
340     ASSERT(GetMode(stub) == mode);
341     CPU::FlushICache(stub->instruction_start(), 7);
342   }
343 
344  private:
345   // This is a helper class for freeing up 3 scratch registers, where the third
346   // is always rcx (needed for shift operations).  The input is two registers
347   // that must be preserved and one scratch register provided by the caller.
348   class RegisterAllocation {
349    public:
RegisterAllocation(Register object,Register address,Register scratch0)350     RegisterAllocation(Register object,
351                        Register address,
352                        Register scratch0)
353         : object_orig_(object),
354           address_orig_(address),
355           scratch0_orig_(scratch0),
356           object_(object),
357           address_(address),
358           scratch0_(scratch0) {
359       ASSERT(!AreAliased(scratch0, object, address, no_reg));
360       scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
361       if (scratch0.is(rcx)) {
362         scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
363       }
364       if (object.is(rcx)) {
365         object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
366       }
367       if (address.is(rcx)) {
368         address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
369       }
370       ASSERT(!AreAliased(scratch0_, object_, address_, rcx));
371     }
372 
Save(MacroAssembler * masm)373     void Save(MacroAssembler* masm) {
374       ASSERT(!address_orig_.is(object_));
375       ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
376       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
377       ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
378       ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
379       // We don't have to save scratch0_orig_ because it was given to us as
380       // a scratch register.  But if we had to switch to a different reg then
381       // we should save the new scratch0_.
382       if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
383       if (!rcx.is(scratch0_orig_) &&
384           !rcx.is(object_orig_) &&
385           !rcx.is(address_orig_)) {
386         masm->push(rcx);
387       }
388       masm->push(scratch1_);
389       if (!address_.is(address_orig_)) {
390         masm->push(address_);
391         masm->movq(address_, address_orig_);
392       }
393       if (!object_.is(object_orig_)) {
394         masm->push(object_);
395         masm->movq(object_, object_orig_);
396       }
397     }
398 
Restore(MacroAssembler * masm)399     void Restore(MacroAssembler* masm) {
400       // These will have been preserved the entire time, so we just need to move
401       // them back.  Only in one case is the orig_ reg different from the plain
402       // one, since only one of them can alias with rcx.
403       if (!object_.is(object_orig_)) {
404         masm->movq(object_orig_, object_);
405         masm->pop(object_);
406       }
407       if (!address_.is(address_orig_)) {
408         masm->movq(address_orig_, address_);
409         masm->pop(address_);
410       }
411       masm->pop(scratch1_);
412       if (!rcx.is(scratch0_orig_) &&
413           !rcx.is(object_orig_) &&
414           !rcx.is(address_orig_)) {
415         masm->pop(rcx);
416       }
417       if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
418     }
419 
420     // If we have to call into C then we need to save and restore all caller-
421     // saved registers that were not already preserved.
422 
423     // The three scratch registers (incl. rcx) will be restored by other means
424     // so we don't bother pushing them here.  Rbx, rbp and r12-15 are callee
425     // save and don't need to be preserved.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)426     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
427       masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
428     }
429 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)430     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
431                                            SaveFPRegsMode mode) {
432       masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
433     }
434 
object()435     inline Register object() { return object_; }
address()436     inline Register address() { return address_; }
scratch0()437     inline Register scratch0() { return scratch0_; }
scratch1()438     inline Register scratch1() { return scratch1_; }
439 
440    private:
441     Register object_orig_;
442     Register address_orig_;
443     Register scratch0_orig_;
444     Register object_;
445     Register address_;
446     Register scratch0_;
447     Register scratch1_;
448     // Third scratch register is always rcx.
449 
GetRegThatIsNotRcxOr(Register r1,Register r2,Register r3)450     Register GetRegThatIsNotRcxOr(Register r1,
451                                   Register r2,
452                                   Register r3) {
453       for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
454         Register candidate = Register::FromAllocationIndex(i);
455         if (candidate.is(rcx)) continue;
456         if (candidate.is(r1)) continue;
457         if (candidate.is(r2)) continue;
458         if (candidate.is(r3)) continue;
459         return candidate;
460       }
461       UNREACHABLE();
462       return no_reg;
463     }
464     friend class RecordWriteStub;
465   };
466 
467   enum OnNoNeedToInformIncrementalMarker {
468     kReturnOnNoNeedToInformIncrementalMarker,
469     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
470   };
471 
472   void Generate(MacroAssembler* masm);
473   void GenerateIncremental(MacroAssembler* masm, Mode mode);
474   void CheckNeedsToInformIncrementalMarker(
475       MacroAssembler* masm,
476       OnNoNeedToInformIncrementalMarker on_no_need,
477       Mode mode);
478   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
479 
MajorKey()480   Major MajorKey() { return RecordWrite; }
481 
MinorKey()482   int MinorKey() {
483     return ObjectBits::encode(object_.code()) |
484         ValueBits::encode(value_.code()) |
485         AddressBits::encode(address_.code()) |
486         RememberedSetActionBits::encode(remembered_set_action_) |
487         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
488   }
489 
Activate(Code * code)490   void Activate(Code* code) {
491     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
492   }
493 
494   class ObjectBits: public BitField<int, 0, 4> {};
495   class ValueBits: public BitField<int, 4, 4> {};
496   class AddressBits: public BitField<int, 8, 4> {};
497   class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
498   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
499 
500   Register object_;
501   Register value_;
502   Register address_;
503   RememberedSetAction remembered_set_action_;
504   SaveFPRegsMode save_fp_regs_mode_;
505   Label slow_;
506   RegisterAllocation regs_;
507 };
508 
509 
510 } }  // namespace v8::internal
511 
512 #endif  // V8_X64_CODE_STUBS_X64_H_
513