1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  *
4  * Copyright 2016 Mozilla Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #ifndef wasm_op_iter_h
20 #define wasm_op_iter_h
21 
22 #include "mozilla/CompactPair.h"
23 #include "mozilla/Poison.h"
24 
25 #include <type_traits>
26 
27 #include "js/Printf.h"
28 #include "wasm/WasmIntrinsic.h"
29 #include "wasm/WasmUtility.h"
30 #include "wasm/WasmValidate.h"
31 
32 namespace js {
33 namespace wasm {
34 
35 // The kind of a control-flow stack item.
36 enum class LabelKind : uint8_t {
37   Body,
38   Block,
39   Loop,
40   Then,
41   Else,
42 #ifdef ENABLE_WASM_EXCEPTIONS
43   Try,
44   Catch,
45   CatchAll,
46 #endif
47 };
48 
49 // The type of values on the operand stack during validation.  This is either a
50 // ValType or the special type "Bottom".
51 
52 class StackType {
53   PackedTypeCode tc_;
54 
StackType(PackedTypeCode tc)55   explicit StackType(PackedTypeCode tc) : tc_(tc) {}
56 
57  public:
StackType()58   StackType() : tc_(PackedTypeCode::invalid()) {}
59 
StackType(const ValType & t)60   explicit StackType(const ValType& t) : tc_(t.packed()) {
61     MOZ_ASSERT(tc_.isValid());
62     MOZ_ASSERT(!isBottom());
63   }
64 
bottom()65   static StackType bottom() {
66     return StackType(PackedTypeCode::pack(TypeCode::Limit));
67   }
68 
isBottom()69   bool isBottom() const {
70     MOZ_ASSERT(tc_.isValid());
71     return tc_.typeCode() == TypeCode::Limit;
72   }
73 
valType()74   ValType valType() const {
75     MOZ_ASSERT(tc_.isValid());
76     MOZ_ASSERT(!isBottom());
77     return ValType(tc_);
78   }
79 
asNonNullable()80   ValType asNonNullable() const {
81     MOZ_ASSERT(tc_.isValid());
82     MOZ_ASSERT(!isBottom());
83     return ValType(tc_.asNonNullable());
84   }
85 
isValidForUntypedSelect()86   bool isValidForUntypedSelect() const {
87     MOZ_ASSERT(tc_.isValid());
88     if (isBottom()) {
89       return true;
90     }
91     switch (valType().kind()) {
92       case ValType::I32:
93       case ValType::F32:
94       case ValType::I64:
95       case ValType::F64:
96 #ifdef ENABLE_WASM_SIMD
97       case ValType::V128:
98 #endif
99         return true;
100       default:
101         return false;
102     }
103   }
104 
105   bool operator==(const StackType& that) const {
106     MOZ_ASSERT(tc_.isValid() && that.tc_.isValid());
107     return tc_ == that.tc_;
108   }
109 
110   bool operator!=(const StackType& that) const {
111     MOZ_ASSERT(tc_.isValid() && that.tc_.isValid());
112     return tc_ != that.tc_;
113   }
114 };
115 
116 #ifdef DEBUG
117 // Families of opcodes that share a signature and validation logic.
118 enum class OpKind {
119   Block,
120   Loop,
121   Unreachable,
122   Drop,
123   I32,
124   I64,
125   F32,
126   F64,
127   V128,
128   Br,
129   BrIf,
130   BrTable,
131   Nop,
132   Unary,
133   Binary,
134   Ternary,
135   Comparison,
136   Conversion,
137   Load,
138   Store,
139   TeeStore,
140   MemorySize,
141   MemoryGrow,
142   Select,
143   GetLocal,
144   SetLocal,
145   TeeLocal,
146   GetGlobal,
147   SetGlobal,
148   TeeGlobal,
149   Call,
150   CallIndirect,
151   OldCallDirect,
152   OldCallIndirect,
153   Return,
154   If,
155   Else,
156   End,
157   Wait,
158   Wake,
159   Fence,
160   AtomicLoad,
161   AtomicStore,
162   AtomicBinOp,
163   AtomicCompareExchange,
164   OldAtomicLoad,
165   OldAtomicStore,
166   OldAtomicBinOp,
167   OldAtomicCompareExchange,
168   OldAtomicExchange,
169   MemOrTableCopy,
170   DataOrElemDrop,
171   MemFill,
172   MemOrTableInit,
173   TableFill,
174   TableGet,
175   TableGrow,
176   TableSet,
177   TableSize,
178   RefNull,
179   RefFunc,
180   RefAsNonNull,
181   BrOnNull,
182   StructNewWithRtt,
183   StructNewDefaultWithRtt,
184   StructGet,
185   StructSet,
186   ArrayNewWithRtt,
187   ArrayNewDefaultWithRtt,
188   ArrayGet,
189   ArraySet,
190   ArrayLen,
191   RttCanon,
192   RttSub,
193   RefTest,
194   RefCast,
195   BrOnCast,
196 #  ifdef ENABLE_WASM_SIMD
197   ExtractLane,
198   ReplaceLane,
199   LoadLane,
200   StoreLane,
201   VectorShift,
202   VectorShuffle,
203 #  endif
204 #  ifdef ENABLE_WASM_EXCEPTIONS
205   Catch,
206   CatchAll,
207   Delegate,
208   Throw,
209   Rethrow,
210   Try,
211 #  endif
212   Intrinsic,
213 };
214 
215 // Return the OpKind for a given Op. This is used for sanity-checking that
216 // API users use the correct read function for a given Op.
217 OpKind Classify(OpBytes op);
218 #endif
219 
220 // Common fields for linear memory access.
221 template <typename Value>
222 struct LinearMemoryAddress {
223   Value base;
224   uint64_t offset;
225   uint32_t align;
226 
LinearMemoryAddressLinearMemoryAddress227   LinearMemoryAddress() : offset(0), align(0) {}
LinearMemoryAddressLinearMemoryAddress228   LinearMemoryAddress(Value base, uint64_t offset, uint32_t align)
229       : base(base), offset(offset), align(align) {}
230 };
231 
232 template <typename ControlItem>
233 class ControlStackEntry {
234   // Use a pair to optimize away empty ControlItem.
235   mozilla::CompactPair<BlockType, ControlItem> typeAndItem_;
236 
237   // The "base" of a control stack entry is valueStack_.length() minus
238   // type().params().length(), i.e., the size of the value stack "below"
239   // this block.
240   uint32_t valueStackBase_;
241   bool polymorphicBase_;
242 
243   LabelKind kind_;
244 
245  public:
ControlStackEntry(LabelKind kind,BlockType type,uint32_t valueStackBase)246   ControlStackEntry(LabelKind kind, BlockType type, uint32_t valueStackBase)
247       : typeAndItem_(type, ControlItem()),
248         valueStackBase_(valueStackBase),
249         polymorphicBase_(false),
250         kind_(kind) {
251     MOZ_ASSERT(type != BlockType());
252   }
253 
kind()254   LabelKind kind() const { return kind_; }
type()255   BlockType type() const { return typeAndItem_.first(); }
resultType()256   ResultType resultType() const { return type().results(); }
branchTargetType()257   ResultType branchTargetType() const {
258     return kind_ == LabelKind::Loop ? type().params() : type().results();
259   }
valueStackBase()260   uint32_t valueStackBase() const { return valueStackBase_; }
controlItem()261   ControlItem& controlItem() { return typeAndItem_.second(); }
setPolymorphicBase()262   void setPolymorphicBase() { polymorphicBase_ = true; }
polymorphicBase()263   bool polymorphicBase() const { return polymorphicBase_; }
264 
switchToElse()265   void switchToElse() {
266     MOZ_ASSERT(kind() == LabelKind::Then);
267     kind_ = LabelKind::Else;
268     polymorphicBase_ = false;
269   }
270 
271 #ifdef ENABLE_WASM_EXCEPTIONS
switchToCatch()272   void switchToCatch() {
273     MOZ_ASSERT(kind() == LabelKind::Try);
274     kind_ = LabelKind::Catch;
275     polymorphicBase_ = false;
276   }
277 
switchToCatchAll()278   void switchToCatchAll() {
279     MOZ_ASSERT(kind() == LabelKind::Try || kind() == LabelKind::Catch);
280     kind_ = LabelKind::CatchAll;
281     polymorphicBase_ = false;
282   }
283 #endif
284 };
285 
286 template <typename Value>
287 class TypeAndValueT {
288   // Use a Pair to optimize away empty Value.
289   mozilla::CompactPair<StackType, Value> tv_;
290 
291  public:
TypeAndValueT()292   TypeAndValueT() : tv_(StackType::bottom(), Value()) {}
TypeAndValueT(StackType type)293   explicit TypeAndValueT(StackType type) : tv_(type, Value()) {}
TypeAndValueT(ValType type)294   explicit TypeAndValueT(ValType type) : tv_(StackType(type), Value()) {}
TypeAndValueT(StackType type,Value value)295   TypeAndValueT(StackType type, Value value) : tv_(type, value) {}
TypeAndValueT(ValType type,Value value)296   TypeAndValueT(ValType type, Value value) : tv_(StackType(type), value) {}
type()297   StackType type() const { return tv_.first(); }
typeRef()298   StackType& typeRef() { return tv_.first(); }
value()299   Value value() const { return tv_.second(); }
setValue(Value value)300   void setValue(Value value) { tv_.second() = value; }
301 };
302 
303 // An iterator over the bytes of a function body. It performs validation
304 // and unpacks the data into a usable form.
305 //
306 // The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly.
307 // There's otherwise nothing inherent in this class which would require
308 // it to be used on the stack.
309 template <typename Policy>
310 class MOZ_STACK_CLASS OpIter : private Policy {
311  public:
312   using Value = typename Policy::Value;
313   using ValueVector = typename Policy::ValueVector;
314   using TypeAndValue = TypeAndValueT<Value>;
315   using TypeAndValueStack = Vector<TypeAndValue, 8, SystemAllocPolicy>;
316   using ControlItem = typename Policy::ControlItem;
317   using Control = ControlStackEntry<ControlItem>;
318   using ControlStack = Vector<Control, 8, SystemAllocPolicy>;
319 
320   enum Kind {
321     Func,
322     InitExpr,
323   };
324 
325  private:
326   Kind kind_;
327   Decoder& d_;
328   const ModuleEnvironment& env_;
329   TypeCache cache_;
330 
331   TypeAndValueStack valueStack_;
332   TypeAndValueStack elseParamStack_;
333   ControlStack controlStack_;
334 
335 #ifdef DEBUG
336   OpBytes op_;
337 #endif
338   size_t offsetOfLastReadOp_;
339 
readFixedU8(uint8_t * out)340   [[nodiscard]] bool readFixedU8(uint8_t* out) { return d_.readFixedU8(out); }
readFixedU32(uint32_t * out)341   [[nodiscard]] bool readFixedU32(uint32_t* out) {
342     return d_.readFixedU32(out);
343   }
readVarS32(int32_t * out)344   [[nodiscard]] bool readVarS32(int32_t* out) { return d_.readVarS32(out); }
readVarU32(uint32_t * out)345   [[nodiscard]] bool readVarU32(uint32_t* out) { return d_.readVarU32(out); }
readVarS64(int64_t * out)346   [[nodiscard]] bool readVarS64(int64_t* out) { return d_.readVarS64(out); }
readVarU64(uint64_t * out)347   [[nodiscard]] bool readVarU64(uint64_t* out) { return d_.readVarU64(out); }
readFixedF32(float * out)348   [[nodiscard]] bool readFixedF32(float* out) { return d_.readFixedF32(out); }
readFixedF64(double * out)349   [[nodiscard]] bool readFixedF64(double* out) { return d_.readFixedF64(out); }
350 
351   [[nodiscard]] bool readMemOrTableIndex(bool isMem, uint32_t* index);
352   [[nodiscard]] bool readLinearMemoryAddress(uint32_t byteSize,
353                                              LinearMemoryAddress<Value>* addr);
354   [[nodiscard]] bool readLinearMemoryAddressAligned(
355       uint32_t byteSize, LinearMemoryAddress<Value>* addr);
356   [[nodiscard]] bool readBlockType(BlockType* type);
357   [[nodiscard]] bool readGcTypeIndex(uint32_t* typeIndex);
358   [[nodiscard]] bool readStructTypeIndex(uint32_t* typeIndex);
359   [[nodiscard]] bool readArrayTypeIndex(uint32_t* typeIndex);
360   [[nodiscard]] bool readFieldIndex(uint32_t* fieldIndex,
361                                     const StructType& structType);
362 
363   [[nodiscard]] bool popCallArgs(const ValTypeVector& expectedTypes,
364                                  ValueVector* values);
365 
366   [[nodiscard]] bool failEmptyStack();
367   [[nodiscard]] bool popStackType(StackType* type, Value* value);
368   [[nodiscard]] bool popWithType(ValType expected, Value* value);
369   [[nodiscard]] bool popWithType(ResultType expected, ValueVector* values);
370   template <typename ValTypeSpanT>
371   [[nodiscard]] bool popWithTypes(ValTypeSpanT expected, ValueVector* values);
372   [[nodiscard]] bool popWithRefType(Value* value, StackType* type);
373   [[nodiscard]] bool popWithRttType(Value* rtt, uint32_t* rttTypeIndex,
374                                     uint32_t* rttDepth);
375   [[nodiscard]] bool popWithRttType(Value* rtt, uint32_t rttTypeIndex,
376                                     uint32_t* rttDepth);
377   [[nodiscard]] bool popThenPushType(ResultType expected, ValueVector* values);
378   [[nodiscard]] bool topWithTypeAndPush(ResultType expected,
379                                         ValueVector* values);
380 
381   [[nodiscard]] bool pushControl(LabelKind kind, BlockType type);
382   [[nodiscard]] bool checkStackAtEndOfBlock(ResultType* type,
383                                             ValueVector* values);
384   [[nodiscard]] bool getControl(uint32_t relativeDepth, Control** controlEntry);
385   [[nodiscard]] bool checkBranchValueAndPush(uint32_t relativeDepth,
386                                              ResultType* type,
387                                              ValueVector* values);
388   [[nodiscard]] bool checkCastedBranchValueAndPush(uint32_t relativeDepth,
389                                                    ValType castedFromType,
390                                                    ValType castedToType,
391                                                    ResultType* branchTargetType,
392                                                    ValueVector* values);
393   [[nodiscard]] bool checkBrTableEntryAndPush(uint32_t* relativeDepth,
394                                               ResultType prevBranchType,
395                                               ResultType* branchType,
396                                               ValueVector* branchValues);
397 
push(StackType t)398   [[nodiscard]] bool push(StackType t) { return valueStack_.emplaceBack(t); }
push(ValType t)399   [[nodiscard]] bool push(ValType t) { return valueStack_.emplaceBack(t); }
push(TypeAndValue tv)400   [[nodiscard]] bool push(TypeAndValue tv) { return valueStack_.append(tv); }
push(ResultType t)401   [[nodiscard]] bool push(ResultType t) {
402     for (size_t i = 0; i < t.length(); i++) {
403       if (!push(t[i])) {
404         return false;
405       }
406     }
407     return true;
408   }
infalliblePush(StackType t)409   void infalliblePush(StackType t) { valueStack_.infallibleEmplaceBack(t); }
infalliblePush(ValType t)410   void infalliblePush(ValType t) {
411     valueStack_.infallibleEmplaceBack(StackType(t));
412   }
infalliblePush(TypeAndValue tv)413   void infalliblePush(TypeAndValue tv) { valueStack_.infallibleAppend(tv); }
414 
afterUnconditionalBranch()415   void afterUnconditionalBranch() {
416     valueStack_.shrinkTo(controlStack_.back().valueStackBase());
417     controlStack_.back().setPolymorphicBase();
418   }
419 
420   inline bool checkIsSubtypeOf(ValType actual, ValType expected);
421   inline bool checkIsSubtypeOf(ResultType params, ResultType results);
422 
423 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
424   inline bool checkIsSubtypeOf(uint32_t actualTypeIndex,
425                                uint32_t expectedTypeIndex);
426 #endif
427 
428  public:
429 #ifdef DEBUG
430   explicit OpIter(const ModuleEnvironment& env, Decoder& decoder,
431                   Kind kind = OpIter::Func)
kind_(kind)432       : kind_(kind),
433         d_(decoder),
434         env_(env),
435         op_(OpBytes(Op::Limit)),
436         offsetOfLastReadOp_(0) {}
437 #else
438   explicit OpIter(const ModuleEnvironment& env, Decoder& decoder,
439                   Kind kind = OpIter::Func)
440       : kind_(kind), d_(decoder), env_(env), offsetOfLastReadOp_(0) {}
441 #endif
442 
443   // Return the decoding byte offset.
currentOffset()444   uint32_t currentOffset() const { return d_.currentOffset(); }
445 
446   // Return the offset within the entire module of the last-read op.
lastOpcodeOffset()447   size_t lastOpcodeOffset() const {
448     return offsetOfLastReadOp_ ? offsetOfLastReadOp_ : d_.currentOffset();
449   }
450 
451   // Return a BytecodeOffset describing where the current op should be reported
452   // to trap/call.
bytecodeOffset()453   BytecodeOffset bytecodeOffset() const {
454     return BytecodeOffset(lastOpcodeOffset());
455   }
456 
457   // Test whether the iterator has reached the end of the buffer.
done()458   bool done() const { return d_.done(); }
459 
460   // Return a pointer to the end of the buffer being decoded by this iterator.
end()461   const uint8_t* end() const { return d_.end(); }
462 
463   // Report a general failure.
464   [[nodiscard]] bool fail(const char* msg) MOZ_COLD;
465 
466   // Report a general failure with a context
467   [[nodiscard]] bool fail_ctx(const char* fmt, const char* context) MOZ_COLD;
468 
469   // Report an unrecognized opcode.
470   [[nodiscard]] 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.
currentBlockHasPolymorphicBase()474   bool currentBlockHasPolymorphicBase() const {
475     return !controlStack_.empty() && controlStack_.back().polymorphicBase();
476   }
477 
478   // ------------------------------------------------------------------------
479   // Decoding and validation interface.
480 
481   // Initialization and termination
482 
483   [[nodiscard]] bool startFunction(uint32_t funcIndex);
484   [[nodiscard]] bool endFunction(const uint8_t* bodyEnd);
485 
486   [[nodiscard]] bool startInitExpr(ValType expected);
487   [[nodiscard]] bool endInitExpr();
488 
489   // Value and reference types
490 
491   [[nodiscard]] bool readValType(ValType* type);
492   [[nodiscard]] bool readHeapType(bool nullable, RefType* type);
493 
494   // Instructions
495 
496   [[nodiscard]] bool readOp(OpBytes* op);
497   [[nodiscard]] bool readReturn(ValueVector* values);
498   [[nodiscard]] bool readBlock(ResultType* paramType);
499   [[nodiscard]] bool readLoop(ResultType* paramType);
500   [[nodiscard]] bool readIf(ResultType* paramType, Value* condition);
501   [[nodiscard]] bool readElse(ResultType* paramType, ResultType* resultType,
502                               ValueVector* thenResults);
503   [[nodiscard]] bool readEnd(LabelKind* kind, ResultType* type,
504                              ValueVector* results,
505                              ValueVector* resultsForEmptyElse);
506   void popEnd();
507   [[nodiscard]] bool readBr(uint32_t* relativeDepth, ResultType* type,
508                             ValueVector* values);
509   [[nodiscard]] bool readBrIf(uint32_t* relativeDepth, ResultType* type,
510                               ValueVector* values, Value* condition);
511   [[nodiscard]] bool readBrTable(Uint32Vector* depths, uint32_t* defaultDepth,
512                                  ResultType* defaultBranchType,
513                                  ValueVector* branchValues, Value* index);
514 #ifdef ENABLE_WASM_EXCEPTIONS
515   [[nodiscard]] bool readTry(ResultType* type);
516   [[nodiscard]] bool readCatch(LabelKind* kind, uint32_t* tagIndex,
517                                ResultType* paramType, ResultType* resultType,
518                                ValueVector* tryResults);
519   [[nodiscard]] bool readCatchAll(LabelKind* kind, ResultType* paramType,
520                                   ResultType* resultType,
521                                   ValueVector* tryResults);
522   [[nodiscard]] bool readDelegate(uint32_t* relativeDepth,
523                                   ResultType* resultType,
524                                   ValueVector* tryResults);
525   void popDelegate();
526   [[nodiscard]] bool readThrow(uint32_t* tagIndex, ValueVector* argValues);
527   [[nodiscard]] bool readRethrow(uint32_t* relativeDepth);
528 #endif
529   [[nodiscard]] bool readUnreachable();
530   [[nodiscard]] bool readDrop();
531   [[nodiscard]] bool readUnary(ValType operandType, Value* input);
532   [[nodiscard]] bool readConversion(ValType operandType, ValType resultType,
533                                     Value* input);
534   [[nodiscard]] bool readBinary(ValType operandType, Value* lhs, Value* rhs);
535   [[nodiscard]] bool readComparison(ValType operandType, Value* lhs,
536                                     Value* rhs);
537   [[nodiscard]] bool readTernary(ValType operandType, Value* v0, Value* v1,
538                                  Value* v2);
539   [[nodiscard]] bool readLoad(ValType resultType, uint32_t byteSize,
540                               LinearMemoryAddress<Value>* addr);
541   [[nodiscard]] bool readStore(ValType resultType, uint32_t byteSize,
542                                LinearMemoryAddress<Value>* addr, Value* value);
543   [[nodiscard]] bool readTeeStore(ValType resultType, uint32_t byteSize,
544                                   LinearMemoryAddress<Value>* addr,
545                                   Value* value);
546   [[nodiscard]] bool readNop();
547   [[nodiscard]] bool readMemorySize();
548   [[nodiscard]] bool readMemoryGrow(Value* input);
549   [[nodiscard]] bool readSelect(bool typed, StackType* type, Value* trueValue,
550                                 Value* falseValue, Value* condition);
551   [[nodiscard]] bool readGetLocal(const ValTypeVector& locals, uint32_t* id);
552   [[nodiscard]] bool readSetLocal(const ValTypeVector& locals, uint32_t* id,
553                                   Value* value);
554   [[nodiscard]] bool readTeeLocal(const ValTypeVector& locals, uint32_t* id,
555                                   Value* value);
556   [[nodiscard]] bool readGetGlobal(uint32_t* id);
557   [[nodiscard]] bool readSetGlobal(uint32_t* id, Value* value);
558   [[nodiscard]] bool readTeeGlobal(uint32_t* id, Value* value);
559   [[nodiscard]] bool readI32Const(int32_t* i32);
560   [[nodiscard]] bool readI64Const(int64_t* i64);
561   [[nodiscard]] bool readF32Const(float* f32);
562   [[nodiscard]] bool readF64Const(double* f64);
563   [[nodiscard]] bool readRefFunc(uint32_t* funcIndex);
564   [[nodiscard]] bool readRefNull(RefType* type);
565   [[nodiscard]] bool readRefIsNull(Value* input);
566   [[nodiscard]] bool readRefAsNonNull(Value* input);
567   [[nodiscard]] bool readBrOnNull(uint32_t* relativeDepth, ResultType* type,
568                                   ValueVector* values, Value* condition);
569   [[nodiscard]] bool readCall(uint32_t* funcTypeIndex, ValueVector* argValues);
570   [[nodiscard]] bool readCallIndirect(uint32_t* funcTypeIndex,
571                                       uint32_t* tableIndex, Value* callee,
572                                       ValueVector* argValues);
573   [[nodiscard]] bool readOldCallDirect(uint32_t numFuncImports,
574                                        uint32_t* funcTypeIndex,
575                                        ValueVector* argValues);
576   [[nodiscard]] bool readOldCallIndirect(uint32_t* funcTypeIndex, Value* callee,
577                                          ValueVector* argValues);
578   [[nodiscard]] bool readWake(LinearMemoryAddress<Value>* addr, Value* count);
579   [[nodiscard]] bool readWait(LinearMemoryAddress<Value>* addr,
580                               ValType valueType, uint32_t byteSize,
581                               Value* value, Value* timeout);
582   [[nodiscard]] bool readFence();
583   [[nodiscard]] bool readAtomicLoad(LinearMemoryAddress<Value>* addr,
584                                     ValType resultType, uint32_t byteSize);
585   [[nodiscard]] bool readAtomicStore(LinearMemoryAddress<Value>* addr,
586                                      ValType resultType, uint32_t byteSize,
587                                      Value* value);
588   [[nodiscard]] bool readAtomicRMW(LinearMemoryAddress<Value>* addr,
589                                    ValType resultType, uint32_t byteSize,
590                                    Value* value);
591   [[nodiscard]] bool readAtomicCmpXchg(LinearMemoryAddress<Value>* addr,
592                                        ValType resultType, uint32_t byteSize,
593                                        Value* oldValue, Value* newValue);
594   [[nodiscard]] bool readMemOrTableCopy(bool isMem,
595                                         uint32_t* dstMemOrTableIndex,
596                                         Value* dst,
597                                         uint32_t* srcMemOrTableIndex,
598                                         Value* src, Value* len);
599   [[nodiscard]] bool readDataOrElemDrop(bool isData, uint32_t* segIndex);
600   [[nodiscard]] bool readMemFill(Value* start, Value* val, Value* len);
601   [[nodiscard]] bool readMemOrTableInit(bool isMem, uint32_t* segIndex,
602                                         uint32_t* dstTableIndex, Value* dst,
603                                         Value* src, Value* len);
604   [[nodiscard]] bool readTableFill(uint32_t* tableIndex, Value* start,
605                                    Value* val, Value* len);
606   [[nodiscard]] bool readTableGet(uint32_t* tableIndex, Value* index);
607   [[nodiscard]] bool readTableGrow(uint32_t* tableIndex, Value* initValue,
608                                    Value* delta);
609   [[nodiscard]] bool readTableSet(uint32_t* tableIndex, Value* index,
610                                   Value* value);
611 
612   [[nodiscard]] bool readTableSize(uint32_t* tableIndex);
613 
614 #ifdef ENABLE_WASM_GC
615   [[nodiscard]] bool readStructNewWithRtt(uint32_t* typeIndex, Value* rtt,
616                                           ValueVector* argValues);
617   [[nodiscard]] bool readStructNewDefaultWithRtt(uint32_t* typeIndex,
618                                                  Value* rtt);
619   [[nodiscard]] bool readStructGet(uint32_t* typeIndex, uint32_t* fieldIndex,
620                                    FieldExtension extension, Value* ptr);
621   [[nodiscard]] bool readStructSet(uint32_t* typeIndex, uint32_t* fieldIndex,
622                                    Value* ptr, Value* val);
623   [[nodiscard]] bool readArrayNewWithRtt(uint32_t* typeIndex, Value* rtt,
624                                          Value* length, Value* argValue);
625   [[nodiscard]] bool readArrayNewDefaultWithRtt(uint32_t* typeIndex, Value* rtt,
626                                                 Value* length);
627   [[nodiscard]] bool readArrayGet(uint32_t* typeIndex, FieldExtension extension,
628                                   Value* index, Value* ptr);
629   [[nodiscard]] bool readArraySet(uint32_t* typeIndex, Value* val, Value* index,
630                                   Value* ptr);
631   [[nodiscard]] bool readArrayLen(uint32_t* typeIndex, Value* ptr);
632   [[nodiscard]] bool readRttCanon(ValType* rttType);
633   [[nodiscard]] bool readRttSub(Value* parentRtt, uint32_t* rttSubTypeIndex);
634   [[nodiscard]] bool readRefTest(Value* rtt, uint32_t* rttTypeIndex,
635                                  uint32_t* rttDepth, Value* ref);
636   [[nodiscard]] bool readRefCast(Value* rtt, uint32_t* rttTypeIndex,
637                                  uint32_t* rttDepth, Value* ref);
638   [[nodiscard]] bool readBrOnCast(uint32_t* relativeDepth, Value* rtt,
639                                   uint32_t* rttTypeIndex, uint32_t* rttDepth,
640                                   ResultType* branchTargetType,
641                                   ValueVector* values);
642 #endif
643 
644 #ifdef ENABLE_WASM_SIMD
645   [[nodiscard]] bool readLaneIndex(uint32_t inputLanes, uint32_t* laneIndex);
646   [[nodiscard]] bool readExtractLane(ValType resultType, uint32_t inputLanes,
647                                      uint32_t* laneIndex, Value* input);
648   [[nodiscard]] bool readReplaceLane(ValType operandType, uint32_t inputLanes,
649                                      uint32_t* laneIndex, Value* baseValue,
650                                      Value* operand);
651   [[nodiscard]] bool readVectorShift(Value* baseValue, Value* shift);
652   [[nodiscard]] bool readVectorShuffle(Value* v1, Value* v2, V128* selectMask);
653   [[nodiscard]] bool readV128Const(V128* value);
654   [[nodiscard]] bool readLoadSplat(uint32_t byteSize,
655                                    LinearMemoryAddress<Value>* addr);
656   [[nodiscard]] bool readLoadExtend(LinearMemoryAddress<Value>* addr);
657   [[nodiscard]] bool readLoadLane(uint32_t byteSize,
658                                   LinearMemoryAddress<Value>* addr,
659                                   uint32_t* laneIndex, Value* input);
660   [[nodiscard]] bool readStoreLane(uint32_t byteSize,
661                                    LinearMemoryAddress<Value>* addr,
662                                    uint32_t* laneIndex, Value* input);
663 #endif
664 
665   [[nodiscard]] bool readIntrinsic(const Intrinsic** intrinsic,
666                                    ValueVector* params);
667 
668   // At a location where readOp is allowed, peek at the next opcode
669   // without consuming it or updating any internal state.
670   // Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read.
671   void peekOp(OpBytes* op);
672 
673   // ------------------------------------------------------------------------
674   // Stack management.
675 
676   // Set the top N result values.
setResults(size_t count,const ValueVector & values)677   void setResults(size_t count, const ValueVector& values) {
678     MOZ_ASSERT(valueStack_.length() >= count);
679     size_t base = valueStack_.length() - count;
680     for (size_t i = 0; i < count; i++) {
681       valueStack_[base + i].setValue(values[i]);
682     }
683   }
684 
getResults(size_t count,ValueVector * values)685   bool getResults(size_t count, ValueVector* values) {
686     MOZ_ASSERT(valueStack_.length() >= count);
687     if (!values->resize(count)) {
688       return false;
689     }
690     size_t base = valueStack_.length() - count;
691     for (size_t i = 0; i < count; i++) {
692       (*values)[i] = valueStack_[base + i].value();
693     }
694     return true;
695   }
696 
697   // Set the result value of the current top-of-value-stack expression.
setResult(Value value)698   void setResult(Value value) { valueStack_.back().setValue(value); }
699 
700   // Return the result value of the current top-of-value-stack expression.
getResult()701   Value getResult() { return valueStack_.back().value(); }
702 
703   // Return a reference to the top of the control stack.
controlItem()704   ControlItem& controlItem() { return controlStack_.back().controlItem(); }
705 
706   // Return a reference to an element in the control stack.
controlItem(uint32_t relativeDepth)707   ControlItem& controlItem(uint32_t relativeDepth) {
708     return controlStack_[controlStack_.length() - 1 - relativeDepth]
709         .controlItem();
710   }
711 
712   // Return the LabelKind of an element in the control stack.
controlKind(uint32_t relativeDepth)713   LabelKind controlKind(uint32_t relativeDepth) {
714     return controlStack_[controlStack_.length() - 1 - relativeDepth].kind();
715   }
716 
717   // Return a reference to the outermost element on the control stack.
controlOutermost()718   ControlItem& controlOutermost() { return controlStack_[0].controlItem(); }
719 
720   // Test whether the control-stack is empty, meaning we've consumed the final
721   // end of the function body.
controlStackEmpty()722   bool controlStackEmpty() const { return controlStack_.empty(); }
723 
724   // Return the depth of the control stack.
controlStackDepth()725   size_t controlStackDepth() const { return controlStack_.length(); }
726 
727   // Find the innermost control item of a specific kind, starting to search from
728   // a certain relative depth, and returning true if such innermost control item
729   // is found. The relative depth of the found item is returned via a parameter.
controlFindInnermostFrom(LabelKind kind,uint32_t fromRelativeDepth,uint32_t * foundRelativeDepth)730   bool controlFindInnermostFrom(LabelKind kind, uint32_t fromRelativeDepth,
731                                 uint32_t* foundRelativeDepth) {
732     int32_t fromAbsoluteDepth = controlStack_.length() - fromRelativeDepth - 1;
733     for (int32_t i = fromAbsoluteDepth; i >= 0; i--) {
734       if (controlStack_[i].kind() == kind) {
735         *foundRelativeDepth = controlStack_.length() - 1 - i;
736         return true;
737       }
738     }
739     return false;
740   }
741 
controlFindInnermost(LabelKind kind,uint32_t * foundRelativeDepth)742   bool controlFindInnermost(LabelKind kind, uint32_t* foundRelativeDepth) {
743     return controlFindInnermostFrom(kind, 0, foundRelativeDepth);
744   }
745 };
746 
747 template <typename Policy>
checkIsSubtypeOf(ValType actual,ValType expected)748 inline bool OpIter<Policy>::checkIsSubtypeOf(ValType actual, ValType expected) {
749   return CheckIsSubtypeOf(d_, env_, lastOpcodeOffset(), actual, expected,
750                           &cache_);
751 }
752 
753 template <typename Policy>
checkIsSubtypeOf(ResultType params,ResultType results)754 inline bool OpIter<Policy>::checkIsSubtypeOf(ResultType params,
755                                              ResultType results) {
756   if (params.length() != results.length()) {
757     UniqueChars error(
758         JS_smprintf("type mismatch: expected %zu values, got %zu values",
759                     results.length(), params.length()));
760     if (!error) {
761       return false;
762     }
763     return fail(error.get());
764   }
765   for (uint32_t i = 0; i < params.length(); i++) {
766     ValType param = params[i];
767     ValType result = results[i];
768     if (!checkIsSubtypeOf(param, result)) {
769       return false;
770     }
771   }
772   return true;
773 }
774 
775 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
776 template <typename Policy>
checkIsSubtypeOf(uint32_t actualTypeIndex,uint32_t expectedTypeIndex)777 inline bool OpIter<Policy>::checkIsSubtypeOf(uint32_t actualTypeIndex,
778                                              uint32_t expectedTypeIndex) {
779   return CheckIsSubtypeOf(
780       d_, env_, lastOpcodeOffset(),
781       ValType(RefType::fromTypeIndex(actualTypeIndex, true)),
782       ValType(RefType::fromTypeIndex(expectedTypeIndex, true)), &cache_);
783 }
784 #endif
785 
786 template <typename Policy>
unrecognizedOpcode(const OpBytes * expr)787 inline bool OpIter<Policy>::unrecognizedOpcode(const OpBytes* expr) {
788   UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0,
789                                 IsPrefixByte(expr->b0) ? expr->b1 : 0));
790   if (!error) {
791     return false;
792   }
793 
794   return fail(error.get());
795 }
796 
797 template <typename Policy>
fail(const char * msg)798 inline bool OpIter<Policy>::fail(const char* msg) {
799   return d_.fail(lastOpcodeOffset(), msg);
800 }
801 
802 template <typename Policy>
fail_ctx(const char * fmt,const char * context)803 inline bool OpIter<Policy>::fail_ctx(const char* fmt, const char* context) {
804   UniqueChars error(JS_smprintf(fmt, context));
805   if (!error) {
806     return false;
807   }
808   return fail(error.get());
809 }
810 
811 template <typename Policy>
failEmptyStack()812 inline bool OpIter<Policy>::failEmptyStack() {
813   return valueStack_.empty() ? fail("popping value from empty stack")
814                              : fail("popping value from outside block");
815 }
816 
817 // This function pops exactly one value from the stack, yielding Bottom types in
818 // various cases and therefore making it the caller's responsibility to do the
819 // right thing for StackType::Bottom. Prefer (pop|top)WithType.  This is an
820 // optimization for the super-common case where the caller is statically
821 // expecting the resulttype `[valtype]`.
822 template <typename Policy>
popStackType(StackType * type,Value * value)823 inline bool OpIter<Policy>::popStackType(StackType* type, Value* value) {
824   Control& block = controlStack_.back();
825 
826   MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
827   if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackBase())) {
828     // If the base of this block's stack is polymorphic, then we can pop a
829     // dummy value of the bottom type; it won't be used since we're in
830     // unreachable code.
831     if (block.polymorphicBase()) {
832       *type = StackType::bottom();
833       *value = Value();
834 
835       // Maintain the invariant that, after a pop, there is always memory
836       // reserved to push a value infallibly.
837       return valueStack_.reserve(valueStack_.length() + 1);
838     }
839 
840     return failEmptyStack();
841   }
842 
843   TypeAndValue& tv = valueStack_.back();
844   *type = tv.type();
845   *value = tv.value();
846   valueStack_.popBack();
847   return true;
848 }
849 
850 // This function pops exactly one value from the stack, checking that it has the
851 // expected type which can either be a specific value type or a type variable.
852 template <typename Policy>
popWithType(ValType expectedType,Value * value)853 inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value) {
854   StackType stackType;
855   if (!popStackType(&stackType, value)) {
856     return false;
857   }
858 
859   return stackType.isBottom() ||
860          checkIsSubtypeOf(stackType.valType(), expectedType);
861 }
862 
863 template <typename Policy>
popWithType(ResultType expected,ValueVector * values)864 inline bool OpIter<Policy>::popWithType(ResultType expected,
865                                         ValueVector* values) {
866   return popWithTypes(expected, values);
867 }
868 
869 // Pops each of the given expected types (in reverse, because it's a stack).
870 template <typename Policy>
871 template <typename ValTypeSpanT>
popWithTypes(ValTypeSpanT expected,ValueVector * values)872 inline bool OpIter<Policy>::popWithTypes(ValTypeSpanT expected,
873                                          ValueVector* values) {
874   size_t expectedLength = expected.size();
875   if (!values->resize(expectedLength)) {
876     return false;
877   }
878   for (size_t i = 0; i < expectedLength; i++) {
879     size_t reverseIndex = expectedLength - i - 1;
880     ValType expectedType = expected[reverseIndex];
881     Value* value = &(*values)[reverseIndex];
882     if (!popWithType(expectedType, value)) {
883       return false;
884     }
885   }
886   return true;
887 }
888 
889 // This function pops exactly one value from the stack, checking that it is a
890 // reference type.
891 template <typename Policy>
popWithRefType(Value * value,StackType * type)892 inline bool OpIter<Policy>::popWithRefType(Value* value, StackType* type) {
893   if (!popStackType(type, value)) {
894     return false;
895   }
896 
897   if (type->isBottom() || type->valType().isRefType()) {
898     return true;
899   }
900 
901   UniqueChars actualText = ToString(type->valType());
902   if (!actualText) {
903     return false;
904   }
905 
906   UniqueChars error(JS_smprintf(
907       "type mismatch: expression has type %s but expected a reference type",
908       actualText.get()));
909   if (!error) {
910     return false;
911   }
912 
913   return fail(error.get());
914 }
915 
916 // This function pops exactly one value from the stack, checking that it is an
917 // rtt type with any type index or depth value.
918 template <typename Policy>
popWithRttType(Value * rtt,uint32_t * rttTypeIndex,uint32_t * rttDepth)919 inline bool OpIter<Policy>::popWithRttType(Value* rtt, uint32_t* rttTypeIndex,
920                                            uint32_t* rttDepth) {
921   StackType type;
922   if (!popStackType(&type, rtt)) {
923     return false;
924   }
925 
926   if (type.isBottom()) {
927     return fail("gc instruction temporarily not allowed in dead code");
928   }
929 
930   if (type.valType().isRtt()) {
931     *rttTypeIndex = type.valType().typeIndex();
932     *rttDepth = type.valType().rttDepth();
933     return true;
934   }
935 
936   UniqueChars actualText = ToString(type.valType());
937   if (!actualText) {
938     return false;
939   }
940 
941   UniqueChars error(
942       JS_smprintf("type mismatch: expression has type %s but expected (rtt _)",
943                   actualText.get()));
944   if (!error) {
945     return false;
946   }
947 
948   return fail(error.get());
949 }
950 
951 // This function is an optimization of the sequence:
952 //   popWithType(ResultType, tmp)
953 //   push(ResultType, tmp)
954 template <typename Policy>
popThenPushType(ResultType expected,ValueVector * values)955 inline bool OpIter<Policy>::popThenPushType(ResultType expected,
956                                             ValueVector* values) {
957   if (expected.empty()) {
958     return true;
959   }
960 
961   Control& block = controlStack_.back();
962 
963   size_t expectedLength = expected.length();
964   if (values && !values->resize(expectedLength)) {
965     return false;
966   }
967 
968   for (size_t i = 0; i != expectedLength; i++) {
969     // We're iterating as-if we were popping each expected/actual type one by
970     // one, which means iterating the array of expected results backwards.
971     // The "current" value stack length refers to what the value stack length
972     // would have been if we were popping it.
973     size_t reverseIndex = expectedLength - i - 1;
974     ValType expectedType = expected[reverseIndex];
975     auto collectValue = [&](const Value& v) {
976       if (values) {
977         (*values)[reverseIndex] = v;
978       }
979     };
980 
981     size_t currentValueStackLength = valueStack_.length() - i;
982 
983     MOZ_ASSERT(currentValueStackLength >= block.valueStackBase());
984     if (currentValueStackLength == block.valueStackBase()) {
985       if (!block.polymorphicBase()) {
986         return failEmptyStack();
987       }
988 
989       // If the base of this block's stack is polymorphic, then we can just
990       // pull out as many fake values as we need to validate; they won't be used
991       // since we're in unreachable code. We must however push these types on
992       // the operand stack since they are now fixed by this constraint.
993       if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength,
994                               TypeAndValue(expectedType))) {
995         return false;
996       }
997 
998       collectValue(Value());
999     } else {
1000       TypeAndValue& observed = valueStack_[currentValueStackLength - 1];
1001 
1002       if (observed.type().isBottom()) {
1003         observed.typeRef() = StackType(expectedType);
1004         collectValue(Value());
1005       } else {
1006         if (!checkIsSubtypeOf(observed.type().valType(), expectedType)) {
1007           return false;
1008         }
1009 
1010         collectValue(observed.value());
1011       }
1012     }
1013   }
1014   return true;
1015 }
1016 
1017 template <typename Policy>
topWithTypeAndPush(ResultType expected,ValueVector * values)1018 inline bool OpIter<Policy>::topWithTypeAndPush(ResultType expected,
1019                                                ValueVector* values) {
1020   if (expected.empty()) {
1021     return true;
1022   }
1023 
1024   Control& block = controlStack_.back();
1025 
1026   size_t expectedLength = expected.length();
1027   if (values && !values->resize(expectedLength)) {
1028     return false;
1029   }
1030 
1031   for (size_t i = 0; i != expectedLength; i++) {
1032     // We're iterating as-if we were popping each expected/actual type one by
1033     // one, which means iterating the array of expected results backwards.
1034     // The "current" value stack length refers to what the value stack length
1035     // would have been if we were popping it.
1036     size_t reverseIndex = expectedLength - i - 1;
1037     ValType expectedType = expected[reverseIndex];
1038     auto collectValue = [&](const Value& v) {
1039       if (values) {
1040         (*values)[reverseIndex] = v;
1041       }
1042     };
1043 
1044     size_t currentValueStackLength = valueStack_.length() - i;
1045 
1046     MOZ_ASSERT(currentValueStackLength >= block.valueStackBase());
1047     if (currentValueStackLength == block.valueStackBase()) {
1048       if (!block.polymorphicBase()) {
1049         return failEmptyStack();
1050       }
1051 
1052       // If the base of this block's stack is polymorphic, then we can just
1053       // pull out as many fake values as we need to validate; they won't be used
1054       // since we're in unreachable code.
1055       if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength,
1056                               TypeAndValue())) {
1057         return false;
1058       }
1059 
1060       collectValue(Value());
1061     } else {
1062       TypeAndValue& observed = valueStack_[currentValueStackLength - 1];
1063 
1064       if (observed.type().isBottom()) {
1065         collectValue(Value());
1066       } else {
1067         if (!checkIsSubtypeOf(observed.type().valType(), expectedType)) {
1068           return false;
1069         }
1070 
1071         collectValue(observed.value());
1072       }
1073     }
1074   }
1075   return true;
1076 }
1077 
1078 template <typename Policy>
pushControl(LabelKind kind,BlockType type)1079 inline bool OpIter<Policy>::pushControl(LabelKind kind, BlockType type) {
1080   ResultType paramType = type.params();
1081 
1082   ValueVector values;
1083   if (!popThenPushType(paramType, &values)) {
1084     return false;
1085   }
1086   MOZ_ASSERT(valueStack_.length() >= paramType.length());
1087   uint32_t valueStackBase = valueStack_.length() - paramType.length();
1088   return controlStack_.emplaceBack(kind, type, valueStackBase);
1089 }
1090 
1091 template <typename Policy>
checkStackAtEndOfBlock(ResultType * expectedType,ValueVector * values)1092 inline bool OpIter<Policy>::checkStackAtEndOfBlock(ResultType* expectedType,
1093                                                    ValueVector* values) {
1094   Control& block = controlStack_.back();
1095   *expectedType = block.type().results();
1096 
1097   MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
1098   if (expectedType->length() < valueStack_.length() - block.valueStackBase()) {
1099     return fail("unused values not explicitly dropped by end of block");
1100   }
1101 
1102   return popThenPushType(*expectedType, values);
1103 }
1104 
1105 template <typename Policy>
getControl(uint32_t relativeDepth,Control ** controlEntry)1106 inline bool OpIter<Policy>::getControl(uint32_t relativeDepth,
1107                                        Control** controlEntry) {
1108   if (relativeDepth >= controlStack_.length()) {
1109     return fail("branch depth exceeds current nesting level");
1110   }
1111 
1112   *controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth];
1113   return true;
1114 }
1115 
1116 template <typename Policy>
readBlockType(BlockType * type)1117 inline bool OpIter<Policy>::readBlockType(BlockType* type) {
1118   uint8_t nextByte;
1119   if (!d_.peekByte(&nextByte)) {
1120     return fail("unable to read block type");
1121   }
1122 
1123   if (nextByte == uint8_t(TypeCode::BlockVoid)) {
1124     d_.uncheckedReadFixedU8();
1125     *type = BlockType::VoidToVoid();
1126     return true;
1127   }
1128 
1129   if ((nextByte & SLEB128SignMask) == SLEB128SignBit) {
1130     ValType v;
1131     if (!readValType(&v)) {
1132       return false;
1133     }
1134     *type = BlockType::VoidToSingle(v);
1135     return true;
1136   }
1137 
1138   int32_t x;
1139   if (!d_.readVarS32(&x) || x < 0 || uint32_t(x) >= env_.types->length()) {
1140     return fail("invalid block type type index");
1141   }
1142 
1143   if (!env_.types->isFuncType(x)) {
1144     return fail("block type type index must be func type");
1145   }
1146 
1147   *type = BlockType::Func(env_.types->funcType(x));
1148 
1149   return true;
1150 }
1151 
1152 template <typename Policy>
readOp(OpBytes * op)1153 inline bool OpIter<Policy>::readOp(OpBytes* op) {
1154   MOZ_ASSERT(!controlStack_.empty());
1155 
1156   offsetOfLastReadOp_ = d_.currentOffset();
1157 
1158   if (MOZ_UNLIKELY(!d_.readOp(op))) {
1159     return fail("unable to read opcode");
1160   }
1161 
1162 #ifdef DEBUG
1163   op_ = *op;
1164 #endif
1165 
1166   return true;
1167 }
1168 
1169 template <typename Policy>
peekOp(OpBytes * op)1170 inline void OpIter<Policy>::peekOp(OpBytes* op) {
1171   const uint8_t* pos = d_.currentPosition();
1172 
1173   if (MOZ_UNLIKELY(!d_.readOp(op))) {
1174     op->b0 = uint16_t(Op::Limit);
1175   }
1176 
1177   d_.rollbackPosition(pos);
1178 }
1179 
1180 template <typename Policy>
startFunction(uint32_t funcIndex)1181 inline bool OpIter<Policy>::startFunction(uint32_t funcIndex) {
1182   MOZ_ASSERT(kind_ == OpIter::Func);
1183   MOZ_ASSERT(elseParamStack_.empty());
1184   MOZ_ASSERT(valueStack_.empty());
1185   MOZ_ASSERT(controlStack_.empty());
1186   MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
1187   BlockType type = BlockType::FuncResults(*env_.funcs[funcIndex].type);
1188   return pushControl(LabelKind::Body, type);
1189 }
1190 
1191 template <typename Policy>
endFunction(const uint8_t * bodyEnd)1192 inline bool OpIter<Policy>::endFunction(const uint8_t* bodyEnd) {
1193   if (d_.currentPosition() != bodyEnd) {
1194     return fail("function body length mismatch");
1195   }
1196 
1197   if (!controlStack_.empty()) {
1198     return fail("unbalanced function body control flow");
1199   }
1200   MOZ_ASSERT(elseParamStack_.empty());
1201 
1202 #ifdef DEBUG
1203   op_ = OpBytes(Op::Limit);
1204 #endif
1205   valueStack_.clear();
1206   return true;
1207 }
1208 
1209 template <typename Policy>
startInitExpr(ValType expected)1210 inline bool OpIter<Policy>::startInitExpr(ValType expected) {
1211   MOZ_ASSERT(kind_ == OpIter::InitExpr);
1212   MOZ_ASSERT(elseParamStack_.empty());
1213   MOZ_ASSERT(valueStack_.empty());
1214   MOZ_ASSERT(controlStack_.empty());
1215   MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
1216   BlockType type = BlockType::VoidToSingle(expected);
1217   return pushControl(LabelKind::Body, type);
1218 }
1219 
1220 template <typename Policy>
endInitExpr()1221 inline bool OpIter<Policy>::endInitExpr() {
1222   MOZ_ASSERT(controlStack_.empty());
1223   MOZ_ASSERT(elseParamStack_.empty());
1224 
1225 #ifdef DEBUG
1226   op_ = OpBytes(Op::Limit);
1227 #endif
1228   valueStack_.clear();
1229   return true;
1230 }
1231 
1232 template <typename Policy>
readValType(ValType * type)1233 inline bool OpIter<Policy>::readValType(ValType* type) {
1234   return d_.readValType(*env_.types, env_.features, type);
1235 }
1236 
1237 template <typename Policy>
readHeapType(bool nullable,RefType * type)1238 inline bool OpIter<Policy>::readHeapType(bool nullable, RefType* type) {
1239   return d_.readHeapType(*env_.types, env_.features, nullable, type);
1240 }
1241 
1242 template <typename Policy>
readReturn(ValueVector * values)1243 inline bool OpIter<Policy>::readReturn(ValueVector* values) {
1244   MOZ_ASSERT(Classify(op_) == OpKind::Return);
1245 
1246   Control& body = controlStack_[0];
1247   MOZ_ASSERT(body.kind() == LabelKind::Body);
1248 
1249   if (!popWithType(body.resultType(), values)) {
1250     return false;
1251   }
1252 
1253   afterUnconditionalBranch();
1254   return true;
1255 }
1256 
1257 template <typename Policy>
readBlock(ResultType * paramType)1258 inline bool OpIter<Policy>::readBlock(ResultType* paramType) {
1259   MOZ_ASSERT(Classify(op_) == OpKind::Block);
1260 
1261   BlockType type;
1262   if (!readBlockType(&type)) {
1263     return false;
1264   }
1265 
1266   *paramType = type.params();
1267   return pushControl(LabelKind::Block, type);
1268 }
1269 
1270 template <typename Policy>
readLoop(ResultType * paramType)1271 inline bool OpIter<Policy>::readLoop(ResultType* paramType) {
1272   MOZ_ASSERT(Classify(op_) == OpKind::Loop);
1273 
1274   BlockType type;
1275   if (!readBlockType(&type)) {
1276     return false;
1277   }
1278 
1279   *paramType = type.params();
1280   return pushControl(LabelKind::Loop, type);
1281 }
1282 
1283 template <typename Policy>
readIf(ResultType * paramType,Value * condition)1284 inline bool OpIter<Policy>::readIf(ResultType* paramType, Value* condition) {
1285   MOZ_ASSERT(Classify(op_) == OpKind::If);
1286 
1287   BlockType type;
1288   if (!readBlockType(&type)) {
1289     return false;
1290   }
1291 
1292   if (!popWithType(ValType::I32, condition)) {
1293     return false;
1294   }
1295 
1296   if (!pushControl(LabelKind::Then, type)) {
1297     return false;
1298   }
1299 
1300   *paramType = type.params();
1301   size_t paramsLength = type.params().length();
1302   return elseParamStack_.append(valueStack_.end() - paramsLength, paramsLength);
1303 }
1304 
1305 template <typename Policy>
readElse(ResultType * paramType,ResultType * resultType,ValueVector * thenResults)1306 inline bool OpIter<Policy>::readElse(ResultType* paramType,
1307                                      ResultType* resultType,
1308                                      ValueVector* thenResults) {
1309   MOZ_ASSERT(Classify(op_) == OpKind::Else);
1310 
1311   Control& block = controlStack_.back();
1312   if (block.kind() != LabelKind::Then) {
1313     return fail("else can only be used within an if");
1314   }
1315 
1316   *paramType = block.type().params();
1317   if (!checkStackAtEndOfBlock(resultType, thenResults)) {
1318     return false;
1319   }
1320 
1321   valueStack_.shrinkTo(block.valueStackBase());
1322 
1323   size_t nparams = block.type().params().length();
1324   MOZ_ASSERT(elseParamStack_.length() >= nparams);
1325   valueStack_.infallibleAppend(elseParamStack_.end() - nparams, nparams);
1326   elseParamStack_.shrinkBy(nparams);
1327 
1328   block.switchToElse();
1329   return true;
1330 }
1331 
1332 template <typename Policy>
readEnd(LabelKind * kind,ResultType * type,ValueVector * results,ValueVector * resultsForEmptyElse)1333 inline bool OpIter<Policy>::readEnd(LabelKind* kind, ResultType* type,
1334                                     ValueVector* results,
1335                                     ValueVector* resultsForEmptyElse) {
1336   MOZ_ASSERT(Classify(op_) == OpKind::End);
1337 
1338   Control& block = controlStack_.back();
1339 
1340   if (!checkStackAtEndOfBlock(type, results)) {
1341     return false;
1342   }
1343 
1344   if (block.kind() == LabelKind::Then) {
1345     ResultType params = block.type().params();
1346     // If an `if` block ends with `end` instead of `else`, then the `else` block
1347     // implicitly passes the `if` parameters as the `else` results.  In that
1348     // case, assert that the `if`'s param type matches the result type.
1349     if (params != block.type().results()) {
1350       return fail("if without else with a result value");
1351     }
1352 
1353     size_t nparams = params.length();
1354     MOZ_ASSERT(elseParamStack_.length() >= nparams);
1355     if (!resultsForEmptyElse->resize(nparams)) {
1356       return false;
1357     }
1358     const TypeAndValue* elseParams = elseParamStack_.end() - nparams;
1359     for (size_t i = 0; i < nparams; i++) {
1360       (*resultsForEmptyElse)[i] = elseParams[i].value();
1361     }
1362     elseParamStack_.shrinkBy(nparams);
1363   }
1364 
1365   *kind = block.kind();
1366   return true;
1367 }
1368 
1369 template <typename Policy>
popEnd()1370 inline void OpIter<Policy>::popEnd() {
1371   MOZ_ASSERT(Classify(op_) == OpKind::End);
1372 
1373   controlStack_.popBack();
1374 }
1375 
1376 template <typename Policy>
checkBranchValueAndPush(uint32_t relativeDepth,ResultType * type,ValueVector * values)1377 inline bool OpIter<Policy>::checkBranchValueAndPush(uint32_t relativeDepth,
1378                                                     ResultType* type,
1379                                                     ValueVector* values) {
1380   Control* block = nullptr;
1381   if (!getControl(relativeDepth, &block)) {
1382     return false;
1383   }
1384 
1385   *type = block->branchTargetType();
1386   return topWithTypeAndPush(*type, values);
1387 }
1388 
1389 // Check the typing of a branch instruction which casts an input type to
1390 // an output type, branching on success to a target which takes the output
1391 // type along with extra values from the stack. On casting failure, the
1392 // original input type and extra values are left on the stack.
1393 template <typename Policy>
checkCastedBranchValueAndPush(uint32_t relativeDepth,ValType castedFromType,ValType castedToType,ResultType * branchTargetType,ValueVector * values)1394 inline bool OpIter<Policy>::checkCastedBranchValueAndPush(
1395     uint32_t relativeDepth, ValType castedFromType, ValType castedToType,
1396     ResultType* branchTargetType, ValueVector* values) {
1397   // Get the branch target type, which will determine the type of extra values
1398   // that are passed along with the casted type.
1399   Control* block = nullptr;
1400   if (!getControl(relativeDepth, &block)) {
1401     return false;
1402   }
1403   *branchTargetType = block->branchTargetType();
1404 
1405   // Check we at least have one type in the branch target type, which will take
1406   // the casted type.
1407   if (branchTargetType->length() < 1) {
1408     UniqueChars expectedText = ToString(castedToType);
1409     if (!expectedText) {
1410       return false;
1411     }
1412 
1413     UniqueChars error(JS_smprintf("type mismatch: expected [_, %s], got []",
1414                                   expectedText.get()));
1415     if (!error) {
1416       return false;
1417     }
1418     return fail(error.get());
1419   }
1420 
1421   // The top of the stack is the type that is being cast. This is the last type
1422   // in the branch target type. This is guaranteed to exist by the above check.
1423   const size_t castTypeIndex = branchTargetType->length() - 1;
1424 
1425   // Check that the branch target type can accept the castedToType. The branch
1426   // target may specify a super type of the castedToType, and this is okay.
1427   if (!checkIsSubtypeOf(castedToType, (*branchTargetType)[castTypeIndex])) {
1428     return false;
1429   }
1430 
1431   // Create a copy of the branch target type, with the castTypeIndex replaced
1432   // with the castedFromType. Use this to check that the stack has the proper
1433   // types to branch to the target type.
1434   //
1435   // TODO: We could avoid a potential allocation here by handwriting a custom
1436   //       topWithTypeAndPush that handles this case.
1437   ValTypeVector stackTargetType;
1438   if (!branchTargetType->cloneToVector(&stackTargetType)) {
1439     return false;
1440   }
1441   stackTargetType[castTypeIndex] = castedFromType;
1442 
1443   return topWithTypeAndPush(ResultType::Vector(stackTargetType), values);
1444 }
1445 
1446 template <typename Policy>
readBr(uint32_t * relativeDepth,ResultType * type,ValueVector * values)1447 inline bool OpIter<Policy>::readBr(uint32_t* relativeDepth, ResultType* type,
1448                                    ValueVector* values) {
1449   MOZ_ASSERT(Classify(op_) == OpKind::Br);
1450 
1451   if (!readVarU32(relativeDepth)) {
1452     return fail("unable to read br depth");
1453   }
1454 
1455   if (!checkBranchValueAndPush(*relativeDepth, type, values)) {
1456     return false;
1457   }
1458 
1459   afterUnconditionalBranch();
1460   return true;
1461 }
1462 
1463 template <typename Policy>
readBrIf(uint32_t * relativeDepth,ResultType * type,ValueVector * values,Value * condition)1464 inline bool OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ResultType* type,
1465                                      ValueVector* values, Value* condition) {
1466   MOZ_ASSERT(Classify(op_) == OpKind::BrIf);
1467 
1468   if (!readVarU32(relativeDepth)) {
1469     return fail("unable to read br_if depth");
1470   }
1471 
1472   if (!popWithType(ValType::I32, condition)) {
1473     return false;
1474   }
1475 
1476   return checkBranchValueAndPush(*relativeDepth, type, values);
1477 }
1478 
1479 #define UNKNOWN_ARITY UINT32_MAX
1480 
1481 template <typename Policy>
checkBrTableEntryAndPush(uint32_t * relativeDepth,ResultType prevBranchType,ResultType * type,ValueVector * branchValues)1482 inline bool OpIter<Policy>::checkBrTableEntryAndPush(
1483     uint32_t* relativeDepth, ResultType prevBranchType, ResultType* type,
1484     ValueVector* branchValues) {
1485   if (!readVarU32(relativeDepth)) {
1486     return fail("unable to read br_table depth");
1487   }
1488 
1489   Control* block = nullptr;
1490   if (!getControl(*relativeDepth, &block)) {
1491     return false;
1492   }
1493 
1494   *type = block->branchTargetType();
1495 
1496   if (prevBranchType != ResultType()) {
1497     if (prevBranchType.length() != type->length()) {
1498       return fail("br_table targets must all have the same arity");
1499     }
1500 
1501     // Avoid re-collecting the same values for subsequent branch targets.
1502     branchValues = nullptr;
1503   }
1504 
1505   return topWithTypeAndPush(*type, branchValues);
1506 }
1507 
1508 template <typename Policy>
readBrTable(Uint32Vector * depths,uint32_t * defaultDepth,ResultType * defaultBranchType,ValueVector * branchValues,Value * index)1509 inline bool OpIter<Policy>::readBrTable(Uint32Vector* depths,
1510                                         uint32_t* defaultDepth,
1511                                         ResultType* defaultBranchType,
1512                                         ValueVector* branchValues,
1513                                         Value* index) {
1514   MOZ_ASSERT(Classify(op_) == OpKind::BrTable);
1515 
1516   uint32_t tableLength;
1517   if (!readVarU32(&tableLength)) {
1518     return fail("unable to read br_table table length");
1519   }
1520 
1521   if (tableLength > MaxBrTableElems) {
1522     return fail("br_table too big");
1523   }
1524 
1525   if (!popWithType(ValType::I32, index)) {
1526     return false;
1527   }
1528 
1529   if (!depths->resize(tableLength)) {
1530     return false;
1531   }
1532 
1533   ResultType prevBranchType;
1534   for (uint32_t i = 0; i < tableLength; i++) {
1535     ResultType branchType;
1536     if (!checkBrTableEntryAndPush(&(*depths)[i], prevBranchType, &branchType,
1537                                   branchValues)) {
1538       return false;
1539     }
1540     prevBranchType = branchType;
1541   }
1542 
1543   if (!checkBrTableEntryAndPush(defaultDepth, prevBranchType, defaultBranchType,
1544                                 branchValues)) {
1545     return false;
1546   }
1547 
1548   MOZ_ASSERT(*defaultBranchType != ResultType());
1549 
1550   afterUnconditionalBranch();
1551   return true;
1552 }
1553 
1554 #undef UNKNOWN_ARITY
1555 
1556 #ifdef ENABLE_WASM_EXCEPTIONS
1557 template <typename Policy>
readTry(ResultType * paramType)1558 inline bool OpIter<Policy>::readTry(ResultType* paramType) {
1559   MOZ_ASSERT(Classify(op_) == OpKind::Try);
1560 
1561   BlockType type;
1562   if (!readBlockType(&type)) {
1563     return false;
1564   }
1565 
1566   *paramType = type.params();
1567   return pushControl(LabelKind::Try, type);
1568 }
1569 
1570 template <typename Policy>
readCatch(LabelKind * kind,uint32_t * tagIndex,ResultType * paramType,ResultType * resultType,ValueVector * tryResults)1571 inline bool OpIter<Policy>::readCatch(LabelKind* kind, uint32_t* tagIndex,
1572                                       ResultType* paramType,
1573                                       ResultType* resultType,
1574                                       ValueVector* tryResults) {
1575   MOZ_ASSERT(Classify(op_) == OpKind::Catch);
1576 
1577   if (!readVarU32(tagIndex)) {
1578     return fail("expected tag index");
1579   }
1580   if (*tagIndex >= env_.tags.length()) {
1581     return fail("tag index out of range");
1582   }
1583 
1584   Control& block = controlStack_.back();
1585   if (block.kind() == LabelKind::CatchAll) {
1586     return fail("catch cannot follow a catch_all");
1587   }
1588   if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) {
1589     return fail("catch can only be used within a try-catch");
1590   }
1591   *kind = block.kind();
1592   *paramType = block.type().params();
1593 
1594   if (!checkStackAtEndOfBlock(resultType, tryResults)) {
1595     return false;
1596   }
1597 
1598   valueStack_.shrinkTo(block.valueStackBase());
1599   if (block.kind() == LabelKind::Try) {
1600     block.switchToCatch();
1601   }
1602 
1603   return push(env_.tags[*tagIndex].type->resultType());
1604 }
1605 
1606 template <typename Policy>
readCatchAll(LabelKind * kind,ResultType * paramType,ResultType * resultType,ValueVector * tryResults)1607 inline bool OpIter<Policy>::readCatchAll(LabelKind* kind, ResultType* paramType,
1608                                          ResultType* resultType,
1609                                          ValueVector* tryResults) {
1610   MOZ_ASSERT(Classify(op_) == OpKind::CatchAll);
1611 
1612   Control& block = controlStack_.back();
1613   if (block.kind() != LabelKind::Try && block.kind() != LabelKind::Catch) {
1614     return fail("catch_all can only be used within a try-catch");
1615   }
1616   *kind = block.kind();
1617   *paramType = block.type().params();
1618 
1619   if (!checkStackAtEndOfBlock(resultType, tryResults)) {
1620     return false;
1621   }
1622 
1623   valueStack_.shrinkTo(block.valueStackBase());
1624   block.switchToCatchAll();
1625 
1626   return true;
1627 }
1628 
1629 template <typename Policy>
readDelegate(uint32_t * relativeDepth,ResultType * resultType,ValueVector * tryResults)1630 inline bool OpIter<Policy>::readDelegate(uint32_t* relativeDepth,
1631                                          ResultType* resultType,
1632                                          ValueVector* tryResults) {
1633   MOZ_ASSERT(Classify(op_) == OpKind::Delegate);
1634 
1635   uint32_t originalDepth;
1636   if (!readVarU32(&originalDepth)) {
1637     return fail("unable to read delegate depth");
1638   }
1639 
1640   Control& block = controlStack_.back();
1641   if (block.kind() != LabelKind::Try) {
1642     return fail("delegate can only be used within a try");
1643   }
1644 
1645   // Depths for delegate start counting in the surrounding block.
1646   *relativeDepth = originalDepth + 1;
1647   if (*relativeDepth >= controlStack_.length()) {
1648     return fail("delegate depth exceeds current nesting level");
1649   }
1650 
1651   // Because `delegate` acts like `end` and ends the block, we will check
1652   // the stack here.
1653   return checkStackAtEndOfBlock(resultType, tryResults);
1654 }
1655 
1656 // We need popDelegate because readDelegate cannot pop the control stack
1657 // itself, as its caller may need to use the control item for delegate.
1658 template <typename Policy>
popDelegate()1659 inline void OpIter<Policy>::popDelegate() {
1660   MOZ_ASSERT(Classify(op_) == OpKind::Delegate);
1661 
1662   controlStack_.popBack();
1663 }
1664 
1665 template <typename Policy>
readThrow(uint32_t * tagIndex,ValueVector * argValues)1666 inline bool OpIter<Policy>::readThrow(uint32_t* tagIndex,
1667                                       ValueVector* argValues) {
1668   MOZ_ASSERT(Classify(op_) == OpKind::Throw);
1669 
1670   if (!readVarU32(tagIndex)) {
1671     return fail("expected tag index");
1672   }
1673   if (*tagIndex >= env_.tags.length()) {
1674     return fail("tag index out of range");
1675   }
1676 
1677   if (!popWithType(env_.tags[*tagIndex].type->resultType(), argValues)) {
1678     return false;
1679   }
1680 
1681   afterUnconditionalBranch();
1682   return true;
1683 }
1684 
1685 template <typename Policy>
readRethrow(uint32_t * relativeDepth)1686 inline bool OpIter<Policy>::readRethrow(uint32_t* relativeDepth) {
1687   MOZ_ASSERT(Classify(op_) == OpKind::Rethrow);
1688 
1689   if (!readVarU32(relativeDepth)) {
1690     return fail("unable to read rethrow depth");
1691   }
1692 
1693   if (*relativeDepth >= controlStack_.length()) {
1694     return fail("rethrow depth exceeds current nesting level");
1695   }
1696   LabelKind kind = controlKind(*relativeDepth);
1697   if (kind != LabelKind::Catch && kind != LabelKind::CatchAll) {
1698     return fail("rethrow target was not a catch block");
1699   }
1700 
1701   afterUnconditionalBranch();
1702   return true;
1703 }
1704 #endif
1705 
1706 template <typename Policy>
readUnreachable()1707 inline bool OpIter<Policy>::readUnreachable() {
1708   MOZ_ASSERT(Classify(op_) == OpKind::Unreachable);
1709 
1710   afterUnconditionalBranch();
1711   return true;
1712 }
1713 
1714 template <typename Policy>
readDrop()1715 inline bool OpIter<Policy>::readDrop() {
1716   MOZ_ASSERT(Classify(op_) == OpKind::Drop);
1717   StackType type;
1718   Value value;
1719   return popStackType(&type, &value);
1720 }
1721 
1722 template <typename Policy>
readUnary(ValType operandType,Value * input)1723 inline bool OpIter<Policy>::readUnary(ValType operandType, Value* input) {
1724   MOZ_ASSERT(Classify(op_) == OpKind::Unary);
1725 
1726   if (!popWithType(operandType, input)) {
1727     return false;
1728   }
1729 
1730   infalliblePush(operandType);
1731 
1732   return true;
1733 }
1734 
1735 template <typename Policy>
readConversion(ValType operandType,ValType resultType,Value * input)1736 inline bool OpIter<Policy>::readConversion(ValType operandType,
1737                                            ValType resultType, Value* input) {
1738   MOZ_ASSERT(Classify(op_) == OpKind::Conversion);
1739 
1740   if (!popWithType(operandType, input)) {
1741     return false;
1742   }
1743 
1744   infalliblePush(resultType);
1745 
1746   return true;
1747 }
1748 
1749 template <typename Policy>
readBinary(ValType operandType,Value * lhs,Value * rhs)1750 inline bool OpIter<Policy>::readBinary(ValType operandType, Value* lhs,
1751                                        Value* rhs) {
1752   MOZ_ASSERT(Classify(op_) == OpKind::Binary);
1753 
1754   if (!popWithType(operandType, rhs)) {
1755     return false;
1756   }
1757 
1758   if (!popWithType(operandType, lhs)) {
1759     return false;
1760   }
1761 
1762   infalliblePush(operandType);
1763 
1764   return true;
1765 }
1766 
1767 template <typename Policy>
readComparison(ValType operandType,Value * lhs,Value * rhs)1768 inline bool OpIter<Policy>::readComparison(ValType operandType, Value* lhs,
1769                                            Value* rhs) {
1770   MOZ_ASSERT(Classify(op_) == OpKind::Comparison);
1771 
1772   if (!popWithType(operandType, rhs)) {
1773     return false;
1774   }
1775 
1776   if (!popWithType(operandType, lhs)) {
1777     return false;
1778   }
1779 
1780   infalliblePush(ValType::I32);
1781 
1782   return true;
1783 }
1784 
1785 template <typename Policy>
readTernary(ValType operandType,Value * v0,Value * v1,Value * v2)1786 inline bool OpIter<Policy>::readTernary(ValType operandType, Value* v0,
1787                                         Value* v1, Value* v2) {
1788   MOZ_ASSERT(Classify(op_) == OpKind::Ternary);
1789 
1790   if (!popWithType(operandType, v2)) {
1791     return false;
1792   }
1793 
1794   if (!popWithType(operandType, v1)) {
1795     return false;
1796   }
1797 
1798   if (!popWithType(operandType, v0)) {
1799     return false;
1800   }
1801 
1802   infalliblePush(operandType);
1803 
1804   return true;
1805 }
1806 
1807 // For memories, the index is currently always a placeholder zero byte.
1808 //
1809 // For tables, the index is a placeholder zero byte until we get multi-table
1810 // with the reftypes proposal.
1811 //
1812 // The zero-ness of the value must be checked by the caller.
1813 template <typename Policy>
readMemOrTableIndex(bool isMem,uint32_t * index)1814 inline bool OpIter<Policy>::readMemOrTableIndex(bool isMem, uint32_t* index) {
1815   bool readByte = isMem;
1816   if (readByte) {
1817     uint8_t indexTmp;
1818     if (!readFixedU8(&indexTmp)) {
1819       return fail("unable to read memory or table index");
1820     }
1821     *index = indexTmp;
1822   } else {
1823     if (!readVarU32(index)) {
1824       return fail("unable to read memory or table index");
1825     }
1826   }
1827   return true;
1828 }
1829 
1830 template <typename Policy>
readLinearMemoryAddress(uint32_t byteSize,LinearMemoryAddress<Value> * addr)1831 inline bool OpIter<Policy>::readLinearMemoryAddress(
1832     uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
1833   if (!env_.usesMemory()) {
1834     return fail("can't touch memory without memory");
1835   }
1836 
1837   IndexType it = env_.memory->indexType();
1838 
1839   uint8_t alignLog2;
1840   if (!readFixedU8(&alignLog2)) {
1841     return fail("unable to read load alignment");
1842   }
1843 
1844   if (!readVarU64(&addr->offset)) {
1845     return fail("unable to read load offset");
1846   }
1847 
1848   if (it == IndexType::I32 && addr->offset > UINT32_MAX) {
1849     return fail("offset too large for memory type");
1850   }
1851 
1852   if (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize) {
1853     return fail("greater than natural alignment");
1854   }
1855 
1856   if (!popWithType(ToValType(it), &addr->base)) {
1857     return false;
1858   }
1859 
1860   addr->align = uint32_t(1) << alignLog2;
1861   return true;
1862 }
1863 
1864 template <typename Policy>
readLinearMemoryAddressAligned(uint32_t byteSize,LinearMemoryAddress<Value> * addr)1865 inline bool OpIter<Policy>::readLinearMemoryAddressAligned(
1866     uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
1867   if (!readLinearMemoryAddress(byteSize, addr)) {
1868     return false;
1869   }
1870 
1871   if (addr->align != byteSize) {
1872     return fail("not natural alignment");
1873   }
1874 
1875   return true;
1876 }
1877 
1878 template <typename Policy>
readLoad(ValType resultType,uint32_t byteSize,LinearMemoryAddress<Value> * addr)1879 inline bool OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize,
1880                                      LinearMemoryAddress<Value>* addr) {
1881   MOZ_ASSERT(Classify(op_) == OpKind::Load);
1882 
1883   if (!readLinearMemoryAddress(byteSize, addr)) {
1884     return false;
1885   }
1886 
1887   infalliblePush(resultType);
1888 
1889   return true;
1890 }
1891 
1892 template <typename Policy>
readStore(ValType resultType,uint32_t byteSize,LinearMemoryAddress<Value> * addr,Value * value)1893 inline bool OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize,
1894                                       LinearMemoryAddress<Value>* addr,
1895                                       Value* value) {
1896   MOZ_ASSERT(Classify(op_) == OpKind::Store);
1897 
1898   if (!popWithType(resultType, value)) {
1899     return false;
1900   }
1901 
1902   if (!readLinearMemoryAddress(byteSize, addr)) {
1903     return false;
1904   }
1905 
1906   return true;
1907 }
1908 
1909 template <typename Policy>
readTeeStore(ValType resultType,uint32_t byteSize,LinearMemoryAddress<Value> * addr,Value * value)1910 inline bool OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize,
1911                                          LinearMemoryAddress<Value>* addr,
1912                                          Value* value) {
1913   MOZ_ASSERT(Classify(op_) == OpKind::TeeStore);
1914 
1915   if (!popWithType(resultType, value)) {
1916     return false;
1917   }
1918 
1919   if (!readLinearMemoryAddress(byteSize, addr)) {
1920     return false;
1921   }
1922 
1923   infalliblePush(TypeAndValue(resultType, *value));
1924   return true;
1925 }
1926 
1927 template <typename Policy>
readNop()1928 inline bool OpIter<Policy>::readNop() {
1929   MOZ_ASSERT(Classify(op_) == OpKind::Nop);
1930 
1931   return true;
1932 }
1933 
1934 template <typename Policy>
readMemorySize()1935 inline bool OpIter<Policy>::readMemorySize() {
1936   MOZ_ASSERT(Classify(op_) == OpKind::MemorySize);
1937 
1938   if (!env_.usesMemory()) {
1939     return fail("can't touch memory without memory");
1940   }
1941 
1942   uint8_t flags;
1943   if (!readFixedU8(&flags)) {
1944     return fail("failed to read memory flags");
1945   }
1946 
1947   if (flags != uint8_t(0)) {
1948     return fail("unexpected flags");
1949   }
1950 
1951   ValType ptrType = ToValType(env_.memory->indexType());
1952   return push(ptrType);
1953 }
1954 
1955 template <typename Policy>
readMemoryGrow(Value * input)1956 inline bool OpIter<Policy>::readMemoryGrow(Value* input) {
1957   MOZ_ASSERT(Classify(op_) == OpKind::MemoryGrow);
1958 
1959   if (!env_.usesMemory()) {
1960     return fail("can't touch memory without memory");
1961   }
1962 
1963   uint8_t flags;
1964   if (!readFixedU8(&flags)) {
1965     return fail("failed to read memory flags");
1966   }
1967 
1968   if (flags != uint8_t(0)) {
1969     return fail("unexpected flags");
1970   }
1971 
1972   ValType ptrType = ToValType(env_.memory->indexType());
1973   if (!popWithType(ptrType, input)) {
1974     return false;
1975   }
1976 
1977   infalliblePush(ptrType);
1978 
1979   return true;
1980 }
1981 
1982 template <typename Policy>
readSelect(bool typed,StackType * type,Value * trueValue,Value * falseValue,Value * condition)1983 inline bool OpIter<Policy>::readSelect(bool typed, StackType* type,
1984                                        Value* trueValue, Value* falseValue,
1985                                        Value* condition) {
1986   MOZ_ASSERT(Classify(op_) == OpKind::Select);
1987 
1988   if (typed) {
1989     uint32_t length;
1990     if (!readVarU32(&length)) {
1991       return fail("unable to read select result length");
1992     }
1993     if (length != 1) {
1994       return fail("bad number of results");
1995     }
1996     ValType result;
1997     if (!readValType(&result)) {
1998       return fail("invalid result type for select");
1999     }
2000 
2001     if (!popWithType(ValType::I32, condition)) {
2002       return false;
2003     }
2004     if (!popWithType(result, falseValue)) {
2005       return false;
2006     }
2007     if (!popWithType(result, trueValue)) {
2008       return false;
2009     }
2010 
2011     *type = StackType(result);
2012     infalliblePush(*type);
2013     return true;
2014   }
2015 
2016   if (!popWithType(ValType::I32, condition)) {
2017     return false;
2018   }
2019 
2020   StackType falseType;
2021   if (!popStackType(&falseType, falseValue)) {
2022     return false;
2023   }
2024 
2025   StackType trueType;
2026   if (!popStackType(&trueType, trueValue)) {
2027     return false;
2028   }
2029 
2030   if (!falseType.isValidForUntypedSelect() ||
2031       !trueType.isValidForUntypedSelect()) {
2032     return fail("invalid types for untyped select");
2033   }
2034 
2035   if (falseType.isBottom()) {
2036     *type = trueType;
2037   } else if (trueType.isBottom() || falseType == trueType) {
2038     *type = falseType;
2039   } else {
2040     return fail("select operand types must match");
2041   }
2042 
2043   infalliblePush(*type);
2044   return true;
2045 }
2046 
2047 template <typename Policy>
readGetLocal(const ValTypeVector & locals,uint32_t * id)2048 inline bool OpIter<Policy>::readGetLocal(const ValTypeVector& locals,
2049                                          uint32_t* id) {
2050   MOZ_ASSERT(Classify(op_) == OpKind::GetLocal);
2051 
2052   if (!readVarU32(id)) {
2053     return fail("unable to read local index");
2054   }
2055 
2056   if (*id >= locals.length()) {
2057     return fail("local.get index out of range");
2058   }
2059 
2060   return push(locals[*id]);
2061 }
2062 
2063 template <typename Policy>
readSetLocal(const ValTypeVector & locals,uint32_t * id,Value * value)2064 inline bool OpIter<Policy>::readSetLocal(const ValTypeVector& locals,
2065                                          uint32_t* id, Value* value) {
2066   MOZ_ASSERT(Classify(op_) == OpKind::SetLocal);
2067 
2068   if (!readVarU32(id)) {
2069     return fail("unable to read local index");
2070   }
2071 
2072   if (*id >= locals.length()) {
2073     return fail("local.set index out of range");
2074   }
2075 
2076   return popWithType(locals[*id], value);
2077 }
2078 
2079 template <typename Policy>
readTeeLocal(const ValTypeVector & locals,uint32_t * id,Value * value)2080 inline bool OpIter<Policy>::readTeeLocal(const ValTypeVector& locals,
2081                                          uint32_t* id, Value* value) {
2082   MOZ_ASSERT(Classify(op_) == OpKind::TeeLocal);
2083 
2084   if (!readVarU32(id)) {
2085     return fail("unable to read local index");
2086   }
2087 
2088   if (*id >= locals.length()) {
2089     return fail("local.set index out of range");
2090   }
2091 
2092   ValueVector single;
2093   if (!popThenPushType(ResultType::Single(locals[*id]), &single)) {
2094     return false;
2095   }
2096 
2097   *value = single[0];
2098   return true;
2099 }
2100 
2101 template <typename Policy>
readGetGlobal(uint32_t * id)2102 inline bool OpIter<Policy>::readGetGlobal(uint32_t* id) {
2103   MOZ_ASSERT(Classify(op_) == OpKind::GetGlobal);
2104 
2105   if (!d_.readGlobalIndex(id)) {
2106     return false;
2107   }
2108 
2109   if (*id >= env_.globals.length()) {
2110     return fail("global.get index out of range");
2111   }
2112 
2113   if (kind_ == OpIter::InitExpr &&
2114       (!env_.globals[*id].isImport() || env_.globals[*id].isMutable())) {
2115     return fail(
2116         "global.get in initializer expression must reference a global "
2117         "immutable import");
2118   }
2119 
2120   return push(env_.globals[*id].type());
2121 }
2122 
2123 template <typename Policy>
readSetGlobal(uint32_t * id,Value * value)2124 inline bool OpIter<Policy>::readSetGlobal(uint32_t* id, Value* value) {
2125   MOZ_ASSERT(Classify(op_) == OpKind::SetGlobal);
2126 
2127   if (!d_.readGlobalIndex(id)) {
2128     return false;
2129   }
2130 
2131   if (*id >= env_.globals.length()) {
2132     return fail("global.set index out of range");
2133   }
2134 
2135   if (!env_.globals[*id].isMutable()) {
2136     return fail("can't write an immutable global");
2137   }
2138 
2139   return popWithType(env_.globals[*id].type(), value);
2140 }
2141 
2142 template <typename Policy>
readTeeGlobal(uint32_t * id,Value * value)2143 inline bool OpIter<Policy>::readTeeGlobal(uint32_t* id, Value* value) {
2144   MOZ_ASSERT(Classify(op_) == OpKind::TeeGlobal);
2145 
2146   if (!d_.readGlobalIndex(id)) {
2147     return false;
2148   }
2149 
2150   if (*id >= env_.globals.length()) {
2151     return fail("global.set index out of range");
2152   }
2153 
2154   if (!env_.globals[*id].isMutable()) {
2155     return fail("can't write an immutable global");
2156   }
2157 
2158   ValueVector single;
2159   if (!popThenPushType(ResultType::Single(env_.globals[*id].type()), &single)) {
2160     return false;
2161   }
2162 
2163   MOZ_ASSERT(single.length() == 1);
2164   *value = single[0];
2165   return true;
2166 }
2167 
2168 template <typename Policy>
readI32Const(int32_t * i32)2169 inline bool OpIter<Policy>::readI32Const(int32_t* i32) {
2170   MOZ_ASSERT(Classify(op_) == OpKind::I32);
2171 
2172   if (!d_.readI32Const(i32)) {
2173     return false;
2174   }
2175 
2176   return push(ValType::I32);
2177 }
2178 
2179 template <typename Policy>
readI64Const(int64_t * i64)2180 inline bool OpIter<Policy>::readI64Const(int64_t* i64) {
2181   MOZ_ASSERT(Classify(op_) == OpKind::I64);
2182 
2183   if (!d_.readI64Const(i64)) {
2184     return false;
2185   }
2186 
2187   return push(ValType::I64);
2188 }
2189 
2190 template <typename Policy>
readF32Const(float * f32)2191 inline bool OpIter<Policy>::readF32Const(float* f32) {
2192   MOZ_ASSERT(Classify(op_) == OpKind::F32);
2193 
2194   if (!d_.readF32Const(f32)) {
2195     return false;
2196   }
2197 
2198   return push(ValType::F32);
2199 }
2200 
2201 template <typename Policy>
readF64Const(double * f64)2202 inline bool OpIter<Policy>::readF64Const(double* f64) {
2203   MOZ_ASSERT(Classify(op_) == OpKind::F64);
2204 
2205   if (!d_.readF64Const(f64)) {
2206     return false;
2207   }
2208 
2209   return push(ValType::F64);
2210 }
2211 
2212 template <typename Policy>
readRefFunc(uint32_t * funcIndex)2213 inline bool OpIter<Policy>::readRefFunc(uint32_t* funcIndex) {
2214   MOZ_ASSERT(Classify(op_) == OpKind::RefFunc);
2215 
2216   if (!d_.readFuncIndex(funcIndex)) {
2217     return false;
2218   }
2219   if (*funcIndex >= env_.funcs.length()) {
2220     return fail("function index out of range");
2221   }
2222   if (kind_ == OpIter::Func && !env_.funcs[*funcIndex].canRefFunc()) {
2223     return fail(
2224         "function index is not declared in a section before the code section");
2225   }
2226   return push(RefType::func());
2227 }
2228 
2229 template <typename Policy>
readRefNull(RefType * type)2230 inline bool OpIter<Policy>::readRefNull(RefType* type) {
2231   MOZ_ASSERT(Classify(op_) == OpKind::RefNull);
2232 
2233   if (!d_.readRefNull(*env_.types, env_.features, type)) {
2234     return false;
2235   }
2236   return push(*type);
2237 }
2238 
2239 template <typename Policy>
readRefIsNull(Value * input)2240 inline bool OpIter<Policy>::readRefIsNull(Value* input) {
2241   MOZ_ASSERT(Classify(op_) == OpKind::Conversion);
2242 
2243   StackType type;
2244   if (!popWithRefType(input, &type)) {
2245     return false;
2246   }
2247   return push(ValType::I32);
2248 }
2249 
2250 template <typename Policy>
readRefAsNonNull(Value * input)2251 inline bool OpIter<Policy>::readRefAsNonNull(Value* input) {
2252   MOZ_ASSERT(Classify(op_) == OpKind::RefAsNonNull);
2253 
2254   StackType type;
2255   if (!popWithRefType(input, &type)) {
2256     return false;
2257   }
2258 
2259   if (type.isBottom()) {
2260     infalliblePush(type);
2261   } else {
2262     infalliblePush(type.asNonNullable());
2263   }
2264   return true;
2265 }
2266 
2267 template <typename Policy>
readBrOnNull(uint32_t * relativeDepth,ResultType * type,ValueVector * values,Value * condition)2268 inline bool OpIter<Policy>::readBrOnNull(uint32_t* relativeDepth,
2269                                          ResultType* type, ValueVector* values,
2270                                          Value* condition) {
2271   MOZ_ASSERT(Classify(op_) == OpKind::BrOnNull);
2272 
2273   if (!readVarU32(relativeDepth)) {
2274     return fail("unable to read br_on_null depth");
2275   }
2276 
2277   StackType refType;
2278   if (!popWithRefType(condition, &refType)) {
2279     return false;
2280   }
2281 
2282   if (!checkBranchValueAndPush(*relativeDepth, type, values)) {
2283     return false;
2284   }
2285 
2286   if (refType.isBottom()) {
2287     return push(refType);
2288   }
2289   return push(refType.asNonNullable());
2290 }
2291 
2292 template <typename Policy>
popCallArgs(const ValTypeVector & expectedTypes,ValueVector * values)2293 inline bool OpIter<Policy>::popCallArgs(const ValTypeVector& expectedTypes,
2294                                         ValueVector* values) {
2295   // Iterate through the argument types backward so that pops occur in the
2296   // right order.
2297 
2298   if (!values->resize(expectedTypes.length())) {
2299     return false;
2300   }
2301 
2302   for (int32_t i = expectedTypes.length() - 1; i >= 0; i--) {
2303     if (!popWithType(expectedTypes[i], &(*values)[i])) {
2304       return false;
2305     }
2306   }
2307 
2308   return true;
2309 }
2310 
2311 template <typename Policy>
readCall(uint32_t * funcTypeIndex,ValueVector * argValues)2312 inline bool OpIter<Policy>::readCall(uint32_t* funcTypeIndex,
2313                                      ValueVector* argValues) {
2314   MOZ_ASSERT(Classify(op_) == OpKind::Call);
2315 
2316   if (!readVarU32(funcTypeIndex)) {
2317     return fail("unable to read call function index");
2318   }
2319 
2320   if (*funcTypeIndex >= env_.funcs.length()) {
2321     return fail("callee index out of range");
2322   }
2323 
2324   const FuncType& funcType = *env_.funcs[*funcTypeIndex].type;
2325 
2326   if (!popCallArgs(funcType.args(), argValues)) {
2327     return false;
2328   }
2329 
2330   return push(ResultType::Vector(funcType.results()));
2331 }
2332 
2333 template <typename Policy>
readCallIndirect(uint32_t * funcTypeIndex,uint32_t * tableIndex,Value * callee,ValueVector * argValues)2334 inline bool OpIter<Policy>::readCallIndirect(uint32_t* funcTypeIndex,
2335                                              uint32_t* tableIndex,
2336                                              Value* callee,
2337                                              ValueVector* argValues) {
2338   MOZ_ASSERT(Classify(op_) == OpKind::CallIndirect);
2339   MOZ_ASSERT(funcTypeIndex != tableIndex);
2340 
2341   if (!readVarU32(funcTypeIndex)) {
2342     return fail("unable to read call_indirect signature index");
2343   }
2344 
2345   if (*funcTypeIndex >= env_.numTypes()) {
2346     return fail("signature index out of range");
2347   }
2348 
2349   if (!readVarU32(tableIndex)) {
2350     return fail("unable to read call_indirect table index");
2351   }
2352   if (*tableIndex >= env_.tables.length()) {
2353     // Special case this for improved user experience.
2354     if (!env_.tables.length()) {
2355       return fail("can't call_indirect without a table");
2356     }
2357     return fail("table index out of range for call_indirect");
2358   }
2359   if (!env_.tables[*tableIndex].elemType.isFunc()) {
2360     return fail("indirect calls must go through a table of 'funcref'");
2361   }
2362 
2363   if (!popWithType(ValType::I32, callee)) {
2364     return false;
2365   }
2366 
2367   if (!env_.types->isFuncType(*funcTypeIndex)) {
2368     return fail("expected signature type");
2369   }
2370 
2371   const FuncType& funcType = env_.types->funcType(*funcTypeIndex);
2372 
2373 #ifdef WASM_PRIVATE_REFTYPES
2374   if (env_.tables[*tableIndex].isImportedOrExported &&
2375       funcType.exposesTypeIndex()) {
2376     return fail("cannot expose indexed reference type");
2377   }
2378 #endif
2379 
2380   if (!popCallArgs(funcType.args(), argValues)) {
2381     return false;
2382   }
2383 
2384   return push(ResultType::Vector(funcType.results()));
2385 }
2386 
2387 template <typename Policy>
readOldCallDirect(uint32_t numFuncImports,uint32_t * funcTypeIndex,ValueVector * argValues)2388 inline bool OpIter<Policy>::readOldCallDirect(uint32_t numFuncImports,
2389                                               uint32_t* funcTypeIndex,
2390                                               ValueVector* argValues) {
2391   MOZ_ASSERT(Classify(op_) == OpKind::OldCallDirect);
2392 
2393   uint32_t funcDefIndex;
2394   if (!readVarU32(&funcDefIndex)) {
2395     return fail("unable to read call function index");
2396   }
2397 
2398   if (UINT32_MAX - funcDefIndex < numFuncImports) {
2399     return fail("callee index out of range");
2400   }
2401 
2402   *funcTypeIndex = numFuncImports + funcDefIndex;
2403 
2404   if (*funcTypeIndex >= env_.funcs.length()) {
2405     return fail("callee index out of range");
2406   }
2407 
2408   const FuncType& funcType = *env_.funcs[*funcTypeIndex].type;
2409 
2410   if (!popCallArgs(funcType.args(), argValues)) {
2411     return false;
2412   }
2413 
2414   return push(ResultType::Vector(funcType.results()));
2415 }
2416 
2417 template <typename Policy>
readOldCallIndirect(uint32_t * funcTypeIndex,Value * callee,ValueVector * argValues)2418 inline bool OpIter<Policy>::readOldCallIndirect(uint32_t* funcTypeIndex,
2419                                                 Value* callee,
2420                                                 ValueVector* argValues) {
2421   MOZ_ASSERT(Classify(op_) == OpKind::OldCallIndirect);
2422 
2423   if (!readVarU32(funcTypeIndex)) {
2424     return fail("unable to read call_indirect signature index");
2425   }
2426 
2427   if (*funcTypeIndex >= env_.numTypes()) {
2428     return fail("signature index out of range");
2429   }
2430 
2431   if (!env_.types->isFuncType(*funcTypeIndex)) {
2432     return fail("expected signature type");
2433   }
2434 
2435   const FuncType& funcType = env_.types->funcType(*funcTypeIndex);
2436 
2437   if (!popCallArgs(funcType.args(), argValues)) {
2438     return false;
2439   }
2440 
2441   if (!popWithType(ValType::I32, callee)) {
2442     return false;
2443   }
2444 
2445   return push(ResultType::Vector(funcType.results()));
2446 }
2447 
2448 template <typename Policy>
readWake(LinearMemoryAddress<Value> * addr,Value * count)2449 inline bool OpIter<Policy>::readWake(LinearMemoryAddress<Value>* addr,
2450                                      Value* count) {
2451   MOZ_ASSERT(Classify(op_) == OpKind::Wake);
2452 
2453   if (!popWithType(ValType::I32, count)) {
2454     return false;
2455   }
2456 
2457   uint32_t byteSize = 4;  // Per spec; smallest WAIT is i32.
2458 
2459   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2460     return false;
2461   }
2462 
2463   infalliblePush(ValType::I32);
2464   return true;
2465 }
2466 
2467 template <typename Policy>
readWait(LinearMemoryAddress<Value> * addr,ValType valueType,uint32_t byteSize,Value * value,Value * timeout)2468 inline bool OpIter<Policy>::readWait(LinearMemoryAddress<Value>* addr,
2469                                      ValType valueType, uint32_t byteSize,
2470                                      Value* value, Value* timeout) {
2471   MOZ_ASSERT(Classify(op_) == OpKind::Wait);
2472 
2473   if (!popWithType(ValType::I64, timeout)) {
2474     return false;
2475   }
2476 
2477   if (!popWithType(valueType, value)) {
2478     return false;
2479   }
2480 
2481   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2482     return false;
2483   }
2484 
2485   infalliblePush(ValType::I32);
2486   return true;
2487 }
2488 
2489 template <typename Policy>
readFence()2490 inline bool OpIter<Policy>::readFence() {
2491   MOZ_ASSERT(Classify(op_) == OpKind::Fence);
2492   uint8_t flags;
2493   if (!readFixedU8(&flags)) {
2494     return fail("expected memory order after fence");
2495   }
2496   if (flags != 0) {
2497     return fail("non-zero memory order not supported yet");
2498   }
2499   return true;
2500 }
2501 
2502 template <typename Policy>
readAtomicLoad(LinearMemoryAddress<Value> * addr,ValType resultType,uint32_t byteSize)2503 inline bool OpIter<Policy>::readAtomicLoad(LinearMemoryAddress<Value>* addr,
2504                                            ValType resultType,
2505                                            uint32_t byteSize) {
2506   MOZ_ASSERT(Classify(op_) == OpKind::AtomicLoad);
2507 
2508   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2509     return false;
2510   }
2511 
2512   infalliblePush(resultType);
2513   return true;
2514 }
2515 
2516 template <typename Policy>
readAtomicStore(LinearMemoryAddress<Value> * addr,ValType resultType,uint32_t byteSize,Value * value)2517 inline bool OpIter<Policy>::readAtomicStore(LinearMemoryAddress<Value>* addr,
2518                                             ValType resultType,
2519                                             uint32_t byteSize, Value* value) {
2520   MOZ_ASSERT(Classify(op_) == OpKind::AtomicStore);
2521 
2522   if (!popWithType(resultType, value)) {
2523     return false;
2524   }
2525 
2526   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2527     return false;
2528   }
2529 
2530   return true;
2531 }
2532 
2533 template <typename Policy>
readAtomicRMW(LinearMemoryAddress<Value> * addr,ValType resultType,uint32_t byteSize,Value * value)2534 inline bool OpIter<Policy>::readAtomicRMW(LinearMemoryAddress<Value>* addr,
2535                                           ValType resultType, uint32_t byteSize,
2536                                           Value* value) {
2537   MOZ_ASSERT(Classify(op_) == OpKind::AtomicBinOp);
2538 
2539   if (!popWithType(resultType, value)) {
2540     return false;
2541   }
2542 
2543   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2544     return false;
2545   }
2546 
2547   infalliblePush(resultType);
2548   return true;
2549 }
2550 
2551 template <typename Policy>
readAtomicCmpXchg(LinearMemoryAddress<Value> * addr,ValType resultType,uint32_t byteSize,Value * oldValue,Value * newValue)2552 inline bool OpIter<Policy>::readAtomicCmpXchg(LinearMemoryAddress<Value>* addr,
2553                                               ValType resultType,
2554                                               uint32_t byteSize,
2555                                               Value* oldValue,
2556                                               Value* newValue) {
2557   MOZ_ASSERT(Classify(op_) == OpKind::AtomicCompareExchange);
2558 
2559   if (!popWithType(resultType, newValue)) {
2560     return false;
2561   }
2562 
2563   if (!popWithType(resultType, oldValue)) {
2564     return false;
2565   }
2566 
2567   if (!readLinearMemoryAddressAligned(byteSize, addr)) {
2568     return false;
2569   }
2570 
2571   infalliblePush(resultType);
2572   return true;
2573 }
2574 
2575 template <typename Policy>
readMemOrTableCopy(bool isMem,uint32_t * dstMemOrTableIndex,Value * dst,uint32_t * srcMemOrTableIndex,Value * src,Value * len)2576 inline bool OpIter<Policy>::readMemOrTableCopy(bool isMem,
2577                                                uint32_t* dstMemOrTableIndex,
2578                                                Value* dst,
2579                                                uint32_t* srcMemOrTableIndex,
2580                                                Value* src, Value* len) {
2581   MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableCopy);
2582   MOZ_ASSERT(dstMemOrTableIndex != srcMemOrTableIndex);
2583 
2584   // Spec requires (dest, src) as of 2019-10-04.
2585   if (!readMemOrTableIndex(isMem, dstMemOrTableIndex)) {
2586     return false;
2587   }
2588   if (!readMemOrTableIndex(isMem, srcMemOrTableIndex)) {
2589     return false;
2590   }
2591 
2592   if (isMem) {
2593     if (!env_.usesMemory()) {
2594       return fail("can't touch memory without memory");
2595     }
2596     if (*srcMemOrTableIndex != 0 || *dstMemOrTableIndex != 0) {
2597       return fail("memory index out of range for memory.copy");
2598     }
2599   } else {
2600     if (*dstMemOrTableIndex >= env_.tables.length() ||
2601         *srcMemOrTableIndex >= env_.tables.length()) {
2602       return fail("table index out of range for table.copy");
2603     }
2604     ValType dstElemType = env_.tables[*dstMemOrTableIndex].elemType;
2605     ValType srcElemType = env_.tables[*srcMemOrTableIndex].elemType;
2606     if (!checkIsSubtypeOf(srcElemType, dstElemType)) {
2607       return false;
2608     }
2609   }
2610 
2611   ValType ptrType = isMem ? ToValType(env_.memory->indexType()) : ValType::I32;
2612 
2613   if (!popWithType(ptrType, len)) {
2614     return false;
2615   }
2616 
2617   if (!popWithType(ptrType, src)) {
2618     return false;
2619   }
2620 
2621   if (!popWithType(ptrType, dst)) {
2622     return false;
2623   }
2624 
2625   return true;
2626 }
2627 
2628 template <typename Policy>
readDataOrElemDrop(bool isData,uint32_t * segIndex)2629 inline bool OpIter<Policy>::readDataOrElemDrop(bool isData,
2630                                                uint32_t* segIndex) {
2631   MOZ_ASSERT(Classify(op_) == OpKind::DataOrElemDrop);
2632 
2633   if (!readVarU32(segIndex)) {
2634     return fail("unable to read segment index");
2635   }
2636 
2637   if (isData) {
2638     if (env_.dataCount.isNothing()) {
2639       return fail("data.drop requires a DataCount section");
2640     }
2641     if (*segIndex >= *env_.dataCount) {
2642       return fail("data.drop segment index out of range");
2643     }
2644   } else {
2645     if (*segIndex >= env_.elemSegments.length()) {
2646       return fail("element segment index out of range for elem.drop");
2647     }
2648   }
2649 
2650   return true;
2651 }
2652 
2653 template <typename Policy>
readMemFill(Value * start,Value * val,Value * len)2654 inline bool OpIter<Policy>::readMemFill(Value* start, Value* val, Value* len) {
2655   MOZ_ASSERT(Classify(op_) == OpKind::MemFill);
2656 
2657   if (!env_.usesMemory()) {
2658     return fail("can't touch memory without memory");
2659   }
2660 
2661   uint8_t memoryIndex;
2662   if (!readFixedU8(&memoryIndex)) {
2663     return fail("failed to read memory index");
2664   }
2665   if (!env_.usesMemory()) {
2666     return fail("can't touch memory without memory");
2667   }
2668   if (memoryIndex != 0) {
2669     return fail("memory index must be zero");
2670   }
2671 
2672   ValType ptrType = ToValType(env_.memory->indexType());
2673 
2674   if (!popWithType(ptrType, len)) {
2675     return false;
2676   }
2677 
2678   if (!popWithType(ValType::I32, val)) {
2679     return false;
2680   }
2681 
2682   if (!popWithType(ptrType, start)) {
2683     return false;
2684   }
2685 
2686   return true;
2687 }
2688 
2689 template <typename Policy>
readMemOrTableInit(bool isMem,uint32_t * segIndex,uint32_t * dstTableIndex,Value * dst,Value * src,Value * len)2690 inline bool OpIter<Policy>::readMemOrTableInit(bool isMem, uint32_t* segIndex,
2691                                                uint32_t* dstTableIndex,
2692                                                Value* dst, Value* src,
2693                                                Value* len) {
2694   MOZ_ASSERT(Classify(op_) == OpKind::MemOrTableInit);
2695   MOZ_ASSERT(segIndex != dstTableIndex);
2696 
2697   if (!readVarU32(segIndex)) {
2698     return fail("unable to read segment index");
2699   }
2700 
2701   uint32_t memOrTableIndex = 0;
2702   if (!readMemOrTableIndex(isMem, &memOrTableIndex)) {
2703     return false;
2704   }
2705 
2706   if (isMem) {
2707     if (!env_.usesMemory()) {
2708       return fail("can't touch memory without memory");
2709     }
2710     if (memOrTableIndex != 0) {
2711       return fail("memory index must be zero");
2712     }
2713     if (env_.dataCount.isNothing()) {
2714       return fail("memory.init requires a DataCount section");
2715     }
2716     if (*segIndex >= *env_.dataCount) {
2717       return fail("memory.init segment index out of range");
2718     }
2719   } else {
2720     if (memOrTableIndex >= env_.tables.length()) {
2721       return fail("table index out of range for table.init");
2722     }
2723     *dstTableIndex = memOrTableIndex;
2724 
2725     if (*segIndex >= env_.elemSegments.length()) {
2726       return fail("table.init segment index out of range");
2727     }
2728     if (!checkIsSubtypeOf(env_.elemSegments[*segIndex]->elemType,
2729                           env_.tables[*dstTableIndex].elemType)) {
2730       return false;
2731     }
2732   }
2733 
2734   if (!popWithType(ValType::I32, len)) {
2735     return false;
2736   }
2737 
2738   if (!popWithType(ValType::I32, src)) {
2739     return false;
2740   }
2741 
2742   ValType ptrType = isMem ? ToValType(env_.memory->indexType()) : ValType::I32;
2743 
2744   if (!popWithType(ptrType, dst)) {
2745     return false;
2746   }
2747 
2748   return true;
2749 }
2750 
2751 template <typename Policy>
readTableFill(uint32_t * tableIndex,Value * start,Value * val,Value * len)2752 inline bool OpIter<Policy>::readTableFill(uint32_t* tableIndex, Value* start,
2753                                           Value* val, Value* len) {
2754   MOZ_ASSERT(Classify(op_) == OpKind::TableFill);
2755 
2756   if (!readVarU32(tableIndex)) {
2757     return fail("unable to read table index");
2758   }
2759   if (*tableIndex >= env_.tables.length()) {
2760     return fail("table index out of range for table.fill");
2761   }
2762 
2763   if (!popWithType(ValType::I32, len)) {
2764     return false;
2765   }
2766   if (!popWithType(env_.tables[*tableIndex].elemType, val)) {
2767     return false;
2768   }
2769   if (!popWithType(ValType::I32, start)) {
2770     return false;
2771   }
2772 
2773   return true;
2774 }
2775 
2776 template <typename Policy>
readTableGet(uint32_t * tableIndex,Value * index)2777 inline bool OpIter<Policy>::readTableGet(uint32_t* tableIndex, Value* index) {
2778   MOZ_ASSERT(Classify(op_) == OpKind::TableGet);
2779 
2780   if (!readVarU32(tableIndex)) {
2781     return fail("unable to read table index");
2782   }
2783   if (*tableIndex >= env_.tables.length()) {
2784     return fail("table index out of range for table.get");
2785   }
2786 
2787   if (!popWithType(ValType::I32, index)) {
2788     return false;
2789   }
2790 
2791   infalliblePush(env_.tables[*tableIndex].elemType);
2792   return true;
2793 }
2794 
2795 template <typename Policy>
readTableGrow(uint32_t * tableIndex,Value * initValue,Value * delta)2796 inline bool OpIter<Policy>::readTableGrow(uint32_t* tableIndex,
2797                                           Value* initValue, Value* delta) {
2798   MOZ_ASSERT(Classify(op_) == OpKind::TableGrow);
2799 
2800   if (!readVarU32(tableIndex)) {
2801     return fail("unable to read table index");
2802   }
2803   if (*tableIndex >= env_.tables.length()) {
2804     return fail("table index out of range for table.grow");
2805   }
2806 
2807   if (!popWithType(ValType::I32, delta)) {
2808     return false;
2809   }
2810   if (!popWithType(env_.tables[*tableIndex].elemType, initValue)) {
2811     return false;
2812   }
2813 
2814   infalliblePush(ValType::I32);
2815   return true;
2816 }
2817 
2818 template <typename Policy>
readTableSet(uint32_t * tableIndex,Value * index,Value * value)2819 inline bool OpIter<Policy>::readTableSet(uint32_t* tableIndex, Value* index,
2820                                          Value* value) {
2821   MOZ_ASSERT(Classify(op_) == OpKind::TableSet);
2822 
2823   if (!readVarU32(tableIndex)) {
2824     return fail("unable to read table index");
2825   }
2826   if (*tableIndex >= env_.tables.length()) {
2827     return fail("table index out of range for table.set");
2828   }
2829 
2830   if (!popWithType(env_.tables[*tableIndex].elemType, value)) {
2831     return false;
2832   }
2833   if (!popWithType(ValType::I32, index)) {
2834     return false;
2835   }
2836 
2837   return true;
2838 }
2839 
2840 template <typename Policy>
readTableSize(uint32_t * tableIndex)2841 inline bool OpIter<Policy>::readTableSize(uint32_t* tableIndex) {
2842   MOZ_ASSERT(Classify(op_) == OpKind::TableSize);
2843 
2844   *tableIndex = 0;
2845 
2846   if (!readVarU32(tableIndex)) {
2847     return fail("unable to read table index");
2848   }
2849   if (*tableIndex >= env_.tables.length()) {
2850     return fail("table index out of range for table.size");
2851   }
2852 
2853   return push(ValType::I32);
2854 }
2855 
2856 template <typename Policy>
readGcTypeIndex(uint32_t * typeIndex)2857 inline bool OpIter<Policy>::readGcTypeIndex(uint32_t* typeIndex) {
2858   if (!d_.readTypeIndex(typeIndex)) {
2859     return false;
2860   }
2861 
2862   if (*typeIndex >= env_.types->length()) {
2863     return fail("type index out of range");
2864   }
2865 
2866   if (!env_.types->isStructType(*typeIndex) &&
2867       !env_.types->isArrayType(*typeIndex)) {
2868     return fail("not a gc type");
2869   }
2870 
2871   return true;
2872 }
2873 
2874 template <typename Policy>
readStructTypeIndex(uint32_t * typeIndex)2875 inline bool OpIter<Policy>::readStructTypeIndex(uint32_t* typeIndex) {
2876   if (!readVarU32(typeIndex)) {
2877     return fail("unable to read type index");
2878   }
2879 
2880   if (*typeIndex >= env_.types->length()) {
2881     return fail("type index out of range");
2882   }
2883 
2884   if (!env_.types->isStructType(*typeIndex)) {
2885     return fail("not a struct type");
2886   }
2887 
2888   return true;
2889 }
2890 
2891 template <typename Policy>
readArrayTypeIndex(uint32_t * typeIndex)2892 inline bool OpIter<Policy>::readArrayTypeIndex(uint32_t* typeIndex) {
2893   if (!readVarU32(typeIndex)) {
2894     return fail("unable to read type index");
2895   }
2896 
2897   if (*typeIndex >= env_.types->length()) {
2898     return fail("type index out of range");
2899   }
2900 
2901   if (!env_.types->isArrayType(*typeIndex)) {
2902     return fail("not an array type");
2903   }
2904 
2905   return true;
2906 }
2907 
2908 template <typename Policy>
readFieldIndex(uint32_t * fieldIndex,const StructType & structType)2909 inline bool OpIter<Policy>::readFieldIndex(uint32_t* fieldIndex,
2910                                            const StructType& structType) {
2911   if (!readVarU32(fieldIndex)) {
2912     return fail("unable to read field index");
2913   }
2914 
2915   if (structType.fields_.length() <= *fieldIndex) {
2916     return fail("field index out of range");
2917   }
2918 
2919   return true;
2920 }
2921 
2922 #ifdef ENABLE_WASM_GC
2923 
2924 template <typename Policy>
readStructNewWithRtt(uint32_t * typeIndex,Value * rtt,ValueVector * argValues)2925 inline bool OpIter<Policy>::readStructNewWithRtt(uint32_t* typeIndex,
2926                                                  Value* rtt,
2927                                                  ValueVector* argValues) {
2928   MOZ_ASSERT(Classify(op_) == OpKind::StructNewWithRtt);
2929 
2930   if (!readStructTypeIndex(typeIndex)) {
2931     return false;
2932   }
2933 
2934   const StructType& str = env_.types->structType(*typeIndex);
2935   const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
2936 
2937   if (!popWithType(rttType, rtt)) {
2938     return false;
2939   }
2940 
2941   if (!argValues->resize(str.fields_.length())) {
2942     return false;
2943   }
2944 
2945   static_assert(MaxStructFields <= INT32_MAX, "Or we iloop below");
2946 
2947   for (int32_t i = str.fields_.length() - 1; i >= 0; i--) {
2948     if (!popWithType(str.fields_[i].type.widenToValType(), &(*argValues)[i])) {
2949       return false;
2950     }
2951   }
2952 
2953   return push(RefType::fromTypeIndex(*typeIndex, false));
2954 }
2955 
2956 template <typename Policy>
readStructNewDefaultWithRtt(uint32_t * typeIndex,Value * rtt)2957 inline bool OpIter<Policy>::readStructNewDefaultWithRtt(uint32_t* typeIndex,
2958                                                         Value* rtt) {
2959   MOZ_ASSERT(Classify(op_) == OpKind::StructNewDefaultWithRtt);
2960 
2961   if (!readStructTypeIndex(typeIndex)) {
2962     return false;
2963   }
2964 
2965   const StructType& str = env_.types->structType(*typeIndex);
2966   const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
2967 
2968   if (!popWithType(rttType, rtt)) {
2969     return false;
2970   }
2971 
2972   if (!str.isDefaultable()) {
2973     return fail("struct must be defaultable");
2974   }
2975 
2976   return push(RefType::fromTypeIndex(*typeIndex, false));
2977 }
2978 
2979 template <typename Policy>
readStructGet(uint32_t * typeIndex,uint32_t * fieldIndex,FieldExtension fieldExtension,Value * ptr)2980 inline bool OpIter<Policy>::readStructGet(uint32_t* typeIndex,
2981                                           uint32_t* fieldIndex,
2982                                           FieldExtension fieldExtension,
2983                                           Value* ptr) {
2984   MOZ_ASSERT(typeIndex != fieldIndex);
2985   MOZ_ASSERT(Classify(op_) == OpKind::StructGet);
2986 
2987   if (!readStructTypeIndex(typeIndex)) {
2988     return false;
2989   }
2990 
2991   const StructType& structType = env_.types->structType(*typeIndex);
2992 
2993   if (!readFieldIndex(fieldIndex, structType)) {
2994     return false;
2995   }
2996 
2997   if (!popWithType(RefType::fromTypeIndex(*typeIndex, true), ptr)) {
2998     return false;
2999   }
3000 
3001   FieldType fieldType = structType.fields_[*fieldIndex].type;
3002 
3003   if (fieldType.isValType() && fieldExtension != FieldExtension::None) {
3004     return fail("must not specify signedness for unpacked field type");
3005   }
3006 
3007   if (!fieldType.isValType() && fieldExtension == FieldExtension::None) {
3008     return fail("must specify signedness for packed field type");
3009   }
3010 
3011   return push(fieldType.widenToValType());
3012 }
3013 
3014 template <typename Policy>
readStructSet(uint32_t * typeIndex,uint32_t * fieldIndex,Value * ptr,Value * val)3015 inline bool OpIter<Policy>::readStructSet(uint32_t* typeIndex,
3016                                           uint32_t* fieldIndex, Value* ptr,
3017                                           Value* val) {
3018   MOZ_ASSERT(typeIndex != fieldIndex);
3019   MOZ_ASSERT(Classify(op_) == OpKind::StructSet);
3020 
3021   if (!readStructTypeIndex(typeIndex)) {
3022     return false;
3023   }
3024 
3025   const StructType& structType = env_.types->structType(*typeIndex);
3026 
3027   if (!readFieldIndex(fieldIndex, structType)) {
3028     return false;
3029   }
3030 
3031   if (!popWithType(structType.fields_[*fieldIndex].type.widenToValType(),
3032                    val)) {
3033     return false;
3034   }
3035 
3036   if (!structType.fields_[*fieldIndex].isMutable) {
3037     return fail("field is not mutable");
3038   }
3039 
3040   if (!popWithType(RefType::fromTypeIndex(*typeIndex, true), ptr)) {
3041     return false;
3042   }
3043 
3044   return true;
3045 }
3046 
3047 template <typename Policy>
readArrayNewWithRtt(uint32_t * typeIndex,Value * rtt,Value * length,Value * argValue)3048 inline bool OpIter<Policy>::readArrayNewWithRtt(uint32_t* typeIndex, Value* rtt,
3049                                                 Value* length,
3050                                                 Value* argValue) {
3051   MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewWithRtt);
3052 
3053   if (!readArrayTypeIndex(typeIndex)) {
3054     return false;
3055   }
3056 
3057   const ArrayType& arr = env_.types->arrayType(*typeIndex);
3058   const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
3059 
3060   if (!popWithType(rttType, rtt)) {
3061     return false;
3062   }
3063 
3064   if (!popWithType(ValType::I32, length)) {
3065     return false;
3066   }
3067 
3068   if (!popWithType(arr.elementType_.widenToValType(), argValue)) {
3069     return false;
3070   }
3071 
3072   return push(RefType::fromTypeIndex(*typeIndex, false));
3073 }
3074 
3075 template <typename Policy>
readArrayNewDefaultWithRtt(uint32_t * typeIndex,Value * rtt,Value * length)3076 inline bool OpIter<Policy>::readArrayNewDefaultWithRtt(uint32_t* typeIndex,
3077                                                        Value* rtt,
3078                                                        Value* length) {
3079   MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewDefaultWithRtt);
3080 
3081   if (!readArrayTypeIndex(typeIndex)) {
3082     return false;
3083   }
3084 
3085   const ArrayType& arr = env_.types->arrayType(*typeIndex);
3086   const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
3087 
3088   if (!popWithType(rttType, rtt)) {
3089     return false;
3090   }
3091 
3092   if (!popWithType(ValType::I32, length)) {
3093     return false;
3094   }
3095 
3096   if (!arr.elementType_.isDefaultable()) {
3097     return fail("array must be defaultable");
3098   }
3099 
3100   return push(RefType::fromTypeIndex(*typeIndex, false));
3101 }
3102 
3103 template <typename Policy>
readArrayGet(uint32_t * typeIndex,FieldExtension extension,Value * index,Value * ptr)3104 inline bool OpIter<Policy>::readArrayGet(uint32_t* typeIndex,
3105                                          FieldExtension extension, Value* index,
3106                                          Value* ptr) {
3107   MOZ_ASSERT(Classify(op_) == OpKind::ArrayGet);
3108 
3109   if (!readArrayTypeIndex(typeIndex)) {
3110     return false;
3111   }
3112 
3113   const ArrayType& arrayType = env_.types->arrayType(*typeIndex);
3114 
3115   if (!popWithType(ValType::I32, index)) {
3116     return false;
3117   }
3118 
3119   if (!popWithType(RefType::fromTypeIndex(*typeIndex, true), ptr)) {
3120     return false;
3121   }
3122 
3123   FieldType fieldType = arrayType.elementType_;
3124 
3125   if (fieldType.isValType() && extension != FieldExtension::None) {
3126     return fail("must not specify signedness for unpacked element type");
3127   }
3128 
3129   if (!fieldType.isValType() && extension == FieldExtension::None) {
3130     return fail("must specify signedness for packed element type");
3131   }
3132 
3133   return push(fieldType.widenToValType());
3134 }
3135 
3136 template <typename Policy>
readArraySet(uint32_t * typeIndex,Value * val,Value * index,Value * ptr)3137 inline bool OpIter<Policy>::readArraySet(uint32_t* typeIndex, Value* val,
3138                                          Value* index, Value* ptr) {
3139   MOZ_ASSERT(Classify(op_) == OpKind::ArraySet);
3140 
3141   if (!readArrayTypeIndex(typeIndex)) {
3142     return false;
3143   }
3144 
3145   const ArrayType& arrayType = env_.types->arrayType(*typeIndex);
3146 
3147   if (!arrayType.isMutable_) {
3148     return fail("array is not mutable");
3149   }
3150 
3151   if (!popWithType(arrayType.elementType_.widenToValType(), val)) {
3152     return false;
3153   }
3154 
3155   if (!popWithType(ValType::I32, index)) {
3156     return false;
3157   }
3158 
3159   if (!popWithType(RefType::fromTypeIndex(*typeIndex, true), ptr)) {
3160     return false;
3161   }
3162 
3163   return true;
3164 }
3165 
3166 template <typename Policy>
readArrayLen(uint32_t * typeIndex,Value * ptr)3167 inline bool OpIter<Policy>::readArrayLen(uint32_t* typeIndex, Value* ptr) {
3168   MOZ_ASSERT(Classify(op_) == OpKind::ArrayLen);
3169 
3170   if (!readArrayTypeIndex(typeIndex)) {
3171     return false;
3172   }
3173 
3174   if (!popWithType(RefType::fromTypeIndex(*typeIndex, true), ptr)) {
3175     return false;
3176   }
3177 
3178   return push(ValType::I32);
3179 }
3180 
3181 template <typename Policy>
readRttCanon(ValType * rttType)3182 inline bool OpIter<Policy>::readRttCanon(ValType* rttType) {
3183   MOZ_ASSERT(Classify(op_) == OpKind::RttCanon);
3184 
3185   uint32_t typeIndex;
3186   if (!readGcTypeIndex(&typeIndex)) {
3187     return false;
3188   }
3189 
3190   *rttType = ValType::fromRtt(typeIndex, 0);
3191   return push(*rttType);
3192 }
3193 
3194 template <typename Policy>
readRttSub(Value * parentRtt,uint32_t * rttSubTypeIndex)3195 inline bool OpIter<Policy>::readRttSub(Value* parentRtt,
3196                                        uint32_t* rttSubTypeIndex) {
3197   MOZ_ASSERT(Classify(op_) == OpKind::RttSub);
3198 
3199   if (!readGcTypeIndex(rttSubTypeIndex)) {
3200     return false;
3201   }
3202 
3203   uint32_t rttParentTypeIndex;
3204   uint32_t rttParentDepth;
3205   if (!popWithRttType(parentRtt, &rttParentTypeIndex, &rttParentDepth)) {
3206     return false;
3207   }
3208 
3209   if (!checkIsSubtypeOf(*rttSubTypeIndex, rttParentTypeIndex)) {
3210     return false;
3211   }
3212 
3213   uint32_t subRttDepth;
3214   if (rttParentDepth == RttDepthNone) {
3215     subRttDepth = RttDepthNone;
3216   } else {
3217     if (rttParentDepth >= MaxRttDepth) {
3218       return fail("rtt depth is too deep");
3219     }
3220     subRttDepth = rttParentDepth + 1;
3221   }
3222   return push(ValType::fromRtt(*rttSubTypeIndex, subRttDepth));
3223 }
3224 
3225 template <typename Policy>
readRefTest(Value * rtt,uint32_t * rttTypeIndex,uint32_t * rttDepth,Value * ref)3226 inline bool OpIter<Policy>::readRefTest(Value* rtt, uint32_t* rttTypeIndex,
3227                                         uint32_t* rttDepth, Value* ref) {
3228   MOZ_ASSERT(Classify(op_) == OpKind::RefTest);
3229 
3230   if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
3231     return false;
3232   }
3233   if (!popWithType(RefType::eq(), ref)) {
3234     return false;
3235   }
3236   return push(ValType(ValType::I32));
3237 }
3238 
3239 template <typename Policy>
readRefCast(Value * rtt,uint32_t * rttTypeIndex,uint32_t * rttDepth,Value * ref)3240 inline bool OpIter<Policy>::readRefCast(Value* rtt, uint32_t* rttTypeIndex,
3241                                         uint32_t* rttDepth, Value* ref) {
3242   MOZ_ASSERT(Classify(op_) == OpKind::RefCast);
3243 
3244   if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
3245     return false;
3246   }
3247   if (!popWithType(RefType::eq(), ref)) {
3248     return false;
3249   }
3250   return push(RefType::fromTypeIndex(*rttTypeIndex, false));
3251 }
3252 
3253 template <typename Policy>
readBrOnCast(uint32_t * relativeDepth,Value * rtt,uint32_t * rttTypeIndex,uint32_t * rttDepth,ResultType * branchTargetType,ValueVector * values)3254 inline bool OpIter<Policy>::readBrOnCast(uint32_t* relativeDepth, Value* rtt,
3255                                          uint32_t* rttTypeIndex,
3256                                          uint32_t* rttDepth,
3257                                          ResultType* branchTargetType,
3258                                          ValueVector* values) {
3259   MOZ_ASSERT(Classify(op_) == OpKind::BrOnCast);
3260 
3261   if (!readVarU32(relativeDepth)) {
3262     return fail("unable to read br_on_cast depth");
3263   }
3264 
3265   if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
3266     return false;
3267   }
3268 
3269   // The casted from type is any subtype of eqref
3270   ValType castedFromType(RefType::eq());
3271 
3272   // The casted to type is a non-nullable reference to the type index specified
3273   // by the input rtt on the stack
3274   ValType castedToType(RefType::fromTypeIndex(*rttTypeIndex, false));
3275 
3276   return checkCastedBranchValueAndPush(*relativeDepth, castedFromType,
3277                                        castedToType, branchTargetType, values);
3278 }
3279 
3280 #endif  // ENABLE_WASM_GC
3281 
3282 #ifdef ENABLE_WASM_SIMD
3283 
3284 template <typename Policy>
readLaneIndex(uint32_t inputLanes,uint32_t * laneIndex)3285 inline bool OpIter<Policy>::readLaneIndex(uint32_t inputLanes,
3286                                           uint32_t* laneIndex) {
3287   uint8_t tmp;
3288   if (!readFixedU8(&tmp)) {
3289     return false;  // Caller signals error
3290   }
3291   if (tmp >= inputLanes) {
3292     return false;
3293   }
3294   *laneIndex = tmp;
3295   return true;
3296 }
3297 
3298 template <typename Policy>
readExtractLane(ValType resultType,uint32_t inputLanes,uint32_t * laneIndex,Value * input)3299 inline bool OpIter<Policy>::readExtractLane(ValType resultType,
3300                                             uint32_t inputLanes,
3301                                             uint32_t* laneIndex, Value* input) {
3302   MOZ_ASSERT(Classify(op_) == OpKind::ExtractLane);
3303 
3304   if (!readLaneIndex(inputLanes, laneIndex)) {
3305     return fail("missing or invalid extract_lane lane index");
3306   }
3307 
3308   if (!popWithType(ValType::V128, input)) {
3309     return false;
3310   }
3311 
3312   infalliblePush(resultType);
3313 
3314   return true;
3315 }
3316 
3317 template <typename Policy>
readReplaceLane(ValType operandType,uint32_t inputLanes,uint32_t * laneIndex,Value * baseValue,Value * operand)3318 inline bool OpIter<Policy>::readReplaceLane(ValType operandType,
3319                                             uint32_t inputLanes,
3320                                             uint32_t* laneIndex,
3321                                             Value* baseValue, Value* operand) {
3322   MOZ_ASSERT(Classify(op_) == OpKind::ReplaceLane);
3323 
3324   if (!readLaneIndex(inputLanes, laneIndex)) {
3325     return fail("missing or invalid replace_lane lane index");
3326   }
3327 
3328   if (!popWithType(operandType, operand)) {
3329     return false;
3330   }
3331 
3332   if (!popWithType(ValType::V128, baseValue)) {
3333     return false;
3334   }
3335 
3336   infalliblePush(ValType::V128);
3337 
3338   return true;
3339 }
3340 
3341 template <typename Policy>
readVectorShift(Value * baseValue,Value * shift)3342 inline bool OpIter<Policy>::readVectorShift(Value* baseValue, Value* shift) {
3343   MOZ_ASSERT(Classify(op_) == OpKind::VectorShift);
3344 
3345   if (!popWithType(ValType::I32, shift)) {
3346     return false;
3347   }
3348 
3349   if (!popWithType(ValType::V128, baseValue)) {
3350     return false;
3351   }
3352 
3353   infalliblePush(ValType::V128);
3354 
3355   return true;
3356 }
3357 
3358 template <typename Policy>
readVectorShuffle(Value * v1,Value * v2,V128 * selectMask)3359 inline bool OpIter<Policy>::readVectorShuffle(Value* v1, Value* v2,
3360                                               V128* selectMask) {
3361   MOZ_ASSERT(Classify(op_) == OpKind::VectorShuffle);
3362 
3363   for (unsigned char& byte : selectMask->bytes) {
3364     uint8_t tmp;
3365     if (!readFixedU8(&tmp)) {
3366       return fail("unable to read shuffle index");
3367     }
3368     if (tmp > 31) {
3369       return fail("shuffle index out of range");
3370     }
3371     byte = tmp;
3372   }
3373 
3374   if (!popWithType(ValType::V128, v2)) {
3375     return false;
3376   }
3377 
3378   if (!popWithType(ValType::V128, v1)) {
3379     return false;
3380   }
3381 
3382   infalliblePush(ValType::V128);
3383 
3384   return true;
3385 }
3386 
3387 template <typename Policy>
readV128Const(V128 * value)3388 inline bool OpIter<Policy>::readV128Const(V128* value) {
3389   MOZ_ASSERT(Classify(op_) == OpKind::V128);
3390 
3391   if (!d_.readV128Const(value)) {
3392     return false;
3393   }
3394 
3395   return push(ValType::V128);
3396 }
3397 
3398 template <typename Policy>
readLoadSplat(uint32_t byteSize,LinearMemoryAddress<Value> * addr)3399 inline bool OpIter<Policy>::readLoadSplat(uint32_t byteSize,
3400                                           LinearMemoryAddress<Value>* addr) {
3401   MOZ_ASSERT(Classify(op_) == OpKind::Load);
3402 
3403   if (!readLinearMemoryAddress(byteSize, addr)) {
3404     return false;
3405   }
3406 
3407   infalliblePush(ValType::V128);
3408 
3409   return true;
3410 }
3411 
3412 template <typename Policy>
readLoadExtend(LinearMemoryAddress<Value> * addr)3413 inline bool OpIter<Policy>::readLoadExtend(LinearMemoryAddress<Value>* addr) {
3414   MOZ_ASSERT(Classify(op_) == OpKind::Load);
3415 
3416   if (!readLinearMemoryAddress(/*byteSize=*/8, addr)) {
3417     return false;
3418   }
3419 
3420   infalliblePush(ValType::V128);
3421 
3422   return true;
3423 }
3424 
3425 template <typename Policy>
readLoadLane(uint32_t byteSize,LinearMemoryAddress<Value> * addr,uint32_t * laneIndex,Value * input)3426 inline bool OpIter<Policy>::readLoadLane(uint32_t byteSize,
3427                                          LinearMemoryAddress<Value>* addr,
3428                                          uint32_t* laneIndex, Value* input) {
3429   MOZ_ASSERT(Classify(op_) == OpKind::LoadLane);
3430 
3431   if (!popWithType(ValType::V128, input)) {
3432     return false;
3433   }
3434 
3435   if (!readLinearMemoryAddress(byteSize, addr)) {
3436     return false;
3437   }
3438 
3439   uint32_t inputLanes = 16 / byteSize;
3440   if (!readLaneIndex(inputLanes, laneIndex)) {
3441     return fail("missing or invalid load_lane lane index");
3442   }
3443 
3444   infalliblePush(ValType::V128);
3445 
3446   return true;
3447 }
3448 
3449 template <typename Policy>
readStoreLane(uint32_t byteSize,LinearMemoryAddress<Value> * addr,uint32_t * laneIndex,Value * input)3450 inline bool OpIter<Policy>::readStoreLane(uint32_t byteSize,
3451                                           LinearMemoryAddress<Value>* addr,
3452                                           uint32_t* laneIndex, Value* input) {
3453   MOZ_ASSERT(Classify(op_) == OpKind::StoreLane);
3454 
3455   if (!popWithType(ValType::V128, input)) {
3456     return false;
3457   }
3458 
3459   if (!readLinearMemoryAddress(byteSize, addr)) {
3460     return false;
3461   }
3462 
3463   uint32_t inputLanes = 16 / byteSize;
3464   if (!readLaneIndex(inputLanes, laneIndex)) {
3465     return fail("missing or invalid store_lane lane index");
3466   }
3467 
3468   return true;
3469 }
3470 
3471 #endif  // ENABLE_WASM_SIMD
3472 
3473 template <typename Policy>
readIntrinsic(const Intrinsic ** intrinsic,ValueVector * params)3474 inline bool OpIter<Policy>::readIntrinsic(const Intrinsic** intrinsic,
3475                                           ValueVector* params) {
3476   MOZ_ASSERT(Classify(op_) == OpKind::Intrinsic);
3477 
3478   uint32_t id;
3479   if (!d_.readVarU32(&id)) {
3480     return false;
3481   }
3482 
3483   if (id >= uint32_t(IntrinsicId::Limit)) {
3484     return fail("intrinsic index out of range");
3485   }
3486 
3487   *intrinsic = &Intrinsic::getFromId(IntrinsicId(id));
3488 
3489   if (!env_.usesMemory()) {
3490     return fail("can't touch memory without memory");
3491   }
3492   return popWithTypes((*intrinsic)->params, params);
3493 }
3494 
3495 }  // namespace wasm
3496 }  // namespace js
3497 
3498 namespace mozilla {
3499 
3500 // Specialize IsPod for the Nothing specializations.
3501 template <>
3502 struct IsPod<js::wasm::TypeAndValueT<Nothing>> : std::true_type {};
3503 template <>
3504 struct IsPod<js::wasm::ControlStackEntry<Nothing>> : std::true_type {};
3505 
3506 }  // namespace mozilla
3507 
3508 #endif  // wasm_op_iter_h
3509