summaryrefslogtreecommitdiff
path: root/js/src/assembler/assembler/X86Assembler.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/assembler/assembler/X86Assembler.h')
-rw-r--r--js/src/assembler/assembler/X86Assembler.h3004
1 files changed, 3004 insertions, 0 deletions
diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h
new file mode 100644
index 0000000..85dc968
--- /dev/null
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -0,0 +1,3004 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=79:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef X86Assembler_h
+#define X86Assembler_h
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_ASSEMBLER && (WTF_CPU_X86 || WTF_CPU_X86_64)
+
+#include "AssemblerBuffer.h"
+#include "jsstdint.h"
+#include "assembler/wtf/Assertions.h"
+#include "jsvector.h"
+
+#include "methodjit/Logging.h"
+#define IPFX " %s"
+#define ISPFX " "
+#ifdef JS_METHODJIT_SPEW
+# define MAYBE_PAD (isOOLPath ? "> " : "")
+# define PRETTY_PRINT_OFFSET(os) (((os)<0)?"-":""), (((os)<0)?-(os):(os))
+# define FIXME_INSN_PRINTING \
+ do { \
+ js::JaegerSpew(js::JSpew_Insns, \
+ ISPFX "FIXME insn printing %s:%d\n", \
+ __FILE__, __LINE__); \
+ } while (0)
+#else
+# define MAYBE_PAD ""
+# define FIXME_INSN_PRINTING ((void) 0)
+# define PRETTY_PRINT_OFFSET(os) "", 0
+#endif
+
+
+namespace JSC {
+
+inline bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(signed char)value; }
+
+namespace X86Registers {
+ typedef enum {
+ eax,
+ ecx,
+ edx,
+ ebx,
+ esp,
+ ebp,
+ esi,
+ edi
+
+#if WTF_CPU_X86_64
+ ,r8,
+ r9,
+ r10,
+ r11,
+ r12,
+ r13,
+ r14,
+ r15
+#endif
+ } RegisterID;
+
+ typedef enum {
+ xmm0,
+ xmm1,
+ xmm2,
+ xmm3,
+ xmm4,
+ xmm5,
+ xmm6,
+ xmm7
+ } XMMRegisterID;
+
+ static const char* nameFPReg(XMMRegisterID fpreg)
+ {
+ static const char* xmmnames[8]
+ = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
+ "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
+ int off = (XMMRegisterID)fpreg - (XMMRegisterID)xmm0;
+ return (off < 0 || off > 7) ? "%xmm?" : xmmnames[off];
+ }
+
+ static const char* nameIReg(int szB, RegisterID reg)
+ {
+ static const char* r64names[16]
+ = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
+ static const char* r32names[16]
+ = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
+ "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" };
+ static const char* r16names[16]
+ = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+ "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" };
+ static const char* r8names[16]
+ = { "%al", "%cl", "%dl", "%bl", "%ah/spl", "%ch/bpl", "%dh/sil", "%bh/dil",
+ "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" };
+ int off = (RegisterID)reg - (RegisterID)eax;
+ const char** tab = r64names;
+ switch (szB) {
+ case 1: tab = r8names; break;
+ case 2: tab = r16names; break;
+ case 4: tab = r32names; break;
+ }
+ return (off < 0 || off > 15) ? "%r???" : tab[off];
+ }
+
+ static const char* nameIReg(RegisterID reg)
+ {
+# if WTF_CPU_X86_64
+ return nameIReg(8, reg);
+# else
+ return nameIReg(4, reg);
+# endif
+ }
+
+} /* namespace X86Registers */
+
+
+class X86Assembler {
+public:
+ typedef X86Registers::RegisterID RegisterID;
+ typedef X86Registers::XMMRegisterID XMMRegisterID;
+ typedef XMMRegisterID FPRegisterID;
+
+ typedef enum {
+ ConditionO,
+ ConditionNO,
+ ConditionB,
+ ConditionAE,
+ ConditionE,
+ ConditionNE,
+ ConditionBE,
+ ConditionA,
+ ConditionS,
+ ConditionNS,
+ ConditionP,
+ ConditionNP,
+ ConditionL,
+ ConditionGE,
+ ConditionLE,
+ ConditionG,
+
+ ConditionC = ConditionB,
+ ConditionNC = ConditionAE
+ } Condition;
+
+ static const char* nameCC(Condition cc)
+ {
+ static const char* names[16]
+ = { "o ", "no", "b ", "ae", "e ", "ne", "be", "a ",
+ "s ", "ns", "p ", "np", "l ", "ge", "le", "g " };
+ int ix = (int)cc;
+ return (ix < 0 || ix > 15) ? "??" : names[ix];
+ }
+
+private:
+ typedef enum {
+ OP_ADD_EvGv = 0x01,
+ OP_ADD_GvEv = 0x03,
+ OP_OR_EvGv = 0x09,
+ OP_OR_GvEv = 0x0B,
+ OP_2BYTE_ESCAPE = 0x0F,
+ OP_3BYTE_ESCAPE = 0x3A,
+ OP_AND_EvGv = 0x21,
+ OP_AND_GvEv = 0x23,
+ OP_SUB_EvGv = 0x29,
+ OP_SUB_GvEv = 0x2B,
+ PRE_PREDICT_BRANCH_NOT_TAKEN = 0x2E,
+ OP_XOR_EvGv = 0x31,
+ OP_XOR_GvEv = 0x33,
+ OP_CMP_EvGv = 0x39,
+ OP_CMP_GvEv = 0x3B,
+#if WTF_CPU_X86_64
+ PRE_REX = 0x40,
+#endif
+ OP_PUSH_EAX = 0x50,
+ OP_POP_EAX = 0x58,
+#if WTF_CPU_X86
+ OP_PUSHA = 0x60,
+ OP_POPA = 0x61,
+#endif
+#if WTF_CPU_X86_64
+ OP_MOVSXD_GvEv = 0x63,
+#endif
+ PRE_OPERAND_SIZE = 0x66,
+ PRE_SSE_66 = 0x66,
+ OP_PUSH_Iz = 0x68,
+ OP_IMUL_GvEvIz = 0x69,
+ OP_GROUP1_EbIb = 0x80,
+ OP_GROUP1_EvIz = 0x81,
+ OP_GROUP1_EvIb = 0x83,
+ OP_TEST_EvGv = 0x85,
+ OP_XCHG_EvGv = 0x87,
+ OP_MOV_EbGv = 0x88,
+ OP_MOV_EvGv = 0x89,
+ OP_MOV_GvEv = 0x8B,
+ OP_LEA = 0x8D,
+ OP_GROUP1A_Ev = 0x8F,
+ OP_CDQ = 0x99,
+ OP_MOV_EAXOv = 0xA1,
+ OP_MOV_OvEAX = 0xA3,
+ OP_MOV_EAXIv = 0xB8,
+ OP_GROUP2_EvIb = 0xC1,
+ OP_RET = 0xC3,
+ OP_GROUP11_EvIb = 0xC6,
+ OP_GROUP11_EvIz = 0xC7,
+ OP_INT3 = 0xCC,
+ OP_GROUP2_Ev1 = 0xD1,
+ OP_GROUP2_EvCL = 0xD3,
+ OP_CALL_rel32 = 0xE8,
+ OP_JMP_rel32 = 0xE9,
+ PRE_SSE_F2 = 0xF2,
+ PRE_SSE_F3 = 0xF3,
+ OP_HLT = 0xF4,
+ OP_GROUP3_EbIb = 0xF6,
+ OP_GROUP3_Ev = 0xF7,
+ OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test.
+ OP_GROUP5_Ev = 0xFF
+ } OneByteOpcodeID;
+
+ typedef enum {
+ OP2_MOVSD_VsdWsd = 0x10,
+ OP2_MOVSD_WsdVsd = 0x11,
+ OP2_UNPCKLPS_VsdWsd = 0x14,
+ OP2_CVTSI2SD_VsdEd = 0x2A,
+ OP2_CVTTSD2SI_GdWsd = 0x2C,
+ OP2_UCOMISD_VsdWsd = 0x2E,
+ OP2_ADDSD_VsdWsd = 0x58,
+ OP2_MULSD_VsdWsd = 0x59,
+ OP2_CVTSS2SD_VsdEd = 0x5A,
+ OP2_CVTSD2SS_VsdEd = 0x5A,
+ OP2_SUBSD_VsdWsd = 0x5C,
+ OP2_DIVSD_VsdWsd = 0x5E,
+ OP2_SQRTSD_VsdWsd = 0x51,
+ OP2_XORPD_VpdWpd = 0x57,
+ OP2_MOVD_VdEd = 0x6E,
+ OP2_PSRLDQ_Vd = 0x73,
+ OP2_MOVD_EdVd = 0x7E,
+ OP2_JCC_rel32 = 0x80,
+ OP_SETCC = 0x90,
+ OP2_IMUL_GvEv = 0xAF,
+ OP2_MOVSX_GvEb = 0xBE,
+ OP2_MOVSX_GvEw = 0xBF,
+ OP2_MOVZX_GvEb = 0xB6,
+ OP2_MOVZX_GvEw = 0xB7,
+ OP2_PEXTRW_GdUdIb = 0xC5
+ } TwoByteOpcodeID;
+
+ typedef enum {
+ OP3_PINSRD_VsdWsd = 0x22
+ } ThreeByteOpcodeID;
+
+ TwoByteOpcodeID jccRel32(Condition cond)
+ {
+ return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond);
+ }
+
+ TwoByteOpcodeID setccOpcode(Condition cond)
+ {
+ return (TwoByteOpcodeID)(OP_SETCC + cond);
+ }
+
+ typedef enum {
+ GROUP1_OP_ADD = 0,
+ GROUP1_OP_OR = 1,
+ GROUP1_OP_ADC = 2,
+ GROUP1_OP_AND = 4,
+ GROUP1_OP_SUB = 5,
+ GROUP1_OP_XOR = 6,
+ GROUP1_OP_CMP = 7,
+
+ GROUP1A_OP_POP = 0,
+
+ GROUP2_OP_SHL = 4,
+ GROUP2_OP_SHR = 5,
+ GROUP2_OP_SAR = 7,
+
+ GROUP3_OP_TEST = 0,
+ GROUP3_OP_NOT = 2,
+ GROUP3_OP_NEG = 3,
+ GROUP3_OP_IDIV = 7,
+
+ GROUP5_OP_CALLN = 2,
+ GROUP5_OP_JMPN = 4,
+ GROUP5_OP_PUSH = 6,
+
+ GROUP11_MOV = 0
+ } GroupOpcodeID;
+
+ class X86InstructionFormatter;
+public:
+
+#ifdef JS_METHODJIT_SPEW
+ bool isOOLPath;
+#endif
+
+ class JmpSrc {
+ friend class X86Assembler;
+ friend class X86InstructionFormatter;
+ public:
+ JmpSrc()
+ : m_offset(-1)
+ {
+ }
+
+ private:
+ JmpSrc(int offset)
+ : m_offset(offset)
+ {
+ }
+
+ int m_offset;
+ };
+
+ class JmpDst {
+ friend class X86Assembler;
+ friend class X86InstructionFormatter;
+ public:
+ JmpDst()
+ : m_offset(-1)
+ , m_used(false)
+ {
+ }
+
+ bool isUsed() const { return m_used; }
+ void used() { m_used = true; }
+ bool isValid() const { return m_offset != -1; }
+ private:
+ JmpDst(int offset)
+ : m_offset(offset)
+ , m_used(false)
+ {
+ ASSERT(m_offset == offset);
+ }
+
+ signed int m_offset : 31;
+ bool m_used : 1;
+ };
+
+ X86Assembler()
+#ifdef JS_METHODJIT_SPEW
+ : isOOLPath(false)
+#endif
+ {
+ }
+
+ size_t size() const { return m_formatter.size(); }
+ unsigned char *buffer() const { return m_formatter.buffer(); }
+ bool oom() const { return m_formatter.oom(); }
+
+ // Stack operations:
+
+ void push_r(RegisterID reg)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "push %s\n", MAYBE_PAD, nameIReg(reg));
+ m_formatter.oneByteOp(OP_PUSH_EAX, reg);
+ }
+
+ void pop_r(RegisterID reg)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "pop %s\n", MAYBE_PAD, nameIReg(reg));
+ m_formatter.oneByteOp(OP_POP_EAX, reg);
+ }
+
+ void push_i32(int imm)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "pushl %s$0x%x\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(imm));
+ m_formatter.oneByteOp(OP_PUSH_Iz);
+ m_formatter.immediate32(imm);
+ }
+
+ void push_m(int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "push %s0x%x(%s)\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_PUSH, base, offset);
+ }
+
+ void pop_m(int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP1A_Ev, GROUP1A_OP_POP, base, offset);
+ }
+
+ // Arithmetic operations:
+
+#if !WTF_CPU_X86_64
+ void adcl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADC, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADC, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void addl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_ADD_EvGv, src, dst);
+ }
+
+ void addl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_ADD_GvEv, dst, base, offset);
+ }
+
+ void addl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_ADD_EvGv, src, base, offset);
+ }
+
+ void addl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void addl_im(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addl %d, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(8,base));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+#if WTF_CPU_X86_64
+ void addq_rr(RegisterID src, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_ADD_EvGv, src, dst);
+ }
+
+ void addq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void addq_im(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addq $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(8,base));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+#else
+ void addl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void andl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "andl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_AND_EvGv, src, dst);
+ }
+
+ void andl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_AND_GvEv, dst, base, offset);
+ }
+
+ void andl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_AND_EvGv, src, base, offset);
+ }
+
+ void andl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "andl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void andl_im(int imm, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+#if WTF_CPU_X86_64
+ void andq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "andq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_AND_EvGv, src, dst);
+ }
+
+ void andq_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "andq %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(8,base), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_AND_GvEv, dst, base, offset);
+ }
+
+ void orq_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orq %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(8,base), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_OR_GvEv, dst, base, offset);
+ }
+
+ void andq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "andq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_AND, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_AND, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+#else
+ void andl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void negl_r(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "negl %s\n", MAYBE_PAD, nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, dst);
+ }
+
+ void negl_m(int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, base, offset);
+ }
+
+ void notl_r(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "notl %s\n", MAYBE_PAD, nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, dst);
+ }
+
+ void notl_m(int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, base, offset);
+ }
+
+ void orl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_OR_EvGv, src, dst);
+ }
+
+ void orl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_OR_GvEv, dst, base, offset);
+ }
+
+ void orl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_OR_EvGv, src, base, offset);
+ }
+
+ void orl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void orl_im(int imm, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+#if WTF_CPU_X86_64
+ void orq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_OR_EvGv, src, dst);
+ }
+
+ void orq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_OR, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_OR, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void notq_r(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "notq %s\n", MAYBE_PAD, nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_GROUP3_Ev, GROUP3_OP_NOT, dst);
+ }
+#else
+ void orl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void subl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_SUB_EvGv, src, dst);
+ }
+
+ void subl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_SUB_GvEv, dst, base, offset);
+ }
+
+ void subl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_SUB_EvGv, src, base, offset);
+ }
+
+ void subl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void subl_im(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subl $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(4, base));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+#if WTF_CPU_X86_64
+ void subq_rr(RegisterID src, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_SUB_EvGv, src, dst);
+ }
+
+ void subq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+#else
+ void subl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void xorl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xorl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_XOR_EvGv, src, dst);
+ }
+
+ void xorl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_XOR_GvEv, dst, base, offset);
+ }
+
+ void xorl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_XOR_EvGv, src, base, offset);
+ }
+
+ void xorl_im(int imm, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void xorl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xorl %d, %s\n", MAYBE_PAD,
+ imm, nameIReg(4,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+#if WTF_CPU_X86_64
+ void xorq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xorq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8, dst));
+ m_formatter.oneByteOp64(OP_XOR_EvGv, src, dst);
+ }
+
+ void xorq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xorq %d, %s\n", MAYBE_PAD,
+ imm, nameIReg(8,dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void sarl_i8r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "sarl $%d, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
+ if (imm == 1)
+ m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
+ else {
+ m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+ void sarl_CLr(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "sarl %%cl, %s\n", MAYBE_PAD, nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+ }
+
+ void shrl_i8r(int imm, RegisterID dst)
+ {
+ if (imm == 1)
+ m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
+ else {
+ m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+ void shrl_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst);
+ }
+
+ void shll_i8r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "shll $%d, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
+ if (imm == 1)
+ m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
+ else {
+ m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+ void shll_CLr(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "shll %%cl, %s\n", MAYBE_PAD, nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
+ }
+
+#if WTF_CPU_X86_64
+ void sarq_CLr(RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+ }
+
+ void sarq_i8r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "sarq $%d, %s\n", MAYBE_PAD, imm, nameIReg(8, dst));
+ if (imm == 1)
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
+ else {
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+ void shlq_i8r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "shlq $%d, %s\n", MAYBE_PAD, imm, nameIReg(8, dst));
+ if (imm == 1)
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
+ else {
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+#endif
+
+ void imull_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "imull %s, %s\n", MAYBE_PAD, nameIReg(4,src), nameIReg(4, dst));
+ m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src);
+ }
+
+ void imull_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset);
+ }
+
+ void imull_i32r(RegisterID src, int32_t value, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_IMUL_GvEvIz, dst, src);
+ m_formatter.immediate32(value);
+ }
+
+ void idivl_r(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "idivl %s\n", MAYBE_PAD,
+ nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst);
+ }
+
+ // Comparisons:
+
+ void cmpl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl %s, %s\n", MAYBE_PAD,
+ nameIReg(4, src), nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_CMP_EvGv, src, dst);
+ }
+
+ void cmpl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(4, src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_CMP_EvGv, src, base, offset);
+ }
+
+ void cmpl_mr(int offset, RegisterID base, RegisterID src)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(4, base), nameIReg(src));
+ m_formatter.oneByteOp(OP_CMP_GvEv, src, base, offset);
+ }
+
+ void cmpl_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void cmpl_ir_force32(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst);
+ m_formatter.immediate32(imm);
+ }
+
+ void cmpl_im(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(4,base));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void cmpb_im(int imm, int offset, RegisterID base)
+ {
+ m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void cmpb_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpl %d, %d(%s,%s,%d)\n", MAYBE_PAD,
+ imm, offset, nameIReg(4,base), nameIReg(4,index), scale);
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void cmpl_im_force32(int imm, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate32(imm);
+ }
+
+#if WTF_CPU_X86_64
+ void cmpq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpq %s, %s\n", MAYBE_PAD,
+ nameIReg(8, src), nameIReg(8, dst));
+ m_formatter.oneByteOp64(OP_CMP_EvGv, src, dst);
+ }
+
+ void cmpq_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpq %s, %d(%s)\n", MAYBE_PAD,
+ nameIReg(8, src), offset, nameIReg(8, base));
+ m_formatter.oneByteOp64(OP_CMP_EvGv, src, base, offset);
+ }
+
+ void cmpq_mr(int offset, RegisterID base, RegisterID src)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpq %d(%s), %s\n", MAYBE_PAD,
+ offset, nameIReg(8, base), nameIReg(8, src));
+ m_formatter.oneByteOp64(OP_CMP_GvEv, src, base, offset);
+ }
+
+ void cmpq_ir(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cmpq %d, %s\n", MAYBE_PAD,
+ imm, nameIReg(8, dst));
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void cmpq_im(int imm, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+
+ void cmpq_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+ }
+#else
+ void cmpl_rm(RegisterID reg, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_CMP_EvGv, reg, addr);
+ }
+
+ void cmpl_im(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, addr);
+ m_formatter.immediate32(imm);
+ }
+ }
+#endif
+
+ void cmpw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_CMP_EvGv, src, base, index, scale, offset);
+ }
+
+ void cmpw_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ FIXME_INSN_PRINTING;
+ if (CAN_SIGN_EXTEND_8_32(imm)) {
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ } else {
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset);
+ m_formatter.immediate16(imm);
+ }
+ }
+
+ void testl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_TEST_EvGv, src, dst);
+ }
+
+ void testl_i32r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testl $0x%x, %s\n", MAYBE_PAD,
+ imm, nameIReg(dst));
+ m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst);
+ m_formatter.immediate32(imm);
+ }
+
+ void testl_i32m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testl $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void testb_im(int imm, int offset, RegisterID base)
+ {
+ m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void testb_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+
+#if WTF_CPU_X86_64
+ void testq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_TEST_EvGv, src, dst);
+ }
+
+ void testq_i32r(int imm, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst);
+ m_formatter.immediate32(imm);
+ }
+
+ void testq_i32m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testq $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void testq_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+#endif
+
+ void testw_rr(RegisterID src, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_TEST_EvGv, src, dst);
+ }
+
+ void testb_i8r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "testb $0x%x, %s\n", MAYBE_PAD,
+ imm, nameIReg(1,dst));
+ m_formatter.oneByteOp8(OP_GROUP3_EbIb, GROUP3_OP_TEST, dst);
+ m_formatter.immediate8(imm);
+ }
+
+ void setCC_r(Condition cond, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "set%s %s\n", MAYBE_PAD,
+ nameCC(cond), nameIReg(1,dst));
+ m_formatter.twoByteOp8(setccOpcode(cond), (GroupOpcodeID)0, dst);
+ }
+
+ void sete_r(RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp8(setccOpcode(ConditionE), (GroupOpcodeID)0, dst);
+ }
+
+ void setz_r(RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ sete_r(dst);
+ }
+
+ void setne_r(RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp8(setccOpcode(ConditionNE), (GroupOpcodeID)0, dst);
+ }
+
+ void setnz_r(RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ setne_r(dst);
+ }
+
+ // Various move ops:
+
+ void cdq()
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cdq \n", MAYBE_PAD);
+ m_formatter.oneByteOp(OP_CDQ);
+ }
+
+ void xchgl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xchgl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_XCHG_EvGv, src, dst);
+ }
+
+#if WTF_CPU_X86_64
+ void xchgq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xchgq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_XCHG_EvGv, src, dst);
+ }
+#endif
+
+ void movl_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, dst);
+ }
+
+ void movw_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movw %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(2,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset);
+ }
+
+ void movl_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(4,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset);
+ }
+
+ void movl_rm_disp32(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp_disp32(OP_MOV_EvGv, src, base, offset);
+ }
+
+ void movw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movw %s, %d(%s,%s,%d)\n", MAYBE_PAD,
+ nameIReg(2, src), offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset);
+ }
+
+ void movl_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl %s, %d(%s,%s,%d)\n", MAYBE_PAD,
+ nameIReg(4, src), offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset);
+ }
+
+ void movl_mEAX(void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_MOV_EAXOv);
+#if WTF_CPU_X86_64
+ m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
+#else
+ m_formatter.immediate32(reinterpret_cast<int>(addr));
+#endif
+ }
+
+ void movl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, offset);
+ }
+
+ void movl_mr_disp32(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
+ }
+
+ void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(4, dst));
+ m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset);
+ }
+
+ void movl_i32r(int imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl $0x%x, %s\n", MAYBE_PAD,
+ imm, nameIReg(dst));
+ m_formatter.oneByteOp(OP_MOV_EAXIv, dst);
+ m_formatter.immediate32(imm);
+ }
+
+ void movb_i8m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movb $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void movb_i8m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movb $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD,
+ imm, offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, index, scale, offset);
+ m_formatter.immediate8(imm);
+ }
+
+ void movw_i16m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movw $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset);
+ m_formatter.immediate16(imm);
+ }
+
+ void movl_i32m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl $0x%x, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void movw_i16m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movw $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD,
+ imm, offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.prefix(PRE_OPERAND_SIZE);
+ m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
+ m_formatter.immediate16(imm);
+ }
+
+ void movl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD,
+ imm, offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void movl_EAXm(void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_MOV_OvEAX);
+#if WTF_CPU_X86_64
+ m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
+#else
+ m_formatter.immediate32(reinterpret_cast<int>(addr));
+#endif
+ }
+
+#if WTF_CPU_X86_64
+ void movq_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s, %s\n", MAYBE_PAD,
+ nameIReg(8,src), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_MOV_EvGv, src, dst);
+ }
+
+ void movq_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(8,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, offset);
+ }
+
+ void movq_rm_disp32(RegisterID src, int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64_disp32(OP_MOV_EvGv, src, base, offset);
+ }
+
+ void movq_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(8,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset);
+ }
+
+ void movq_mEAX(void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_MOV_EAXOv);
+ m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
+ }
+
+ void movq_EAXm(void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64(OP_MOV_OvEAX);
+ m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
+ }
+
+ void movq_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, offset);
+ }
+
+ void movq_mr_disp32(int offset, RegisterID base, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, dst, base, offset);
+ }
+
+ void movq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset);
+ }
+
+ void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "leaq %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(8,dst)),
+ m_formatter.oneByteOp64(OP_LEA, dst, base, index, scale, offset);
+ }
+
+ void movq_i32m(int imm, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq $%d, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void movq_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq $%d, %s0x%x(%s)\n", MAYBE_PAD,
+ imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
+ m_formatter.immediate32(imm);
+ }
+
+ void movq_i64r(int64_t imm, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movabsq $0x%llx, %s\n", MAYBE_PAD,
+ (unsigned long long int)imm, nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_MOV_EAXIv, dst);
+ m_formatter.immediate64(imm);
+ }
+
+ void movsxd_rr(RegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsxd %s, %s\n", MAYBE_PAD,
+ nameIReg(4, src), nameIReg(8, dst));
+ m_formatter.oneByteOp64(OP_MOVSXD_GvEv, dst, src);
+ }
+
+
+#else
+ void movl_rm(RegisterID src, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ if (src == X86Registers::eax)
+ movl_EAXm(addr);
+ else
+ m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
+ }
+
+ void movl_mr(void* addr, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movl 0(%p), %s\n", MAYBE_PAD,
+ addr, nameIReg(4, dst));
+ if (dst == X86Registers::eax)
+ movl_mEAX(addr);
+ else
+ m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
+ }
+
+ void movl_i32m(int imm, void* addr)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr);
+ m_formatter.immediate32(imm);
+ }
+#endif
+
+ void movb_rm(RegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movb %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameIReg(1, src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.oneByteOp8(OP_MOV_EbGv, src, base, offset);
+ }
+
+ void movb_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movb %s, %d(%s,%s,%d)\n", MAYBE_PAD,
+ nameIReg(1, src), offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.oneByteOp8(OP_MOV_EbGv, src, base, index, scale, offset);
+ }
+
+ void movzbl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movzbl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst));
+ m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, offset);
+ }
+
+ void movzbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movzbl %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst));
+ m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, index, scale, offset);
+ }
+
+ void movxbl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movxbl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst));
+ m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, offset);
+ }
+
+ void movxbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movxbl %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst));
+ m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, index, scale, offset);
+ }
+
+ void movzwl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movzwl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst));
+ m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, offset);
+ }
+
+ void movzwl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movzwl %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst));
+ m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, index, scale, offset);
+ }
+
+ void movxwl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movxwl %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst));
+ m_formatter.twoByteOp(OP2_MOVSX_GvEw, dst, base, offset);
+ }
+
+ void movxwl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movxwl %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst));
+ m_formatter.twoByteOp(OP2_MOVSX_GvEw, dst, base, index, scale, offset);
+ }
+
+ void movzbl_rr(RegisterID src, RegisterID dst)
+ {
+ // In 64-bit, this may cause an unnecessary REX to be planted (if the dst register
+ // is in the range ESP-EDI, and the src would not have required a REX). Unneeded
+ // REX prefixes are defined to be silently ignored by the processor.
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movzbl %s, %s\n", MAYBE_PAD,
+ nameIReg(4,src), nameIReg(4,dst));
+ m_formatter.twoByteOp8(OP2_MOVZX_GvEb, dst, src);
+ }
+
+ void leal_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "leal %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst));
+ m_formatter.oneByteOp(OP_LEA, dst, base, index, scale, offset);
+ }
+
+ void leal_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "leal %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4,dst));
+ m_formatter.oneByteOp(OP_LEA, dst, base, offset);
+ }
+#if WTF_CPU_X86_64
+ void leaq_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "leaq %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
+ m_formatter.oneByteOp64(OP_LEA, dst, base, offset);
+ }
+#endif
+
+ // Flow control:
+
+ JmpSrc call()
+ {
+ m_formatter.oneByteOp(OP_CALL_rel32);
+ JmpSrc r = m_formatter.immediateRel32();
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "call ((%d))\n", MAYBE_PAD, r.m_offset);
+ return r;
+ }
+
+ JmpSrc call(RegisterID dst)
+ {
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst);
+ JmpSrc r = JmpSrc(m_formatter.size());
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "call *%s\n", MAYBE_PAD, nameIReg(dst));
+ return r;
+ }
+
+ void call_m(int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset);
+ }
+
+ JmpSrc jmp()
+ {
+ m_formatter.oneByteOp(OP_JMP_rel32);
+ JmpSrc r = m_formatter.immediateRel32();
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "jmp ((%d))\n", MAYBE_PAD, r.m_offset);
+ return r;
+ }
+
+ // Return a JmpSrc so we have a label to the jump, so we can use this
+ // To make a tail recursive call on x86-64. The MacroAssembler
+ // really shouldn't wrap this as a Jump, since it can't be linked. :-/
+ JmpSrc jmp_r(RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "jmp ((%s))\n", MAYBE_PAD,
+ nameIReg(dst));
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, dst);
+ return JmpSrc(m_formatter.size());
+ }
+
+ void jmp_m(int offset, RegisterID base)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, offset);
+ }
+
+ void jmp_m(int offset, RegisterID base, RegisterID index, int scale) {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "jmp ((%d(%s,%s,%d)))\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, index, scale, offset);
+ }
+
+ JmpSrc jne()
+ {
+ return jCC(ConditionNE);
+ }
+
+ JmpSrc jnz()
+ {
+ // printing done by jne()
+ return jne();
+ }
+
+ JmpSrc je()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionE));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jz()
+ {
+ // printing done by je()
+ return je();
+ }
+
+ JmpSrc jl()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionL));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jb()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionB));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jle()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionLE));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jbe()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionBE));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jge()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionGE));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jg()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionG));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc ja()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionA));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jae()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionAE));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jo()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionO));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jp()
+ {
+ return jCC(ConditionP);
+ }
+
+ JmpSrc js()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.twoByteOp(jccRel32(ConditionS));
+ return m_formatter.immediateRel32();
+ }
+
+ JmpSrc jCC(Condition cond)
+ {
+ m_formatter.twoByteOp(jccRel32(cond));
+ JmpSrc r = m_formatter.immediateRel32();
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "j%s ((%d))\n", MAYBE_PAD,
+ nameCC(cond), r.m_offset);
+ return r;
+ }
+
+ // SSE operations:
+
+ void addsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void addsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "addsd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void cvtss2sd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtps2pd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F3);
+ m_formatter.twoByteOp(OP2_CVTSS2SD_VsdEd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void cvtsd2ss_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtps2pd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_CVTSD2SS_VsdEd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void cvtsi2sd_rr(RegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtsi2sd %s, %s\n", MAYBE_PAD,
+ nameIReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
+ }
+
+#if WTF_CPU_X86_64
+ void cvtsq2sd_rr(RegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtsq2sd %s, %s\n", MAYBE_PAD,
+ nameIReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp64(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
+ }
+#endif
+
+ void cvtsi2sd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtsi2sd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, base, offset);
+ }
+
+#if !WTF_CPU_X86_64
+ void cvtsi2sd_mr(void* address, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvtsi2sd %p, %s\n", MAYBE_PAD,
+ address, nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, address);
+ }
+#endif
+
+ void cvttsd2si_rr(XMMRegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "cvttsd2si %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameIReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src);
+ }
+
+ void unpcklps_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "unpcklps %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.twoByteOp(OP2_UNPCKLPS_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void movd_rr(RegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movd %s, %s\n", MAYBE_PAD,
+ nameIReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_MOVD_VdEd, (RegisterID)dst, src);
+ }
+
+ void psrldq_rr(XMMRegisterID dest, int shift)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "pslldq %s, %d\n", MAYBE_PAD,
+ nameFPReg(dest), shift);
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)3, (RegisterID)dest);
+ m_formatter.immediate8(shift);
+ }
+
+ void movd_rr(XMMRegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameIReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_MOVD_EdVd, (RegisterID)src, dst);
+ }
+
+#if WTF_CPU_X86_64
+ void movq_rr(XMMRegisterID src, RegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameIReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp64(OP2_MOVD_EdVd, (RegisterID)src, dst);
+ }
+
+ void movq_rr(RegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movq %s, %s\n", MAYBE_PAD,
+ nameIReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp64(OP2_MOVD_VdEd, (RegisterID)dst, src);
+ }
+#endif
+
+ void movsd_rm(XMMRegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameFPReg(src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset);
+ }
+
+ void movss_rm(XMMRegisterID src, int offset, RegisterID base)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movss %s, %s0x%x(%s)\n", MAYBE_PAD,
+ nameFPReg(src), PRETTY_PRINT_OFFSET(offset), nameIReg(base));
+ m_formatter.prefix(PRE_SSE_F3);
+ m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset);
+ }
+
+ void movss_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movss %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F3);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void movsd_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %s, %d(%s,%s,%d)\n", MAYBE_PAD,
+ nameFPReg(src), offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset);
+ }
+
+ void movss_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movss %s, %d(%s,%s,%d)\n", MAYBE_PAD,
+ nameFPReg(src), offset, nameIReg(base), nameIReg(index), scale);
+ m_formatter.prefix(PRE_SSE_F3);
+ m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset);
+ }
+
+ void movss_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movss %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F3);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, index, scale, offset);
+ }
+
+ void movsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void movsd_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %d(%s,%s,%d), %s\n", MAYBE_PAD,
+ offset, nameIReg(base), nameIReg(index), scale, nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, index, scale, offset);
+ }
+
+ void movsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+#if !WTF_CPU_X86_64
+ void movsd_mr(const void* address, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "movsd %p, %s\n", MAYBE_PAD,
+ address, nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, address);
+ }
+#endif
+
+ void mulsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "mulsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void mulsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "mulsd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst)
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_PEXTRW_GdUdIb, (RegisterID)dst, (RegisterID)src);
+ m_formatter.immediate8(whichWord);
+ }
+
+ void subsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void subsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "subsd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void ucomisd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "ucomisd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void ucomisd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "ucomisd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void divsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "divsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void divsd_mr(int offset, RegisterID base, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "divsd %s0x%x(%s), %s\n", MAYBE_PAD,
+ PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, base, offset);
+ }
+
+ void xorpd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "xorpd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void sqrtsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "sqrtsd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_SQRTSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
+ void pinsrd_rr(RegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "pinsrd $1, %s, %s\n", MAYBE_PAD,
+ nameIReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.threeByteOp(OP3_PINSRD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ m_formatter.immediate8(0x01); // the $1
+ }
+
+ // Misc instructions:
+
+ void int3()
+ {
+ js::JaegerSpew(js::JSpew_Insns, IPFX "int3\n", MAYBE_PAD);
+ m_formatter.oneByteOp(OP_INT3);
+ }
+
+ void ret()
+ {
+ js::JaegerSpew(js::JSpew_Insns, IPFX "ret\n", MAYBE_PAD);
+ m_formatter.oneByteOp(OP_RET);
+ }
+
+ void predictNotTaken()
+ {
+ FIXME_INSN_PRINTING;
+ m_formatter.prefix(PRE_PREDICT_BRANCH_NOT_TAKEN);
+ }
+
+#if WTF_CPU_X86
+ void pusha()
+ {
+ js::JaegerSpew(js::JSpew_Insns, IPFX "pusha\n", MAYBE_PAD);
+ m_formatter.oneByteOp(OP_PUSHA);
+ }
+
+ void popa()
+ {
+ js::JaegerSpew(js::JSpew_Insns, IPFX "popa\n", MAYBE_PAD);
+ m_formatter.oneByteOp(OP_POPA);
+ }
+#endif
+
+ // Assembler admin methods:
+
+ JmpDst label()
+ {
+ JmpDst r = JmpDst(m_formatter.size());
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "#label ((%d))\n", MAYBE_PAD, r.m_offset);
+ return r;
+ }
+
+ static JmpDst labelFor(JmpSrc jump, intptr_t offset = 0)
+ {
+ FIXME_INSN_PRINTING;
+ return JmpDst(jump.m_offset + offset);
+ }
+
+ JmpDst align(int alignment)
+ {
+ FIXME_INSN_PRINTING;
+ while (!m_formatter.isAligned(alignment))
+ m_formatter.oneByteOp(OP_HLT);
+
+ return label();
+ }
+
+ // Linking & patching:
+ //
+ // 'link' and 'patch' methods are for use on unprotected code - such as the code
+ // within the AssemblerBuffer, and code being patched by the patch buffer. Once
+ // code has been finalized it is (platform support permitting) within a non-
+ // writable region of memory; to modify the code in an execute-only execuable
+ // pool the 'repatch' and 'relink' methods should be used.
+
+ void linkJump(JmpSrc from, JmpDst to)
+ {
+ ASSERT(from.m_offset != -1);
+ ASSERT(to.m_offset != -1);
+
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "##link ((%d)) jumps to ((%d))\n", MAYBE_PAD,
+ from.m_offset, to.m_offset);
+ char* code = reinterpret_cast<char*>(m_formatter.data());
+ setRel32(code + from.m_offset, code + to.m_offset);
+ }
+
+ static void linkJump(void* code, JmpSrc from, void* to)
+ {
+ ASSERT(from.m_offset != -1);
+
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##link ((%d)) jumps to ((%p))\n",
+ from.m_offset, to);
+ setRel32(reinterpret_cast<char*>(code) + from.m_offset, to);
+ }
+
+ static void linkCall(void* code, JmpSrc from, void* to)
+ {
+ ASSERT(from.m_offset != -1);
+
+ FIXME_INSN_PRINTING;
+ setRel32(reinterpret_cast<char*>(code) + from.m_offset, to);
+ }
+
+ static void linkPointer(void* code, JmpDst where, void* value)
+ {
+ ASSERT(where.m_offset != -1);
+
+ FIXME_INSN_PRINTING;
+ setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
+ }
+
+ static void relinkJump(void* from, void* to)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##relinkJump ((from=%p)) ((to=%p))\n",
+ from, to);
+ setRel32(from, to);
+ }
+
+ static bool canRelinkJump(void* from, void* to)
+ {
+ intptr_t offset = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
+ return (offset == static_cast<int32_t>(offset));
+ }
+
+ static void relinkCall(void* from, void* to)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##relinkCall ((from=%p)) ((to=%p))\n",
+ from, to);
+ setRel32(from, to);
+ }
+
+ static void repatchInt32(void* where, int32_t value)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##relinkInt32 ((where=%p)) ((value=%d))\n",
+ where, value);
+ setInt32(where, value);
+ }
+
+ static void repatchPointer(void* where, void* value)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##repatchPtr ((where=%p)) ((value=%p))\n",
+ where, value);
+ setPointer(where, value);
+ }
+
+ static void repatchLoadPtrToLEA(void* where)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##repatchLoadPtrToLEA ((where=%p))\n",
+ where);
+
+#if WTF_CPU_X86_64
+ // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix.
+ // Skip over the prefix byte.
+ where = reinterpret_cast<char*>(where) + 1;
+#endif
+ *reinterpret_cast<unsigned char*>(where) = static_cast<unsigned char>(OP_LEA);
+ }
+
+ static void repatchLEAToLoadPtr(void* where)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##repatchLEAToLoadPtr ((where=%p))\n",
+ where);
+#if WTF_CPU_X86_64
+ // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix.
+ // Skip over the prefix byte.
+ where = reinterpret_cast<char*>(where) + 1;
+#endif
+ *reinterpret_cast<unsigned char*>(where) = static_cast<unsigned char>(OP_MOV_GvEv);
+ }
+
+ static unsigned getCallReturnOffset(JmpSrc call)
+ {
+ ASSERT(call.m_offset >= 0);
+ return call.m_offset;
+ }
+
+ static void* getRelocatedAddress(void* code, JmpSrc jump)
+ {
+ ASSERT(jump.m_offset != -1);
+
+ return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
+ }
+
+ static void* getRelocatedAddress(void* code, JmpDst destination)
+ {
+ ASSERT(destination.m_offset != -1);
+
+ return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
+ }
+
+ static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
+ {
+ return dst.m_offset - src.m_offset;
+ }
+
+ static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
+ {
+ return dst.m_offset - src.m_offset;
+ }
+
+ static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
+ {
+ return dst.m_offset - src.m_offset;
+ }
+
+ void* executableCopy(ExecutablePool* allocator)
+ {
+ void* copy = m_formatter.executableCopy(allocator);
+ return copy;
+ }
+
+ void* executableCopy(void* buffer)
+ {
+ if (m_formatter.oom())
+ return NULL;
+ return memcpy(buffer, m_formatter.buffer(), size());
+ }
+
+private:
+
+ static void setPointer(void* where, void* value)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##setPtr ((where=%p)) ((value=%p))\n", where, value);
+ reinterpret_cast<void**>(where)[-1] = value;
+ }
+
+ static void setInt32(void* where, int32_t value)
+ {
+ reinterpret_cast<int32_t*>(where)[-1] = value;
+ }
+
+ static void setRel32(void* from, void* to)
+ {
+ intptr_t offset = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
+ ASSERT(offset == static_cast<int32_t>(offset));
+#define JS_CRASH(x) *(int *)x = 0
+ if (offset != static_cast<int32_t>(offset))
+ JS_CRASH(0xC0DE);
+#undef JS_CRASH
+
+ js::JaegerSpew(js::JSpew_Insns,
+ ISPFX "##setRel32 ((from=%p)) ((to=%p))\n", from, to);
+ setInt32(from, offset);
+ }
+
+ class X86InstructionFormatter {
+
+ static const int maxInstructionSize = 16;
+
+ public:
+
+ // Legacy prefix bytes:
+ //
+ // These are emmitted prior to the instruction.
+
+ void prefix(OneByteOpcodeID pre)
+ {
+ m_buffer.putByte(pre);
+ }
+
+ // Word-sized operands / no operand instruction formatters.
+ //
+ // In addition to the opcode, the following operand permutations are supported:
+ // * None - instruction takes no operands.
+ // * One register - the low three bits of the RegisterID are added into the opcode.
+ // * Two registers - encode a register form ModRm (for all ModRm formats, the reg field is passed first, and a GroupOpcodeID may be passed in its place).
+ // * Three argument ModRM - a register, and a register and an offset describing a memory operand.
+ // * Five argument ModRM - a register, and a base register, an index, scale, and offset describing a memory operand.
+ //
+ // For 32-bit x86 targets, the address operand may also be provided as a void*.
+ // On 64-bit targets REX prefixes will be planted as necessary, where high numbered registers are used.
+ //
+ // The twoByteOp methods plant two-byte Intel instructions sequences (first opcode byte 0x0F).
+
+ void oneByteOp(OneByteOpcodeID opcode)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ m_buffer.putByteUnchecked(opcode);
+ }
+
+ void oneByteOp(OneByteOpcodeID opcode, RegisterID reg)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(0, 0, reg);
+ m_buffer.putByteUnchecked(opcode + (reg & 7));
+ }
+
+ void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, rm);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+ void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, offset);
+ }
+
+ void oneByteOp_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM_disp32(reg, base, offset);
+ }
+
+ void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, index, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, index, scale, offset);
+ }
+
+#if !WTF_CPU_X86_64
+ void oneByteOp(OneByteOpcodeID opcode, int reg, void* address)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, address);
+ }
+#endif
+
+ void twoByteOp(TwoByteOpcodeID opcode)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ }
+
+ void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+ void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, base);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, offset);
+ }
+
+ void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, index, base);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, index, scale, offset);
+ }
+
+#if !WTF_CPU_X86_64
+ void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, address);
+ }
+#endif
+
+ void threeByteOp(ThreeByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(OP_3BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+#if WTF_CPU_X86_64
+ // Quad-word-sized operands:
+ //
+ // Used to format 64-bit operantions, planting a REX.w prefix.
+ // When planting d64 or f64 instructions, not requiring a REX.w prefix,
+ // the normal (non-'64'-postfixed) formatters should be used.
+
+ void oneByteOp64(OneByteOpcodeID opcode)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(0, 0, 0);
+ m_buffer.putByteUnchecked(opcode);
+ }
+
+ void oneByteOp64(OneByteOpcodeID opcode, RegisterID reg)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(0, 0, reg);
+ m_buffer.putByteUnchecked(opcode + (reg & 7));
+ }
+
+ void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, 0, rm);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+ void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, offset);
+ }
+
+ void oneByteOp64_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM_disp32(reg, base, offset);
+ }
+
+ void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, index, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, index, scale, offset);
+ }
+
+ void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+#endif
+
+ // Byte-operands:
+ //
+ // These methods format byte operations. Byte operations differ from the normal
+ // formatters in the circumstances under which they will decide to emit REX prefixes.
+ // These should be used where any register operand signifies a byte register.
+ //
+ // The disctinction is due to the handling of register numbers in the range 4..7 on
+ // x86-64. These register numbers may either represent the second byte of the first
+ // four registers (ah..bh) or the first byte of the second four registers (spl..dil).
+ //
+ // Since ah..bh cannot be used in all permutations of operands (specifically cannot
+ // be accessed where a REX prefix is present), these are likely best treated as
+ // deprecated. In order to ensure the correct registers spl..dil are selected a
+ // REX prefix will be emitted for any byte register operand in the range 4..15.
+ //
+ // These formatters may be used in instructions where a mix of operand sizes, in which
+ // case an unnecessary REX will be emitted, for example:
+ // movzbl %al, %edi
+ // In this case a REX will be planted since edi is 7 (and were this a byte operand
+ // a REX would be required to specify dil instead of bh). Unneeded REX prefixes will
+ // be silently ignored by the processor.
+ //
+ // Address operands should still be checked using regRequiresRex(), while byteRegRequiresRex()
+ // is provided to check byte register operands.
+
+ void oneByteOp8(OneByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm)
+ {
+#if !WTF_CPU_X86_64
+ ASSERT(!byteRegRequiresRex(rm));
+#endif
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIf(byteRegRequiresRex(rm), 0, 0, rm);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(groupOp, rm);
+ }
+
+ void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+#if !WTF_CPU_X86_64
+ ASSERT(!byteRegRequiresRex(reg));
+#endif
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIf(byteRegRequiresRex(reg), reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, offset);
+ }
+
+ void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
+ {
+#if !WTF_CPU_X86_64
+ ASSERT(!byteRegRequiresRex(reg));
+#endif
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIf(byteRegRequiresRex(reg), reg, index, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, index, scale, offset);
+ }
+
+ void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+ void twoByteOp8(TwoByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIf(byteRegRequiresRex(rm), 0, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(groupOp, rm);
+ }
+
+ // Immediates:
+ //
+ // An immedaite should be appended where appropriate after an op has been emitted.
+ // The writes are unchecked since the opcode formatters above will have ensured space.
+
+ void immediate8(int imm)
+ {
+ m_buffer.putByteUnchecked(imm);
+ }
+
+ void immediate16(int imm)
+ {
+ m_buffer.putShortUnchecked(imm);
+ }
+
+ void immediate32(int imm)
+ {
+ m_buffer.putIntUnchecked(imm);
+ }
+
+ void immediate64(int64_t imm)
+ {
+ m_buffer.putInt64Unchecked(imm);
+ }
+
+ JmpSrc immediateRel32()
+ {
+ m_buffer.putIntUnchecked(0);
+ return JmpSrc(m_buffer.size());
+ }
+
+ // Administrative methods:
+
+ size_t size() const { return m_buffer.size(); }
+ unsigned char *buffer() const { return m_buffer.buffer(); }
+ bool oom() const { return m_buffer.oom(); }
+ bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
+ void* data() const { return m_buffer.data(); }
+ void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
+
+ private:
+
+ // Internals; ModRm and REX formatters.
+
+ // Byte operand register spl & above require a REX prefix (to prevent the 'H' registers be accessed).
+ inline bool byteRegRequiresRex(int reg)
+ {
+ return (reg >= X86Registers::esp);
+ }
+
+ static const RegisterID noBase = X86Registers::ebp;
+ static const RegisterID hasSib = X86Registers::esp;
+ static const RegisterID noIndex = X86Registers::esp;
+#if WTF_CPU_X86_64
+ static const RegisterID noBase2 = X86Registers::r13;
+ static const RegisterID hasSib2 = X86Registers::r12;
+
+ // Registers r8 & above require a REX prefixe.
+ inline bool regRequiresRex(int reg)
+ {
+ return (reg >= X86Registers::r8);
+ }
+
+ // Format a REX prefix byte.
+ inline void emitRex(bool w, int r, int x, int b)
+ {
+ m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3));
+ }
+
+ // Used to plant a REX byte with REX.w set (for 64-bit operations).
+ inline void emitRexW(int r, int x, int b)
+ {
+ emitRex(true, r, x, b);
+ }
+
+ // Used for operations with byte operands - use byteRegRequiresRex() to check register operands,
+ // regRequiresRex() to check other registers (i.e. address base & index).
+ //
+ // NB: WebKit's use of emitRexIf() is limited such that the reqRequiresRex() checks are
+ // not needed. SpiderMonkey extends oneByteOp8 functionality such that r, x, and b can
+ // all be used.
+ inline void emitRexIf(bool condition, int r, int x, int b)
+ {
+ if (condition || regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b))
+ emitRex(false, r, x, b);
+ }
+
+ // Used for word sized operations, will plant a REX prefix if necessary (if any register is r8 or above).
+ inline void emitRexIfNeeded(int r, int x, int b)
+ {
+ emitRexIf(regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b), r, x, b);
+ }
+#else
+ // No REX prefix bytes on 32-bit x86.
+ inline bool regRequiresRex(int) { return false; }
+ inline void emitRexIf(bool, int, int, int) {}
+ inline void emitRexIfNeeded(int, int, int) {}
+#endif
+
+ enum ModRmMode {
+ ModRmMemoryNoDisp,
+ ModRmMemoryDisp8,
+ ModRmMemoryDisp32,
+ ModRmRegister
+ };
+
+ void putModRm(ModRmMode mode, int reg, RegisterID rm)
+ {
+ m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7));
+ }
+
+ void putModRmSib(ModRmMode mode, int reg, RegisterID base, RegisterID index, int scale)
+ {
+ ASSERT(mode != ModRmRegister);
+
+ putModRm(mode, reg, hasSib);
+ m_buffer.putByteUnchecked((scale << 6) | ((index & 7) << 3) | (base & 7));
+ }
+
+ void registerModRM(int reg, RegisterID rm)
+ {
+ putModRm(ModRmRegister, reg, rm);
+ }
+
+ void memoryModRM(int reg, RegisterID base, int offset)
+ {
+ // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.
+#if WTF_CPU_X86_64
+ if ((base == hasSib) || (base == hasSib2)) {
+#else
+ if (base == hasSib) {
+#endif
+ if (!offset) // No need to check if the base is noBase, since we know it is hasSib!
+ putModRmSib(ModRmMemoryNoDisp, reg, base, noIndex, 0);
+ else if (CAN_SIGN_EXTEND_8_32(offset)) {
+ putModRmSib(ModRmMemoryDisp8, reg, base, noIndex, 0);
+ m_buffer.putByteUnchecked(offset);
+ } else {
+ putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0);
+ m_buffer.putIntUnchecked(offset);
+ }
+ } else {
+#if WTF_CPU_X86_64
+ if (!offset && (base != noBase) && (base != noBase2))
+#else
+ if (!offset && (base != noBase))
+#endif
+ putModRm(ModRmMemoryNoDisp, reg, base);
+ else if (CAN_SIGN_EXTEND_8_32(offset)) {
+ putModRm(ModRmMemoryDisp8, reg, base);
+ m_buffer.putByteUnchecked(offset);
+ } else {
+ putModRm(ModRmMemoryDisp32, reg, base);
+ m_buffer.putIntUnchecked(offset);
+ }
+ }
+ }
+
+ void memoryModRM_disp32(int reg, RegisterID base, int offset)
+ {
+ // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.
+#if WTF_CPU_X86_64
+ if ((base == hasSib) || (base == hasSib2)) {
+#else
+ if (base == hasSib) {
+#endif
+ putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0);
+ m_buffer.putIntUnchecked(offset);
+ } else {
+ putModRm(ModRmMemoryDisp32, reg, base);
+ m_buffer.putIntUnchecked(offset);
+ }
+ }
+
+ void memoryModRM(int reg, RegisterID base, RegisterID index, int scale, int offset)
+ {
+ ASSERT(index != noIndex);
+
+#if WTF_CPU_X86_64
+ if (!offset && (base != noBase) && (base != noBase2))
+#else
+ if (!offset && (base != noBase))
+#endif
+ putModRmSib(ModRmMemoryNoDisp, reg, base, index, scale);
+ else if (CAN_SIGN_EXTEND_8_32(offset)) {
+ putModRmSib(ModRmMemoryDisp8, reg, base, index, scale);
+ m_buffer.putByteUnchecked(offset);
+ } else {
+ putModRmSib(ModRmMemoryDisp32, reg, base, index, scale);
+ m_buffer.putIntUnchecked(offset);
+ }
+ }
+
+#if !WTF_CPU_X86_64
+ void memoryModRM(int reg, const void* address)
+ {
+ // noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32!
+ putModRm(ModRmMemoryNoDisp, reg, noBase);
+ m_buffer.putIntUnchecked(reinterpret_cast<int32_t>(address));
+ }
+#endif
+
+ AssemblerBuffer m_buffer;
+ } m_formatter;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER) && CPU(X86)
+
+#endif // X86Assembler_h