/* -*- 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 */