Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/jit/Disassembler.h
Line
Count
Source (jump to first uncovered line)
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
    ComplexAddress()
27
      : disp_(0),
28
        base_(Registers::Invalid),
29
        index_(Registers::Invalid),
30
        scale_(0),
31
        isPCRelative_(false)
32
0
    {
33
0
        MOZ_ASSERT(*this == *this);
34
0
    }
35
36
    ComplexAddress(int32_t disp, Register::Encoding base)
37
      : disp_(disp),
38
        base_(base),
39
        index_(Registers::Invalid),
40
        scale_(0),
41
        isPCRelative_(false)
42
0
    {
43
0
        MOZ_ASSERT(*this == *this);
44
0
        MOZ_ASSERT(base != Registers::Invalid);
45
0
        MOZ_ASSERT(base_ == base);
46
0
    }
47
48
    ComplexAddress(int32_t disp, Register::Encoding base, Register::Encoding index, int scale)
49
      : disp_(disp),
50
        base_(base),
51
        index_(index),
52
        scale_(scale),
53
        isPCRelative_(false)
54
0
    {
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
    explicit ComplexAddress(const void* addr)
63
      : disp_(static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr))),
64
        base_(Registers::Invalid),
65
        index_(Registers::Invalid),
66
        scale_(0),
67
        isPCRelative_(false)
68
0
    {
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
0
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
75
0
        switch (op.kind()) {
76
0
          case Operand::MEM_REG_DISP:
77
0
            *this = ComplexAddress(op.disp(), op.base());
78
0
            return;
79
0
          case Operand::MEM_SCALE:
80
0
            *this = ComplexAddress(op.disp(), op.base(), op.index(), op.scale());
81
0
            return;
82
0
          case Operand::MEM_ADDRESS32:
83
0
            *this = ComplexAddress(op.address());
84
0
            return;
85
0
          default:
86
0
            break;
87
0
        }
88
0
#endif
89
0
        MOZ_CRASH("Unexpected Operand kind");
90
0
    }
91
92
0
    bool isPCRelative() const {
93
0
        return isPCRelative_;
94
0
    }
95
96
0
    int32_t disp() const {
97
0
        return disp_;
98
0
    }
99
100
0
    bool hasBase() const {
101
0
        return base_ != Registers::Invalid;
102
0
    }
103
104
0
    Register::Encoding base() const {
105
0
        MOZ_ASSERT(hasBase());
106
0
        return base_;
107
0
    }
108
109
0
    bool hasIndex() const {
110
0
        return index_ != Registers::Invalid;
111
0
    }
112
113
0
    Register::Encoding index() const {
114
0
        MOZ_ASSERT(hasIndex());
115
0
        return index_;
116
0
    }
117
118
0
    uint32_t scale() const {
119
0
        return scale_;
120
0
    }
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
    OtherOperand()
147
      : kind_(Imm)
148
0
    {
149
0
        u_.imm = 0;
150
0
        MOZ_ASSERT(*this == *this);
151
0
    }
152
153
    explicit OtherOperand(int32_t imm)
154
      : kind_(Imm)
155
0
    {
156
0
        u_.imm = imm;
157
0
        MOZ_ASSERT(*this == *this);
158
0
    }
159
160
    explicit OtherOperand(Register::Encoding gpr)
161
      : kind_(GPR)
162
0
    {
163
0
        u_.gpr = gpr;
164
0
        MOZ_ASSERT(*this == *this);
165
0
    }
166
167
    explicit OtherOperand(FloatRegister::Encoding fpr)
168
      : kind_(FPR)
169
0
    {
170
0
        u_.fpr = fpr;
171
0
        MOZ_ASSERT(*this == *this);
172
0
    }
173
174
0
    Kind kind() const {
175
0
        return kind_;
176
0
    }
177
178
0
    int32_t imm() const {
179
0
        MOZ_ASSERT(kind_ == Imm);
180
0
        return u_.imm;
181
0
    }
182
183
0
    Register::Encoding gpr() const {
184
0
        MOZ_ASSERT(kind_ == GPR);
185
0
        return u_.gpr;
186
0
    }
187
188
0
    FloatRegister::Encoding fpr() const {
189
0
        MOZ_ASSERT(kind_ == FPR);
190
0
        return u_.fpr;
191
0
    }
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
    HeapAccess()
217
      : kind_(Unknown),
218
        size_(0)
219
0
    {
220
0
        MOZ_ASSERT(*this == *this);
221
0
    }
222
223
    HeapAccess(Kind kind, size_t size, const ComplexAddress& address, const OtherOperand& otherOperand)
224
      : kind_(kind),
225
        size_(size),
226
        address_(address),
227
        otherOperand_(otherOperand)
228
0
    {
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
0
    }
238
239
0
    size_t size() const {
240
0
        MOZ_ASSERT(kind_ != Unknown);
241
0
        return size_;
242
0
    }
243
244
0
    const ComplexAddress& address() const {
245
0
        return address_;
246
0
    }
247
248
0
    const OtherOperand& otherOperand() const {
249
0
        return otherOperand_;
250
0
    }
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
VerifyHeapAccess(uint8_t* begin, uint8_t* end, const HeapAccess& expected)
265
{
266
    HeapAccess disassembled;
267
    uint8_t* e = DisassembleHeapAccess(begin, &disassembled);
268
    MOZ_ASSERT(e == end);
269
    MOZ_ASSERT(disassembled == expected);
270
}
271
#endif
272
273
} // namespace Disassembler
274
275
} // namespace jit
276
} // namespace js
277
278
#endif /* jit_Disassembler_h */