mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 02:05:42 +00:00
Bug 1125236 - SpiderMonkey: Implement a minimal x86 disassembler r=jandem
This commit is contained in:
parent
e0bbe4717a
commit
9057901f95
64
js/src/jit/Disassembler.cpp
Normal file
64
js/src/jit/Disassembler.cpp
Normal file
@ -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
|
254
js/src/jit/Disassembler.h
Normal file
254
js/src/jit/Disassembler.h
Normal file
@ -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<uint32_t>(reinterpret_cast<uintptr_t>(addr))),
|
||||
base_(Registers::Invalid),
|
||||
index_(Registers::Invalid),
|
||||
scale_(0),
|
||||
isPCRelative_(false)
|
||||
{
|
||||
MOZ_ASSERT(*this == *this);
|
||||
MOZ_ASSERT(reinterpret_cast<const void *>(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 */
|
525
js/src/jit/shared/Disassembler-x86-shared.cpp
Normal file
525
js/src/jit/shared/Disassembler-x86-shared.cpp
Normal file
@ -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
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user