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/. */
7 #ifndef vm_BytecodeLocation_h
8 #define vm_BytecodeLocation_h
10 #include "frontend/NameAnalysisTypes.h"
11 #include "js/TypeDecls.h"
12 #include "vm/AsyncFunctionResolveKind.h"
13 #include "vm/BuiltinObjectKind.h"
14 #include "vm/BytecodeUtil.h"
15 #include "vm/CheckIsObjectKind.h" // CheckIsObjectKind
16 #include "vm/CompletionKind.h" // CompletionKind
17 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
18 #include "vm/GeneratorResumeKind.h"
22 using RawBytecodeLocationOffset
= uint32_t;
27 class BytecodeLocationOffset
{
28 RawBytecodeLocationOffset rawOffset_
;
31 explicit BytecodeLocationOffset(RawBytecodeLocationOffset offset
)
32 : rawOffset_(offset
) {}
34 RawBytecodeLocationOffset
rawOffset() const { return rawOffset_
; }
37 using RawBytecode
= jsbytecode
*;
39 // A immutable representation of a program location
41 class BytecodeLocation
{
42 RawBytecode rawBytecode_
;
44 const JSScript
* debugOnlyScript_
;
47 // Construct a new BytecodeLocation, while borrowing scriptIdentity
48 // from some other BytecodeLocation.
49 BytecodeLocation(const BytecodeLocation
& loc
, RawBytecode pc
)
53 debugOnlyScript_(loc
.debugOnlyScript_
)
56 MOZ_ASSERT(isValid());
60 // Disallow the creation of an uninitialized location.
61 BytecodeLocation() = delete;
63 BytecodeLocation(const JSScript
* script
, RawBytecode pc
)
67 debugOnlyScript_(script
)
70 MOZ_ASSERT(isValid());
73 RawBytecode
toRawBytecode() const { return rawBytecode_
; }
76 // Return true if this bytecode location is valid for the given script.
77 // This includes the location 1-past the end of the bytecode.
78 bool isValid(const JSScript
* script
) const;
80 // Return true if this bytecode location is within the bounds of the
81 // bytecode for a given script.
82 bool isInBounds(const JSScript
* script
) const;
84 const JSScript
* getDebugOnlyScript() const;
87 inline uint32_t bytecodeToOffset(const JSScript
* script
) const;
89 inline uint32_t tableSwitchCaseOffset(const JSScript
* script
,
90 uint32_t caseIndex
) const;
92 inline uint32_t getJumpTargetOffset(const JSScript
* script
) const;
94 inline uint32_t getTableSwitchDefaultOffset(const JSScript
* script
) const;
96 inline BytecodeLocation
getTableSwitchDefaultTarget() const;
97 inline BytecodeLocation
getTableSwitchCaseTarget(const JSScript
* script
,
98 uint32_t caseIndex
) const;
100 inline uint32_t useCount() const;
101 inline uint32_t defCount() const;
103 int32_t jumpOffset() const { return GET_JUMP_OFFSET(rawBytecode_
); }
105 inline JSAtom
* getAtom(const JSScript
* script
) const;
106 inline JSString
* getString(const JSScript
* script
) const;
107 inline PropertyName
* getPropertyName(const JSScript
* script
) const;
108 inline JS::BigInt
* getBigInt(const JSScript
* script
) const;
109 inline JSObject
* getObject(const JSScript
* script
) const;
110 inline JSFunction
* getFunction(const JSScript
* script
) const;
111 inline js::RegExpObject
* getRegExp(const JSScript
* script
) const;
112 inline js::Scope
* getScope(const JSScript
* script
) const;
114 uint32_t getSymbolIndex() const {
115 MOZ_ASSERT(is(JSOp::Symbol
));
116 return GET_UINT8(rawBytecode_
);
119 inline Scope
* innermostScope(const JSScript
* script
) const;
122 bool hasSameScript(const BytecodeLocation
& other
) const {
123 return debugOnlyScript_
== other
.debugOnlyScript_
;
127 // Overloaded operators
129 bool operator==(const BytecodeLocation
& other
) const {
130 MOZ_ASSERT(this->debugOnlyScript_
== other
.debugOnlyScript_
);
131 return rawBytecode_
== other
.rawBytecode_
;
134 bool operator!=(const BytecodeLocation
& other
) const {
135 return !(other
== *this);
138 bool operator<(const BytecodeLocation
& other
) const {
139 MOZ_ASSERT(this->debugOnlyScript_
== other
.debugOnlyScript_
);
140 return rawBytecode_
< other
.rawBytecode_
;
143 // It is traditional to represent the rest of the relational operators
144 // using operator<, so we don't need to assert for these.
145 bool operator>(const BytecodeLocation
& other
) const { return other
< *this; }
147 bool operator<=(const BytecodeLocation
& other
) const {
148 return !(other
< *this);
151 bool operator>=(const BytecodeLocation
& other
) const {
152 return !(*this < other
);
155 // Return the next bytecode
156 BytecodeLocation
next() const {
157 return BytecodeLocation(*this,
158 rawBytecode_
+ GetBytecodeLength(rawBytecode_
));
162 BytecodeLocation
operator+(const BytecodeLocationOffset
& offset
) const {
163 return BytecodeLocation(*this, rawBytecode_
+ offset
.rawOffset());
167 bool is(JSOp op
) const {
168 MOZ_ASSERT(isInBounds());
169 return getOp() == op
;
174 uint32_t length() const { return GetBytecodeLength(rawBytecode_
); }
176 bool isJumpTarget() const { return BytecodeIsJumpTarget(getOp()); }
178 bool isJump() const { return IsJumpOpcode(getOp()); }
180 bool isBackedge() const { return IsBackedgePC(rawBytecode_
); }
182 bool isBackedgeForLoophead(BytecodeLocation loopHead
) const {
183 return IsBackedgeForLoopHead(rawBytecode_
, loopHead
.rawBytecode_
);
186 bool opHasIC() const { return BytecodeOpHasIC(getOp()); }
188 bool fallsThrough() const { return BytecodeFallsThrough(getOp()); }
190 uint32_t icIndex() const { return GET_ICINDEX(rawBytecode_
); }
192 uint32_t local() const { return GET_LOCALNO(rawBytecode_
); }
194 uint16_t arg() const { return GET_ARGNO(rawBytecode_
); }
196 bool isEqualityOp() const { return IsEqualityOp(getOp()); }
198 bool isStrictEqualityOp() const { return IsStrictEqualityOp(getOp()); }
200 bool isStrictSetOp() const { return IsStrictSetPC(rawBytecode_
); }
202 bool isNameOp() const { return IsNameOp(getOp()); }
204 bool isSpreadOp() const { return IsSpreadOp(getOp()); }
206 bool isInvokeOp() const { return IsInvokeOp(getOp()); }
208 bool isGetPropOp() const { return IsGetPropOp(getOp()); }
209 bool isGetElemOp() const { return IsGetElemOp(getOp()); }
211 bool isSetPropOp() const { return IsSetPropOp(getOp()); }
212 bool isSetElemOp() const { return IsSetElemOp(getOp()); }
214 AsyncFunctionResolveKind
getAsyncFunctionResolveKind() {
215 return AsyncFunctionResolveKind(GET_UINT8(rawBytecode_
));
218 bool resultIsPopped() const {
219 MOZ_ASSERT(StackDefs(getOp()) == 1);
220 return BytecodeIsPopped(rawBytecode_
);
224 JSOp
getOp() const { return JSOp(*rawBytecode_
); }
226 BytecodeLocation
getJumpTarget() const {
227 MOZ_ASSERT(isJump());
228 return BytecodeLocation(*this,
229 rawBytecode_
+ GET_JUMP_OFFSET(rawBytecode_
));
232 // Return the 'low' parameter to the tableswitch opcode
233 int32_t getTableSwitchLow() const {
234 MOZ_ASSERT(is(JSOp::TableSwitch
));
235 return GET_JUMP_OFFSET(rawBytecode_
+ JUMP_OFFSET_LEN
);
238 // Return the 'high' parameter to the tableswitch opcode
239 int32_t getTableSwitchHigh() const {
240 MOZ_ASSERT(is(JSOp::TableSwitch
));
241 return GET_JUMP_OFFSET(rawBytecode_
+ (2 * JUMP_OFFSET_LEN
));
244 uint32_t getPopCount() const {
245 MOZ_ASSERT(is(JSOp::PopN
));
246 return GET_UINT16(rawBytecode_
);
249 uint32_t getDupAtIndex() const {
250 MOZ_ASSERT(is(JSOp::DupAt
));
251 return GET_UINT24(rawBytecode_
);
254 uint8_t getPickDepth() const {
255 MOZ_ASSERT(is(JSOp::Pick
));
256 return GET_UINT8(rawBytecode_
);
258 uint8_t getUnpickDepth() const {
259 MOZ_ASSERT(is(JSOp::Unpick
));
260 return GET_UINT8(rawBytecode_
);
263 uint32_t getEnvCalleeNumHops() const {
264 MOZ_ASSERT(is(JSOp::EnvCallee
));
265 return GET_UINT8(rawBytecode_
);
268 EnvironmentCoordinate
getEnvironmentCoordinate() const {
269 MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ENVCOORD
);
270 return EnvironmentCoordinate(rawBytecode_
);
273 uint32_t getCallArgc() const {
274 MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ARGC
);
275 return GET_ARGC(rawBytecode_
);
278 uint32_t getInitElemArrayIndex() const {
279 MOZ_ASSERT(is(JSOp::InitElemArray
));
280 uint32_t index
= GET_UINT32(rawBytecode_
);
281 MOZ_ASSERT(index
<= INT32_MAX
,
282 "the bytecode emitter must never generate JSOp::InitElemArray "
283 "with an index exceeding int32_t range");
287 FunctionPrefixKind
getFunctionPrefixKind() const {
288 MOZ_ASSERT(is(JSOp::SetFunName
));
289 return FunctionPrefixKind(GET_UINT8(rawBytecode_
));
292 CheckIsObjectKind
getCheckIsObjectKind() const {
293 MOZ_ASSERT(is(JSOp::CheckIsObj
));
294 return CheckIsObjectKind(GET_UINT8(rawBytecode_
));
297 BuiltinObjectKind
getBuiltinObjectKind() const {
298 MOZ_ASSERT(is(JSOp::BuiltinObject
));
299 return BuiltinObjectKind(GET_UINT8(rawBytecode_
));
302 CompletionKind
getCompletionKind() const {
303 MOZ_ASSERT(is(JSOp::CloseIter
));
304 return CompletionKind(GET_UINT8(rawBytecode_
));
307 uint32_t getNewArrayLength() const {
308 MOZ_ASSERT(is(JSOp::NewArray
));
309 return GET_UINT32(rawBytecode_
);
312 int8_t getInt8() const {
313 MOZ_ASSERT(is(JSOp::Int8
));
314 return GET_INT8(rawBytecode_
);
316 uint16_t getUint16() const {
317 MOZ_ASSERT(is(JSOp::Uint16
));
318 return GET_UINT16(rawBytecode_
);
320 uint32_t getUint24() const {
321 MOZ_ASSERT(is(JSOp::Uint24
));
322 return GET_UINT24(rawBytecode_
);
324 int32_t getInt32() const {
325 MOZ_ASSERT(is(JSOp::Int32
));
326 return GET_INT32(rawBytecode_
);
328 uint32_t getResumeIndex() const {
329 MOZ_ASSERT(is(JSOp::InitialYield
) || is(JSOp::Yield
) || is(JSOp::Await
));
330 return GET_RESUMEINDEX(rawBytecode_
);
332 Value
getInlineValue() const {
333 MOZ_ASSERT(is(JSOp::Double
));
334 return GET_INLINE_VALUE(rawBytecode_
);
337 GeneratorResumeKind
resumeKind() { return ResumeKindFromPC(rawBytecode_
); }
339 ThrowMsgKind
throwMsgKind() {
340 MOZ_ASSERT(is(JSOp::ThrowMsg
));
341 return static_cast<ThrowMsgKind
>(GET_UINT8(rawBytecode_
));
345 // To ease writing assertions
346 bool isValid() const { return isValid(debugOnlyScript_
); }
348 bool isInBounds() const { return isInBounds(debugOnlyScript_
); }