blob: c733aecf789b9db764794f667e8b087fba237d3a [file] [log] [blame]
/* -*- 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
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 */