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 "js/TypeDecls.h"
11 #include "vm/BytecodeUtil.h"
15 typedef uint32_t RawBytecodeLocationOffset
;
17 class BytecodeLocationOffset
{
18 RawBytecodeLocationOffset rawOffset_
;
21 explicit BytecodeLocationOffset(RawBytecodeLocationOffset offset
)
22 : rawOffset_(offset
) {}
24 RawBytecodeLocationOffset
rawOffset() const { return rawOffset_
; }
27 typedef jsbytecode
* RawBytecode
;
29 // A immutable representation of a program location
31 class BytecodeLocation
{
32 RawBytecode rawBytecode_
;
34 const JSScript
* debugOnlyScript_
;
37 // Construct a new BytecodeLocation, while borrowing scriptIdentity
38 // from some other BytecodeLocation.
39 BytecodeLocation(const BytecodeLocation
& loc
, RawBytecode pc
)
43 debugOnlyScript_(loc
.debugOnlyScript_
)
46 MOZ_ASSERT(isValid());
50 BytecodeLocation(const JSScript
* script
, RawBytecode pc
)
54 debugOnlyScript_(script
)
57 MOZ_ASSERT(isValid());
60 RawBytecode
toRawBytecode() const { return rawBytecode_
; }
62 // Return true if this bytecode location is valid for the given script.
63 // This includes the location 1-past the end of the bytecode.
64 bool isValid(const JSScript
* script
) const;
66 // Return true if this bytecode location is within the bounds of the
67 // bytecode for a given script.
68 bool isInBounds(const JSScript
* script
) const;
70 uint32_t bytecodeToOffset(JSScript
* script
);
72 bool operator==(const BytecodeLocation
& other
) const {
73 MOZ_ASSERT(this->debugOnlyScript_
== other
.debugOnlyScript_
);
74 return rawBytecode_
== other
.rawBytecode_
;
77 bool operator!=(const BytecodeLocation
& other
) const {
78 return !(other
== *this);
81 bool operator<(const BytecodeLocation
& other
) const {
82 MOZ_ASSERT(this->debugOnlyScript_
== other
.debugOnlyScript_
);
83 return rawBytecode_
< other
.rawBytecode_
;
86 // It is traditional to represent the rest of the relational operators
87 // using operator<, so we don't need to assert for these.
88 bool operator>(const BytecodeLocation
& other
) const { return other
< *this; }
90 bool operator<=(const BytecodeLocation
& other
) const {
91 return !(other
< *this);
94 bool operator>=(const BytecodeLocation
& other
) const {
95 return !(*this < other
);
98 // Return the next bytecode
99 BytecodeLocation
next() const {
100 return BytecodeLocation(*this,
101 rawBytecode_
+ GetBytecodeLength(rawBytecode_
));
105 BytecodeLocation
operator+(const BytecodeLocationOffset
& offset
) {
106 return BytecodeLocation(*this, rawBytecode_
+ offset
.rawOffset());
110 bool is(JSOp op
) const {
111 MOZ_ASSERT(isInBounds());
112 return getOp() == op
;
115 bool isJumpTarget() const { return BytecodeIsJumpTarget(getOp()); }
117 bool isJump() const { return IsJumpOpcode(getOp()); }
119 bool fallsThrough() const { return BytecodeFallsThrough(getOp()); }
121 uint32_t icIndex() const { return GET_ICINDEX(rawBytecode_
); }
124 JSOp
getOp() const { return JSOp(*rawBytecode_
); }
126 BytecodeLocation
getJumpTarget() const {
127 // The default target of a JSOP_TABLESWITCH also follows this format.
128 MOZ_ASSERT(isJump() || is(JSOP_TABLESWITCH
));
129 return BytecodeLocation(*this,
130 rawBytecode_
+ GET_JUMP_OFFSET(rawBytecode_
));
133 // Return the 'low' parameter to the tableswitch opcode
134 int32_t getTableSwitchLow() const {
135 MOZ_ASSERT(is(JSOP_TABLESWITCH
));
136 return GET_JUMP_OFFSET(rawBytecode_
+ JUMP_OFFSET_LEN
);
139 // Return the 'high' parameter to the tableswitch opcode
140 int32_t getTableSwitchHigh() const {
141 MOZ_ASSERT(is(JSOP_TABLESWITCH
));
142 return GET_JUMP_OFFSET(rawBytecode_
+ (2 * JUMP_OFFSET_LEN
));
146 // To ease writing assertions
147 bool isValid() const { return isValid(debugOnlyScript_
); }
149 bool isInBounds() const { return isInBounds(debugOnlyScript_
); }