• 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 // Compute a transcendental math function natively, or call the
39 // TranscendentalCache runtime function.
40 class TranscendentalCacheStub: public CodeStub {
41  public:
42   enum ArgumentType {
43     TAGGED = 0,
44     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
45   };
46 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)47   explicit TranscendentalCacheStub(TranscendentalCache::Type type,
48                                    ArgumentType argument_type)
49       : type_(type), argument_type_(argument_type) {}
50   void Generate(MacroAssembler* masm);
51   static void GenerateOperation(MacroAssembler* masm,
52                                 TranscendentalCache::Type type);
53  private:
54   TranscendentalCache::Type type_;
55   ArgumentType argument_type_;
56 
MajorKey()57   Major MajorKey() { return TranscendentalCache; }
MinorKey()58   int MinorKey() { return type_ | argument_type_; }
59   Runtime::FunctionId RuntimeFunction();
60 };
61 
62 
63 class StoreBufferOverflowStub: public CodeStub {
64  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)65   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
66       : save_doubles_(save_fp) { }
67 
68   void Generate(MacroAssembler* masm);
69 
IsPregenerated()70   virtual bool IsPregenerated() { return true; }
71   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()72   virtual bool SometimesSetsUpAFrame() { return false; }
73 
74  private:
75   SaveFPRegsMode save_doubles_;
76 
MajorKey()77   Major MajorKey() { return StoreBufferOverflow; }
MinorKey()78   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
79 };
80 
81 
82 // Flag that indicates how to generate code for the stub GenericBinaryOpStub.
83 enum GenericBinaryFlags {
84   NO_GENERIC_BINARY_FLAGS = 0,
85   NO_SMI_CODE_IN_STUB = 1 << 0  // Omit smi code in stub.
86 };
87 
88 
89 class UnaryOpStub: public CodeStub {
90  public:
91   UnaryOpStub(Token::Value op,
92               UnaryOverwriteMode mode,
93               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
op_(op)94       : op_(op),
95         mode_(mode),
96         operand_type_(operand_type) {
97   }
98 
99  private:
100   Token::Value op_;
101   UnaryOverwriteMode mode_;
102 
103   // Operand type information determined at runtime.
104   UnaryOpIC::TypeInfo operand_type_;
105 
106   virtual void PrintName(StringStream* stream);
107 
108   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
109   class OpBits: public BitField<Token::Value, 1, 7> {};
110   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
111 
MajorKey()112   Major MajorKey() { return UnaryOp; }
MinorKey()113   int MinorKey() {
114     return ModeBits::encode(mode_)
115            | OpBits::encode(op_)
116            | OperandTypeInfoBits::encode(operand_type_);
117   }
118 
119   // Note: A lot of the helper functions below will vanish when we use virtual
120   // function instead of switch more often.
121   void Generate(MacroAssembler* masm);
122 
123   void GenerateTypeTransition(MacroAssembler* masm);
124 
125   void GenerateSmiStub(MacroAssembler* masm);
126   void GenerateSmiStubSub(MacroAssembler* masm);
127   void GenerateSmiStubBitNot(MacroAssembler* masm);
128   void GenerateSmiCodeSub(MacroAssembler* masm,
129                           Label* non_smi,
130                           Label* slow,
131                           Label::Distance non_smi_near = Label::kFar,
132                           Label::Distance slow_near = Label::kFar);
133   void GenerateSmiCodeBitNot(MacroAssembler* masm,
134                              Label* non_smi,
135                              Label::Distance non_smi_near);
136 
137   void GenerateHeapNumberStub(MacroAssembler* masm);
138   void GenerateHeapNumberStubSub(MacroAssembler* masm);
139   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
140   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
141   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
142 
143   void GenerateGenericStub(MacroAssembler* masm);
144   void GenerateGenericStubSub(MacroAssembler* masm);
145   void GenerateGenericStubBitNot(MacroAssembler* masm);
146   void GenerateGenericCodeFallback(MacroAssembler* masm);
147 
GetCodeKind()148   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
149 
GetICState()150   virtual InlineCacheState GetICState() {
151     return UnaryOpIC::ToState(operand_type_);
152   }
153 
FinishCode(Handle<Code> code)154   virtual void FinishCode(Handle<Code> code) {
155     code->set_unary_op_type(operand_type_);
156   }
157 };
158 
159 
160 class BinaryOpStub: public CodeStub {
161  public:
BinaryOpStub(Token::Value op,OverwriteMode mode)162   BinaryOpStub(Token::Value op, OverwriteMode mode)
163       : op_(op),
164         mode_(mode),
165         operands_type_(BinaryOpIC::UNINITIALIZED),
166         result_type_(BinaryOpIC::UNINITIALIZED) {
167     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
168   }
169 
170   BinaryOpStub(
171       int key,
172       BinaryOpIC::TypeInfo operands_type,
173       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
op_(OpBits::decode (key))174       : op_(OpBits::decode(key)),
175         mode_(ModeBits::decode(key)),
176         operands_type_(operands_type),
177         result_type_(result_type) { }
178 
179  private:
180   enum SmiCodeGenerateHeapNumberResults {
181     ALLOW_HEAPNUMBER_RESULTS,
182     NO_HEAPNUMBER_RESULTS
183   };
184 
185   Token::Value op_;
186   OverwriteMode mode_;
187 
188   // Operand type information determined at runtime.
189   BinaryOpIC::TypeInfo operands_type_;
190   BinaryOpIC::TypeInfo result_type_;
191 
192   virtual void PrintName(StringStream* stream);
193 
194   // Minor key encoding in 15 bits RRRTTTOOOOOOOMM.
195   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
196   class OpBits: public BitField<Token::Value, 2, 7> {};
197   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {};
198   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {};
199 
MajorKey()200   Major MajorKey() { return BinaryOp; }
MinorKey()201   int MinorKey() {
202     return OpBits::encode(op_)
203            | ModeBits::encode(mode_)
204            | OperandTypeInfoBits::encode(operands_type_)
205            | ResultTypeInfoBits::encode(result_type_);
206   }
207 
208   void Generate(MacroAssembler* masm);
209   void GenerateGeneric(MacroAssembler* masm);
210   void GenerateSmiCode(MacroAssembler* masm,
211                        Label* slow,
212                        SmiCodeGenerateHeapNumberResults heapnumber_results);
213   void GenerateFloatingPointCode(MacroAssembler* masm,
214                                  Label* allocation_failure,
215                                  Label* non_numeric_failure);
216   void GenerateStringAddCode(MacroAssembler* masm);
217   void GenerateCallRuntimeCode(MacroAssembler* masm);
218   void GenerateLoadArguments(MacroAssembler* masm);
219   void GenerateReturn(MacroAssembler* masm);
220   void GenerateUninitializedStub(MacroAssembler* masm);
221   void GenerateSmiStub(MacroAssembler* masm);
222   void GenerateInt32Stub(MacroAssembler* masm);
223   void GenerateHeapNumberStub(MacroAssembler* masm);
224   void GenerateOddballStub(MacroAssembler* masm);
225   void GenerateStringStub(MacroAssembler* masm);
226   void GenerateBothStringStub(MacroAssembler* masm);
227   void GenerateGenericStub(MacroAssembler* masm);
228 
229   void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
230   void GenerateRegisterArgsPush(MacroAssembler* masm);
231   void GenerateTypeTransition(MacroAssembler* masm);
232   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
233 
GetCodeKind()234   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
235 
GetICState()236   virtual InlineCacheState GetICState() {
237     return BinaryOpIC::ToState(operands_type_);
238   }
239 
FinishCode(Handle<Code> code)240   virtual void FinishCode(Handle<Code> code) {
241     code->set_binary_op_type(operands_type_);
242     code->set_binary_op_result_type(result_type_);
243   }
244 
245   friend class CodeGenerator;
246 };
247 
248 
249 class StringHelper : public AllStatic {
250  public:
251   // Generate code for copying characters using a simple loop. This should only
252   // be used in places where the number of characters is small and the
253   // additional setup and checking in GenerateCopyCharactersREP adds too much
254   // overhead. Copying of overlapping regions is not supported.
255   static void GenerateCopyCharacters(MacroAssembler* masm,
256                                      Register dest,
257                                      Register src,
258                                      Register count,
259                                      bool ascii);
260 
261   // Generate code for copying characters using the rep movs instruction.
262   // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
263   // not supported.
264   static void GenerateCopyCharactersREP(MacroAssembler* masm,
265                                         Register dest,     // Must be rdi.
266                                         Register src,      // Must be rsi.
267                                         Register count,    // Must be rcx.
268                                         bool ascii);
269 
270 
271   // Probe the symbol table for a two character string. If the string is
272   // not found by probing a jump to the label not_found is performed. This jump
273   // does not guarantee that the string is not in the symbol table. If the
274   // string is found the code falls through with the string in register rax.
275   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
276                                                    Register c1,
277                                                    Register c2,
278                                                    Register scratch1,
279                                                    Register scratch2,
280                                                    Register scratch3,
281                                                    Register scratch4,
282                                                    Label* not_found);
283 
284   // Generate string hash.
285   static void GenerateHashInit(MacroAssembler* masm,
286                                Register hash,
287                                Register character,
288                                Register scratch);
289   static void GenerateHashAddCharacter(MacroAssembler* masm,
290                                        Register hash,
291                                        Register character,
292                                        Register scratch);
293   static void GenerateHashGetHash(MacroAssembler* masm,
294                                   Register hash,
295                                   Register scratch);
296 
297  private:
298   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
299 };
300 
301 
302 // Flag that indicates how to generate code for the stub StringAddStub.
303 enum StringAddFlags {
304   NO_STRING_ADD_FLAGS = 0,
305   // Omit left string check in stub (left is definitely a string).
306   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
307   // Omit right string check in stub (right is definitely a string).
308   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
309   // Omit both string checks in stub.
310   NO_STRING_CHECK_IN_STUB =
311       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
312 };
313 
314 
315 class StringAddStub: public CodeStub {
316  public:
StringAddStub(StringAddFlags flags)317   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
318 
319  private:
MajorKey()320   Major MajorKey() { return StringAdd; }
MinorKey()321   int MinorKey() { return flags_; }
322 
323   void Generate(MacroAssembler* masm);
324 
325   void GenerateConvertArgument(MacroAssembler* masm,
326                                int stack_offset,
327                                Register arg,
328                                Register scratch1,
329                                Register scratch2,
330                                Register scratch3,
331                                Label* slow);
332 
333   const StringAddFlags flags_;
334 };
335 
336 
337 class SubStringStub: public CodeStub {
338  public:
SubStringStub()339   SubStringStub() {}
340 
341  private:
MajorKey()342   Major MajorKey() { return SubString; }
MinorKey()343   int MinorKey() { return 0; }
344 
345   void Generate(MacroAssembler* masm);
346 };
347 
348 
349 class StringCompareStub: public CodeStub {
350  public:
StringCompareStub()351   StringCompareStub() {}
352 
353   // Compares two flat ASCII strings and returns result in rax.
354   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
355                                               Register left,
356                                               Register right,
357                                               Register scratch1,
358                                               Register scratch2,
359                                               Register scratch3,
360                                               Register scratch4);
361 
362   // Compares two flat ASCII strings for equality and returns result
363   // in rax.
364   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
365                                             Register left,
366                                             Register right,
367                                             Register scratch1,
368                                             Register scratch2);
369 
370  private:
MajorKey()371   virtual Major MajorKey() { return StringCompare; }
MinorKey()372   virtual int MinorKey() { return 0; }
373   virtual void Generate(MacroAssembler* masm);
374 
375   static void GenerateAsciiCharsCompareLoop(
376       MacroAssembler* masm,
377       Register left,
378       Register right,
379       Register length,
380       Register scratch,
381       Label* chars_not_equal,
382       Label::Distance near_jump = Label::kFar);
383 };
384 
385 
386 class NumberToStringStub: public CodeStub {
387  public:
NumberToStringStub()388   NumberToStringStub() { }
389 
390   // Generate code to do a lookup in the number string cache. If the number in
391   // the register object is found in the cache the generated code falls through
392   // with the result in the result register. The object and the result register
393   // can be the same. If the number is not found in the cache the code jumps to
394   // the label not_found with only the content of register object unchanged.
395   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
396                                               Register object,
397                                               Register result,
398                                               Register scratch1,
399                                               Register scratch2,
400                                               bool object_is_smi,
401                                               Label* not_found);
402 
403  private:
404   static void GenerateConvertHashCodeToIndex(MacroAssembler* masm,
405                                              Register hash,
406                                              Register mask);
407 
MajorKey()408   Major MajorKey() { return NumberToString; }
MinorKey()409   int MinorKey() { return 0; }
410 
411   void Generate(MacroAssembler* masm);
412 };
413 
414 
415 class StringDictionaryLookupStub: public CodeStub {
416  public:
417   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
418 
StringDictionaryLookupStub(Register dictionary,Register result,Register index,LookupMode mode)419   StringDictionaryLookupStub(Register dictionary,
420                              Register result,
421                              Register index,
422                              LookupMode mode)
423       : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
424 
425   void Generate(MacroAssembler* masm);
426 
427   static void GenerateNegativeLookup(MacroAssembler* masm,
428                                      Label* miss,
429                                      Label* done,
430                                      Register properties,
431                                      Handle<String> name,
432                                      Register r0);
433 
434   static void GeneratePositiveLookup(MacroAssembler* masm,
435                                      Label* miss,
436                                      Label* done,
437                                      Register elements,
438                                      Register name,
439                                      Register r0,
440                                      Register r1);
441 
SometimesSetsUpAFrame()442   virtual bool SometimesSetsUpAFrame() { return false; }
443 
444  private:
445   static const int kInlinedProbes = 4;
446   static const int kTotalProbes = 20;
447 
448   static const int kCapacityOffset =
449       StringDictionary::kHeaderSize +
450       StringDictionary::kCapacityIndex * kPointerSize;
451 
452   static const int kElementsStartOffset =
453       StringDictionary::kHeaderSize +
454       StringDictionary::kElementsStartIndex * kPointerSize;
455 
MajorKey()456   Major MajorKey() { return StringDictionaryLookup; }
457 
MinorKey()458   int MinorKey() {
459     return DictionaryBits::encode(dictionary_.code()) |
460         ResultBits::encode(result_.code()) |
461         IndexBits::encode(index_.code()) |
462         LookupModeBits::encode(mode_);
463   }
464 
465   class DictionaryBits: public BitField<int, 0, 4> {};
466   class ResultBits: public BitField<int, 4, 4> {};
467   class IndexBits: public BitField<int, 8, 4> {};
468   class LookupModeBits: public BitField<LookupMode, 12, 1> {};
469 
470   Register dictionary_;
471   Register result_;
472   Register index_;
473   LookupMode mode_;
474 };
475 
476 
477 class RecordWriteStub: public CodeStub {
478  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)479   RecordWriteStub(Register object,
480                   Register value,
481                   Register address,
482                   RememberedSetAction remembered_set_action,
483                   SaveFPRegsMode fp_mode)
484       : object_(object),
485         value_(value),
486         address_(address),
487         remembered_set_action_(remembered_set_action),
488         save_fp_regs_mode_(fp_mode),
489         regs_(object,   // An input reg.
490               address,  // An input reg.
491               value) {  // One scratch reg.
492   }
493 
494   enum Mode {
495     STORE_BUFFER_ONLY,
496     INCREMENTAL,
497     INCREMENTAL_COMPACTION
498   };
499 
500   virtual bool IsPregenerated();
501   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()502   virtual bool SometimesSetsUpAFrame() { return false; }
503 
504   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
505   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
506 
507   static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
508   static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
509 
GetMode(Code * stub)510   static Mode GetMode(Code* stub) {
511     byte first_instruction = stub->instruction_start()[0];
512     byte second_instruction = stub->instruction_start()[2];
513 
514     if (first_instruction == kTwoByteJumpInstruction) {
515       return INCREMENTAL;
516     }
517 
518     ASSERT(first_instruction == kTwoByteNopInstruction);
519 
520     if (second_instruction == kFiveByteJumpInstruction) {
521       return INCREMENTAL_COMPACTION;
522     }
523 
524     ASSERT(second_instruction == kFiveByteNopInstruction);
525 
526     return STORE_BUFFER_ONLY;
527   }
528 
Patch(Code * stub,Mode mode)529   static void Patch(Code* stub, Mode mode) {
530     switch (mode) {
531       case STORE_BUFFER_ONLY:
532         ASSERT(GetMode(stub) == INCREMENTAL ||
533                GetMode(stub) == INCREMENTAL_COMPACTION);
534         stub->instruction_start()[0] = kTwoByteNopInstruction;
535         stub->instruction_start()[2] = kFiveByteNopInstruction;
536         break;
537       case INCREMENTAL:
538         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
539         stub->instruction_start()[0] = kTwoByteJumpInstruction;
540         break;
541       case INCREMENTAL_COMPACTION:
542         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
543         stub->instruction_start()[0] = kTwoByteNopInstruction;
544         stub->instruction_start()[2] = kFiveByteJumpInstruction;
545         break;
546     }
547     ASSERT(GetMode(stub) == mode);
548     CPU::FlushICache(stub->instruction_start(), 7);
549   }
550 
551  private:
552   // This is a helper class for freeing up 3 scratch registers, where the third
553   // is always rcx (needed for shift operations).  The input is two registers
554   // that must be preserved and one scratch register provided by the caller.
555   class RegisterAllocation {
556    public:
RegisterAllocation(Register object,Register address,Register scratch0)557     RegisterAllocation(Register object,
558                        Register address,
559                        Register scratch0)
560         : object_orig_(object),
561           address_orig_(address),
562           scratch0_orig_(scratch0),
563           object_(object),
564           address_(address),
565           scratch0_(scratch0) {
566       ASSERT(!AreAliased(scratch0, object, address, no_reg));
567       scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
568       if (scratch0.is(rcx)) {
569         scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
570       }
571       if (object.is(rcx)) {
572         object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
573       }
574       if (address.is(rcx)) {
575         address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
576       }
577       ASSERT(!AreAliased(scratch0_, object_, address_, rcx));
578     }
579 
Save(MacroAssembler * masm)580     void Save(MacroAssembler* masm) {
581       ASSERT(!address_orig_.is(object_));
582       ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
583       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
584       ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
585       ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
586       // We don't have to save scratch0_orig_ because it was given to us as
587       // a scratch register.  But if we had to switch to a different reg then
588       // we should save the new scratch0_.
589       if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
590       if (!rcx.is(scratch0_orig_) &&
591           !rcx.is(object_orig_) &&
592           !rcx.is(address_orig_)) {
593         masm->push(rcx);
594       }
595       masm->push(scratch1_);
596       if (!address_.is(address_orig_)) {
597         masm->push(address_);
598         masm->movq(address_, address_orig_);
599       }
600       if (!object_.is(object_orig_)) {
601         masm->push(object_);
602         masm->movq(object_, object_orig_);
603       }
604     }
605 
Restore(MacroAssembler * masm)606     void Restore(MacroAssembler* masm) {
607       // These will have been preserved the entire time, so we just need to move
608       // them back.  Only in one case is the orig_ reg different from the plain
609       // one, since only one of them can alias with rcx.
610       if (!object_.is(object_orig_)) {
611         masm->movq(object_orig_, object_);
612         masm->pop(object_);
613       }
614       if (!address_.is(address_orig_)) {
615         masm->movq(address_orig_, address_);
616         masm->pop(address_);
617       }
618       masm->pop(scratch1_);
619       if (!rcx.is(scratch0_orig_) &&
620           !rcx.is(object_orig_) &&
621           !rcx.is(address_orig_)) {
622         masm->pop(rcx);
623       }
624       if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
625     }
626 
627     // If we have to call into C then we need to save and restore all caller-
628     // saved registers that were not already preserved.
629 
630     // The three scratch registers (incl. rcx) will be restored by other means
631     // so we don't bother pushing them here.  Rbx, rbp and r12-15 are callee
632     // save and don't need to be preserved.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)633     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
634       masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
635     }
636 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)637     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
638                                            SaveFPRegsMode mode) {
639       masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
640     }
641 
object()642     inline Register object() { return object_; }
address()643     inline Register address() { return address_; }
scratch0()644     inline Register scratch0() { return scratch0_; }
scratch1()645     inline Register scratch1() { return scratch1_; }
646 
647    private:
648     Register object_orig_;
649     Register address_orig_;
650     Register scratch0_orig_;
651     Register object_;
652     Register address_;
653     Register scratch0_;
654     Register scratch1_;
655     // Third scratch register is always rcx.
656 
GetRegThatIsNotRcxOr(Register r1,Register r2,Register r3)657     Register GetRegThatIsNotRcxOr(Register r1,
658                                   Register r2,
659                                   Register r3) {
660       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
661         Register candidate = Register::FromAllocationIndex(i);
662         if (candidate.is(rcx)) continue;
663         if (candidate.is(r1)) continue;
664         if (candidate.is(r2)) continue;
665         if (candidate.is(r3)) continue;
666         return candidate;
667       }
668       UNREACHABLE();
669       return no_reg;
670     }
671     friend class RecordWriteStub;
672   };
673 
674   enum OnNoNeedToInformIncrementalMarker {
675     kReturnOnNoNeedToInformIncrementalMarker,
676     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
677   };
678 
679   void Generate(MacroAssembler* masm);
680   void GenerateIncremental(MacroAssembler* masm, Mode mode);
681   void CheckNeedsToInformIncrementalMarker(
682       MacroAssembler* masm,
683       OnNoNeedToInformIncrementalMarker on_no_need,
684       Mode mode);
685   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
686 
MajorKey()687   Major MajorKey() { return RecordWrite; }
688 
MinorKey()689   int MinorKey() {
690     return ObjectBits::encode(object_.code()) |
691         ValueBits::encode(value_.code()) |
692         AddressBits::encode(address_.code()) |
693         RememberedSetActionBits::encode(remembered_set_action_) |
694         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
695   }
696 
Activate(Code * code)697   void Activate(Code* code) {
698     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
699   }
700 
701   class ObjectBits: public BitField<int, 0, 4> {};
702   class ValueBits: public BitField<int, 4, 4> {};
703   class AddressBits: public BitField<int, 8, 4> {};
704   class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
705   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
706 
707   Register object_;
708   Register value_;
709   Register address_;
710   RememberedSetAction remembered_set_action_;
711   SaveFPRegsMode save_fp_regs_mode_;
712   Label slow_;
713   RegisterAllocation regs_;
714 };
715 
716 
717 } }  // namespace v8::internal
718 
719 #endif  // V8_X64_CODE_STUBS_X64_H_
720