279 lines
6.4 KiB
C++
279 lines
6.4 KiB
C++
/* -*- 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/MacroAssembler.h"
|
|
#include "jit/Registers.h"
|
|
|
|
namespace js {
|
|
namespace jit {
|
|
|
|
namespace Disassembler {
|
|
|
|
class ComplexAddress {
|
|
int32_t disp_;
|
|
Register::Encoding base_ : 8;
|
|
Register::Encoding 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::Encoding 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::Encoding base, Register::Encoding 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;
|
|
case Operand::MEM_ADDRESS32:
|
|
*this = ComplexAddress(op.address());
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
MOZ_CRASH("Unexpected Operand kind");
|
|
}
|
|
|
|
bool isPCRelative() const {
|
|
return isPCRelative_;
|
|
}
|
|
|
|
int32_t disp() const {
|
|
return disp_;
|
|
}
|
|
|
|
bool hasBase() const {
|
|
return base_ != Registers::Invalid;
|
|
}
|
|
|
|
Register::Encoding base() const {
|
|
MOZ_ASSERT(hasBase());
|
|
return base_;
|
|
}
|
|
|
|
bool hasIndex() const {
|
|
return index_ != Registers::Invalid;
|
|
}
|
|
|
|
Register::Encoding index() const {
|
|
MOZ_ASSERT(hasIndex());
|
|
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::Encoding gpr;
|
|
FloatRegister::Encoding 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::Encoding gpr)
|
|
: kind_(GPR)
|
|
{
|
|
u_.gpr = gpr;
|
|
MOZ_ASSERT(*this == *this);
|
|
}
|
|
|
|
explicit OtherOperand(FloatRegister::Encoding 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::Encoding gpr() const {
|
|
MOZ_ASSERT(kind_ == GPR);
|
|
return u_.gpr;
|
|
}
|
|
|
|
FloatRegister::Encoding 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
|
|
LoadSext64, // like Load, but sign-extend to 64 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);
|
|
|
|
inline void
|
|
VerifyHeapAccess(uint8_t* begin, uint8_t* end, const HeapAccess& expected)
|
|
{
|
|
HeapAccess disassembled;
|
|
uint8_t* e = DisassembleHeapAccess(begin, &disassembled);
|
|
MOZ_ASSERT(e == end);
|
|
MOZ_ASSERT(disassembled == expected);
|
|
}
|
|
#endif
|
|
|
|
} // namespace Disassembler
|
|
|
|
} // namespace jit
|
|
} // namespace js
|
|
|
|
#endif /* jit_Disassembler_h */
|