Home | History | Annotate | Download | only in x64
      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 
     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 
     57   Major MajorKey() { return TranscendentalCache; }
     58   int MinorKey() { return type_ | argument_type_; }
     59   Runtime::FunctionId RuntimeFunction();
     60 };
     61 
     62 
     63 class StoreBufferOverflowStub: public CodeStub {
     64  public:
     65   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
     66       : save_doubles_(save_fp) { }
     67 
     68   void Generate(MacroAssembler* masm);
     69 
     70   virtual bool IsPregenerated() { return true; }
     71   static void GenerateFixedRegStubsAheadOfTime();
     72   virtual bool SometimesSetsUpAFrame() { return false; }
     73 
     74  private:
     75   SaveFPRegsMode save_doubles_;
     76 
     77   Major MajorKey() { return StoreBufferOverflow; }
     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)
     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 
    112   Major MajorKey() { return UnaryOp; }
    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 
    148   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
    149 
    150   virtual InlineCacheState GetICState() {
    151     return UnaryOpIC::ToState(operand_type_);
    152   }
    153 
    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:
    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)
    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 
    200   Major MajorKey() { return BinaryOp; }
    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 
    234   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
    235 
    236   virtual InlineCacheState GetICState() {
    237     return BinaryOpIC::ToState(operands_type_);
    238   }
    239 
    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:
    317   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
    318 
    319  private:
    320   Major MajorKey() { return StringAdd; }
    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:
    339   SubStringStub() {}
    340 
    341  private:
    342   Major MajorKey() { return SubString; }
    343   int MinorKey() { return 0; }
    344 
    345   void Generate(MacroAssembler* masm);
    346 };
    347 
    348 
    349 class StringCompareStub: public CodeStub {
    350  public:
    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:
    371   virtual Major MajorKey() { return StringCompare; }
    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:
    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 
    408   Major MajorKey() { return NumberToString; }
    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 
    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 
    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 
    456   Major MajorKey() { return StringDictionaryLookup; }
    457 
    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:
    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();
    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 
    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 
    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:
    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 
    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 
    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.
    633     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
    634       masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
    635     }
    636 
    637     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
    638                                            SaveFPRegsMode mode) {
    639       masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
    640     }
    641 
    642     inline Register object() { return object_; }
    643     inline Register address() { return address_; }
    644     inline Register scratch0() { return scratch0_; }
    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 
    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 
    687   Major MajorKey() { return RecordWrite; }
    688 
    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 
    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