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