Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
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 vm_BytecodeLocation_h
8
#define vm_BytecodeLocation_h
9
10
#include "frontend/NameAnalysisTypes.h"
11
#include "js/TypeDecls.h"
12
#include "vm/BytecodeUtil.h"
13
#include "vm/CheckIsCallableKind.h" // CheckIsCallableKind
14
#include "vm/CheckIsObjectKind.h" // CheckIsObjectKind
15
#include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
16
#include "vm/StringType.h"
17
18
namespace js {
19
20
using RawBytecodeLocationOffset = uint32_t;
21
22
class PropertyName;
23
class RegExpObject;
24
25
class BytecodeLocationOffset {
26
RawBytecodeLocationOffset rawOffset_;
27
28
public:
29
explicit BytecodeLocationOffset(RawBytecodeLocationOffset offset)
30
: rawOffset_(offset) {}
31
32
RawBytecodeLocationOffset rawOffset() const { return rawOffset_; }
33
};
34
35
using RawBytecode = jsbytecode*;
36
37
// A immutable representation of a program location
38
//
39
class BytecodeLocation {
40
RawBytecode rawBytecode_;
41
#ifdef DEBUG
42
const JSScript* debugOnlyScript_;
43
#endif
44
45
// Construct a new BytecodeLocation, while borrowing scriptIdentity
46
// from some other BytecodeLocation.
47
BytecodeLocation(const BytecodeLocation& loc, RawBytecode pc)
48
: rawBytecode_(pc)
49
#ifdef DEBUG
50
,
51
debugOnlyScript_(loc.debugOnlyScript_)
52
#endif
53
{
54
MOZ_ASSERT(isValid());
55
}
56
57
public:
58
// Disallow the creation of an uninitialized location.
59
BytecodeLocation() = delete;
60
61
BytecodeLocation(const JSScript* script, RawBytecode pc)
62
: rawBytecode_(pc)
63
#ifdef DEBUG
64
,
65
debugOnlyScript_(script)
66
#endif
67
{
68
MOZ_ASSERT(isValid());
69
}
70
71
RawBytecode toRawBytecode() const { return rawBytecode_; }
72
73
// Return true if this bytecode location is valid for the given script.
74
// This includes the location 1-past the end of the bytecode.
75
JS_PUBLIC_API bool isValid(const JSScript* script) const;
76
77
// Return true if this bytecode location is within the bounds of the
78
// bytecode for a given script.
79
bool isInBounds(const JSScript* script) const;
80
81
uint32_t bytecodeToOffset(const JSScript* script) const;
82
83
uint32_t tableSwitchCaseOffset(const JSScript* script,
84
uint32_t caseIndex) const;
85
86
uint32_t getJumpTargetOffset(const JSScript* script) const;
87
88
uint32_t getTableSwitchDefaultOffset(const JSScript* script) const;
89
90
inline BytecodeLocation getTableSwitchDefaultTarget() const;
91
inline BytecodeLocation getTableSwitchCaseTarget(const JSScript* script,
92
uint32_t caseIndex) const;
93
94
uint32_t useCount() const;
95
96
uint32_t defCount() const;
97
98
int32_t jumpOffset() const { return GET_JUMP_OFFSET(rawBytecode_); }
99
int32_t codeOffset() const { return GET_CODE_OFFSET(rawBytecode_); }
100
101
inline JSAtom* getAtom(const JSScript* script) const;
102
inline PropertyName* getPropertyName(const JSScript* script) const;
103
inline JS::BigInt* getBigInt(const JSScript* script) const;
104
inline JSObject* getObject(const JSScript* script) const;
105
inline JSFunction* getFunction(const JSScript* script) const;
106
inline js::RegExpObject* getRegExp(const JSScript* script) const;
107
inline js::Scope* getScope(const JSScript* script) const;
108
109
uint32_t getSymbolIndex() const {
110
MOZ_ASSERT(is(JSOp::Symbol));
111
return GET_UINT8(rawBytecode_);
112
}
113
114
Scope* innermostScope(const JSScript* script) const;
115
116
#ifdef DEBUG
117
bool hasSameScript(const BytecodeLocation& other) const {
118
return debugOnlyScript_ == other.debugOnlyScript_;
119
}
120
#endif
121
122
// Overloaded operators
123
124
bool operator==(const BytecodeLocation& other) const {
125
MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_);
126
return rawBytecode_ == other.rawBytecode_;
127
}
128
129
bool operator!=(const BytecodeLocation& other) const {
130
return !(other == *this);
131
}
132
133
bool operator<(const BytecodeLocation& other) const {
134
MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_);
135
return rawBytecode_ < other.rawBytecode_;
136
}
137
138
// It is traditional to represent the rest of the relational operators
139
// using operator<, so we don't need to assert for these.
140
bool operator>(const BytecodeLocation& other) const { return other < *this; }
141
142
bool operator<=(const BytecodeLocation& other) const {
143
return !(other < *this);
144
}
145
146
bool operator>=(const BytecodeLocation& other) const {
147
return !(*this < other);
148
}
149
150
// Return the next bytecode
151
BytecodeLocation next() const {
152
return BytecodeLocation(*this,
153
rawBytecode_ + GetBytecodeLength(rawBytecode_));
154
}
155
156
// Add an offset.
157
BytecodeLocation operator+(const BytecodeLocationOffset& offset) {
158
return BytecodeLocation(*this, rawBytecode_ + offset.rawOffset());
159
}
160
161
// Identity Checks
162
bool is(JSOp op) const {
163
MOZ_ASSERT(isInBounds());
164
return getOp() == op;
165
}
166
167
// Accessors:
168
169
uint32_t length() const { return GetBytecodeLength(rawBytecode_); }
170
171
bool isJumpTarget() const { return BytecodeIsJumpTarget(getOp()); }
172
173
bool isJump() const { return IsJumpOpcode(getOp()); }
174
175
bool isBackedge() const { return IsBackedgePC(rawBytecode_); }
176
177
bool isBackedgeForLoophead(BytecodeLocation loopHead) const {
178
return IsBackedgeForLoopHead(rawBytecode_, loopHead.rawBytecode_);
179
}
180
181
bool opHasTypeSet() const { return BytecodeOpHasTypeSet(getOp()); }
182
183
bool fallsThrough() const { return BytecodeFallsThrough(getOp()); }
184
185
uint32_t icIndex() const { return GET_ICINDEX(rawBytecode_); }
186
187
uint32_t local() const { return GET_LOCALNO(rawBytecode_); }
188
189
uint16_t arg() const { return GET_ARGNO(rawBytecode_); }
190
191
bool isEqualityOp() const { return IsEqualityOp(getOp()); }
192
193
bool isStrictEqualityOp() const { return IsStrictEqualityOp(getOp()); }
194
195
bool isStrictSetOp() const { return IsStrictSetPC(rawBytecode_); }
196
197
bool isNameOp() const { return IsNameOp(getOp()); }
198
199
bool resultIsPopped() const {
200
MOZ_ASSERT(StackDefs(rawBytecode_) == 1);
201
return BytecodeIsPopped(rawBytecode_);
202
}
203
204
// Accessors:
205
JSOp getOp() const { return JSOp(*rawBytecode_); }
206
207
BytecodeLocation getJumpTarget() const {
208
MOZ_ASSERT(isJump());
209
return BytecodeLocation(*this,
210
rawBytecode_ + GET_JUMP_OFFSET(rawBytecode_));
211
}
212
213
BytecodeLocation getEndOfTryLocation() const {
214
MOZ_ASSERT(is(JSOp::Try));
215
return BytecodeLocation(*this,
216
rawBytecode_ + GET_CODE_OFFSET(rawBytecode_));
217
}
218
219
// Return the 'low' parameter to the tableswitch opcode
220
int32_t getTableSwitchLow() const {
221
MOZ_ASSERT(is(JSOp::TableSwitch));
222
return GET_JUMP_OFFSET(rawBytecode_ + JUMP_OFFSET_LEN);
223
}
224
225
// Return the 'high' parameter to the tableswitch opcode
226
int32_t getTableSwitchHigh() const {
227
MOZ_ASSERT(is(JSOp::TableSwitch));
228
return GET_JUMP_OFFSET(rawBytecode_ + (2 * JUMP_OFFSET_LEN));
229
}
230
231
uint32_t getPopCount() const {
232
MOZ_ASSERT(is(JSOp::PopN));
233
return GET_UINT16(rawBytecode_);
234
}
235
236
uint32_t getDupAtIndex() const {
237
MOZ_ASSERT(is(JSOp::DupAt));
238
return GET_UINT24(rawBytecode_);
239
}
240
241
uint8_t getPickDepth() const {
242
MOZ_ASSERT(is(JSOp::Pick));
243
return GET_UINT8(rawBytecode_);
244
}
245
uint8_t getUnpickDepth() const {
246
MOZ_ASSERT(is(JSOp::Unpick));
247
return GET_UINT8(rawBytecode_);
248
}
249
250
uint32_t getEnvCalleeNumHops() const {
251
MOZ_ASSERT(is(JSOp::EnvCallee));
252
return GET_UINT8(rawBytecode_);
253
}
254
255
EnvironmentCoordinate getEnvironmentCoordinate() const {
256
MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ENVCOORD);
257
return EnvironmentCoordinate(rawBytecode_);
258
}
259
260
uint32_t getCallArgc() const {
261
MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ARGC);
262
return GET_ARGC(rawBytecode_);
263
}
264
265
uint32_t getInitElemArrayIndex() const {
266
MOZ_ASSERT(is(JSOp::InitElemArray));
267
uint32_t index = GET_UINT32(rawBytecode_);
268
MOZ_ASSERT(index <= INT32_MAX,
269
"the bytecode emitter must never generate JSOp::InitElemArray "
270
"with an index exceeding int32_t range");
271
return index;
272
}
273
274
FunctionPrefixKind getFunctionPrefixKind() const {
275
MOZ_ASSERT(is(JSOp::SetFunName));
276
return FunctionPrefixKind(GET_UINT8(rawBytecode_));
277
}
278
279
CheckIsObjectKind getCheckIsObjectKind() const {
280
MOZ_ASSERT(is(JSOp::CheckIsObj));
281
return CheckIsObjectKind(GET_UINT8(rawBytecode_));
282
}
283
CheckIsCallableKind getCheckIsCallableKind() const {
284
MOZ_ASSERT(is(JSOp::CheckIsCallable));
285
return CheckIsCallableKind(GET_UINT8(rawBytecode_));
286
}
287
288
uint32_t getNewArrayLength() const {
289
MOZ_ASSERT(is(JSOp::NewArray));
290
return GET_UINT32(rawBytecode_);
291
}
292
293
int8_t getInt8() const {
294
MOZ_ASSERT(is(JSOp::Int8));
295
return GET_INT8(rawBytecode_);
296
}
297
uint16_t getUint16() const {
298
MOZ_ASSERT(is(JSOp::Uint16));
299
return GET_UINT16(rawBytecode_);
300
}
301
uint32_t getUint24() const {
302
MOZ_ASSERT(is(JSOp::Uint24));
303
return GET_UINT24(rawBytecode_);
304
}
305
int32_t getInt32() const {
306
MOZ_ASSERT(is(JSOp::Int32));
307
return GET_INT32(rawBytecode_);
308
}
309
uint32_t getResumeIndex() const {
310
MOZ_ASSERT(is(JSOp::ResumeIndex));
311
return GET_RESUMEINDEX(rawBytecode_);
312
}
313
Value getInlineValue() const {
314
MOZ_ASSERT(is(JSOp::Double));
315
return GET_INLINE_VALUE(rawBytecode_);
316
}
317
318
#ifdef DEBUG
319
// To ease writing assertions
320
bool isValid() const { return isValid(debugOnlyScript_); }
321
322
bool isInBounds() const { return isInBounds(debugOnlyScript_); }
323
#endif
324
};
325
326
} // namespace js
327
328
#endif