From 9057901f9525a92ca4f87fd5b345d85a0b227d12 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 30 Jan 2015 16:32:26 -0800 Subject: [PATCH] Bug 1125236 - SpiderMonkey: Implement a minimal x86 disassembler r=jandem --- js/src/jit/Disassembler.cpp | 64 +++ js/src/jit/Disassembler.h | 254 +++++++++ js/src/jit/shared/Disassembler-x86-shared.cpp | 525 ++++++++++++++++++ js/src/moz.build | 2 + 4 files changed, 845 insertions(+) create mode 100644 js/src/jit/Disassembler.cpp create mode 100644 js/src/jit/Disassembler.h create mode 100644 js/src/jit/shared/Disassembler-x86-shared.cpp diff --git a/js/src/jit/Disassembler.cpp b/js/src/jit/Disassembler.cpp new file mode 100644 index 000000000000..433803e82930 --- /dev/null +++ b/js/src/jit/Disassembler.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/Disassembler.h" + +using namespace js; +using namespace js::jit; +using namespace js::jit::Disassembler; + +#ifdef DEBUG +bool +Disassembler::ComplexAddress::operator==(const ComplexAddress &other) const +{ + return base_ == other.base_ && + index_ == other.index_ && + scale_ == other.scale_ && + disp_ == other.disp_ && + isPCRelative_ == other.isPCRelative_; +} + +bool +Disassembler::ComplexAddress::operator!=(const ComplexAddress &other) const +{ + return !operator==(other); +} + +bool +Disassembler::OtherOperand::operator==(const OtherOperand &other) const +{ + if (kind_ != other.kind_) + return false; + switch (kind_) { + case Imm: return u_.imm == other.u_.imm; + case GPR: return u_.gpr == other.u_.gpr; + case FPR: return u_.fpr == other.u_.fpr; + } + MOZ_CRASH("Unexpected OtherOperand kind"); +} + +bool +Disassembler::OtherOperand::operator!=(const OtherOperand &other) const +{ + return !operator==(other); +} + +bool +Disassembler::HeapAccess::operator==(const HeapAccess &other) const +{ + return kind_ == other.kind_ && + size_ == other.size_ && + address_ == other.address_ && + otherOperand_ == other.otherOperand_; +} + +bool +Disassembler::HeapAccess::operator!=(const HeapAccess &other) const +{ + return !operator==(other); +} + +#endif diff --git a/js/src/jit/Disassembler.h b/js/src/jit/Disassembler.h new file mode 100644 index 000000000000..df7ffa7c278b --- /dev/null +++ b/js/src/jit/Disassembler.h @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_Disassembler_h +#define jit_Disassembler_h + +#include "jit/Registers.h" + +namespace js { +namespace jit { + +namespace Disassembler { + +class ComplexAddress { + int32_t disp_; + Register::Code base_ : 8; + Register::Code index_ : 8; + int8_t scale_; // log2 encoding + bool isPCRelative_; + + public: + ComplexAddress() + : disp_(0), + base_(Registers::Invalid), + index_(Registers::Invalid), + scale_(0), + isPCRelative_(false) + { + MOZ_ASSERT(*this == *this); + } + + ComplexAddress(int32_t disp, Register::Code base) + : disp_(disp), + base_(base), + index_(Registers::Invalid), + scale_(0), + isPCRelative_(false) + { + MOZ_ASSERT(*this == *this); + MOZ_ASSERT(base != Registers::Invalid); + MOZ_ASSERT(base_ == base); + } + + ComplexAddress(int32_t disp, Register::Code base, Register::Code index, int scale) + : disp_(disp), + base_(base), + index_(index), + scale_(scale), + isPCRelative_(false) + { + MOZ_ASSERT(scale >= 0 && scale < 4); + MOZ_ASSERT_IF(index == Registers::Invalid, scale == 0); + MOZ_ASSERT(*this == *this); + MOZ_ASSERT(base_ == base); + MOZ_ASSERT(index_ == index); + } + + explicit ComplexAddress(const void *addr) + : disp_(static_cast(reinterpret_cast(addr))), + base_(Registers::Invalid), + index_(Registers::Invalid), + scale_(0), + isPCRelative_(false) + { + MOZ_ASSERT(*this == *this); + MOZ_ASSERT(reinterpret_cast(uintptr_t(disp_)) == addr); + } + + explicit ComplexAddress(const Operand &op) { +#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) + switch (op.kind()) { + case Operand::MEM_REG_DISP: + *this = ComplexAddress(op.disp(), op.base()); + return; + case Operand::MEM_SCALE: + *this = ComplexAddress(op.disp(), op.base(), op.index(), op.scale()); + return; + default: + break; + } +#endif + MOZ_CRASH("Unexpected Operand kind"); + } + + bool isPCRelative() const { + return isPCRelative_; + } + + int32_t disp() const { + return disp_; + } + + Register::Code base() const { + return base_; + } + + Register::Code index() const { + return index_; + } + + uint32_t scale() const { + return scale_; + } + +#ifdef DEBUG + bool operator==(const ComplexAddress &other) const; + bool operator!=(const ComplexAddress &other) const; +#endif +}; + +// An operand other than a memory operand -- a register or an immediate. +class OtherOperand { + public: + enum Kind { + Imm, + GPR, + FPR, + }; + + private: + Kind kind_; + union { + int32_t imm; + Register::Code gpr; + FloatRegister::Code fpr; + } u_; + + public: + OtherOperand() + : kind_(Imm) + { + u_.imm = 0; + MOZ_ASSERT(*this == *this); + } + + explicit OtherOperand(int32_t imm) + : kind_(Imm) + { + u_.imm = imm; + MOZ_ASSERT(*this == *this); + } + + explicit OtherOperand(Register::Code gpr) + : kind_(GPR) + { + u_.gpr = gpr; + MOZ_ASSERT(*this == *this); + } + + explicit OtherOperand(FloatRegister::Code fpr) + : kind_(FPR) + { + u_.fpr = fpr; + MOZ_ASSERT(*this == *this); + } + + Kind kind() const { + return kind_; + } + + int32_t imm() const { + MOZ_ASSERT(kind_ == Imm); + return u_.imm; + } + + Register::Code gpr() const { + MOZ_ASSERT(kind_ == GPR); + return u_.gpr; + } + + FloatRegister::Code fpr() const { + MOZ_ASSERT(kind_ == FPR); + return u_.fpr; + } + +#ifdef DEBUG + bool operator==(const OtherOperand &other) const; + bool operator!=(const OtherOperand &other) const; +#endif +}; + +class HeapAccess { + public: + enum Kind { + Unknown, + Load, // any bits not covered by the load are zeroed + LoadSext32, // like Load, but sign-extend to 32 bits + Store + }; + + private: + Kind kind_; + size_t size_; // The number of bytes of memory accessed + ComplexAddress address_; + OtherOperand otherOperand_; + + public: + HeapAccess() + : kind_(Unknown), + size_(0) + { + MOZ_ASSERT(*this == *this); + } + + HeapAccess(Kind kind, size_t size, const ComplexAddress &address, const OtherOperand &otherOperand) + : kind_(kind), + size_(size), + address_(address), + otherOperand_(otherOperand) + { + MOZ_ASSERT(kind != Unknown); + MOZ_ASSERT_IF(kind == LoadSext32, otherOperand.kind() != OtherOperand::FPR); + MOZ_ASSERT_IF(kind == Load || kind == LoadSext32, otherOperand.kind() != OtherOperand::Imm); + MOZ_ASSERT(*this == *this); + } + + Kind kind() const { + return kind_; + } + + size_t size() const { + MOZ_ASSERT(kind_ != Unknown); + return size_; + } + + const ComplexAddress &address() const { + return address_; + } + + const OtherOperand &otherOperand() const { + return otherOperand_; + } + +#ifdef DEBUG + bool operator==(const HeapAccess &other) const; + bool operator!=(const HeapAccess &other) const; +#endif +}; + +MOZ_COLD uint8_t *DisassembleHeapAccess(uint8_t *ptr, HeapAccess *access); + +#ifdef DEBUG +void DumpHeapAccess(const HeapAccess &access); +#endif + +} // namespace Disassembler + +} // namespace jit +} // namespace js + +#endif /* jit_Disassembler_h */ diff --git a/js/src/jit/shared/Disassembler-x86-shared.cpp b/js/src/jit/shared/Disassembler-x86-shared.cpp new file mode 100644 index 000000000000..53497ec2b975 --- /dev/null +++ b/js/src/jit/shared/Disassembler-x86-shared.cpp @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/Disassembler.h" + +#include "jit/shared/Encoding-x86-shared.h" + +using namespace js; +using namespace js::jit; +using namespace js::jit::X86Encoding; +using namespace js::jit::Disassembler; + +static bool REX_W(uint8_t rex) { return (rex >> 3) & 0x1; } +static bool REX_R(uint8_t rex) { return (rex >> 2) & 0x1; } +static bool REX_X(uint8_t rex) { return (rex >> 1) & 0x1; } +static bool REX_B(uint8_t rex) { return (rex >> 0) & 0x1; } + +static uint8_t +MakeREXFlags(bool w, bool r, bool x, bool b) +{ + uint8_t rex = (w << 3) | (r << 2) | (x << 1) | (b << 0); + MOZ_ASSERT(REX_W(rex) == w); + MOZ_ASSERT(REX_R(rex) == r); + MOZ_ASSERT(REX_X(rex) == x); + MOZ_ASSERT(REX_B(rex) == b); + return rex; +} + +static ModRmMode +ModRM_Mode(uint8_t modrm) +{ + return ModRmMode((modrm >> 6) & 0x3); +} + +static uint8_t +ModRM_Reg(uint8_t modrm) +{ + return (modrm >> 3) & 0x7; +} + +static uint8_t +ModRM_RM(uint8_t modrm) +{ + return (modrm >> 0) & 0x7; +} + +static bool +ModRM_hasSIB(uint8_t modrm) +{ + return ModRM_Mode(modrm) != ModRmRegister && ModRM_RM(modrm) == hasSib; +} +static bool +ModRM_hasDisp8(uint8_t modrm) +{ + return ModRM_Mode(modrm) == ModRmMemoryDisp8; +} +static bool +ModRM_hasRIP(uint8_t modrm) +{ +#ifdef JS_CODEGEN_X64 + return ModRM_Mode(modrm) == ModRmMemoryNoDisp && ModRM_RM(modrm) == noBase; +#else + return false; +#endif +} +static bool +ModRM_hasDisp32(uint8_t modrm) +{ + return ModRM_Mode(modrm) == ModRmMemoryDisp32 || + ModRM_hasRIP(modrm); +} + +static uint8_t +SIB_SS(uint8_t sib) +{ + return (sib >> 6) & 0x3; +} + +static uint8_t +SIB_Index(uint8_t sib) +{ + return (sib >> 3) & 0x7; +} + +static uint8_t +SIB_Base(uint8_t sib) +{ + return (sib >> 0) & 0x7; +} + +static bool +SIB_hasRIP(uint8_t sib) +{ + return SIB_Base(sib) == noBase && SIB_Index(sib) == noIndex; +} + +static bool +HasRIP(uint8_t modrm, uint8_t sib, uint8_t rex) +{ + return ModRM_hasRIP(modrm) && SIB_hasRIP(sib); +} + +static bool +HasDisp8(uint8_t modrm) +{ + return ModRM_hasDisp8(modrm); +} + +static bool +HasDisp32(uint8_t modrm, uint8_t sib) +{ + return ModRM_hasDisp32(modrm) || + (SIB_Base(sib) == noBase && + SIB_Index(sib) == noIndex && + ModRM_Mode(modrm) == ModRmMemoryNoDisp); +} + +static uint32_t +Reg(uint8_t modrm, uint8_t sib, uint8_t rex) +{ + return ModRM_Reg(modrm) | (REX_R(rex) << 3); +} + +static bool +HasBase(uint8_t modrm, uint8_t sib) +{ + return !ModRM_hasSIB(modrm) || + SIB_Base(sib) != noBase || + SIB_Index(sib) != noIndex || + ModRM_Mode(modrm) != ModRmMemoryNoDisp; +} + +static RegisterID +DecodeBase(uint8_t modrm, uint8_t sib, uint8_t rex) +{ + return HasBase(modrm, sib) + ? RegisterID((ModRM_hasSIB(modrm) ? SIB_Base(sib) : ModRM_RM(modrm)) | (REX_B(rex) << 3)) + : invalid_reg; +} + +static RegisterID +DecodeIndex(uint8_t modrm, uint8_t sib, uint8_t rex) +{ + RegisterID index = RegisterID(SIB_Index(sib) | (REX_X(rex) << 3)); + return ModRM_hasSIB(modrm) && index != noIndex ? index : invalid_reg; +} + +static uint32_t +DecodeScale(uint8_t modrm, uint8_t sib, uint8_t rex) +{ + return ModRM_hasSIB(modrm) ? SIB_SS(sib) : 0; +} + +#define PackOpcode(op0, op1, op2) ((op0) | ((op1) << 8) | ((op2) << 16)) +#define Pack2ByteOpcode(op1) PackOpcode(OP_2BYTE_ESCAPE, op1, 0) +#define Pack3ByteOpcode(op1, op2) PackOpcode(OP_2BYTE_ESCAPE, op1, op2) + +uint8_t * +js::jit::Disassembler::DisassembleHeapAccess(uint8_t *ptr, HeapAccess *access) +{ + VexOperandType type = VEX_PS; + uint32_t opcode = OP_HLT; + uint8_t modrm = 0; + uint8_t sib = 0; + uint8_t rex = 0; + int32_t disp = 0; + int32_t imm = 0; + bool haveImm = false; + int opsize = 4; + + // Legacy prefixes + switch (*ptr) { + case PRE_LOCK: + case PRE_PREDICT_BRANCH_NOT_TAKEN: // (obsolete), aka %cs + case 0x3E: // aka predict-branch-taken (obsolete) + case 0x36: // %ss + case 0x26: // %es + case 0x64: // %fs + case 0x65: // %gs + case 0x67: // address-size override + MOZ_CRASH("Unable to disassemble instruction"); + case PRE_SSE_F2: // aka REPNZ/REPNE + type = VEX_SD; + ptr++; + break; + case PRE_SSE_F3: // aka REP/REPE/REPZ + type = VEX_SS; + ptr++; + break; + case PRE_SSE_66: // aka PRE_OPERAND_SIZE + type = VEX_PD; + opsize = 2; + ptr++; + break; + default: + break; + } + + // REX and VEX prefixes + { + int x = 0, b = 0, m = 1, w = 0; + int r, l, p; + switch (*ptr) { +#ifdef JS_CODEGEN_X64 + case PRE_REX | 0x0: case PRE_REX | 0x1: case PRE_REX | 0x2: case PRE_REX | 0x3: + case PRE_REX | 0x4: case PRE_REX | 0x5: case PRE_REX | 0x6: case PRE_REX | 0x7: + case PRE_REX | 0x8: case PRE_REX | 0x9: case PRE_REX | 0xa: case PRE_REX | 0xb: + case PRE_REX | 0xc: case PRE_REX | 0xd: case PRE_REX | 0xe: case PRE_REX | 0xf: + rex = *ptr++ & 0xf; + goto rex_done; +#endif + case PRE_VEX_C4: { + if (type != VEX_PS) + MOZ_CRASH("Unable to disassemble instruction"); + ++ptr; + uint8_t c4a = *ptr++ ^ 0xe0; + uint8_t c4b = *ptr++ ^ 0x78; + r = (c4a >> 7) & 0x1; + x = (c4a >> 6) & 0x1; + b = (c4a >> 5) & 0x1; + m = (c4a >> 0) & 0x1f; + w = (c4b >> 7) & 0x1; + l = (c4b >> 2) & 0x1; + p = (c4b >> 0) & 0x3; + break; + } + case PRE_VEX_C5: { + if (type != VEX_PS) + MOZ_CRASH("Unable to disassemble instruction"); + ++ptr; + uint8_t c5 = *ptr++ ^ 0xf8; + r = (c5 >> 7) & 0x1; + l = (c5 >> 2) & 0x1; + p = (c5 >> 0) & 0x3; + break; + } + default: + goto rex_done; + } + type = VexOperandType(p); + rex = MakeREXFlags(w, r, x, b); + switch (m) { + case 0x1: + opcode = Pack2ByteOpcode(*ptr++); + goto opcode_done; + case 0x2: + opcode = Pack3ByteOpcode(ESCAPE_38, *ptr++); + goto opcode_done; + case 0x3: + opcode = Pack3ByteOpcode(ESCAPE_3A, *ptr++); + goto opcode_done; + default: + MOZ_CRASH("Unable to disassemble instruction"); + } + if (l != 0) // 256-bit SIMD + MOZ_CRASH("Unable to disassemble instruction"); + } + rex_done:; + if (REX_W(rex)) + opsize = 8; + + // Opcode. + opcode = *ptr++; + switch (opcode) { +#ifdef JS_CODEGEN_X64 + case OP_PUSH_EAX + 0: case OP_PUSH_EAX + 1: case OP_PUSH_EAX + 2: case OP_PUSH_EAX + 3: + case OP_PUSH_EAX + 4: case OP_PUSH_EAX + 5: case OP_PUSH_EAX + 6: case OP_PUSH_EAX + 7: + case OP_POP_EAX + 0: case OP_POP_EAX + 1: case OP_POP_EAX + 2: case OP_POP_EAX + 3: + case OP_POP_EAX + 4: case OP_POP_EAX + 5: case OP_POP_EAX + 6: case OP_POP_EAX + 7: + case OP_PUSH_Iz: + case OP_PUSH_Ib: + opsize = 8; + break; +#endif + case OP_2BYTE_ESCAPE: + opcode |= *ptr << 8; + switch (*ptr++) { + case ESCAPE_38: + case ESCAPE_3A: + opcode |= *ptr++ << 16; + break; + default: + break; + } + break; + default: + break; + } + opcode_done:; + + // ModR/M + modrm = *ptr++; + + // SIB + if (ModRM_hasSIB(modrm)) + sib = *ptr++; + + // Address Displacement + if (HasDisp8(modrm)) { + disp = int8_t(*ptr++); + } else if (HasDisp32(modrm, sib)) { + memcpy(&disp, ptr, sizeof(int32_t)); + ptr += sizeof(int32_t); + } + + // Immediate operand + switch (opcode) { + case OP_PUSH_Ib: + case OP_IMUL_GvEvIb: + case OP_GROUP1_EbIb: + case OP_GROUP1_EvIb: + case OP_TEST_EAXIb: + case OP_GROUP2_EvIb: + case OP_GROUP11_EvIb: + case OP_GROUP3_EbIb: + case Pack2ByteOpcode(OP2_PSHUFD_VdqWdqIb): + case Pack2ByteOpcode(OP2_PSLLD_UdqIb): // aka OP2_PSRAD_UdqIb, aka OP2_PSRLD_UdqIb + case Pack2ByteOpcode(OP2_PEXTRW_GdUdIb): + case Pack2ByteOpcode(OP2_SHUFPS_VpsWpsIb): + case Pack3ByteOpcode(ESCAPE_3A, OP3_PEXTRD_EdVdqIb): + case Pack3ByteOpcode(ESCAPE_3A, OP3_BLENDPS_VpsWpsIb): + case Pack3ByteOpcode(ESCAPE_3A, OP3_PINSRD_VdqEdIb): + // 8-bit signed immediate + imm = int8_t(*ptr++); + haveImm = true; + break; + case OP_RET_Iz: + // 16-bit unsigned immediate + memcpy(&imm, ptr, sizeof(int16_t)); + ptr += sizeof(int16_t); + haveImm = true; + break; + case OP_ADD_EAXIv: + case OP_OR_EAXIv: + case OP_AND_EAXIv: + case OP_SUB_EAXIv: + case OP_XOR_EAXIv: + case OP_CMP_EAXIv: + case OP_PUSH_Iz: + case OP_IMUL_GvEvIz: + case OP_GROUP1_EvIz: + case OP_TEST_EAXIv: + case OP_MOV_EAXIv: + case OP_GROUP3_EvIz: + // 32-bit signed immediate + memcpy(&imm, ptr, sizeof(int32_t)); + ptr += sizeof(int32_t); + haveImm = true; + break; + case OP_GROUP11_EvIz: + // opsize-sized signed immediate + memcpy(&imm, ptr, opsize); + imm = (imm << (32 - opsize * 8)) >> (32 - opsize * 8); + ptr += opsize; + haveImm = true; + break; + default: + break; + } + + // Interpret the opcode. + if (HasRIP(modrm, sib, rex)) + MOZ_CRASH("Unable to disassemble instruction"); + size_t memSize = 0; + OtherOperand otherOperand(imm); + HeapAccess::Kind kind = HeapAccess::Unknown; + RegisterID gpr(RegisterID(Reg(modrm, sib, rex))); + XMMRegisterID xmm(XMMRegisterID(Reg(modrm, sib, rex))); + ComplexAddress addr(disp, + DecodeBase(modrm, sib, rex), + DecodeIndex(modrm, sib, rex), + DecodeScale(modrm, sib, rex)); + switch (opcode) { + case OP_GROUP11_EvIb: + if (gpr != RegisterID(GROUP11_MOV)) + MOZ_CRASH("Unable to disassemble instruction"); + MOZ_ASSERT(haveImm); + memSize = 1; + kind = HeapAccess::Store; + break; + case OP_GROUP11_EvIz: + if (gpr != RegisterID(GROUP11_MOV)) + MOZ_CRASH("Unable to disassemble instruction"); + MOZ_ASSERT(haveImm); + memSize = opsize; + kind = HeapAccess::Store; + break; + case OP_MOV_GvEv: + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = opsize; + kind = HeapAccess::Load; + break; + case OP_MOV_GvEb: + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = 1; + kind = HeapAccess::Load; + break; + case OP_MOV_EvGv: + if (!haveImm) + otherOperand = OtherOperand(gpr); + memSize = opsize; + kind = HeapAccess::Store; + break; + case OP_MOV_EbGv: + if (!haveImm) + otherOperand = OtherOperand(gpr); + memSize = 1; + kind = HeapAccess::Store; + break; + case Pack2ByteOpcode(OP2_MOVZX_GvEb): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = 1; + kind = HeapAccess::Load; + break; + case Pack2ByteOpcode(OP2_MOVZX_GvEw): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = 2; + kind = HeapAccess::Load; + break; + case Pack2ByteOpcode(OP2_MOVSX_GvEb): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = 1; + kind = HeapAccess::LoadSext32; + break; + case Pack2ByteOpcode(OP2_MOVSX_GvEw): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(gpr); + memSize = 2; + kind = HeapAccess::LoadSext32; + break; + case Pack2ByteOpcode(OP2_MOVDQ_VdqWdq): // aka OP2_MOVDQ_VsdWsd + case Pack2ByteOpcode(OP2_MOVAPS_VsdWsd): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(xmm); + memSize = 16; + kind = HeapAccess::Load; + break; + case Pack2ByteOpcode(OP2_MOVSD_VsdWsd): // aka OP2_MOVPS_VpsWps + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(xmm); + switch (type) { + case VEX_SS: memSize = 4; break; + case VEX_SD: memSize = 8; break; + case VEX_PS: + case VEX_PD: memSize = 16; break; + default: MOZ_CRASH("Unexpected VEX type"); + } + kind = HeapAccess::Load; + break; + case Pack2ByteOpcode(OP2_MOVDQ_WdqVdq): + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(xmm); + memSize = 16; + kind = HeapAccess::Store; + break; + case Pack2ByteOpcode(OP2_MOVSD_WsdVsd): // aka OP2_MOVPS_WpsVps + MOZ_ASSERT(!haveImm); + otherOperand = OtherOperand(xmm); + switch (type) { + case VEX_SS: memSize = 4; break; + case VEX_SD: memSize = 8; break; + case VEX_PS: + case VEX_PD: memSize = 16; break; + default: MOZ_CRASH("Unexpected VEX type"); + } + kind = HeapAccess::Store; + break; + default: + MOZ_CRASH("Unable to disassemble instruction"); + } + + *access = HeapAccess(kind, memSize, addr, otherOperand); + return ptr; +} + +#ifdef DEBUG +void +js::jit::Disassembler::DumpHeapAccess(const HeapAccess &access) +{ + switch (access.kind()) { + case HeapAccess::Store: fprintf(stderr, "store"); break; + case HeapAccess::Load: fprintf(stderr, "load"); break; + case HeapAccess::LoadSext32: fprintf(stderr, "loadSext32"); break; + default: fprintf(stderr, "unknown"); break; + } + fprintf(stderr, "%u ", unsigned(access.size())); + + switch (access.otherOperand().kind()) { + case OtherOperand::Imm: fprintf(stderr, "imm %d", access.otherOperand().imm()); break; + case OtherOperand::GPR: fprintf(stderr, "gpr %s", X86Encoding::GPRegName(access.otherOperand().gpr())); break; + case OtherOperand::FPR: fprintf(stderr, "fpr %s", X86Encoding::XMMRegName(access.otherOperand().fpr())); break; + default: fprintf(stderr, "unknown"); + } + + fprintf(stderr, " @ "); + + if (access.address().isPCRelative()) { + fprintf(stderr, MEM_o32r " ", ADDR_o32r(access.address().disp())); + } else if (access.address().index() != X86Encoding::invalid_reg) { + if (access.address().base() != X86Encoding::invalid_reg) { + fprintf(stderr, MEM_obs " ", + ADDR_obs(access.address().disp(), access.address().base(), + access.address().index(), access.address().scale())); + } else { + fprintf(stderr, MEM_os " ", + ADDR_os(access.address().disp(), + access.address().index(), access.address().scale())); + } + } else if (access.address().base() != X86Encoding::invalid_reg) { + fprintf(stderr, MEM_ob " ", ADDR_ob(access.address().disp(), access.address().base())); + } else { + fprintf(stderr, MEM_o " ", ADDR_o(access.address().disp())); + } + + fprintf(stderr, "\n"); +} +#endif diff --git a/js/src/moz.build b/js/src/moz.build index e93d2eff71ad..0e6a6496220c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -154,6 +154,7 @@ UNIFIED_SOURCES += [ 'jit/C1Spewer.cpp', 'jit/CodeGenerator.cpp', 'jit/CompileWrappers.cpp', + 'jit/Disassembler.cpp', 'jit/EdgeCaseAnalysis.cpp', 'jit/EffectiveAddressAnalysis.cpp', 'jit/ExecutableAllocator.cpp', @@ -326,6 +327,7 @@ elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']: 'jit/shared/BaselineCompiler-x86-shared.cpp', 'jit/shared/BaselineIC-x86-shared.cpp', 'jit/shared/CodeGenerator-x86-shared.cpp', + 'jit/shared/Disassembler-x86-shared.cpp', 'jit/shared/Lowering-x86-shared.cpp', 'jit/shared/MacroAssembler-x86-shared.cpp', 'jit/shared/MoveEmitter-x86-shared.cpp',