Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_Disassembler_h
8 : #define jit_Disassembler_h
9 :
10 : #include "jit/MacroAssembler.h"
11 : #include "jit/Registers.h"
12 :
13 : namespace js {
14 : namespace jit {
15 :
16 : namespace Disassembler {
17 :
18 : class ComplexAddress {
19 : int32_t disp_;
20 : Register::Encoding base_ : 8;
21 : Register::Encoding index_ : 8;
22 : int8_t scale_; // log2 encoding
23 : bool isPCRelative_;
24 :
25 : public:
26 0 : ComplexAddress()
27 0 : : disp_(0),
28 : base_(Registers::Invalid),
29 : index_(Registers::Invalid),
30 : scale_(0),
31 0 : isPCRelative_(false)
32 : {
33 0 : MOZ_ASSERT(*this == *this);
34 0 : }
35 :
36 0 : ComplexAddress(int32_t disp, Register::Encoding base)
37 0 : : disp_(disp),
38 : base_(base),
39 : index_(Registers::Invalid),
40 : scale_(0),
41 0 : isPCRelative_(false)
42 : {
43 0 : MOZ_ASSERT(*this == *this);
44 0 : MOZ_ASSERT(base != Registers::Invalid);
45 0 : MOZ_ASSERT(base_ == base);
46 0 : }
47 :
48 0 : ComplexAddress(int32_t disp, Register::Encoding base, Register::Encoding index, int scale)
49 0 : : disp_(disp),
50 : base_(base),
51 : index_(index),
52 : scale_(scale),
53 0 : isPCRelative_(false)
54 : {
55 0 : MOZ_ASSERT(scale >= 0 && scale < 4);
56 0 : MOZ_ASSERT_IF(index == Registers::Invalid, scale == 0);
57 0 : MOZ_ASSERT(*this == *this);
58 0 : MOZ_ASSERT(base_ == base);
59 0 : MOZ_ASSERT(index_ == index);
60 0 : }
61 :
62 0 : explicit ComplexAddress(const void* addr)
63 0 : : disp_(static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr))),
64 : base_(Registers::Invalid),
65 : index_(Registers::Invalid),
66 : scale_(0),
67 0 : isPCRelative_(false)
68 : {
69 0 : MOZ_ASSERT(*this == *this);
70 0 : MOZ_ASSERT(reinterpret_cast<const void*>(uintptr_t(disp_)) == addr);
71 0 : }
72 :
73 0 : explicit ComplexAddress(const Operand& op) {
74 : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
75 0 : switch (op.kind()) {
76 : case Operand::MEM_REG_DISP:
77 0 : *this = ComplexAddress(op.disp(), op.base());
78 0 : return;
79 : case Operand::MEM_SCALE:
80 0 : *this = ComplexAddress(op.disp(), op.base(), op.index(), op.scale());
81 0 : return;
82 : case Operand::MEM_ADDRESS32:
83 0 : *this = ComplexAddress(op.address());
84 0 : return;
85 : default:
86 0 : break;
87 : }
88 : #endif
89 0 : MOZ_CRASH("Unexpected Operand kind");
90 : }
91 :
92 0 : bool isPCRelative() const {
93 0 : return isPCRelative_;
94 : }
95 :
96 0 : int32_t disp() const {
97 0 : return disp_;
98 : }
99 :
100 0 : bool hasBase() const {
101 0 : return base_ != Registers::Invalid;
102 : }
103 :
104 0 : Register::Encoding base() const {
105 0 : MOZ_ASSERT(hasBase());
106 0 : return base_;
107 : }
108 :
109 0 : bool hasIndex() const {
110 0 : return index_ != Registers::Invalid;
111 : }
112 :
113 0 : Register::Encoding index() const {
114 0 : MOZ_ASSERT(hasIndex());
115 0 : return index_;
116 : }
117 :
118 0 : uint32_t scale() const {
119 0 : return scale_;
120 : }
121 :
122 : #ifdef DEBUG
123 : bool operator==(const ComplexAddress& other) const;
124 : bool operator!=(const ComplexAddress& other) const;
125 : #endif
126 : };
127 :
128 : // An operand other than a memory operand -- a register or an immediate.
129 : class OtherOperand {
130 : public:
131 : enum Kind {
132 : Imm,
133 : GPR,
134 : FPR,
135 : };
136 :
137 : private:
138 : Kind kind_;
139 : union {
140 : int32_t imm;
141 : Register::Encoding gpr;
142 : FloatRegister::Encoding fpr;
143 : } u_;
144 :
145 : public:
146 0 : OtherOperand()
147 0 : : kind_(Imm)
148 : {
149 0 : u_.imm = 0;
150 0 : MOZ_ASSERT(*this == *this);
151 0 : }
152 :
153 0 : explicit OtherOperand(int32_t imm)
154 0 : : kind_(Imm)
155 : {
156 0 : u_.imm = imm;
157 0 : MOZ_ASSERT(*this == *this);
158 0 : }
159 :
160 0 : explicit OtherOperand(Register::Encoding gpr)
161 0 : : kind_(GPR)
162 : {
163 0 : u_.gpr = gpr;
164 0 : MOZ_ASSERT(*this == *this);
165 0 : }
166 :
167 0 : explicit OtherOperand(FloatRegister::Encoding fpr)
168 0 : : kind_(FPR)
169 : {
170 0 : u_.fpr = fpr;
171 0 : MOZ_ASSERT(*this == *this);
172 0 : }
173 :
174 0 : Kind kind() const {
175 0 : return kind_;
176 : }
177 :
178 0 : int32_t imm() const {
179 0 : MOZ_ASSERT(kind_ == Imm);
180 0 : return u_.imm;
181 : }
182 :
183 0 : Register::Encoding gpr() const {
184 0 : MOZ_ASSERT(kind_ == GPR);
185 0 : return u_.gpr;
186 : }
187 :
188 0 : FloatRegister::Encoding fpr() const {
189 0 : MOZ_ASSERT(kind_ == FPR);
190 0 : return u_.fpr;
191 : }
192 :
193 : #ifdef DEBUG
194 : bool operator==(const OtherOperand& other) const;
195 : bool operator!=(const OtherOperand& other) const;
196 : #endif
197 : };
198 :
199 : class HeapAccess {
200 : public:
201 : enum Kind {
202 : Unknown,
203 : Load, // any bits not covered by the load are zeroed
204 : LoadSext32, // like Load, but sign-extend to 32 bits
205 : LoadSext64, // like Load, but sign-extend to 64 bits
206 : Store
207 : };
208 :
209 : private:
210 : Kind kind_;
211 : size_t size_; // The number of bytes of memory accessed
212 : ComplexAddress address_;
213 : OtherOperand otherOperand_;
214 :
215 : public:
216 0 : HeapAccess()
217 0 : : kind_(Unknown),
218 0 : size_(0)
219 : {
220 0 : MOZ_ASSERT(*this == *this);
221 0 : }
222 :
223 0 : HeapAccess(Kind kind, size_t size, const ComplexAddress& address, const OtherOperand& otherOperand)
224 0 : : kind_(kind),
225 : size_(size),
226 : address_(address),
227 0 : otherOperand_(otherOperand)
228 : {
229 0 : MOZ_ASSERT(kind != Unknown);
230 0 : MOZ_ASSERT_IF(kind == LoadSext32, otherOperand.kind() != OtherOperand::FPR);
231 0 : MOZ_ASSERT_IF(kind == Load || kind == LoadSext32, otherOperand.kind() != OtherOperand::Imm);
232 0 : MOZ_ASSERT(*this == *this);
233 0 : }
234 :
235 0 : Kind kind() const {
236 0 : return kind_;
237 : }
238 :
239 0 : size_t size() const {
240 0 : MOZ_ASSERT(kind_ != Unknown);
241 0 : return size_;
242 : }
243 :
244 0 : const ComplexAddress& address() const {
245 0 : return address_;
246 : }
247 :
248 0 : const OtherOperand& otherOperand() const {
249 0 : return otherOperand_;
250 : }
251 :
252 : #ifdef DEBUG
253 : bool operator==(const HeapAccess& other) const;
254 : bool operator!=(const HeapAccess& other) const;
255 : #endif
256 : };
257 :
258 : MOZ_COLD uint8_t* DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access);
259 :
260 : #ifdef DEBUG
261 : void DumpHeapAccess(const HeapAccess& access);
262 :
263 : inline void
264 0 : VerifyHeapAccess(uint8_t* begin, uint8_t* end, const HeapAccess& expected)
265 : {
266 0 : HeapAccess disassembled;
267 0 : uint8_t* e = DisassembleHeapAccess(begin, &disassembled);
268 0 : MOZ_ASSERT(e == end);
269 0 : MOZ_ASSERT(disassembled == expected);
270 0 : }
271 : #endif
272 :
273 : } // namespace Disassembler
274 :
275 : } // namespace jit
276 : } // namespace js
277 :
278 : #endif /* jit_Disassembler_h */
|