LCOV - code coverage report
Current view: top level - src/x64 - macro-assembler-x64.h (source / functions) Hit Total Coverage
Test: app.info Lines: 50 57 87.7 %
Date: 2017-10-20 Functions: 13 18 72.2 %

          Line data    Source code
       1             : // Copyright 2012 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_X64_MACRO_ASSEMBLER_X64_H_
       6             : #define V8_X64_MACRO_ASSEMBLER_X64_H_
       7             : 
       8             : #include "src/bailout-reason.h"
       9             : #include "src/base/flags.h"
      10             : #include "src/globals.h"
      11             : #include "src/x64/assembler-x64.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : // Give alias names to registers for calling conventions.
      17             : constexpr Register kReturnRegister0 = rax;
      18             : constexpr Register kReturnRegister1 = rdx;
      19             : constexpr Register kReturnRegister2 = r8;
      20             : constexpr Register kJSFunctionRegister = rdi;
      21             : constexpr Register kContextRegister = rsi;
      22             : constexpr Register kAllocateSizeRegister = rdx;
      23             : constexpr Register kInterpreterAccumulatorRegister = rax;
      24             : constexpr Register kInterpreterBytecodeOffsetRegister = r12;
      25             : constexpr Register kInterpreterBytecodeArrayRegister = r14;
      26             : constexpr Register kInterpreterDispatchTableRegister = r15;
      27             : constexpr Register kJavaScriptCallArgCountRegister = rax;
      28             : constexpr Register kJavaScriptCallNewTargetRegister = rdx;
      29             : constexpr Register kRuntimeCallFunctionRegister = rbx;
      30             : constexpr Register kRuntimeCallArgCountRegister = rax;
      31             : 
      32             : // Default scratch register used by MacroAssembler (and other code that needs
      33             : // a spare register). The register isn't callee save, and not used by the
      34             : // function calling convention.
      35             : constexpr Register kScratchRegister = r10;
      36             : constexpr XMMRegister kScratchDoubleReg = xmm15;
      37             : constexpr Register kRootRegister = r13;  // callee save
      38             : // Actual value of root register is offset from the root array's start
      39             : // to take advantage of negitive 8-bit displacement values.
      40             : constexpr int kRootRegisterBias = 128;
      41             : 
      42             : // Convenience for platform-independent signatures.
      43             : typedef Operand MemOperand;
      44             : 
      45             : enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
      46             : enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
      47             : 
      48             : #ifdef DEBUG
      49             : bool AreAliased(Register reg1,
      50             :                 Register reg2,
      51             :                 Register reg3 = no_reg,
      52             :                 Register reg4 = no_reg,
      53             :                 Register reg5 = no_reg,
      54             :                 Register reg6 = no_reg,
      55             :                 Register reg7 = no_reg,
      56             :                 Register reg8 = no_reg);
      57             : #endif
      58             : 
      59             : // Forward declaration.
      60             : class JumpTarget;
      61             : 
      62             : struct SmiIndex {
      63             :   SmiIndex(Register index_register, ScaleFactor scale)
      64             :       : reg(index_register),
      65             :         scale(scale) {}
      66             :   Register reg;
      67             :   ScaleFactor scale;
      68             : };
      69             : 
      70             : enum StackArgumentsAccessorReceiverMode {
      71             :   ARGUMENTS_CONTAIN_RECEIVER,
      72             :   ARGUMENTS_DONT_CONTAIN_RECEIVER
      73             : };
      74             : 
      75             : class StackArgumentsAccessor BASE_EMBEDDED {
      76             :  public:
      77             :   StackArgumentsAccessor(Register base_reg, int argument_count_immediate,
      78             :                          StackArgumentsAccessorReceiverMode receiver_mode =
      79             :                              ARGUMENTS_CONTAIN_RECEIVER,
      80             :                          int extra_displacement_to_last_argument = 0)
      81             :       : base_reg_(base_reg),
      82             :         argument_count_reg_(no_reg),
      83             :         argument_count_immediate_(argument_count_immediate),
      84             :         receiver_mode_(receiver_mode),
      85             :         extra_displacement_to_last_argument_(
      86        3546 :             extra_displacement_to_last_argument) {}
      87             : 
      88             :   StackArgumentsAccessor(Register base_reg, Register argument_count_reg,
      89             :                          StackArgumentsAccessorReceiverMode receiver_mode =
      90             :                              ARGUMENTS_CONTAIN_RECEIVER,
      91             :                          int extra_displacement_to_last_argument = 0)
      92             :       : base_reg_(base_reg),
      93             :         argument_count_reg_(argument_count_reg),
      94             :         argument_count_immediate_(0),
      95             :         receiver_mode_(receiver_mode),
      96             :         extra_displacement_to_last_argument_(
      97         558 :             extra_displacement_to_last_argument) {}
      98             : 
      99             :   StackArgumentsAccessor(Register base_reg,
     100             :                          const ParameterCount& parameter_count,
     101             :                          StackArgumentsAccessorReceiverMode receiver_mode =
     102             :                              ARGUMENTS_CONTAIN_RECEIVER,
     103             :                          int extra_displacement_to_last_argument = 0);
     104             : 
     105             :   Operand GetArgumentOperand(int index);
     106             :   Operand GetReceiverOperand() {
     107             :     DCHECK(receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER);
     108         403 :     return GetArgumentOperand(0);
     109             :   }
     110             : 
     111             :  private:
     112             :   const Register base_reg_;
     113             :   const Register argument_count_reg_;
     114             :   const int argument_count_immediate_;
     115             :   const StackArgumentsAccessorReceiverMode receiver_mode_;
     116             :   const int extra_displacement_to_last_argument_;
     117             : 
     118             :   DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
     119             : };
     120             : 
     121     1708847 : class TurboAssembler : public Assembler {
     122             :  public:
     123             :   TurboAssembler(Isolate* isolate, void* buffer, int buffer_size,
     124             :                  CodeObjectRequired create_code_object);
     125             : 
     126     3339759 :   void set_has_frame(bool value) { has_frame_ = value; }
     127             :   bool has_frame() const { return has_frame_; }
     128             : 
     129             :   Isolate* isolate() const { return isolate_; }
     130             : 
     131             :   Handle<HeapObject> CodeObject() {
     132             :     DCHECK(!code_object_.is_null());
     133             :     return code_object_;
     134             :   }
     135             : 
     136             : #define AVX_OP2_WITH_TYPE(macro_name, name, src_type) \
     137             :   void macro_name(XMMRegister dst, src_type src) {    \
     138             :     if (CpuFeatures::IsSupported(AVX)) {              \
     139             :       CpuFeatureScope scope(this, AVX);               \
     140             :       v##name(dst, dst, src);                         \
     141             :     } else {                                          \
     142             :       name(dst, src);                                 \
     143             :     }                                                 \
     144             :   }
     145             : #define AVX_OP2_X(macro_name, name) \
     146             :   AVX_OP2_WITH_TYPE(macro_name, name, XMMRegister)
     147             : #define AVX_OP2_O(macro_name, name) \
     148             :   AVX_OP2_WITH_TYPE(macro_name, name, const Operand&)
     149             : #define AVX_OP2_XO(macro_name, name) \
     150             :   AVX_OP2_X(macro_name, name)        \
     151             :   AVX_OP2_O(macro_name, name)
     152             : 
     153        3650 :   AVX_OP2_XO(Subsd, subsd)
     154       15468 :   AVX_OP2_XO(Divss, divss)
     155        3014 :   AVX_OP2_XO(Divsd, divsd)
     156      219805 :   AVX_OP2_XO(Xorpd, xorpd)
     157      106538 :   AVX_OP2_X(Pcmpeqd, pcmpeqd)
     158       58568 :   AVX_OP2_WITH_TYPE(Psllq, psllq, byte)
     159       12124 :   AVX_OP2_WITH_TYPE(Psrlq, psrlq, byte)
     160             : 
     161             : #undef AVX_OP2_O
     162             : #undef AVX_OP2_X
     163             : #undef AVX_OP2_XO
     164             : #undef AVX_OP2_WITH_TYPE
     165             : 
     166             :   void Xorps(XMMRegister dst, XMMRegister src);
     167             :   void Xorps(XMMRegister dst, const Operand& src);
     168             : 
     169             :   void Movd(XMMRegister dst, Register src);
     170             :   void Movd(XMMRegister dst, const Operand& src);
     171             :   void Movd(Register dst, XMMRegister src);
     172             :   void Movq(XMMRegister dst, Register src);
     173             :   void Movq(Register dst, XMMRegister src);
     174             : 
     175             :   void Movsd(XMMRegister dst, XMMRegister src);
     176             :   void Movsd(XMMRegister dst, const Operand& src);
     177             :   void Movsd(const Operand& dst, XMMRegister src);
     178             :   void Movss(XMMRegister dst, XMMRegister src);
     179             :   void Movss(XMMRegister dst, const Operand& src);
     180             :   void Movss(const Operand& dst, XMMRegister src);
     181             : 
     182      122645 :   void PushReturnAddressFrom(Register src) { pushq(src); }
     183      108920 :   void PopReturnAddressTo(Register dst) { popq(dst); }
     184             : 
     185             :   void Ret();
     186             : 
     187             :   // Return and drop arguments from stack, where the number of arguments
     188             :   // may be bigger than 2^16 - 1.  Requires a scratch register.
     189             :   void Ret(int bytes_dropped, Register scratch);
     190             : 
     191             :   // Load a register with a long value as efficiently as possible.
     192             :   void Set(Register dst, int64_t x);
     193             :   void Set(const Operand& dst, intptr_t x);
     194             : 
     195             :   // Operations on roots in the root-array.
     196             :   void LoadRoot(Register destination, Heap::RootListIndex index);
     197             :   void LoadRoot(const Operand& destination, Heap::RootListIndex index) {
     198             :     LoadRoot(kScratchRegister, index);
     199             :     movp(destination, kScratchRegister);
     200             :   }
     201             : 
     202             :   void Movups(XMMRegister dst, XMMRegister src);
     203             :   void Movups(XMMRegister dst, const Operand& src);
     204             :   void Movups(const Operand& dst, XMMRegister src);
     205             :   void Movapd(XMMRegister dst, XMMRegister src);
     206             :   void Movaps(XMMRegister dst, XMMRegister src);
     207             :   void Movmskpd(Register dst, XMMRegister src);
     208             :   void Movmskps(Register dst, XMMRegister src);
     209             : 
     210             :   void Push(Register src);
     211             :   void Push(const Operand& src);
     212             :   void Push(Immediate value);
     213             :   void Push(Smi* smi);
     214             :   void Push(Handle<HeapObject> source);
     215             : 
     216             :   // Before calling a C-function from generated code, align arguments on stack.
     217             :   // After aligning the frame, arguments must be stored in rsp[0], rsp[8],
     218             :   // etc., not pushed. The argument count assumes all arguments are word sized.
     219             :   // The number of slots reserved for arguments depends on platform. On Windows
     220             :   // stack slots are reserved for the arguments passed in registers. On other
     221             :   // platforms stack slots are only reserved for the arguments actually passed
     222             :   // on the stack.
     223             :   void PrepareCallCFunction(int num_arguments);
     224             : 
     225             :   // Calls a C function and cleans up the space for arguments allocated
     226             :   // by PrepareCallCFunction. The called function is not allowed to trigger a
     227             :   // garbage collection, since that might move the code and invalidate the
     228             :   // return address (unless this is somehow accounted for by the called
     229             :   // function).
     230             :   void CallCFunction(ExternalReference function, int num_arguments);
     231             :   void CallCFunction(Register function, int num_arguments);
     232             : 
     233             :   // Calculate the number of stack slots to reserve for arguments when calling a
     234             :   // C function.
     235             :   int ArgumentStackSlotsForCFunctionCall(int num_arguments);
     236             : 
     237             :   void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
     238             :                      Label* condition_met,
     239             :                      Label::Distance condition_met_distance = Label::kFar);
     240             : 
     241             :   void Cvtss2sd(XMMRegister dst, XMMRegister src);
     242             :   void Cvtss2sd(XMMRegister dst, const Operand& src);
     243             :   void Cvtsd2ss(XMMRegister dst, XMMRegister src);
     244             :   void Cvtsd2ss(XMMRegister dst, const Operand& src);
     245             :   void Cvttsd2si(Register dst, XMMRegister src);
     246             :   void Cvttsd2si(Register dst, const Operand& src);
     247             :   void Cvttsd2siq(Register dst, XMMRegister src);
     248             :   void Cvttsd2siq(Register dst, const Operand& src);
     249             :   void Cvttss2si(Register dst, XMMRegister src);
     250             :   void Cvttss2si(Register dst, const Operand& src);
     251             :   void Cvttss2siq(Register dst, XMMRegister src);
     252             :   void Cvttss2siq(Register dst, const Operand& src);
     253             :   void Cvtqsi2ss(XMMRegister dst, Register src);
     254             :   void Cvtqsi2ss(XMMRegister dst, const Operand& src);
     255             :   void Cvtqsi2sd(XMMRegister dst, Register src);
     256             :   void Cvtqsi2sd(XMMRegister dst, const Operand& src);
     257             :   void Cvtlsi2ss(XMMRegister dst, Register src);
     258             :   void Cvtlsi2ss(XMMRegister dst, const Operand& src);
     259             :   void Cvtqui2ss(XMMRegister dst, Register src, Register tmp);
     260             :   void Cvtqui2sd(XMMRegister dst, Register src, Register tmp);
     261             : 
     262             :   // cvtsi2sd instruction only writes to the low 64-bit of dst register, which
     263             :   // hinders register renaming and makes dependence chains longer. So we use
     264             :   // xorpd to clear the dst register before cvtsi2sd to solve this issue.
     265             :   void Cvtlsi2sd(XMMRegister dst, Register src);
     266             :   void Cvtlsi2sd(XMMRegister dst, const Operand& src);
     267             : 
     268             :   void Roundss(XMMRegister dst, XMMRegister src, RoundingMode mode);
     269             :   void Roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
     270             : 
     271             :   void Sqrtsd(XMMRegister dst, XMMRegister src);
     272             :   void Sqrtsd(XMMRegister dst, const Operand& src);
     273             : 
     274             :   void Ucomiss(XMMRegister src1, XMMRegister src2);
     275             :   void Ucomiss(XMMRegister src1, const Operand& src2);
     276             :   void Ucomisd(XMMRegister src1, XMMRegister src2);
     277             :   void Ucomisd(XMMRegister src1, const Operand& src2);
     278             : 
     279             :   void Lzcntq(Register dst, Register src);
     280             :   void Lzcntq(Register dst, const Operand& src);
     281             :   void Lzcntl(Register dst, Register src);
     282             :   void Lzcntl(Register dst, const Operand& src);
     283             :   void Tzcntq(Register dst, Register src);
     284             :   void Tzcntq(Register dst, const Operand& src);
     285             :   void Tzcntl(Register dst, Register src);
     286             :   void Tzcntl(Register dst, const Operand& src);
     287             :   void Popcntl(Register dst, Register src);
     288             :   void Popcntl(Register dst, const Operand& src);
     289             :   void Popcntq(Register dst, Register src);
     290             :   void Popcntq(Register dst, const Operand& src);
     291             : 
     292             :   // Is the value a tagged smi.
     293             :   Condition CheckSmi(Register src);
     294             :   Condition CheckSmi(const Operand& src);
     295             : 
     296             :   // Jump to label if the value is a tagged smi.
     297             :   void JumpIfSmi(Register src, Label* on_smi,
     298             :                  Label::Distance near_jump = Label::kFar);
     299             : 
     300             :   void Move(Register dst, Smi* source);
     301             : 
     302             :   void Move(const Operand& dst, Smi* source) {
     303             :     Register constant = GetSmiConstant(source);
     304             :     movp(dst, constant);
     305             :   }
     306             : 
     307             :   void Move(Register dst, ExternalReference ext) {
     308             :     movp(dst, reinterpret_cast<void*>(ext.address()),
     309     2363437 :          RelocInfo::EXTERNAL_REFERENCE);
     310             :   }
     311             : 
     312             :   void Move(XMMRegister dst, uint32_t src);
     313             :   void Move(XMMRegister dst, uint64_t src);
     314         239 :   void Move(XMMRegister dst, float src) { Move(dst, bit_cast<uint32_t>(src)); }
     315         439 :   void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
     316             : 
     317             :   // Move if the registers are not identical.
     318             :   void Move(Register target, Register source);
     319             : 
     320             :   void Move(Register dst, Handle<HeapObject> source,
     321             :             RelocInfo::Mode rmode = RelocInfo::EMBEDDED_OBJECT);
     322             :   void Move(const Operand& dst, Handle<HeapObject> source,
     323             :             RelocInfo::Mode rmode = RelocInfo::EMBEDDED_OBJECT);
     324             : 
     325             :   // Loads a pointer into a register with a relocation mode.
     326             :   void Move(Register dst, void* ptr, RelocInfo::Mode rmode) {
     327             :     // This method must not be used with heap object references. The stored
     328             :     // address is not GC safe. Use the handle version instead.
     329             :     DCHECK(rmode > RelocInfo::LAST_GCED_ENUM);
     330     2998058 :     movp(dst, ptr, rmode);
     331             :   }
     332             : 
     333             :   // Convert smi to 32-bit integer. I.e., not sign extended into
     334             :   // high 32 bits of destination.
     335             :   void SmiToInteger32(Register dst, Register src);
     336             :   void SmiToInteger32(Register dst, const Operand& src);
     337             : 
     338             :   // Loads the address of the external reference into the destination
     339             :   // register.
     340             :   void LoadAddress(Register destination, ExternalReference source);
     341             : 
     342             :   void Call(const Operand& op);
     343             :   void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
     344             :   void Call(Address destination, RelocInfo::Mode rmode);
     345             :   void Call(ExternalReference ext);
     346             :   void Call(Label* target) { call(target); }
     347             : 
     348             :   void CallForDeoptimization(Address target, RelocInfo::Mode rmode) {
     349     3087701 :     call(target, rmode);
     350             :   }
     351             : 
     352             :   // The size of the code generated for different call instructions.
     353             :   int CallSize(ExternalReference ext);
     354             :   int CallSize(Address destination) { return kCallSequenceLength; }
     355             :   int CallSize(Handle<Code> code_object) {
     356             :     // Code calls use 32-bit relative addressing.
     357             :     return kShortCallInstructionLength;
     358             :   }
     359             :   int CallSize(Register target) {
     360             :     // Opcode: REX_opt FF /2 m64
     361             :     return (target.high_bit() != 0) ? 3 : 2;
     362             :   }
     363             :   int CallSize(const Operand& target) {
     364             :     // Opcode: REX_opt FF /2 m64
     365             :     return (target.requires_rex() ? 2 : 1) + target.operand_size();
     366             :   }
     367             : 
     368             :   // Returns the size of the code generated by LoadAddress.
     369             :   // Used by CallSize(ExternalReference) to find the size of a call.
     370             :   int LoadAddressSize(ExternalReference source);
     371             : 
     372             :   // Non-SSE2 instructions.
     373             :   void Pextrd(Register dst, XMMRegister src, int8_t imm8);
     374             :   void Pinsrd(XMMRegister dst, Register src, int8_t imm8);
     375             :   void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
     376             : 
     377             :   void CompareRoot(Register with, Heap::RootListIndex index);
     378             :   void CompareRoot(const Operand& with, Heap::RootListIndex index);
     379             : 
     380             :   // Generates function and stub prologue code.
     381             :   void StubPrologue(StackFrame::Type type);
     382             :   void Prologue();
     383             : 
     384             :   // Calls Abort(msg) if the condition cc is not satisfied.
     385             :   // Use --debug_code to enable.
     386             :   void Assert(Condition cc, BailoutReason reason);
     387             : 
     388             :   // Like Assert(), but without condition.
     389             :   // Use --debug_code to enable.
     390             :   void AssertUnreachable(BailoutReason reason);
     391             : 
     392             :   // Abort execution if a 64 bit register containing a 32 bit payload does not
     393             :   // have zeros in the top 32 bits, enabled via --debug-code.
     394             :   void AssertZeroExtended(Register reg);
     395             : 
     396             :   // Like Assert(), but always enabled.
     397             :   void Check(Condition cc, BailoutReason reason);
     398             : 
     399             :   // Print a message to stdout and abort execution.
     400             :   void Abort(BailoutReason msg);
     401             : 
     402             :   // Check that the stack is aligned.
     403             :   void CheckStackAlignment();
     404             : 
     405             :   // Activation support.
     406             :   void EnterFrame(StackFrame::Type type);
     407             :   void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg) {
     408             :     // Out-of-line constant pool not implemented on x64.
     409             :     UNREACHABLE();
     410             :   }
     411             :   void LeaveFrame(StackFrame::Type type);
     412             : 
     413             :   // Removes current frame and its arguments from the stack preserving the
     414             :   // arguments and a return address pushed to the stack for the next call.  Both
     415             :   // |callee_args_count| and |caller_args_count_reg| do not include receiver.
     416             :   // |callee_args_count| is not modified, |caller_args_count_reg| is trashed.
     417             :   void PrepareForTailCall(const ParameterCount& callee_args_count,
     418             :                           Register caller_args_count_reg, Register scratch0,
     419             :                           Register scratch1);
     420             : 
     421             :   inline bool AllowThisStubCall(CodeStub* stub);
     422             : 
     423             :   // Call a code stub. This expects {stub} to be zone-allocated, as it does not
     424             :   // trigger generation of the stub's code object but instead files a
     425             :   // HeapObjectRequest that will be fulfilled after code assembly.
     426             :   void CallStubDelayed(CodeStub* stub);
     427             : 
     428             :   void SlowTruncateToIDelayed(Zone* zone, Register result_reg);
     429             : 
     430             :   // Call a runtime routine.
     431             :   void CallRuntimeDelayed(Zone* zone, Runtime::FunctionId fid,
     432             :                           SaveFPRegsMode save_doubles = kDontSaveFPRegs);
     433             : 
     434      243643 :   void InitializeRootRegister() {
     435             :     ExternalReference roots_array_start =
     436      243643 :         ExternalReference::roots_array_start(isolate());
     437             :     Move(kRootRegister, roots_array_start);
     438      243643 :     addp(kRootRegister, Immediate(kRootRegisterBias));
     439      243643 :   }
     440             : 
     441             :   void SaveRegisters(RegList registers);
     442             :   void RestoreRegisters(RegList registers);
     443             : 
     444             :   void CallRecordWriteStub(Register object, Register address,
     445             :                            RememberedSetAction remembered_set_action,
     446             :                            SaveFPRegsMode fp_mode);
     447             : 
     448             :   void MoveNumber(Register dst, double value);
     449             :   void MoveNonSmi(Register dst, double value);
     450             : 
     451             :   // Calculate how much stack space (in bytes) are required to store caller
     452             :   // registers excluding those specified in the arguments.
     453             :   int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
     454             :                                       Register exclusion1 = no_reg,
     455             :                                       Register exclusion2 = no_reg,
     456             :                                       Register exclusion3 = no_reg) const;
     457             : 
     458             :   // PushCallerSaved and PopCallerSaved do not arrange the registers in any
     459             :   // particular order so they are not useful for calls that can cause a GC.
     460             :   // The caller can exclude up to 3 registers that do not need to be saved and
     461             :   // restored.
     462             : 
     463             :   // Push caller saved registers on the stack, and return the number of bytes
     464             :   // stack pointer is adjusted.
     465             :   int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
     466             :                       Register exclusion2 = no_reg,
     467             :                       Register exclusion3 = no_reg);
     468             :   // Restore caller saved registers from the stack, and return the number of
     469             :   // bytes stack pointer is adjusted.
     470             :   int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
     471             :                      Register exclusion2 = no_reg,
     472             :                      Register exclusion3 = no_reg);
     473             : 
     474             :  protected:
     475             :   static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
     476             :   int smi_count = 0;
     477             :   int heap_object_count = 0;
     478             : 
     479             :   bool root_array_available_ = true;
     480             : 
     481             :   int64_t RootRegisterDelta(ExternalReference other);
     482             : 
     483             :   // Returns a register holding the smi value. The register MUST NOT be
     484             :   // modified. It may be the "smi 1 constant" register.
     485             :   Register GetSmiConstant(Smi* value);
     486             : 
     487             :  private:
     488             :   bool has_frame_ = false;
     489             :   // This handle will be patched with the code object on installation.
     490             :   Handle<HeapObject> code_object_;
     491             :   Isolate* const isolate_;
     492             : };
     493             : 
     494             : // MacroAssembler implements a collection of frequently used macros.
     495      407254 : class MacroAssembler : public TurboAssembler {
     496             :  public:
     497             :   MacroAssembler(Isolate* isolate, void* buffer, int size,
     498             :                  CodeObjectRequired create_code_object);
     499             : 
     500             :   // Prevent the use of the RootArray during the lifetime of this
     501             :   // scope object.
     502             :   class NoRootArrayScope BASE_EMBEDDED {
     503             :    public:
     504             :     explicit NoRootArrayScope(MacroAssembler* assembler)
     505             :         : variable_(&assembler->root_array_available_),
     506       93646 :           old_value_(assembler->root_array_available_) {
     507       93646 :       assembler->root_array_available_ = false;
     508             :     }
     509             :     ~NoRootArrayScope() {
     510       93646 :       *variable_ = old_value_;
     511             :     }
     512             :    private:
     513             :     bool* variable_;
     514             :     bool old_value_;
     515             :   };
     516             : 
     517             :   // Operand pointing to an external reference.
     518             :   // May emit code to set up the scratch register. The operand is
     519             :   // only guaranteed to be correct as long as the scratch register
     520             :   // isn't changed.
     521             :   // If the operand is used more than once, use a scratch register
     522             :   // that is guaranteed not to be clobbered.
     523             :   Operand ExternalOperand(ExternalReference reference,
     524             :                           Register scratch = kScratchRegister);
     525             :   // Loads and stores the value of an external reference.
     526             :   // Special case code for load and store to take advantage of
     527             :   // load_rax/store_rax if possible/necessary.
     528             :   // For other operations, just use:
     529             :   //   Operand operand = ExternalOperand(extref);
     530             :   //   operation(operand, ..);
     531             :   void Load(Register destination, ExternalReference source);
     532             :   void Store(ExternalReference destination, Register source);
     533             : 
     534             :   // Pushes the address of the external reference onto the stack.
     535             :   void PushAddress(ExternalReference source);
     536             : 
     537             :   // Operations on roots in the root-array.
     538             :   // Load a root value where the index (or part of it) is variable.
     539             :   // The variable_offset register is added to the fixed_offset value
     540             :   // to get the index into the root-array.
     541             :   void PushRoot(Heap::RootListIndex index);
     542             : 
     543             :   // Compare the object in a register to a value and jump if they are equal.
     544             :   void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal,
     545             :                   Label::Distance if_equal_distance = Label::kFar) {
     546         279 :     CompareRoot(with, index);
     547         279 :     j(equal, if_equal, if_equal_distance);
     548             :   }
     549             :   void JumpIfRoot(const Operand& with, Heap::RootListIndex index,
     550             :                   Label* if_equal,
     551             :                   Label::Distance if_equal_distance = Label::kFar) {
     552             :     CompareRoot(with, index);
     553             :     j(equal, if_equal, if_equal_distance);
     554             :   }
     555             : 
     556             :   // Compare the object in a register to a value and jump if they are not equal.
     557             :   void JumpIfNotRoot(Register with, Heap::RootListIndex index,
     558             :                      Label* if_not_equal,
     559             :                      Label::Distance if_not_equal_distance = Label::kFar) {
     560          31 :     CompareRoot(with, index);
     561          31 :     j(not_equal, if_not_equal, if_not_equal_distance);
     562             :   }
     563             :   void JumpIfNotRoot(const Operand& with, Heap::RootListIndex index,
     564             :                      Label* if_not_equal,
     565             :                      Label::Distance if_not_equal_distance = Label::kFar) {
     566             :     CompareRoot(with, index);
     567             :     j(not_equal, if_not_equal, if_not_equal_distance);
     568             :   }
     569             : 
     570             : 
     571             : // ---------------------------------------------------------------------------
     572             : // GC Support
     573             : 
     574             : 
     575             :   // Record in the remembered set the fact that we have a pointer to new space
     576             :   // at the address pointed to by the addr register.  Only works if addr is not
     577             :   // in new space.
     578             :   void RememberedSetHelper(Register object,  // Used for debug code.
     579             :                            Register addr, Register scratch,
     580             :                            SaveFPRegsMode save_fp);
     581             : 
     582             :   // Check if object is in new space.  Jumps if the object is not in new space.
     583             :   // The register scratch can be object itself, but scratch will be clobbered.
     584           0 :   void JumpIfNotInNewSpace(Register object,
     585             :                            Register scratch,
     586             :                            Label* branch,
     587             :                            Label::Distance distance = Label::kFar) {
     588           0 :     InNewSpace(object, scratch, zero, branch, distance);
     589           0 :   }
     590             : 
     591             :   // Check if object is in new space.  Jumps if the object is in new space.
     592             :   // The register scratch can be object itself, but it will be clobbered.
     593             :   void JumpIfInNewSpace(Register object,
     594             :                         Register scratch,
     595             :                         Label* branch,
     596             :                         Label::Distance distance = Label::kFar) {
     597           0 :     InNewSpace(object, scratch, not_zero, branch, distance);
     598             :   }
     599             : 
     600             :   // Check if an object has the black incremental marking color.  Also uses rcx!
     601             :   void JumpIfBlack(Register object, Register bitmap_scratch,
     602             :                    Register mask_scratch, Label* on_black,
     603             :                    Label::Distance on_black_distance);
     604             : 
     605             :   // Checks the color of an object.  If the object is white we jump to the
     606             :   // incremental marker.
     607             :   void JumpIfWhite(Register value, Register scratch1, Register scratch2,
     608             :                    Label* value_is_white, Label::Distance distance);
     609             : 
     610             :   // Notify the garbage collector that we wrote a pointer into an object.
     611             :   // |object| is the object being stored into, |value| is the object being
     612             :   // stored.  value and scratch registers are clobbered by the operation.
     613             :   // The offset is the offset from the start of the object, not the offset from
     614             :   // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
     615             :   void RecordWriteField(
     616             :       Register object, int offset, Register value, Register scratch,
     617             :       SaveFPRegsMode save_fp,
     618             :       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
     619             :       SmiCheck smi_check = INLINE_SMI_CHECK);
     620             : 
     621             :   // For page containing |object| mark region covering |address|
     622             :   // dirty. |object| is the object being stored into, |value| is the
     623             :   // object being stored. The address and value registers are clobbered by the
     624             :   // operation.  RecordWrite filters out smis so it does not update
     625             :   // the write barrier if the value is a smi.
     626             :   void RecordWrite(
     627             :       Register object, Register address, Register value, SaveFPRegsMode save_fp,
     628             :       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
     629             :       SmiCheck smi_check = INLINE_SMI_CHECK);
     630             : 
     631             :   // Frame restart support.
     632             :   void MaybeDropFrames();
     633             : 
     634             :   // Enter specific kind of exit frame; either in normal or
     635             :   // debug mode. Expects the number of arguments in register rax and
     636             :   // sets up the number of arguments in register rdi and the pointer
     637             :   // to the first argument in register rsi.
     638             :   //
     639             :   // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
     640             :   // accessible via StackSpaceOperand.
     641             :   void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false,
     642             :                       StackFrame::Type frame_type = StackFrame::EXIT);
     643             : 
     644             :   // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
     645             :   // memory (not GCed) on the stack accessible via StackSpaceOperand.
     646             :   void EnterApiExitFrame(int arg_stack_space);
     647             : 
     648             :   // Leave the current exit frame. Expects/provides the return value in
     649             :   // register rax:rdx (untouched) and the pointer to the first
     650             :   // argument in register rsi (if pop_arguments == true).
     651             :   void LeaveExitFrame(bool save_doubles = false, bool pop_arguments = true);
     652             : 
     653             :   // Leave the current exit frame. Expects/provides the return value in
     654             :   // register rax (untouched).
     655             :   void LeaveApiExitFrame(bool restore_context);
     656             : 
     657             :   // Push and pop the registers that can hold pointers.
     658           0 :   void PushSafepointRegisters() { Pushad(); }
     659           0 :   void PopSafepointRegisters() { Popad(); }
     660             : 
     661             :   // ---------------------------------------------------------------------------
     662             :   // JavaScript invokes
     663             : 
     664             :   // Invoke the JavaScript function code by either calling or jumping.
     665             :   void InvokeFunctionCode(Register function, Register new_target,
     666             :                           const ParameterCount& expected,
     667             :                           const ParameterCount& actual, InvokeFlag flag);
     668             : 
     669             :   // On function call, call into the debugger if necessary.
     670             :   void CheckDebugHook(Register fun, Register new_target,
     671             :                       const ParameterCount& expected,
     672             :                       const ParameterCount& actual);
     673             : 
     674             :   // Invoke the JavaScript function in the given register. Changes the
     675             :   // current context to the context in the function before invoking.
     676             :   void InvokeFunction(Register function, Register new_target,
     677             :                       const ParameterCount& actual, InvokeFlag flag);
     678             : 
     679             :   void InvokeFunction(Register function, Register new_target,
     680             :                       const ParameterCount& expected,
     681             :                       const ParameterCount& actual, InvokeFlag flag);
     682             : 
     683             :   void InvokeFunction(Handle<JSFunction> function,
     684             :                       const ParameterCount& expected,
     685             :                       const ParameterCount& actual, InvokeFlag flag);
     686             : 
     687             :   // ---------------------------------------------------------------------------
     688             :   // Conversions between tagged smi values and non-tagged integer values.
     689             : 
     690             :   // Tag an integer value. The result must be known to be a valid smi value.
     691             :   // Only uses the low 32 bits of the src register. Sets the N and Z flags
     692             :   // based on the value of the resulting smi.
     693             :   void Integer32ToSmi(Register dst, Register src);
     694             : 
     695             :   // Convert smi to 64-bit integer (sign extended if necessary).
     696             :   void SmiToInteger64(Register dst, Register src);
     697             : 
     698             :   // Simple comparison of smis.  Both sides must be known smis to use these,
     699             :   // otherwise use Cmp.
     700             :   void SmiCompare(Register smi1, Register smi2);
     701             :   void SmiCompare(Register dst, Smi* src);
     702             :   void SmiCompare(Register dst, const Operand& src);
     703             :   void SmiCompare(const Operand& dst, Register src);
     704             :   void SmiCompare(const Operand& dst, Smi* src);
     705             : 
     706             :   // Functions performing a check on a known or potential smi. Returns
     707             :   // a condition that is satisfied if the check is successful.
     708             : 
     709             :   // Test-and-jump functions. Typically combines a check function
     710             :   // above with a conditional jump.
     711             : 
     712             :   // Jump to label if the value is not a tagged smi.
     713             :   void JumpIfNotSmi(Register src,
     714             :                     Label* on_not_smi,
     715             :                     Label::Distance near_jump = Label::kFar);
     716             : 
     717             :   // Jump to label if the value is not a tagged smi.
     718             :   void JumpIfNotSmi(Operand src, Label* on_not_smi,
     719             :                     Label::Distance near_jump = Label::kFar);
     720             : 
     721             :   // Operations on tagged smi values.
     722             : 
     723             :   // Smis represent a subset of integers. The subset is always equivalent to
     724             :   // a two's complement interpretation of a fixed number of bits.
     725             : 
     726             :   // Add an integer constant to a tagged smi, giving a tagged smi as result.
     727             :   // No overflow testing on the result is done.
     728             :   void SmiAddConstant(const Operand& dst, Smi* constant);
     729             : 
     730             :   // Specialized operations
     731             : 
     732             :   // Converts, if necessary, a smi to a combination of number and
     733             :   // multiplier to be used as a scaled index.
     734             :   // The src register contains a *positive* smi value. The shift is the
     735             :   // power of two to multiply the index value by (e.g.
     736             :   // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2).
     737             :   // The returned index register may be either src or dst, depending
     738             :   // on what is most efficient. If src and dst are different registers,
     739             :   // src is always unchanged.
     740             :   SmiIndex SmiToIndex(Register dst, Register src, int shift);
     741             : 
     742             :   // ---------------------------------------------------------------------------
     743             :   // Macro instructions.
     744             : 
     745             :   // Load/store with specific representation.
     746             :   void Load(Register dst, const Operand& src, Representation r);
     747             :   void Store(const Operand& dst, Register src, Representation r);
     748             : 
     749             :   void Cmp(Register dst, Handle<Object> source);
     750             :   void Cmp(const Operand& dst, Handle<Object> source);
     751             :   void Cmp(Register dst, Smi* src);
     752             :   void Cmp(const Operand& dst, Smi* src);
     753             : 
     754             :   void GetWeakValue(Register value, Handle<WeakCell> cell);
     755             : 
     756             :   // Load the value of the weak cell in the value register. Branch to the given
     757             :   // miss label if the weak cell was cleared.
     758             :   void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
     759             : 
     760             :   // Emit code that loads |parameter_index|'th parameter from the stack to
     761             :   // the register according to the CallInterfaceDescriptor definition.
     762             :   // |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
     763             :   // below the caller's sp (on x64 it's at least return address).
     764             :   template <class Descriptor>
     765             :   void LoadParameterFromStack(
     766             :       Register reg, typename Descriptor::ParameterIndices parameter_index,
     767             :       int sp_to_ra_offset_in_words = 1) {
     768             :     DCHECK(Descriptor::kPassLastArgsOnStack);
     769             :     UNIMPLEMENTED();
     770             :   }
     771             : 
     772             :   // Emit code to discard a non-negative number of pointer-sized elements
     773             :   // from the stack, clobbering only the rsp register.
     774             :   void Drop(int stack_elements);
     775             :   // Emit code to discard a positive number of pointer-sized elements
     776             :   // from the stack under the return address which remains on the top,
     777             :   // clobbering the rsp register.
     778             :   void DropUnderReturnAddress(int stack_elements,
     779             :                               Register scratch = kScratchRegister);
     780             : 
     781             :   void PushQuad(const Operand& src);
     782             :   void PushImm32(int32_t imm32);
     783             :   void Pop(Register dst);
     784             :   void Pop(const Operand& dst);
     785             :   void PopQuad(const Operand& dst);
     786             : 
     787             : #define AVX_OP2_WITH_TYPE(macro_name, name, src_type) \
     788             :   void macro_name(XMMRegister dst, src_type src) {    \
     789             :     if (CpuFeatures::IsSupported(AVX)) {              \
     790             :       CpuFeatureScope scope(this, AVX);               \
     791             :       v##name(dst, dst, src);                         \
     792             :     } else {                                          \
     793             :       name(dst, src);                                 \
     794             :     }                                                 \
     795             :   }
     796             : #define AVX_OP2_X(macro_name, name) \
     797             :   AVX_OP2_WITH_TYPE(macro_name, name, XMMRegister)
     798             : #define AVX_OP2_O(macro_name, name) \
     799             :   AVX_OP2_WITH_TYPE(macro_name, name, const Operand&)
     800             : #define AVX_OP2_XO(macro_name, name) \
     801             :   AVX_OP2_X(macro_name, name)        \
     802             :   AVX_OP2_O(macro_name, name)
     803             : 
     804             :   AVX_OP2_XO(Addsd, addsd)
     805         124 :   AVX_OP2_XO(Mulsd, mulsd)
     806          24 :   AVX_OP2_XO(Andps, andps)
     807             :   AVX_OP2_XO(Andpd, andpd)
     808             :   AVX_OP2_XO(Orpd, orpd)
     809             :   AVX_OP2_XO(Cmpeqps, cmpeqps)
     810             :   AVX_OP2_XO(Cmpltps, cmpltps)
     811             :   AVX_OP2_XO(Cmpleps, cmpleps)
     812             :   AVX_OP2_XO(Cmpneqps, cmpneqps)
     813             :   AVX_OP2_XO(Cmpnltps, cmpnltps)
     814             :   AVX_OP2_XO(Cmpnleps, cmpnleps)
     815             :   AVX_OP2_XO(Cmpeqpd, cmpeqpd)
     816             :   AVX_OP2_XO(Cmpltpd, cmpltpd)
     817             :   AVX_OP2_XO(Cmplepd, cmplepd)
     818             :   AVX_OP2_XO(Cmpneqpd, cmpneqpd)
     819             :   AVX_OP2_XO(Cmpnltpd, cmpnltpd)
     820             :   AVX_OP2_XO(Cmpnlepd, cmpnlepd)
     821             : 
     822             : #undef AVX_OP2_O
     823             : #undef AVX_OP2_X
     824             : #undef AVX_OP2_XO
     825             : #undef AVX_OP2_WITH_TYPE
     826             : 
     827             :   // ---------------------------------------------------------------------------
     828             :   // SIMD macros.
     829             :   void Absps(XMMRegister dst);
     830             :   void Negps(XMMRegister dst);
     831             :   void Abspd(XMMRegister dst);
     832             :   void Negpd(XMMRegister dst);
     833             : 
     834             :   // Control Flow
     835             :   void Jump(Address destination, RelocInfo::Mode rmode);
     836             :   void Jump(ExternalReference ext);
     837             :   void Jump(const Operand& op);
     838             :   void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
     839             : 
     840             :   // Non-x64 instructions.
     841             :   // Push/pop all general purpose registers.
     842             :   // Does not push rsp/rbp nor any of the assembler's special purpose registers
     843             :   // (kScratchRegister, kRootRegister).
     844             :   void Pushad();
     845             :   void Popad();
     846             : 
     847             :   // Compare object type for heap object.
     848             :   // Always use unsigned comparisons: above and below, not less and greater.
     849             :   // Incoming register is heap_object and outgoing register is map.
     850             :   // They may be the same register, and may be kScratchRegister.
     851             :   void CmpObjectType(Register heap_object, InstanceType type, Register map);
     852             : 
     853             :   // Compare instance type for map.
     854             :   // Always use unsigned comparisons: above and below, not less and greater.
     855             :   void CmpInstanceType(Register map, InstanceType type);
     856             : 
     857             :   void DoubleToI(Register result_reg, XMMRegister input_reg,
     858             :                  XMMRegister scratch, MinusZeroMode minus_zero_mode,
     859             :                  Label* lost_precision, Label* is_nan, Label* minus_zero,
     860             :                  Label::Distance dst = Label::kFar);
     861             : 
     862             :   void LoadInstanceDescriptors(Register map, Register descriptors);
     863             :   void LoadAccessor(Register dst, Register holder, int accessor_index,
     864             :                     AccessorComponent accessor);
     865             : 
     866             :   template<typename Field>
     867          31 :   void DecodeField(Register reg) {
     868             :     static const int shift = Field::kShift;
     869             :     static const int mask = Field::kMask >> Field::kShift;
     870             :     if (shift != 0) {
     871          31 :       shrp(reg, Immediate(shift));
     872             :     }
     873          31 :     andp(reg, Immediate(mask));
     874          31 :   }
     875             : 
     876             :   // Abort execution if argument is a smi, enabled via --debug-code.
     877             :   void AssertNotSmi(Register object);
     878             : 
     879             :   // Abort execution if argument is not a smi, enabled via --debug-code.
     880             :   void AssertSmi(Register object);
     881             :   void AssertSmi(const Operand& object);
     882             : 
     883             :   // Abort execution if argument is not a FixedArray, enabled via --debug-code.
     884             :   void AssertFixedArray(Register object);
     885             : 
     886             :   // Abort execution if argument is not a JSFunction, enabled via --debug-code.
     887             :   void AssertFunction(Register object);
     888             : 
     889             :   // Abort execution if argument is not a JSBoundFunction,
     890             :   // enabled via --debug-code.
     891             :   void AssertBoundFunction(Register object);
     892             : 
     893             :   // Abort execution if argument is not a JSGeneratorObject (or subclass),
     894             :   // enabled via --debug-code.
     895             :   void AssertGeneratorObject(Register object);
     896             : 
     897             :   // Abort execution if argument is not undefined or an AllocationSite, enabled
     898             :   // via --debug-code.
     899             :   void AssertUndefinedOrAllocationSite(Register object);
     900             : 
     901             :   // ---------------------------------------------------------------------------
     902             :   // Exception handling
     903             : 
     904             :   // Push a new stack handler and link it into stack handler chain.
     905             :   void PushStackHandler();
     906             : 
     907             :   // Unlink the stack handler on top of the stack from the stack handler chain.
     908             :   void PopStackHandler();
     909             : 
     910             :   // ---------------------------------------------------------------------------
     911             :   // Support functions.
     912             : 
     913             :   // Machine code version of Map::GetConstructor().
     914             :   // |temp| holds |result|'s map when done.
     915             :   void GetMapConstructor(Register result, Register map, Register temp);
     916             : 
     917             :   // Load the global proxy from the current context.
     918             :   void LoadGlobalProxy(Register dst) {
     919          62 :     LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst);
     920             :   }
     921             : 
     922             :   // Load the native context slot with the current index.
     923             :   void LoadNativeContextSlot(int index, Register dst);
     924             : 
     925             :   // ---------------------------------------------------------------------------
     926             :   // Runtime calls
     927             : 
     928             :   // Call a code stub.
     929             :   // The code object is generated immediately, in contrast to
     930             :   // TurboAssembler::CallStubDelayed.
     931             :   void CallStub(CodeStub* stub);
     932             : 
     933             :   // Tail call a code stub (jump).
     934             :   void TailCallStub(CodeStub* stub);
     935             : 
     936             :   // Call a runtime routine.
     937             :   void CallRuntime(const Runtime::Function* f,
     938             :                    int num_arguments,
     939             :                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
     940             : 
     941             :   // Convenience function: Same as above, but takes the fid instead.
     942        1023 :   void CallRuntime(Runtime::FunctionId fid,
     943             :                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
     944        1023 :     const Runtime::Function* function = Runtime::FunctionForId(fid);
     945        1023 :     CallRuntime(function, function->nargs, save_doubles);
     946        1023 :   }
     947             : 
     948             :   // Convenience function: Same as above, but takes the fid instead.
     949             :   void CallRuntime(Runtime::FunctionId fid, int num_arguments,
     950             :                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
     951         527 :     CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
     952             :   }
     953             : 
     954             :   // Convenience function: tail call a runtime routine (jump)
     955             :   void TailCallRuntime(Runtime::FunctionId fid);
     956             : 
     957             :   // Jump to a runtime routines
     958             :   void JumpToExternalReference(const ExternalReference& ext,
     959             :                                bool builtin_exit_frame = false);
     960             : 
     961             :   // ---------------------------------------------------------------------------
     962             :   // StatsCounter support
     963             :   void IncrementCounter(StatsCounter* counter, int value);
     964             :   void DecrementCounter(StatsCounter* counter, int value);
     965             : 
     966             : 
     967             :   // ---------------------------------------------------------------------------
     968             :   // Debugging
     969             : 
     970             :   static int SafepointRegisterStackIndex(Register reg) {
     971             :     return SafepointRegisterStackIndex(reg.code());
     972             :   }
     973             : 
     974             :   void EnterBuiltinFrame(Register context, Register target, Register argc);
     975             :   void LeaveBuiltinFrame(Register context, Register target, Register argc);
     976             : 
     977             :  private:
     978             :   // Order general registers are pushed by Pushad.
     979             :   // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14, r15.
     980             :   static const int kSafepointPushRegisterIndices[Register::kNumRegisters];
     981             :   static const int kNumSafepointSavedRegisters = 12;
     982             : 
     983             :   // Helper functions for generating invokes.
     984             :   void InvokePrologue(const ParameterCount& expected,
     985             :                       const ParameterCount& actual, Label* done,
     986             :                       bool* definitely_mismatches, InvokeFlag flag,
     987             :                       Label::Distance near_jump);
     988             : 
     989             :   void EnterExitFramePrologue(bool save_rax, StackFrame::Type frame_type);
     990             : 
     991             :   // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
     992             :   // accessible via StackSpaceOperand.
     993             :   void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);
     994             : 
     995             :   void LeaveExitFrameEpilogue(bool restore_context);
     996             : 
     997             :   // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
     998             :   void InNewSpace(Register object,
     999             :                   Register scratch,
    1000             :                   Condition cc,
    1001             :                   Label* branch,
    1002             :                   Label::Distance distance = Label::kFar);
    1003             : 
    1004             :   // Helper for finding the mark bits for an address.  Afterwards, the
    1005             :   // bitmap register points at the word with the mark bits and the mask
    1006             :   // the position of the first bit.  Uses rcx as scratch and leaves addr_reg
    1007             :   // unchanged.
    1008             :   inline void GetMarkBits(Register addr_reg,
    1009             :                           Register bitmap_reg,
    1010             :                           Register mask_reg);
    1011             : 
    1012             :   // Compute memory operands for safepoint stack slots.
    1013             :   static int SafepointRegisterStackIndex(int reg_code) {
    1014           0 :     return kNumSafepointRegisters - kSafepointPushRegisterIndices[reg_code] - 1;
    1015             :   }
    1016             : 
    1017             :   // Needs access to SafepointRegisterStackIndex for compiled frame
    1018             :   // traversal.
    1019             :   friend class StandardFrame;
    1020             : };
    1021             : 
    1022             : // -----------------------------------------------------------------------------
    1023             : // Static helper functions.
    1024             : 
    1025             : // Generate an Operand for loading a field from an object.
    1026             : inline Operand FieldOperand(Register object, int offset) {
    1027     1141907 :   return Operand(object, offset - kHeapObjectTag);
    1028             : }
    1029             : 
    1030             : 
    1031             : // Generate an Operand for loading an indexed field from an object.
    1032             : inline Operand FieldOperand(Register object,
    1033             :                             Register index,
    1034             :                             ScaleFactor scale,
    1035             :                             int offset) {
    1036       28709 :   return Operand(object, index, scale, offset - kHeapObjectTag);
    1037             : }
    1038             : 
    1039             : 
    1040         715 : inline Operand ContextOperand(Register context, int index) {
    1041         715 :   return Operand(context, Context::SlotOffset(index));
    1042             : }
    1043             : 
    1044             : 
    1045             : inline Operand ContextOperand(Register context, Register index) {
    1046             :   return Operand(context, index, times_pointer_size, Context::SlotOffset(0));
    1047             : }
    1048             : 
    1049             : 
    1050             : inline Operand NativeContextOperand() {
    1051         321 :   return ContextOperand(rsi, Context::NATIVE_CONTEXT_INDEX);
    1052             : }
    1053             : 
    1054             : 
    1055             : // Provides access to exit frame stack space (not GCed).
    1056             : inline Operand StackSpaceOperand(int index) {
    1057             : #ifdef _WIN64
    1058             :   const int kShaddowSpace = 4;
    1059             :   return Operand(rsp, (index + kShaddowSpace) * kPointerSize);
    1060             : #else
    1061       13951 :   return Operand(rsp, index * kPointerSize);
    1062             : #endif
    1063             : }
    1064             : 
    1065             : 
    1066             : inline Operand StackOperandForReturnAddress(int32_t disp) {
    1067          62 :   return Operand(rsp, disp);
    1068             : }
    1069             : 
    1070             : #define ACCESS_MASM(masm) masm->
    1071             : 
    1072             : }  // namespace internal
    1073             : }  // namespace v8
    1074             : 
    1075             : #endif  // V8_X64_MACRO_ASSEMBLER_X64_H_

Generated by: LCOV version 1.10