tor-browser

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

WasmOpIter.h (133443B)


      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 *
      4 * Copyright 2016 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 #ifndef wasm_op_iter_h
     20 #define wasm_op_iter_h
     21 
     22 #include "mozilla/CompactPair.h"
     23 
     24 #include <type_traits>
     25 
     26 #include "js/Printf.h"
     27 #include "wasm/WasmBinary.h"
     28 #include "wasm/WasmBuiltinModule.h"
     29 #include "wasm/WasmMetadata.h"
     30 #include "wasm/WasmUtility.h"
     31 
     32 namespace js {
     33 namespace wasm {
     34 
     35 // The kind of a control-flow stack item.
     36 enum class LabelKind : uint8_t {
     37  Body,
     38  Block,
     39  Loop,
     40  Then,
     41  Else,
     42  Try,
     43  Catch,
     44  CatchAll,
     45  TryTable,
     46 };
     47 
     48 // The type of values on the operand stack during validation.  This is either a
     49 // ValType or the special type "Bottom".
     50 
     51 class StackType {
     52  PackedTypeCode tc_;
     53 
     54  explicit StackType(PackedTypeCode tc) : tc_(tc) {}
     55 
     56 public:
     57  StackType() : tc_(PackedTypeCode::invalid()) {}
     58 
     59  explicit StackType(const ValType& t) : tc_(t.packed()) {
     60    MOZ_ASSERT(tc_.isValid());
     61    MOZ_ASSERT(!isStackBottom());
     62  }
     63 
     64  static StackType bottom() {
     65    return StackType(PackedTypeCode::pack(TypeCode::Limit));
     66  }
     67 
     68  bool isStackBottom() const {
     69    MOZ_ASSERT(tc_.isValid());
     70    return tc_.typeCode() == TypeCode::Limit;
     71  }
     72 
     73  // Returns whether this input is nullable when interpreted as an operand.
     74  // When the type is bottom for unreachable code, this returns false as that
     75  // is the most permissive option.
     76  bool isNullableAsOperand() const {
     77    MOZ_ASSERT(tc_.isValid());
     78    return isStackBottom() ? false : tc_.isNullable();
     79  }
     80 
     81  ValType valType() const {
     82    MOZ_ASSERT(tc_.isValid());
     83    MOZ_ASSERT(!isStackBottom());
     84    return ValType(tc_);
     85  }
     86 
     87  ValType valTypeOr(ValType ifBottom) const {
     88    MOZ_ASSERT(tc_.isValid());
     89    if (isStackBottom()) {
     90      return ifBottom;
     91    }
     92    return valType();
     93  }
     94 
     95  ValType asNonNullable() const {
     96    MOZ_ASSERT(tc_.isValid());
     97    MOZ_ASSERT(!isStackBottom());
     98    return ValType(tc_.withIsNullable(false));
     99  }
    100 
    101  bool isValidForUntypedSelect() const {
    102    MOZ_ASSERT(tc_.isValid());
    103    if (isStackBottom()) {
    104      return true;
    105    }
    106    switch (valType().kind()) {
    107      case ValType::I32:
    108      case ValType::F32:
    109      case ValType::I64:
    110      case ValType::F64:
    111 #ifdef ENABLE_WASM_SIMD
    112      case ValType::V128:
    113 #endif
    114        return true;
    115      default:
    116        return false;
    117    }
    118  }
    119 
    120  bool operator==(const StackType& that) const {
    121    MOZ_ASSERT(tc_.isValid() && that.tc_.isValid());
    122    return tc_ == that.tc_;
    123  }
    124 
    125  bool operator!=(const StackType& that) const {
    126    MOZ_ASSERT(tc_.isValid() && that.tc_.isValid());
    127    return tc_ != that.tc_;
    128  }
    129 };
    130 
    131 #ifdef DEBUG
    132 // Families of opcodes that share a signature and validation logic.
    133 enum class OpKind {
    134  Block,
    135  Loop,
    136  Unreachable,
    137  Drop,
    138  I32Const,
    139  I64Const,
    140  F32Const,
    141  F64Const,
    142  V128Const,
    143  Br,
    144  BrIf,
    145  BrTable,
    146  Nop,
    147  Unary,
    148  Binary,
    149  Ternary,
    150  Comparison,
    151  Conversion,
    152  Load,
    153  Store,
    154  TeeStore,
    155  MemorySize,
    156  MemoryGrow,
    157  Select,
    158  GetLocal,
    159  SetLocal,
    160  TeeLocal,
    161  GetGlobal,
    162  SetGlobal,
    163  TeeGlobal,
    164  Call,
    165  ReturnCall,
    166  CallIndirect,
    167  ReturnCallIndirect,
    168  CallRef,
    169  ReturnCallRef,
    170  OldCallDirect,
    171  OldCallIndirect,
    172  Return,
    173  If,
    174  Else,
    175  End,
    176  Wait,
    177  Notify,
    178  Fence,
    179  AtomicLoad,
    180  AtomicStore,
    181  AtomicRMW,
    182  AtomicCmpXchg,
    183  MemOrTableCopy,
    184  DataOrElemDrop,
    185  MemFill,
    186  MemOrTableInit,
    187  TableFill,
    188  MemDiscard,
    189  TableGet,
    190  TableGrow,
    191  TableSet,
    192  TableSize,
    193  RefNull,
    194  RefFunc,
    195  RefIsNull,
    196  RefAsNonNull,
    197  BrOnNull,
    198  BrOnNonNull,
    199  StructNew,
    200  StructNewDefault,
    201  StructGet,
    202  StructSet,
    203  ArrayNew,
    204  ArrayNewFixed,
    205  ArrayNewDefault,
    206  ArrayNewData,
    207  ArrayNewElem,
    208  ArrayInitData,
    209  ArrayInitElem,
    210  ArrayGet,
    211  ArraySet,
    212  ArrayLen,
    213  ArrayCopy,
    214  ArrayFill,
    215  RefTest,
    216  RefCast,
    217  BrOnCast,
    218  RefConversion,
    219 #  ifdef ENABLE_WASM_SIMD
    220  ExtractLane,
    221  ReplaceLane,
    222  LoadLane,
    223  StoreLane,
    224  VectorShift,
    225  VectorShuffle,
    226 #  endif
    227  Catch,
    228  CatchAll,
    229  Delegate,
    230  Throw,
    231  ThrowRef,
    232  Rethrow,
    233  Try,
    234  TryTable,
    235  CallBuiltinModuleFunc,
    236  StackSwitch,
    237 };
    238 
    239 // Return the OpKind for a given Op. This is used for sanity-checking that
    240 // API users use the correct read function for a given Op.
    241 OpKind Classify(OpBytes op);
    242 #endif
    243 
    244 // Common fields for linear memory access.
    245 template <typename Value>
    246 struct LinearMemoryAddress {
    247  Value base;
    248  uint32_t memoryIndex;
    249  uint64_t offset;
    250  uint32_t align;
    251 
    252  LinearMemoryAddress() : memoryIndex(0), offset(0), align(0) {}
    253  LinearMemoryAddress(Value base, uint32_t memoryIndex, uint64_t offset,
    254                      uint32_t align)
    255      : base(base), memoryIndex(memoryIndex), offset(offset), align(align) {}
    256 };
    257 
    258 template <typename ControlItem>
    259 class ControlStackEntry {
    260  // Use a pair to optimize away empty ControlItem.
    261  mozilla::CompactPair<BlockType, ControlItem> typeAndItem_;
    262 
    263  // The "base" of a control stack entry is valueStack_.length() minus
    264  // type().params().length(), i.e., the size of the value stack "below"
    265  // this block.
    266  uint32_t valueStackBase_;
    267  bool polymorphicBase_;
    268 
    269  LabelKind kind_;
    270 
    271 public:
    272  ControlStackEntry(LabelKind kind, BlockType type, uint32_t valueStackBase)
    273      : typeAndItem_(type, ControlItem()),
    274        valueStackBase_(valueStackBase),
    275        polymorphicBase_(false),
    276        kind_(kind) {
    277    MOZ_ASSERT(type != BlockType());
    278  }
    279 
    280  LabelKind kind() const { return kind_; }
    281  BlockType type() const { return typeAndItem_.first(); }
    282  ResultType resultType() const { return type().results(); }
    283  ResultType branchTargetType() const {
    284    return kind_ == LabelKind::Loop ? type().params() : type().results();
    285  }
    286  uint32_t valueStackBase() const { return valueStackBase_; }
    287  ControlItem& controlItem() { return typeAndItem_.second(); }
    288  const ControlItem& controlItem() const { return typeAndItem_.second(); }
    289  void setPolymorphicBase() { polymorphicBase_ = true; }
    290  bool polymorphicBase() const { return polymorphicBase_; }
    291 
    292  void switchToElse() {
    293    MOZ_ASSERT(kind() == LabelKind::Then);
    294    kind_ = LabelKind::Else;
    295    polymorphicBase_ = false;
    296  }
    297 
    298  void switchToCatch() {
    299    MOZ_ASSERT(kind() == LabelKind::Try || kind() == LabelKind::Catch);
    300    kind_ = LabelKind::Catch;
    301    polymorphicBase_ = false;
    302  }
    303 
    304  void switchToCatchAll() {
    305    MOZ_ASSERT(kind() == LabelKind::Try || kind() == LabelKind::Catch);
    306    kind_ = LabelKind::CatchAll;
    307    polymorphicBase_ = false;
    308  }
    309 };
    310 
    311 // Track state of the non-defaultable locals. Every time such local is
    312 // initialized, the stack will record at what depth and which local was set.
    313 // On a block end, the "unset" state will be rolled back to how it was before
    314 // the block started.
    315 //
    316 // It is very likely only a few functions will have non-defaultable locals and
    317 // very few locals will be non-defaultable. This class is optimized to be fast
    318 // for this common case.
    319 class UnsetLocalsState {
    320  struct SetLocalEntry {
    321    uint32_t depth;
    322    uint32_t localUnsetIndex;
    323    SetLocalEntry(uint32_t depth_, uint32_t localUnsetIndex_)
    324        : depth(depth_), localUnsetIndex(localUnsetIndex_) {}
    325  };
    326  using SetLocalsStack = Vector<SetLocalEntry, 16, SystemAllocPolicy>;
    327  using UnsetLocals = Vector<uint32_t, 16, SystemAllocPolicy>;
    328 
    329  static constexpr size_t WordSize = 4;
    330  static constexpr size_t WordBits = WordSize * 8;
    331 
    332  // Bit array of "unset" function locals. Stores only unset states of the
    333  // locals that are declared after the first non-defaultable local.
    334  UnsetLocals unsetLocals_;
    335  // Stack of "set" operations. Contains pair where the first field is a depth,
    336  // and the second field is local id (offset by firstNonDefaultLocal_).
    337  SetLocalsStack setLocalsStack_;
    338  uint32_t firstNonDefaultLocal_;
    339 
    340 public:
    341  UnsetLocalsState() : firstNonDefaultLocal_(UINT32_MAX) {}
    342 
    343  [[nodiscard]] bool init(const ValTypeVector& locals, size_t numParams);
    344 
    345  inline bool isUnset(uint32_t id) const {
    346    if (MOZ_LIKELY(id < firstNonDefaultLocal_)) {
    347      return false;
    348    }
    349    uint32_t localUnsetIndex = id - firstNonDefaultLocal_;
    350    return unsetLocals_[localUnsetIndex / WordBits] &
    351           (1 << (localUnsetIndex % WordBits));
    352  }
    353 
    354  inline void set(uint32_t id, uint32_t depth) {
    355    MOZ_ASSERT(isUnset(id));
    356    MOZ_ASSERT(id >= firstNonDefaultLocal_ &&
    357               (id - firstNonDefaultLocal_) / WordBits < unsetLocals_.length());
    358    uint32_t localUnsetIndex = id - firstNonDefaultLocal_;
    359    unsetLocals_[localUnsetIndex / WordBits] ^= 1
    360                                                << (localUnsetIndex % WordBits);
    361    // The setLocalsStack_ is reserved upfront in the UnsetLocalsState::init.
    362    // A SetLocalEntry will be pushed only once per local.
    363    setLocalsStack_.infallibleEmplaceBack(depth, localUnsetIndex);
    364  }
    365 
    366  inline void resetToBlock(uint32_t controlDepth) {
    367    while (MOZ_UNLIKELY(setLocalsStack_.length() > 0) &&
    368           setLocalsStack_.back().depth > controlDepth) {
    369      uint32_t localUnsetIndex = setLocalsStack_.back().localUnsetIndex;
    370      MOZ_ASSERT(!(unsetLocals_[localUnsetIndex / WordBits] &
    371                   (1 << (localUnsetIndex % WordBits))));
    372      unsetLocals_[localUnsetIndex / WordBits] |=
    373          1 << (localUnsetIndex % WordBits);
    374      setLocalsStack_.popBack();
    375    }
    376  }
    377 
    378  int empty() const { return setLocalsStack_.empty(); }
    379 };
    380 
    381 template <typename Value>
    382 class TypeAndValueT {
    383  // Use a Pair to optimize away empty Value.
    384  mozilla::CompactPair<StackType, Value> tv_;
    385 
    386 public:
    387  TypeAndValueT() : tv_(StackType::bottom(), Value()) {}
    388  explicit TypeAndValueT(StackType type) : tv_(type, Value()) {}
    389  explicit TypeAndValueT(ValType type) : tv_(StackType(type), Value()) {}
    390  TypeAndValueT(StackType type, Value value) : tv_(type, value) {}
    391  TypeAndValueT(ValType type, Value value) : tv_(StackType(type), value) {}
    392  StackType type() const { return tv_.first(); }
    393  void setType(StackType type) { tv_.first() = type; }
    394  Value value() const { return tv_.second(); }
    395  void setValue(Value value) { tv_.second() = value; }
    396 };
    397 
    398 // An iterator over the bytes of a function body. It performs validation
    399 // and unpacks the data into a usable form.
    400 //
    401 // The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly.
    402 // There's otherwise nothing inherent in this class which would require
    403 // it to be used on the stack.
    404 template <typename Policy>
    405 class MOZ_STACK_CLASS OpIter : private Policy {
    406 public:
    407  using Value = typename Policy::Value;
    408  using ValueVector = typename Policy::ValueVector;
    409  using TypeAndValue = TypeAndValueT<Value>;
    410  using TypeAndValueStack = Vector<TypeAndValue, 32, SystemAllocPolicy>;
    411  using ControlItem = typename Policy::ControlItem;
    412  using Control = ControlStackEntry<ControlItem>;
    413  using ControlStack = Vector<Control, 16, SystemAllocPolicy>;
    414 
    415  enum Kind {
    416    Func,
    417    InitExpr,
    418  };
    419 
    420 private:
    421  Kind kind_;
    422  Decoder& d_;
    423  const CodeMetadata& codeMeta_;
    424  const ValTypeVector& locals_;
    425 
    426  TypeAndValueStack valueStack_;
    427  TypeAndValueStack elseParamStack_;
    428  ControlStack controlStack_;
    429  UnsetLocalsState unsetLocals_;
    430  FeatureUsage featureUsage_;
    431  uint32_t lastBranchHintIndex_;
    432  BranchHintVector* branchHintVector_;
    433 
    434 #ifdef DEBUG
    435  OpBytes op_;
    436 #endif
    437  size_t offsetOfLastReadOp_;
    438 
    439  [[nodiscard]] bool readFixedU8(uint8_t* out) { return d_.readFixedU8(out); }
    440  [[nodiscard]] bool readFixedU32(uint32_t* out) {
    441    return d_.readFixedU32(out);
    442  }
    443  [[nodiscard]] bool readVarS32(int32_t* out) { return d_.readVarS32(out); }
    444  [[nodiscard]] bool readVarU32(uint32_t* out) { return d_.readVarU32(out); }
    445  [[nodiscard]] bool readVarS64(int64_t* out) { return d_.readVarS64(out); }
    446  [[nodiscard]] bool readVarU64(uint64_t* out) { return d_.readVarU64(out); }
    447  [[nodiscard]] bool readFixedF32(float* out) { return d_.readFixedF32(out); }
    448  [[nodiscard]] bool readFixedF64(double* out) { return d_.readFixedF64(out); }
    449 
    450  [[nodiscard]] bool readLinearMemoryAddress(uint32_t byteSize,
    451                                             LinearMemoryAddress<Value>* addr);
    452  [[nodiscard]] bool readLinearMemoryAddressAligned(
    453      uint32_t byteSize, LinearMemoryAddress<Value>* addr);
    454  [[nodiscard]] bool readBlockType(BlockType* type);
    455  [[nodiscard]] bool readGcTypeIndex(uint32_t* typeIndex);
    456  [[nodiscard]] bool readStructTypeIndex(uint32_t* typeIndex);
    457  [[nodiscard]] bool readArrayTypeIndex(uint32_t* typeIndex);
    458  [[nodiscard]] bool readFuncTypeIndex(uint32_t* typeIndex);
    459  [[nodiscard]] bool readFieldIndex(uint32_t* fieldIndex,
    460                                    const StructType& structType);
    461 
    462  [[nodiscard]] bool popCallArgs(const ValTypeVector& expectedTypes,
    463                                 ValueVector* values);
    464 
    465  [[nodiscard]] bool failEmptyStack();
    466  [[nodiscard]] bool popStackType(StackType* type, Value* value);
    467  [[nodiscard]] bool popWithType(ValType expected, Value* value,
    468                                 StackType* stackType);
    469  [[nodiscard]] bool popWithType(ValType expected, Value* value);
    470  [[nodiscard]] bool popWithType(ResultType expected, ValueVector* values);
    471  template <typename ValTypeSpanT>
    472  [[nodiscard]] bool popWithTypes(ValTypeSpanT expected, ValueVector* values);
    473  [[nodiscard]] bool popWithRefType(Value* value, StackType* type);
    474  // Check that the top of the value stack has type `expected`, bearing in
    475  // mind that it may be a block type, hence involving multiple values.
    476  //
    477  // If the block's stack contains polymorphic values at its base (because we
    478  // are in unreachable code) then suitable extra values are inserted into the
    479  // value stack, as controlled by `rewriteStackTypes`: if this is true,
    480  // polymorphic values have their types created/updated from `expected`.  If
    481  // it is false, such values are left as `StackType::bottom()`.
    482  //
    483  // If `values` is non-null, it is filled in with Value components of the
    484  // relevant stack entries, including those of any new entries created.
    485  [[nodiscard]] bool checkTopTypeMatches(ResultType expected,
    486                                         ValueVector* values,
    487                                         bool rewriteStackTypes);
    488 
    489  [[nodiscard]] bool pushControl(LabelKind kind, BlockType type);
    490  [[nodiscard]] bool checkStackAtEndOfBlock(ResultType* type,
    491                                            ValueVector* values);
    492  [[nodiscard]] bool getControl(uint32_t relativeDepth, Control** controlEntry);
    493  [[nodiscard]] bool checkBranchValueAndPush(uint32_t relativeDepth,
    494                                             ResultType* type,
    495                                             ValueVector* values,
    496                                             bool rewriteStackTypes);
    497  [[nodiscard]] bool checkBrTableEntryAndPush(uint32_t* relativeDepth,
    498                                              ResultType prevBranchType,
    499                                              ResultType* branchType,
    500                                              ValueVector* branchValues);
    501 
    502  [[nodiscard]] bool push(StackType t) { return valueStack_.emplaceBack(t); }
    503  [[nodiscard]] bool push(ValType t) { return valueStack_.emplaceBack(t); }
    504  [[nodiscard]] bool push(TypeAndValue tv) { return valueStack_.append(tv); }
    505  [[nodiscard]] bool push(ResultType t) {
    506    for (size_t i = 0; i < t.length(); i++) {
    507      if (!push(t[i])) {
    508        return false;
    509      }
    510    }
    511    return true;
    512  }
    513  void infalliblePush(StackType t) { valueStack_.infallibleEmplaceBack(t); }
    514  void infalliblePush(ValType t) {
    515    valueStack_.infallibleEmplaceBack(StackType(t));
    516  }
    517  void infalliblePush(TypeAndValue tv) { valueStack_.infallibleAppend(tv); }
    518 
    519  void afterUnconditionalBranch() {
    520    valueStack_.shrinkTo(controlStack_.back().valueStackBase());
    521    controlStack_.back().setPolymorphicBase();
    522  }
    523 
    524  inline bool checkIsSubtypeOf(StorageType actual, StorageType expected);
    525 
    526  inline bool checkIsSubtypeOf(RefType actual, RefType expected) {
    527    return checkIsSubtypeOf(ValType(actual).storageType(),
    528                            ValType(expected).storageType());
    529  }
    530  inline bool checkIsSubtypeOf(ValType actual, ValType expected) {
    531    return checkIsSubtypeOf(actual.storageType(), expected.storageType());
    532  }
    533 
    534  inline bool checkIsSubtypeOf(ResultType params, ResultType results);
    535 
    536  inline bool checkIsSubtypeOf(uint32_t actualTypeIndex,
    537                               uint32_t expectedTypeIndex);
    538 
    539 public:
    540  explicit OpIter(const CodeMetadata& codeMeta, Decoder& decoder,
    541                  const ValTypeVector& locals, Kind kind = OpIter::Func)
    542      : kind_(kind),
    543        d_(decoder),
    544        codeMeta_(codeMeta),
    545        locals_(locals),
    546        featureUsage_(FeatureUsage::None),
    547        branchHintVector_(nullptr),
    548 #ifdef DEBUG
    549        op_(OpBytes(Op::Limit)),
    550 #endif
    551        offsetOfLastReadOp_(0) {
    552  }
    553 
    554  FeatureUsage featureUsage() const { return featureUsage_; }
    555  void addFeatureUsage(FeatureUsage featureUsage) {
    556    featureUsage_ |= featureUsage;
    557  }
    558 
    559  // Return the decoding byte offset.
    560  uint32_t currentOffset() const { return d_.currentOffset(); }
    561 
    562  // Return the offset within the entire module of the last-read op.
    563  size_t lastOpcodeOffset() const {
    564    return offsetOfLastReadOp_ ? offsetOfLastReadOp_ : d_.currentOffset();
    565  }
    566 
    567  // Return a BytecodeOffset describing where the current op should be reported
    568  // to trap/call.
    569  BytecodeOffset bytecodeOffset() const {
    570    return BytecodeOffset(lastOpcodeOffset());
    571  }
    572 
    573  // Test whether the iterator has reached the end of the buffer.
    574  bool done() const { return d_.done(); }
    575 
    576  // Return a pointer to the end of the buffer being decoded by this iterator.
    577  const uint8_t* end() const { return d_.end(); }
    578 
    579  // Report a general failure.
    580  [[nodiscard]] bool fail(const char* msg) MOZ_COLD;
    581 
    582  // Report a general failure with a context
    583  [[nodiscard]] bool fail_ctx(const char* fmt, const char* context) MOZ_COLD;
    584 
    585  // Report an unrecognized opcode.
    586  [[nodiscard]] bool unrecognizedOpcode(const OpBytes* expr) MOZ_COLD;
    587 
    588  // Return whether the innermost block has a polymorphic base of its stack.
    589  // Ideally this accessor would be removed; consider using something else.
    590  bool currentBlockHasPolymorphicBase() const {
    591    return !controlStack_.empty() && controlStack_.back().polymorphicBase();
    592  }
    593 
    594  // If it exists, return the BranchHint value from a function index and a
    595  // branch offset.
    596  // Branch hints are stored in a sorted vector. Because code in compiled in
    597  // order, we keep track of the most recently accessed index.
    598  // Retrieving branch hints is also done in order inside a function.
    599  BranchHint getBranchHint(uint32_t funcIndex, uint32_t branchOffset) {
    600    if (!codeMeta_.branchHintingEnabled()) {
    601      return BranchHint::Invalid;
    602    }
    603 
    604    // Get the next hint in the collection
    605    while (lastBranchHintIndex_ < branchHintVector_->length() &&
    606           (*branchHintVector_)[lastBranchHintIndex_].branchOffset <
    607               branchOffset) {
    608      lastBranchHintIndex_++;
    609    }
    610 
    611    // No hint found for this branch.
    612    if (lastBranchHintIndex_ >= branchHintVector_->length()) {
    613      return BranchHint::Invalid;
    614    }
    615 
    616    // The last index is saved, now return the hint.
    617    return (*branchHintVector_)[lastBranchHintIndex_].value;
    618  }
    619 
    620  // ------------------------------------------------------------------------
    621  // Decoding and validation interface.
    622 
    623  // Initialization and termination
    624 
    625  [[nodiscard]] bool startFunction(uint32_t funcIndex);
    626  [[nodiscard]] bool endFunction(const uint8_t* bodyEnd);
    627 
    628  [[nodiscard]] bool startInitExpr(ValType expected);
    629  [[nodiscard]] bool endInitExpr();
    630 
    631  // Value and reference types
    632 
    633  [[nodiscard]] bool readValType(ValType* type);
    634  [[nodiscard]] bool readHeapType(bool nullable, RefType* type);
    635 
    636  // Instructions
    637 
    638  [[nodiscard]] bool readOp(OpBytes* op);
    639  [[nodiscard]] bool readReturn(ValueVector* values);
    640  [[nodiscard]] bool readBlock(BlockType* type);
    641  [[nodiscard]] bool readLoop(BlockType* type);
    642  [[nodiscard]] bool readIf(BlockType* type, Value* condition);
    643  [[nodiscard]] bool readElse(ResultType* paramType, ResultType* resultType,
    644                              ValueVector* thenResults);
    645  [[nodiscard]] bool readEnd(LabelKind* kind, ResultType* type,
    646                             ValueVector* results,
    647                             ValueVector* resultsForEmptyElse);
    648  void popEnd();
    649  [[nodiscard]] bool readBr(uint32_t* relativeDepth, ResultType* type,
    650                            ValueVector* values);
    651  [[nodiscard]] bool readBrIf(uint32_t* relativeDepth, ResultType* type,
    652                              ValueVector* values, Value* condition);
    653  [[nodiscard]] bool readBrTable(Uint32Vector* depths, uint32_t* defaultDepth,
    654                                 ResultType* defaultBranchType,
    655                                 ValueVector* branchValues, Value* index);
    656  [[nodiscard]] bool readTry(BlockType* type);
    657  [[nodiscard]] bool readTryTable(BlockType* type,
    658                                  TryTableCatchVector* catches);
    659  [[nodiscard]] bool readCatch(LabelKind* kind, uint32_t* tagIndex,
    660                               ResultType* paramType, ResultType* resultType,
    661                               ValueVector* tryResults);
    662  [[nodiscard]] bool readCatchAll(LabelKind* kind, ResultType* paramType,
    663                                  ResultType* resultType,
    664                                  ValueVector* tryResults);
    665  [[nodiscard]] bool readDelegate(uint32_t* relativeDepth,
    666                                  ResultType* resultType,
    667                                  ValueVector* tryResults);
    668  void popDelegate();
    669  [[nodiscard]] bool readThrow(uint32_t* tagIndex, ValueVector* argValues);
    670  [[nodiscard]] bool readThrowRef(Value* exnRef);
    671  [[nodiscard]] bool readRethrow(uint32_t* relativeDepth);
    672  [[nodiscard]] bool readUnreachable();
    673  [[nodiscard]] bool readDrop();
    674  [[nodiscard]] bool readUnary(ValType operandType, Value* input);
    675  [[nodiscard]] bool readConversion(ValType operandType, ValType resultType,
    676                                    Value* input);
    677  [[nodiscard]] bool readBinary(ValType operandType, Value* lhs, Value* rhs);
    678  [[nodiscard]] bool readComparison(ValType operandType, Value* lhs,
    679                                    Value* rhs);
    680  [[nodiscard]] bool readTernary(ValType operandType, Value* v0, Value* v1,
    681                                 Value* v2);
    682  [[nodiscard]] bool readLoad(ValType resultType, uint32_t byteSize,
    683                              LinearMemoryAddress<Value>* addr);
    684  [[nodiscard]] bool readStore(ValType resultType, uint32_t byteSize,
    685                               LinearMemoryAddress<Value>* addr, Value* value);
    686  [[nodiscard]] bool readTeeStore(ValType resultType, uint32_t byteSize,
    687                                  LinearMemoryAddress<Value>* addr,
    688                                  Value* value);
    689  [[nodiscard]] bool readNop();
    690  [[nodiscard]] bool readMemorySize(uint32_t* memoryIndex);
    691  [[nodiscard]] bool readMemoryGrow(uint32_t* memoryIndex, Value* input);
    692  [[nodiscard]] bool readSelect(bool typed, StackType* type, Value* trueValue,
    693                                Value* falseValue, Value* condition);
    694  [[nodiscard]] bool readGetLocal(uint32_t* id);
    695  [[nodiscard]] bool readSetLocal(uint32_t* id, Value* value);
    696  [[nodiscard]] bool readTeeLocal(uint32_t* id, Value* value);
    697  [[nodiscard]] bool readGetGlobal(uint32_t* id);
    698  [[nodiscard]] bool readSetGlobal(uint32_t* id, Value* value);
    699  [[nodiscard]] bool readTeeGlobal(uint32_t* id, Value* value);
    700  [[nodiscard]] bool readI32Const(int32_t* i32);
    701  [[nodiscard]] bool readI64Const(int64_t* i64);
    702  [[nodiscard]] bool readF32Const(float* f32);
    703  [[nodiscard]] bool readF64Const(double* f64);
    704  [[nodiscard]] bool readRefFunc(uint32_t* funcIndex);
    705  [[nodiscard]] bool readRefNull(RefType* type);
    706  [[nodiscard]] bool readRefIsNull(Value* input);
    707  [[nodiscard]] bool readRefAsNonNull(Value* input);
    708  [[nodiscard]] bool readBrOnNull(uint32_t* relativeDepth, ResultType* type,
    709                                  ValueVector* values, Value* condition);
    710  [[nodiscard]] bool readBrOnNonNull(uint32_t* relativeDepth, ResultType* type,
    711                                     ValueVector* values, Value* condition);
    712  [[nodiscard]] bool readCall(uint32_t* funcIndex, ValueVector* argValues);
    713  [[nodiscard]] bool readCallIndirect(uint32_t* funcTypeIndex,
    714                                      uint32_t* tableIndex, Value* callee,
    715                                      ValueVector* argValues);
    716  [[nodiscard]] bool readReturnCall(uint32_t* funcIndex,
    717                                    ValueVector* argValues);
    718  [[nodiscard]] bool readReturnCallIndirect(uint32_t* funcTypeIndex,
    719                                            uint32_t* tableIndex, Value* callee,
    720                                            ValueVector* argValues);
    721  [[nodiscard]] bool readCallRef(uint32_t* funcTypeIndex, Value* callee,
    722                                 ValueVector* argValues);
    723  [[nodiscard]] bool readReturnCallRef(uint32_t* funcTypeIndex, Value* callee,
    724                                       ValueVector* argValues);
    725  [[nodiscard]] bool readOldCallDirect(uint32_t numFuncImports,
    726                                       uint32_t* funcIndex,
    727                                       ValueVector* argValues);
    728  [[nodiscard]] bool readOldCallIndirect(uint32_t* funcTypeIndex, Value* callee,
    729                                         ValueVector* argValues);
    730  [[nodiscard]] bool readNotify(LinearMemoryAddress<Value>* addr, Value* count);
    731  [[nodiscard]] bool readWait(LinearMemoryAddress<Value>* addr,
    732                              ValType valueType, uint32_t byteSize,
    733                              Value* value, Value* timeout);
    734  [[nodiscard]] bool readFence();
    735  [[nodiscard]] bool readAtomicLoad(LinearMemoryAddress<Value>* addr,
    736                                    ValType resultType, uint32_t byteSize);
    737  [[nodiscard]] bool readAtomicStore(LinearMemoryAddress<Value>* addr,
    738                                     ValType resultType, uint32_t byteSize,
    739                                     Value* value);
    740  [[nodiscard]] bool readAtomicRMW(LinearMemoryAddress<Value>* addr,
    741                                   ValType resultType, uint32_t byteSize,
    742                                   Value* value);
    743  [[nodiscard]] bool readAtomicCmpXchg(LinearMemoryAddress<Value>* addr,
    744                                       ValType resultType, uint32_t byteSize,
    745                                       Value* oldValue, Value* newValue);
    746  [[nodiscard]] bool readMemOrTableCopy(bool isMem,
    747                                        uint32_t* dstMemOrTableIndex,
    748                                        Value* dst,
    749                                        uint32_t* srcMemOrTableIndex,
    750                                        Value* src, Value* len);
    751  [[nodiscard]] bool readDataOrElemDrop(bool isData, uint32_t* segIndex);
    752  [[nodiscard]] bool readMemFill(uint32_t* memoryIndex, Value* start,
    753                                 Value* val, Value* len);
    754  [[nodiscard]] bool readMemOrTableInit(bool isMem, uint32_t* segIndex,
    755                                        uint32_t* dstMemOrTableIndex,
    756                                        Value* dst, Value* src, Value* len);
    757  [[nodiscard]] bool readTableFill(uint32_t* tableIndex, Value* start,
    758                                   Value* val, Value* len);
    759  [[nodiscard]] bool readMemDiscard(uint32_t* memoryIndex, Value* start,
    760                                    Value* len);
    761  [[nodiscard]] bool readTableGet(uint32_t* tableIndex, Value* address);
    762  [[nodiscard]] bool readTableGrow(uint32_t* tableIndex, Value* initValue,
    763                                   Value* delta);
    764  [[nodiscard]] bool readTableSet(uint32_t* tableIndex, Value* address,
    765                                  Value* value);
    766 
    767  [[nodiscard]] bool readTableSize(uint32_t* tableIndex);
    768 
    769  [[nodiscard]] bool readStructNew(uint32_t* typeIndex, ValueVector* argValues);
    770  [[nodiscard]] bool readStructNewDefault(uint32_t* typeIndex);
    771  [[nodiscard]] bool readStructGet(uint32_t* typeIndex, uint32_t* fieldIndex,
    772                                   FieldWideningOp wideningOp, Value* ptr);
    773  [[nodiscard]] bool readStructSet(uint32_t* typeIndex, uint32_t* fieldIndex,
    774                                   Value* ptr, Value* val);
    775  [[nodiscard]] bool readArrayNew(uint32_t* typeIndex, Value* numElements,
    776                                  Value* argValue);
    777  [[nodiscard]] bool readArrayNewFixed(uint32_t* typeIndex,
    778                                       uint32_t* numElements,
    779                                       ValueVector* values);
    780  [[nodiscard]] bool readArrayNewDefault(uint32_t* typeIndex,
    781                                         Value* numElements);
    782  [[nodiscard]] bool readArrayNewData(uint32_t* typeIndex, uint32_t* segIndex,
    783                                      Value* offset, Value* numElements);
    784  [[nodiscard]] bool readArrayNewElem(uint32_t* typeIndex, uint32_t* segIndex,
    785                                      Value* offset, Value* numElements);
    786  [[nodiscard]] bool readArrayInitData(uint32_t* typeIndex, uint32_t* segIndex,
    787                                       Value* array, Value* arrayIndex,
    788                                       Value* segOffset, Value* length);
    789  [[nodiscard]] bool readArrayInitElem(uint32_t* typeIndex, uint32_t* segIndex,
    790                                       Value* array, Value* arrayIndex,
    791                                       Value* segOffset, Value* length);
    792  [[nodiscard]] bool readArrayGet(uint32_t* typeIndex,
    793                                  FieldWideningOp wideningOp, Value* index,
    794                                  Value* ptr);
    795  [[nodiscard]] bool readArraySet(uint32_t* typeIndex, Value* val, Value* index,
    796                                  Value* ptr);
    797  [[nodiscard]] bool readArrayLen(Value* ptr);
    798  [[nodiscard]] bool readArrayCopy(uint32_t* dstArrayTypeIndex,
    799                                   uint32_t* srcArrayTypeIndex, Value* dstArray,
    800                                   Value* dstIndex, Value* srcArray,
    801                                   Value* srcIndex, Value* numElements);
    802  [[nodiscard]] bool readArrayFill(uint32_t* typeIndex, Value* array,
    803                                   Value* index, Value* val, Value* length);
    804  [[nodiscard]] bool readRefTest(bool nullable, RefType* sourceType,
    805                                 RefType* destType, Value* ref);
    806  [[nodiscard]] bool readRefCast(bool nullable, RefType* sourceType,
    807                                 RefType* destType, Value* ref);
    808  [[nodiscard]] bool readBrOnCast(bool onSuccess, uint32_t* labelRelativeDepth,
    809                                  RefType* sourceType, RefType* destType,
    810                                  ResultType* labelType, ValueVector* values);
    811  [[nodiscard]] bool readRefConversion(RefType operandType, RefType resultType,
    812                                       Value* operandValue);
    813 
    814 #ifdef ENABLE_WASM_SIMD
    815  [[nodiscard]] bool readLaneIndex(uint32_t inputLanes, uint32_t* laneIndex);
    816  [[nodiscard]] bool readExtractLane(ValType resultType, uint32_t inputLanes,
    817                                     uint32_t* laneIndex, Value* input);
    818  [[nodiscard]] bool readReplaceLane(ValType operandType, uint32_t inputLanes,
    819                                     uint32_t* laneIndex, Value* baseValue,
    820                                     Value* operand);
    821  [[nodiscard]] bool readVectorShift(Value* baseValue, Value* shift);
    822  [[nodiscard]] bool readVectorShuffle(Value* v1, Value* v2, V128* selectMask);
    823  [[nodiscard]] bool readV128Const(V128* value);
    824  [[nodiscard]] bool readLoadSplat(uint32_t byteSize,
    825                                   LinearMemoryAddress<Value>* addr);
    826  [[nodiscard]] bool readLoadExtend(LinearMemoryAddress<Value>* addr);
    827  [[nodiscard]] bool readLoadLane(uint32_t byteSize,
    828                                  LinearMemoryAddress<Value>* addr,
    829                                  uint32_t* laneIndex, Value* input);
    830  [[nodiscard]] bool readStoreLane(uint32_t byteSize,
    831                                   LinearMemoryAddress<Value>* addr,
    832                                   uint32_t* laneIndex, Value* input);
    833 #endif
    834 
    835  [[nodiscard]] bool readCallBuiltinModuleFunc(
    836      const BuiltinModuleFunc** builtinModuleFunc, ValueVector* params);
    837 
    838 #ifdef ENABLE_WASM_JSPI
    839  [[nodiscard]] bool readStackSwitch(StackSwitchKind* kind, Value* suspender,
    840                                     Value* fn, Value* data);
    841 #endif
    842 
    843  // At a location where readOp is allowed, peek at the next opcode
    844  // without consuming it or updating any internal state.
    845  // Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read.
    846  void peekOp(OpBytes* op);
    847 
    848  // ------------------------------------------------------------------------
    849  // Stack management.
    850 
    851  // Set the top N result values.
    852  void setResults(size_t count, const ValueVector& values) {
    853    MOZ_ASSERT(valueStack_.length() >= count);
    854    size_t base = valueStack_.length() - count;
    855    for (size_t i = 0; i < count; i++) {
    856      valueStack_[base + i].setValue(values[i]);
    857    }
    858  }
    859 
    860  bool getResults(size_t count, ValueVector* values) {
    861    MOZ_ASSERT(valueStack_.length() >= count);
    862    if (!values->resize(count)) {
    863      return false;
    864    }
    865    size_t base = valueStack_.length() - count;
    866    for (size_t i = 0; i < count; i++) {
    867      (*values)[i] = valueStack_[base + i].value();
    868    }
    869    return true;
    870  }
    871 
    872  // Set the result value of the current top-of-value-stack expression.
    873  void setResult(Value value) { valueStack_.back().setValue(value); }
    874 
    875  // Return the result value of the current top-of-value-stack expression.
    876  Value getResult() { return valueStack_.back().value(); }
    877 
    878  // Return a reference to the top of the control stack.
    879  ControlItem& controlItem() { return controlStack_.back().controlItem(); }
    880 
    881  // Return a reference to an element in the control stack.
    882  ControlItem& controlItem(uint32_t relativeDepth) {
    883    return controlStack_[controlStack_.length() - 1 - relativeDepth]
    884        .controlItem();
    885  }
    886 
    887  // Return the LabelKind of an element in the control stack.
    888  LabelKind controlKind(uint32_t relativeDepth) {
    889    return controlStack_[controlStack_.length() - 1 - relativeDepth].kind();
    890  }
    891 
    892  // Return a reference to the outermost element on the control stack.
    893  ControlItem& controlOutermost() { return controlStack_[0].controlItem(); }
    894 
    895  // Test whether the control-stack is empty, meaning we've consumed the final
    896  // end of the function body.
    897  bool controlStackEmpty() const { return controlStack_.empty(); }
    898 
    899  // Return the depth of the control stack.
    900  size_t controlStackDepth() const { return controlStack_.length(); }
    901 
    902  // Find the innermost control item matching a predicate, starting to search
    903  // from a certain relative depth, and returning true if such innermost
    904  // control item is found. The relative depth of the found item is returned
    905  // via a parameter.
    906  template <typename Predicate>
    907  bool controlFindInnermostFrom(Predicate predicate, uint32_t fromRelativeDepth,
    908                                uint32_t* foundRelativeDepth) const {
    909    int32_t fromAbsoluteDepth = controlStack_.length() - fromRelativeDepth - 1;
    910    for (int32_t i = fromAbsoluteDepth; i >= 0; i--) {
    911      if (predicate(controlStack_[i].kind(), controlStack_[i].controlItem())) {
    912        *foundRelativeDepth = controlStack_.length() - 1 - i;
    913        return true;
    914      }
    915    }
    916    return false;
    917  }
    918 };
    919 
    920 template <typename Policy>
    921 inline bool OpIter<Policy>::checkIsSubtypeOf(StorageType subType,
    922                                             StorageType superType) {
    923  return CheckIsSubtypeOf(d_, codeMeta_, lastOpcodeOffset(), subType,
    924                          superType);
    925 }
    926 
    927 template <typename Policy>
    928 inline bool OpIter<Policy>::checkIsSubtypeOf(ResultType params,
    929                                             ResultType results) {
    930  return CheckIsSubtypeOf(d_, codeMeta_, lastOpcodeOffset(), params, results);
    931 }
    932 
    933 template <typename Policy>
    934 inline bool OpIter<Policy>::checkIsSubtypeOf(uint32_t actualTypeIndex,
    935                                             uint32_t expectedTypeIndex) {
    936  const TypeDef& actualTypeDef = codeMeta_.types->type(actualTypeIndex);
    937  const TypeDef& expectedTypeDef = codeMeta_.types->type(expectedTypeIndex);
    938  return CheckIsSubtypeOf(
    939      d_, codeMeta_, lastOpcodeOffset(),
    940      ValType(RefType::fromTypeDef(&actualTypeDef, true)),
    941      ValType(RefType::fromTypeDef(&expectedTypeDef, true)));
    942 }
    943 
    944 template <typename Policy>
    945 inline bool OpIter<Policy>::unrecognizedOpcode(const OpBytes* expr) {
    946  UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0,
    947                                IsPrefixByte(expr->b0) ? expr->b1 : 0));
    948  if (!error) {
    949    return false;
    950  }
    951 
    952  return fail(error.get());
    953 }
    954 
    955 template <typename Policy>
    956 inline bool OpIter<Policy>::fail(const char* msg) {
    957  return d_.fail(lastOpcodeOffset(), msg);
    958 }
    959 
    960 template <typename Policy>
    961 inline bool OpIter<Policy>::fail_ctx(const char* fmt, const char* context) {
    962  UniqueChars error(JS_smprintf(fmt, context));
    963  if (!error) {
    964    return false;
    965  }
    966  return fail(error.get());
    967 }
    968 
    969 template <typename Policy>
    970 inline bool OpIter<Policy>::failEmptyStack() {
    971  return valueStack_.empty() ? fail("popping value from empty stack")
    972                             : fail("popping value from outside block");
    973 }
    974 
    975 // This function pops exactly one value from the stack, yielding Bottom types in
    976 // various cases and therefore making it the caller's responsibility to do the
    977 // right thing for StackType::Bottom. Prefer (pop|top)WithType.  This is an
    978 // optimization for the super-common case where the caller is statically
    979 // expecting the resulttype `[valtype]`.
    980 template <typename Policy>
    981 inline bool OpIter<Policy>::popStackType(StackType* type, Value* value) {
    982  Control& block = controlStack_.back();
    983 
    984  MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
    985  if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackBase())) {
    986    // If the base of this block's stack is polymorphic, then we can pop a
    987    // dummy value of the bottom type; it won't be used since we're in
    988    // unreachable code.
    989    if (block.polymorphicBase()) {
    990      *type = StackType::bottom();
    991      *value = Value();
    992 
    993      // Maintain the invariant that, after a pop, there is always memory
    994      // reserved to push a value infallibly.
    995      return valueStack_.reserve(valueStack_.length() + 1);
    996    }
    997 
    998    return failEmptyStack();
    999  }
   1000 
   1001  TypeAndValue& tv = valueStack_.back();
   1002  *type = tv.type();
   1003  *value = tv.value();
   1004  valueStack_.popBack();
   1005  return true;
   1006 }
   1007 
   1008 // This function pops exactly one value from the stack, checking that it has the
   1009 // expected type which can either be a specific value type or the bottom type.
   1010 template <typename Policy>
   1011 inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value,
   1012                                        StackType* stackType) {
   1013  if (!popStackType(stackType, value)) {
   1014    return false;
   1015  }
   1016 
   1017  return stackType->isStackBottom() ||
   1018         checkIsSubtypeOf(stackType->valType(), expectedType);
   1019 }
   1020 
   1021 // This function pops exactly one value from the stack, checking that it has the
   1022 // expected type which can either be a specific value type or the bottom type.
   1023 template <typename Policy>
   1024 inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value) {
   1025  StackType stackType;
   1026  return popWithType(expectedType, value, &stackType);
   1027 }
   1028 
   1029 template <typename Policy>
   1030 inline bool OpIter<Policy>::popWithType(ResultType expected,
   1031                                        ValueVector* values) {
   1032  return popWithTypes(expected, values);
   1033 }
   1034 
   1035 // Pops each of the given expected types (in reverse, because it's a stack).
   1036 template <typename Policy>
   1037 template <typename ValTypeSpanT>
   1038 inline bool OpIter<Policy>::popWithTypes(ValTypeSpanT expected,
   1039                                         ValueVector* values) {
   1040  size_t expectedLength = expected.size();
   1041  if (!values->resize(expectedLength)) {
   1042    return false;
   1043  }
   1044  for (size_t i = 0; i < expectedLength; i++) {
   1045    size_t reverseIndex = expectedLength - i - 1;
   1046    ValType expectedType = expected[reverseIndex];
   1047    Value* value = &(*values)[reverseIndex];
   1048    if (!popWithType(expectedType, value)) {
   1049      return false;
   1050    }
   1051  }
   1052  return true;
   1053 }
   1054 
   1055 // This function pops exactly one value from the stack, checking that it is a
   1056 // reference type.
   1057 template <typename Policy>
   1058 inline bool OpIter<Policy>::popWithRefType(Value* value, StackType* type) {
   1059  if (!popStackType(type, value)) {
   1060    return false;
   1061  }
   1062 
   1063  if (type->isStackBottom() || type->valType().isRefType()) {
   1064    return true;
   1065  }
   1066 
   1067  UniqueChars actualText = ToString(type->valType(), codeMeta_.types);
   1068  if (!actualText) {
   1069    return false;
   1070  }
   1071 
   1072  UniqueChars error(JS_smprintf(
   1073      "type mismatch: expression has type %s but expected a reference type",
   1074      actualText.get()));
   1075  if (!error) {
   1076    return false;
   1077  }
   1078 
   1079  return fail(error.get());
   1080 }
   1081 
   1082 template <typename Policy>
   1083 inline bool OpIter<Policy>::checkTopTypeMatches(ResultType expected,
   1084                                                ValueVector* values,
   1085                                                bool rewriteStackTypes) {
   1086  if (expected.empty()) {
   1087    return true;
   1088  }
   1089 
   1090  Control& block = controlStack_.back();
   1091 
   1092  size_t expectedLength = expected.length();
   1093  if (values && !values->resize(expectedLength)) {
   1094    return false;
   1095  }
   1096 
   1097  for (size_t i = 0; i != expectedLength; i++) {
   1098    // We're iterating as-if we were popping each expected/actual type one by
   1099    // one, which means iterating the array of expected results backwards.
   1100    // The "current" value stack length refers to what the value stack length
   1101    // would have been if we were popping it.
   1102    size_t reverseIndex = expectedLength - i - 1;
   1103    ValType expectedType = expected[reverseIndex];
   1104    auto collectValue = [&](const Value& v) {
   1105      if (values) {
   1106        (*values)[reverseIndex] = v;
   1107      }
   1108    };
   1109 
   1110    size_t currentValueStackLength = valueStack_.length() - i;
   1111 
   1112    MOZ_ASSERT(currentValueStackLength >= block.valueStackBase());
   1113    if (currentValueStackLength == block.valueStackBase()) {
   1114      if (!block.polymorphicBase()) {
   1115        return failEmptyStack();
   1116      }
   1117 
   1118      // If the base of this block's stack is polymorphic, then we can just
   1119      // pull out as many fake values as we need to validate, and create dummy
   1120      // stack entries accordingly; they won't be used since we're in
   1121      // unreachable code.  However, if `rewriteStackTypes` is true, we must
   1122      // set the types on these new entries to whatever `expected` requires
   1123      // them to be.
   1124      TypeAndValue newTandV =
   1125          rewriteStackTypes ? TypeAndValue(expectedType) : TypeAndValue();
   1126      if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength,
   1127                              newTandV)) {
   1128        return false;
   1129      }
   1130 
   1131      collectValue(Value());
   1132    } else {
   1133      TypeAndValue& observed = valueStack_[currentValueStackLength - 1];
   1134 
   1135      if (observed.type().isStackBottom()) {
   1136        collectValue(Value());
   1137      } else {
   1138        if (!checkIsSubtypeOf(observed.type().valType(), expectedType)) {
   1139          return false;
   1140        }
   1141 
   1142        collectValue(observed.value());
   1143      }
   1144 
   1145      if (rewriteStackTypes) {
   1146        observed.setType(StackType(expectedType));
   1147      }
   1148    }
   1149  }
   1150  return true;
   1151 }
   1152 
   1153 template <typename Policy>
   1154 inline bool OpIter<Policy>::pushControl(LabelKind kind, BlockType type) {
   1155  ResultType paramType = type.params();
   1156 
   1157  ValueVector values;
   1158  if (!checkTopTypeMatches(paramType, &values, /*rewriteStackTypes=*/true)) {
   1159    return false;
   1160  }
   1161  MOZ_ASSERT(valueStack_.length() >= paramType.length());
   1162  uint32_t valueStackBase = valueStack_.length() - paramType.length();
   1163  return controlStack_.emplaceBack(kind, type, valueStackBase);
   1164 }
   1165 
   1166 template <typename Policy>
   1167 inline bool OpIter<Policy>::checkStackAtEndOfBlock(ResultType* expectedType,
   1168                                                   ValueVector* values) {
   1169  Control& block = controlStack_.back();
   1170  *expectedType = block.type().results();
   1171 
   1172  MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
   1173  if (expectedType->length() < valueStack_.length() - block.valueStackBase()) {
   1174    return fail("unused values not explicitly dropped by end of block");
   1175  }
   1176 
   1177  return checkTopTypeMatches(*expectedType, values,
   1178                             /*rewriteStackTypes=*/true);
   1179 }
   1180 
   1181 template <typename Policy>
   1182 inline bool OpIter<Policy>::getControl(uint32_t relativeDepth,
   1183                                       Control** controlEntry) {
   1184  if (relativeDepth >= controlStack_.length()) {
   1185    return fail("branch depth exceeds current nesting level");
   1186  }
   1187 
   1188  *controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth];
   1189  return true;
   1190 }
   1191 
   1192 template <typename Policy>
   1193 inline bool OpIter<Policy>::readBlockType(BlockType* type) {
   1194  uint8_t nextByte;
   1195  if (!d_.peekByte(&nextByte)) {
   1196    return fail("unable to read block type");
   1197  }
   1198 
   1199  if (nextByte == uint8_t(TypeCode::BlockVoid)) {
   1200    d_.uncheckedReadFixedU8();
   1201    *type = BlockType::VoidToVoid();
   1202    return true;
   1203  }
   1204 
   1205  if ((nextByte & SLEB128SignMask) == SLEB128SignBit) {
   1206    ValType v;
   1207    if (!readValType(&v)) {
   1208      return false;
   1209    }
   1210    *type = BlockType::VoidToSingle(v);
   1211    return true;
   1212  }
   1213 
   1214  int32_t x;
   1215  if (!d_.readVarS32(&x) || x < 0 || uint32_t(x) >= codeMeta_.types->length()) {
   1216    return fail("invalid block type type index");
   1217  }
   1218 
   1219  const TypeDef* typeDef = &codeMeta_.types->type(x);
   1220  if (!typeDef->isFuncType()) {
   1221    return fail("block type type index must be func type");
   1222  }
   1223 
   1224  *type = BlockType::Func(typeDef->funcType());
   1225 
   1226  return true;
   1227 }
   1228 
   1229 template <typename Policy>
   1230 inline bool OpIter<Policy>::readOp(OpBytes* op) {
   1231  MOZ_ASSERT(!controlStack_.empty());
   1232 
   1233  offsetOfLastReadOp_ = d_.currentOffset();
   1234 
   1235  if (MOZ_UNLIKELY(!d_.readOp(op))) {
   1236    return fail("unable to read opcode");
   1237  }
   1238 
   1239 #ifdef DEBUG
   1240  op_ = *op;
   1241 #endif
   1242 
   1243  return true;
   1244 }
   1245 
   1246 template <typename Policy>
   1247 inline void OpIter<Policy>::peekOp(OpBytes* op) {
   1248  const uint8_t* pos = d_.currentPosition();
   1249 
   1250  if (MOZ_UNLIKELY(!d_.readOp(op))) {
   1251    op->b0 = uint16_t(Op::Limit);
   1252  }
   1253 
   1254  d_.rollbackPosition(pos);
   1255 }
   1256 
   1257 template <typename Policy>
   1258 inline bool OpIter<Policy>::startFunction(uint32_t funcIndex) {
   1259  MOZ_ASSERT(kind_ == OpIter::Func);
   1260  MOZ_ASSERT(elseParamStack_.empty());
   1261  MOZ_ASSERT(valueStack_.empty());
   1262  MOZ_ASSERT(controlStack_.empty());
   1263  MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
   1264  BlockType type = BlockType::FuncResults(codeMeta_.getFuncType(funcIndex));
   1265 
   1266  // Initialize information related to branch hinting.
   1267  lastBranchHintIndex_ = 0;
   1268  if (codeMeta_.branchHintingEnabled()) {
   1269    branchHintVector_ = &codeMeta_.branchHints.getHintVector(funcIndex);
   1270  }
   1271 
   1272  size_t numArgs = codeMeta_.getFuncType(funcIndex).args().length();
   1273  if (!unsetLocals_.init(locals_, numArgs)) {
   1274    return false;
   1275  }
   1276 
   1277  return pushControl(LabelKind::Body, type);
   1278 }
   1279 
   1280 template <typename Policy>
   1281 inline bool OpIter<Policy>::endFunction(const uint8_t* bodyEnd) {
   1282  if (d_.currentPosition() != bodyEnd) {
   1283    return fail("function body length mismatch");
   1284  }
   1285 
   1286  if (!controlStack_.empty()) {
   1287    return fail("unbalanced function body control flow");
   1288  }
   1289  MOZ_ASSERT(elseParamStack_.empty());
   1290  MOZ_ASSERT(unsetLocals_.empty());
   1291 
   1292 #ifdef DEBUG
   1293  op_ = OpBytes(Op::Limit);
   1294 #endif
   1295  valueStack_.clear();
   1296  return true;
   1297 }
   1298 
   1299 template <typename Policy>
   1300 inline bool OpIter<Policy>::startInitExpr(ValType expected) {
   1301  MOZ_ASSERT(kind_ == OpIter::InitExpr);
   1302  MOZ_ASSERT(locals_.length() == 0);
   1303  MOZ_ASSERT(elseParamStack_.empty());
   1304  MOZ_ASSERT(valueStack_.empty());
   1305  MOZ_ASSERT(controlStack_.empty());
   1306  MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
   1307  lastBranchHintIndex_ = 0;
   1308 
   1309  BlockType type = BlockType::VoidToSingle(expected);
   1310  return pushControl(LabelKind::Body, type);
   1311 }
   1312 
   1313 template <typename Policy>
   1314 inline bool OpIter<Policy>::endInitExpr() {
   1315  MOZ_ASSERT(controlStack_.empty());
   1316  MOZ_ASSERT(elseParamStack_.empty());
   1317 
   1318 #ifdef DEBUG
   1319  op_ = OpBytes(Op::Limit);
   1320 #endif
   1321  valueStack_.clear();
   1322  return true;
   1323 }
   1324 
   1325 template <typename Policy>
   1326 inline bool OpIter<Policy>::readValType(ValType* type) {
   1327  return d_.readValType(*codeMeta_.types, codeMeta_.features(), type);
   1328 }
   1329 
   1330 template <typename Policy>
   1331 inline bool OpIter<Policy>::readHeapType(bool nullable, RefType* type) {
   1332  return d_.readHeapType(*codeMeta_.types, codeMeta_.features(), nullable,
   1333                         type);
   1334 }
   1335 
   1336 template <typename Policy>
   1337 inline bool OpIter<Policy>::readReturn(ValueVector* values) {
   1338  MOZ_ASSERT(Classify(op_) == OpKind::Return);
   1339 
   1340  Control& body = controlStack_[0];
   1341  MOZ_ASSERT(body.kind() == LabelKind::Body);
   1342 
   1343  if (!popWithType(body.resultType(), values)) {
   1344    return false;
   1345  }
   1346 
   1347  afterUnconditionalBranch();
   1348  return true;
   1349 }
   1350 
   1351 template <typename Policy>
   1352 inline bool OpIter<Policy>::readBlock(BlockType* type) {
   1353  MOZ_ASSERT(Classify(op_) == OpKind::Block);
   1354 
   1355  if (!readBlockType(type)) {
   1356    return false;
   1357  }
   1358 
   1359  return pushControl(LabelKind::Block, *type);
   1360 }
   1361 
   1362 template <typename Policy>
   1363 inline bool OpIter<Policy>::readLoop(BlockType* type) {
   1364  MOZ_ASSERT(Classify(op_) == OpKind::Loop);
   1365 
   1366  if (!readBlockType(type)) {
   1367    return false;
   1368  }
   1369 
   1370  return pushControl(LabelKind::Loop, *type);
   1371 }
   1372 
   1373 template <typename Policy>
   1374 inline bool OpIter<Policy>::readIf(BlockType* type, Value* condition) {
   1375  MOZ_ASSERT(Classify(op_) == OpKind::If);
   1376 
   1377  if (!readBlockType(type)) {
   1378    return false;
   1379  }
   1380 
   1381  if (!popWithType(ValType::I32, condition)) {
   1382    return false;
   1383  }
   1384 
   1385  if (!pushControl(LabelKind::Then, *type)) {
   1386    return false;
   1387  }
   1388 
   1389  size_t paramsLength = type->params().length();
   1390  return elseParamStack_.append(valueStack_.end() - paramsLength, paramsLength);
   1391 }
   1392 
   1393 template <typename Policy>
   1394 inline bool OpIter<Policy>::readElse(ResultType* paramType,
   1395                                     ResultType* resultType,
   1396                                     ValueVector* thenResults) {
   1397  MOZ_ASSERT(Classify(op_) == OpKind::Else);
   1398 
   1399  Control& block = controlStack_.back();
   1400  if (block.kind() != LabelKind::Then) {
   1401    return fail("else can only be used within an if");
   1402  }
   1403 
   1404  *paramType = block.type().params();
   1405  if (!checkStackAtEndOfBlock(resultType, thenResults)) {
   1406    return false;
   1407  }
   1408 
   1409  valueStack_.shrinkTo(block.valueStackBase());
   1410 
   1411  size_t nparams = block.type().params().length();
   1412  MOZ_ASSERT(elseParamStack_.length() >= nparams);
   1413  valueStack_.infallibleAppend(elseParamStack_.end() - nparams, nparams);
   1414  elseParamStack_.shrinkBy(nparams);
   1415 
   1416  // Reset local state to the beginning of the 'if' block for the new block
   1417  // started by 'else'.
   1418  unsetLocals_.resetToBlock(controlStack_.length() - 1);
   1419 
   1420  block.switchToElse();
   1421  return true;
   1422 }
   1423 
   1424 template <typename Policy>
   1425 inline bool OpIter<Policy>::readEnd(LabelKind* kind, ResultType* type,
   1426                                    ValueVector* results,
   1427                                    ValueVector* resultsForEmptyElse) {
   1428  MOZ_ASSERT(Classify(op_) == OpKind::End);
   1429 
   1430  Control& block = controlStack_.back();
   1431 
   1432  if (!checkStackAtEndOfBlock(type, results)) {
   1433    return false;
   1434  }
   1435 
   1436  if (block.kind() == LabelKind::Then) {
   1437    ResultType params = block.type().params();
   1438    // If an `if` block ends with `end` instead of `else`, then the `else` block
   1439    // implicitly passes the `if` parameters as the `else` results.  In that
   1440    // case, assert that the `if`'s param type matches the result type.
   1441    if (!checkIsSubtypeOf(params, block.type().results())) {
   1442      return fail(
   1443          "the parameters to an if without an else must be compatible with the "
   1444          "if's result type");
   1445    }
   1446 
   1447    size_t nparams = params.length();
   1448    MOZ_ASSERT(elseParamStack_.length() >= nparams);
   1449    if (!resultsForEmptyElse->resize(nparams)) {
   1450      return false;
   1451    }
   1452    const TypeAndValue* elseParams = elseParamStack_.end() - nparams;
   1453    for (size_t i = 0; i < nparams; i++) {
   1454      (*resultsForEmptyElse)[i] = elseParams[i].value();
   1455    }
   1456    elseParamStack_.shrinkBy(nparams);
   1457  }
   1458 
   1459  *kind = block.kind();
   1460  return true;
   1461 }
   1462 
   1463 template <typename Policy>
   1464 inline void OpIter<Policy>::popEnd() {
   1465  MOZ_ASSERT(Classify(op_) == OpKind::End);
   1466 
   1467  controlStack_.popBack();
   1468  unsetLocals_.resetToBlock(controlStack_.length());
   1469 }
   1470 
   1471 template <typename Policy>
   1472 inline bool OpIter<Policy>::checkBranchValueAndPush(uint32_t relativeDepth,
   1473                                                    ResultType* type,
   1474                                                    ValueVector* values,
   1475                                                    bool rewriteStackTypes) {
   1476  Control* block = nullptr;
   1477  if (!getControl(relativeDepth, &block)) {
   1478    return false;
   1479  }
   1480 
   1481  *type = block->branchTargetType();
   1482  return checkTopTypeMatches(*type, values, rewriteStackTypes);
   1483 }
   1484 
   1485 template <typename Policy>
   1486 inline bool OpIter<Policy>::readBr(uint32_t* relativeDepth, ResultType* type,
   1487                                   ValueVector* values) {
   1488  MOZ_ASSERT(Classify(op_) == OpKind::Br);
   1489 
   1490  if (!readVarU32(relativeDepth)) {
   1491    return fail("unable to read br depth");
   1492  }
   1493 
   1494  if (!checkBranchValueAndPush(*relativeDepth, type, values,
   1495                               /*rewriteStackTypes=*/false)) {
   1496    return false;
   1497  }
   1498 
   1499  afterUnconditionalBranch();
   1500  return true;
   1501 }
   1502 
   1503 template <typename Policy>
   1504 inline bool OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ResultType* type,
   1505                                     ValueVector* values, Value* condition) {
   1506  MOZ_ASSERT(Classify(op_) == OpKind::BrIf);
   1507 
   1508  if (!readVarU32(relativeDepth)) {
   1509    return fail("unable to read br_if depth");
   1510  }
   1511 
   1512  if (!popWithType(ValType::I32, condition)) {
   1513    return false;
   1514  }
   1515 
   1516  return checkBranchValueAndPush(*relativeDepth, type, values,
   1517                                 /*rewriteStackTypes=*/true);
   1518 }
   1519 
   1520 #define UNKNOWN_ARITY UINT32_MAX
   1521 
   1522 template <typename Policy>
   1523 inline bool OpIter<Policy>::checkBrTableEntryAndPush(
   1524    uint32_t* relativeDepth, ResultType prevBranchType, ResultType* type,
   1525    ValueVector* branchValues) {
   1526  if (!readVarU32(relativeDepth)) {
   1527    return fail("unable to read br_table depth");
   1528  }
   1529 
   1530  Control* block = nullptr;
   1531  if (!getControl(*relativeDepth, &block)) {
   1532    return false;
   1533  }
   1534 
   1535  *type = block->branchTargetType();
   1536 
   1537  if (prevBranchType.valid()) {
   1538    if (prevBranchType.length() != type->length()) {
   1539      return fail("br_table targets must all have the same arity");
   1540    }
   1541 
   1542    // Avoid re-collecting the same values for subsequent branch targets.
   1543    branchValues = nullptr;
   1544  }
   1545 
   1546  return checkTopTypeMatches(*type, branchValues, /*rewriteStackTypes=*/false);
   1547 }
   1548 
   1549 template <typename Policy>
   1550 inline bool OpIter<Policy>::readBrTable(Uint32Vector* depths,
   1551                                        uint32_t* defaultDepth,
   1552                                        ResultType* defaultBranchType,
   1553                                        ValueVector* branchValues,
   1554                                        Value* index) {
   1555  MOZ_ASSERT(Classify(op_) == OpKind::BrTable);
   1556 
   1557  uint32_t tableLength;
   1558  if (!readVarU32(&tableLength)) {
   1559    return fail("unable to read br_table table length");
   1560  }
   1561 
   1562  if (tableLength > MaxBrTableElems) {
   1563    return fail("br_table too big");
   1564  }
   1565 
   1566  if (!popWithType(ValType::I32, index)) {
   1567    return false;
   1568  }
   1569 
   1570  if (!depths->resize(tableLength)) {
   1571    return false;
   1572  }
   1573 
   1574  ResultType prevBranchType;
   1575  for (uint32_t i = 0; i < tableLength; i++) {
   1576    ResultType branchType;
   1577    if (!checkBrTableEntryAndPush(&(*depths)[i], prevBranchType, &branchType,
   1578                                  branchValues)) {
   1579      return false;
   1580    }
   1581    prevBranchType = branchType;
   1582  }
   1583 
   1584  if (!checkBrTableEntryAndPush(defaultDepth, prevBranchType, defaultBranchType,
   1585                                branchValues)) {
   1586    return false;
   1587  }
   1588 
   1589  MOZ_ASSERT(defaultBranchType->valid());
   1590 
   1591  afterUnconditionalBranch();
   1592  return true;
   1593 }
   1594 
   1595 #undef UNKNOWN_ARITY
   1596 
   1597 template <typename Policy>
   1598 inline bool OpIter<Policy>::readTry(BlockType* type) {
   1599  MOZ_ASSERT(Classify(op_) == OpKind::Try);
   1600  featureUsage_ |= FeatureUsage::LegacyExceptions;
   1601 
   1602  if (!readBlockType(type)) {
   1603    return false;
   1604  }
   1605 
   1606  return pushControl(LabelKind::Try, *type);
   1607 }
   1608 
   1609 enum class TryTableCatchFlags : uint8_t {
   1610  CaptureExnRef = 0x1,
   1611  CatchAll = 0x1 << 1,
   1612  AllowedMask = uint8_t(CaptureExnRef) | uint8_t(CatchAll),
   1613 };
   1614 
   1615 template <typename Policy>
   1616 inline bool OpIter<Policy>::readTryTable(BlockType* type,
   1617                                         TryTableCatchVector* catches) {
   1618  MOZ_ASSERT(Classify(op_) == OpKind::TryTable);
   1619 
   1620  if (!readBlockType(type)) {
   1621    return false;
   1622  }
   1623 
   1624  if (!pushControl(LabelKind::TryTable, *type)) {
   1625    return false;
   1626  }
   1627 
   1628  uint32_t catchesLength;
   1629  if (!readVarU32(&catchesLength)) {
   1630    return fail("failed to read catches length");
   1631  }
   1632 
   1633  if (catchesLength > MaxTryTableCatches) {
   1634    return fail("too many catches");
   1635  }
   1636 
   1637  if (!catches->reserve(catchesLength)) {
   1638    return false;
   1639  }
   1640 
   1641  for (uint32_t i = 0; i < catchesLength; i++) {
   1642    TryTableCatch tryTableCatch;
   1643 
   1644    // Decode the flags
   1645    uint8_t flags;
   1646    if (!readFixedU8(&flags)) {
   1647      return fail("expected flags");
   1648    }
   1649    if ((flags & ~uint8_t(TryTableCatchFlags::AllowedMask)) != 0) {
   1650      return fail("invalid try_table catch flags");
   1651    }
   1652 
   1653    // Decode if this catch wants to capture an exnref
   1654    tryTableCatch.captureExnRef =
   1655        (flags & uint8_t(TryTableCatchFlags::CaptureExnRef)) != 0;
   1656 
   1657    // Decode the tag, if any
   1658    if ((flags & uint8_t(TryTableCatchFlags::CatchAll)) != 0) {
   1659      tryTableCatch.tagIndex = CatchAllIndex;
   1660    } else {
   1661      if (!readVarU32(&tryTableCatch.tagIndex)) {
   1662        return fail("expected tag index");
   1663      }
   1664      if (tryTableCatch.tagIndex >= codeMeta_.tags.length()) {
   1665        return fail("tag index out of range");
   1666      }
   1667    }
   1668 
   1669    // Decode the target branch and construct the type we need to compare
   1670    // against the branch
   1671    if (!readVarU32(&tryTableCatch.labelRelativeDepth)) {
   1672      return fail("unable to read catch depth");
   1673    }
   1674 
   1675    // The target branch depth is relative to the control labels outside of
   1676    // this try_table. e.g. `0` is a branch to the control outside of this
   1677    // try_table, not to the try_table itself. However, we've already pushed
   1678    // the control block for the try_table, and users will read it after we've
   1679    // returned, so we need to return the relative depth adjusted by 1 to
   1680    // account for our own control block.
   1681    if (tryTableCatch.labelRelativeDepth == UINT32_MAX) {
   1682      return fail("catch depth out of range");
   1683    }
   1684    tryTableCatch.labelRelativeDepth += 1;
   1685 
   1686    // Tagged catches will unpack the exception package and pass it to the
   1687    // branch
   1688    if (tryTableCatch.tagIndex != CatchAllIndex) {
   1689      const TagType& tagType = *codeMeta_.tags[tryTableCatch.tagIndex].type;
   1690      ResultType tagResult = tagType.resultType();
   1691      if (!tagResult.cloneToVector(&tryTableCatch.labelType)) {
   1692        return false;
   1693      }
   1694    }
   1695 
   1696    // Any captured exnref is the final parameter
   1697    if (tryTableCatch.captureExnRef && !tryTableCatch.labelType.append(ValType(
   1698                                           RefType::exn().asNonNullable()))) {
   1699      return false;
   1700    }
   1701 
   1702    Control* block;
   1703    if (!getControl(tryTableCatch.labelRelativeDepth, &block)) {
   1704      return false;
   1705    }
   1706 
   1707    ResultType blockTargetType = block->branchTargetType();
   1708    if (!checkIsSubtypeOf(ResultType::Vector(tryTableCatch.labelType),
   1709                          blockTargetType)) {
   1710      return false;
   1711    }
   1712 
   1713    catches->infallibleAppend(std::move(tryTableCatch));
   1714  }
   1715 
   1716  return true;
   1717 }
   1718 
   1719 template <typename Policy>
   1720 inline bool OpIter<Policy>::readCatch(LabelKind* kind, uint32_t* tagIndex,
   1721                                      ResultType* paramType,
   1722                                      ResultType* resultType,
   1723                                      ValueVector* tryResults) {
   1724  MOZ_ASSERT(Classify(op_) == OpKind::Catch);
   1725 
   1726  if (!readVarU32(tagIndex)) {
   1727    return fail("expected tag index");
   1728  }
   1729  if (*tagIndex >= codeMeta_.tags.length()) {
   1730    return fail("tag index out of range");
   1731  }
   1732 
   1733  Control& block = controlStack_.back();
   1734  if (block.kind() == LabelKind::CatchAll) {
   1735    return fail("catch cannot follow a catch_all");
   1736  }
   1737  if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) {
   1738    return fail("catch can only be used within a try-catch");
   1739  }
   1740  *kind = block.kind();
   1741  *paramType = block.type().params();
   1742 
   1743  if (!checkStackAtEndOfBlock(resultType, tryResults)) {
   1744    return false;
   1745  }
   1746 
   1747  valueStack_.shrinkTo(block.valueStackBase());
   1748  block.switchToCatch();
   1749  // Reset local state to the beginning of the 'try' block.
   1750  unsetLocals_.resetToBlock(controlStack_.length() - 1);
   1751 
   1752  return push(codeMeta_.tags[*tagIndex].type->resultType());
   1753 }
   1754 
   1755 template <typename Policy>
   1756 inline bool OpIter<Policy>::readCatchAll(LabelKind* kind, ResultType* paramType,
   1757                                         ResultType* resultType,
   1758                                         ValueVector* tryResults) {
   1759  MOZ_ASSERT(Classify(op_) == OpKind::CatchAll);
   1760 
   1761  Control& block = controlStack_.back();
   1762  if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) {
   1763    return fail("catch_all can only be used within a try-catch");
   1764  }
   1765  *kind = block.kind();
   1766  *paramType = block.type().params();
   1767 
   1768  if (!checkStackAtEndOfBlock(resultType, tryResults)) {
   1769    return false;
   1770  }
   1771 
   1772  valueStack_.shrinkTo(block.valueStackBase());
   1773  block.switchToCatchAll();
   1774  // Reset local state to the beginning of the 'try' block.
   1775  unsetLocals_.resetToBlock(controlStack_.length() - 1);
   1776  return true;
   1777 }
   1778 
   1779 template <typename Policy>
   1780 inline bool OpIter<Policy>::readDelegate(uint32_t* relativeDepth,
   1781                                         ResultType* resultType,
   1782                                         ValueVector* tryResults) {
   1783  MOZ_ASSERT(Classify(op_) == OpKind::Delegate);
   1784 
   1785  Control& block = controlStack_.back();
   1786  if (block.kind() != LabelKind::Try) {
   1787    return fail("delegate can only be used within a try");
   1788  }
   1789 
   1790  uint32_t delegateDepth;
   1791  if (!readVarU32(&delegateDepth)) {
   1792    return fail("unable to read delegate depth");
   1793  }
   1794 
   1795  // Depths for delegate start counting in the surrounding block.
   1796  if (delegateDepth >= controlStack_.length() - 1) {
   1797    return fail("delegate depth exceeds current nesting level");
   1798  }
   1799  *relativeDepth = delegateDepth + 1;
   1800 
   1801  // Because `delegate` acts like `end` and ends the block, we will check
   1802  // the stack here.
   1803  return checkStackAtEndOfBlock(resultType, tryResults);
   1804 }
   1805 
   1806 // We need popDelegate because readDelegate cannot pop the control stack
   1807 // itself, as its caller may need to use the control item for delegate.
   1808 template <typename Policy>
   1809 inline void OpIter<Policy>::popDelegate() {
   1810  MOZ_ASSERT(Classify(op_) == OpKind::Delegate);
   1811 
   1812  controlStack_.popBack();
   1813  unsetLocals_.resetToBlock(controlStack_.length());
   1814 }
   1815 
   1816 template <typename Policy>
   1817 inline bool OpIter<Policy>::readThrow(uint32_t* tagIndex,
   1818                                      ValueVector* argValues) {
   1819  MOZ_ASSERT(Classify(op_) == OpKind::Throw);
   1820 
   1821  if (!readVarU32(tagIndex)) {
   1822    return fail("expected tag index");
   1823  }
   1824  if (*tagIndex >= codeMeta_.tags.length()) {
   1825    return fail("tag index out of range");
   1826  }
   1827 
   1828  if (!popWithType(codeMeta_.tags[*tagIndex].type->resultType(), argValues)) {
   1829    return false;
   1830  }
   1831 
   1832  afterUnconditionalBranch();
   1833  return true;
   1834 }
   1835 
   1836 template <typename Policy>
   1837 inline bool OpIter<Policy>::readThrowRef(Value* exnRef) {
   1838  MOZ_ASSERT(Classify(op_) == OpKind::ThrowRef);
   1839 
   1840  if (!popWithType(ValType(RefType::exn()), exnRef)) {
   1841    return false;
   1842  }
   1843 
   1844  afterUnconditionalBranch();
   1845  return true;
   1846 }
   1847 
   1848 template <typename Policy>
   1849 inline bool OpIter<Policy>::readRethrow(uint32_t* relativeDepth) {
   1850  MOZ_ASSERT(Classify(op_) == OpKind::Rethrow);
   1851 
   1852  if (!readVarU32(relativeDepth)) {
   1853    return fail("unable to read rethrow depth");
   1854  }
   1855 
   1856  if (*relativeDepth >= controlStack_.length()) {
   1857    return fail("rethrow depth exceeds current nesting level");
   1858  }
   1859  LabelKind kind = controlKind(*relativeDepth);
   1860  if (kind != LabelKind::Catch && kind != LabelKind::CatchAll) {
   1861    return fail("rethrow target was not a catch block");
   1862  }
   1863 
   1864  afterUnconditionalBranch();
   1865  return true;
   1866 }
   1867 
   1868 template <typename Policy>
   1869 inline bool OpIter<Policy>::readUnreachable() {
   1870  MOZ_ASSERT(Classify(op_) == OpKind::Unreachable);
   1871 
   1872  afterUnconditionalBranch();
   1873  return true;
   1874 }
   1875 
   1876 template <typename Policy>
   1877 inline bool OpIter<Policy>::readDrop() {
   1878  MOZ_ASSERT(Classify(op_) == OpKind::Drop);
   1879  StackType type;
   1880  Value value;
   1881  return popStackType(&type, &value);
   1882 }
   1883 
   1884 template <typename Policy>
   1885 inline bool OpIter<Policy>::readUnary(ValType operandType, Value* input) {
   1886  MOZ_ASSERT(Classify(op_) == OpKind::Unary);
   1887 
   1888  if (!popWithType(operandType, input)) {
   1889    return false;
   1890  }
   1891 
   1892  infalliblePush(operandType);
   1893 
   1894  return true;
   1895 }
   1896 
   1897 template <typename Policy>
   1898 inline bool OpIter<Policy>::readConversion(ValType operandType,
   1899                                           ValType resultType, Value* input) {
   1900  MOZ_ASSERT(Classify(op_) == OpKind::Conversion);
   1901 
   1902  if (!popWithType(operandType, input)) {
   1903    return false;
   1904  }
   1905 
   1906  infalliblePush(resultType);
   1907 
   1908  return true;
   1909 }
   1910 
   1911 template <typename Policy>
   1912 inline bool OpIter<Policy>::readBinary(ValType operandType, Value* lhs,
   1913                                       Value* rhs) {
   1914  MOZ_ASSERT(Classify(op_) == OpKind::Binary);
   1915 
   1916  if (!popWithType(operandType, rhs)) {
   1917    return false;
   1918  }
   1919 
   1920  if (!popWithType(operandType, lhs)) {
   1921    return false;
   1922  }
   1923 
   1924  infalliblePush(operandType);
   1925 
   1926  return true;
   1927 }
   1928 
   1929 template <typename Policy>
   1930 inline bool OpIter<Policy>::readComparison(ValType operandType, Value* lhs,
   1931                                           Value* rhs) {
   1932  MOZ_ASSERT(Classify(op_) == OpKind::Comparison);
   1933 
   1934  if (!popWithType(operandType, rhs)) {
   1935    return false;
   1936  }
   1937 
   1938  if (!popWithType(operandType, lhs)) {
   1939    return false;
   1940  }
   1941 
   1942  infalliblePush(ValType::I32);
   1943 
   1944  return true;
   1945 }
   1946 
   1947 template <typename Policy>
   1948 inline bool OpIter<Policy>::readTernary(ValType operandType, Value* v0,
   1949                                        Value* v1, Value* v2) {
   1950  MOZ_ASSERT(Classify(op_) == OpKind::Ternary);
   1951 
   1952  if (!popWithType(operandType, v2)) {
   1953    return false;
   1954  }
   1955 
   1956  if (!popWithType(operandType, v1)) {
   1957    return false;
   1958  }
   1959 
   1960  if (!popWithType(operandType, v0)) {
   1961    return false;
   1962  }
   1963 
   1964  infalliblePush(operandType);
   1965 
   1966  return true;
   1967 }
   1968 
   1969 template <typename Policy>
   1970 inline bool OpIter<Policy>::readLinearMemoryAddress(
   1971    uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
   1972  uint32_t flags;
   1973  if (!readVarU32(&flags)) {
   1974    return fail("unable to read load alignment");
   1975  }
   1976 
   1977  uint8_t alignLog2 = flags & ((1 << 6) - 1);
   1978  uint8_t hasMemoryIndex = flags & (1 << 6);
   1979  uint32_t undefinedBits = flags & ~((1 << 7) - 1);
   1980 
   1981  if (undefinedBits != 0) {
   1982    return fail("invalid memory flags");
   1983  }
   1984 
   1985  if (hasMemoryIndex != 0) {
   1986    if (!readVarU32(&addr->memoryIndex)) {
   1987      return fail("unable to read memory index");
   1988    }
   1989  } else {
   1990    addr->memoryIndex = 0;
   1991  }
   1992 
   1993  if (addr->memoryIndex >= codeMeta_.numMemories()) {
   1994    return fail("memory index out of range");
   1995  }
   1996 
   1997  if (!readVarU64(&addr->offset)) {
   1998    return fail("unable to read load offset");
   1999  }
   2000 
   2001  AddressType at = codeMeta_.memories[addr->memoryIndex].addressType();
   2002  if (at == AddressType::I32 && addr->offset > UINT32_MAX) {
   2003    return fail("offset too large for memory type");
   2004  }
   2005 
   2006  if (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize) {
   2007    return fail("greater than natural alignment");
   2008  }
   2009 
   2010  if (!popWithType(ToValType(at), &addr->base)) {
   2011    return false;
   2012  }
   2013 
   2014  addr->align = uint32_t(1) << alignLog2;
   2015  return true;
   2016 }
   2017 
   2018 template <typename Policy>
   2019 inline bool OpIter<Policy>::readLinearMemoryAddressAligned(
   2020    uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
   2021  if (!readLinearMemoryAddress(byteSize, addr)) {
   2022    return false;
   2023  }
   2024 
   2025  if (addr->align != byteSize) {
   2026    return fail("not natural alignment");
   2027  }
   2028 
   2029  return true;
   2030 }
   2031 
   2032 template <typename Policy>
   2033 inline bool OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize,
   2034                                     LinearMemoryAddress<Value>* addr) {
   2035  MOZ_ASSERT(Classify(op_) == OpKind::Load);
   2036 
   2037  if (!readLinearMemoryAddress(byteSize, addr)) {
   2038    return false;
   2039  }
   2040 
   2041  infalliblePush(resultType);
   2042 
   2043  return true;
   2044 }
   2045 
   2046 template <typename Policy>
   2047 inline bool OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize,
   2048                                      LinearMemoryAddress<Value>* addr,
   2049                                      Value* value) {
   2050  MOZ_ASSERT(Classify(op_) == OpKind::Store);
   2051 
   2052  if (!popWithType(resultType, value)) {
   2053    return false;
   2054  }
   2055 
   2056  return readLinearMemoryAddress(byteSize, addr);
   2057 }
   2058 
   2059 template <typename Policy>
   2060 inline bool OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize,
   2061                                         LinearMemoryAddress<Value>* addr,
   2062                                         Value* value) {
   2063  MOZ_ASSERT(Classify(op_) == OpKind::TeeStore);
   2064 
   2065  if (!popWithType(resultType, value)) {
   2066    return false;
   2067  }
   2068 
   2069  if (!readLinearMemoryAddress(byteSize, addr)) {
   2070    return false;
   2071  }
   2072 
   2073  infalliblePush(TypeAndValue(resultType, *value));
   2074  return true;
   2075 }
   2076 
   2077 template <typename Policy>
   2078 inline bool OpIter<Policy>::readNop() {
   2079  MOZ_ASSERT(Classify(op_) == OpKind::Nop);
   2080 
   2081  return true;
   2082 }
   2083 
   2084 template <typename Policy>
   2085 inline bool OpIter<Policy>::readMemorySize(uint32_t* memoryIndex) {
   2086  MOZ_ASSERT(Classify(op_) == OpKind::MemorySize);
   2087 
   2088  if (!readVarU32(memoryIndex)) {
   2089    return fail("failed to read memory flags");
   2090  }
   2091 
   2092  if (*memoryIndex >= codeMeta_.numMemories()) {
   2093    return fail("memory index out of range for memory.size");
   2094  }
   2095 
   2096  ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType());
   2097  return push(ptrType);
   2098 }
   2099 
   2100 template <typename Policy>
   2101 inline bool OpIter<Policy>::readMemoryGrow(uint32_t* memoryIndex,
   2102                                           Value* input) {
   2103  MOZ_ASSERT(Classify(op_) == OpKind::MemoryGrow);
   2104 
   2105  if (!readVarU32(memoryIndex)) {
   2106    return fail("failed to read memory flags");
   2107  }
   2108 
   2109  if (*memoryIndex >= codeMeta_.numMemories()) {
   2110    return fail("memory index out of range for memory.grow");
   2111  }
   2112 
   2113  ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType());
   2114  if (!popWithType(ptrType, input)) {
   2115    return false;
   2116  }
   2117 
   2118  infalliblePush(ptrType);
   2119 
   2120  return true;
   2121 }
   2122 
   2123 template <typename Policy>
   2124 inline bool OpIter<Policy>::readSelect(bool typed, StackType* type,
   2125                                       Value* trueValue, Value* falseValue,
   2126                                       Value* condition) {
   2127  MOZ_ASSERT(Classify(op_) == OpKind::Select);
   2128 
   2129  if (typed) {
   2130    uint32_t length;
   2131    if (!readVarU32(&length)) {
   2132      return fail("unable to read select result length");
   2133    }
   2134    if (length != 1) {
   2135      return fail("bad number of results");
   2136    }
   2137    ValType result;
   2138    if (!readValType(&result)) {
   2139      return fail("invalid result type for select");
   2140    }
   2141 
   2142    if (!popWithType(ValType::I32, condition)) {
   2143      return false;
   2144    }
   2145    if (!popWithType(result, falseValue)) {
   2146      return false;
   2147    }
   2148    if (!popWithType(result, trueValue)) {
   2149      return false;
   2150    }
   2151 
   2152    *type = StackType(result);
   2153    infalliblePush(*type);
   2154    return true;
   2155  }
   2156 
   2157  if (!popWithType(ValType::I32, condition)) {
   2158    return false;
   2159  }
   2160 
   2161  StackType falseType;
   2162  if (!popStackType(&falseType, falseValue)) {
   2163    return false;
   2164  }
   2165 
   2166  StackType trueType;
   2167  if (!popStackType(&trueType, trueValue)) {
   2168    return false;
   2169  }
   2170 
   2171  if (!falseType.isValidForUntypedSelect() ||
   2172      !trueType.isValidForUntypedSelect()) {
   2173    return fail("invalid types for untyped select");
   2174  }
   2175 
   2176  if (falseType.isStackBottom()) {
   2177    *type = trueType;
   2178  } else if (trueType.isStackBottom() || falseType == trueType) {
   2179    *type = falseType;
   2180  } else {
   2181    return fail("select operand types must match");
   2182  }
   2183 
   2184  infalliblePush(*type);
   2185  return true;
   2186 }
   2187 
   2188 template <typename Policy>
   2189 inline bool OpIter<Policy>::readGetLocal(uint32_t* id) {
   2190  MOZ_ASSERT(Classify(op_) == OpKind::GetLocal);
   2191 
   2192  if (!readVarU32(id)) {
   2193    return fail("unable to read local index");
   2194  }
   2195 
   2196  if (*id >= locals_.length()) {
   2197    return fail("local.get index out of range");
   2198  }
   2199 
   2200  if (unsetLocals_.isUnset(*id)) {
   2201    return fail("local.get read from unset local");
   2202  }
   2203 
   2204  return push(locals_[*id]);
   2205 }
   2206 
   2207 template <typename Policy>
   2208 inline bool OpIter<Policy>::readSetLocal(uint32_t* id, Value* value) {
   2209  MOZ_ASSERT(Classify(op_) == OpKind::SetLocal);
   2210 
   2211  if (!readVarU32(id)) {
   2212    return fail("unable to read local index");
   2213  }
   2214 
   2215  if (*id >= locals_.length()) {
   2216    return fail("local.set index out of range");
   2217  }
   2218 
   2219  if (unsetLocals_.isUnset(*id)) {
   2220    unsetLocals_.set(*id, controlStackDepth());
   2221  }
   2222 
   2223  return popWithType(locals_[*id], value);
   2224 }
   2225 
   2226 template <typename Policy>
   2227 inline bool OpIter<Policy>::readTeeLocal(uint32_t* id, Value* value) {
   2228  MOZ_ASSERT(Classify(op_) == OpKind::TeeLocal);
   2229 
   2230  if (!readVarU32(id)) {
   2231    return fail("unable to read local index");
   2232  }
   2233 
   2234  if (*id >= locals_.length()) {
   2235    return fail("local.set index out of range");
   2236  }
   2237 
   2238  if (unsetLocals_.isUnset(*id)) {
   2239    unsetLocals_.set(*id, controlStackDepth());
   2240  }
   2241 
   2242  ValueVector single;
   2243  if (!checkTopTypeMatches(ResultType::Single(locals_[*id]), &single,
   2244                           /*rewriteStackTypes=*/true)) {
   2245    return false;
   2246  }
   2247 
   2248  *value = single[0];
   2249  return true;
   2250 }
   2251 
   2252 template <typename Policy>
   2253 inline bool OpIter<Policy>::readGetGlobal(uint32_t* id) {
   2254  MOZ_ASSERT(Classify(op_) == OpKind::GetGlobal);
   2255 
   2256  if (!d_.readGlobalIndex(id)) {
   2257    return false;
   2258  }
   2259 
   2260  if (*id >= codeMeta_.globals.length()) {
   2261    return fail("global.get index out of range");
   2262  }
   2263 
   2264  // Initializer expressions can only access previously-defined immutable
   2265  // globals.
   2266  if (kind_ == OpIter::InitExpr && codeMeta_.globals[*id].isMutable()) {
   2267    return fail(
   2268        "global.get in initializer expression must reference a "
   2269        "previously-defined immutable global");
   2270  }
   2271 
   2272  return push(codeMeta_.globals[*id].type());
   2273 }
   2274 
   2275 template <typename Policy>
   2276 inline bool OpIter<Policy>::readSetGlobal(uint32_t* id, Value* value) {
   2277  MOZ_ASSERT(Classify(op_) == OpKind::SetGlobal);
   2278 
   2279  if (!d_.readGlobalIndex(id)) {
   2280    return false;
   2281  }
   2282 
   2283  if (*id >= codeMeta_.globals.length()) {
   2284    return fail("global.set index out of range");
   2285  }
   2286 
   2287  if (!codeMeta_.globals[*id].isMutable()) {
   2288    return fail("can't write an immutable global");
   2289  }
   2290 
   2291  return popWithType(codeMeta_.globals[*id].type(), value);
   2292 }
   2293 
   2294 template <typename Policy>
   2295 inline bool OpIter<Policy>::readTeeGlobal(uint32_t* id, Value* value) {
   2296  MOZ_ASSERT(Classify(op_) == OpKind::TeeGlobal);
   2297 
   2298  if (!d_.readGlobalIndex(id)) {
   2299    return false;
   2300  }
   2301 
   2302  if (*id >= codeMeta_.globals.length()) {
   2303    return fail("global.set index out of range");
   2304  }
   2305 
   2306  if (!codeMeta_.globals[*id].isMutable()) {
   2307    return fail("can't write an immutable global");
   2308  }
   2309 
   2310  ValueVector single;
   2311  if (!checkTopTypeMatches(ResultType::Single(codeMeta_.globals[*id].type()),
   2312                           &single,
   2313                           /*rewriteStackTypes=*/true)) {
   2314    return false;
   2315  }
   2316 
   2317  MOZ_ASSERT(single.length() == 1);
   2318  *value = single[0];
   2319  return true;
   2320 }
   2321 
   2322 template <typename Policy>
   2323 inline bool OpIter<Policy>::readI32Const(int32_t* i32) {
   2324  MOZ_ASSERT(Classify(op_) == OpKind::I32Const);
   2325 
   2326  if (!d_.readI32Const(i32)) {
   2327    return false;
   2328  }
   2329 
   2330  return push(ValType::I32);
   2331 }
   2332 
   2333 template <typename Policy>
   2334 inline bool OpIter<Policy>::readI64Const(int64_t* i64) {
   2335  MOZ_ASSERT(Classify(op_) == OpKind::I64Const);
   2336 
   2337  if (!d_.readI64Const(i64)) {
   2338    return false;
   2339  }
   2340 
   2341  return push(ValType::I64);
   2342 }
   2343 
   2344 template <typename Policy>
   2345 inline bool OpIter<Policy>::readF32Const(float* f32) {
   2346  MOZ_ASSERT(Classify(op_) == OpKind::F32Const);
   2347 
   2348  if (!d_.readF32Const(f32)) {
   2349    return false;
   2350  }
   2351 
   2352  return push(ValType::F32);
   2353 }
   2354 
   2355 template <typename Policy>
   2356 inline bool OpIter<Policy>::readF64Const(double* f64) {
   2357  MOZ_ASSERT(Classify(op_) == OpKind::F64Const);
   2358 
   2359  if (!d_.readF64Const(f64)) {
   2360    return false;
   2361  }
   2362 
   2363  return push(ValType::F64);
   2364 }
   2365 
   2366 template <typename Policy>
   2367 inline bool OpIter<Policy>::readRefFunc(uint32_t* funcIndex) {
   2368  MOZ_ASSERT(Classify(op_) == OpKind::RefFunc);
   2369 
   2370  if (!d_.readFuncIndex(funcIndex)) {
   2371    return false;
   2372  }
   2373  if (*funcIndex >= codeMeta_.funcs.length()) {
   2374    return fail("function index out of range");
   2375  }
   2376  if (kind_ == OpIter::Func && !codeMeta_.funcs[*funcIndex].canRefFunc()) {
   2377    return fail(
   2378        "function index is not declared in a section before the code section");
   2379  }
   2380 
   2381  const uint32_t typeIndex = codeMeta_.funcs[*funcIndex].typeIndex;
   2382  const TypeDef& typeDef = codeMeta_.types->type(typeIndex);
   2383  return push(RefType::fromTypeDef(&typeDef, false));
   2384 }
   2385 
   2386 template <typename Policy>
   2387 inline bool OpIter<Policy>::readRefNull(RefType* type) {
   2388  MOZ_ASSERT(Classify(op_) == OpKind::RefNull);
   2389 
   2390  if (!d_.readRefNull(*codeMeta_.types, codeMeta_.features(), type)) {
   2391    return false;
   2392  }
   2393  return push(*type);
   2394 }
   2395 
   2396 template <typename Policy>
   2397 inline bool OpIter<Policy>::readRefIsNull(Value* input) {
   2398  MOZ_ASSERT(Classify(op_) == OpKind::RefIsNull);
   2399 
   2400  StackType type;
   2401  if (!popWithRefType(input, &type)) {
   2402    return false;
   2403  }
   2404  return push(ValType::I32);
   2405 }
   2406 
   2407 template <typename Policy>
   2408 inline bool OpIter<Policy>::readRefAsNonNull(Value* input) {
   2409  MOZ_ASSERT(Classify(op_) == OpKind::RefAsNonNull);
   2410 
   2411  StackType type;
   2412  if (!popWithRefType(input, &type)) {
   2413    return false;
   2414  }
   2415 
   2416  if (type.isStackBottom()) {
   2417    infalliblePush(type);
   2418  } else {
   2419    infalliblePush(TypeAndValue(type.asNonNullable(), *input));
   2420  }
   2421  return true;
   2422 }
   2423 
   2424 template <typename Policy>
   2425 inline bool OpIter<Policy>::readBrOnNull(uint32_t* relativeDepth,
   2426                                         ResultType* type, ValueVector* values,
   2427                                         Value* condition) {
   2428  MOZ_ASSERT(Classify(op_) == OpKind::BrOnNull);
   2429 
   2430  if (!readVarU32(relativeDepth)) {
   2431    return fail("unable to read br_on_null depth");
   2432  }
   2433 
   2434  StackType refType;
   2435  if (!popWithRefType(condition, &refType)) {
   2436    return false;
   2437  }
   2438 
   2439  if (!checkBranchValueAndPush(*relativeDepth, type, values,
   2440                               /*rewriteStackTypes=*/true)) {
   2441    return false;
   2442  }
   2443 
   2444  if (refType.isStackBottom()) {
   2445    return push(refType);
   2446  }
   2447  return push(TypeAndValue(refType.asNonNullable(), *condition));
   2448 }
   2449 
   2450 template <typename Policy>
   2451 inline bool OpIter<Policy>::readBrOnNonNull(uint32_t* relativeDepth,
   2452                                            ResultType* type,
   2453                                            ValueVector* values,
   2454                                            Value* condition) {
   2455  MOZ_ASSERT(Classify(op_) == OpKind::BrOnNonNull);
   2456 
   2457  if (!readVarU32(relativeDepth)) {
   2458    return fail("unable to read br_on_non_null depth");
   2459  }
   2460 
   2461  Control* block = nullptr;
   2462  if (!getControl(*relativeDepth, &block)) {
   2463    return false;
   2464  }
   2465 
   2466  *type = block->branchTargetType();
   2467 
   2468  // Check we at least have one type in the branch target type.
   2469  if (type->length() < 1) {
   2470    return fail("type mismatch: target block type expected to be [_, ref]");
   2471  }
   2472 
   2473  // Pop the condition reference.
   2474  StackType refType;
   2475  if (!popWithRefType(condition, &refType)) {
   2476    return false;
   2477  }
   2478 
   2479  // Push non-nullable version of condition reference on the stack, prior
   2480  // checking the target type below.
   2481  if (!(refType.isStackBottom()
   2482            ? push(refType)
   2483            : push(TypeAndValue(refType.asNonNullable(), *condition)))) {
   2484    return false;
   2485  }
   2486 
   2487  // Check if the type stack matches the branch target type.
   2488  if (!checkTopTypeMatches(*type, values, /*rewriteStackTypes=*/true)) {
   2489    return false;
   2490  }
   2491 
   2492  // Pop the condition reference -- the null-branch does not receive the value.
   2493  StackType unusedType;
   2494  Value unusedValue;
   2495  return popStackType(&unusedType, &unusedValue);
   2496 }
   2497 
   2498 template <typename Policy>
   2499 inline bool OpIter<Policy>::popCallArgs(const ValTypeVector& expectedTypes,
   2500                                        ValueVector* values) {
   2501  // Iterate through the argument types backward so that pops occur in the
   2502  // right order.
   2503 
   2504  if (!values->resize(expectedTypes.length())) {
   2505    return false;
   2506  }
   2507 
   2508  for (int32_t i = int32_t(expectedTypes.length()) - 1; i >= 0; i--) {
   2509    if (!popWithType(expectedTypes[i], &(*values)[i])) {
   2510      return false;
   2511    }
   2512  }
   2513 
   2514  return true;
   2515 }
   2516 
   2517 template <typename Policy>
   2518 inline bool OpIter<Policy>::readCall(uint32_t* funcIndex,
   2519                                     ValueVector* argValues) {
   2520  MOZ_ASSERT(Classify(op_) == OpKind::Call);
   2521 
   2522  if (!readVarU32(funcIndex)) {
   2523    return fail("unable to read call function index");
   2524  }
   2525 
   2526  if (*funcIndex >= codeMeta_.funcs.length()) {
   2527    return fail("callee index out of range");
   2528  }
   2529 
   2530  const FuncType& funcType = codeMeta_.getFuncType(*funcIndex);
   2531 
   2532  if (!popCallArgs(funcType.args(), argValues)) {
   2533    return false;
   2534  }
   2535 
   2536  return push(ResultType::Vector(funcType.results()));
   2537 }
   2538 
   2539 template <typename Policy>
   2540 inline bool OpIter<Policy>::readReturnCall(uint32_t* funcIndex,
   2541                                           ValueVector* argValues) {
   2542  MOZ_ASSERT(Classify(op_) == OpKind::ReturnCall);
   2543 
   2544  featureUsage_ |= FeatureUsage::ReturnCall;
   2545 
   2546  if (!readVarU32(funcIndex)) {
   2547    return fail("unable to read call function index");
   2548  }
   2549 
   2550  if (*funcIndex >= codeMeta_.funcs.length()) {
   2551    return fail("callee index out of range");
   2552  }
   2553 
   2554  const FuncType& funcType = codeMeta_.getFuncType(*funcIndex);
   2555 
   2556  if (!popCallArgs(funcType.args(), argValues)) {
   2557    return false;
   2558  }
   2559 
   2560  // Check if callee results are subtypes of caller's.
   2561  Control& body = controlStack_[0];
   2562  MOZ_ASSERT(body.kind() == LabelKind::Body);
   2563  if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()),
   2564                        body.resultType())) {
   2565    return false;
   2566  }
   2567 
   2568  afterUnconditionalBranch();
   2569  return true;
   2570 }
   2571 
   2572 template <typename Policy>
   2573 inline bool OpIter<Policy>::readCallIndirect(uint32_t* funcTypeIndex,
   2574                                             uint32_t* tableIndex,
   2575                                             Value* callee,
   2576                                             ValueVector* argValues) {
   2577  MOZ_ASSERT(Classify(op_) == OpKind::CallIndirect);
   2578  MOZ_ASSERT(funcTypeIndex != tableIndex);
   2579 
   2580  if (!readVarU32(funcTypeIndex)) {
   2581    return fail("unable to read call_indirect signature index");
   2582  }
   2583 
   2584  if (*funcTypeIndex >= codeMeta_.numTypes()) {
   2585    return fail("signature index out of range");
   2586  }
   2587 
   2588  if (!readVarU32(tableIndex)) {
   2589    return fail("unable to read call_indirect table index");
   2590  }
   2591  if (*tableIndex >= codeMeta_.tables.length()) {
   2592    // Special case this for improved user experience.
   2593    if (!codeMeta_.tables.length()) {
   2594      return fail("can't call_indirect without a table");
   2595    }
   2596    return fail("table index out of range for call_indirect");
   2597  }
   2598  if (!codeMeta_.tables[*tableIndex].elemType.isFuncHierarchy()) {
   2599    return fail("indirect calls must go through a table of 'funcref'");
   2600  }
   2601 
   2602  if (!popWithType(ToValType(codeMeta_.tables[*tableIndex].addressType()),
   2603                   callee)) {
   2604    return false;
   2605  }
   2606 
   2607  const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex);
   2608  if (!typeDef.isFuncType()) {
   2609    return fail("expected signature type");
   2610  }
   2611  const FuncType& funcType = typeDef.funcType();
   2612 
   2613  if (!popCallArgs(funcType.args(), argValues)) {
   2614    return false;
   2615  }
   2616 
   2617  return push(ResultType::Vector(funcType.results()));
   2618 }
   2619 
   2620 template <typename Policy>
   2621 inline bool OpIter<Policy>::readReturnCallIndirect(uint32_t* funcTypeIndex,
   2622                                                   uint32_t* tableIndex,
   2623                                                   Value* callee,
   2624                                                   ValueVector* argValues) {
   2625  MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallIndirect);
   2626  MOZ_ASSERT(funcTypeIndex != tableIndex);
   2627 
   2628  featureUsage_ |= FeatureUsage::ReturnCall;
   2629 
   2630  if (!readVarU32(funcTypeIndex)) {
   2631    return fail("unable to read return_call_indirect signature index");
   2632  }
   2633  if (*funcTypeIndex >= codeMeta_.numTypes()) {
   2634    return fail("signature index out of range");
   2635  }
   2636 
   2637  if (!readVarU32(tableIndex)) {
   2638    return fail("unable to read return_call_indirect table index");
   2639  }
   2640  if (*tableIndex >= codeMeta_.tables.length()) {
   2641    // Special case this for improved user experience.
   2642    if (!codeMeta_.tables.length()) {
   2643      return fail("can't return_call_indirect without a table");
   2644    }
   2645    return fail("table index out of range for return_call_indirect");
   2646  }
   2647  if (!codeMeta_.tables[*tableIndex].elemType.isFuncHierarchy()) {
   2648    return fail("indirect calls must go through a table of 'funcref'");
   2649  }
   2650 
   2651  if (!popWithType(ToValType(codeMeta_.tables[*tableIndex].addressType()),
   2652                   callee)) {
   2653    return false;
   2654  }
   2655 
   2656  const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex);
   2657  if (!typeDef.isFuncType()) {
   2658    return fail("expected signature type");
   2659  }
   2660  const FuncType& funcType = typeDef.funcType();
   2661 
   2662  if (!popCallArgs(funcType.args(), argValues)) {
   2663    return false;
   2664  }
   2665 
   2666  // Check if callee results are subtypes of caller's.
   2667  Control& body = controlStack_[0];
   2668  MOZ_ASSERT(body.kind() == LabelKind::Body);
   2669  if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()),
   2670                        body.resultType())) {
   2671    return false;
   2672  }
   2673 
   2674  afterUnconditionalBranch();
   2675  return true;
   2676 }
   2677 
   2678 template <typename Policy>
   2679 inline bool OpIter<Policy>::readCallRef(uint32_t* funcTypeIndex, Value* callee,
   2680                                        ValueVector* argValues) {
   2681  MOZ_ASSERT(Classify(op_) == OpKind::CallRef);
   2682 
   2683  if (!readFuncTypeIndex(funcTypeIndex)) {
   2684    return false;
   2685  }
   2686 
   2687  const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex);
   2688  const FuncType& funcType = typeDef.funcType();
   2689 
   2690  if (!popWithType(ValType(RefType::fromTypeDef(&typeDef, true)), callee)) {
   2691    return false;
   2692  }
   2693 
   2694  if (!popCallArgs(funcType.args(), argValues)) {
   2695    return false;
   2696  }
   2697 
   2698  return push(ResultType::Vector(funcType.results()));
   2699 }
   2700 
   2701 template <typename Policy>
   2702 inline bool OpIter<Policy>::readReturnCallRef(uint32_t* funcTypeIndex,
   2703                                              Value* callee,
   2704                                              ValueVector* argValues) {
   2705  MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallRef);
   2706 
   2707  featureUsage_ |= FeatureUsage::ReturnCall;
   2708 
   2709  if (!readFuncTypeIndex(funcTypeIndex)) {
   2710    return false;
   2711  }
   2712 
   2713  const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex);
   2714  const FuncType& funcType = typeDef.funcType();
   2715 
   2716  if (!popWithType(ValType(RefType::fromTypeDef(&typeDef, true)), callee)) {
   2717    return false;
   2718  }
   2719 
   2720  if (!popCallArgs(funcType.args(), argValues)) {
   2721    return false;
   2722  }
   2723 
   2724  // Check if callee results are subtypes of caller's.
   2725  Control& body = controlStack_[0];
   2726  MOZ_ASSERT(body.kind() == LabelKind::Body);
   2727  if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()),
   2728                        body.resultType())) {
   2729    return false;
   2730  }
   2731 
   2732  afterUnconditionalBranch();
   2733  return true;
   2734 }
   2735 
   2736 template <typename Policy>
   2737 inline bool OpIter<Policy>::readOldCallDirect(uint32_t numFuncImports,
   2738                                              uint32_t* funcIndex,
   2739                                              ValueVector* argValues) {
   2740  MOZ_ASSERT(Classify(op_) == OpKind::OldCallDirect);
   2741 
   2742  uint32_t funcDefIndex;
   2743  if (!readVarU32(&funcDefIndex)) {
   2744    return fail("unable to read call function index");
   2745  }
   2746 
   2747  if (UINT32_MAX - funcDefIndex < numFuncImports) {
   2748    return fail("callee index out of range");
   2749  }
   2750 
   2751  *funcIndex = numFuncImports + funcDefIndex;
   2752 
   2753  if (*funcIndex >= codeMeta_.funcs.length()) {
   2754    return fail("callee index out of range");
   2755  }
   2756 
   2757  const FuncType& funcType = codeMeta_.getFuncType(*funcIndex);
   2758 
   2759  if (!popCallArgs(funcType.args(), argValues)) {
   2760    return false;
   2761  }
   2762 
   2763  return push(ResultType::Vector(funcType.results()));
   2764 }
   2765 
   2766 template <typename Policy>
   2767 inline bool OpIter<Policy>::readOldCallIndirect(uint32_t* funcTypeIndex,
   2768                                                Value* callee,
   2769                                                ValueVector* argValues) {
   2770  MOZ_ASSERT(Classify(op_) == OpKind::OldCallIndirect);
   2771 
   2772  if (!readVarU32(funcTypeIndex)) {
   2773    return fail("unable to read call_indirect signature index");
   2774  }
   2775 
   2776  if (*funcTypeIndex >= codeMeta_.numTypes()) {
   2777    return fail("signature index out of range");
   2778  }
   2779 
   2780  const TypeDef& typeDef = codeMeta_.types->type(*funcTypeIndex);
   2781  if (!typeDef.isFuncType()) {
   2782    return fail("expected signature type");
   2783  }
   2784  const FuncType& funcType = typeDef.funcType();
   2785 
   2786  if (!popCallArgs(funcType.args(), argValues)) {
   2787    return false;
   2788  }
   2789 
   2790  if (!popWithType(ValType::I32, callee)) {
   2791    return false;
   2792  }
   2793 
   2794  return push(ResultType::Vector(funcType.results()));
   2795 }
   2796 
   2797 template <typename Policy>
   2798 inline bool OpIter<Policy>::readNotify(LinearMemoryAddress<Value>* addr,
   2799                                       Value* count) {
   2800  MOZ_ASSERT(Classify(op_) == OpKind::Notify);
   2801 
   2802  if (!popWithType(ValType::I32, count)) {
   2803    return false;
   2804  }
   2805 
   2806  uint32_t byteSize = 4;  // Per spec; smallest WAIT is i32.
   2807 
   2808  if (!readLinearMemoryAddressAligned(byteSize, addr)) {
   2809    return false;
   2810  }
   2811 
   2812  infalliblePush(ValType::I32);
   2813  return true;
   2814 }
   2815 
   2816 template <typename Policy>
   2817 inline bool OpIter<Policy>::readWait(LinearMemoryAddress<Value>* addr,
   2818                                     ValType valueType, uint32_t byteSize,
   2819                                     Value* value, Value* timeout) {
   2820  MOZ_ASSERT(Classify(op_) == OpKind::Wait);
   2821 
   2822  if (!popWithType(ValType::I64, timeout)) {
   2823    return false;
   2824  }
   2825 
   2826  if (!popWithType(valueType, value)) {
   2827    return false;
   2828  }
   2829 
   2830  if (!readLinearMemoryAddressAligned(byteSize, addr)) {
   2831    return false;
   2832  }
   2833 
   2834  infalliblePush(ValType::I32);
   2835  return true;
   2836 }
   2837 
   2838 template <typename Policy>
   2839 inline bool OpIter<Policy>::readFence() {
   2840  MOZ_ASSERT(Classify(op_) == OpKind::Fence);
   2841  uint8_t flags;
   2842  if (!readFixedU8(&flags)) {
   2843    return fail("expected memory order after fence");
   2844  }
   2845  if (flags != 0) {
   2846    return fail("non-zero memory order not supported yet");
   2847  }
   2848  return true;
   2849 }
   2850 
   2851 template <typename Policy>
   2852 inline bool OpIter<Policy>::readAtomicLoad(LinearMemoryAddress<Value>* addr,
   2853                                           ValType resultType,
   2854                                           uint32_t byteSize) {
   2855  MOZ_ASSERT(Classify(op_) == OpKind::AtomicLoad);
   2856 
   2857  if (!readLinearMemoryAddressAligned(byteSize, addr)) {
   2858    return false;
   2859  }
   2860 
   2861  infalliblePush(resultType);
   2862  return true;
   2863 }
   2864 
   2865 template <typename Policy>
   2866 inline bool OpIter<Policy>::readAtomicStore(LinearMemoryAddress<Value>* addr,
   2867                                            ValType resultType,
   2868                                            uint32_t byteSize, Value* value) {
   2869  MOZ_ASSERT(Classify(op_) == OpKind::AtomicStore);
   2870 
   2871  if (!popWithType(resultType, value)) {
   2872    return false;
   2873  }
   2874 
   2875  return readLinearMemoryAddressAligned(byteSize, addr);
   2876 }
   2877 
   2878 template <typename Policy>
   2879 inline bool OpIter<Policy>::readAtomicRMW(LinearMemoryAddress<Value>* addr,
   2880                                          ValType resultType, uint32_t byteSize,
   2881                                          Value* value) {
   2882  MOZ_ASSERT(Classify(op_) == OpKind::AtomicRMW);
   2883 
   2884  if (!popWithType(resultType, value)) {
   2885    return false;
   2886  }
   2887 
   2888  if (!readLinearMemoryAddressAligned(byteSize, addr)) {
   2889    return false;
   2890  }
   2891 
   2892  infalliblePush(resultType);
   2893  return true;
   2894 }
   2895 
   2896 template <typename Policy>
   2897 inline bool OpIter<Policy>::readAtomicCmpXchg(LinearMemoryAddress<Value>* addr,
   2898                                              ValType resultType,
   2899                                              uint32_t byteSize,
   2900                                              Value* oldValue,
   2901                                              Value* newValue) {
   2902  MOZ_ASSERT(Classify(op_) == OpKind::AtomicCmpXchg);
   2903 
   2904  if (!popWithType(resultType, newValue)) {
   2905    return false;
   2906  }
   2907 
   2908  if (!popWithType(resultType, oldValue)) {
   2909    return false;
   2910  }
   2911 
   2912  if (!readLinearMemoryAddressAligned(byteSize, addr)) {
   2913    return false;
   2914  }
   2915 
   2916  infalliblePush(resultType);
   2917  return true;
   2918 }
   2919 
   2920 template <typename Policy>
   2921 inline bool OpIter<Policy>::readMemOrTableCopy(bool isMem,
   2922                                               uint32_t* dstMemOrTableIndex,
   2923                                               Value* dst,
   2924                                               uint32_t* srcMemOrTableIndex,
   2925                                               Value* src, Value* len) {
   2926  MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableCopy);
   2927  MOZ_ASSERT(dstMemOrTableIndex != srcMemOrTableIndex);
   2928 
   2929  // Spec requires (dest, src) as of 2019-10-04.
   2930  if (!readVarU32(dstMemOrTableIndex)) {
   2931    return false;
   2932  }
   2933  if (!readVarU32(srcMemOrTableIndex)) {
   2934    return false;
   2935  }
   2936 
   2937  if (isMem) {
   2938    if (*srcMemOrTableIndex >= codeMeta_.memories.length() ||
   2939        *dstMemOrTableIndex >= codeMeta_.memories.length()) {
   2940      return fail("memory index out of range for memory.copy");
   2941    }
   2942  } else {
   2943    if (*dstMemOrTableIndex >= codeMeta_.tables.length() ||
   2944        *srcMemOrTableIndex >= codeMeta_.tables.length()) {
   2945      return fail("table index out of range for table.copy");
   2946    }
   2947    ValType dstElemType = codeMeta_.tables[*dstMemOrTableIndex].elemType;
   2948    ValType srcElemType = codeMeta_.tables[*srcMemOrTableIndex].elemType;
   2949    if (!checkIsSubtypeOf(srcElemType, dstElemType)) {
   2950      return false;
   2951    }
   2952  }
   2953 
   2954  ValType dstPtrType;
   2955  ValType srcPtrType;
   2956  ValType lenType;
   2957  if (isMem) {
   2958    dstPtrType =
   2959        ToValType(codeMeta_.memories[*dstMemOrTableIndex].addressType());
   2960    srcPtrType =
   2961        ToValType(codeMeta_.memories[*srcMemOrTableIndex].addressType());
   2962  } else {
   2963    dstPtrType = ToValType(codeMeta_.tables[*dstMemOrTableIndex].addressType());
   2964    srcPtrType = ToValType(codeMeta_.tables[*srcMemOrTableIndex].addressType());
   2965  }
   2966  if (dstPtrType == ValType::I64 && srcPtrType == ValType::I64) {
   2967    lenType = ValType::I64;
   2968  } else {
   2969    lenType = ValType::I32;
   2970  }
   2971 
   2972  if (!popWithType(lenType, len)) {
   2973    return false;
   2974  }
   2975 
   2976  if (!popWithType(srcPtrType, src)) {
   2977    return false;
   2978  }
   2979 
   2980  return popWithType(dstPtrType, dst);
   2981 }
   2982 
   2983 template <typename Policy>
   2984 inline bool OpIter<Policy>::readDataOrElemDrop(bool isData,
   2985                                               uint32_t* segIndex) {
   2986  MOZ_ASSERT(Classify(op_) == OpKind::DataOrElemDrop);
   2987 
   2988  if (!readVarU32(segIndex)) {
   2989    return fail("unable to read segment index");
   2990  }
   2991 
   2992  if (isData) {
   2993    if (codeMeta_.dataCount.isNothing()) {
   2994      return fail("data.drop requires a DataCount section");
   2995    }
   2996    if (*segIndex >= *codeMeta_.dataCount) {
   2997      return fail("data.drop segment index out of range");
   2998    }
   2999  } else {
   3000    if (*segIndex >= codeMeta_.elemSegmentTypes.length()) {
   3001      return fail("element segment index out of range for elem.drop");
   3002    }
   3003  }
   3004 
   3005  return true;
   3006 }
   3007 
   3008 template <typename Policy>
   3009 inline bool OpIter<Policy>::readMemFill(uint32_t* memoryIndex, Value* start,
   3010                                        Value* val, Value* len) {
   3011  MOZ_ASSERT(Classify(op_) == OpKind::MemFill);
   3012 
   3013  if (!readVarU32(memoryIndex)) {
   3014    return fail("failed to read memory index");
   3015  }
   3016 
   3017  if (*memoryIndex >= codeMeta_.numMemories()) {
   3018    return fail("memory index out of range for memory.fill");
   3019  }
   3020 
   3021  ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType());
   3022 
   3023  if (!popWithType(ptrType, len)) {
   3024    return false;
   3025  }
   3026 
   3027  if (!popWithType(ValType::I32, val)) {
   3028    return false;
   3029  }
   3030 
   3031  return popWithType(ptrType, start);
   3032 }
   3033 
   3034 template <typename Policy>
   3035 inline bool OpIter<Policy>::readMemOrTableInit(bool isMem, uint32_t* segIndex,
   3036                                               uint32_t* dstMemOrTableIndex,
   3037                                               Value* dst, Value* src,
   3038                                               Value* len) {
   3039  MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableInit);
   3040  MOZ_ASSERT(segIndex != dstMemOrTableIndex);
   3041 
   3042  if (!readVarU32(segIndex)) {
   3043    return fail("unable to read segment index");
   3044  }
   3045 
   3046  uint32_t memOrTableIndex = 0;
   3047  if (!readVarU32(&memOrTableIndex)) {
   3048    return false;
   3049  }
   3050 
   3051  if (isMem) {
   3052    if (memOrTableIndex >= codeMeta_.memories.length()) {
   3053      return fail("memory index out of range for memory.init");
   3054    }
   3055    *dstMemOrTableIndex = memOrTableIndex;
   3056 
   3057    if (codeMeta_.dataCount.isNothing()) {
   3058      return fail("memory.init requires a DataCount section");
   3059    }
   3060    if (*segIndex >= *codeMeta_.dataCount) {
   3061      return fail("memory.init segment index out of range");
   3062    }
   3063  } else {
   3064    if (memOrTableIndex >= codeMeta_.tables.length()) {
   3065      return fail("table index out of range for table.init");
   3066    }
   3067    *dstMemOrTableIndex = memOrTableIndex;
   3068 
   3069    if (*segIndex >= codeMeta_.elemSegmentTypes.length()) {
   3070      return fail("table.init segment index out of range");
   3071    }
   3072    if (!checkIsSubtypeOf(codeMeta_.elemSegmentTypes[*segIndex],
   3073                          codeMeta_.tables[*dstMemOrTableIndex].elemType)) {
   3074      return false;
   3075    }
   3076  }
   3077 
   3078  if (!popWithType(ValType::I32, len)) {
   3079    return false;
   3080  }
   3081 
   3082  if (!popWithType(ValType::I32, src)) {
   3083    return false;
   3084  }
   3085 
   3086  ValType ptrType =
   3087      isMem ? ToValType(codeMeta_.memories[*dstMemOrTableIndex].addressType())
   3088            : ToValType(codeMeta_.tables[*dstMemOrTableIndex].addressType());
   3089  return popWithType(ptrType, dst);
   3090 }
   3091 
   3092 template <typename Policy>
   3093 inline bool OpIter<Policy>::readTableFill(uint32_t* tableIndex, Value* start,
   3094                                          Value* val, Value* len) {
   3095  MOZ_ASSERT(Classify(op_) == OpKind::TableFill);
   3096 
   3097  if (!readVarU32(tableIndex)) {
   3098    return fail("unable to read table index");
   3099  }
   3100  if (*tableIndex >= codeMeta_.tables.length()) {
   3101    return fail("table index out of range for table.fill");
   3102  }
   3103 
   3104  const TableDesc& table = codeMeta_.tables[*tableIndex];
   3105 
   3106  if (!popWithType(ToValType(table.addressType()), len)) {
   3107    return false;
   3108  }
   3109  if (!popWithType(table.elemType, val)) {
   3110    return false;
   3111  }
   3112  return popWithType(ToValType(table.addressType()), start);
   3113 }
   3114 
   3115 template <typename Policy>
   3116 inline bool OpIter<Policy>::readMemDiscard(uint32_t* memoryIndex, Value* start,
   3117                                           Value* len) {
   3118  MOZ_ASSERT(Classify(op_) == OpKind::MemDiscard);
   3119 
   3120  if (!readVarU32(memoryIndex)) {
   3121    return fail("failed to read memory index");
   3122  }
   3123  if (*memoryIndex >= codeMeta_.memories.length()) {
   3124    return fail("memory index out of range for memory.discard");
   3125  }
   3126 
   3127  ValType ptrType = ToValType(codeMeta_.memories[*memoryIndex].addressType());
   3128 
   3129  if (!popWithType(ptrType, len)) {
   3130    return false;
   3131  }
   3132 
   3133  return popWithType(ptrType, start);
   3134 }
   3135 
   3136 template <typename Policy>
   3137 inline bool OpIter<Policy>::readTableGet(uint32_t* tableIndex, Value* address) {
   3138  MOZ_ASSERT(Classify(op_) == OpKind::TableGet);
   3139 
   3140  if (!readVarU32(tableIndex)) {
   3141    return fail("unable to read table index");
   3142  }
   3143  if (*tableIndex >= codeMeta_.tables.length()) {
   3144    return fail("table index out of range for table.get");
   3145  }
   3146 
   3147  const TableDesc& table = codeMeta_.tables[*tableIndex];
   3148 
   3149  if (!popWithType(ToValType(table.addressType()), address)) {
   3150    return false;
   3151  }
   3152 
   3153  infalliblePush(table.elemType);
   3154  return true;
   3155 }
   3156 
   3157 template <typename Policy>
   3158 inline bool OpIter<Policy>::readTableGrow(uint32_t* tableIndex,
   3159                                          Value* initValue, Value* delta) {
   3160  MOZ_ASSERT(Classify(op_) == OpKind::TableGrow);
   3161 
   3162  if (!readVarU32(tableIndex)) {
   3163    return fail("unable to read table index");
   3164  }
   3165  if (*tableIndex >= codeMeta_.tables.length()) {
   3166    return fail("table index out of range for table.grow");
   3167  }
   3168 
   3169  const TableDesc& table = codeMeta_.tables[*tableIndex];
   3170 
   3171  if (!popWithType(ToValType(table.addressType()), delta)) {
   3172    return false;
   3173  }
   3174  if (!popWithType(table.elemType, initValue)) {
   3175    return false;
   3176  }
   3177 
   3178  infalliblePush(ToValType(table.addressType()));
   3179  return true;
   3180 }
   3181 
   3182 template <typename Policy>
   3183 inline bool OpIter<Policy>::readTableSet(uint32_t* tableIndex, Value* address,
   3184                                         Value* value) {
   3185  MOZ_ASSERT(Classify(op_) == OpKind::TableSet);
   3186 
   3187  if (!readVarU32(tableIndex)) {
   3188    return fail("unable to read table index");
   3189  }
   3190  if (*tableIndex >= codeMeta_.tables.length()) {
   3191    return fail("table index out of range for table.set");
   3192  }
   3193 
   3194  const TableDesc& table = codeMeta_.tables[*tableIndex];
   3195 
   3196  if (!popWithType(table.elemType, value)) {
   3197    return false;
   3198  }
   3199 
   3200  return popWithType(ToValType(table.addressType()), address);
   3201 }
   3202 
   3203 template <typename Policy>
   3204 inline bool OpIter<Policy>::readTableSize(uint32_t* tableIndex) {
   3205  MOZ_ASSERT(Classify(op_) == OpKind::TableSize);
   3206 
   3207  *tableIndex = 0;
   3208 
   3209  if (!readVarU32(tableIndex)) {
   3210    return fail("unable to read table index");
   3211  }
   3212  if (*tableIndex >= codeMeta_.tables.length()) {
   3213    return fail("table index out of range for table.size");
   3214  }
   3215 
   3216  return push(ToValType(codeMeta_.tables[*tableIndex].addressType()));
   3217 }
   3218 
   3219 template <typename Policy>
   3220 inline bool OpIter<Policy>::readGcTypeIndex(uint32_t* typeIndex) {
   3221  if (!d_.readTypeIndex(typeIndex)) {
   3222    return false;
   3223  }
   3224 
   3225  if (*typeIndex >= codeMeta_.types->length()) {
   3226    return fail("type index out of range");
   3227  }
   3228 
   3229  if (!codeMeta_.types->type(*typeIndex).isStructType() &&
   3230      !codeMeta_.types->type(*typeIndex).isArrayType()) {
   3231    return fail("not a gc type");
   3232  }
   3233 
   3234  return true;
   3235 }
   3236 
   3237 template <typename Policy>
   3238 inline bool OpIter<Policy>::readStructTypeIndex(uint32_t* typeIndex) {
   3239  if (!readVarU32(typeIndex)) {
   3240    return fail("unable to read type index");
   3241  }
   3242 
   3243  if (*typeIndex >= codeMeta_.types->length()) {
   3244    return fail("type index out of range");
   3245  }
   3246 
   3247  if (!codeMeta_.types->type(*typeIndex).isStructType()) {
   3248    return fail("not a struct type");
   3249  }
   3250 
   3251  return true;
   3252 }
   3253 
   3254 template <typename Policy>
   3255 inline bool OpIter<Policy>::readArrayTypeIndex(uint32_t* typeIndex) {
   3256  if (!readVarU32(typeIndex)) {
   3257    return fail("unable to read type index");
   3258  }
   3259 
   3260  if (*typeIndex >= codeMeta_.types->length()) {
   3261    return fail("type index out of range");
   3262  }
   3263 
   3264  if (!codeMeta_.types->type(*typeIndex).isArrayType()) {
   3265    return fail("not an array type");
   3266  }
   3267 
   3268  return true;
   3269 }
   3270 
   3271 template <typename Policy>
   3272 inline bool OpIter<Policy>::readFuncTypeIndex(uint32_t* typeIndex) {
   3273  if (!readVarU32(typeIndex)) {
   3274    return fail("unable to read type index");
   3275  }
   3276 
   3277  if (*typeIndex >= codeMeta_.types->length()) {
   3278    return fail("type index out of range");
   3279  }
   3280 
   3281  if (!codeMeta_.types->type(*typeIndex).isFuncType()) {
   3282    return fail("not an func type");
   3283  }
   3284 
   3285  return true;
   3286 }
   3287 
   3288 template <typename Policy>
   3289 inline bool OpIter<Policy>::readFieldIndex(uint32_t* fieldIndex,
   3290                                           const StructType& structType) {
   3291  if (!readVarU32(fieldIndex)) {
   3292    return fail("unable to read field index");
   3293  }
   3294 
   3295  if (structType.fields_.length() <= *fieldIndex) {
   3296    return fail("field index out of range");
   3297  }
   3298 
   3299  return true;
   3300 }
   3301 
   3302 template <typename Policy>
   3303 inline bool OpIter<Policy>::readStructNew(uint32_t* typeIndex,
   3304                                          ValueVector* argValues) {
   3305  MOZ_ASSERT(Classify(op_) == OpKind::StructNew);
   3306 
   3307  if (!readStructTypeIndex(typeIndex)) {
   3308    return false;
   3309  }
   3310 
   3311  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3312  const StructType& structType = typeDef.structType();
   3313 
   3314  if (!argValues->resize(structType.fields_.length())) {
   3315    return false;
   3316  }
   3317 
   3318  static_assert(MaxStructFields <= INT32_MAX, "Or we iloop below");
   3319 
   3320  for (int32_t i = structType.fields_.length() - 1; i >= 0; i--) {
   3321    if (!popWithType(structType.fields_[i].type.widenToValType(),
   3322                     &(*argValues)[i])) {
   3323      return false;
   3324    }
   3325  }
   3326 
   3327  return push(RefType::fromTypeDef(&typeDef, false));
   3328 }
   3329 
   3330 template <typename Policy>
   3331 inline bool OpIter<Policy>::readStructNewDefault(uint32_t* typeIndex) {
   3332  MOZ_ASSERT(Classify(op_) == OpKind::StructNewDefault);
   3333 
   3334  if (!readStructTypeIndex(typeIndex)) {
   3335    return false;
   3336  }
   3337 
   3338  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3339  const StructType& structType = typeDef.structType();
   3340 
   3341  if (!structType.isDefaultable()) {
   3342    return fail("struct must be defaultable");
   3343  }
   3344 
   3345  return push(RefType::fromTypeDef(&typeDef, false));
   3346 }
   3347 
   3348 template <typename Policy>
   3349 inline bool OpIter<Policy>::readStructGet(uint32_t* typeIndex,
   3350                                          uint32_t* fieldIndex,
   3351                                          FieldWideningOp wideningOp,
   3352                                          Value* ptr) {
   3353  MOZ_ASSERT(typeIndex != fieldIndex);
   3354  MOZ_ASSERT(Classify(op_) == OpKind::StructGet);
   3355 
   3356  if (!readStructTypeIndex(typeIndex)) {
   3357    return false;
   3358  }
   3359 
   3360  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3361  const StructType& structType = typeDef.structType();
   3362 
   3363  if (!readFieldIndex(fieldIndex, structType)) {
   3364    return false;
   3365  }
   3366 
   3367  if (!popWithType(RefType::fromTypeDef(&typeDef, true), ptr)) {
   3368    return false;
   3369  }
   3370 
   3371  StorageType StorageType = structType.fields_[*fieldIndex].type;
   3372 
   3373  if (StorageType.isValType() && wideningOp != FieldWideningOp::None) {
   3374    return fail("must not specify signedness for unpacked field type");
   3375  }
   3376 
   3377  if (!StorageType.isValType() && wideningOp == FieldWideningOp::None) {
   3378    return fail("must specify signedness for packed field type");
   3379  }
   3380 
   3381  return push(StorageType.widenToValType());
   3382 }
   3383 
   3384 template <typename Policy>
   3385 inline bool OpIter<Policy>::readStructSet(uint32_t* typeIndex,
   3386                                          uint32_t* fieldIndex, Value* ptr,
   3387                                          Value* val) {
   3388  MOZ_ASSERT(typeIndex != fieldIndex);
   3389  MOZ_ASSERT(Classify(op_) == OpKind::StructSet);
   3390 
   3391  if (!readStructTypeIndex(typeIndex)) {
   3392    return false;
   3393  }
   3394 
   3395  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3396  const StructType& structType = typeDef.structType();
   3397 
   3398  if (!readFieldIndex(fieldIndex, structType)) {
   3399    return false;
   3400  }
   3401 
   3402  if (!popWithType(structType.fields_[*fieldIndex].type.widenToValType(),
   3403                   val)) {
   3404    return false;
   3405  }
   3406 
   3407  if (!structType.fields_[*fieldIndex].isMutable) {
   3408    return fail("field is not mutable");
   3409  }
   3410 
   3411  return popWithType(RefType::fromTypeDef(&typeDef, true), ptr);
   3412 }
   3413 
   3414 template <typename Policy>
   3415 inline bool OpIter<Policy>::readArrayNew(uint32_t* typeIndex,
   3416                                         Value* numElements, Value* argValue) {
   3417  MOZ_ASSERT(Classify(op_) == OpKind::ArrayNew);
   3418 
   3419  if (!readArrayTypeIndex(typeIndex)) {
   3420    return false;
   3421  }
   3422 
   3423  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3424  const ArrayType& arrayType = typeDef.arrayType();
   3425 
   3426  if (!popWithType(ValType::I32, numElements)) {
   3427    return false;
   3428  }
   3429 
   3430  if (!popWithType(arrayType.elementType().widenToValType(), argValue)) {
   3431    return false;
   3432  }
   3433 
   3434  return push(RefType::fromTypeDef(&typeDef, false));
   3435 }
   3436 
   3437 template <typename Policy>
   3438 inline bool OpIter<Policy>::readArrayNewFixed(uint32_t* typeIndex,
   3439                                              uint32_t* numElements,
   3440                                              ValueVector* values) {
   3441  MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewFixed);
   3442  MOZ_ASSERT(values->length() == 0);
   3443 
   3444  if (!readArrayTypeIndex(typeIndex)) {
   3445    return false;
   3446  }
   3447 
   3448  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3449  const ArrayType& arrayType = typeDef.arrayType();
   3450 
   3451  if (!readVarU32(numElements)) {
   3452    return false;
   3453  }
   3454 
   3455  if (*numElements > MaxArrayNewFixedElements) {
   3456    return fail("too many array.new_fixed elements");
   3457  }
   3458 
   3459  if (!values->reserve(*numElements)) {
   3460    return false;
   3461  }
   3462 
   3463  ValType widenedElementType = arrayType.elementType().widenToValType();
   3464  for (uint32_t i = 0; i < *numElements; i++) {
   3465    Value v;
   3466    if (!popWithType(widenedElementType, &v)) {
   3467      return false;
   3468    }
   3469    values->infallibleAppend(v);
   3470  }
   3471 
   3472  return push(RefType::fromTypeDef(&typeDef, false));
   3473 }
   3474 
   3475 template <typename Policy>
   3476 inline bool OpIter<Policy>::readArrayNewDefault(uint32_t* typeIndex,
   3477                                                Value* numElements) {
   3478  MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewDefault);
   3479 
   3480  if (!readArrayTypeIndex(typeIndex)) {
   3481    return false;
   3482  }
   3483 
   3484  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3485  const ArrayType& arrayType = typeDef.arrayType();
   3486 
   3487  if (!popWithType(ValType::I32, numElements)) {
   3488    return false;
   3489  }
   3490 
   3491  if (!arrayType.elementType().isDefaultable()) {
   3492    return fail("array must be defaultable");
   3493  }
   3494 
   3495  return push(RefType::fromTypeDef(&typeDef, false));
   3496 }
   3497 
   3498 template <typename Policy>
   3499 inline bool OpIter<Policy>::readArrayNewData(uint32_t* typeIndex,
   3500                                             uint32_t* segIndex, Value* offset,
   3501                                             Value* numElements) {
   3502  MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewData);
   3503 
   3504  if (!readArrayTypeIndex(typeIndex)) {
   3505    return false;
   3506  }
   3507 
   3508  if (!readVarU32(segIndex)) {
   3509    return fail("unable to read segment index");
   3510  }
   3511 
   3512  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3513  const ArrayType& arrayType = typeDef.arrayType();
   3514  StorageType elemType = arrayType.elementType();
   3515  if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) {
   3516    return fail("element type must be i8/i16/i32/i64/f32/f64/v128");
   3517  }
   3518  if (codeMeta_.dataCount.isNothing()) {
   3519    return fail("datacount section missing");
   3520  }
   3521  if (*segIndex >= *codeMeta_.dataCount) {
   3522    return fail("segment index is out of range");
   3523  }
   3524 
   3525  if (!popWithType(ValType::I32, numElements)) {
   3526    return false;
   3527  }
   3528  if (!popWithType(ValType::I32, offset)) {
   3529    return false;
   3530  }
   3531 
   3532  return push(RefType::fromTypeDef(&typeDef, false));
   3533 }
   3534 
   3535 template <typename Policy>
   3536 inline bool OpIter<Policy>::readArrayNewElem(uint32_t* typeIndex,
   3537                                             uint32_t* segIndex, Value* offset,
   3538                                             Value* numElements) {
   3539  MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewElem);
   3540 
   3541  if (!readArrayTypeIndex(typeIndex)) {
   3542    return false;
   3543  }
   3544 
   3545  if (!readVarU32(segIndex)) {
   3546    return fail("unable to read segment index");
   3547  }
   3548 
   3549  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3550  const ArrayType& arrayType = typeDef.arrayType();
   3551  StorageType dstElemType = arrayType.elementType();
   3552  if (!dstElemType.isRefType()) {
   3553    return fail("element type is not a reftype");
   3554  }
   3555  if (*segIndex >= codeMeta_.elemSegmentTypes.length()) {
   3556    return fail("segment index is out of range");
   3557  }
   3558 
   3559  RefType srcElemType = codeMeta_.elemSegmentTypes[*segIndex];
   3560  // srcElemType needs to be a subtype (child) of dstElemType
   3561  if (!checkIsSubtypeOf(srcElemType, dstElemType.refType())) {
   3562    return fail("incompatible element types");
   3563  }
   3564 
   3565  if (!popWithType(ValType::I32, numElements)) {
   3566    return false;
   3567  }
   3568  if (!popWithType(ValType::I32, offset)) {
   3569    return false;
   3570  }
   3571 
   3572  return push(RefType::fromTypeDef(&typeDef, false));
   3573 }
   3574 
   3575 template <typename Policy>
   3576 inline bool OpIter<Policy>::readArrayInitData(uint32_t* typeIndex,
   3577                                              uint32_t* segIndex, Value* array,
   3578                                              Value* arrayIndex,
   3579                                              Value* segOffset, Value* length) {
   3580  MOZ_ASSERT(Classify(op_) == OpKind::ArrayInitData);
   3581 
   3582  if (!readArrayTypeIndex(typeIndex)) {
   3583    return false;
   3584  }
   3585 
   3586  if (!readVarU32(segIndex)) {
   3587    return fail("unable to read segment index");
   3588  }
   3589 
   3590  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3591  const ArrayType& arrayType = typeDef.arrayType();
   3592  StorageType elemType = arrayType.elementType();
   3593  if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) {
   3594    return fail("element type must be i8/i16/i32/i64/f32/f64/v128");
   3595  }
   3596  if (!arrayType.isMutable()) {
   3597    return fail("destination array is not mutable");
   3598  }
   3599  if (codeMeta_.dataCount.isNothing()) {
   3600    return fail("datacount section missing");
   3601  }
   3602  if (*segIndex >= *codeMeta_.dataCount) {
   3603    return fail("segment index is out of range");
   3604  }
   3605 
   3606  if (!popWithType(ValType::I32, length)) {
   3607    return false;
   3608  }
   3609  if (!popWithType(ValType::I32, segOffset)) {
   3610    return false;
   3611  }
   3612  if (!popWithType(ValType::I32, arrayIndex)) {
   3613    return false;
   3614  }
   3615  return popWithType(RefType::fromTypeDef(&typeDef, true), array);
   3616 }
   3617 
   3618 template <typename Policy>
   3619 inline bool OpIter<Policy>::readArrayInitElem(uint32_t* typeIndex,
   3620                                              uint32_t* segIndex, Value* array,
   3621                                              Value* arrayIndex,
   3622                                              Value* segOffset, Value* length) {
   3623  MOZ_ASSERT(Classify(op_) == OpKind::ArrayInitElem);
   3624 
   3625  if (!readArrayTypeIndex(typeIndex)) {
   3626    return false;
   3627  }
   3628 
   3629  if (!readVarU32(segIndex)) {
   3630    return fail("unable to read segment index");
   3631  }
   3632 
   3633  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3634  const ArrayType& arrayType = typeDef.arrayType();
   3635  StorageType dstElemType = arrayType.elementType();
   3636  if (!arrayType.isMutable()) {
   3637    return fail("destination array is not mutable");
   3638  }
   3639  if (!dstElemType.isRefType()) {
   3640    return fail("element type is not a reftype");
   3641  }
   3642  if (*segIndex >= codeMeta_.elemSegmentTypes.length()) {
   3643    return fail("segment index is out of range");
   3644  }
   3645 
   3646  RefType srcElemType = codeMeta_.elemSegmentTypes[*segIndex];
   3647  // srcElemType needs to be a subtype (child) of dstElemType
   3648  if (!checkIsSubtypeOf(srcElemType, dstElemType.refType())) {
   3649    return fail("incompatible element types");
   3650  }
   3651 
   3652  if (!popWithType(ValType::I32, length)) {
   3653    return false;
   3654  }
   3655  if (!popWithType(ValType::I32, segOffset)) {
   3656    return false;
   3657  }
   3658  if (!popWithType(ValType::I32, arrayIndex)) {
   3659    return false;
   3660  }
   3661  return popWithType(RefType::fromTypeDef(&typeDef, true), array);
   3662 }
   3663 
   3664 template <typename Policy>
   3665 inline bool OpIter<Policy>::readArrayGet(uint32_t* typeIndex,
   3666                                         FieldWideningOp wideningOp,
   3667                                         Value* index, Value* ptr) {
   3668  MOZ_ASSERT(Classify(op_) == OpKind::ArrayGet);
   3669 
   3670  if (!readArrayTypeIndex(typeIndex)) {
   3671    return false;
   3672  }
   3673 
   3674  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3675  const ArrayType& arrayType = typeDef.arrayType();
   3676 
   3677  if (!popWithType(ValType::I32, index)) {
   3678    return false;
   3679  }
   3680 
   3681  if (!popWithType(RefType::fromTypeDef(&typeDef, true), ptr)) {
   3682    return false;
   3683  }
   3684 
   3685  StorageType elementType = arrayType.elementType();
   3686 
   3687  if (elementType.isValType() && wideningOp != FieldWideningOp::None) {
   3688    return fail("must not specify signedness for unpacked element type");
   3689  }
   3690 
   3691  if (!elementType.isValType() && wideningOp == FieldWideningOp::None) {
   3692    return fail("must specify signedness for packed element type");
   3693  }
   3694 
   3695  return push(elementType.widenToValType());
   3696 }
   3697 
   3698 template <typename Policy>
   3699 inline bool OpIter<Policy>::readArraySet(uint32_t* typeIndex, Value* val,
   3700                                         Value* index, Value* ptr) {
   3701  MOZ_ASSERT(Classify(op_) == OpKind::ArraySet);
   3702 
   3703  if (!readArrayTypeIndex(typeIndex)) {
   3704    return false;
   3705  }
   3706 
   3707  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3708  const ArrayType& arrayType = typeDef.arrayType();
   3709 
   3710  if (!arrayType.isMutable()) {
   3711    return fail("array is not mutable");
   3712  }
   3713 
   3714  if (!popWithType(arrayType.elementType().widenToValType(), val)) {
   3715    return false;
   3716  }
   3717 
   3718  if (!popWithType(ValType::I32, index)) {
   3719    return false;
   3720  }
   3721 
   3722  return popWithType(RefType::fromTypeDef(&typeDef, true), ptr);
   3723 }
   3724 
   3725 template <typename Policy>
   3726 inline bool OpIter<Policy>::readArrayLen(Value* ptr) {
   3727  MOZ_ASSERT(Classify(op_) == OpKind::ArrayLen);
   3728 
   3729  if (!popWithType(RefType::array(), ptr)) {
   3730    return false;
   3731  }
   3732 
   3733  return push(ValType::I32);
   3734 }
   3735 
   3736 template <typename Policy>
   3737 inline bool OpIter<Policy>::readArrayCopy(uint32_t* dstArrayTypeIndex,
   3738                                          uint32_t* srcArrayTypeIndex,
   3739                                          Value* dstArray, Value* dstIndex,
   3740                                          Value* srcArray, Value* srcIndex,
   3741                                          Value* numElements) {
   3742  MOZ_ASSERT(Classify(op_) == OpKind::ArrayCopy);
   3743 
   3744  if (!readArrayTypeIndex(dstArrayTypeIndex)) {
   3745    return false;
   3746  }
   3747  if (!readArrayTypeIndex(srcArrayTypeIndex)) {
   3748    return false;
   3749  }
   3750 
   3751  // `dstArrayTypeIndex`/`srcArrayTypeIndex` are ensured by the above to both be
   3752  // array types.  Reject if:
   3753  // * the dst array is not of mutable type
   3754  // * the element types are incompatible
   3755  const TypeDef& dstTypeDef = codeMeta_.types->type(*dstArrayTypeIndex);
   3756  const ArrayType& dstArrayType = dstTypeDef.arrayType();
   3757  const TypeDef& srcTypeDef = codeMeta_.types->type(*srcArrayTypeIndex);
   3758  const ArrayType& srcArrayType = srcTypeDef.arrayType();
   3759  StorageType dstElemType = dstArrayType.elementType();
   3760  StorageType srcElemType = srcArrayType.elementType();
   3761  if (!dstArrayType.isMutable()) {
   3762    return fail("destination array is not mutable");
   3763  }
   3764 
   3765  if (!checkIsSubtypeOf(srcElemType, dstElemType)) {
   3766    return fail("incompatible element types");
   3767  }
   3768  MOZ_ASSERT(dstElemType.isRefType() == srcElemType.isRefType());
   3769 
   3770  if (!popWithType(ValType::I32, numElements)) {
   3771    return false;
   3772  }
   3773  if (!popWithType(ValType::I32, srcIndex)) {
   3774    return false;
   3775  }
   3776  if (!popWithType(RefType::fromTypeDef(&srcTypeDef, true), srcArray)) {
   3777    return false;
   3778  }
   3779  if (!popWithType(ValType::I32, dstIndex)) {
   3780    return false;
   3781  }
   3782 
   3783  return popWithType(RefType::fromTypeDef(&dstTypeDef, true), dstArray);
   3784 }
   3785 
   3786 template <typename Policy>
   3787 inline bool OpIter<Policy>::readArrayFill(uint32_t* typeIndex, Value* array,
   3788                                          Value* index, Value* val,
   3789                                          Value* length) {
   3790  MOZ_ASSERT(Classify(op_) == OpKind::ArrayFill);
   3791 
   3792  if (!readArrayTypeIndex(typeIndex)) {
   3793    return false;
   3794  }
   3795 
   3796  const TypeDef& typeDef = codeMeta_.types->type(*typeIndex);
   3797  const ArrayType& arrayType = typeDef.arrayType();
   3798  if (!arrayType.isMutable()) {
   3799    return fail("destination array is not mutable");
   3800  }
   3801 
   3802  if (!popWithType(ValType::I32, length)) {
   3803    return false;
   3804  }
   3805  if (!popWithType(arrayType.elementType().widenToValType(), val)) {
   3806    return false;
   3807  }
   3808  if (!popWithType(ValType::I32, index)) {
   3809    return false;
   3810  }
   3811 
   3812  return popWithType(RefType::fromTypeDef(&typeDef, true), array);
   3813 }
   3814 
   3815 template <typename Policy>
   3816 inline bool OpIter<Policy>::readRefTest(bool nullable, RefType* sourceType,
   3817                                        RefType* destType, Value* ref) {
   3818  MOZ_ASSERT(Classify(op_) == OpKind::RefTest);
   3819 
   3820  if (!readHeapType(nullable, destType)) {
   3821    return false;
   3822  }
   3823 
   3824  StackType inputType;
   3825  if (!popWithType(destType->topType(), ref, &inputType)) {
   3826    return false;
   3827  }
   3828  *sourceType = inputType.valTypeOr(RefType::any()).refType();
   3829 
   3830  return push(ValType(ValType::I32));
   3831 }
   3832 
   3833 template <typename Policy>
   3834 inline bool OpIter<Policy>::readRefCast(bool nullable, RefType* sourceType,
   3835                                        RefType* destType, Value* ref) {
   3836  MOZ_ASSERT(Classify(op_) == OpKind::RefCast);
   3837 
   3838  if (!readHeapType(nullable, destType)) {
   3839    return false;
   3840  }
   3841 
   3842  StackType inputType;
   3843  if (!popWithType(destType->topType(), ref, &inputType)) {
   3844    return false;
   3845  }
   3846  *sourceType = inputType.valTypeOr(RefType::any()).refType();
   3847 
   3848  return push(*destType);
   3849 }
   3850 
   3851 // `br_on_cast <flags> <labelRelativeDepth> <rt1> <rt2>`
   3852 // branches if a reference has a given heap type.
   3853 //
   3854 // V6 spec text follows - note that br_on_cast and br_on_cast_fail are both
   3855 // handled by this function (disambiguated by a flag).
   3856 //
   3857 // * `br_on_cast <labelidx> <reftype> <reftype>` branches if a reference has a
   3858 //   given type
   3859 //   - `br_on_cast $l rt1 rt2 : [t0* rt1] -> [t0* rt1\rt2]`
   3860 //     - iff `$l : [t0* rt2]`
   3861 //     - and `rt2 <: rt1`
   3862 //   - passes operand along with branch under target type, plus possible extra
   3863 //     args
   3864 //   - if `rt2` contains `null`, branches on null, otherwise does not
   3865 // * `br_on_cast_fail <labelidx> <reftype> <reftype>` branches if a reference
   3866 //   does not have a given type
   3867 //   - `br_on_cast_fail $l rt1 rt2 : [t0* rt1] -> [t0* rt2]`
   3868 //     - iff `$l : [t0* rt1\rt2]`
   3869 //     - and `rt2 <: rt1`
   3870 //   - passes operand along with branch, plus possible extra args
   3871 //   - if `rt2` contains `null`, does not branch on null, otherwise does
   3872 // where:
   3873 //   - `(ref null1? ht1)\(ref null ht2) = (ref ht1)`
   3874 //   - `(ref null1? ht1)\(ref ht2)      = (ref null1? ht1)`
   3875 //
   3876 // The `rt1\rt2` syntax is a "diff" - it is basically rt1 minus rt2, because a
   3877 // successful cast to rt2 will branch away. So if rt2 allows null, the result
   3878 // after a non-branch will be non-null; on the other hand, if rt2 is
   3879 // non-nullable, the cast will have nothing to say about nullability and the
   3880 // nullability of rt1 will be preserved.
   3881 //
   3882 // `values` will be nonempty after the call, and its last entry will be the
   3883 // type that causes a branch (rt1\rt2 or rt2, depending).
   3884 
   3885 enum class BrOnCastFlags : uint8_t {
   3886  SourceNullable = 0x1,
   3887  DestNullable = 0x1 << 1,
   3888  AllowedMask = uint8_t(SourceNullable) | uint8_t(DestNullable),
   3889 };
   3890 
   3891 template <typename Policy>
   3892 inline bool OpIter<Policy>::readBrOnCast(bool onSuccess,
   3893                                         uint32_t* labelRelativeDepth,
   3894                                         RefType* sourceType, RefType* destType,
   3895                                         ResultType* labelType,
   3896                                         ValueVector* values) {
   3897  MOZ_ASSERT(Classify(op_) == OpKind::BrOnCast);
   3898 
   3899  uint8_t flags;
   3900  if (!readFixedU8(&flags)) {
   3901    return fail("unable to read br_on_cast flags");
   3902  }
   3903  if ((flags & ~uint8_t(BrOnCastFlags::AllowedMask)) != 0) {
   3904    return fail("invalid br_on_cast flags");
   3905  }
   3906  bool sourceNullable = flags & uint8_t(BrOnCastFlags::SourceNullable);
   3907  bool destNullable = flags & uint8_t(BrOnCastFlags::DestNullable);
   3908 
   3909  if (!readVarU32(labelRelativeDepth)) {
   3910    return fail("unable to read br_on_cast depth");
   3911  }
   3912 
   3913  // This is distinct from the actual source type we pop from the stack, which
   3914  // can be more specific and allow for better optimizations.
   3915  RefType immediateSourceType;
   3916  if (!readHeapType(sourceNullable, &immediateSourceType)) {
   3917    return fail("unable to read br_on_cast source type");
   3918  }
   3919 
   3920  if (!readHeapType(destNullable, destType)) {
   3921    return fail("unable to read br_on_cast dest type");
   3922  }
   3923 
   3924  // Check that source and destination types are compatible
   3925  if (!checkIsSubtypeOf(*destType, immediateSourceType)) {
   3926    return fail(
   3927        "type mismatch: source and destination types for cast are "
   3928        "incompatible");
   3929  }
   3930 
   3931  RefType typeOnSuccess = *destType;
   3932  // This is rt1\rt2
   3933  RefType typeOnFail =
   3934      destNullable ? immediateSourceType.asNonNullable() : immediateSourceType;
   3935  RefType typeOnBranch = onSuccess ? typeOnSuccess : typeOnFail;
   3936  RefType typeOnFallthrough = onSuccess ? typeOnFail : typeOnSuccess;
   3937 
   3938  // Get the branch target type, which will also determine the type of extra
   3939  // values that are passed along on branch.
   3940  Control* block = nullptr;
   3941  if (!getControl(*labelRelativeDepth, &block)) {
   3942    return false;
   3943  }
   3944  *labelType = block->branchTargetType();
   3945 
   3946  // Check we have at least one value slot in the branch target type, so as to
   3947  // receive the casted or non-casted type when we branch.
   3948  const size_t labelTypeNumValues = labelType->length();
   3949  if (labelTypeNumValues < 1) {
   3950    return fail("type mismatch: branch target type has no value types");
   3951  }
   3952 
   3953  // The last value slot in the branch target type is what is being cast.
   3954  // This slot is guaranteed to exist by the above check.
   3955 
   3956  // Check that the branch target type can accept typeOnBranch.
   3957  if (!checkIsSubtypeOf(typeOnBranch, (*labelType)[labelTypeNumValues - 1])) {
   3958    return false;
   3959  }
   3960 
   3961  // Replace the top operand with the result of falling through. Even branching
   3962  // on success can change the type on top of the stack on fallthrough.
   3963  Value inputValue;
   3964  StackType inputType;
   3965  if (!popWithType(immediateSourceType, &inputValue, &inputType)) {
   3966    return false;
   3967  }
   3968  *sourceType = inputType.valTypeOr(immediateSourceType).refType();
   3969  infalliblePush(TypeAndValue(typeOnFallthrough, inputValue));
   3970 
   3971  // Create a copy of the branch target type, with the relevant value slot
   3972  // replaced by typeOnFallthrough.
   3973  ValTypeVector fallthroughTypes;
   3974  if (!labelType->cloneToVector(&fallthroughTypes)) {
   3975    return false;
   3976  }
   3977  fallthroughTypes[labelTypeNumValues - 1] = typeOnFallthrough;
   3978 
   3979  return checkTopTypeMatches(ResultType::Vector(fallthroughTypes), values,
   3980                             /*rewriteStackTypes=*/true);
   3981 }
   3982 
   3983 template <typename Policy>
   3984 inline bool OpIter<Policy>::readRefConversion(RefType operandType,
   3985                                              RefType resultType,
   3986                                              Value* operandValue) {
   3987  MOZ_ASSERT(Classify(op_) == OpKind::RefConversion);
   3988 
   3989  StackType actualOperandType;
   3990  if (!popWithType(ValType(operandType), operandValue, &actualOperandType)) {
   3991    return false;
   3992  }
   3993 
   3994  // The result nullability is the same as the operand nullability
   3995  bool outputNullable = actualOperandType.isNullableAsOperand();
   3996  infalliblePush(ValType(resultType.withIsNullable(outputNullable)));
   3997  return true;
   3998 }
   3999 
   4000 #ifdef ENABLE_WASM_SIMD
   4001 
   4002 template <typename Policy>
   4003 inline bool OpIter<Policy>::readLaneIndex(uint32_t inputLanes,
   4004                                          uint32_t* laneIndex) {
   4005  uint8_t tmp;
   4006  if (!readFixedU8(&tmp)) {
   4007    return false;  // Caller signals error
   4008  }
   4009  if (tmp >= inputLanes) {
   4010    return false;
   4011  }
   4012  *laneIndex = tmp;
   4013  return true;
   4014 }
   4015 
   4016 template <typename Policy>
   4017 inline bool OpIter<Policy>::readExtractLane(ValType resultType,
   4018                                            uint32_t inputLanes,
   4019                                            uint32_t* laneIndex, Value* input) {
   4020  MOZ_ASSERT(Classify(op_) == OpKind::ExtractLane);
   4021 
   4022  if (!readLaneIndex(inputLanes, laneIndex)) {
   4023    return fail("missing or invalid extract_lane lane index");
   4024  }
   4025 
   4026  if (!popWithType(ValType::V128, input)) {
   4027    return false;
   4028  }
   4029 
   4030  infalliblePush(resultType);
   4031 
   4032  return true;
   4033 }
   4034 
   4035 template <typename Policy>
   4036 inline bool OpIter<Policy>::readReplaceLane(ValType operandType,
   4037                                            uint32_t inputLanes,
   4038                                            uint32_t* laneIndex,
   4039                                            Value* baseValue, Value* operand) {
   4040  MOZ_ASSERT(Classify(op_) == OpKind::ReplaceLane);
   4041 
   4042  if (!readLaneIndex(inputLanes, laneIndex)) {
   4043    return fail("missing or invalid replace_lane lane index");
   4044  }
   4045 
   4046  if (!popWithType(operandType, operand)) {
   4047    return false;
   4048  }
   4049 
   4050  if (!popWithType(ValType::V128, baseValue)) {
   4051    return false;
   4052  }
   4053 
   4054  infalliblePush(ValType::V128);
   4055 
   4056  return true;
   4057 }
   4058 
   4059 template <typename Policy>
   4060 inline bool OpIter<Policy>::readVectorShift(Value* baseValue, Value* shift) {
   4061  MOZ_ASSERT(Classify(op_) == OpKind::VectorShift);
   4062 
   4063  if (!popWithType(ValType::I32, shift)) {
   4064    return false;
   4065  }
   4066 
   4067  if (!popWithType(ValType::V128, baseValue)) {
   4068    return false;
   4069  }
   4070 
   4071  infalliblePush(ValType::V128);
   4072 
   4073  return true;
   4074 }
   4075 
   4076 template <typename Policy>
   4077 inline bool OpIter<Policy>::readVectorShuffle(Value* v1, Value* v2,
   4078                                              V128* selectMask) {
   4079  MOZ_ASSERT(Classify(op_) == OpKind::VectorShuffle);
   4080 
   4081  for (unsigned char& byte : selectMask->bytes) {
   4082    uint8_t tmp;
   4083    if (!readFixedU8(&tmp)) {
   4084      return fail("unable to read shuffle index");
   4085    }
   4086    if (tmp > 31) {
   4087      return fail("shuffle index out of range");
   4088    }
   4089    byte = tmp;
   4090  }
   4091 
   4092  if (!popWithType(ValType::V128, v2)) {
   4093    return false;
   4094  }
   4095 
   4096  if (!popWithType(ValType::V128, v1)) {
   4097    return false;
   4098  }
   4099 
   4100  infalliblePush(ValType::V128);
   4101 
   4102  return true;
   4103 }
   4104 
   4105 template <typename Policy>
   4106 inline bool OpIter<Policy>::readV128Const(V128* value) {
   4107  MOZ_ASSERT(Classify(op_) == OpKind::V128Const);
   4108 
   4109  if (!d_.readV128Const(value)) {
   4110    return false;
   4111  }
   4112 
   4113  return push(ValType::V128);
   4114 }
   4115 
   4116 template <typename Policy>
   4117 inline bool OpIter<Policy>::readLoadSplat(uint32_t byteSize,
   4118                                          LinearMemoryAddress<Value>* addr) {
   4119  MOZ_ASSERT(Classify(op_) == OpKind::Load);
   4120 
   4121  if (!readLinearMemoryAddress(byteSize, addr)) {
   4122    return false;
   4123  }
   4124 
   4125  infalliblePush(ValType::V128);
   4126 
   4127  return true;
   4128 }
   4129 
   4130 template <typename Policy>
   4131 inline bool OpIter<Policy>::readLoadExtend(LinearMemoryAddress<Value>* addr) {
   4132  MOZ_ASSERT(Classify(op_) == OpKind::Load);
   4133 
   4134  if (!readLinearMemoryAddress(/*byteSize=*/8, addr)) {
   4135    return false;
   4136  }
   4137 
   4138  infalliblePush(ValType::V128);
   4139 
   4140  return true;
   4141 }
   4142 
   4143 template <typename Policy>
   4144 inline bool OpIter<Policy>::readLoadLane(uint32_t byteSize,
   4145                                         LinearMemoryAddress<Value>* addr,
   4146                                         uint32_t* laneIndex, Value* input) {
   4147  MOZ_ASSERT(Classify(op_) == OpKind::LoadLane);
   4148 
   4149  if (!popWithType(ValType::V128, input)) {
   4150    return false;
   4151  }
   4152 
   4153  if (!readLinearMemoryAddress(byteSize, addr)) {
   4154    return false;
   4155  }
   4156 
   4157  uint32_t inputLanes = 16 / byteSize;
   4158  if (!readLaneIndex(inputLanes, laneIndex)) {
   4159    return fail("missing or invalid load_lane lane index");
   4160  }
   4161 
   4162  infalliblePush(ValType::V128);
   4163 
   4164  return true;
   4165 }
   4166 
   4167 template <typename Policy>
   4168 inline bool OpIter<Policy>::readStoreLane(uint32_t byteSize,
   4169                                          LinearMemoryAddress<Value>* addr,
   4170                                          uint32_t* laneIndex, Value* input) {
   4171  MOZ_ASSERT(Classify(op_) == OpKind::StoreLane);
   4172 
   4173  if (!popWithType(ValType::V128, input)) {
   4174    return false;
   4175  }
   4176 
   4177  if (!readLinearMemoryAddress(byteSize, addr)) {
   4178    return false;
   4179  }
   4180 
   4181  uint32_t inputLanes = 16 / byteSize;
   4182  if (!readLaneIndex(inputLanes, laneIndex)) {
   4183    return fail("missing or invalid store_lane lane index");
   4184  }
   4185 
   4186  return true;
   4187 }
   4188 
   4189 #endif  // ENABLE_WASM_SIMD
   4190 
   4191 #ifdef ENABLE_WASM_JSPI
   4192 template <typename Policy>
   4193 inline bool OpIter<Policy>::readStackSwitch(StackSwitchKind* kind,
   4194                                            Value* suspender, Value* fn,
   4195                                            Value* data) {
   4196  MOZ_ASSERT(Classify(op_) == OpKind::StackSwitch);
   4197  MOZ_ASSERT(codeMeta_.jsPromiseIntegrationEnabled());
   4198  uint32_t kind_;
   4199  if (!d_.readVarU32(&kind_)) {
   4200    return false;
   4201  }
   4202  *kind = StackSwitchKind(kind_);
   4203  if (!popWithType(ValType(RefType::any()), data)) {
   4204    return false;
   4205  }
   4206  StackType stackType;
   4207  if (!popWithType(ValType(RefType::func()), fn, &stackType)) {
   4208    return false;
   4209  }
   4210 #  if DEBUG
   4211  // Verify that the function takes suspender and data as parameters.
   4212  MOZ_ASSERT((*kind == StackSwitchKind::ContinueOnSuspendable) ==
   4213             stackType.isNullableAsOperand());
   4214  if (!stackType.isNullableAsOperand()) {
   4215    ValType valType = stackType.valType();
   4216    MOZ_ASSERT(valType.isRefType() && valType.typeDef()->isFuncType());
   4217    const FuncType& func = valType.typeDef()->funcType();
   4218    MOZ_ASSERT(func.args().length() == 2 && func.arg(0).isExternRef() &&
   4219               ValType::isSubTypeOf(func.arg(1), RefType::any()));
   4220    MOZ_ASSERT_IF(*kind != StackSwitchKind::SwitchToMain,
   4221                  func.results().empty());
   4222    MOZ_ASSERT_IF(*kind == StackSwitchKind::SwitchToMain,
   4223                  func.results().length() == 1 && func.result(0).isAnyRef());
   4224  }
   4225 #  endif
   4226  if (!popWithType(ValType(RefType::extern_()), suspender)) {
   4227    return false;
   4228  }
   4229  // Returns a value only for SwitchToMain.
   4230  if (*kind == StackSwitchKind::SwitchToMain) {
   4231    return push(RefType::extern_());
   4232  }
   4233  return true;
   4234 }
   4235 #endif
   4236 
   4237 template <typename Policy>
   4238 inline bool OpIter<Policy>::readCallBuiltinModuleFunc(
   4239    const BuiltinModuleFunc** builtinModuleFunc, ValueVector* params) {
   4240  MOZ_ASSERT(Classify(op_) == OpKind::CallBuiltinModuleFunc);
   4241 
   4242  uint32_t id;
   4243  if (!d_.readVarU32(&id)) {
   4244    return false;
   4245  }
   4246 
   4247  if (id >= uint32_t(BuiltinModuleFuncId::Limit)) {
   4248    return fail("index out of range");
   4249  }
   4250 
   4251  *builtinModuleFunc = &BuiltinModuleFuncs::getFromId(BuiltinModuleFuncId(id));
   4252 
   4253  if ((*builtinModuleFunc)->usesMemory() && codeMeta_.numMemories() == 0) {
   4254    return fail("can't touch memory without memory");
   4255  }
   4256 
   4257  const FuncType& funcType = *(*builtinModuleFunc)->funcType();
   4258  if (!popCallArgs(funcType.args(), params)) {
   4259    return false;
   4260  }
   4261 
   4262  return push(ResultType::Vector(funcType.results()));
   4263 }
   4264 
   4265 }  // namespace wasm
   4266 }  // namespace js
   4267 
   4268 static_assert(std::is_trivially_copyable<
   4269                  js::wasm::TypeAndValueT<mozilla::Nothing>>::value,
   4270              "Must be trivially copyable");
   4271 static_assert(std::is_trivially_destructible<
   4272                  js::wasm::TypeAndValueT<mozilla::Nothing>>::value,
   4273              "Must be trivially destructible");
   4274 
   4275 static_assert(std::is_trivially_copyable<
   4276                  js::wasm::ControlStackEntry<mozilla::Nothing>>::value,
   4277              "Must be trivially copyable");
   4278 static_assert(std::is_trivially_destructible<
   4279                  js::wasm::ControlStackEntry<mozilla::Nothing>>::value,
   4280              "Must be trivially destructible");
   4281 
   4282 #endif  // wasm_op_iter_h