js/src/jit/x64/Assembler-x64.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #ifndef jit_x64_Assembler_x64_h
     8 #define jit_x64_Assembler_x64_h
    10 #include "mozilla/ArrayUtils.h"
    12 #include "jit/IonCode.h"
    13 #include "jit/shared/Assembler-shared.h"
    15 namespace js {
    16 namespace jit {
    18 static MOZ_CONSTEXPR_VAR Register rax = { JSC::X86Registers::eax };
    19 static MOZ_CONSTEXPR_VAR Register rbx = { JSC::X86Registers::ebx };
    20 static MOZ_CONSTEXPR_VAR Register rcx = { JSC::X86Registers::ecx };
    21 static MOZ_CONSTEXPR_VAR Register rdx = { JSC::X86Registers::edx };
    22 static MOZ_CONSTEXPR_VAR Register rsi = { JSC::X86Registers::esi };
    23 static MOZ_CONSTEXPR_VAR Register rdi = { JSC::X86Registers::edi };
    24 static MOZ_CONSTEXPR_VAR Register rbp = { JSC::X86Registers::ebp };
    25 static MOZ_CONSTEXPR_VAR Register r8  = { JSC::X86Registers::r8  };
    26 static MOZ_CONSTEXPR_VAR Register r9  = { JSC::X86Registers::r9  };
    27 static MOZ_CONSTEXPR_VAR Register r10 = { JSC::X86Registers::r10 };
    28 static MOZ_CONSTEXPR_VAR Register r11 = { JSC::X86Registers::r11 };
    29 static MOZ_CONSTEXPR_VAR Register r12 = { JSC::X86Registers::r12 };
    30 static MOZ_CONSTEXPR_VAR Register r13 = { JSC::X86Registers::r13 };
    31 static MOZ_CONSTEXPR_VAR Register r14 = { JSC::X86Registers::r14 };
    32 static MOZ_CONSTEXPR_VAR Register r15 = { JSC::X86Registers::r15 };
    33 static MOZ_CONSTEXPR_VAR Register rsp = { JSC::X86Registers::esp };
    35 static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = { JSC::X86Registers::xmm0 };
    36 static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = { JSC::X86Registers::xmm1 };
    37 static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = { JSC::X86Registers::xmm2 };
    38 static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = { JSC::X86Registers::xmm3 };
    39 static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = { JSC::X86Registers::xmm4 };
    40 static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = { JSC::X86Registers::xmm5 };
    41 static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = { JSC::X86Registers::xmm6 };
    42 static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = { JSC::X86Registers::xmm7 };
    43 static MOZ_CONSTEXPR_VAR FloatRegister xmm8 = { JSC::X86Registers::xmm8 };
    44 static MOZ_CONSTEXPR_VAR FloatRegister xmm9 = { JSC::X86Registers::xmm9 };
    45 static MOZ_CONSTEXPR_VAR FloatRegister xmm10 = { JSC::X86Registers::xmm10 };
    46 static MOZ_CONSTEXPR_VAR FloatRegister xmm11 = { JSC::X86Registers::xmm11 };
    47 static MOZ_CONSTEXPR_VAR FloatRegister xmm12 = { JSC::X86Registers::xmm12 };
    48 static MOZ_CONSTEXPR_VAR FloatRegister xmm13 = { JSC::X86Registers::xmm13 };
    49 static MOZ_CONSTEXPR_VAR FloatRegister xmm14 = { JSC::X86Registers::xmm14 };
    50 static MOZ_CONSTEXPR_VAR FloatRegister xmm15 = { JSC::X86Registers::xmm15 };
    52 // X86-common synonyms.
    53 static MOZ_CONSTEXPR_VAR Register eax = rax;
    54 static MOZ_CONSTEXPR_VAR Register ebx = rbx;
    55 static MOZ_CONSTEXPR_VAR Register ecx = rcx;
    56 static MOZ_CONSTEXPR_VAR Register edx = rdx;
    57 static MOZ_CONSTEXPR_VAR Register esi = rsi;
    58 static MOZ_CONSTEXPR_VAR Register edi = rdi;
    59 static MOZ_CONSTEXPR_VAR Register ebp = rbp;
    60 static MOZ_CONSTEXPR_VAR Register esp = rsp;
    62 static MOZ_CONSTEXPR_VAR Register InvalidReg = { JSC::X86Registers::invalid_reg };
    63 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm };
    65 static MOZ_CONSTEXPR_VAR Register StackPointer = rsp;
    66 static MOZ_CONSTEXPR_VAR Register FramePointer = rbp;
    67 static MOZ_CONSTEXPR_VAR Register JSReturnReg = rcx;
    68 // Avoid, except for assertions.
    69 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = JSReturnReg;
    70 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg;
    72 static MOZ_CONSTEXPR_VAR Register ReturnReg = rax;
    73 static MOZ_CONSTEXPR_VAR Register ScratchReg = r11;
    74 static MOZ_CONSTEXPR_VAR Register HeapReg = r15;
    75 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = xmm0;
    76 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = xmm15;
    78 // Avoid rbp, which is the FramePointer, which is unavailable in some modes.
    79 static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = r8;
    80 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = rax;
    81 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = rdi;
    82 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = rbx;
    83 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = rcx;
    84 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = rsi;
    85 static MOZ_CONSTEXPR_VAR Register CallTempReg5 = rdx;
    87 // Different argument registers for WIN64
    88 #if defined(_WIN64)
    89 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = rcx;
    90 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = rdx;
    91 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = r8;
    92 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = r9;
    93 static MOZ_CONSTEXPR_VAR uint32_t NumIntArgRegs = 4;
    94 static MOZ_CONSTEXPR_VAR Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 };
    96 static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi };
    97 static const uint32_t NumCallTempNonArgRegs =
    98     mozilla::ArrayLength(CallTempNonArgRegs);
   100 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg0 = xmm0;
   101 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg1 = xmm1;
   102 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg2 = xmm2;
   103 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg3 = xmm3;
   104 static const uint32_t NumFloatArgRegs = 4;
   105 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3 };
   106 #else
   107 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = rdi;
   108 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = rsi;
   109 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = rdx;
   110 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = rcx;
   111 static MOZ_CONSTEXPR_VAR Register IntArgReg4 = r8;
   112 static MOZ_CONSTEXPR_VAR Register IntArgReg5 = r9;
   113 static MOZ_CONSTEXPR_VAR uint32_t NumIntArgRegs = 6;
   114 static MOZ_CONSTEXPR_VAR Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 };
   116 static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { rax, rbx };
   117 static const uint32_t NumCallTempNonArgRegs =
   118     mozilla::ArrayLength(CallTempNonArgRegs);
   120 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg0 = xmm0;
   121 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg1 = xmm1;
   122 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg2 = xmm2;
   123 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg3 = xmm3;
   124 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg4 = xmm4;
   125 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg5 = xmm5;
   126 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg6 = xmm6;
   127 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg7 = xmm7;
   128 static MOZ_CONSTEXPR_VAR uint32_t NumFloatArgRegs = 8;
   129 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 };
   130 #endif
   132 // The convention used by the ForkJoinGetSlice stub. None of these can be rax
   133 // or rdx, which the stub also needs for cmpxchg and div, respectively.
   134 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_cx = rdi;
   135 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp0 = rbx;
   136 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp1 = rcx;
   137 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_output = rsi;
   139 // Registers used in the GenerateFFIIonExit Enable Activation block.
   140 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r10;
   141 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = rax;
   142 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = rdi;
   143 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = rbx;
   144 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = rsi;
   146 // Registers used in the GenerateFFIIonExit Disable Activation block.
   147 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = ecx;
   148 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx;
   149 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = rax;
   150 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = rdi;
   151 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = rbx;
   153 class ABIArgGenerator
   154 {
   155 #if defined(XP_WIN)
   156     unsigned regIndex_;
   157 #else
   158     unsigned intRegIndex_;
   159     unsigned floatRegIndex_;
   160 #endif
   161     uint32_t stackOffset_;
   162     ABIArg current_;
   164   public:
   165     ABIArgGenerator();
   166     ABIArg next(MIRType argType);
   167     ABIArg &current() { return current_; }
   168     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
   170     // Note: these registers are all guaranteed to be different
   171     static const Register NonArgReturnVolatileReg0;
   172     static const Register NonArgReturnVolatileReg1;
   173     static const Register NonVolatileReg;
   174 };
   176 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = IntArgReg3;
   178 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx;
   180 // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in
   181 // jitted code.
   182 static const uint32_t StackAlignment = 16;
   183 static const bool StackKeptAligned = false;
   184 static const uint32_t CodeAlignment = 8;
   185 static const uint32_t NativeFrameSize = sizeof(void*);
   186 static const uint32_t AlignmentAtPrologue = sizeof(void*);
   187 static const uint32_t AlignmentMidPrologue = AlignmentAtPrologue;
   189 static const Scale ScalePointer = TimesEight;
   191 } // namespace jit
   192 } // namespace js
   194 #include "jit/shared/Assembler-x86-shared.h"
   196 namespace js {
   197 namespace jit {
   199 // Return operand from a JS -> JS call.
   200 static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand = ValueOperand(JSReturnReg);
   202 class Assembler : public AssemblerX86Shared
   203 {
   204     // x64 jumps may need extra bits of relocation, because a jump may extend
   205     // beyond the signed 32-bit range. To account for this we add an extended
   206     // jump table at the bottom of the instruction stream, and if a jump
   207     // overflows its range, it will redirect here.
   208     //
   209     // In our relocation table, we store two offsets instead of one: the offset
   210     // to the original jump, and an offset to the extended jump if we will need
   211     // to use it instead. The offsets are stored as:
   212     //    [unsigned] Unsigned offset to short jump, from the start of the code.
   213     //    [unsigned] Unsigned offset to the extended jump, from the start of
   214     //               the jump table, in units of SizeOfJumpTableEntry.
   215     //
   216     // The start of the relocation table contains the offset from the code
   217     // buffer to the start of the extended jump table.
   218     //
   219     // Each entry in this table is a jmp [rip], followed by a ud2 to hint to the
   220     // hardware branch predictor that there is no fallthrough, followed by the
   221     // eight bytes containing an immediate address. This comes out to 16 bytes.
   222     //    +1 byte for opcode
   223     //    +1 byte for mod r/m
   224     //    +4 bytes for rip-relative offset (2)
   225     //    +2 bytes for ud2 instruction
   226     //    +8 bytes for 64-bit address
   227     //
   228     static const uint32_t SizeOfExtendedJump = 1 + 1 + 4 + 2 + 8;
   229     static const uint32_t SizeOfJumpTableEntry = 16;
   231     uint32_t extendedJumpTable_;
   233     static JitCode *CodeFromJump(JitCode *code, uint8_t *jump);
   235   private:
   236     void writeRelocation(JmpSrc src, Relocation::Kind reloc);
   237     void addPendingJump(JmpSrc src, ImmPtr target, Relocation::Kind reloc);
   239   protected:
   240     size_t addPatchableJump(JmpSrc src, Relocation::Kind reloc);
   242   public:
   243     using AssemblerX86Shared::j;
   244     using AssemblerX86Shared::jmp;
   245     using AssemblerX86Shared::push;
   246     using AssemblerX86Shared::pop;
   248     static uint8_t *PatchableJumpAddress(JitCode *code, size_t index);
   249     static void PatchJumpEntry(uint8_t *entry, uint8_t *target);
   251     Assembler()
   252       : extendedJumpTable_(0)
   253     {
   254     }
   256     static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
   258     // The buffer is about to be linked, make sure any constant pools or excess
   259     // bookkeeping has been flushed to the instruction stream.
   260     void finish();
   262     // Copy the assembly code to the given buffer, and perform any pending
   263     // relocations relying on the target address.
   264     void executableCopy(uint8_t *buffer);
   266     // Actual assembly emitting functions.
   268     void push(const ImmGCPtr ptr) {
   269         movq(ptr, ScratchReg);
   270         push(ScratchReg);
   271     }
   272     void push(const ImmWord ptr) {
   273         // We often end up with ImmWords that actually fit into int32.
   274         // Be aware of the sign extension behavior.
   275         if (ptr.value <= INT32_MAX) {
   276             push(Imm32(ptr.value));
   277         } else {
   278             movq(ptr, ScratchReg);
   279             push(ScratchReg);
   280         }
   281     }
   282     void push(const ImmPtr &imm) {
   283         push(ImmWord(uintptr_t(imm.value)));
   284     }
   285     void push(const FloatRegister &src) {
   286         subq(Imm32(sizeof(double)), StackPointer);
   287         movsd(src, Address(StackPointer, 0));
   288     }
   289     CodeOffsetLabel pushWithPatch(const ImmWord &word) {
   290         CodeOffsetLabel label = movWithPatch(word, ScratchReg);
   291         push(ScratchReg);
   292         return label;
   293     }
   295     void pop(const FloatRegister &src) {
   296         movsd(Address(StackPointer, 0), src);
   297         addq(Imm32(sizeof(double)), StackPointer);
   298     }
   300     CodeOffsetLabel movWithPatch(const ImmWord &word, const Register &dest) {
   301         masm.movq_i64r(word.value, dest.code());
   302         return masm.currentOffset();
   303     }
   304     CodeOffsetLabel movWithPatch(const ImmPtr &imm, const Register &dest) {
   305         return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
   306     }
   308     // Load an ImmWord value into a register. Note that this instruction will
   309     // attempt to optimize its immediate field size. When a full 64-bit
   310     // immediate is needed for a relocation, use movWithPatch.
   311     void movq(ImmWord word, const Register &dest) {
   312         // Load a 64-bit immediate into a register. If the value falls into
   313         // certain ranges, we can use specialized instructions which have
   314         // smaller encodings.
   315         if (word.value <= UINT32_MAX) {
   316             // movl has a 32-bit unsigned (effectively) immediate field.
   317             masm.movl_i32r((uint32_t)word.value, dest.code());
   318         } else if ((intptr_t)word.value >= INT32_MIN && (intptr_t)word.value <= INT32_MAX) {
   319             // movq has a 32-bit signed immediate field.
   320             masm.movq_i32r((int32_t)(intptr_t)word.value, dest.code());
   321         } else {
   322             // Otherwise use movabs.
   323             masm.movq_i64r(word.value, dest.code());
   324         }
   325     }
   326     void movq(ImmPtr imm, const Register &dest) {
   327         movq(ImmWord(uintptr_t(imm.value)), dest);
   328     }
   329     void movq(ImmGCPtr ptr, const Register &dest) {
   330         masm.movq_i64r(ptr.value, dest.code());
   331         writeDataRelocation(ptr);
   332     }
   333     void movq(const Operand &src, const Register &dest) {
   334         switch (src.kind()) {
   335           case Operand::REG:
   336             masm.movq_rr(src.reg(), dest.code());
   337             break;
   338           case Operand::MEM_REG_DISP:
   339             masm.movq_mr(src.disp(), src.base(), dest.code());
   340             break;
   341           case Operand::MEM_SCALE:
   342             masm.movq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
   343             break;
   344           case Operand::MEM_ADDRESS32:
   345             masm.movq_mr(src.address(), dest.code());
   346             break;
   347           default:
   348             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   349         }
   350     }
   351     void movq(const Register &src, const Operand &dest) {
   352         switch (dest.kind()) {
   353           case Operand::REG:
   354             masm.movq_rr(src.code(), dest.reg());
   355             break;
   356           case Operand::MEM_REG_DISP:
   357             masm.movq_rm(src.code(), dest.disp(), dest.base());
   358             break;
   359           case Operand::MEM_SCALE:
   360             masm.movq_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
   361             break;
   362           case Operand::MEM_ADDRESS32:
   363             masm.movq_rm(src.code(), dest.address());
   364             break;
   365           default:
   366             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   367         }
   368     }
   369     void movq(Imm32 imm32, const Operand &dest) {
   370         switch (dest.kind()) {
   371           case Operand::REG:
   372             masm.movl_i32r(imm32.value, dest.reg());
   373             break;
   374           case Operand::MEM_REG_DISP:
   375             masm.movq_i32m(imm32.value, dest.disp(), dest.base());
   376             break;
   377           case Operand::MEM_SCALE:
   378             masm.movq_i32m(imm32.value, dest.disp(), dest.base(), dest.index(), dest.scale());
   379             break;
   380           case Operand::MEM_ADDRESS32:
   381             masm.movq_i32m(imm32.value, dest.address());
   382             break;
   383           default:
   384             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   385         }
   386     }
   387     void movq(const Register &src, const FloatRegister &dest) {
   388         masm.movq_rr(src.code(), dest.code());
   389     }
   390     void movq(const FloatRegister &src, const Register &dest) {
   391         masm.movq_rr(src.code(), dest.code());
   392     }
   393     void movq(const Register &src, const Register &dest) {
   394         masm.movq_rr(src.code(), dest.code());
   395     }
   397     void xchgq(const Register &src, const Register &dest) {
   398         masm.xchgq_rr(src.code(), dest.code());
   399     }
   401     void andq(const Register &src, const Register &dest) {
   402         masm.andq_rr(src.code(), dest.code());
   403     }
   404     void andq(Imm32 imm, const Register &dest) {
   405         masm.andq_ir(imm.value, dest.code());
   406     }
   408     void addq(Imm32 imm, const Register &dest) {
   409         masm.addq_ir(imm.value, dest.code());
   410     }
   411     void addq(Imm32 imm, const Operand &dest) {
   412         switch (dest.kind()) {
   413           case Operand::REG:
   414             masm.addq_ir(imm.value, dest.reg());
   415             break;
   416           case Operand::MEM_REG_DISP:
   417             masm.addq_im(imm.value, dest.disp(), dest.base());
   418             break;
   419           case Operand::MEM_ADDRESS32:
   420             masm.addq_im(imm.value, dest.address());
   421             break;
   422           default:
   423             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   424         }
   425     }
   426     void addq(const Register &src, const Register &dest) {
   427         masm.addq_rr(src.code(), dest.code());
   428     }
   429     void addq(const Operand &src, const Register &dest) {
   430         switch (src.kind()) {
   431           case Operand::REG:
   432             masm.addq_rr(src.reg(), dest.code());
   433             break;
   434           case Operand::MEM_REG_DISP:
   435             masm.addq_mr(src.disp(), src.base(), dest.code());
   436             break;
   437           case Operand::MEM_ADDRESS32:
   438             masm.addq_mr(src.address(), dest.code());
   439             break;
   440           default:
   441             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   442         }
   443     }
   445     void subq(Imm32 imm, const Register &dest) {
   446         masm.subq_ir(imm.value, dest.code());
   447     }
   448     void subq(const Register &src, const Register &dest) {
   449         masm.subq_rr(src.code(), dest.code());
   450     }
   451     void subq(const Operand &src, const Register &dest) {
   452         switch (src.kind()) {
   453           case Operand::REG:
   454             masm.subq_rr(src.reg(), dest.code());
   455             break;
   456           case Operand::MEM_REG_DISP:
   457             masm.subq_mr(src.disp(), src.base(), dest.code());
   458             break;
   459           case Operand::MEM_ADDRESS32:
   460             masm.subq_mr(src.address(), dest.code());
   461             break;
   462           default:
   463             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   464         }
   465     }
   466     void subq(const Register &src, const Operand &dest) {
   467         switch (dest.kind()) {
   468           case Operand::REG:
   469             masm.subq_rr(src.code(), dest.reg());
   470             break;
   471           case Operand::MEM_REG_DISP:
   472             masm.subq_rm(src.code(), dest.disp(), dest.base());
   473             break;
   474           default:
   475             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   476         }
   477     }
   478     void shlq(Imm32 imm, const Register &dest) {
   479         masm.shlq_i8r(imm.value, dest.code());
   480     }
   481     void shrq(Imm32 imm, const Register &dest) {
   482         masm.shrq_i8r(imm.value, dest.code());
   483     }
   484     void sarq(Imm32 imm, const Register &dest) {
   485         masm.sarq_i8r(imm.value, dest.code());
   486     }
   487     void orq(Imm32 imm, const Register &dest) {
   488         masm.orq_ir(imm.value, dest.code());
   489     }
   490     void orq(const Register &src, const Register &dest) {
   491         masm.orq_rr(src.code(), dest.code());
   492     }
   493     void orq(const Operand &src, const Register &dest) {
   494         switch (src.kind()) {
   495           case Operand::REG:
   496             masm.orq_rr(src.reg(), dest.code());
   497             break;
   498           case Operand::MEM_REG_DISP:
   499             masm.orq_mr(src.disp(), src.base(), dest.code());
   500             break;
   501           case Operand::MEM_ADDRESS32:
   502             masm.orq_mr(src.address(), dest.code());
   503             break;
   504           default:
   505             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   506         }
   507     }
   508     void xorq(const Register &src, const Register &dest) {
   509         masm.xorq_rr(src.code(), dest.code());
   510     }
   511     void xorq(Imm32 imm, const Register &dest) {
   512         masm.xorq_ir(imm.value, dest.code());
   513     }
   515     void mov(ImmWord word, const Register &dest) {
   516         // Use xor for setting registers to zero, as it is specially optimized
   517         // for this purpose on modern hardware. Note that it does clobber FLAGS
   518         // though. Use xorl instead of xorq since they are functionally
   519         // equivalent (32-bit instructions zero-extend their results to 64 bits)
   520         // and xorl has a smaller encoding.
   521         if (word.value == 0)
   522             xorl(dest, dest);
   523         else
   524             movq(word, dest);
   525     }
   526     void mov(ImmPtr imm, const Register &dest) {
   527         movq(imm, dest);
   528     }
   529     void mov(AsmJSImmPtr imm, const Register &dest) {
   530         masm.movq_i64r(-1, dest.code());
   531         enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), imm.kind()));
   532     }
   533     void mov(const Operand &src, const Register &dest) {
   534         movq(src, dest);
   535     }
   536     void mov(const Register &src, const Operand &dest) {
   537         movq(src, dest);
   538     }
   539     void mov(const Imm32 &imm32, const Operand &dest) {
   540         movq(imm32, dest);
   541     }
   542     void mov(const Register &src, const Register &dest) {
   543         movq(src, dest);
   544     }
   545     void mov(AbsoluteLabel *label, const Register &dest) {
   546         JS_ASSERT(!label->bound());
   547         // Thread the patch list through the unpatched address word in the
   548         // instruction stream.
   549         masm.movq_i64r(label->prev(), dest.code());
   550         label->setPrev(masm.size());
   551     }
   552     void xchg(const Register &src, const Register &dest) {
   553         xchgq(src, dest);
   554     }
   555     void lea(const Operand &src, const Register &dest) {
   556         switch (src.kind()) {
   557           case Operand::MEM_REG_DISP:
   558             masm.leaq_mr(src.disp(), src.base(), dest.code());
   559             break;
   560           case Operand::MEM_SCALE:
   561             masm.leaq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
   562             break;
   563           default:
   564             MOZ_ASSUME_UNREACHABLE("unexepcted operand kind");
   565         }
   566     }
   568     CodeOffsetLabel loadRipRelativeInt32(const Register &dest) {
   569         return CodeOffsetLabel(masm.movl_ripr(dest.code()).offset());
   570     }
   571     CodeOffsetLabel loadRipRelativeInt64(const Register &dest) {
   572         return CodeOffsetLabel(masm.movq_ripr(dest.code()).offset());
   573     }
   574     CodeOffsetLabel loadRipRelativeDouble(const FloatRegister &dest) {
   575         return CodeOffsetLabel(masm.movsd_ripr(dest.code()).offset());
   576     }
   577     CodeOffsetLabel storeRipRelativeInt32(const Register &dest) {
   578         return CodeOffsetLabel(masm.movl_rrip(dest.code()).offset());
   579     }
   580     CodeOffsetLabel storeRipRelativeDouble(const FloatRegister &dest) {
   581         return CodeOffsetLabel(masm.movsd_rrip(dest.code()).offset());
   582     }
   583     CodeOffsetLabel leaRipRelative(const Register &dest) {
   584         return CodeOffsetLabel(masm.leaq_rip(dest.code()).offset());
   585     }
   587     // The below cmpq methods switch the lhs and rhs when it invokes the
   588     // macroassembler to conform with intel standard.  When calling this
   589     // function put the left operand on the left as you would expect.
   590     void cmpq(const Operand &lhs, const Register &rhs) {
   591         switch (lhs.kind()) {
   592           case Operand::REG:
   593             masm.cmpq_rr(rhs.code(), lhs.reg());
   594             break;
   595           case Operand::MEM_REG_DISP:
   596             masm.cmpq_rm(rhs.code(), lhs.disp(), lhs.base());
   597             break;
   598           case Operand::MEM_ADDRESS32:
   599             masm.cmpq_rm(rhs.code(), lhs.address());
   600             break;
   601           default:
   602             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   603         }
   604     }
   605     void cmpq(const Operand &lhs, Imm32 rhs) {
   606         switch (lhs.kind()) {
   607           case Operand::REG:
   608             masm.cmpq_ir(rhs.value, lhs.reg());
   609             break;
   610           case Operand::MEM_REG_DISP:
   611             masm.cmpq_im(rhs.value, lhs.disp(), lhs.base());
   612             break;
   613           case Operand::MEM_ADDRESS32:
   614             masm.cmpq_im(rhs.value, lhs.address());
   615             break;
   616           default:
   617             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   618         }
   619     }
   620     void cmpq(const Register &lhs, const Operand &rhs) {
   621         switch (rhs.kind()) {
   622           case Operand::REG:
   623             masm.cmpq_rr(rhs.reg(), lhs.code());
   624             break;
   625           case Operand::MEM_REG_DISP:
   626             masm.cmpq_mr(rhs.disp(), rhs.base(), lhs.code());
   627             break;
   628           default:
   629             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   630         }
   631     }
   632     void cmpq(const Register &lhs, const Register &rhs) {
   633         masm.cmpq_rr(rhs.code(), lhs.code());
   634     }
   635     void cmpq(const Register &lhs, Imm32 rhs) {
   636         masm.cmpq_ir(rhs.value, lhs.code());
   637     }
   639     void testq(const Register &lhs, Imm32 rhs) {
   640         masm.testq_i32r(rhs.value, lhs.code());
   641     }
   642     void testq(const Register &lhs, const Register &rhs) {
   643         masm.testq_rr(rhs.code(), lhs.code());
   644     }
   645     void testq(const Operand &lhs, Imm32 rhs) {
   646         switch (lhs.kind()) {
   647           case Operand::REG:
   648             masm.testq_i32r(rhs.value, lhs.reg());
   649             break;
   650           case Operand::MEM_REG_DISP:
   651             masm.testq_i32m(rhs.value, lhs.disp(), lhs.base());
   652             break;
   653           default:
   654             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
   655             break;
   656         }
   657     }
   659     void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) {
   660         JmpSrc src = masm.jmp();
   661         addPendingJump(src, target, reloc);
   662     }
   663     void j(Condition cond, ImmPtr target,
   664            Relocation::Kind reloc = Relocation::HARDCODED) {
   665         JmpSrc src = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond));
   666         addPendingJump(src, target, reloc);
   667     }
   669     void jmp(JitCode *target) {
   670         jmp(ImmPtr(target->raw()), Relocation::JITCODE);
   671     }
   672     void j(Condition cond, JitCode *target) {
   673         j(cond, ImmPtr(target->raw()), Relocation::JITCODE);
   674     }
   675     void call(JitCode *target) {
   676         JmpSrc src = masm.call();
   677         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
   678     }
   680     // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
   681     // this instruction.
   682     CodeOffsetLabel toggledCall(JitCode *target, bool enabled) {
   683         CodeOffsetLabel offset(size());
   684         JmpSrc src = enabled ? masm.call() : masm.cmp_eax();
   685         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
   686         JS_ASSERT(size() - offset.offset() == ToggledCallSize());
   687         return offset;
   688     }
   690     static size_t ToggledCallSize() {
   691         // Size of a call instruction.
   692         return 5;
   693     }
   695     // Do not mask shared implementations.
   696     using AssemblerX86Shared::call;
   698     void cvttsd2sq(const FloatRegister &src, const Register &dest) {
   699         masm.cvttsd2sq_rr(src.code(), dest.code());
   700     }
   701     void cvttss2sq(const FloatRegister &src, const Register &dest) {
   702         masm.cvttss2sq_rr(src.code(), dest.code());
   703     }
   704     void cvtsq2sd(const Register &src, const FloatRegister &dest) {
   705         masm.cvtsq2sd_rr(src.code(), dest.code());
   706     }
   707     void cvtsq2ss(const Register &src, const FloatRegister &dest) {
   708         masm.cvtsq2ss_rr(src.code(), dest.code());
   709     }
   710 };
   712 static inline void
   713 PatchJump(CodeLocationJump jump, CodeLocationLabel label)
   714 {
   715     if (JSC::X86Assembler::canRelinkJump(jump.raw(), label.raw())) {
   716         JSC::X86Assembler::setRel32(jump.raw(), label.raw());
   717     } else {
   718         JSC::X86Assembler::setRel32(jump.raw(), jump.jumpTableEntry());
   719         Assembler::PatchJumpEntry(jump.jumpTableEntry(), label.raw());
   720     }
   721 }
   723 static inline bool
   724 GetIntArgReg(uint32_t intArg, uint32_t floatArg, Register *out)
   725 {
   726 #if defined(_WIN64)
   727     uint32_t arg = intArg + floatArg;
   728 #else
   729     uint32_t arg = intArg;
   730 #endif
   731     if (arg >= NumIntArgRegs)
   732         return false;
   733     *out = IntArgRegs[arg];
   734     return true;
   735 }
   737 // Get a register in which we plan to put a quantity that will be used as an
   738 // integer argument.  This differs from GetIntArgReg in that if we have no more
   739 // actual argument registers to use we will fall back on using whatever
   740 // CallTempReg* don't overlap the argument registers, and only fail once those
   741 // run out too.
   742 static inline bool
   743 GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out)
   744 {
   745     if (GetIntArgReg(usedIntArgs, usedFloatArgs, out))
   746         return true;
   747     // Unfortunately, we have to assume things about the point at which
   748     // GetIntArgReg returns false, because we need to know how many registers it
   749     // can allocate.
   750 #if defined(_WIN64)
   751     uint32_t arg = usedIntArgs + usedFloatArgs;
   752 #else
   753     uint32_t arg = usedIntArgs;
   754 #endif
   755     arg -= NumIntArgRegs;
   756     if (arg >= NumCallTempNonArgRegs)
   757         return false;
   758     *out = CallTempNonArgRegs[arg];
   759     return true;
   760 }
   762 static inline bool
   763 GetFloatArgReg(uint32_t intArg, uint32_t floatArg, FloatRegister *out)
   764 {
   765 #if defined(_WIN64)
   766     uint32_t arg = intArg + floatArg;
   767 #else
   768     uint32_t arg = floatArg;
   769 #endif
   770     if (floatArg >= NumFloatArgRegs)
   771         return false;
   772     *out = FloatArgRegs[arg];
   773     return true;
   774 }
   776 } // namespace jit
   777 } // namespace js
   779 #endif /* jit_x64_Assembler_x64_h */

mercurial