BytecodeLocation.h (10772B)
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 <compare> // std::strong_ordering 11 12 #include "frontend/NameAnalysisTypes.h" 13 #include "js/TypeDecls.h" 14 #include "vm/BuiltinObjectKind.h" 15 #include "vm/BytecodeUtil.h" // GET_ENVCOORD_HOPS 16 #include "vm/CheckIsObjectKind.h" // CheckIsObjectKind 17 #include "vm/CompletionKind.h" // CompletionKind 18 #include "vm/ConstantCompareOperand.h" // ConstantCompareOperand 19 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind 20 #include "vm/GeneratorResumeKind.h" 21 #include "vm/TypeofEqOperand.h" // TypeofEqOperand 22 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 23 # include "vm/UsingHint.h" 24 #endif 25 26 namespace js { 27 28 using RawBytecodeLocationOffset = uint32_t; 29 30 class PropertyName; 31 class RegExpObject; 32 33 class BytecodeLocationOffset { 34 RawBytecodeLocationOffset rawOffset_; 35 36 public: 37 explicit BytecodeLocationOffset(RawBytecodeLocationOffset offset) 38 : rawOffset_(offset) {} 39 40 RawBytecodeLocationOffset rawOffset() const { return rawOffset_; } 41 }; 42 43 using RawBytecode = jsbytecode*; 44 45 // A immutable representation of a program location 46 // 47 class BytecodeLocation { 48 RawBytecode rawBytecode_; 49 #ifdef DEBUG 50 const JSScript* debugOnlyScript_; 51 #endif 52 53 // Construct a new BytecodeLocation, while borrowing scriptIdentity 54 // from some other BytecodeLocation. 55 BytecodeLocation(const BytecodeLocation& loc, RawBytecode pc) 56 : rawBytecode_(pc) 57 #ifdef DEBUG 58 , 59 debugOnlyScript_(loc.debugOnlyScript_) 60 #endif 61 { 62 MOZ_ASSERT(isValid()); 63 } 64 65 public: 66 // Disallow the creation of an uninitialized location. 67 BytecodeLocation() = delete; 68 69 BytecodeLocation(const JSScript* script, RawBytecode pc) 70 : rawBytecode_(pc) 71 #ifdef DEBUG 72 , 73 debugOnlyScript_(script) 74 #endif 75 { 76 MOZ_ASSERT(isValid()); 77 } 78 79 RawBytecode toRawBytecode() const { return rawBytecode_; } 80 81 #ifdef DEBUG 82 // Return true if this bytecode location is valid for the given script. 83 // This includes the location 1-past the end of the bytecode. 84 bool isValid(const JSScript* script) const; 85 86 // Return true if this bytecode location is within the bounds of the 87 // bytecode for a given script. 88 bool isInBounds(const JSScript* script) const; 89 90 const JSScript* getDebugOnlyScript() const; 91 #endif 92 93 inline uint32_t bytecodeToOffset(const JSScript* script) const; 94 95 inline uint32_t tableSwitchCaseOffset(const JSScript* script, 96 uint32_t caseIndex) const; 97 98 inline uint32_t getJumpTargetOffset(const JSScript* script) const; 99 100 inline uint32_t getTableSwitchDefaultOffset(const JSScript* script) const; 101 102 inline BytecodeLocation getTableSwitchDefaultTarget() const; 103 inline BytecodeLocation getTableSwitchCaseTarget(const JSScript* script, 104 uint32_t caseIndex) const; 105 106 inline uint32_t useCount() const; 107 inline uint32_t defCount() const; 108 109 int32_t jumpOffset() const { return GET_JUMP_OFFSET(rawBytecode_); } 110 111 inline JSAtom* getAtom(const JSScript* script) const; 112 inline JSString* getString(const JSScript* script) const; 113 inline bool atomizeString(JSContext* cx, JSScript* script); 114 inline PropertyName* getPropertyName(const JSScript* script) const; 115 inline JS::BigInt* getBigInt(const JSScript* script) const; 116 inline JSObject* getObject(const JSScript* script) const; 117 inline JSFunction* getFunction(const JSScript* script) const; 118 inline js::RegExpObject* getRegExp(const JSScript* script) const; 119 inline js::Scope* getScope(const JSScript* script) const; 120 121 uint32_t getSymbolIndex() const { 122 MOZ_ASSERT(is(JSOp::Symbol)); 123 return GET_UINT8(rawBytecode_); 124 } 125 126 inline Scope* innermostScope(const JSScript* script) const; 127 128 #ifdef DEBUG 129 bool hasSameScript(const BytecodeLocation& other) const { 130 return debugOnlyScript_ == other.debugOnlyScript_; 131 } 132 #endif 133 134 // Overloaded operators 135 136 bool operator==(const BytecodeLocation& other) const { 137 MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_); 138 return rawBytecode_ == other.rawBytecode_; 139 } 140 141 bool operator!=(const BytecodeLocation& other) const { 142 return !(other == *this); 143 } 144 145 auto operator<=>(const BytecodeLocation& other) const { 146 MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_); 147 return rawBytecode_ <=> other.rawBytecode_; 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) const { 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 opHasIC() const { return BytecodeOpHasIC(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 isSpreadOp() const { return IsSpreadOp(getOp()); } 198 199 bool isInvokeOp() const { return IsInvokeOp(getOp()); } 200 201 bool isGetPropOp() const { return IsGetPropOp(getOp()); } 202 bool isGetElemOp() const { return IsGetElemOp(getOp()); } 203 204 bool isSetPropOp() const { return IsSetPropOp(getOp()); } 205 bool isSetElemOp() const { return IsSetElemOp(getOp()); } 206 207 bool resultIsPopped() const { 208 MOZ_ASSERT(StackDefs(getOp()) == 1); 209 return BytecodeIsPopped(rawBytecode_); 210 } 211 212 // Accessors: 213 JSOp getOp() const { return JSOp(*rawBytecode_); } 214 215 BytecodeLocation getJumpTarget() const { 216 MOZ_ASSERT(isJump()); 217 return BytecodeLocation(*this, 218 rawBytecode_ + GET_JUMP_OFFSET(rawBytecode_)); 219 } 220 221 // Return the 'low' parameter to the tableswitch opcode 222 int32_t getTableSwitchLow() const { 223 MOZ_ASSERT(is(JSOp::TableSwitch)); 224 return GET_JUMP_OFFSET(rawBytecode_ + JUMP_OFFSET_LEN); 225 } 226 227 // Return the 'high' parameter to the tableswitch opcode 228 int32_t getTableSwitchHigh() const { 229 MOZ_ASSERT(is(JSOp::TableSwitch)); 230 return GET_JUMP_OFFSET(rawBytecode_ + (2 * JUMP_OFFSET_LEN)); 231 } 232 233 uint32_t getPopCount() const { 234 MOZ_ASSERT(is(JSOp::PopN)); 235 return GET_UINT16(rawBytecode_); 236 } 237 238 uint32_t getDupAtIndex() const { 239 MOZ_ASSERT(is(JSOp::DupAt)); 240 return GET_UINT24(rawBytecode_); 241 } 242 243 uint8_t getPickDepth() const { 244 MOZ_ASSERT(is(JSOp::Pick)); 245 return GET_UINT8(rawBytecode_); 246 } 247 uint8_t getUnpickDepth() const { 248 MOZ_ASSERT(is(JSOp::Unpick)); 249 return GET_UINT8(rawBytecode_); 250 } 251 252 uint32_t getEnvCalleeNumHops() const { 253 MOZ_ASSERT(is(JSOp::EnvCallee)); 254 return GET_ENVCOORD_HOPS(rawBytecode_); 255 } 256 257 EnvironmentCoordinate getEnvironmentCoordinate() const { 258 MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ENVCOORD); 259 return EnvironmentCoordinate(rawBytecode_); 260 } 261 262 uint32_t getCallArgc() const { 263 MOZ_ASSERT(JOF_OPTYPE(getOp()) == JOF_ARGC); 264 return GET_ARGC(rawBytecode_); 265 } 266 267 uint32_t getInitElemArrayIndex() const { 268 MOZ_ASSERT(is(JSOp::InitElemArray)); 269 uint32_t index = GET_UINT32(rawBytecode_); 270 MOZ_ASSERT(index <= INT32_MAX, 271 "the bytecode emitter must never generate JSOp::InitElemArray " 272 "with an index exceeding int32_t range"); 273 return index; 274 } 275 276 TypeofEqOperand getTypeofEqOperand() const { 277 MOZ_ASSERT(is(JSOp::TypeofEq)); 278 return TypeofEqOperand::fromRawValue(GET_UINT8(rawBytecode_)); 279 } 280 281 ConstantCompareOperand getConstantCompareOperand() const { 282 MOZ_ASSERT(is(JSOp::StrictConstantEq) || is(JSOp::StrictConstantNe)); 283 return ConstantCompareOperand::fromRawValue(GET_UINT16(rawBytecode_)); 284 } 285 286 FunctionPrefixKind getFunctionPrefixKind() const { 287 MOZ_ASSERT(is(JSOp::SetFunName)); 288 return FunctionPrefixKind(GET_UINT8(rawBytecode_)); 289 } 290 291 CheckIsObjectKind getCheckIsObjectKind() const { 292 MOZ_ASSERT(is(JSOp::CheckIsObj)); 293 return CheckIsObjectKind(GET_UINT8(rawBytecode_)); 294 } 295 296 BuiltinObjectKind getBuiltinObjectKind() const { 297 MOZ_ASSERT(is(JSOp::BuiltinObject)); 298 return BuiltinObjectKind(GET_UINT8(rawBytecode_)); 299 } 300 301 CompletionKind getCompletionKind() const { 302 MOZ_ASSERT(is(JSOp::CloseIter)); 303 return CompletionKind(GET_UINT8(rawBytecode_)); 304 } 305 306 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 307 UsingHint getUsingHint() const { 308 MOZ_ASSERT(is(JSOp::AddDisposable)); 309 return UsingHint(GET_UINT8(rawBytecode_)); 310 } 311 #endif 312 313 uint32_t getNewArrayLength() const { 314 MOZ_ASSERT(is(JSOp::NewArray)); 315 return GET_UINT32(rawBytecode_); 316 } 317 318 int8_t getInt8() const { 319 MOZ_ASSERT(is(JSOp::Int8)); 320 return GET_INT8(rawBytecode_); 321 } 322 uint16_t getUint16() const { 323 MOZ_ASSERT(is(JSOp::Uint16)); 324 return GET_UINT16(rawBytecode_); 325 } 326 uint32_t getUint24() const { 327 MOZ_ASSERT(is(JSOp::Uint24)); 328 return GET_UINT24(rawBytecode_); 329 } 330 int32_t getInt32() const { 331 MOZ_ASSERT(is(JSOp::Int32)); 332 return GET_INT32(rawBytecode_); 333 } 334 uint32_t getResumeIndex() const { 335 MOZ_ASSERT(is(JSOp::InitialYield) || is(JSOp::Yield) || is(JSOp::Await)); 336 return GET_RESUMEINDEX(rawBytecode_); 337 } 338 Value getInlineValue() const { 339 MOZ_ASSERT(is(JSOp::Double)); 340 return GET_INLINE_VALUE(rawBytecode_); 341 } 342 343 GeneratorResumeKind resumeKind() { return ResumeKindFromPC(rawBytecode_); } 344 345 ThrowMsgKind throwMsgKind() { 346 MOZ_ASSERT(is(JSOp::ThrowMsg)); 347 return static_cast<ThrowMsgKind>(GET_UINT8(rawBytecode_)); 348 } 349 350 #ifdef DEBUG 351 // To ease writing assertions 352 bool isValid() const { return isValid(debugOnlyScript_); } 353 354 bool isInBounds() const { return isInBounds(debugOnlyScript_); } 355 #endif 356 }; 357 358 } // namespace js 359 360 #endif