tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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