LCOV - code coverage report
Current view: top level - js/src/jit/x64 - Assembler-x64.h (source / functions) Hit Total Coverage
Test: output.info Lines: 228 453 50.3 %
Date: 2017-07-14 16:53:18 Functions: 58 98 59.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_x64_Assembler_x64_h
       8             : #define jit_x64_Assembler_x64_h
       9             : 
      10             : #include "mozilla/ArrayUtils.h"
      11             : 
      12             : #include "jit/IonCode.h"
      13             : #include "jit/JitCompartment.h"
      14             : #include "jit/shared/Assembler-shared.h"
      15             : 
      16             : namespace js {
      17             : namespace jit {
      18             : 
      19             : static constexpr Register rax { X86Encoding::rax };
      20             : static constexpr Register rbx { X86Encoding::rbx };
      21             : static constexpr Register rcx { X86Encoding::rcx };
      22             : static constexpr Register rdx { X86Encoding::rdx };
      23             : static constexpr Register rsi { X86Encoding::rsi };
      24             : static constexpr Register rdi { X86Encoding::rdi };
      25             : static constexpr Register rbp { X86Encoding::rbp };
      26             : static constexpr Register r8  { X86Encoding::r8  };
      27             : static constexpr Register r9  { X86Encoding::r9  };
      28             : static constexpr Register r10 { X86Encoding::r10 };
      29             : static constexpr Register r11 { X86Encoding::r11 };
      30             : static constexpr Register r12 { X86Encoding::r12 };
      31             : static constexpr Register r13 { X86Encoding::r13 };
      32             : static constexpr Register r14 { X86Encoding::r14 };
      33             : static constexpr Register r15 { X86Encoding::r15 };
      34             : static constexpr Register rsp { X86Encoding::rsp };
      35             : 
      36             : static constexpr FloatRegister xmm0 = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
      37             : static constexpr FloatRegister xmm1 = FloatRegister(X86Encoding::xmm1, FloatRegisters::Double);
      38             : static constexpr FloatRegister xmm2 = FloatRegister(X86Encoding::xmm2, FloatRegisters::Double);
      39             : static constexpr FloatRegister xmm3 = FloatRegister(X86Encoding::xmm3, FloatRegisters::Double);
      40             : static constexpr FloatRegister xmm4 = FloatRegister(X86Encoding::xmm4, FloatRegisters::Double);
      41             : static constexpr FloatRegister xmm5 = FloatRegister(X86Encoding::xmm5, FloatRegisters::Double);
      42             : static constexpr FloatRegister xmm6 = FloatRegister(X86Encoding::xmm6, FloatRegisters::Double);
      43             : static constexpr FloatRegister xmm7 = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
      44             : static constexpr FloatRegister xmm8 = FloatRegister(X86Encoding::xmm8, FloatRegisters::Double);
      45             : static constexpr FloatRegister xmm9 = FloatRegister(X86Encoding::xmm9, FloatRegisters::Double);
      46             : static constexpr FloatRegister xmm10 = FloatRegister(X86Encoding::xmm10, FloatRegisters::Double);
      47             : static constexpr FloatRegister xmm11 = FloatRegister(X86Encoding::xmm11, FloatRegisters::Double);
      48             : static constexpr FloatRegister xmm12 = FloatRegister(X86Encoding::xmm12, FloatRegisters::Double);
      49             : static constexpr FloatRegister xmm13 = FloatRegister(X86Encoding::xmm13, FloatRegisters::Double);
      50             : static constexpr FloatRegister xmm14 = FloatRegister(X86Encoding::xmm14, FloatRegisters::Double);
      51             : static constexpr FloatRegister xmm15 = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
      52             : 
      53             : // X86-common synonyms.
      54             : static constexpr Register eax = rax;
      55             : static constexpr Register ebx = rbx;
      56             : static constexpr Register ecx = rcx;
      57             : static constexpr Register edx = rdx;
      58             : static constexpr Register esi = rsi;
      59             : static constexpr Register edi = rdi;
      60             : static constexpr Register ebp = rbp;
      61             : static constexpr Register esp = rsp;
      62             : 
      63             : static constexpr Register InvalidReg { X86Encoding::invalid_reg };
      64             : static constexpr FloatRegister InvalidFloatReg = FloatRegister();
      65             : 
      66             : static constexpr Register StackPointer = rsp;
      67             : static constexpr Register FramePointer = rbp;
      68             : static constexpr Register JSReturnReg = rcx;
      69             : // Avoid, except for assertions.
      70             : static constexpr Register JSReturnReg_Type = JSReturnReg;
      71             : static constexpr Register JSReturnReg_Data = JSReturnReg;
      72             : 
      73             : static constexpr Register ScratchReg = r11;
      74             : 
      75             : // Helper class for ScratchRegister usage. Asserts that only one piece
      76             : // of code thinks it has exclusive ownership of the scratch register.
      77       25577 : struct ScratchRegisterScope : public AutoRegisterScope
      78             : {
      79       25577 :     explicit ScratchRegisterScope(MacroAssembler& masm)
      80       25577 :       : AutoRegisterScope(masm, ScratchReg)
      81       25576 :     { }
      82             : };
      83             : 
      84             : static constexpr Register ReturnReg = rax;
      85             : static constexpr Register HeapReg = r15;
      86             : static constexpr Register64 ReturnReg64(rax);
      87             : static constexpr FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
      88             : static constexpr FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
      89             : static constexpr FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
      90             : static constexpr FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Single);
      91             : static constexpr FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
      92             : static constexpr FloatRegister ScratchSimd128Reg = xmm15;
      93             : 
      94             : // Avoid rbp, which is the FramePointer, which is unavailable in some modes.
      95             : static constexpr Register ArgumentsRectifierReg = r8;
      96             : static constexpr Register CallTempReg0 = rax;
      97             : static constexpr Register CallTempReg1 = rdi;
      98             : static constexpr Register CallTempReg2 = rbx;
      99             : static constexpr Register CallTempReg3 = rcx;
     100             : static constexpr Register CallTempReg4 = rsi;
     101             : static constexpr Register CallTempReg5 = rdx;
     102             : 
     103             : // Different argument registers for WIN64
     104             : #if defined(_WIN64)
     105             : static constexpr Register IntArgReg0 = rcx;
     106             : static constexpr Register IntArgReg1 = rdx;
     107             : static constexpr Register IntArgReg2 = r8;
     108             : static constexpr Register IntArgReg3 = r9;
     109             : static constexpr uint32_t NumIntArgRegs = 4;
     110             : // Use "const" instead of constexpr here to work around a bug
     111             : // of VS2015 Update 1. See bug 1229604.
     112             : static const Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 };
     113             : 
     114             : static const Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi };
     115             : static const uint32_t NumCallTempNonArgRegs =
     116             :     mozilla::ArrayLength(CallTempNonArgRegs);
     117             : 
     118             : static constexpr FloatRegister FloatArgReg0 = xmm0;
     119             : static constexpr FloatRegister FloatArgReg1 = xmm1;
     120             : static constexpr FloatRegister FloatArgReg2 = xmm2;
     121             : static constexpr FloatRegister FloatArgReg3 = xmm3;
     122             : static const uint32_t NumFloatArgRegs = 4;
     123             : static constexpr FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3 };
     124             : #else
     125             : static constexpr Register IntArgReg0 = rdi;
     126             : static constexpr Register IntArgReg1 = rsi;
     127             : static constexpr Register IntArgReg2 = rdx;
     128             : static constexpr Register IntArgReg3 = rcx;
     129             : static constexpr Register IntArgReg4 = r8;
     130             : static constexpr Register IntArgReg5 = r9;
     131             : static constexpr uint32_t NumIntArgRegs = 6;
     132             : static const Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 };
     133             : 
     134             : // Use "const" instead of constexpr here to work around a bug
     135             : // of VS2015 Update 1. See bug 1229604.
     136             : static const Register CallTempNonArgRegs[] = { rax, rbx };
     137             : static const uint32_t NumCallTempNonArgRegs =
     138             :     mozilla::ArrayLength(CallTempNonArgRegs);
     139             : 
     140             : static constexpr FloatRegister FloatArgReg0 = xmm0;
     141             : static constexpr FloatRegister FloatArgReg1 = xmm1;
     142             : static constexpr FloatRegister FloatArgReg2 = xmm2;
     143             : static constexpr FloatRegister FloatArgReg3 = xmm3;
     144             : static constexpr FloatRegister FloatArgReg4 = xmm4;
     145             : static constexpr FloatRegister FloatArgReg5 = xmm5;
     146             : static constexpr FloatRegister FloatArgReg6 = xmm6;
     147             : static constexpr FloatRegister FloatArgReg7 = xmm7;
     148             : static constexpr uint32_t NumFloatArgRegs = 8;
     149             : static constexpr FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 };
     150             : #endif
     151             : 
     152             : // Registers used in the GenerateFFIIonExit Enable Activation block.
     153             : static constexpr Register WasmIonExitRegCallee = r10;
     154             : static constexpr Register WasmIonExitRegE0 = rax;
     155             : static constexpr Register WasmIonExitRegE1 = rdi;
     156             : 
     157             : // Registers used in the GenerateFFIIonExit Disable Activation block.
     158             : static constexpr Register WasmIonExitRegReturnData = ecx;
     159             : static constexpr Register WasmIonExitRegReturnType = ecx;
     160             : static constexpr Register WasmIonExitTlsReg = r14;
     161             : static constexpr Register WasmIonExitRegD0 = rax;
     162             : static constexpr Register WasmIonExitRegD1 = rdi;
     163             : static constexpr Register WasmIonExitRegD2 = rbx;
     164             : 
     165             : // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
     166             : static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
     167             : static constexpr Register RegExpMatcherStringReg = CallTempReg1;
     168             : static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
     169             : 
     170             : // Registerd used in RegExpTester instruction (do not use ReturnReg).
     171             : static constexpr Register RegExpTesterRegExpReg = CallTempReg1;
     172             : static constexpr Register RegExpTesterStringReg = CallTempReg2;
     173             : static constexpr Register RegExpTesterLastIndexReg = CallTempReg3;
     174             : 
     175             : class ABIArgGenerator
     176             : {
     177             : #if defined(XP_WIN)
     178             :     unsigned regIndex_;
     179             : #else
     180             :     unsigned intRegIndex_;
     181             :     unsigned floatRegIndex_;
     182             : #endif
     183             :     uint32_t stackOffset_;
     184             :     ABIArg current_;
     185             : 
     186             :   public:
     187             :     ABIArgGenerator();
     188             :     ABIArg next(MIRType argType);
     189           0 :     ABIArg& current() { return current_; }
     190       13023 :     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
     191             : };
     192             : 
     193             : // Avoid r11, which is the MacroAssembler's ScratchReg.
     194             : static constexpr Register ABINonArgReg0 = rax;
     195             : static constexpr Register ABINonArgReg1 = rbx;
     196             : static constexpr Register ABINonArgReg2 = r10;
     197             : 
     198             : // Note: these three registers are all guaranteed to be different
     199             : static constexpr Register ABINonArgReturnReg0 = r10;
     200             : static constexpr Register ABINonArgReturnReg1 = r12;
     201             : static constexpr Register ABINonVolatileReg = r13;
     202             : 
     203             : // TLS pointer argument register for WebAssembly functions. This must not alias
     204             : // any other register used for passing function arguments or return values.
     205             : // Preserved by WebAssembly functions.
     206             : static constexpr Register WasmTlsReg = r14;
     207             : 
     208             : // Registers used for asm.js/wasm table calls. These registers must be disjoint
     209             : // from the ABI argument registers, WasmTlsReg and each other.
     210             : static constexpr Register WasmTableCallScratchReg = ABINonArgReg0;
     211             : static constexpr Register WasmTableCallSigReg = ABINonArgReg1;
     212             : static constexpr Register WasmTableCallIndexReg = ABINonArgReg2;
     213             : 
     214             : static constexpr Register OsrFrameReg = IntArgReg3;
     215             : 
     216             : static constexpr Register PreBarrierReg = rdx;
     217             : 
     218             : static constexpr uint32_t ABIStackAlignment = 16;
     219             : static constexpr uint32_t CodeAlignment = 16;
     220             : static constexpr uint32_t JitStackAlignment = 16;
     221             : 
     222             : static constexpr uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
     223             : static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1,
     224             :   "Stack alignment should be a non-zero multiple of sizeof(Value)");
     225             : 
     226             : // This boolean indicates whether we support SIMD instructions flavoured for
     227             : // this architecture or not. Rather than a method in the LIRGenerator, it is
     228             : // here such that it is accessible from the entire codebase. Once full support
     229             : // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
     230             : static constexpr bool SupportsSimd = true;
     231             : static constexpr uint32_t SimdMemoryAlignment = 16;
     232             : 
     233             : static_assert(CodeAlignment % SimdMemoryAlignment == 0,
     234             :   "Code alignment should be larger than any of the alignments which are used for "
     235             :   "the constant sections of the code buffer.  Thus it should be larger than the "
     236             :   "alignment for SIMD constants.");
     237             : 
     238             : static_assert(JitStackAlignment % SimdMemoryAlignment == 0,
     239             :   "Stack alignment should be larger than any of the alignments which are used for "
     240             :   "spilled values.  Thus it should be larger than the alignment for SIMD accesses.");
     241             : 
     242             : static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
     243             : 
     244             : static const Scale ScalePointer = TimesEight;
     245             : 
     246             : } // namespace jit
     247             : } // namespace js
     248             : 
     249             : #include "jit/x86-shared/Assembler-x86-shared.h"
     250             : 
     251             : namespace js {
     252             : namespace jit {
     253             : 
     254             : // Return operand from a JS -> JS call.
     255             : static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg);
     256             : 
     257        4503 : class Assembler : public AssemblerX86Shared
     258             : {
     259             :     // x64 jumps may need extra bits of relocation, because a jump may extend
     260             :     // beyond the signed 32-bit range. To account for this we add an extended
     261             :     // jump table at the bottom of the instruction stream, and if a jump
     262             :     // overflows its range, it will redirect here.
     263             :     //
     264             :     // In our relocation table, we store two offsets instead of one: the offset
     265             :     // to the original jump, and an offset to the extended jump if we will need
     266             :     // to use it instead. The offsets are stored as:
     267             :     //    [unsigned] Unsigned offset to short jump, from the start of the code.
     268             :     //    [unsigned] Unsigned offset to the extended jump, from the start of
     269             :     //               the jump table, in units of SizeOfJumpTableEntry.
     270             :     //
     271             :     // The start of the relocation table contains the offset from the code
     272             :     // buffer to the start of the extended jump table.
     273             :     //
     274             :     // Each entry in this table is a jmp [rip], followed by a ud2 to hint to the
     275             :     // hardware branch predictor that there is no fallthrough, followed by the
     276             :     // eight bytes containing an immediate address. This comes out to 16 bytes.
     277             :     //    +1 byte for opcode
     278             :     //    +1 byte for mod r/m
     279             :     //    +4 bytes for rip-relative offset (2)
     280             :     //    +2 bytes for ud2 instruction
     281             :     //    +8 bytes for 64-bit address
     282             :     //
     283             :     static const uint32_t SizeOfExtendedJump = 1 + 1 + 4 + 2 + 8;
     284             :     static const uint32_t SizeOfJumpTableEntry = 16;
     285             : 
     286             :     uint32_t extendedJumpTable_;
     287             : 
     288             :     static JitCode* CodeFromJump(JitCode* code, uint8_t* jump);
     289             : 
     290             :   private:
     291             :     void writeRelocation(JmpSrc src, Relocation::Kind reloc);
     292             :     void addPendingJump(JmpSrc src, ImmPtr target, Relocation::Kind reloc);
     293             : 
     294             :   protected:
     295             :     size_t addPatchableJump(JmpSrc src, Relocation::Kind reloc);
     296             : 
     297             :   public:
     298             :     using AssemblerX86Shared::j;
     299             :     using AssemblerX86Shared::jmp;
     300             :     using AssemblerX86Shared::push;
     301             :     using AssemblerX86Shared::pop;
     302             :     using AssemblerX86Shared::vmovq;
     303             : 
     304             :     static uint8_t* PatchableJumpAddress(JitCode* code, size_t index);
     305             :     static void PatchJumpEntry(uint8_t* entry, uint8_t* target, ReprotectCode reprotect);
     306             : 
     307        4503 :     Assembler()
     308        4503 :       : extendedJumpTable_(0)
     309             :     {
     310        4503 :     }
     311             : 
     312             :     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     313             : 
     314             :     // The buffer is about to be linked, make sure any constant pools or excess
     315             :     // bookkeeping has been flushed to the instruction stream.
     316             :     void finish();
     317             : 
     318             :     // Copy the assembly code to the given buffer, and perform any pending
     319             :     // relocations relying on the target address.
     320             :     void executableCopy(uint8_t* buffer, bool flushICache = true);
     321             : 
     322             :     // Actual assembly emitting functions.
     323             : 
     324         514 :     void push(const ImmGCPtr ptr) {
     325         514 :         movq(ptr, ScratchReg);
     326         514 :         push(ScratchReg);
     327         514 :     }
     328        5419 :     void push(const ImmWord ptr) {
     329             :         // We often end up with ImmWords that actually fit into int32.
     330             :         // Be aware of the sign extension behavior.
     331        5419 :         if (ptr.value <= INT32_MAX) {
     332         102 :             push(Imm32(ptr.value));
     333             :         } else {
     334        5317 :             movq(ptr, ScratchReg);
     335        5317 :             push(ScratchReg);
     336             :         }
     337        5419 :     }
     338             :     void push(ImmPtr imm) {
     339             :         push(ImmWord(uintptr_t(imm.value)));
     340             :     }
     341           1 :     void push(FloatRegister src) {
     342           1 :         subq(Imm32(sizeof(double)), StackPointer);
     343           1 :         vmovsd(src, Address(StackPointer, 0));
     344           1 :     }
     345        1087 :     CodeOffset pushWithPatch(ImmWord word) {
     346        1087 :         CodeOffset label = movWithPatch(word, ScratchReg);
     347        1087 :         push(ScratchReg);
     348        1087 :         return label;
     349             :     }
     350             : 
     351           2 :     void pop(FloatRegister src) {
     352           2 :         vmovsd(Address(StackPointer, 0), src);
     353           2 :         addq(Imm32(sizeof(double)), StackPointer);
     354           2 :     }
     355             : 
     356       25869 :     CodeOffset movWithPatch(ImmWord word, Register dest) {
     357       25869 :         masm.movq_i64r(word.value, dest.encoding());
     358       25869 :         return CodeOffset(masm.currentOffset());
     359             :     }
     360         206 :     CodeOffset movWithPatch(ImmPtr imm, Register dest) {
     361         206 :         return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
     362             :     }
     363             : 
     364             :     // This is for patching during code generation, not after.
     365           0 :     void patchAddq(CodeOffset offset, int32_t n) {
     366           0 :         unsigned char* code = masm.data();
     367           0 :         X86Encoding::SetInt32(code + offset.offset(), n);
     368           0 :     }
     369             : 
     370             :     // Load an ImmWord value into a register. Note that this instruction will
     371             :     // attempt to optimize its immediate field size. When a full 64-bit
     372             :     // immediate is needed for a relocation, use movWithPatch.
     373       37932 :     void movq(ImmWord word, Register dest) {
     374             :         // Load a 64-bit immediate into a register. If the value falls into
     375             :         // certain ranges, we can use specialized instructions which have
     376             :         // smaller encodings.
     377       37932 :         if (word.value <= UINT32_MAX) {
     378             :             // movl has a 32-bit unsigned (effectively) immediate field.
     379        5777 :             masm.movl_i32r((uint32_t)word.value, dest.encoding());
     380       32155 :         } else if ((intptr_t)word.value >= INT32_MIN && (intptr_t)word.value <= INT32_MAX) {
     381             :             // movq has a 32-bit signed immediate field.
     382           0 :             masm.movq_i32r((int32_t)(intptr_t)word.value, dest.encoding());
     383             :         } else {
     384             :             // Otherwise use movabs.
     385       32155 :             masm.movq_i64r(word.value, dest.encoding());
     386             :         }
     387       37931 :     }
     388       22704 :     void movq(ImmPtr imm, Register dest) {
     389       22704 :         movq(ImmWord(uintptr_t(imm.value)), dest);
     390       22704 :     }
     391        4213 :     void movq(ImmGCPtr ptr, Register dest) {
     392        4213 :         masm.movq_i64r(uintptr_t(ptr.value), dest.encoding());
     393        4213 :         writeDataRelocation(ptr);
     394        4213 :     }
     395       51753 :     void movq(const Operand& src, Register dest) {
     396       51753 :         switch (src.kind()) {
     397             :           case Operand::REG:
     398           0 :             masm.movq_rr(src.reg(), dest.encoding());
     399           0 :             break;
     400             :           case Operand::MEM_REG_DISP:
     401       51409 :             masm.movq_mr(src.disp(), src.base(), dest.encoding());
     402       51409 :             break;
     403             :           case Operand::MEM_SCALE:
     404         344 :             masm.movq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     405         344 :             break;
     406             :           case Operand::MEM_ADDRESS32:
     407           0 :             masm.movq_mr(src.address(), dest.encoding());
     408           0 :             break;
     409             :           default:
     410           0 :             MOZ_CRASH("unexpected operand kind");
     411             :         }
     412       51753 :     }
     413       26241 :     void movq(Register src, const Operand& dest) {
     414       26241 :         switch (dest.kind()) {
     415             :           case Operand::REG:
     416       16925 :             masm.movq_rr(src.encoding(), dest.reg());
     417       16925 :             break;
     418             :           case Operand::MEM_REG_DISP:
     419        9252 :             masm.movq_rm(src.encoding(), dest.disp(), dest.base());
     420        9252 :             break;
     421             :           case Operand::MEM_SCALE:
     422          65 :             masm.movq_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
     423          65 :             break;
     424             :           case Operand::MEM_ADDRESS32:
     425           0 :             masm.movq_rm(src.encoding(), dest.address());
     426           0 :             break;
     427             :           default:
     428           0 :             MOZ_CRASH("unexpected operand kind");
     429             :         }
     430       26242 :     }
     431        1381 :     void movq(Imm32 imm32, const Operand& dest) {
     432        1381 :         switch (dest.kind()) {
     433             :           case Operand::REG:
     434           0 :             masm.movl_i32r(imm32.value, dest.reg());
     435           0 :             break;
     436             :           case Operand::MEM_REG_DISP:
     437        1381 :             masm.movq_i32m(imm32.value, dest.disp(), dest.base());
     438        1381 :             break;
     439             :           case Operand::MEM_SCALE:
     440           0 :             masm.movq_i32m(imm32.value, dest.disp(), dest.base(), dest.index(), dest.scale());
     441           0 :             break;
     442             :           case Operand::MEM_ADDRESS32:
     443           0 :             masm.movq_i32m(imm32.value, dest.address());
     444           0 :             break;
     445             :           default:
     446           0 :             MOZ_CRASH("unexpected operand kind");
     447             :         }
     448        1381 :     }
     449          52 :     void vmovq(Register src, FloatRegister dest) {
     450          52 :         masm.vmovq_rr(src.encoding(), dest.encoding());
     451          52 :     }
     452           9 :     void vmovq(FloatRegister src, Register dest) {
     453           9 :         masm.vmovq_rr(src.encoding(), dest.encoding());
     454           9 :     }
     455       33037 :     void movq(Register src, Register dest) {
     456       33037 :         masm.movq_rr(src.encoding(), dest.encoding());
     457       33037 :     }
     458             : 
     459           0 :     void cmovzq(const Operand& src, Register dest) {
     460           0 :         switch (src.kind()) {
     461             :           case Operand::REG:
     462           0 :             masm.cmovzq_rr(src.reg(), dest.encoding());
     463           0 :             break;
     464             :           case Operand::MEM_REG_DISP:
     465           0 :             masm.cmovzq_mr(src.disp(), src.base(), dest.encoding());
     466           0 :             break;
     467             :           case Operand::MEM_SCALE:
     468           0 :             masm.cmovzq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     469           0 :             break;
     470             :           default:
     471           0 :             MOZ_CRASH("unexpected operand kind");
     472             :         }
     473           0 :     }
     474             : 
     475           5 :     void xchgq(Register src, Register dest) {
     476           5 :         masm.xchgq_rr(src.encoding(), dest.encoding());
     477           5 :     }
     478             : 
     479           0 :     void movsbq(const Operand& src, Register dest) {
     480           0 :         switch (src.kind()) {
     481             :           case Operand::MEM_REG_DISP:
     482           0 :             masm.movsbq_mr(src.disp(), src.base(), dest.encoding());
     483           0 :             break;
     484             :           case Operand::MEM_SCALE:
     485           0 :             masm.movsbq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     486           0 :             break;
     487             :           default:
     488           0 :             MOZ_CRASH("unexpected operand kind");
     489             :         }
     490           0 :     }
     491             : 
     492           0 :     void movzbq(const Operand& src, Register dest) {
     493             :         // movzbl zero-extends to 64 bits and is one byte smaller, so use that
     494             :         // instead.
     495           0 :         movzbl(src, dest);
     496           0 :     }
     497             : 
     498           0 :     void movswq(const Operand& src, Register dest) {
     499           0 :         switch (src.kind()) {
     500             :           case Operand::MEM_REG_DISP:
     501           0 :             masm.movswq_mr(src.disp(), src.base(), dest.encoding());
     502           0 :             break;
     503             :           case Operand::MEM_SCALE:
     504           0 :             masm.movswq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     505           0 :             break;
     506             :           default:
     507           0 :             MOZ_CRASH("unexpected operand kind");
     508             :         }
     509           0 :     }
     510             : 
     511           0 :     void movzwq(const Operand& src, Register dest) {
     512             :         // movzwl zero-extends to 64 bits and is one byte smaller, so use that
     513             :         // instead.
     514           0 :         movzwl(src, dest);
     515           0 :     }
     516             : 
     517           0 :     void movslq(Register src, Register dest) {
     518           0 :         masm.movslq_rr(src.encoding(), dest.encoding());
     519           0 :     }
     520           0 :     void movslq(const Operand& src, Register dest) {
     521           0 :         switch (src.kind()) {
     522             :           case Operand::REG:
     523           0 :             masm.movslq_rr(src.reg(), dest.encoding());
     524           0 :             break;
     525             :           case Operand::MEM_REG_DISP:
     526           0 :             masm.movslq_mr(src.disp(), src.base(), dest.encoding());
     527           0 :             break;
     528             :           case Operand::MEM_SCALE:
     529           0 :             masm.movslq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     530           0 :             break;
     531             :           default:
     532           0 :             MOZ_CRASH("unexpected operand kind");
     533             :         }
     534           0 :     }
     535             : 
     536        1452 :     void andq(Register src, Register dest) {
     537        1452 :         masm.andq_rr(src.encoding(), dest.encoding());
     538        1452 :     }
     539       14369 :     void andq(Imm32 imm, Register dest) {
     540       14369 :         masm.andq_ir(imm.value, dest.encoding());
     541       14369 :     }
     542         196 :     void andq(const Operand& src, Register dest) {
     543         196 :         switch (src.kind()) {
     544             :           case Operand::REG:
     545          33 :             masm.andq_rr(src.reg(), dest.encoding());
     546          33 :             break;
     547             :           case Operand::MEM_REG_DISP:
     548         162 :             masm.andq_mr(src.disp(), src.base(), dest.encoding());
     549         162 :             break;
     550             :           case Operand::MEM_SCALE:
     551           1 :             masm.andq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     552           1 :             break;
     553             :           case Operand::MEM_ADDRESS32:
     554           0 :             masm.andq_mr(src.address(), dest.encoding());
     555           0 :             break;
     556             :           default:
     557           0 :             MOZ_CRASH("unexpected operand kind");
     558             :         }
     559         196 :     }
     560             : 
     561       35224 :     void addq(Imm32 imm, Register dest) {
     562       35224 :         masm.addq_ir(imm.value, dest.encoding());
     563       35223 :     }
     564           0 :     CodeOffset addqWithPatch(Imm32 imm, Register dest) {
     565           0 :         masm.addq_i32r(imm.value, dest.encoding());
     566           0 :         return CodeOffset(masm.currentOffset());
     567             :     }
     568        7508 :     void addq(Imm32 imm, const Operand& dest) {
     569        7508 :         switch (dest.kind()) {
     570             :           case Operand::REG:
     571           0 :             masm.addq_ir(imm.value, dest.reg());
     572           0 :             break;
     573             :           case Operand::MEM_REG_DISP:
     574        7508 :             masm.addq_im(imm.value, dest.disp(), dest.base());
     575        7508 :             break;
     576             :           case Operand::MEM_ADDRESS32:
     577           0 :             masm.addq_im(imm.value, dest.address());
     578           0 :             break;
     579             :           default:
     580           0 :             MOZ_CRASH("unexpected operand kind");
     581             :         }
     582        7508 :     }
     583         497 :     void addq(Register src, Register dest) {
     584         497 :         masm.addq_rr(src.encoding(), dest.encoding());
     585         497 :     }
     586          22 :     void addq(const Operand& src, Register dest) {
     587          22 :         switch (src.kind()) {
     588             :           case Operand::REG:
     589           0 :             masm.addq_rr(src.reg(), dest.encoding());
     590           0 :             break;
     591             :           case Operand::MEM_REG_DISP:
     592          22 :             masm.addq_mr(src.disp(), src.base(), dest.encoding());
     593          22 :             break;
     594             :           case Operand::MEM_ADDRESS32:
     595           0 :             masm.addq_mr(src.address(), dest.encoding());
     596           0 :             break;
     597             :           default:
     598           0 :             MOZ_CRASH("unexpected operand kind");
     599             :         }
     600          22 :     }
     601             : 
     602       28836 :     void subq(Imm32 imm, Register dest) {
     603       28836 :         masm.subq_ir(imm.value, dest.encoding());
     604       28836 :     }
     605        1700 :     void subq(Register src, Register dest) {
     606        1700 :         masm.subq_rr(src.encoding(), dest.encoding());
     607        1700 :     }
     608          91 :     void subq(const Operand& src, Register dest) {
     609          91 :         switch (src.kind()) {
     610             :           case Operand::REG:
     611           0 :             masm.subq_rr(src.reg(), dest.encoding());
     612           0 :             break;
     613             :           case Operand::MEM_REG_DISP:
     614          91 :             masm.subq_mr(src.disp(), src.base(), dest.encoding());
     615          91 :             break;
     616             :           case Operand::MEM_ADDRESS32:
     617           0 :             masm.subq_mr(src.address(), dest.encoding());
     618           0 :             break;
     619             :           default:
     620           0 :             MOZ_CRASH("unexpected operand kind");
     621             :         }
     622          91 :     }
     623             :     void subq(Register src, const Operand& dest) {
     624             :         switch (dest.kind()) {
     625             :           case Operand::REG:
     626             :             masm.subq_rr(src.encoding(), dest.reg());
     627             :             break;
     628             :           case Operand::MEM_REG_DISP:
     629             :             masm.subq_rm(src.encoding(), dest.disp(), dest.base());
     630             :             break;
     631             :           default:
     632             :             MOZ_CRASH("unexpected operand kind");
     633             :         }
     634             :     }
     635        1668 :     void shlq(Imm32 imm, Register dest) {
     636        1668 :         masm.shlq_ir(imm.value, dest.encoding());
     637        1668 :     }
     638        5828 :     void shrq(Imm32 imm, Register dest) {
     639        5828 :         masm.shrq_ir(imm.value, dest.encoding());
     640        5828 :     }
     641          17 :     void sarq(Imm32 imm, Register dest) {
     642          17 :         masm.sarq_ir(imm.value, dest.encoding());
     643          17 :     }
     644           0 :     void shlq_cl(Register dest) {
     645           0 :         masm.shlq_CLr(dest.encoding());
     646           0 :     }
     647           0 :     void shrq_cl(Register dest) {
     648           0 :         masm.shrq_CLr(dest.encoding());
     649           0 :     }
     650           0 :     void sarq_cl(Register dest) {
     651           0 :         masm.sarq_CLr(dest.encoding());
     652           0 :     }
     653           0 :     void rolq(Imm32 imm, Register dest) {
     654           0 :         masm.rolq_ir(imm.value, dest.encoding());
     655           0 :     }
     656           0 :     void rolq_cl(Register dest) {
     657           0 :         masm.rolq_CLr(dest.encoding());
     658           0 :     }
     659           0 :     void rorq(Imm32 imm, Register dest) {
     660           0 :         masm.rorq_ir(imm.value, dest.encoding());
     661           0 :     }
     662           0 :     void rorq_cl(Register dest) {
     663           0 :         masm.rorq_CLr(dest.encoding());
     664           0 :     }
     665        2084 :     void orq(Imm32 imm, Register dest) {
     666        2084 :         masm.orq_ir(imm.value, dest.encoding());
     667        2084 :     }
     668        1306 :     void orq(Register src, Register dest) {
     669        1306 :         masm.orq_rr(src.encoding(), dest.encoding());
     670        1306 :     }
     671           0 :     void orq(const Operand& src, Register dest) {
     672           0 :         switch (src.kind()) {
     673             :           case Operand::REG:
     674           0 :             masm.orq_rr(src.reg(), dest.encoding());
     675           0 :             break;
     676             :           case Operand::MEM_REG_DISP:
     677           0 :             masm.orq_mr(src.disp(), src.base(), dest.encoding());
     678           0 :             break;
     679             :           case Operand::MEM_ADDRESS32:
     680           0 :             masm.orq_mr(src.address(), dest.encoding());
     681           0 :             break;
     682             :           default:
     683           0 :             MOZ_CRASH("unexpected operand kind");
     684             :         }
     685           0 :     }
     686           0 :     void xorq(Register src, Register dest) {
     687           0 :         masm.xorq_rr(src.encoding(), dest.encoding());
     688           0 :     }
     689         473 :     void xorq(Imm32 imm, Register dest) {
     690         473 :         masm.xorq_ir(imm.value, dest.encoding());
     691         473 :     }
     692           0 :     void xorq(const Operand& src, Register dest) {
     693           0 :         switch (src.kind()) {
     694             :           case Operand::REG:
     695           0 :             masm.xorq_rr(src.reg(), dest.encoding());
     696           0 :             break;
     697             :           case Operand::MEM_REG_DISP:
     698           0 :             masm.xorq_mr(src.disp(), src.base(), dest.encoding());
     699           0 :             break;
     700             :           case Operand::MEM_ADDRESS32:
     701           0 :             masm.xorq_mr(src.address(), dest.encoding());
     702           0 :             break;
     703             :           default:
     704           0 :             MOZ_CRASH("unexpected operand kind");
     705             :         }
     706           0 :     }
     707             : 
     708           0 :     void bsrq(const Register& src, const Register& dest) {
     709           0 :         masm.bsrq_rr(src.encoding(), dest.encoding());
     710           0 :     }
     711           0 :     void bsfq(const Register& src, const Register& dest) {
     712           0 :         masm.bsfq_rr(src.encoding(), dest.encoding());
     713           0 :     }
     714           0 :     void popcntq(const Register& src, const Register& dest) {
     715           0 :         masm.popcntq_rr(src.encoding(), dest.encoding());
     716           0 :     }
     717             : 
     718           0 :     void imulq(Register src, Register dest) {
     719           0 :         masm.imulq_rr(src.encoding(), dest.encoding());
     720           0 :     }
     721           0 :     void imulq(const Operand& src, Register dest) {
     722           0 :         switch (src.kind()) {
     723             :           case Operand::REG:
     724           0 :             masm.imulq_rr(src.reg(), dest.encoding());
     725           0 :             break;
     726             :           case Operand::MEM_REG_DISP:
     727           0 :             masm.imulq_mr(src.disp(), src.base(), dest.encoding());
     728           0 :             break;
     729             :           case Operand::MEM_ADDRESS32:
     730           0 :             MOZ_CRASH("NYI");
     731             :             break;
     732             :           default:
     733           0 :             MOZ_CRASH("unexpected operand kind");
     734             :         }
     735           0 :     }
     736             : 
     737           0 :     void cqo() {
     738           0 :         masm.cqo();
     739           0 :     }
     740           0 :     void idivq(Register divisor) {
     741           0 :         masm.idivq_r(divisor.encoding());
     742           0 :     }
     743           0 :     void udivq(Register divisor) {
     744           0 :         masm.divq_r(divisor.encoding());
     745           0 :     }
     746             : 
     747             :     void vcvtsi2sdq(Register src, FloatRegister dest) {
     748             :         masm.vcvtsi2sdq_rr(src.encoding(), dest.encoding());
     749             :     }
     750             : 
     751           0 :     void negq(Register reg) {
     752           0 :         masm.negq_r(reg.encoding());
     753           0 :     }
     754             : 
     755       11110 :     void mov(ImmWord word, Register dest) {
     756             :         // Use xor for setting registers to zero, as it is specially optimized
     757             :         // for this purpose on modern hardware. Note that it does clobber FLAGS
     758             :         // though. Use xorl instead of xorq since they are functionally
     759             :         // equivalent (32-bit instructions zero-extend their results to 64 bits)
     760             :         // and xorl has a smaller encoding.
     761       11110 :         if (word.value == 0)
     762        1199 :             xorl(dest, dest);
     763             :         else
     764        9911 :             movq(word, dest);
     765       11110 :     }
     766       22704 :     void mov(ImmPtr imm, Register dest) {
     767       22704 :         movq(imm, dest);
     768       22704 :     }
     769           0 :     void mov(wasm::SymbolicAddress imm, Register dest) {
     770           0 :         masm.movq_i64r(-1, dest.encoding());
     771           0 :         append(wasm::SymbolicAccess(CodeOffset(masm.currentOffset()), imm));
     772           0 :     }
     773             :     void mov(const Operand& src, Register dest) {
     774             :         movq(src, dest);
     775             :     }
     776       17128 :     void mov(Register src, const Operand& dest) {
     777       17128 :         movq(src, dest);
     778       17128 :     }
     779             :     void mov(Imm32 imm32, const Operand& dest) {
     780             :         movq(imm32, dest);
     781             :     }
     782        1000 :     void mov(Register src, Register dest) {
     783        1000 :         movq(src, dest);
     784        1000 :     }
     785          17 :     void mov(CodeOffset* label, Register dest) {
     786          17 :         masm.movq_i64r(/* placeholder */ 0, dest.encoding());
     787          17 :         label->bind(masm.size());
     788          17 :     }
     789           5 :     void xchg(Register src, Register dest) {
     790           5 :         xchgq(src, dest);
     791           5 :     }
     792        3205 :     void lea(const Operand& src, Register dest) {
     793        3205 :         switch (src.kind()) {
     794             :           case Operand::MEM_REG_DISP:
     795        3087 :             masm.leaq_mr(src.disp(), src.base(), dest.encoding());
     796        3087 :             break;
     797             :           case Operand::MEM_SCALE:
     798         118 :             masm.leaq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
     799         118 :             break;
     800             :           default:
     801           0 :             MOZ_CRASH("unexepcted operand kind");
     802             :         }
     803        3205 :     }
     804             : 
     805             :     CodeOffset loadRipRelativeInt32(Register dest) {
     806             :         return CodeOffset(masm.movl_ripr(dest.encoding()).offset());
     807             :     }
     808             :     CodeOffset loadRipRelativeInt64(Register dest) {
     809             :         return CodeOffset(masm.movq_ripr(dest.encoding()).offset());
     810             :     }
     811             :     CodeOffset loadRipRelativeDouble(FloatRegister dest) {
     812             :         return CodeOffset(masm.vmovsd_ripr(dest.encoding()).offset());
     813             :     }
     814             :     CodeOffset loadRipRelativeFloat32(FloatRegister dest) {
     815             :         return CodeOffset(masm.vmovss_ripr(dest.encoding()).offset());
     816             :     }
     817             :     CodeOffset loadRipRelativeInt32x4(FloatRegister dest) {
     818             :         return CodeOffset(masm.vmovdqa_ripr(dest.encoding()).offset());
     819             :     }
     820             :     CodeOffset loadRipRelativeFloat32x4(FloatRegister dest) {
     821             :         return CodeOffset(masm.vmovaps_ripr(dest.encoding()).offset());
     822             :     }
     823             :     CodeOffset storeRipRelativeInt32(Register dest) {
     824             :         return CodeOffset(masm.movl_rrip(dest.encoding()).offset());
     825             :     }
     826             :     CodeOffset storeRipRelativeInt64(Register dest) {
     827             :         return CodeOffset(masm.movq_rrip(dest.encoding()).offset());
     828             :     }
     829             :     CodeOffset storeRipRelativeDouble(FloatRegister dest) {
     830             :         return CodeOffset(masm.vmovsd_rrip(dest.encoding()).offset());
     831             :     }
     832             :     CodeOffset storeRipRelativeFloat32(FloatRegister dest) {
     833             :         return CodeOffset(masm.vmovss_rrip(dest.encoding()).offset());
     834             :     }
     835             :     CodeOffset storeRipRelativeInt32x4(FloatRegister dest) {
     836             :         return CodeOffset(masm.vmovdqa_rrip(dest.encoding()).offset());
     837             :     }
     838             :     CodeOffset storeRipRelativeFloat32x4(FloatRegister dest) {
     839             :         return CodeOffset(masm.vmovaps_rrip(dest.encoding()).offset());
     840             :     }
     841             :     CodeOffset leaRipRelative(Register dest) {
     842             :         return CodeOffset(masm.leaq_rip(dest.encoding()).offset());
     843             :     }
     844             : 
     845         413 :     void cmpq(Register rhs, Register lhs) {
     846         413 :         masm.cmpq_rr(rhs.encoding(), lhs.encoding());
     847         413 :     }
     848        1946 :     void cmpq(Register rhs, const Operand& lhs) {
     849        1946 :         switch (lhs.kind()) {
     850             :           case Operand::REG:
     851         117 :             masm.cmpq_rr(rhs.encoding(), lhs.reg());
     852         117 :             break;
     853             :           case Operand::MEM_REG_DISP:
     854        1829 :             masm.cmpq_rm(rhs.encoding(), lhs.disp(), lhs.base());
     855        1829 :             break;
     856             :           case Operand::MEM_ADDRESS32:
     857           0 :             masm.cmpq_rm(rhs.encoding(), lhs.address());
     858           0 :             break;
     859             :           default:
     860           0 :             MOZ_CRASH("unexpected operand kind");
     861             :         }
     862        1946 :     }
     863           0 :     void cmpq(Imm32 rhs, Register lhs) {
     864           0 :         masm.cmpq_ir(rhs.value, lhs.encoding());
     865           0 :     }
     866        2748 :     void cmpq(Imm32 rhs, const Operand& lhs) {
     867        2748 :         switch (lhs.kind()) {
     868             :           case Operand::REG:
     869        1694 :             masm.cmpq_ir(rhs.value, lhs.reg());
     870        1694 :             break;
     871             :           case Operand::MEM_REG_DISP:
     872        1047 :             masm.cmpq_im(rhs.value, lhs.disp(), lhs.base());
     873        1047 :             break;
     874             :           case Operand::MEM_SCALE:
     875           7 :             masm.cmpq_im(rhs.value, lhs.disp(), lhs.base(), lhs.index(), lhs.scale());
     876           7 :             break;
     877             :           case Operand::MEM_ADDRESS32:
     878           0 :             masm.cmpq_im(rhs.value, lhs.address());
     879           0 :             break;
     880             :           default:
     881           0 :             MOZ_CRASH("unexpected operand kind");
     882             :         }
     883        2748 :     }
     884           0 :     void cmpq(const Operand& rhs, Register lhs) {
     885           0 :         switch (rhs.kind()) {
     886             :           case Operand::REG:
     887           0 :             masm.cmpq_rr(rhs.reg(), lhs.encoding());
     888           0 :             break;
     889             :           case Operand::MEM_REG_DISP:
     890           0 :             masm.cmpq_mr(rhs.disp(), rhs.base(), lhs.encoding());
     891           0 :             break;
     892             :           default:
     893           0 :             MOZ_CRASH("unexpected operand kind");
     894             :         }
     895           0 :     }
     896             : 
     897       13390 :     void testq(Imm32 rhs, Register lhs) {
     898       13390 :         masm.testq_ir(rhs.value, lhs.encoding());
     899       13390 :     }
     900         357 :     void testq(Register rhs, Register lhs) {
     901         357 :         masm.testq_rr(rhs.encoding(), lhs.encoding());
     902         357 :     }
     903          57 :     void testq(Imm32 rhs, const Operand& lhs) {
     904          57 :         switch (lhs.kind()) {
     905             :           case Operand::REG:
     906           0 :             masm.testq_ir(rhs.value, lhs.reg());
     907           0 :             break;
     908             :           case Operand::MEM_REG_DISP:
     909          57 :             masm.testq_i32m(rhs.value, lhs.disp(), lhs.base());
     910          57 :             break;
     911             :           default:
     912           0 :             MOZ_CRASH("unexpected operand kind");
     913             :             break;
     914             :         }
     915          57 :     }
     916             : 
     917        2614 :     void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) {
     918        2614 :         JmpSrc src = masm.jmp();
     919        2614 :         addPendingJump(src, target, reloc);
     920        2614 :     }
     921             :     void j(Condition cond, ImmPtr target,
     922             :            Relocation::Kind reloc = Relocation::HARDCODED) {
     923             :         JmpSrc src = masm.jCC(static_cast<X86Encoding::Condition>(cond));
     924             :         addPendingJump(src, target, reloc);
     925             :     }
     926             : 
     927        2606 :     void jmp(JitCode* target) {
     928        2606 :         jmp(ImmPtr(target->raw()), Relocation::JITCODE);
     929        2606 :     }
     930             :     void j(Condition cond, JitCode* target) {
     931             :         j(cond, ImmPtr(target->raw()), Relocation::JITCODE);
     932             :     }
     933        4069 :     void call(JitCode* target) {
     934        4069 :         JmpSrc src = masm.call();
     935        4069 :         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
     936        4069 :     }
     937           0 :     void call(ImmWord target) {
     938           0 :         call(ImmPtr((void*)target.value));
     939           0 :     }
     940       12946 :     void call(ImmPtr target) {
     941       12946 :         JmpSrc src = masm.call();
     942       12946 :         addPendingJump(src, target, Relocation::HARDCODED);
     943       12946 :     }
     944             : 
     945             :     // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
     946             :     // this instruction.
     947           0 :     CodeOffset toggledCall(JitCode* target, bool enabled) {
     948           0 :         CodeOffset offset(size());
     949           0 :         JmpSrc src = enabled ? masm.call() : masm.cmp_eax();
     950           0 :         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
     951           0 :         MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr));
     952           0 :         return offset;
     953             :     }
     954             : 
     955           0 :     static size_t ToggledCallSize(uint8_t* code) {
     956             :         // Size of a call instruction.
     957           0 :         return 5;
     958             :     }
     959             : 
     960             :     // Do not mask shared implementations.
     961             :     using AssemblerX86Shared::call;
     962             : 
     963           0 :     void vcvttsd2sq(FloatRegister src, Register dest) {
     964           0 :         masm.vcvttsd2sq_rr(src.encoding(), dest.encoding());
     965           0 :     }
     966           0 :     void vcvttss2sq(FloatRegister src, Register dest) {
     967           0 :         masm.vcvttss2sq_rr(src.encoding(), dest.encoding());
     968           0 :     }
     969           0 :     void vcvtsq2sd(Register src1, FloatRegister src0, FloatRegister dest) {
     970           0 :         masm.vcvtsq2sd_rr(src1.encoding(), src0.encoding(), dest.encoding());
     971           0 :     }
     972           0 :     void vcvtsq2ss(Register src1, FloatRegister src0, FloatRegister dest) {
     973           0 :         masm.vcvtsq2ss_rr(src1.encoding(), src0.encoding(), dest.encoding());
     974           0 :     }
     975             : };
     976             : 
     977             : static inline void
     978          21 : PatchJump(CodeLocationJump jump, CodeLocationLabel label, ReprotectCode reprotect = DontReprotect)
     979             : {
     980          21 :     if (X86Encoding::CanRelinkJump(jump.raw(), label.raw())) {
     981          42 :         MaybeAutoWritableJitCode awjc(jump.raw() - 8, 8, reprotect);
     982          21 :         X86Encoding::SetRel32(jump.raw(), label.raw());
     983             :     } else {
     984             :         {
     985           0 :             MaybeAutoWritableJitCode awjc(jump.raw() - 8, 8, reprotect);
     986           0 :             X86Encoding::SetRel32(jump.raw(), jump.jumpTableEntry());
     987             :         }
     988           0 :         Assembler::PatchJumpEntry(jump.jumpTableEntry(), label.raw(), reprotect);
     989             :     }
     990          21 : }
     991             : 
     992             : static inline void
     993           0 : PatchBackedge(CodeLocationJump& jump_, CodeLocationLabel label, JitZoneGroup::BackedgeTarget target)
     994             : {
     995           0 :     PatchJump(jump_, label);
     996           0 : }
     997             : 
     998             : static inline bool
     999          36 : GetIntArgReg(uint32_t intArg, uint32_t floatArg, Register* out)
    1000             : {
    1001             : #if defined(_WIN64)
    1002             :     uint32_t arg = intArg + floatArg;
    1003             : #else
    1004          36 :     uint32_t arg = intArg;
    1005             : #endif
    1006          36 :     if (arg >= NumIntArgRegs)
    1007           0 :         return false;
    1008          36 :     *out = IntArgRegs[arg];
    1009          36 :     return true;
    1010             : }
    1011             : 
    1012             : // Get a register in which we plan to put a quantity that will be used as an
    1013             : // integer argument.  This differs from GetIntArgReg in that if we have no more
    1014             : // actual argument registers to use we will fall back on using whatever
    1015             : // CallTempReg* don't overlap the argument registers, and only fail once those
    1016             : // run out too.
    1017             : static inline bool
    1018          36 : GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out)
    1019             : {
    1020          36 :     if (GetIntArgReg(usedIntArgs, usedFloatArgs, out))
    1021          36 :         return true;
    1022             :     // Unfortunately, we have to assume things about the point at which
    1023             :     // GetIntArgReg returns false, because we need to know how many registers it
    1024             :     // can allocate.
    1025             : #if defined(_WIN64)
    1026             :     uint32_t arg = usedIntArgs + usedFloatArgs;
    1027             : #else
    1028           0 :     uint32_t arg = usedIntArgs;
    1029             : #endif
    1030           0 :     arg -= NumIntArgRegs;
    1031           0 :     if (arg >= NumCallTempNonArgRegs)
    1032           0 :         return false;
    1033           0 :     *out = CallTempNonArgRegs[arg];
    1034           0 :     return true;
    1035             : }
    1036             : 
    1037             : static inline bool
    1038             : GetFloatArgReg(uint32_t intArg, uint32_t floatArg, FloatRegister* out)
    1039             : {
    1040             : #if defined(_WIN64)
    1041             :     uint32_t arg = intArg + floatArg;
    1042             : #else
    1043             :     uint32_t arg = floatArg;
    1044             : #endif
    1045             :     if (floatArg >= NumFloatArgRegs)
    1046             :         return false;
    1047             :     *out = FloatArgRegs[arg];
    1048             :     return true;
    1049             : }
    1050             : 
    1051             : } // namespace jit
    1052             : } // namespace js
    1053             : 
    1054             : #endif /* jit_x64_Assembler_x64_h */

Generated by: LCOV version 1.13