diff options
Diffstat (limited to 'js/src/jit/Disassembler.h')
-rw-r--r-- | js/src/jit/Disassembler.h | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/js/src/jit/Disassembler.h b/js/src/jit/Disassembler.h new file mode 100644 index 000000000..101b78968 --- /dev/null +++ b/js/src/jit/Disassembler.h @@ -0,0 +1,278 @@ +/* -*- 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 */ |