LCOV - code coverage report
Current view: top level - js/src/wasm - WasmBinaryIterator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 783 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 363 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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_binary_iterator_h
      20             : #define wasm_binary_iterator_h
      21             : 
      22             : #include "mozilla/Poison.h"
      23             : 
      24             : #include "jsprf.h"
      25             : 
      26             : #include "jit/AtomicOp.h"
      27             : #include "wasm/WasmValidate.h"
      28             : 
      29             : namespace js {
      30             : namespace wasm {
      31             : 
      32             : // The kind of a control-flow stack item.
      33             : enum class LabelKind : uint8_t
      34             : {
      35             :     Block,
      36             :     Loop,
      37             :     Then,
      38             :     Else
      39             : };
      40             : 
      41             : // The type of values on the operand stack during validation. The Any type
      42             : // represents the type of a value produced by an unconditional branch.
      43             : enum class StackType
      44             : {
      45             :     I32   = uint8_t(ValType::I32),
      46             :     I64   = uint8_t(ValType::I64),
      47             :     F32   = uint8_t(ValType::F32),
      48             :     F64   = uint8_t(ValType::F64),
      49             : 
      50             :     I8x16 = uint8_t(ValType::I8x16),
      51             :     I16x8 = uint8_t(ValType::I16x8),
      52             :     I32x4 = uint8_t(ValType::I32x4),
      53             :     F32x4 = uint8_t(ValType::F32x4),
      54             :     B8x16 = uint8_t(ValType::B8x16),
      55             :     B16x8 = uint8_t(ValType::B16x8),
      56             :     B32x4 = uint8_t(ValType::B32x4),
      57             : 
      58             :     Any   = uint8_t(TypeCode::Limit)
      59             : };
      60             : 
      61             : static inline StackType
      62           0 : ToStackType(ValType type)
      63             : {
      64           0 :     return StackType(type);
      65             : }
      66             : 
      67             : static inline ValType
      68           0 : NonAnyToValType(StackType type)
      69             : {
      70           0 :     MOZ_ASSERT(type != StackType::Any);
      71           0 :     return ValType(type);
      72             : }
      73             : 
      74             : static inline bool
      75           0 : Unify(StackType one, StackType two, StackType* result)
      76             : {
      77           0 :     if (MOZ_LIKELY(one == two)) {
      78           0 :         *result = one;
      79           0 :         return true;
      80             :     }
      81             : 
      82           0 :     if (one == StackType::Any) {
      83           0 :         *result = two;
      84           0 :         return true;
      85             :     }
      86             : 
      87           0 :     if (two == StackType::Any) {
      88           0 :         *result = one;
      89           0 :         return true;
      90             :     }
      91             : 
      92           0 :     return false;
      93             : }
      94             : 
      95             : #ifdef DEBUG
      96             : // Families of opcodes that share a signature and validation logic.
      97             : enum class OpKind {
      98             :     Block,
      99             :     Loop,
     100             :     Unreachable,
     101             :     Drop,
     102             :     I32,
     103             :     I64,
     104             :     F32,
     105             :     F64,
     106             :     I8x16,
     107             :     I16x8,
     108             :     I32x4,
     109             :     F32x4,
     110             :     B8x16,
     111             :     B16x8,
     112             :     B32x4,
     113             :     Br,
     114             :     BrIf,
     115             :     BrTable,
     116             :     Nop,
     117             :     Nullary,
     118             :     Unary,
     119             :     Binary,
     120             :     Comparison,
     121             :     Conversion,
     122             :     Load,
     123             :     Store,
     124             :     TeeStore,
     125             :     CurrentMemory,
     126             :     GrowMemory,
     127             :     Select,
     128             :     GetLocal,
     129             :     SetLocal,
     130             :     TeeLocal,
     131             :     GetGlobal,
     132             :     SetGlobal,
     133             :     TeeGlobal,
     134             :     Call,
     135             :     CallIndirect,
     136             :     OldCallIndirect,
     137             :     Return,
     138             :     If,
     139             :     Else,
     140             :     End,
     141             :     AtomicLoad,
     142             :     AtomicStore,
     143             :     AtomicBinOp,
     144             :     AtomicCompareExchange,
     145             :     AtomicExchange,
     146             :     ExtractLane,
     147             :     ReplaceLane,
     148             :     Swizzle,
     149             :     Shuffle,
     150             :     Splat,
     151             :     SimdSelect,
     152             :     SimdCtor,
     153             :     SimdBooleanReduction,
     154             :     SimdShiftByScalar,
     155             :     SimdComparison,
     156             : };
     157             : 
     158             : // Return the OpKind for a given Op. This is used for sanity-checking that
     159             : // API users use the correct read function for a given Op.
     160             : OpKind
     161             : Classify(OpBytes op);
     162             : #endif
     163             : 
     164             : // Common fields for linear memory access.
     165             : template <typename Value>
     166             : struct LinearMemoryAddress
     167             : {
     168             :     Value base;
     169             :     uint32_t offset;
     170             :     uint32_t align;
     171             : 
     172           0 :     LinearMemoryAddress()
     173           0 :     {}
     174             :     LinearMemoryAddress(Value base, uint32_t offset, uint32_t align)
     175             :       : base(base), offset(offset), align(align)
     176             :     {}
     177             : };
     178             : 
     179             : template <typename ControlItem>
     180           0 : class ControlStackEntry
     181             : {
     182             :     LabelKind kind_;
     183             :     bool polymorphicBase_;
     184             :     ExprType type_;
     185             :     size_t valueStackStart_;
     186             :     ControlItem controlItem_;
     187             : 
     188             :   public:
     189           0 :     ControlStackEntry(LabelKind kind, ExprType type, size_t valueStackStart)
     190             :       : kind_(kind), polymorphicBase_(false), type_(type), valueStackStart_(valueStackStart),
     191           0 :         controlItem_()
     192             :     {
     193           0 :         MOZ_ASSERT(type != ExprType::Limit);
     194           0 :     }
     195             : 
     196           0 :     LabelKind kind() const { return kind_; }
     197           0 :     ExprType resultType() const { return type_; }
     198           0 :     ExprType branchTargetType() const { return kind_ == LabelKind::Loop ? ExprType::Void : type_; }
     199           0 :     size_t valueStackStart() const { return valueStackStart_; }
     200           0 :     ControlItem& controlItem() { return controlItem_; }
     201           0 :     void setPolymorphicBase() { polymorphicBase_ = true; }
     202           0 :     bool polymorphicBase() const { return polymorphicBase_; }
     203             : 
     204           0 :     void switchToElse() {
     205           0 :         MOZ_ASSERT(kind_ == LabelKind::Then);
     206           0 :         kind_ = LabelKind::Else;
     207           0 :         polymorphicBase_ = false;
     208           0 :     }
     209             : };
     210             : 
     211             : // Specialization for when there is no additional data needed.
     212             : template <>
     213             : class ControlStackEntry<Nothing>
     214             : {
     215             :     LabelKind kind_;
     216             :     bool polymorphicBase_;
     217             :     ExprType type_;
     218             :     size_t valueStackStart_;
     219             : 
     220             :   public:
     221           0 :     ControlStackEntry(LabelKind kind, ExprType type, size_t valueStackStart)
     222           0 :       : kind_(kind), polymorphicBase_(false), type_(type), valueStackStart_(valueStackStart)
     223             :     {
     224           0 :         MOZ_ASSERT(type != ExprType::Limit);
     225           0 :     }
     226             : 
     227           0 :     LabelKind kind() const { return kind_; }
     228           0 :     ExprType resultType() const { return type_; }
     229           0 :     ExprType branchTargetType() const { return kind_ == LabelKind::Loop ? ExprType::Void : type_; }
     230           0 :     size_t valueStackStart() const { return valueStackStart_; }
     231             :     Nothing controlItem() { return Nothing(); }
     232           0 :     void setPolymorphicBase() { polymorphicBase_ = true; }
     233           0 :     bool polymorphicBase() const { return polymorphicBase_; }
     234             : 
     235           0 :     void switchToElse() {
     236           0 :         MOZ_ASSERT(kind_ == LabelKind::Then);
     237           0 :         kind_ = LabelKind::Else;
     238           0 :         polymorphicBase_ = false;
     239           0 :     }
     240             : };
     241             : 
     242             : template <typename Value>
     243             : class TypeAndValue
     244             : {
     245             :     StackType type_;
     246             :     Value value_;
     247             : 
     248             :   public:
     249             :     TypeAndValue() : type_(StackType(TypeCode::Limit)), value_() {}
     250           0 :     explicit TypeAndValue(StackType type)
     251           0 :       : type_(type), value_()
     252           0 :     {}
     253           0 :     explicit TypeAndValue(ValType type)
     254           0 :       : type_(ToStackType(type)), value_()
     255           0 :     {}
     256             :     TypeAndValue(StackType type, Value value)
     257             :       : type_(type), value_(value)
     258             :     {}
     259           0 :     TypeAndValue(ValType type, Value value)
     260           0 :       : type_(ToStackType(type)), value_(value)
     261           0 :     {}
     262           0 :     StackType type() const {
     263           0 :         return type_;
     264             :     }
     265           0 :     StackType& typeRef() {
     266           0 :         return type_;
     267             :     }
     268           0 :     Value value() const {
     269           0 :         return value_;
     270             :     }
     271           0 :     void setValue(Value value) {
     272           0 :         value_ = value;
     273           0 :     }
     274             : };
     275             : 
     276             : // Specialization for when there is no additional data needed.
     277             : template <>
     278             : class TypeAndValue<Nothing>
     279             : {
     280             :     StackType type_;
     281             : 
     282             :   public:
     283             :     TypeAndValue() : type_(StackType(TypeCode::Limit)) {}
     284           0 :     explicit TypeAndValue(StackType type) : type_(type) {}
     285           0 :     explicit TypeAndValue(ValType type) : type_(ToStackType(type)) {}
     286             :     TypeAndValue(StackType type, Nothing value) : type_(type) {}
     287           0 :     TypeAndValue(ValType type, Nothing value) : type_(ToStackType(type)) {}
     288             : 
     289           0 :     StackType type() const { return type_; }
     290           0 :     StackType& typeRef() { return type_; }
     291           0 :     Nothing value() const { return Nothing(); }
     292             :     void setValue(Nothing value) {}
     293             : };
     294             : 
     295             : // An iterator over the bytes of a function body. It performs validation
     296             : // and unpacks the data into a usable form.
     297             : //
     298             : // The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly.
     299             : // There's otherwise nothing inherent in this class which would require
     300             : // it to be used on the stack.
     301             : template <typename Policy>
     302           0 : class MOZ_STACK_CLASS OpIter : private Policy
     303             : {
     304             :     typedef typename Policy::Value Value;
     305             :     typedef typename Policy::ControlItem ControlItem;
     306             : 
     307             :     Decoder& d_;
     308             :     const ModuleEnvironment& env_;
     309             : 
     310             :     Vector<TypeAndValue<Value>, 8, SystemAllocPolicy> valueStack_;
     311             :     Vector<ControlStackEntry<ControlItem>, 8, SystemAllocPolicy> controlStack_;
     312             : 
     313             : #ifdef DEBUG
     314             :     OpBytes op_;
     315             : #endif
     316             :     size_t offsetOfLastReadOp_;
     317             : 
     318           0 :     MOZ_MUST_USE bool readFixedU8(uint8_t* out) {
     319           0 :         return d_.readFixedU8(out);
     320             :     }
     321             :     MOZ_MUST_USE bool readFixedU32(uint32_t* out) {
     322             :         return d_.readFixedU32(out);
     323             :     }
     324           0 :     MOZ_MUST_USE bool readVarS32(int32_t* out) {
     325           0 :         return d_.readVarS32(out);
     326             :     }
     327           0 :     MOZ_MUST_USE bool readVarU32(uint32_t* out) {
     328           0 :         return d_.readVarU32(out);
     329             :     }
     330           0 :     MOZ_MUST_USE bool readVarS64(int64_t* out) {
     331           0 :         return d_.readVarS64(out);
     332             :     }
     333             :     MOZ_MUST_USE bool readVarU64(uint64_t* out) {
     334             :         return d_.readVarU64(out);
     335             :     }
     336           0 :     MOZ_MUST_USE bool readFixedF32(float* out) {
     337           0 :         return d_.readFixedF32(out);
     338             :     }
     339           0 :     MOZ_MUST_USE bool readFixedF64(double* out) {
     340           0 :         return d_.readFixedF64(out);
     341             :     }
     342           0 :     MOZ_MUST_USE bool readFixedI8x16(I8x16* out) {
     343           0 :         return d_.readFixedI8x16(out);
     344             :     }
     345           0 :     MOZ_MUST_USE bool readFixedI16x8(I16x8* out) {
     346           0 :         return d_.readFixedI16x8(out);
     347             :     }
     348           0 :     MOZ_MUST_USE bool readFixedI32x4(I32x4* out) {
     349           0 :         return d_.readFixedI32x4(out);
     350             :     }
     351           0 :     MOZ_MUST_USE bool readFixedF32x4(F32x4* out) {
     352           0 :         return d_.readFixedF32x4(out);
     353             :     }
     354             : 
     355           0 :     MOZ_MUST_USE bool readAtomicViewType(Scalar::Type* viewType) {
     356             :         uint8_t x;
     357           0 :         if (!readFixedU8(&x))
     358           0 :             return fail("unable to read atomic view");
     359           0 :         if (x >= Scalar::MaxTypedArrayViewType)
     360           0 :             return fail("invalid atomic view type");
     361           0 :         *viewType = Scalar::Type(x);
     362           0 :         return true;
     363             :     }
     364             : 
     365           0 :     MOZ_MUST_USE bool readAtomicBinOpOp(jit::AtomicOp* op) {
     366             :         uint8_t x;
     367           0 :         if (!readFixedU8(&x))
     368           0 :             return fail("unable to read atomic opcode");
     369           0 :         switch (x) {
     370             :           case jit::AtomicFetchAddOp:
     371             :           case jit::AtomicFetchSubOp:
     372             :           case jit::AtomicFetchAndOp:
     373             :           case jit::AtomicFetchOrOp:
     374             :           case jit::AtomicFetchXorOp:
     375           0 :             break;
     376             :           default:
     377           0 :             return fail("unrecognized atomic binop");
     378             :         }
     379           0 :         *op = jit::AtomicOp(x);
     380           0 :         return true;
     381             :     }
     382             : 
     383             :     MOZ_MUST_USE bool readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress<Value>* addr);
     384             :     MOZ_MUST_USE bool readBlockType(ExprType* expr);
     385             :     MOZ_MUST_USE bool popCallArgs(const ValTypeVector& expectedTypes, Vector<Value, 8, SystemAllocPolicy>* values);
     386             : 
     387             :     MOZ_MUST_USE bool popAnyType(StackType* type, Value* value);
     388             :     MOZ_MUST_USE bool typeMismatch(StackType actual, StackType expected);
     389             :     MOZ_MUST_USE bool popWithType(StackType expectedType, Value* value);
     390           0 :     MOZ_MUST_USE bool popWithType(ValType valType, Value* value) { return popWithType(ToStackType(valType), value); }
     391             :     MOZ_MUST_USE bool popWithType(ExprType expectedType, Value* value);
     392             :     MOZ_MUST_USE bool topWithType(ExprType expectedType, Value* value);
     393             :     MOZ_MUST_USE bool topWithType(ValType valType, Value* value);
     394             : 
     395             :     MOZ_MUST_USE bool pushControl(LabelKind kind, ExprType type);
     396             :     MOZ_MUST_USE bool checkStackAtEndOfBlock(ExprType* type, Value* value);
     397             :     MOZ_MUST_USE bool getControl(uint32_t relativeDepth, ControlStackEntry<ControlItem>** controlEntry);
     398             :     MOZ_MUST_USE bool checkBranchValue(uint32_t relativeDepth, ExprType* type, Value* value);
     399             :     MOZ_MUST_USE bool checkBrTableEntry(uint32_t* relativeDepth, ExprType* branchValueType, Value* branchValue);
     400             : 
     401             :     MOZ_MUST_USE bool push(StackType t) {
     402             :         return valueStack_.emplaceBack(t);
     403             :     }
     404           0 :     MOZ_MUST_USE bool push(ValType t) {
     405           0 :         return valueStack_.emplaceBack(t);
     406             :     }
     407           0 :     MOZ_MUST_USE bool push(ExprType t) {
     408           0 :         return IsVoid(t) || push(NonVoidToValType(t));
     409             :     }
     410             :     MOZ_MUST_USE bool push(TypeAndValue<Value> tv) {
     411             :         return valueStack_.append(tv);
     412             :     }
     413           0 :     void infalliblePush(StackType t) {
     414           0 :         valueStack_.infallibleEmplaceBack(t);
     415           0 :     }
     416           0 :     void infalliblePush(ValType t) {
     417           0 :         valueStack_.infallibleEmplaceBack(ToStackType(t));
     418           0 :     }
     419           0 :     void infalliblePush(TypeAndValue<Value> tv) {
     420           0 :         valueStack_.infallibleAppend(tv);
     421           0 :     }
     422             : 
     423           0 :     void afterUnconditionalBranch() {
     424           0 :         valueStack_.shrinkTo(controlStack_.back().valueStackStart());
     425           0 :         controlStack_.back().setPolymorphicBase();
     426           0 :     }
     427             : 
     428             :   public:
     429             :     typedef Vector<Value, 8, SystemAllocPolicy> ValueVector;
     430             : 
     431             : #ifdef DEBUG
     432           0 :     explicit OpIter(const ModuleEnvironment& env, Decoder& decoder)
     433           0 :       : d_(decoder), env_(env), op_(OpBytes(Op::Limit)), offsetOfLastReadOp_(0)
     434           0 :     {}
     435             : #else
     436             :     explicit OpIter(const ModuleEnvironment& env, Decoder& decoder)
     437             :       : d_(decoder), env_(env), offsetOfLastReadOp_(0)
     438             :     {}
     439             : #endif
     440             : 
     441             :     // Return the decoding byte offset.
     442           0 :     uint32_t currentOffset() const {
     443           0 :         return d_.currentOffset();
     444             :     }
     445             : 
     446             :     // Return the offset within the entire module of the last-read op.
     447           0 :     size_t lastOpcodeOffset() const {
     448           0 :         return offsetOfLastReadOp_ ? offsetOfLastReadOp_ : d_.currentOffset();
     449             :     }
     450             : 
     451             :     // Return a BytecodeOffset describing where the current op should be reported to trap/call.
     452           0 :     BytecodeOffset bytecodeOffset() const {
     453           0 :         return BytecodeOffset(lastOpcodeOffset());
     454             :     }
     455             : 
     456             :     // Test whether the iterator has reached the end of the buffer.
     457           0 :     bool done() const {
     458           0 :         return d_.done();
     459             :     }
     460             : 
     461             :     // Return a pointer to the end of the buffer being decoded by this iterator.
     462           0 :     const uint8_t* end() const {
     463           0 :         return d_.end();
     464             :     }
     465             : 
     466             :     // Report a general failure.
     467             :     MOZ_MUST_USE bool fail(const char* msg) MOZ_COLD;
     468             : 
     469             :     // Report an unrecognized opcode.
     470             :     MOZ_MUST_USE bool unrecognizedOpcode(const OpBytes* expr) MOZ_COLD;
     471             : 
     472             :     // Return whether the innermost block has a polymorphic base of its stack.
     473             :     // Ideally this accessor would be removed; consider using something else.
     474           0 :     bool currentBlockHasPolymorphicBase() const {
     475           0 :         return !controlStack_.empty() && controlStack_.back().polymorphicBase();
     476             :     }
     477             : 
     478             :     // ------------------------------------------------------------------------
     479             :     // Decoding and validation interface.
     480             : 
     481             :     MOZ_MUST_USE bool readOp(OpBytes* op);
     482             :     MOZ_MUST_USE bool readFunctionStart(ExprType ret);
     483             :     MOZ_MUST_USE bool readFunctionEnd(const uint8_t* bodyEnd);
     484             :     MOZ_MUST_USE bool readReturn(Value* value);
     485             :     MOZ_MUST_USE bool readBlock();
     486             :     MOZ_MUST_USE bool readLoop();
     487             :     MOZ_MUST_USE bool readIf(Value* condition);
     488             :     MOZ_MUST_USE bool readElse(ExprType* thenType, Value* thenValue);
     489             :     MOZ_MUST_USE bool readEnd(LabelKind* kind, ExprType* type, Value* value);
     490             :     void popEnd();
     491             :     MOZ_MUST_USE bool readBr(uint32_t* relativeDepth, ExprType* type, Value* value);
     492             :     MOZ_MUST_USE bool readBrIf(uint32_t* relativeDepth, ExprType* type,
     493             :                                Value* value, Value* condition);
     494             :     MOZ_MUST_USE bool readBrTable(Uint32Vector* depths, uint32_t* defaultDepth,
     495             :                                   ExprType* branchValueType, Value* branchValue, Value* index);
     496             :     MOZ_MUST_USE bool readUnreachable();
     497             :     MOZ_MUST_USE bool readDrop();
     498             :     MOZ_MUST_USE bool readUnary(ValType operandType, Value* input);
     499             :     MOZ_MUST_USE bool readConversion(ValType operandType, ValType resultType, Value* input);
     500             :     MOZ_MUST_USE bool readBinary(ValType operandType, Value* lhs, Value* rhs);
     501             :     MOZ_MUST_USE bool readComparison(ValType operandType, Value* lhs, Value* rhs);
     502             :     MOZ_MUST_USE bool readLoad(ValType resultType, uint32_t byteSize,
     503             :                                LinearMemoryAddress<Value>* addr);
     504             :     MOZ_MUST_USE bool readStore(ValType resultType, uint32_t byteSize,
     505             :                                 LinearMemoryAddress<Value>* addr, Value* value);
     506             :     MOZ_MUST_USE bool readTeeStore(ValType resultType, uint32_t byteSize,
     507             :                                    LinearMemoryAddress<Value>* addr, Value* value);
     508             :     MOZ_MUST_USE bool readNop();
     509             :     MOZ_MUST_USE bool readCurrentMemory();
     510             :     MOZ_MUST_USE bool readGrowMemory(Value* input);
     511             :     MOZ_MUST_USE bool readSelect(StackType* type,
     512             :                                  Value* trueValue, Value* falseValue, Value* condition);
     513             :     MOZ_MUST_USE bool readGetLocal(const ValTypeVector& locals, uint32_t* id);
     514             :     MOZ_MUST_USE bool readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value);
     515             :     MOZ_MUST_USE bool readTeeLocal(const ValTypeVector& locals, uint32_t* id, Value* value);
     516             :     MOZ_MUST_USE bool readGetGlobal(uint32_t* id);
     517             :     MOZ_MUST_USE bool readSetGlobal(uint32_t* id, Value* value);
     518             :     MOZ_MUST_USE bool readTeeGlobal(uint32_t* id, Value* value);
     519             :     MOZ_MUST_USE bool readI32Const(int32_t* i32);
     520             :     MOZ_MUST_USE bool readI64Const(int64_t* i64);
     521             :     MOZ_MUST_USE bool readF32Const(float* f32);
     522             :     MOZ_MUST_USE bool readF64Const(double* f64);
     523             :     MOZ_MUST_USE bool readI8x16Const(I8x16* i8x16);
     524             :     MOZ_MUST_USE bool readI16x8Const(I16x8* i16x8);
     525             :     MOZ_MUST_USE bool readI32x4Const(I32x4* i32x4);
     526             :     MOZ_MUST_USE bool readF32x4Const(F32x4* f32x4);
     527             :     MOZ_MUST_USE bool readB8x16Const(I8x16* i8x16);
     528             :     MOZ_MUST_USE bool readB16x8Const(I16x8* i16x8);
     529             :     MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4);
     530             :     MOZ_MUST_USE bool readCall(uint32_t* calleeIndex, ValueVector* argValues);
     531             :     MOZ_MUST_USE bool readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues);
     532             :     MOZ_MUST_USE bool readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues);
     533             :     MOZ_MUST_USE bool readAtomicLoad(LinearMemoryAddress<Value>* addr,
     534             :                                      Scalar::Type* viewType);
     535             :     MOZ_MUST_USE bool readAtomicStore(LinearMemoryAddress<Value>* addr,
     536             :                                       Scalar::Type* viewType,
     537             :                                       Value* value);
     538             :     MOZ_MUST_USE bool readAtomicBinOp(LinearMemoryAddress<Value>* addr,
     539             :                                       Scalar::Type* viewType,
     540             :                                       jit::AtomicOp* op,
     541             :                                       Value* value);
     542             :     MOZ_MUST_USE bool readAtomicCompareExchange(LinearMemoryAddress<Value>* addr,
     543             :                                                 Scalar::Type* viewType,
     544             :                                                 Value* oldValue,
     545             :                                                 Value* newValue);
     546             :     MOZ_MUST_USE bool readAtomicExchange(LinearMemoryAddress<Value>* addr,
     547             :                                          Scalar::Type* viewType,
     548             :                                          Value* newValue);
     549             :     MOZ_MUST_USE bool readSimdComparison(ValType simdType, Value* lhs,
     550             :                                          Value* rhs);
     551             :     MOZ_MUST_USE bool readSimdShiftByScalar(ValType simdType, Value* lhs,
     552             :                                             Value* rhs);
     553             :     MOZ_MUST_USE bool readSimdBooleanReduction(ValType simdType, Value* input);
     554             :     MOZ_MUST_USE bool readExtractLane(ValType simdType, uint8_t* lane,
     555             :                                       Value* vector);
     556             :     MOZ_MUST_USE bool readReplaceLane(ValType simdType, uint8_t* lane,
     557             :                                       Value* vector, Value* scalar);
     558             :     MOZ_MUST_USE bool readSplat(ValType simdType, Value* scalar);
     559             :     MOZ_MUST_USE bool readSwizzle(ValType simdType, uint8_t (* lanes)[16], Value* vector);
     560             :     MOZ_MUST_USE bool readShuffle(ValType simdType, uint8_t (* lanes)[16],
     561             :                                   Value* lhs, Value* rhs);
     562             :     MOZ_MUST_USE bool readSimdSelect(ValType simdType, Value* trueValue,
     563             :                                      Value* falseValue,
     564             :                                      Value* condition);
     565             :     MOZ_MUST_USE bool readSimdCtor(ValType elementType, uint32_t numElements, ValType simdType,
     566             :                                    ValueVector* argValues);
     567             : 
     568             :     // At a location where readOp is allowed, peek at the next opcode
     569             :     // without consuming it or updating any internal state.
     570             :     // Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read.
     571             :     void peekOp(OpBytes* op);
     572             : 
     573             :     // ------------------------------------------------------------------------
     574             :     // Stack management.
     575             : 
     576             :     // Set the result value of the current top-of-value-stack expression.
     577           0 :     void setResult(Value value) {
     578           0 :         valueStack_.back().setValue(value);
     579           0 :     }
     580             : 
     581             :     // Return the result value of the current top-of-value-stack expression.
     582           0 :     Value getResult() {
     583           0 :         return valueStack_.back().value();
     584             :     }
     585             : 
     586             :     // Return a reference to the top of the control stack.
     587           0 :     ControlItem& controlItem() {
     588           0 :         return controlStack_.back().controlItem();
     589             :     }
     590             : 
     591             :     // Return a reference to an element in the control stack.
     592           0 :     ControlItem& controlItem(uint32_t relativeDepth) {
     593           0 :         return controlStack_[controlStack_.length() - 1 - relativeDepth].controlItem();
     594             :     }
     595             : 
     596             :     // Return a reference to the outermost element on the control stack.
     597           0 :     ControlItem& controlOutermost() {
     598           0 :         return controlStack_[0].controlItem();
     599             :     }
     600             : 
     601             :     // Test whether the control-stack is empty, meaning we've consumed the final
     602             :     // end of the function body.
     603           0 :     bool controlStackEmpty() const {
     604           0 :         return controlStack_.empty();
     605             :     }
     606             : };
     607             : 
     608             : template <typename Policy>
     609             : inline bool
     610           0 : OpIter<Policy>::unrecognizedOpcode(const OpBytes* expr)
     611             : {
     612           0 :     UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0,
     613           0 :                                   IsPrefixByte(expr->b0) ? expr->b1 : 0));
     614           0 :     if (!error)
     615           0 :         return false;
     616             : 
     617           0 :     return fail(error.get());
     618             : }
     619             : 
     620             : template <typename Policy>
     621             : inline bool
     622           0 : OpIter<Policy>::fail(const char* msg)
     623             : {
     624           0 :     return d_.fail(lastOpcodeOffset(), msg);
     625             : }
     626             : 
     627             : // This function pops exactly one value from the stack, yielding Any types in
     628             : // various cases and therefore making it the caller's responsibility to do the
     629             : // right thing for StackType::Any. Prefer (pop|top)WithType.
     630             : template <typename Policy>
     631             : inline bool
     632           0 : OpIter<Policy>::popAnyType(StackType* type, Value* value)
     633             : {
     634           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     635             : 
     636           0 :     MOZ_ASSERT(valueStack_.length() >= block.valueStackStart());
     637           0 :     if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackStart())) {
     638             :         // If the base of this block's stack is polymorphic, then we can pop a
     639             :         // dummy value of any type; it won't be used since we're in unreachable code.
     640           0 :         if (block.polymorphicBase()) {
     641           0 :             *type = StackType::Any;
     642           0 :             *value = Value();
     643             : 
     644             :             // Maintain the invariant that, after a pop, there is always memory
     645             :             // reserved to push a value infallibly.
     646           0 :             return valueStack_.reserve(valueStack_.length() + 1);
     647             :         }
     648             : 
     649           0 :         if (valueStack_.empty())
     650           0 :             return fail("popping value from empty stack");
     651           0 :         return fail("popping value from outside block");
     652             :     }
     653             : 
     654           0 :     TypeAndValue<Value>& tv = valueStack_.back();
     655           0 :     *type = tv.type();
     656           0 :     *value = tv.value();
     657           0 :     valueStack_.popBack();
     658           0 :     return true;
     659             : }
     660             : 
     661             : template <typename Policy>
     662             : inline bool
     663           0 : OpIter<Policy>::typeMismatch(StackType actual, StackType expected)
     664             : {
     665             :     UniqueChars error(JS_smprintf("type mismatch: expression has type %s but expected %s",
     666             :                                   ToCString(NonAnyToValType(actual)),
     667           0 :                                   ToCString(NonAnyToValType(expected))));
     668           0 :     if (!error)
     669           0 :         return false;
     670             : 
     671           0 :     return fail(error.get());
     672             : }
     673             : 
     674             : // This function pops exactly one value from the stack, checking that it has the
     675             : // expected type which can either be a specific value type or a type variable.
     676             : template <typename Policy>
     677             : inline bool
     678           0 : OpIter<Policy>::popWithType(StackType expectedType, Value* value)
     679             : {
     680           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     681             : 
     682           0 :     MOZ_ASSERT(valueStack_.length() >= block.valueStackStart());
     683           0 :     if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackStart())) {
     684             :         // If the base of this block's stack is polymorphic, then we can pop a
     685             :         // dummy value of any expected type; it won't be used since we're in
     686             :         // unreachable code.
     687           0 :         if (block.polymorphicBase()) {
     688           0 :             *value = Value();
     689             : 
     690             :             // Maintain the invariant that, after a pop, there is always memory
     691             :             // reserved to push a value infallibly.
     692           0 :             return valueStack_.reserve(valueStack_.length() + 1);
     693             :         }
     694             : 
     695           0 :         if (valueStack_.empty())
     696           0 :             return fail("popping value from empty stack");
     697           0 :         return fail("popping value from outside block");
     698             :     }
     699             : 
     700           0 :     TypeAndValue<Value> tv = valueStack_.popCopy();
     701             : 
     702             :     StackType _;
     703           0 :     if (MOZ_UNLIKELY(!Unify(tv.type(), expectedType, &_)))
     704           0 :         return typeMismatch(tv.type(), expectedType);
     705             : 
     706           0 :     *value = tv.value();
     707           0 :     return true;
     708             : }
     709             : 
     710             : // This function pops as many types from the stack as determined by the given
     711             : // signature. Currently, all signatures are limited to 0 or 1 types, with
     712             : // ExprType::Void meaning 0 and all other ValTypes meaning 1, but this will be
     713             : // generalized in the future.
     714             : template <typename Policy>
     715             : inline bool
     716           0 : OpIter<Policy>::popWithType(ExprType expectedType, Value* value)
     717             : {
     718           0 :     if (IsVoid(expectedType)) {
     719           0 :         *value = Value();
     720           0 :         return true;
     721             :     }
     722             : 
     723           0 :     return popWithType(NonVoidToValType(expectedType), value);
     724             : }
     725             : 
     726             : // This function is just an optimization of popWithType + push.
     727             : template <typename Policy>
     728             : inline bool
     729           0 : OpIter<Policy>::topWithType(ValType expectedType, Value* value)
     730             : {
     731           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     732             : 
     733           0 :     MOZ_ASSERT(valueStack_.length() >= block.valueStackStart());
     734           0 :     if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackStart())) {
     735             :         // If the base of this block's stack is polymorphic, then we can just
     736             :         // pull out a dummy value of the expected type; it won't be used since
     737             :         // we're in unreachable code. We must however push this value onto the
     738             :         // stack since it is now fixed to a specific type by this type
     739             :         // constraint.
     740           0 :         if (block.polymorphicBase()) {
     741           0 :             if (!valueStack_.emplaceBack(expectedType, Value()))
     742           0 :                 return false;
     743             : 
     744           0 :             *value = Value();
     745           0 :             return true;
     746             :         }
     747             : 
     748           0 :         if (valueStack_.empty())
     749           0 :             return fail("reading value from empty stack");
     750           0 :         return fail("reading value from outside block");
     751             :     }
     752             : 
     753           0 :     TypeAndValue<Value>& tv = valueStack_.back();
     754             : 
     755           0 :     if (MOZ_UNLIKELY(!Unify(tv.type(), ToStackType(expectedType), &tv.typeRef())))
     756           0 :         return typeMismatch(tv.type(), ToStackType(expectedType));
     757             : 
     758           0 :     *value = tv.value();
     759           0 :     return true;
     760             : }
     761             : 
     762             : template <typename Policy>
     763             : inline bool
     764           0 : OpIter<Policy>::topWithType(ExprType expectedType, Value* value)
     765             : {
     766           0 :     if (IsVoid(expectedType)) {
     767           0 :         *value = Value();
     768           0 :         return true;
     769             :     }
     770             : 
     771           0 :     return topWithType(NonVoidToValType(expectedType), value);
     772             : }
     773             : 
     774             : template <typename Policy>
     775             : inline bool
     776           0 : OpIter<Policy>::pushControl(LabelKind kind, ExprType type)
     777             : {
     778           0 :     return controlStack_.emplaceBack(kind, type, valueStack_.length());
     779             : }
     780             : 
     781             : template <typename Policy>
     782             : inline bool
     783           0 : OpIter<Policy>::checkStackAtEndOfBlock(ExprType* type, Value* value)
     784             : {
     785           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     786             : 
     787           0 :     MOZ_ASSERT(valueStack_.length() >= block.valueStackStart());
     788           0 :     size_t pushed = valueStack_.length() - block.valueStackStart();
     789           0 :     if (pushed > (IsVoid(block.resultType()) ? 0u : 1u))
     790           0 :         return fail("unused values not explicitly dropped by end of block");
     791             : 
     792           0 :     if (!topWithType(block.resultType(), value))
     793           0 :         return false;
     794             : 
     795           0 :     *type = block.resultType();
     796           0 :     return true;
     797             : }
     798             : 
     799             : template <typename Policy>
     800             : inline bool
     801           0 : OpIter<Policy>::getControl(uint32_t relativeDepth, ControlStackEntry<ControlItem>** controlEntry)
     802             : {
     803           0 :     if (relativeDepth >= controlStack_.length())
     804           0 :         return fail("branch depth exceeds current nesting level");
     805             : 
     806           0 :     *controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth];
     807           0 :     return true;
     808             : }
     809             : 
     810             : template <typename Policy>
     811             : inline bool
     812           0 : OpIter<Policy>::readBlockType(ExprType* type)
     813             : {
     814             :     uint8_t unchecked;
     815           0 :     if (!d_.readBlockType(&unchecked))
     816           0 :         return fail("unable to read block signature");
     817             : 
     818           0 :     switch (unchecked) {
     819             :       case uint8_t(ExprType::Void):
     820             :       case uint8_t(ExprType::I32):
     821             :       case uint8_t(ExprType::I64):
     822             :       case uint8_t(ExprType::F32):
     823             :       case uint8_t(ExprType::F64):
     824             :       case uint8_t(ExprType::I8x16):
     825             :       case uint8_t(ExprType::I16x8):
     826             :       case uint8_t(ExprType::I32x4):
     827             :       case uint8_t(ExprType::F32x4):
     828             :       case uint8_t(ExprType::B8x16):
     829             :       case uint8_t(ExprType::B16x8):
     830             :       case uint8_t(ExprType::B32x4):
     831           0 :         break;
     832             :       default:
     833           0 :         return fail("invalid inline block type");
     834             :     }
     835             : 
     836           0 :     *type = ExprType(unchecked);
     837           0 :     return true;
     838             : }
     839             : 
     840             : template <typename Policy>
     841             : inline bool
     842           0 : OpIter<Policy>::readOp(OpBytes* op)
     843             : {
     844           0 :     MOZ_ASSERT(!controlStack_.empty());
     845             : 
     846           0 :     offsetOfLastReadOp_ = d_.currentOffset();
     847             : 
     848           0 :     if (MOZ_UNLIKELY(!d_.readOp(op)))
     849           0 :         return fail("unable to read opcode");
     850             : 
     851             : #ifdef DEBUG
     852           0 :     op_ = *op;
     853             : #endif
     854             : 
     855           0 :     return true;
     856             : }
     857             : 
     858             : template <typename Policy>
     859             : inline void
     860           0 : OpIter<Policy>::peekOp(OpBytes* op)
     861             : {
     862           0 :     const uint8_t* pos = d_.currentPosition();
     863             : 
     864           0 :     if (MOZ_UNLIKELY(!d_.readOp(op)))
     865           0 :         op->b0 = uint16_t(Op::Limit);
     866             : 
     867           0 :     d_.rollbackPosition(pos);
     868           0 : }
     869             : 
     870             : template <typename Policy>
     871             : inline bool
     872           0 : OpIter<Policy>::readFunctionStart(ExprType ret)
     873             : {
     874           0 :     MOZ_ASSERT(valueStack_.empty());
     875           0 :     MOZ_ASSERT(controlStack_.empty());
     876           0 :     MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
     877             : 
     878           0 :     return pushControl(LabelKind::Block, ret);
     879             : }
     880             : 
     881             : template <typename Policy>
     882             : inline bool
     883           0 : OpIter<Policy>::readFunctionEnd(const uint8_t* bodyEnd)
     884             : {
     885           0 :     if (d_.currentPosition() != bodyEnd)
     886           0 :         return fail("function body length mismatch");
     887             : 
     888           0 :     if (!controlStack_.empty())
     889           0 :         return fail("unbalanced function body control flow");
     890             : 
     891             : #ifdef DEBUG
     892           0 :     op_ = OpBytes(Op::Limit);
     893             : #endif
     894           0 :     valueStack_.clear();
     895           0 :     return true;
     896             : }
     897             : 
     898             : template <typename Policy>
     899             : inline bool
     900           0 : OpIter<Policy>::readReturn(Value* value)
     901             : {
     902           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Return);
     903             : 
     904           0 :     ControlStackEntry<ControlItem>& body = controlStack_[0];
     905           0 :     MOZ_ASSERT(body.kind() == LabelKind::Block);
     906             : 
     907           0 :     if (!popWithType(body.resultType(), value))
     908           0 :         return false;
     909             : 
     910           0 :     afterUnconditionalBranch();
     911           0 :     return true;
     912             : }
     913             : 
     914             : template <typename Policy>
     915             : inline bool
     916           0 : OpIter<Policy>::readBlock()
     917             : {
     918           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Block);
     919             : 
     920           0 :     ExprType type = ExprType::Limit;
     921           0 :     if (!readBlockType(&type))
     922           0 :         return false;
     923             : 
     924           0 :     return pushControl(LabelKind::Block, type);
     925             : }
     926             : 
     927             : template <typename Policy>
     928             : inline bool
     929           0 : OpIter<Policy>::readLoop()
     930             : {
     931           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Loop);
     932             : 
     933           0 :     ExprType type = ExprType::Limit;
     934           0 :     if (!readBlockType(&type))
     935           0 :         return false;
     936             : 
     937           0 :     return pushControl(LabelKind::Loop, type);
     938             : }
     939             : 
     940             : template <typename Policy>
     941             : inline bool
     942           0 : OpIter<Policy>::readIf(Value* condition)
     943             : {
     944           0 :     MOZ_ASSERT(Classify(op_) == OpKind::If);
     945             : 
     946           0 :     ExprType type = ExprType::Limit;
     947           0 :     if (!readBlockType(&type))
     948           0 :         return false;
     949             : 
     950           0 :     if (!popWithType(ValType::I32, condition))
     951           0 :         return false;
     952             : 
     953           0 :     return pushControl(LabelKind::Then, type);
     954             : }
     955             : 
     956             : template <typename Policy>
     957             : inline bool
     958           0 : OpIter<Policy>::readElse(ExprType* type, Value* value)
     959             : {
     960           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Else);
     961             : 
     962             :     // Finish checking the then-block.
     963             : 
     964           0 :     if (!checkStackAtEndOfBlock(type, value))
     965           0 :         return false;
     966             : 
     967           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     968             : 
     969           0 :     if (block.kind() != LabelKind::Then)
     970           0 :         return fail("else can only be used within an if");
     971             : 
     972             :     // Switch to the else-block.
     973             : 
     974           0 :     if (!IsVoid(block.resultType()))
     975           0 :         valueStack_.popBack();
     976             : 
     977           0 :     MOZ_ASSERT(valueStack_.length() == block.valueStackStart());
     978             : 
     979           0 :     block.switchToElse();
     980           0 :     return true;
     981             : }
     982             : 
     983             : template <typename Policy>
     984             : inline bool
     985           0 : OpIter<Policy>::readEnd(LabelKind* kind, ExprType* type, Value* value)
     986             : {
     987           0 :     MOZ_ASSERT(Classify(op_) == OpKind::End);
     988             : 
     989           0 :     if (!checkStackAtEndOfBlock(type, value))
     990           0 :         return false;
     991             : 
     992           0 :     ControlStackEntry<ControlItem>& block = controlStack_.back();
     993             : 
     994             :     // If an `if` block ends with `end` instead of `else`, then we must
     995             :     // additionally validate that the then-block doesn't push anything.
     996           0 :     if (block.kind() == LabelKind::Then && !IsVoid(block.resultType()))
     997           0 :         return fail("if without else with a result value");
     998             : 
     999           0 :     *kind = block.kind();
    1000           0 :     return true;
    1001             : }
    1002             : 
    1003             : template <typename Policy>
    1004             : inline void
    1005           0 : OpIter<Policy>::popEnd()
    1006             : {
    1007           0 :     MOZ_ASSERT(Classify(op_) == OpKind::End);
    1008             : 
    1009           0 :     controlStack_.popBack();
    1010           0 : }
    1011             : 
    1012             : template <typename Policy>
    1013             : inline bool
    1014           0 : OpIter<Policy>::checkBranchValue(uint32_t relativeDepth, ExprType* type, Value* value)
    1015             : {
    1016           0 :     ControlStackEntry<ControlItem>* block = nullptr;
    1017           0 :     if (!getControl(relativeDepth, &block))
    1018           0 :         return false;
    1019             : 
    1020           0 :     *type = block->branchTargetType();
    1021           0 :     return topWithType(*type, value);
    1022             : }
    1023             : 
    1024             : template <typename Policy>
    1025             : inline bool
    1026           0 : OpIter<Policy>::readBr(uint32_t* relativeDepth, ExprType* type, Value* value)
    1027             : {
    1028           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Br);
    1029             : 
    1030           0 :     if (!readVarU32(relativeDepth))
    1031           0 :         return fail("unable to read br depth");
    1032             : 
    1033           0 :     if (!checkBranchValue(*relativeDepth, type, value))
    1034           0 :         return false;
    1035             : 
    1036           0 :     afterUnconditionalBranch();
    1037           0 :     return true;
    1038             : }
    1039             : 
    1040             : template <typename Policy>
    1041             : inline bool
    1042           0 : OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ExprType* type, Value* value, Value* condition)
    1043             : {
    1044           0 :     MOZ_ASSERT(Classify(op_) == OpKind::BrIf);
    1045             : 
    1046           0 :     if (!readVarU32(relativeDepth))
    1047           0 :         return fail("unable to read br_if depth");
    1048             : 
    1049           0 :     if (!popWithType(ValType::I32, condition))
    1050           0 :         return false;
    1051             : 
    1052           0 :     return checkBranchValue(*relativeDepth, type, value);
    1053             : }
    1054             : 
    1055             : template <typename Policy>
    1056             : inline bool
    1057           0 : OpIter<Policy>::checkBrTableEntry(uint32_t* relativeDepth, ExprType* branchValueType,
    1058             :                                   Value* branchValue)
    1059             : {
    1060           0 :     if (!readVarU32(relativeDepth))
    1061           0 :         return false;
    1062             : 
    1063             :     // For the first encountered branch target, do a normal branch value type
    1064             :     // check which will change *branchValueType to a non-sentinel value. For all
    1065             :     // subsequent branch targets, check that the branch target matches the
    1066             :     // now-known branch value type.
    1067             : 
    1068           0 :     if (*branchValueType == ExprType::Limit) {
    1069           0 :         if (!checkBranchValue(*relativeDepth, branchValueType, branchValue))
    1070           0 :             return false;
    1071             :     } else {
    1072           0 :         ControlStackEntry<ControlItem>* block = nullptr;
    1073           0 :         if (!getControl(*relativeDepth, &block))
    1074           0 :             return false;
    1075             : 
    1076           0 :         if (*branchValueType != block->branchTargetType())
    1077           0 :             return fail("br_table targets must all have the same value type");
    1078             :     }
    1079             : 
    1080           0 :     return true;
    1081             : }
    1082             : 
    1083             : template <typename Policy>
    1084             : inline bool
    1085           0 : OpIter<Policy>::readBrTable(Uint32Vector* depths, uint32_t* defaultDepth,
    1086             :                             ExprType* branchValueType, Value* branchValue, Value* index)
    1087             : {
    1088           0 :     MOZ_ASSERT(Classify(op_) == OpKind::BrTable);
    1089             : 
    1090             :     uint32_t tableLength;
    1091           0 :     if (!readVarU32(&tableLength))
    1092           0 :         return fail("unable to read br_table table length");
    1093             : 
    1094           0 :     if (tableLength > MaxBrTableElems)
    1095           0 :         return fail("br_table too big");
    1096             : 
    1097           0 :     if (!popWithType(ValType::I32, index))
    1098           0 :         return false;
    1099             : 
    1100           0 :     if (!depths->resize(tableLength))
    1101           0 :         return false;
    1102             : 
    1103           0 :     *branchValueType = ExprType::Limit;
    1104             : 
    1105           0 :     for (uint32_t i = 0; i < tableLength; i++) {
    1106           0 :         if (!checkBrTableEntry(&(*depths)[i], branchValueType, branchValue))
    1107           0 :             return false;
    1108             :     }
    1109             : 
    1110           0 :     if (!checkBrTableEntry(defaultDepth, branchValueType, branchValue))
    1111           0 :         return false;
    1112             : 
    1113           0 :     MOZ_ASSERT(*branchValueType != ExprType::Limit);
    1114             : 
    1115           0 :     afterUnconditionalBranch();
    1116           0 :     return true;
    1117             : }
    1118             : 
    1119             : template <typename Policy>
    1120             : inline bool
    1121           0 : OpIter<Policy>::readUnreachable()
    1122             : {
    1123           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Unreachable);
    1124             : 
    1125           0 :     afterUnconditionalBranch();
    1126           0 :     return true;
    1127             : }
    1128             : 
    1129             : template <typename Policy>
    1130             : inline bool
    1131           0 : OpIter<Policy>::readDrop()
    1132             : {
    1133           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Drop);
    1134             :     StackType type;
    1135             :     Value value;
    1136           0 :     return popAnyType(&type, &value);
    1137             : }
    1138             : 
    1139             : template <typename Policy>
    1140             : inline bool
    1141           0 : OpIter<Policy>::readUnary(ValType operandType, Value* input)
    1142             : {
    1143           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Unary);
    1144             : 
    1145           0 :     if (!popWithType(operandType, input))
    1146           0 :         return false;
    1147             : 
    1148           0 :     infalliblePush(operandType);
    1149             : 
    1150           0 :     return true;
    1151             : }
    1152             : 
    1153             : template <typename Policy>
    1154             : inline bool
    1155           0 : OpIter<Policy>::readConversion(ValType operandType, ValType resultType, Value* input)
    1156             : {
    1157           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Conversion);
    1158             : 
    1159           0 :     if (!popWithType(operandType, input))
    1160           0 :         return false;
    1161             : 
    1162           0 :     infalliblePush(resultType);
    1163             : 
    1164           0 :     return true;
    1165             : }
    1166             : 
    1167             : template <typename Policy>
    1168             : inline bool
    1169           0 : OpIter<Policy>::readBinary(ValType operandType, Value* lhs, Value* rhs)
    1170             : {
    1171           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Binary);
    1172             : 
    1173           0 :     if (!popWithType(operandType, rhs))
    1174           0 :         return false;
    1175             : 
    1176           0 :     if (!popWithType(operandType, lhs))
    1177           0 :         return false;
    1178             : 
    1179           0 :     infalliblePush(operandType);
    1180             : 
    1181           0 :     return true;
    1182             : }
    1183             : 
    1184             : template <typename Policy>
    1185             : inline bool
    1186           0 : OpIter<Policy>::readComparison(ValType operandType, Value* lhs, Value* rhs)
    1187             : {
    1188           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Comparison);
    1189             : 
    1190           0 :     if (!popWithType(operandType, rhs))
    1191           0 :         return false;
    1192             : 
    1193           0 :     if (!popWithType(operandType, lhs))
    1194           0 :         return false;
    1195             : 
    1196           0 :     infalliblePush(ValType::I32);
    1197             : 
    1198           0 :     return true;
    1199             : }
    1200             : 
    1201             : template <typename Policy>
    1202             : inline bool
    1203           0 : OpIter<Policy>::readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress<Value>* addr)
    1204             : {
    1205           0 :     if (!env_.usesMemory())
    1206           0 :         return fail("can't touch memory without memory");
    1207             : 
    1208             :     uint8_t alignLog2;
    1209           0 :     if (!readFixedU8(&alignLog2))
    1210           0 :         return fail("unable to read load alignment");
    1211             : 
    1212           0 :     if (!readVarU32(&addr->offset))
    1213           0 :         return fail("unable to read load offset");
    1214             : 
    1215           0 :     if (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize)
    1216           0 :         return fail("greater than natural alignment");
    1217             : 
    1218           0 :     if (!popWithType(ValType::I32, &addr->base))
    1219           0 :         return false;
    1220             : 
    1221           0 :     addr->align = uint32_t(1) << alignLog2;
    1222           0 :     return true;
    1223             : }
    1224             : 
    1225             : template <typename Policy>
    1226             : inline bool
    1227           0 : OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr)
    1228             : {
    1229           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Load);
    1230             : 
    1231           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1232           0 :         return false;
    1233             : 
    1234           0 :     infalliblePush(resultType);
    1235             : 
    1236           0 :     return true;
    1237             : }
    1238             : 
    1239             : template <typename Policy>
    1240             : inline bool
    1241           0 : OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr,
    1242             :                           Value* value)
    1243             : {
    1244           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Store);
    1245             : 
    1246           0 :     if (!popWithType(resultType, value))
    1247           0 :         return false;
    1248             : 
    1249           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1250           0 :         return false;
    1251             : 
    1252           0 :     return true;
    1253             : }
    1254             : 
    1255             : template <typename Policy>
    1256             : inline bool
    1257           0 : OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr,
    1258             :                              Value* value)
    1259             : {
    1260           0 :     MOZ_ASSERT(Classify(op_) == OpKind::TeeStore);
    1261             : 
    1262           0 :     if (!popWithType(resultType, value))
    1263           0 :         return false;
    1264             : 
    1265           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1266           0 :         return false;
    1267             : 
    1268           0 :     infalliblePush(TypeAndValue<Value>(resultType, *value));
    1269           0 :     return true;
    1270             : }
    1271             : 
    1272             : template <typename Policy>
    1273             : inline bool
    1274           0 : OpIter<Policy>::readNop()
    1275             : {
    1276           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Nop);
    1277             : 
    1278           0 :     return true;
    1279             : }
    1280             : 
    1281             : template <typename Policy>
    1282             : inline bool
    1283           0 : OpIter<Policy>::readCurrentMemory()
    1284             : {
    1285           0 :     MOZ_ASSERT(Classify(op_) == OpKind::CurrentMemory);
    1286             : 
    1287           0 :     if (!env_.usesMemory())
    1288           0 :         return fail("can't touch memory without memory");
    1289             : 
    1290             :     uint32_t flags;
    1291           0 :     if (!readVarU32(&flags))
    1292           0 :         return false;
    1293             : 
    1294           0 :     if (flags != uint32_t(MemoryTableFlags::Default))
    1295           0 :         return fail("unexpected flags");
    1296             : 
    1297           0 :     return push(ValType::I32);
    1298             : }
    1299             : 
    1300             : template <typename Policy>
    1301             : inline bool
    1302           0 : OpIter<Policy>::readGrowMemory(Value* input)
    1303             : {
    1304           0 :     MOZ_ASSERT(Classify(op_) == OpKind::GrowMemory);
    1305             : 
    1306           0 :     if (!env_.usesMemory())
    1307           0 :         return fail("can't touch memory without memory");
    1308             : 
    1309             :     uint32_t flags;
    1310           0 :     if (!readVarU32(&flags))
    1311           0 :         return false;
    1312             : 
    1313           0 :     if (flags != uint32_t(MemoryTableFlags::Default))
    1314           0 :         return fail("unexpected flags");
    1315             : 
    1316           0 :     if (!popWithType(ValType::I32, input))
    1317           0 :         return false;
    1318             : 
    1319           0 :     infalliblePush(ValType::I32);
    1320             : 
    1321           0 :     return true;
    1322             : }
    1323             : 
    1324             : template <typename Policy>
    1325             : inline bool
    1326           0 : OpIter<Policy>::readSelect(StackType* type, Value* trueValue, Value* falseValue, Value* condition)
    1327             : {
    1328           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Select);
    1329             : 
    1330           0 :     if (!popWithType(ValType::I32, condition))
    1331           0 :         return false;
    1332             : 
    1333             :     StackType falseType;
    1334           0 :     if (!popAnyType(&falseType, falseValue))
    1335           0 :         return false;
    1336             : 
    1337             :     StackType trueType;
    1338           0 :     if (!popAnyType(&trueType, trueValue))
    1339           0 :         return false;
    1340             : 
    1341           0 :     if (!Unify(falseType, trueType, type))
    1342           0 :         return fail("select operand types must match");
    1343             : 
    1344           0 :     infalliblePush(*type);
    1345           0 :     return true;
    1346             : }
    1347             : 
    1348             : template <typename Policy>
    1349             : inline bool
    1350           0 : OpIter<Policy>::readGetLocal(const ValTypeVector& locals, uint32_t* id)
    1351             : {
    1352           0 :     MOZ_ASSERT(Classify(op_) == OpKind::GetLocal);
    1353             : 
    1354           0 :     if (!readVarU32(id))
    1355           0 :         return false;
    1356             : 
    1357           0 :     if (*id >= locals.length())
    1358           0 :         return fail("get_local index out of range");
    1359             : 
    1360           0 :     return push(locals[*id]);
    1361             : }
    1362             : 
    1363             : template <typename Policy>
    1364             : inline bool
    1365           0 : OpIter<Policy>::readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value)
    1366             : {
    1367           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SetLocal);
    1368             : 
    1369           0 :     if (!readVarU32(id))
    1370           0 :         return false;
    1371             : 
    1372           0 :     if (*id >= locals.length())
    1373           0 :         return fail("set_local index out of range");
    1374             : 
    1375           0 :     return popWithType(locals[*id], value);
    1376             : }
    1377             : 
    1378             : template <typename Policy>
    1379             : inline bool
    1380           0 : OpIter<Policy>::readTeeLocal(const ValTypeVector& locals, uint32_t* id, Value* value)
    1381             : {
    1382           0 :     MOZ_ASSERT(Classify(op_) == OpKind::TeeLocal);
    1383             : 
    1384           0 :     if (!readVarU32(id))
    1385           0 :         return false;
    1386             : 
    1387           0 :     if (*id >= locals.length())
    1388           0 :         return fail("set_local index out of range");
    1389             : 
    1390           0 :     return topWithType(locals[*id], value);
    1391             : }
    1392             : 
    1393             : template <typename Policy>
    1394             : inline bool
    1395           0 : OpIter<Policy>::readGetGlobal(uint32_t* id)
    1396             : {
    1397           0 :     MOZ_ASSERT(Classify(op_) == OpKind::GetGlobal);
    1398             : 
    1399           0 :     if (!readVarU32(id))
    1400           0 :         return false;
    1401             : 
    1402           0 :     if (*id >= env_.globals.length())
    1403           0 :         return fail("get_global index out of range");
    1404             : 
    1405           0 :     return push(env_.globals[*id].type());
    1406             : }
    1407             : 
    1408             : template <typename Policy>
    1409             : inline bool
    1410           0 : OpIter<Policy>::readSetGlobal(uint32_t* id, Value* value)
    1411             : {
    1412           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SetGlobal);
    1413             : 
    1414           0 :     if (!readVarU32(id))
    1415           0 :         return false;
    1416             : 
    1417           0 :     if (*id >= env_.globals.length())
    1418           0 :         return fail("set_global index out of range");
    1419             : 
    1420           0 :     if (!env_.globals[*id].isMutable())
    1421           0 :         return fail("can't write an immutable global");
    1422             : 
    1423           0 :     return popWithType(env_.globals[*id].type(), value);
    1424             : }
    1425             : 
    1426             : template <typename Policy>
    1427             : inline bool
    1428           0 : OpIter<Policy>::readTeeGlobal(uint32_t* id, Value* value)
    1429             : {
    1430           0 :     MOZ_ASSERT(Classify(op_) == OpKind::TeeGlobal);
    1431             : 
    1432           0 :     if (!readVarU32(id))
    1433           0 :         return false;
    1434             : 
    1435           0 :     if (*id >= env_.globals.length())
    1436           0 :         return fail("set_global index out of range");
    1437             : 
    1438           0 :     if (!env_.globals[*id].isMutable())
    1439           0 :         return fail("can't write an immutable global");
    1440             : 
    1441           0 :     return topWithType(env_.globals[*id].type(), value);
    1442             : }
    1443             : 
    1444             : template <typename Policy>
    1445             : inline bool
    1446           0 : OpIter<Policy>::readI32Const(int32_t* i32)
    1447             : {
    1448           0 :     MOZ_ASSERT(Classify(op_) == OpKind::I32);
    1449             : 
    1450           0 :     return readVarS32(i32) &&
    1451           0 :            push(ValType::I32);
    1452             : }
    1453             : 
    1454             : template <typename Policy>
    1455             : inline bool
    1456           0 : OpIter<Policy>::readI64Const(int64_t* i64)
    1457             : {
    1458           0 :     MOZ_ASSERT(Classify(op_) == OpKind::I64);
    1459             : 
    1460           0 :     return readVarS64(i64) &&
    1461           0 :            push(ValType::I64);
    1462             : }
    1463             : 
    1464             : template <typename Policy>
    1465             : inline bool
    1466           0 : OpIter<Policy>::readF32Const(float* f32)
    1467             : {
    1468           0 :     MOZ_ASSERT(Classify(op_) == OpKind::F32);
    1469             : 
    1470           0 :     return readFixedF32(f32) &&
    1471           0 :            push(ValType::F32);
    1472             : }
    1473             : 
    1474             : template <typename Policy>
    1475             : inline bool
    1476           0 : OpIter<Policy>::readF64Const(double* f64)
    1477             : {
    1478           0 :     MOZ_ASSERT(Classify(op_) == OpKind::F64);
    1479             : 
    1480           0 :     return readFixedF64(f64) &&
    1481           0 :            push(ValType::F64);
    1482             : }
    1483             : 
    1484             : template <typename Policy>
    1485             : inline bool
    1486           0 : OpIter<Policy>::readI8x16Const(I8x16* i8x16)
    1487             : {
    1488           0 :     MOZ_ASSERT(Classify(op_) == OpKind::I8x16);
    1489             : 
    1490           0 :     return readFixedI8x16(i8x16) &&
    1491           0 :            push(ValType::I8x16);
    1492             : }
    1493             : 
    1494             : template <typename Policy>
    1495             : inline bool
    1496           0 : OpIter<Policy>::readI16x8Const(I16x8* i16x8)
    1497             : {
    1498           0 :     MOZ_ASSERT(Classify(op_) == OpKind::I16x8);
    1499             : 
    1500           0 :     return readFixedI16x8(i16x8) &&
    1501           0 :            push(ValType::I16x8);
    1502             : }
    1503             : 
    1504             : template <typename Policy>
    1505             : inline bool
    1506           0 : OpIter<Policy>::readI32x4Const(I32x4* i32x4)
    1507             : {
    1508           0 :     MOZ_ASSERT(Classify(op_) == OpKind::I32x4);
    1509             : 
    1510           0 :     return readFixedI32x4(i32x4) &&
    1511           0 :            push(ValType::I32x4);
    1512             : }
    1513             : 
    1514             : template <typename Policy>
    1515             : inline bool
    1516           0 : OpIter<Policy>::readF32x4Const(F32x4* f32x4)
    1517             : {
    1518           0 :     MOZ_ASSERT(Classify(op_) == OpKind::F32x4);
    1519             : 
    1520           0 :     return readFixedF32x4(f32x4) &&
    1521           0 :            push(ValType::F32x4);
    1522             : }
    1523             : 
    1524             : template <typename Policy>
    1525             : inline bool
    1526           0 : OpIter<Policy>::readB8x16Const(I8x16* i8x16)
    1527             : {
    1528           0 :     MOZ_ASSERT(Classify(op_) == OpKind::B8x16);
    1529             : 
    1530           0 :     return readFixedI8x16(i8x16) &&
    1531           0 :            push(ValType::B8x16);
    1532             : }
    1533             : 
    1534             : template <typename Policy>
    1535             : inline bool
    1536           0 : OpIter<Policy>::readB16x8Const(I16x8* i16x8)
    1537             : {
    1538           0 :     MOZ_ASSERT(Classify(op_) == OpKind::B16x8);
    1539             : 
    1540           0 :     return readFixedI16x8(i16x8) &&
    1541           0 :            push(ValType::B16x8);
    1542             : }
    1543             : 
    1544             : template <typename Policy>
    1545             : inline bool
    1546           0 : OpIter<Policy>::readB32x4Const(I32x4* i32x4)
    1547             : {
    1548           0 :     MOZ_ASSERT(Classify(op_) == OpKind::B32x4);
    1549             : 
    1550           0 :     return readFixedI32x4(i32x4) &&
    1551           0 :            push(ValType::B32x4);
    1552             : }
    1553             : 
    1554             : template <typename Policy>
    1555             : inline bool
    1556           0 : OpIter<Policy>::popCallArgs(const ValTypeVector& expectedTypes, ValueVector* values)
    1557             : {
    1558             :     // Iterate through the argument types backward so that pops occur in the
    1559             :     // right order.
    1560             : 
    1561           0 :     if (!values->resize(expectedTypes.length()))
    1562           0 :         return false;
    1563             : 
    1564           0 :     for (int32_t i = expectedTypes.length() - 1; i >= 0; i--) {
    1565           0 :         if (!popWithType(expectedTypes[i], &(*values)[i]))
    1566           0 :             return false;
    1567             :     }
    1568             : 
    1569           0 :     return true;
    1570             : }
    1571             : 
    1572             : template <typename Policy>
    1573             : inline bool
    1574           0 : OpIter<Policy>::readCall(uint32_t* funcIndex, ValueVector* argValues)
    1575             : {
    1576           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Call);
    1577             : 
    1578           0 :     if (!readVarU32(funcIndex))
    1579           0 :         return fail("unable to read call function index");
    1580             : 
    1581           0 :     if (*funcIndex >= env_.funcSigs.length())
    1582           0 :         return fail("callee index out of range");
    1583             : 
    1584           0 :     const Sig& sig = *env_.funcSigs[*funcIndex];
    1585             : 
    1586           0 :     if (!popCallArgs(sig.args(), argValues))
    1587           0 :         return false;
    1588             : 
    1589           0 :     return push(sig.ret());
    1590             : }
    1591             : 
    1592             : template <typename Policy>
    1593             : inline bool
    1594           0 : OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues)
    1595             : {
    1596           0 :     MOZ_ASSERT(Classify(op_) == OpKind::CallIndirect);
    1597             : 
    1598           0 :     if (!env_.tables.length())
    1599           0 :         return fail("can't call_indirect without a table");
    1600             : 
    1601           0 :     if (!readVarU32(sigIndex))
    1602           0 :         return fail("unable to read call_indirect signature index");
    1603             : 
    1604           0 :     if (*sigIndex >= env_.numSigs())
    1605           0 :         return fail("signature index out of range");
    1606             : 
    1607             :     uint32_t flags;
    1608           0 :     if (!readVarU32(&flags))
    1609           0 :         return false;
    1610             : 
    1611           0 :     if (flags != uint32_t(MemoryTableFlags::Default))
    1612           0 :         return fail("unexpected flags");
    1613             : 
    1614           0 :     if (!popWithType(ValType::I32, callee))
    1615           0 :         return false;
    1616             : 
    1617           0 :     const Sig& sig = env_.sigs[*sigIndex];
    1618             : 
    1619           0 :     if (!popCallArgs(sig.args(), argValues))
    1620           0 :         return false;
    1621             : 
    1622           0 :     return push(sig.ret());
    1623             : }
    1624             : 
    1625             : template <typename Policy>
    1626             : inline bool
    1627           0 : OpIter<Policy>::readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues)
    1628             : {
    1629           0 :     MOZ_ASSERT(Classify(op_) == OpKind::OldCallIndirect);
    1630             : 
    1631           0 :     if (!readVarU32(sigIndex))
    1632           0 :         return fail("unable to read call_indirect signature index");
    1633             : 
    1634           0 :     if (*sigIndex >= env_.numSigs())
    1635           0 :         return fail("signature index out of range");
    1636             : 
    1637           0 :     const Sig& sig = env_.sigs[*sigIndex];
    1638             : 
    1639           0 :     if (!popCallArgs(sig.args(), argValues))
    1640           0 :         return false;
    1641             : 
    1642           0 :     if (!popWithType(ValType::I32, callee))
    1643           0 :         return false;
    1644             : 
    1645           0 :     if (!push(sig.ret()))
    1646           0 :         return false;
    1647             : 
    1648           0 :     return true;
    1649             : }
    1650             : 
    1651             : template <typename Policy>
    1652             : inline bool
    1653           0 : OpIter<Policy>::readAtomicLoad(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType)
    1654             : {
    1655           0 :     MOZ_ASSERT(Classify(op_) == OpKind::AtomicLoad);
    1656             : 
    1657           0 :     if (!readAtomicViewType(viewType))
    1658           0 :         return false;
    1659             : 
    1660           0 :     uint32_t byteSize = Scalar::byteSize(*viewType);
    1661           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1662           0 :         return false;
    1663             : 
    1664           0 :     infalliblePush(ValType::I32);
    1665           0 :     return true;
    1666             : }
    1667             : 
    1668             : template <typename Policy>
    1669             : inline bool
    1670           0 : OpIter<Policy>::readAtomicStore(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType,
    1671             :                                 Value* value)
    1672             : {
    1673           0 :     MOZ_ASSERT(Classify(op_) == OpKind::AtomicStore);
    1674             : 
    1675           0 :     if (!readAtomicViewType(viewType))
    1676           0 :         return false;
    1677             : 
    1678           0 :     uint32_t byteSize = Scalar::byteSize(*viewType);
    1679           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1680           0 :         return false;
    1681             : 
    1682           0 :     if (!popWithType(ValType::I32, value))
    1683           0 :         return false;
    1684             : 
    1685           0 :     infalliblePush(ValType::I32);
    1686           0 :     return true;
    1687             : }
    1688             : 
    1689             : template <typename Policy>
    1690             : inline bool
    1691           0 : OpIter<Policy>::readAtomicBinOp(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType,
    1692             :                                 jit::AtomicOp* op, Value* value)
    1693             : {
    1694           0 :     MOZ_ASSERT(Classify(op_) == OpKind::AtomicBinOp);
    1695             : 
    1696           0 :     if (!readAtomicViewType(viewType))
    1697           0 :         return false;
    1698             : 
    1699           0 :     if (!readAtomicBinOpOp(op))
    1700           0 :         return false;
    1701             : 
    1702           0 :     uint32_t byteSize = Scalar::byteSize(*viewType);
    1703           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1704           0 :         return false;
    1705             : 
    1706           0 :     if (!popWithType(ValType::I32, value))
    1707           0 :         return false;
    1708             : 
    1709           0 :     infalliblePush(ValType::I32);
    1710           0 :     return true;
    1711             : }
    1712             : 
    1713             : template <typename Policy>
    1714             : inline bool
    1715           0 : OpIter<Policy>::readAtomicCompareExchange(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType,
    1716             :                                           Value* oldValue, Value* newValue)
    1717             : {
    1718           0 :     MOZ_ASSERT(Classify(op_) == OpKind::AtomicCompareExchange);
    1719             : 
    1720           0 :     if (!readAtomicViewType(viewType))
    1721           0 :         return false;
    1722             : 
    1723           0 :     uint32_t byteSize = Scalar::byteSize(*viewType);
    1724           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1725           0 :         return false;
    1726             : 
    1727           0 :     if (!popWithType(ValType::I32, newValue))
    1728           0 :         return false;
    1729             : 
    1730           0 :     if (!popWithType(ValType::I32, oldValue))
    1731           0 :         return false;
    1732             : 
    1733           0 :     infalliblePush(ValType::I32);
    1734           0 :     return true;
    1735             : }
    1736             : 
    1737             : template <typename Policy>
    1738             : inline bool
    1739           0 : OpIter<Policy>::readAtomicExchange(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType,
    1740             :                                    Value* value)
    1741             : {
    1742           0 :     MOZ_ASSERT(Classify(op_) == OpKind::AtomicExchange);
    1743             : 
    1744           0 :     if (!readAtomicViewType(viewType))
    1745           0 :         return false;
    1746             : 
    1747           0 :     uint32_t byteSize = Scalar::byteSize(*viewType);
    1748           0 :     if (!readLinearMemoryAddress(byteSize, addr))
    1749           0 :         return false;
    1750             : 
    1751           0 :     if (!popWithType(ValType::I32, value))
    1752           0 :         return false;
    1753             : 
    1754           0 :     infalliblePush(ValType::I32);
    1755           0 :     return true;
    1756             : }
    1757             : 
    1758             : template <typename Policy>
    1759             : inline bool
    1760           0 : OpIter<Policy>::readSimdComparison(ValType simdType, Value* lhs, Value* rhs)
    1761             : {
    1762           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SimdComparison);
    1763             : 
    1764           0 :     if (!popWithType(simdType, rhs))
    1765           0 :         return false;
    1766             : 
    1767           0 :     if (!popWithType(simdType, lhs))
    1768           0 :         return false;
    1769             : 
    1770           0 :     infalliblePush(SimdBoolType(simdType));
    1771             : 
    1772           0 :     return true;
    1773             : }
    1774             : 
    1775             : template <typename Policy>
    1776             : inline bool
    1777           0 : OpIter<Policy>::readSimdShiftByScalar(ValType simdType, Value* lhs, Value* rhs)
    1778             : {
    1779           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SimdShiftByScalar);
    1780             : 
    1781           0 :     if (!popWithType(ValType::I32, rhs))
    1782           0 :         return false;
    1783             : 
    1784           0 :     if (!popWithType(simdType, lhs))
    1785           0 :         return false;
    1786             : 
    1787           0 :     infalliblePush(simdType);
    1788             : 
    1789           0 :     return true;
    1790             : }
    1791             : 
    1792             : template <typename Policy>
    1793             : inline bool
    1794           0 : OpIter<Policy>::readSimdBooleanReduction(ValType simdType, Value* input)
    1795             : {
    1796           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SimdBooleanReduction);
    1797             : 
    1798           0 :     if (!popWithType(simdType, input))
    1799           0 :         return false;
    1800             : 
    1801           0 :     infalliblePush(ValType::I32);
    1802             : 
    1803           0 :     return true;
    1804             : }
    1805             : 
    1806             : template <typename Policy>
    1807             : inline bool
    1808           0 : OpIter<Policy>::readExtractLane(ValType simdType, uint8_t* lane, Value* vector)
    1809             : {
    1810           0 :     MOZ_ASSERT(Classify(op_) == OpKind::ExtractLane);
    1811             : 
    1812             :     uint32_t laneBits;
    1813           0 :     if (!readVarU32(&laneBits))
    1814           0 :         return false;
    1815             : 
    1816           0 :     if (laneBits >= NumSimdElements(simdType))
    1817           0 :         return fail("simd lane out of bounds for simd type");
    1818             : 
    1819           0 :     *lane = uint8_t(laneBits);
    1820             : 
    1821           0 :     if (!popWithType(simdType, vector))
    1822           0 :         return false;
    1823             : 
    1824           0 :     infalliblePush(SimdElementType(simdType));
    1825           0 :     return true;
    1826             : }
    1827             : 
    1828             : template <typename Policy>
    1829             : inline bool
    1830           0 : OpIter<Policy>::readReplaceLane(ValType simdType, uint8_t* lane, Value* vector, Value* scalar)
    1831             : {
    1832           0 :     MOZ_ASSERT(Classify(op_) == OpKind::ReplaceLane);
    1833             : 
    1834             :     uint32_t laneBits;
    1835           0 :     if (!readVarU32(&laneBits))
    1836           0 :         return false;
    1837             : 
    1838           0 :     if (laneBits >= NumSimdElements(simdType))
    1839           0 :         return fail("simd lane out of bounds for simd type");
    1840             : 
    1841           0 :     *lane = uint8_t(laneBits);
    1842             : 
    1843           0 :     if (!popWithType(SimdElementType(simdType), scalar))
    1844           0 :         return false;
    1845             : 
    1846           0 :     if (!popWithType(simdType, vector))
    1847           0 :         return false;
    1848             : 
    1849           0 :     infalliblePush(simdType);
    1850           0 :     return true;
    1851             : }
    1852             : 
    1853             : template <typename Policy>
    1854             : inline bool
    1855           0 : OpIter<Policy>::readSplat(ValType simdType, Value* scalar)
    1856             : {
    1857           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Splat);
    1858             : 
    1859           0 :     if (!popWithType(SimdElementType(simdType), scalar))
    1860           0 :         return false;
    1861             : 
    1862           0 :     infalliblePush(simdType);
    1863             : 
    1864           0 :     return true;
    1865             : }
    1866             : 
    1867             : template <typename Policy>
    1868             : inline bool
    1869           0 : OpIter<Policy>::readSwizzle(ValType simdType, uint8_t (* lanes)[16], Value* vector)
    1870             : {
    1871           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Swizzle);
    1872             : 
    1873           0 :     uint32_t numSimdLanes = NumSimdElements(simdType);
    1874           0 :     MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes));
    1875           0 :     for (uint32_t i = 0; i < numSimdLanes; ++i) {
    1876           0 :         if (!readFixedU8(&(*lanes)[i]))
    1877           0 :             return fail("unable to read swizzle lane");
    1878           0 :         if ((*lanes)[i] >= numSimdLanes)
    1879           0 :             return fail("swizzle index out of bounds");
    1880             :     }
    1881             : 
    1882           0 :     if (!popWithType(simdType, vector))
    1883           0 :         return false;
    1884             : 
    1885           0 :     infalliblePush(simdType);
    1886             : 
    1887           0 :     return true;
    1888             : }
    1889             : 
    1890             : template <typename Policy>
    1891             : inline bool
    1892           0 : OpIter<Policy>::readShuffle(ValType simdType, uint8_t (* lanes)[16], Value* lhs, Value* rhs)
    1893             : {
    1894           0 :     MOZ_ASSERT(Classify(op_) == OpKind::Shuffle);
    1895             : 
    1896           0 :     uint32_t numSimdLanes = NumSimdElements(simdType);
    1897           0 :     MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes));
    1898           0 :     for (uint32_t i = 0; i < numSimdLanes; ++i) {
    1899           0 :         if (!readFixedU8(&(*lanes)[i]))
    1900           0 :             return fail("unable to read shuffle lane");
    1901           0 :         if ((*lanes)[i] >= numSimdLanes * 2)
    1902           0 :             return fail("shuffle index out of bounds");
    1903             :     }
    1904             : 
    1905           0 :     if (!popWithType(simdType, rhs))
    1906           0 :         return false;
    1907             : 
    1908           0 :     if (!popWithType(simdType, lhs))
    1909           0 :         return false;
    1910             : 
    1911           0 :     infalliblePush(simdType);
    1912             : 
    1913           0 :     return true;
    1914             : }
    1915             : 
    1916             : template <typename Policy>
    1917             : inline bool
    1918           0 : OpIter<Policy>::readSimdSelect(ValType simdType, Value* trueValue, Value* falseValue,
    1919             :                                Value* condition)
    1920             : {
    1921           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SimdSelect);
    1922             : 
    1923           0 :     if (!popWithType(simdType, falseValue))
    1924           0 :         return false;
    1925           0 :     if (!popWithType(simdType, trueValue))
    1926           0 :         return false;
    1927           0 :     if (!popWithType(SimdBoolType(simdType), condition))
    1928           0 :         return false;
    1929             : 
    1930           0 :     infalliblePush(simdType);
    1931             : 
    1932           0 :     return true;
    1933             : }
    1934             : 
    1935             : template <typename Policy>
    1936             : inline bool
    1937           0 : OpIter<Policy>::readSimdCtor(ValType elementType, uint32_t numElements, ValType simdType,
    1938             :                              ValueVector* argValues)
    1939             : {
    1940           0 :     MOZ_ASSERT(Classify(op_) == OpKind::SimdCtor);
    1941             : 
    1942           0 :     if (!argValues->resize(numElements))
    1943           0 :         return false;
    1944             : 
    1945           0 :     for (int32_t i = numElements - 1; i >= 0; i--) {
    1946           0 :         if (!popWithType(elementType, &(*argValues)[i]))
    1947           0 :             return false;
    1948             :     }
    1949             : 
    1950           0 :     infalliblePush(simdType);
    1951             : 
    1952           0 :     return true;
    1953             : }
    1954             : 
    1955             : } // namespace wasm
    1956             : } // namespace js
    1957             : 
    1958             : namespace mozilla {
    1959             : 
    1960             : // Specialize IsPod for the Nothing specializations.
    1961             : template<> struct IsPod<js::wasm::TypeAndValue<Nothing>> : TrueType {};
    1962             : template<> struct IsPod<js::wasm::ControlStackEntry<Nothing>> : TrueType {};
    1963             : 
    1964             : } // namespace mozilla
    1965             : 
    1966             : #endif // wasm_iterator_h

Generated by: LCOV version 1.13