wasmparser_nostd/validator/
operators.rs

1/* Copyright 2019 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16// The basic validation algorithm here is copied from the "Validation
17// Algorithm" section of the WebAssembly specification -
18// https://webassembly.github.io/spec/core/appendix/algorithm.html.
19//
20// That algorithm is followed pretty closely here, namely `push_operand`,
21// `pop_operand`, `push_ctrl`, and `pop_ctrl`. If anything here is a bit
22// confusing it's recommended to read over that section to see how it maps to
23// the various methods here.
24
25use crate::{
26    limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, Ieee32, Ieee64,
27    MemArg, Result, ValType, VisitOperator, WasmFeatures, WasmFuncType, WasmModuleResources, V128,
28};
29use ::alloc::vec::Vec;
30use ::core::ops::{Deref, DerefMut};
31
32pub(crate) struct OperatorValidator {
33    pub(super) locals: Locals,
34
35    // This is a list of flags for wasm features which are used to gate various
36    // instructions.
37    pub(crate) features: WasmFeatures,
38
39    // Temporary storage used during the validation of `br_table`.
40    br_table_tmp: Vec<Option<ValType>>,
41
42    /// The `control` list is the list of blocks that we're currently in.
43    control: Vec<Frame>,
44    /// The `operands` is the current type stack.
45    operands: Vec<Option<ValType>>,
46
47    /// Offset of the `end` instruction which emptied the `control` stack, which
48    /// must be the end of the function.
49    end_which_emptied_control: Option<usize>,
50}
51
52// No science was performed in the creation of this number, feel free to change
53// it if you so like.
54const MAX_LOCALS_TO_TRACK: usize = 50;
55
56pub(super) struct Locals {
57    // Total number of locals in the function.
58    num_locals: u32,
59
60    // The first MAX_LOCALS_TO_TRACK locals in a function. This is used to
61    // optimize the theoretically common case where most functions don't have
62    // many locals and don't need a full binary search in the entire local space
63    // below.
64    first: Vec<ValType>,
65
66    // This is a "compressed" list of locals for this function. The list of
67    // locals are represented as a list of tuples. The second element is the
68    // type of the local, and the first element is monotonically increasing as
69    // you visit elements of this list. The first element is the maximum index
70    // of the local, after the previous index, of the type specified.
71    //
72    // This allows us to do a binary search on the list for a local's index for
73    // `local.{get,set,tee}`. We do a binary search for the index desired, and
74    // it either lies in a "hole" where the maximum index is specified later,
75    // or it's at the end of the list meaning it's out of bounds.
76    all: Vec<(u32, ValType)>,
77}
78
79/// A Wasm control flow block on the control flow stack during Wasm validation.
80//
81// # Dev. Note
82//
83// This structure corresponds to `ctrl_frame` as specified at in the validation
84// appendix of the wasm spec
85#[derive(Debug, Copy, Clone)]
86pub struct Frame {
87    /// Indicator for what kind of instruction pushed this frame.
88    pub kind: FrameKind,
89    /// The type signature of this frame, represented as a singular return type
90    /// or a type index pointing into the module's types.
91    pub block_type: BlockType,
92    /// The index, below which, this frame cannot modify the operand stack.
93    pub height: usize,
94    /// Whether this frame is unreachable so far.
95    pub unreachable: bool,
96}
97
98/// The kind of a control flow [`Frame`].
99#[derive(Copy, Clone, Debug, PartialEq, Eq)]
100pub enum FrameKind {
101    /// A Wasm `block` control block.
102    Block,
103    /// A Wasm `if` control block.
104    If,
105    /// A Wasm `else` control block.
106    Else,
107    /// A Wasm `loop` control block.
108    Loop,
109    /// A Wasm `try` control block.
110    ///
111    /// # Note
112    ///
113    /// This belongs to the Wasm exception handling proposal.
114    Try,
115    /// A Wasm `catch` control block.
116    ///
117    /// # Note
118    ///
119    /// This belongs to the Wasm exception handling proposal.
120    Catch,
121    /// A Wasm `catch_all` control block.
122    ///
123    /// # Note
124    ///
125    /// This belongs to the Wasm exception handling proposal.
126    CatchAll,
127}
128
129struct OperatorValidatorTemp<'validator, 'resources, T> {
130    offset: usize,
131    inner: &'validator mut OperatorValidator,
132    resources: &'resources T,
133}
134
135#[derive(Default)]
136pub struct OperatorValidatorAllocations {
137    br_table_tmp: Vec<Option<ValType>>,
138    control: Vec<Frame>,
139    operands: Vec<Option<ValType>>,
140    locals_first: Vec<ValType>,
141    locals_all: Vec<(u32, ValType)>,
142}
143
144impl OperatorValidator {
145    fn new(features: &WasmFeatures, allocs: OperatorValidatorAllocations) -> Self {
146        let OperatorValidatorAllocations {
147            br_table_tmp,
148            control,
149            operands,
150            locals_first,
151            locals_all,
152        } = allocs;
153        debug_assert!(br_table_tmp.is_empty());
154        debug_assert!(control.is_empty());
155        debug_assert!(operands.is_empty());
156        debug_assert!(locals_first.is_empty());
157        debug_assert!(locals_all.is_empty());
158        OperatorValidator {
159            locals: Locals {
160                num_locals: 0,
161                first: locals_first,
162                all: locals_all,
163            },
164            features: *features,
165            br_table_tmp,
166            operands,
167            control,
168            end_which_emptied_control: None,
169        }
170    }
171
172    /// Creates a new operator validator which will be used to validate a
173    /// function whose type is the `ty` index specified.
174    ///
175    /// The `resources` are used to learn about the function type underlying
176    /// `ty`.
177    pub fn new_func<T>(
178        ty: u32,
179        offset: usize,
180        features: &WasmFeatures,
181        resources: &T,
182        allocs: OperatorValidatorAllocations,
183    ) -> Result<Self>
184    where
185        T: WasmModuleResources,
186    {
187        let mut ret = OperatorValidator::new(features, allocs);
188        ret.control.push(Frame {
189            kind: FrameKind::Block,
190            block_type: BlockType::FuncType(ty),
191            height: 0,
192            unreachable: false,
193        });
194        let params = OperatorValidatorTemp {
195            // This offset is used by the `func_type_at` and `inputs`.
196            offset,
197            inner: &mut ret,
198            resources,
199        }
200        .func_type_at(ty)?
201        .inputs();
202        for ty in params {
203            ret.locals.define(1, ty);
204        }
205        Ok(ret)
206    }
207
208    /// Creates a new operator validator which will be used to validate an
209    /// `init_expr` constant expression which should result in the `ty`
210    /// specified.
211    pub fn new_const_expr(
212        features: &WasmFeatures,
213        ty: ValType,
214        allocs: OperatorValidatorAllocations,
215    ) -> Self {
216        let mut ret = OperatorValidator::new(features, allocs);
217        ret.control.push(Frame {
218            kind: FrameKind::Block,
219            block_type: BlockType::Type(ty),
220            height: 0,
221            unreachable: false,
222        });
223        ret
224    }
225
226    pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> {
227        self.features
228            .check_value_type(ty)
229            .map_err(|e| BinaryReaderError::new(e, offset))?;
230        if count == 0 {
231            return Ok(());
232        }
233        if !self.locals.define(count, ty) {
234            return Err(BinaryReaderError::new(
235                "too many locals: locals exceed maximum",
236                offset,
237            ));
238        }
239        Ok(())
240    }
241
242    /// Returns the current operands stack height.
243    pub fn operand_stack_height(&self) -> usize {
244        self.operands.len()
245    }
246
247    /// Returns the optional value type of the value operand at the given
248    /// `depth` from the top of the operand stack.
249    ///
250    /// - Returns `None` if the `depth` is out of bounds.
251    /// - Returns `Some(None)` if there is a value with unknown type
252    /// at the given `depth`.
253    ///
254    /// # Note
255    ///
256    /// A `depth` of 0 will refer to the last operand on the stack.
257    pub fn peek_operand_at(&self, depth: usize) -> Option<Option<ValType>> {
258        self.operands.iter().rev().nth(depth).copied()
259    }
260
261    /// Returns the number of frames on the control flow stack.
262    pub fn control_stack_height(&self) -> usize {
263        self.control.len()
264    }
265
266    pub fn get_frame(&self, depth: usize) -> Option<&Frame> {
267        self.control.iter().rev().nth(depth)
268    }
269
270    /// Create a temporary [`OperatorValidatorTemp`] for validation.
271    pub fn with_resources<'a, 'validator, 'resources, T>(
272        &'validator mut self,
273        resources: &'resources T,
274        offset: usize,
275    ) -> impl VisitOperator<'a, Output = Result<()>> + 'validator
276    where
277        T: WasmModuleResources,
278        'resources: 'validator,
279    {
280        WasmProposalValidator(OperatorValidatorTemp {
281            offset,
282            inner: self,
283            resources,
284        })
285    }
286
287    pub fn finish(&mut self, offset: usize) -> Result<()> {
288        if self.control.last().is_some() {
289            bail!(
290                offset,
291                "control frames remain at end of function: END opcode expected"
292            );
293        }
294
295        // The `end` opcode is one byte which means that the `offset` here
296        // should point just beyond the `end` opcode which emptied the control
297        // stack. If not that means more instructions were present after the
298        // control stack was emptied.
299        if offset != self.end_which_emptied_control.unwrap() + 1 {
300            return Err(self.err_beyond_end(offset));
301        }
302        Ok(())
303    }
304
305    fn err_beyond_end(&self, offset: usize) -> BinaryReaderError {
306        format_err!(offset, "operators remaining after end of function")
307    }
308
309    pub fn into_allocations(self) -> OperatorValidatorAllocations {
310        fn truncate<T>(mut tmp: Vec<T>) -> Vec<T> {
311            tmp.truncate(0);
312            tmp
313        }
314        OperatorValidatorAllocations {
315            br_table_tmp: truncate(self.br_table_tmp),
316            control: truncate(self.control),
317            operands: truncate(self.operands),
318            locals_first: truncate(self.locals.first),
319            locals_all: truncate(self.locals.all),
320        }
321    }
322}
323
324impl<R> Deref for OperatorValidatorTemp<'_, '_, R> {
325    type Target = OperatorValidator;
326    fn deref(&self) -> &OperatorValidator {
327        self.inner
328    }
329}
330
331impl<R> DerefMut for OperatorValidatorTemp<'_, '_, R> {
332    fn deref_mut(&mut self) -> &mut OperatorValidator {
333        self.inner
334    }
335}
336
337impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R> {
338    /// Pushes a type onto the operand stack.
339    ///
340    /// This is used by instructions to represent a value that is pushed to the
341    /// operand stack. This can fail, but only if `Type` is feature gated.
342    /// Otherwise the push operation always succeeds.
343    fn push_operand<T>(&mut self, ty: T) -> Result<()>
344    where
345        T: Into<Option<ValType>>,
346    {
347        let maybe_ty = ty.into();
348        self.operands.push(maybe_ty);
349        Ok(())
350    }
351
352    /// Attempts to pop a type from the operand stack.
353    ///
354    /// This function is used to remove types from the operand stack. The
355    /// `expected` argument can be used to indicate that a type is required, or
356    /// simply that something is needed to be popped.
357    ///
358    /// If `expected` is `Some(T)` then this will be guaranteed to return
359    /// `Some(T)`, and it will only return success if the current block is
360    /// unreachable or if `T` was found at the top of the operand stack.
361    ///
362    /// If `expected` is `None` then it indicates that something must be on the
363    /// operand stack, but it doesn't matter what's on the operand stack. This
364    /// is useful for polymorphic instructions like `select`.
365    ///
366    /// If `Some(T)` is returned then `T` was popped from the operand stack and
367    /// matches `expected`. If `None` is returned then it means that `None` was
368    /// expected and a type was successfully popped, but its exact type is
369    /// indeterminate because the current block is unreachable.
370    fn pop_operand(&mut self, expected: Option<ValType>) -> Result<Option<ValType>> {
371        // This method is one of the hottest methods in the validator so to
372        // improve codegen this method contains a fast-path success case where
373        // if the top operand on the stack is as expected it's returned
374        // immediately. This is the most common case where the stack will indeed
375        // have the expected type and all we need to do is pop it off.
376        //
377        // Note that this still has to be careful to be correct, though. For
378        // efficiency an operand is unconditionally popped and on success it is
379        // matched against the state of the world to see if we could actually
380        // pop it. If we shouldn't have popped it then it's passed to the slow
381        // path to get pushed back onto the stack.
382        let popped = if let Some(actual_ty) = self.operands.pop() {
383            if actual_ty == expected {
384                if let Some(control) = self.control.last() {
385                    if self.operands.len() >= control.height {
386                        return Ok(actual_ty);
387                    }
388                }
389            }
390            Some(actual_ty)
391        } else {
392            None
393        };
394
395        self._pop_operand(expected, popped)
396    }
397
398    // This is the "real" implementation of `pop_operand` which is 100%
399    // spec-compliant with little attention paid to efficiency since this is the
400    // slow-path from the actual `pop_operand` function above.
401    #[cold]
402    fn _pop_operand(
403        &mut self,
404        expected: Option<ValType>,
405        popped: Option<Option<ValType>>,
406    ) -> Result<Option<ValType>> {
407        self.operands.extend(popped);
408        let control = match self.control.last() {
409            Some(c) => c,
410            None => return Err(self.err_beyond_end(self.offset)),
411        };
412        let actual = if self.operands.len() == control.height {
413            if control.unreachable {
414                None
415            } else {
416                let desc = match expected {
417                    Some(ty) => ty_to_str(ty),
418                    None => "a type",
419                };
420                bail!(
421                    self.offset,
422                    "type mismatch: expected {desc} but nothing on stack"
423                )
424            }
425        } else {
426            self.operands.pop().unwrap()
427        };
428        if let (Some(actual_ty), Some(expected_ty)) = (actual, expected) {
429            if actual_ty != expected_ty {
430                bail!(
431                    self.offset,
432                    "type mismatch: expected {}, found {}",
433                    ty_to_str(expected_ty),
434                    ty_to_str(actual_ty)
435                )
436            }
437        }
438        Ok(actual)
439    }
440
441    /// Fetches the type for the local at `idx`, returning an error if it's out
442    /// of bounds.
443    fn local(&self, idx: u32) -> Result<ValType> {
444        match self.locals.get(idx) {
445            Some(ty) => Ok(ty),
446            None => bail!(
447                self.offset,
448                "unknown local {}: local index out of bounds",
449                idx
450            ),
451        }
452    }
453
454    /// Flags the current control frame as unreachable, additionally truncating
455    /// the currently active operand stack.
456    fn unreachable(&mut self) -> Result<()> {
457        let control = match self.control.last_mut() {
458            Some(frame) => frame,
459            None => return Err(self.err_beyond_end(self.offset)),
460        };
461        control.unreachable = true;
462        let new_height = control.height;
463        self.operands.truncate(new_height);
464        Ok(())
465    }
466
467    /// Pushes a new frame onto the control stack.
468    ///
469    /// This operation is used when entering a new block such as an if, loop,
470    /// or block itself. The `kind` of block is specified which indicates how
471    /// breaks interact with this block's type. Additionally the type signature
472    /// of the block is specified by `ty`.
473    fn push_ctrl(&mut self, kind: FrameKind, ty: BlockType) -> Result<()> {
474        // Push a new frame which has a snapshot of the height of the current
475        // operand stack.
476        let height = self.operands.len();
477        self.control.push(Frame {
478            kind,
479            block_type: ty,
480            height,
481            unreachable: false,
482        });
483        // All of the parameters are now also available in this control frame,
484        // so we push them here in order.
485        for ty in self.params(ty)? {
486            self.push_operand(ty)?;
487        }
488        Ok(())
489    }
490
491    /// Pops a frame from the control stack.
492    ///
493    /// This function is used when exiting a block and leaves a block scope.
494    /// Internally this will validate that blocks have the correct result type.
495    fn pop_ctrl(&mut self) -> Result<Frame> {
496        // Read the expected type and expected height of the operand stack the
497        // end of the frame.
498        let frame = match self.control.last() {
499            Some(f) => f,
500            None => return Err(self.err_beyond_end(self.offset)),
501        };
502        let ty = frame.block_type;
503        let height = frame.height;
504
505        // Pop all the result types, in reverse order, from the operand stack.
506        // These types will, possibly, be transferred to the next frame.
507        for ty in self.results(ty)?.rev() {
508            self.pop_operand(Some(ty))?;
509        }
510
511        // Make sure that the operand stack has returned to is original
512        // height...
513        if self.operands.len() != height {
514            bail!(
515                self.offset,
516                "type mismatch: values remaining on stack at end of block"
517            );
518        }
519
520        // And then we can remove it!
521        Ok(self.control.pop().unwrap())
522    }
523
524    /// Validates a relative jump to the `depth` specified.
525    ///
526    /// Returns the type signature of the block that we're jumping to as well
527    /// as the kind of block if the jump is valid. Otherwise returns an error.
528    fn jump(&self, depth: u32) -> Result<(BlockType, FrameKind)> {
529        if self.control.is_empty() {
530            return Err(self.err_beyond_end(self.offset));
531        }
532        match (self.control.len() - 1).checked_sub(depth as usize) {
533            Some(i) => {
534                let frame = &self.control[i];
535                Ok((frame.block_type, frame.kind))
536            }
537            None => bail!(self.offset, "unknown label: branch depth too large"),
538        }
539    }
540
541    /// Validates that `memory_index` is valid in this module, and returns the
542    /// type of address used to index the memory specified.
543    fn check_memory_index(&self, memory_index: u32) -> Result<ValType> {
544        match self.resources.memory_at(memory_index) {
545            Some(mem) => Ok(mem.index_type()),
546            None => bail!(self.offset, "unknown memory {}", memory_index),
547        }
548    }
549
550    /// Validates a `memarg for alignment and such (also the memory it
551    /// references), and returns the type of index used to address the memory.
552    fn check_memarg(&self, memarg: MemArg) -> Result<ValType> {
553        let index_ty = self.check_memory_index(memarg.memory)?;
554        if memarg.align > memarg.max_align {
555            bail!(self.offset, "alignment must not be larger than natural");
556        }
557        if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) {
558            bail!(self.offset, "offset out of range: must be <= 2**32");
559        }
560        Ok(index_ty)
561    }
562
563    fn check_floats_enabled(&self) -> Result<()> {
564        if !self.features.floats {
565            bail!(self.offset, "floating-point instruction disallowed");
566        }
567        Ok(())
568    }
569
570    fn check_shared_memarg(&self, memarg: MemArg) -> Result<ValType> {
571        if memarg.align != memarg.max_align {
572            bail!(
573                self.offset,
574                "atomic instructions must always specify maximum alignment"
575            );
576        }
577        self.check_memory_index(memarg.memory)
578    }
579
580    fn check_simd_lane_index(&self, index: u8, max: u8) -> Result<()> {
581        if index >= max {
582            bail!(self.offset, "SIMD index out of bounds");
583        }
584        Ok(())
585    }
586
587    /// Validates a block type, primarily with various in-flight proposals.
588    fn check_block_type(&self, ty: BlockType) -> Result<()> {
589        match ty {
590            BlockType::Empty => Ok(()),
591            BlockType::Type(ty) => self
592                .features
593                .check_value_type(ty)
594                .map_err(|e| BinaryReaderError::new(e, self.offset)),
595            BlockType::FuncType(idx) => {
596                if !self.features.multi_value {
597                    bail!(
598                        self.offset,
599                        "blocks, loops, and ifs may only produce a resulttype \
600                         when multi-value is not enabled",
601                    );
602                }
603                self.func_type_at(idx)?;
604                Ok(())
605            }
606        }
607    }
608
609    /// Validates a `call` instruction, ensuring that the function index is
610    /// in-bounds and the right types are on the stack to call the function.
611    fn check_call(&mut self, function_index: u32) -> Result<()> {
612        let ty = match self.resources.type_of_function(function_index) {
613            Some(i) => i,
614            None => {
615                bail!(
616                    self.offset,
617                    "unknown function {}: function index out of bounds",
618                    function_index
619                );
620            }
621        };
622        for ty in ty.inputs().rev() {
623            self.pop_operand(Some(ty))?;
624        }
625        for ty in ty.outputs() {
626            self.push_operand(ty)?;
627        }
628        Ok(())
629    }
630
631    /// Validates a call to an indirect function, very similar to `check_call`.
632    fn check_call_indirect(&mut self, index: u32, table_index: u32) -> Result<()> {
633        match self.resources.table_at(table_index) {
634            None => {
635                bail!(self.offset, "unknown table: table index out of bounds");
636            }
637            Some(tab) => {
638                if tab.element_type != ValType::FuncRef {
639                    bail!(
640                        self.offset,
641                        "indirect calls must go through a table of funcref"
642                    );
643                }
644            }
645        }
646        let ty = self.func_type_at(index)?;
647        self.pop_operand(Some(ValType::I32))?;
648        for ty in ty.inputs().rev() {
649            self.pop_operand(Some(ty))?;
650        }
651        for ty in ty.outputs() {
652            self.push_operand(ty)?;
653        }
654        Ok(())
655    }
656
657    /// Validates a `return` instruction, popping types from the operand
658    /// stack that the function needs.
659    fn check_return(&mut self) -> Result<()> {
660        if self.control.is_empty() {
661            return Err(self.err_beyond_end(self.offset));
662        }
663        for ty in self.results(self.control[0].block_type)?.rev() {
664            self.pop_operand(Some(ty))?;
665        }
666        self.unreachable()?;
667        Ok(())
668    }
669
670    /// Checks the validity of a common comparison operator.
671    fn check_cmp_op(&mut self, ty: ValType) -> Result<()> {
672        self.pop_operand(Some(ty))?;
673        self.pop_operand(Some(ty))?;
674        self.push_operand(ValType::I32)?;
675        Ok(())
676    }
677
678    /// Checks the validity of a common float comparison operator.
679    fn check_fcmp_op(&mut self, ty: ValType) -> Result<()> {
680        debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
681        self.check_floats_enabled()?;
682        self.check_cmp_op(ty)
683    }
684
685    /// Checks the validity of a common unary operator.
686    fn check_unary_op(&mut self, ty: ValType) -> Result<()> {
687        self.pop_operand(Some(ty))?;
688        self.push_operand(ty)?;
689        Ok(())
690    }
691
692    /// Checks the validity of a common unary float operator.
693    fn check_funary_op(&mut self, ty: ValType) -> Result<()> {
694        debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
695        self.check_floats_enabled()?;
696        self.check_unary_op(ty)
697    }
698
699    /// Checks the validity of a common conversion operator.
700    fn check_conversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
701        self.pop_operand(Some(from))?;
702        self.push_operand(into)?;
703        Ok(())
704    }
705
706    /// Checks the validity of a common conversion operator.
707    fn check_fconversion_op(&mut self, into: ValType, from: ValType) -> Result<()> {
708        debug_assert!(matches!(into, ValType::F32 | ValType::F64));
709        self.check_floats_enabled()?;
710        self.check_conversion_op(into, from)
711    }
712
713    /// Checks the validity of a common binary operator.
714    fn check_binary_op(&mut self, ty: ValType) -> Result<()> {
715        self.pop_operand(Some(ty))?;
716        self.pop_operand(Some(ty))?;
717        self.push_operand(ty)?;
718        Ok(())
719    }
720
721    /// Checks the validity of a common binary float operator.
722    fn check_fbinary_op(&mut self, ty: ValType) -> Result<()> {
723        debug_assert!(matches!(ty, ValType::F32 | ValType::F64));
724        self.check_floats_enabled()?;
725        self.check_binary_op(ty)
726    }
727
728    /// Checks the validity of an atomic load operator.
729    fn check_atomic_load(&mut self, memarg: MemArg, load_ty: ValType) -> Result<()> {
730        let ty = self.check_shared_memarg(memarg)?;
731        self.pop_operand(Some(ty))?;
732        self.push_operand(load_ty)?;
733        Ok(())
734    }
735
736    /// Checks the validity of an atomic store operator.
737    fn check_atomic_store(&mut self, memarg: MemArg, store_ty: ValType) -> Result<()> {
738        let ty = self.check_shared_memarg(memarg)?;
739        self.pop_operand(Some(store_ty))?;
740        self.pop_operand(Some(ty))?;
741        Ok(())
742    }
743
744    /// Checks the validity of a common atomic binary operator.
745    fn check_atomic_binary_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
746        let ty = self.check_shared_memarg(memarg)?;
747        self.pop_operand(Some(op_ty))?;
748        self.pop_operand(Some(ty))?;
749        self.push_operand(op_ty)?;
750        Ok(())
751    }
752
753    /// Checks the validity of an atomic compare exchange operator.
754    fn check_atomic_binary_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
755        let ty = self.check_shared_memarg(memarg)?;
756        self.pop_operand(Some(op_ty))?;
757        self.pop_operand(Some(op_ty))?;
758        self.pop_operand(Some(ty))?;
759        self.push_operand(op_ty)?;
760        Ok(())
761    }
762
763    /// Checks a [`V128`] splat operator.
764    fn check_v128_splat(&mut self, src_ty: ValType) -> Result<()> {
765        self.pop_operand(Some(src_ty))?;
766        self.push_operand(ValType::V128)?;
767        Ok(())
768    }
769
770    /// Checks a [`V128`] binary operator.
771    fn check_v128_binary_op(&mut self) -> Result<()> {
772        self.pop_operand(Some(ValType::V128))?;
773        self.pop_operand(Some(ValType::V128))?;
774        self.push_operand(ValType::V128)?;
775        Ok(())
776    }
777
778    /// Checks a [`V128`] binary float operator.
779    fn check_v128_fbinary_op(&mut self) -> Result<()> {
780        self.check_floats_enabled()?;
781        self.check_v128_binary_op()
782    }
783
784    /// Checks a [`V128`] binary operator.
785    fn check_v128_relaxed_binary_op(&mut self) -> Result<()> {
786        self.pop_operand(Some(ValType::V128))?;
787        self.pop_operand(Some(ValType::V128))?;
788        self.push_operand(ValType::V128)?;
789        Ok(())
790    }
791
792    /// Checks a [`V128`] binary operator.
793    fn check_v128_unary_op(&mut self) -> Result<()> {
794        self.pop_operand(Some(ValType::V128))?;
795        self.push_operand(ValType::V128)?;
796        Ok(())
797    }
798
799    /// Checks a [`V128`] binary operator.
800    fn check_v128_funary_op(&mut self) -> Result<()> {
801        self.check_floats_enabled()?;
802        self.check_v128_unary_op()
803    }
804
805    /// Checks a [`V128`] binary operator.
806    fn check_v128_relaxed_unary_op(&mut self) -> Result<()> {
807        self.pop_operand(Some(ValType::V128))?;
808        self.push_operand(ValType::V128)?;
809        Ok(())
810    }
811
812    /// Checks a [`V128`] relaxed ternary operator.
813    fn check_v128_relaxed_ternary_op(&mut self) -> Result<()> {
814        self.pop_operand(Some(ValType::V128))?;
815        self.pop_operand(Some(ValType::V128))?;
816        self.pop_operand(Some(ValType::V128))?;
817        self.push_operand(ValType::V128)?;
818        Ok(())
819    }
820
821    /// Checks a [`V128`] relaxed ternary operator.
822    fn check_v128_bitmask_op(&mut self) -> Result<()> {
823        self.pop_operand(Some(ValType::V128))?;
824        self.push_operand(ValType::I32)?;
825        Ok(())
826    }
827
828    /// Checks a [`V128`] relaxed ternary operator.
829    fn check_v128_shift_op(&mut self) -> Result<()> {
830        self.pop_operand(Some(ValType::I32))?;
831        self.pop_operand(Some(ValType::V128))?;
832        self.push_operand(ValType::V128)?;
833        Ok(())
834    }
835
836    /// Checks a [`V128`] common load operator.
837    fn check_v128_load_op(&mut self, memarg: MemArg) -> Result<()> {
838        let idx = self.check_memarg(memarg)?;
839        self.pop_operand(Some(idx))?;
840        self.push_operand(ValType::V128)?;
841        Ok(())
842    }
843
844    fn func_type_at(&self, at: u32) -> Result<&'resources R::FuncType> {
845        self.resources
846            .func_type_at(at)
847            .ok_or_else(|| format_err!(self.offset, "unknown type: type index out of bounds"))
848    }
849
850    fn tag_at(&self, at: u32) -> Result<&'resources R::FuncType> {
851        self.resources
852            .tag_at(at)
853            .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at))
854    }
855
856    fn params(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
857        Ok(match ty {
858            BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()),
859            BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.inputs()),
860        })
861    }
862
863    fn results(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
864        Ok(match ty {
865            BlockType::Empty => Either::B(None.into_iter()),
866            BlockType::Type(t) => Either::B(Some(t).into_iter()),
867            BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.outputs()),
868        })
869    }
870
871    fn label_types(
872        &self,
873        ty: BlockType,
874        kind: FrameKind,
875    ) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
876        Ok(match kind {
877            FrameKind::Loop => Either::A(self.params(ty)?),
878            _ => Either::B(self.results(ty)?),
879        })
880    }
881}
882
883fn ty_to_str(ty: ValType) -> &'static str {
884    match ty {
885        ValType::I32 => "i32",
886        ValType::I64 => "i64",
887        ValType::F32 => "f32",
888        ValType::F64 => "f64",
889        ValType::V128 => "v128",
890        ValType::FuncRef => "funcref",
891        ValType::ExternRef => "externref",
892    }
893}
894
895/// A wrapper "visitor" around the real operator validator internally which
896/// exists to check that the required wasm feature is enabled to proceed with
897/// validation.
898///
899/// This validator is macro-generated to ensure that the proposal listed in this
900/// crate's macro matches the one that's validated here. Each instruction's
901/// visit method validates the specified proposal is enabled and then delegates
902/// to `OperatorValidatorTemp` to perform the actual opcode validation.
903struct WasmProposalValidator<'validator, 'resources, T>(
904    OperatorValidatorTemp<'validator, 'resources, T>,
905);
906
907impl<T> WasmProposalValidator<'_, '_, T> {
908    fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> {
909        if flag {
910            return Ok(());
911        }
912        bail!(self.0.offset, "{desc} support is not enabled");
913    }
914}
915
916macro_rules! validate_proposal {
917    ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
918        $(
919            fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()> {
920                validate_proposal!(validate self $proposal);
921                self.0.$visit($( $($arg),* )?)
922            }
923        )*
924    };
925
926    (validate self mvp) => {};
927    (validate $self:ident $proposal:ident) => {
928        $self.check_enabled($self.0.features.$proposal, validate_proposal!(desc $proposal))?
929    };
930
931    (desc simd) => ("SIMD");
932    (desc relaxed_simd) => ("relaxed SIMD");
933    (desc threads) => ("threads");
934    (desc saturating_float_to_int) => ("saturating float to int conversions");
935    (desc reference_types) => ("reference types");
936    (desc bulk_memory) => ("bulk memory");
937    (desc sign_extension) => ("sign extension operations");
938    (desc exceptions) => ("exceptions");
939    (desc tail_call) => ("tail calls");
940    (desc memory_control) => ("memory control");
941}
942
943impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T>
944where
945    T: WasmModuleResources,
946{
947    type Output = Result<()>;
948
949    for_each_operator!(validate_proposal);
950}
951
952impl<'a, T> VisitOperator<'a> for OperatorValidatorTemp<'_, '_, T>
953where
954    T: WasmModuleResources,
955{
956    type Output = Result<()>;
957
958    fn visit_nop(&mut self) -> Self::Output {
959        Ok(())
960    }
961    fn visit_unreachable(&mut self) -> Self::Output {
962        self.unreachable()?;
963        Ok(())
964    }
965    fn visit_block(&mut self, ty: BlockType) -> Self::Output {
966        self.check_block_type(ty)?;
967        for ty in self.params(ty)?.rev() {
968            self.pop_operand(Some(ty))?;
969        }
970        self.push_ctrl(FrameKind::Block, ty)?;
971        Ok(())
972    }
973    fn visit_loop(&mut self, ty: BlockType) -> Self::Output {
974        self.check_block_type(ty)?;
975        for ty in self.params(ty)?.rev() {
976            self.pop_operand(Some(ty))?;
977        }
978        self.push_ctrl(FrameKind::Loop, ty)?;
979        Ok(())
980    }
981    fn visit_if(&mut self, ty: BlockType) -> Self::Output {
982        self.check_block_type(ty)?;
983        self.pop_operand(Some(ValType::I32))?;
984        for ty in self.params(ty)?.rev() {
985            self.pop_operand(Some(ty))?;
986        }
987        self.push_ctrl(FrameKind::If, ty)?;
988        Ok(())
989    }
990    fn visit_else(&mut self) -> Self::Output {
991        let frame = self.pop_ctrl()?;
992        if frame.kind != FrameKind::If {
993            bail!(self.offset, "else found outside of an `if` block");
994        }
995        self.push_ctrl(FrameKind::Else, frame.block_type)?;
996        Ok(())
997    }
998    fn visit_try(&mut self, ty: BlockType) -> Self::Output {
999        self.check_block_type(ty)?;
1000        for ty in self.params(ty)?.rev() {
1001            self.pop_operand(Some(ty))?;
1002        }
1003        self.push_ctrl(FrameKind::Try, ty)?;
1004        Ok(())
1005    }
1006    fn visit_catch(&mut self, index: u32) -> Self::Output {
1007        let frame = self.pop_ctrl()?;
1008        if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch {
1009            bail!(self.offset, "catch found outside of an `try` block");
1010        }
1011        // Start a new frame and push `exnref` value.
1012        let height = self.operands.len();
1013        self.control.push(Frame {
1014            kind: FrameKind::Catch,
1015            block_type: frame.block_type,
1016            height,
1017            unreachable: false,
1018        });
1019        // Push exception argument types.
1020        let ty = self.tag_at(index)?;
1021        for ty in ty.inputs() {
1022            self.push_operand(ty)?;
1023        }
1024        Ok(())
1025    }
1026    fn visit_throw(&mut self, index: u32) -> Self::Output {
1027        // Check values associated with the exception.
1028        let ty = self.tag_at(index)?;
1029        for ty in ty.inputs().rev() {
1030            self.pop_operand(Some(ty))?;
1031        }
1032        if ty.outputs().len() > 0 {
1033            bail!(
1034                self.offset,
1035                "result type expected to be empty for exception"
1036            );
1037        }
1038        self.unreachable()?;
1039        Ok(())
1040    }
1041    fn visit_rethrow(&mut self, relative_depth: u32) -> Self::Output {
1042        // This is not a jump, but we need to check that the `rethrow`
1043        // targets an actual `catch` to get the exception.
1044        let (_, kind) = self.jump(relative_depth)?;
1045        if kind != FrameKind::Catch && kind != FrameKind::CatchAll {
1046            bail!(
1047                self.offset,
1048                "invalid rethrow label: target was not a `catch` block"
1049            );
1050        }
1051        self.unreachable()?;
1052        Ok(())
1053    }
1054    fn visit_delegate(&mut self, relative_depth: u32) -> Self::Output {
1055        let frame = self.pop_ctrl()?;
1056        if frame.kind != FrameKind::Try {
1057            bail!(self.offset, "delegate found outside of an `try` block");
1058        }
1059        // This operation is not a jump, but we need to check the
1060        // depth for validity
1061        let _ = self.jump(relative_depth)?;
1062        for ty in self.results(frame.block_type)? {
1063            self.push_operand(ty)?;
1064        }
1065        Ok(())
1066    }
1067    fn visit_catch_all(&mut self) -> Self::Output {
1068        let frame = self.pop_ctrl()?;
1069        if frame.kind == FrameKind::CatchAll {
1070            bail!(self.offset, "only one catch_all allowed per `try` block");
1071        } else if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch {
1072            bail!(self.offset, "catch_all found outside of a `try` block");
1073        }
1074        let height = self.operands.len();
1075        self.control.push(Frame {
1076            kind: FrameKind::CatchAll,
1077            block_type: frame.block_type,
1078            height,
1079            unreachable: false,
1080        });
1081        Ok(())
1082    }
1083    fn visit_end(&mut self) -> Self::Output {
1084        let mut frame = self.pop_ctrl()?;
1085
1086        // Note that this `if` isn't included in the appendix right
1087        // now, but it's used to allow for `if` statements that are
1088        // missing an `else` block which have the same parameter/return
1089        // types on the block (since that's valid).
1090        if frame.kind == FrameKind::If {
1091            self.push_ctrl(FrameKind::Else, frame.block_type)?;
1092            frame = self.pop_ctrl()?;
1093        }
1094        for ty in self.results(frame.block_type)? {
1095            self.push_operand(ty)?;
1096        }
1097
1098        if self.control.is_empty() && self.end_which_emptied_control.is_none() {
1099            assert_ne!(self.offset, 0);
1100            self.end_which_emptied_control = Some(self.offset);
1101        }
1102        Ok(())
1103    }
1104    fn visit_br(&mut self, relative_depth: u32) -> Self::Output {
1105        let (ty, kind) = self.jump(relative_depth)?;
1106        for ty in self.label_types(ty, kind)?.rev() {
1107            self.pop_operand(Some(ty))?;
1108        }
1109        self.unreachable()?;
1110        Ok(())
1111    }
1112    fn visit_br_if(&mut self, relative_depth: u32) -> Self::Output {
1113        self.pop_operand(Some(ValType::I32))?;
1114        let (ty, kind) = self.jump(relative_depth)?;
1115        let types = self.label_types(ty, kind)?;
1116        for ty in types.clone().rev() {
1117            self.pop_operand(Some(ty))?;
1118        }
1119        for ty in types {
1120            self.push_operand(ty)?;
1121        }
1122        Ok(())
1123    }
1124    fn visit_br_table(&mut self, table: BrTable) -> Self::Output {
1125        self.pop_operand(Some(ValType::I32))?;
1126        let default = self.jump(table.default())?;
1127        let default_types = self.label_types(default.0, default.1)?;
1128        for element in table.targets() {
1129            let relative_depth = element?;
1130            let block = self.jump(relative_depth)?;
1131            let tys = self.label_types(block.0, block.1)?;
1132            if tys.len() != default_types.len() {
1133                bail!(
1134                    self.offset,
1135                    "type mismatch: br_table target labels have different number of types"
1136                );
1137            }
1138            debug_assert!(self.br_table_tmp.is_empty());
1139            for ty in tys.rev() {
1140                let ty = self.pop_operand(Some(ty))?;
1141                self.br_table_tmp.push(ty);
1142            }
1143            for ty in self.inner.br_table_tmp.drain(..).rev() {
1144                self.inner.operands.push(ty);
1145            }
1146        }
1147        for ty in default_types.rev() {
1148            self.pop_operand(Some(ty))?;
1149        }
1150        self.unreachable()?;
1151        Ok(())
1152    }
1153    fn visit_return(&mut self) -> Self::Output {
1154        self.check_return()?;
1155        Ok(())
1156    }
1157    fn visit_call(&mut self, function_index: u32) -> Self::Output {
1158        self.check_call(function_index)?;
1159        Ok(())
1160    }
1161    fn visit_return_call(&mut self, function_index: u32) -> Self::Output {
1162        self.check_call(function_index)?;
1163        self.check_return()?;
1164        Ok(())
1165    }
1166    fn visit_call_indirect(
1167        &mut self,
1168        index: u32,
1169        table_index: u32,
1170        table_byte: u8,
1171    ) -> Self::Output {
1172        if table_byte != 0 && !self.features.reference_types {
1173            bail!(
1174                self.offset,
1175                "reference-types not enabled: zero byte expected"
1176            );
1177        }
1178        self.check_call_indirect(index, table_index)?;
1179        Ok(())
1180    }
1181    fn visit_return_call_indirect(&mut self, index: u32, table_index: u32) -> Self::Output {
1182        self.check_call_indirect(index, table_index)?;
1183        self.check_return()?;
1184        Ok(())
1185    }
1186    fn visit_drop(&mut self) -> Self::Output {
1187        self.pop_operand(None)?;
1188        Ok(())
1189    }
1190    fn visit_select(&mut self) -> Self::Output {
1191        self.pop_operand(Some(ValType::I32))?;
1192        let ty1 = self.pop_operand(None)?;
1193        let ty2 = self.pop_operand(None)?;
1194        fn is_num(ty: Option<ValType>) -> bool {
1195            matches!(
1196                ty,
1197                Some(ValType::I32)
1198                    | Some(ValType::I64)
1199                    | Some(ValType::F32)
1200                    | Some(ValType::F64)
1201                    | Some(ValType::V128)
1202                    | None
1203            )
1204        }
1205        if !is_num(ty1) || !is_num(ty2) {
1206            bail!(
1207                self.offset,
1208                "type mismatch: select only takes integral types"
1209            )
1210        }
1211        if ty1 != ty2 && ty1.is_some() && ty2.is_some() {
1212            bail!(
1213                self.offset,
1214                "type mismatch: select operands have different types"
1215            )
1216        }
1217        self.push_operand(ty1.or(ty2))?;
1218        Ok(())
1219    }
1220    fn visit_typed_select(&mut self, ty: ValType) -> Self::Output {
1221        self.features
1222            .check_value_type(ty)
1223            .map_err(|e| BinaryReaderError::new(e, self.offset))?;
1224        self.pop_operand(Some(ValType::I32))?;
1225        self.pop_operand(Some(ty))?;
1226        self.pop_operand(Some(ty))?;
1227        self.push_operand(ty)?;
1228        Ok(())
1229    }
1230    fn visit_local_get(&mut self, local_index: u32) -> Self::Output {
1231        let ty = self.local(local_index)?;
1232        self.push_operand(ty)?;
1233        Ok(())
1234    }
1235    fn visit_local_set(&mut self, local_index: u32) -> Self::Output {
1236        let ty = self.local(local_index)?;
1237        self.pop_operand(Some(ty))?;
1238        Ok(())
1239    }
1240    fn visit_local_tee(&mut self, local_index: u32) -> Self::Output {
1241        let ty = self.local(local_index)?;
1242        self.pop_operand(Some(ty))?;
1243        self.push_operand(ty)?;
1244        Ok(())
1245    }
1246    fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
1247        if let Some(ty) = self.resources.global_at(global_index) {
1248            self.push_operand(ty.content_type)?;
1249        } else {
1250            bail!(self.offset, "unknown global: global index out of bounds");
1251        };
1252        Ok(())
1253    }
1254    fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
1255        if let Some(ty) = self.resources.global_at(global_index) {
1256            if !ty.mutable {
1257                bail!(
1258                    self.offset,
1259                    "global is immutable: cannot modify it with `global.set`"
1260                );
1261            }
1262            self.pop_operand(Some(ty.content_type))?;
1263        } else {
1264            bail!(self.offset, "unknown global: global index out of bounds");
1265        };
1266        Ok(())
1267    }
1268    fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
1269        let ty = self.check_memarg(memarg)?;
1270        self.pop_operand(Some(ty))?;
1271        self.push_operand(ValType::I32)?;
1272        Ok(())
1273    }
1274    fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output {
1275        let ty = self.check_memarg(memarg)?;
1276        self.pop_operand(Some(ty))?;
1277        self.push_operand(ValType::I64)?;
1278        Ok(())
1279    }
1280    fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output {
1281        self.check_floats_enabled()?;
1282        let ty = self.check_memarg(memarg)?;
1283        self.pop_operand(Some(ty))?;
1284        self.push_operand(ValType::F32)?;
1285        Ok(())
1286    }
1287    fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output {
1288        self.check_floats_enabled()?;
1289        let ty = self.check_memarg(memarg)?;
1290        self.pop_operand(Some(ty))?;
1291        self.push_operand(ValType::F64)?;
1292        Ok(())
1293    }
1294    fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1295        let ty = self.check_memarg(memarg)?;
1296        self.pop_operand(Some(ty))?;
1297        self.push_operand(ValType::I32)?;
1298        Ok(())
1299    }
1300    fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1301        self.visit_i32_load8_s(memarg)
1302    }
1303    fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1304        let ty = self.check_memarg(memarg)?;
1305        self.pop_operand(Some(ty))?;
1306        self.push_operand(ValType::I32)?;
1307        Ok(())
1308    }
1309    fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1310        self.visit_i32_load16_s(memarg)
1311    }
1312    fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output {
1313        let ty = self.check_memarg(memarg)?;
1314        self.pop_operand(Some(ty))?;
1315        self.push_operand(ValType::I64)?;
1316        Ok(())
1317    }
1318    fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1319        self.visit_i64_load8_s(memarg)
1320    }
1321    fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output {
1322        let ty = self.check_memarg(memarg)?;
1323        self.pop_operand(Some(ty))?;
1324        self.push_operand(ValType::I64)?;
1325        Ok(())
1326    }
1327    fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1328        self.visit_i64_load16_s(memarg)
1329    }
1330    fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output {
1331        let ty = self.check_memarg(memarg)?;
1332        self.pop_operand(Some(ty))?;
1333        self.push_operand(ValType::I64)?;
1334        Ok(())
1335    }
1336    fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output {
1337        self.visit_i64_load32_s(memarg)
1338    }
1339    fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output {
1340        let ty = self.check_memarg(memarg)?;
1341        self.pop_operand(Some(ValType::I32))?;
1342        self.pop_operand(Some(ty))?;
1343        Ok(())
1344    }
1345    fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output {
1346        let ty = self.check_memarg(memarg)?;
1347        self.pop_operand(Some(ValType::I64))?;
1348        self.pop_operand(Some(ty))?;
1349        Ok(())
1350    }
1351    fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output {
1352        self.check_floats_enabled()?;
1353        let ty = self.check_memarg(memarg)?;
1354        self.pop_operand(Some(ValType::F32))?;
1355        self.pop_operand(Some(ty))?;
1356        Ok(())
1357    }
1358    fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output {
1359        self.check_floats_enabled()?;
1360        let ty = self.check_memarg(memarg)?;
1361        self.pop_operand(Some(ValType::F64))?;
1362        self.pop_operand(Some(ty))?;
1363        Ok(())
1364    }
1365    fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output {
1366        let ty = self.check_memarg(memarg)?;
1367        self.pop_operand(Some(ValType::I32))?;
1368        self.pop_operand(Some(ty))?;
1369        Ok(())
1370    }
1371    fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output {
1372        let ty = self.check_memarg(memarg)?;
1373        self.pop_operand(Some(ValType::I32))?;
1374        self.pop_operand(Some(ty))?;
1375        Ok(())
1376    }
1377    fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output {
1378        let ty = self.check_memarg(memarg)?;
1379        self.pop_operand(Some(ValType::I64))?;
1380        self.pop_operand(Some(ty))?;
1381        Ok(())
1382    }
1383    fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output {
1384        let ty = self.check_memarg(memarg)?;
1385        self.pop_operand(Some(ValType::I64))?;
1386        self.pop_operand(Some(ty))?;
1387        Ok(())
1388    }
1389    fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output {
1390        let ty = self.check_memarg(memarg)?;
1391        self.pop_operand(Some(ValType::I64))?;
1392        self.pop_operand(Some(ty))?;
1393        Ok(())
1394    }
1395    fn visit_memory_size(&mut self, mem: u32, mem_byte: u8) -> Self::Output {
1396        if mem_byte != 0 && !self.features.multi_memory {
1397            bail!(self.offset, "multi-memory not enabled: zero byte expected");
1398        }
1399        let index_ty = self.check_memory_index(mem)?;
1400        self.push_operand(index_ty)?;
1401        Ok(())
1402    }
1403    fn visit_memory_grow(&mut self, mem: u32, mem_byte: u8) -> Self::Output {
1404        if mem_byte != 0 && !self.features.multi_memory {
1405            bail!(self.offset, "multi-memory not enabled: zero byte expected");
1406        }
1407        let index_ty = self.check_memory_index(mem)?;
1408        self.pop_operand(Some(index_ty))?;
1409        self.push_operand(index_ty)?;
1410        Ok(())
1411    }
1412    fn visit_i32_const(&mut self, _value: i32) -> Self::Output {
1413        self.push_operand(ValType::I32)?;
1414        Ok(())
1415    }
1416    fn visit_i64_const(&mut self, _value: i64) -> Self::Output {
1417        self.push_operand(ValType::I64)?;
1418        Ok(())
1419    }
1420    fn visit_f32_const(&mut self, _value: Ieee32) -> Self::Output {
1421        self.check_floats_enabled()?;
1422        self.push_operand(ValType::F32)?;
1423        Ok(())
1424    }
1425    fn visit_f64_const(&mut self, _value: Ieee64) -> Self::Output {
1426        self.check_floats_enabled()?;
1427        self.push_operand(ValType::F64)?;
1428        Ok(())
1429    }
1430    fn visit_i32_eqz(&mut self) -> Self::Output {
1431        self.pop_operand(Some(ValType::I32))?;
1432        self.push_operand(ValType::I32)?;
1433        Ok(())
1434    }
1435    fn visit_i32_eq(&mut self) -> Self::Output {
1436        self.check_cmp_op(ValType::I32)
1437    }
1438    fn visit_i32_ne(&mut self) -> Self::Output {
1439        self.check_cmp_op(ValType::I32)
1440    }
1441    fn visit_i32_lt_s(&mut self) -> Self::Output {
1442        self.check_cmp_op(ValType::I32)
1443    }
1444    fn visit_i32_lt_u(&mut self) -> Self::Output {
1445        self.check_cmp_op(ValType::I32)
1446    }
1447    fn visit_i32_gt_s(&mut self) -> Self::Output {
1448        self.check_cmp_op(ValType::I32)
1449    }
1450    fn visit_i32_gt_u(&mut self) -> Self::Output {
1451        self.check_cmp_op(ValType::I32)
1452    }
1453    fn visit_i32_le_s(&mut self) -> Self::Output {
1454        self.check_cmp_op(ValType::I32)
1455    }
1456    fn visit_i32_le_u(&mut self) -> Self::Output {
1457        self.check_cmp_op(ValType::I32)
1458    }
1459    fn visit_i32_ge_s(&mut self) -> Self::Output {
1460        self.check_cmp_op(ValType::I32)
1461    }
1462    fn visit_i32_ge_u(&mut self) -> Self::Output {
1463        self.check_cmp_op(ValType::I32)
1464    }
1465    fn visit_i64_eqz(&mut self) -> Self::Output {
1466        self.pop_operand(Some(ValType::I64))?;
1467        self.push_operand(ValType::I32)?;
1468        Ok(())
1469    }
1470    fn visit_i64_eq(&mut self) -> Self::Output {
1471        self.check_cmp_op(ValType::I64)
1472    }
1473    fn visit_i64_ne(&mut self) -> Self::Output {
1474        self.check_cmp_op(ValType::I64)
1475    }
1476    fn visit_i64_lt_s(&mut self) -> Self::Output {
1477        self.check_cmp_op(ValType::I64)
1478    }
1479    fn visit_i64_lt_u(&mut self) -> Self::Output {
1480        self.check_cmp_op(ValType::I64)
1481    }
1482    fn visit_i64_gt_s(&mut self) -> Self::Output {
1483        self.check_cmp_op(ValType::I64)
1484    }
1485    fn visit_i64_gt_u(&mut self) -> Self::Output {
1486        self.check_cmp_op(ValType::I64)
1487    }
1488    fn visit_i64_le_s(&mut self) -> Self::Output {
1489        self.check_cmp_op(ValType::I64)
1490    }
1491    fn visit_i64_le_u(&mut self) -> Self::Output {
1492        self.check_cmp_op(ValType::I64)
1493    }
1494    fn visit_i64_ge_s(&mut self) -> Self::Output {
1495        self.check_cmp_op(ValType::I64)
1496    }
1497    fn visit_i64_ge_u(&mut self) -> Self::Output {
1498        self.check_cmp_op(ValType::I64)
1499    }
1500    fn visit_f32_eq(&mut self) -> Self::Output {
1501        self.check_fcmp_op(ValType::F32)
1502    }
1503    fn visit_f32_ne(&mut self) -> Self::Output {
1504        self.check_fcmp_op(ValType::F32)
1505    }
1506    fn visit_f32_lt(&mut self) -> Self::Output {
1507        self.check_fcmp_op(ValType::F32)
1508    }
1509    fn visit_f32_gt(&mut self) -> Self::Output {
1510        self.check_fcmp_op(ValType::F32)
1511    }
1512    fn visit_f32_le(&mut self) -> Self::Output {
1513        self.check_fcmp_op(ValType::F32)
1514    }
1515    fn visit_f32_ge(&mut self) -> Self::Output {
1516        self.check_fcmp_op(ValType::F32)
1517    }
1518    fn visit_f64_eq(&mut self) -> Self::Output {
1519        self.check_fcmp_op(ValType::F64)
1520    }
1521    fn visit_f64_ne(&mut self) -> Self::Output {
1522        self.check_fcmp_op(ValType::F64)
1523    }
1524    fn visit_f64_lt(&mut self) -> Self::Output {
1525        self.check_fcmp_op(ValType::F64)
1526    }
1527    fn visit_f64_gt(&mut self) -> Self::Output {
1528        self.check_fcmp_op(ValType::F64)
1529    }
1530    fn visit_f64_le(&mut self) -> Self::Output {
1531        self.check_fcmp_op(ValType::F64)
1532    }
1533    fn visit_f64_ge(&mut self) -> Self::Output {
1534        self.check_fcmp_op(ValType::F64)
1535    }
1536    fn visit_i32_clz(&mut self) -> Self::Output {
1537        self.check_unary_op(ValType::I32)
1538    }
1539    fn visit_i32_ctz(&mut self) -> Self::Output {
1540        self.check_unary_op(ValType::I32)
1541    }
1542    fn visit_i32_popcnt(&mut self) -> Self::Output {
1543        self.check_unary_op(ValType::I32)
1544    }
1545    fn visit_i32_add(&mut self) -> Self::Output {
1546        self.check_binary_op(ValType::I32)
1547    }
1548    fn visit_i32_sub(&mut self) -> Self::Output {
1549        self.check_binary_op(ValType::I32)
1550    }
1551    fn visit_i32_mul(&mut self) -> Self::Output {
1552        self.check_binary_op(ValType::I32)
1553    }
1554    fn visit_i32_div_s(&mut self) -> Self::Output {
1555        self.check_binary_op(ValType::I32)
1556    }
1557    fn visit_i32_div_u(&mut self) -> Self::Output {
1558        self.check_binary_op(ValType::I32)
1559    }
1560    fn visit_i32_rem_s(&mut self) -> Self::Output {
1561        self.check_binary_op(ValType::I32)
1562    }
1563    fn visit_i32_rem_u(&mut self) -> Self::Output {
1564        self.check_binary_op(ValType::I32)
1565    }
1566    fn visit_i32_and(&mut self) -> Self::Output {
1567        self.check_binary_op(ValType::I32)
1568    }
1569    fn visit_i32_or(&mut self) -> Self::Output {
1570        self.check_binary_op(ValType::I32)
1571    }
1572    fn visit_i32_xor(&mut self) -> Self::Output {
1573        self.check_binary_op(ValType::I32)
1574    }
1575    fn visit_i32_shl(&mut self) -> Self::Output {
1576        self.check_binary_op(ValType::I32)
1577    }
1578    fn visit_i32_shr_s(&mut self) -> Self::Output {
1579        self.check_binary_op(ValType::I32)
1580    }
1581    fn visit_i32_shr_u(&mut self) -> Self::Output {
1582        self.check_binary_op(ValType::I32)
1583    }
1584    fn visit_i32_rotl(&mut self) -> Self::Output {
1585        self.check_binary_op(ValType::I32)
1586    }
1587    fn visit_i32_rotr(&mut self) -> Self::Output {
1588        self.check_binary_op(ValType::I32)
1589    }
1590    fn visit_i64_clz(&mut self) -> Self::Output {
1591        self.check_unary_op(ValType::I64)
1592    }
1593    fn visit_i64_ctz(&mut self) -> Self::Output {
1594        self.check_unary_op(ValType::I64)
1595    }
1596    fn visit_i64_popcnt(&mut self) -> Self::Output {
1597        self.check_unary_op(ValType::I64)
1598    }
1599    fn visit_i64_add(&mut self) -> Self::Output {
1600        self.check_binary_op(ValType::I64)
1601    }
1602    fn visit_i64_sub(&mut self) -> Self::Output {
1603        self.check_binary_op(ValType::I64)
1604    }
1605    fn visit_i64_mul(&mut self) -> Self::Output {
1606        self.check_binary_op(ValType::I64)
1607    }
1608    fn visit_i64_div_s(&mut self) -> Self::Output {
1609        self.check_binary_op(ValType::I64)
1610    }
1611    fn visit_i64_div_u(&mut self) -> Self::Output {
1612        self.check_binary_op(ValType::I64)
1613    }
1614    fn visit_i64_rem_s(&mut self) -> Self::Output {
1615        self.check_binary_op(ValType::I64)
1616    }
1617    fn visit_i64_rem_u(&mut self) -> Self::Output {
1618        self.check_binary_op(ValType::I64)
1619    }
1620    fn visit_i64_and(&mut self) -> Self::Output {
1621        self.check_binary_op(ValType::I64)
1622    }
1623    fn visit_i64_or(&mut self) -> Self::Output {
1624        self.check_binary_op(ValType::I64)
1625    }
1626    fn visit_i64_xor(&mut self) -> Self::Output {
1627        self.check_binary_op(ValType::I64)
1628    }
1629    fn visit_i64_shl(&mut self) -> Self::Output {
1630        self.check_binary_op(ValType::I64)
1631    }
1632    fn visit_i64_shr_s(&mut self) -> Self::Output {
1633        self.check_binary_op(ValType::I64)
1634    }
1635    fn visit_i64_shr_u(&mut self) -> Self::Output {
1636        self.check_binary_op(ValType::I64)
1637    }
1638    fn visit_i64_rotl(&mut self) -> Self::Output {
1639        self.check_binary_op(ValType::I64)
1640    }
1641    fn visit_i64_rotr(&mut self) -> Self::Output {
1642        self.check_binary_op(ValType::I64)
1643    }
1644    fn visit_f32_abs(&mut self) -> Self::Output {
1645        self.check_funary_op(ValType::F32)
1646    }
1647    fn visit_f32_neg(&mut self) -> Self::Output {
1648        self.check_funary_op(ValType::F32)
1649    }
1650    fn visit_f32_ceil(&mut self) -> Self::Output {
1651        self.check_funary_op(ValType::F32)
1652    }
1653    fn visit_f32_floor(&mut self) -> Self::Output {
1654        self.check_funary_op(ValType::F32)
1655    }
1656    fn visit_f32_trunc(&mut self) -> Self::Output {
1657        self.check_funary_op(ValType::F32)
1658    }
1659    fn visit_f32_nearest(&mut self) -> Self::Output {
1660        self.check_funary_op(ValType::F32)
1661    }
1662    fn visit_f32_sqrt(&mut self) -> Self::Output {
1663        self.check_funary_op(ValType::F32)
1664    }
1665    fn visit_f32_add(&mut self) -> Self::Output {
1666        self.check_fbinary_op(ValType::F32)
1667    }
1668    fn visit_f32_sub(&mut self) -> Self::Output {
1669        self.check_fbinary_op(ValType::F32)
1670    }
1671    fn visit_f32_mul(&mut self) -> Self::Output {
1672        self.check_fbinary_op(ValType::F32)
1673    }
1674    fn visit_f32_div(&mut self) -> Self::Output {
1675        self.check_fbinary_op(ValType::F32)
1676    }
1677    fn visit_f32_min(&mut self) -> Self::Output {
1678        self.check_fbinary_op(ValType::F32)
1679    }
1680    fn visit_f32_max(&mut self) -> Self::Output {
1681        self.check_fbinary_op(ValType::F32)
1682    }
1683    fn visit_f32_copysign(&mut self) -> Self::Output {
1684        self.check_fbinary_op(ValType::F32)
1685    }
1686    fn visit_f64_abs(&mut self) -> Self::Output {
1687        self.check_funary_op(ValType::F64)
1688    }
1689    fn visit_f64_neg(&mut self) -> Self::Output {
1690        self.check_funary_op(ValType::F64)
1691    }
1692    fn visit_f64_ceil(&mut self) -> Self::Output {
1693        self.check_funary_op(ValType::F64)
1694    }
1695    fn visit_f64_floor(&mut self) -> Self::Output {
1696        self.check_funary_op(ValType::F64)
1697    }
1698    fn visit_f64_trunc(&mut self) -> Self::Output {
1699        self.check_funary_op(ValType::F64)
1700    }
1701    fn visit_f64_nearest(&mut self) -> Self::Output {
1702        self.check_funary_op(ValType::F64)
1703    }
1704    fn visit_f64_sqrt(&mut self) -> Self::Output {
1705        self.check_funary_op(ValType::F64)
1706    }
1707    fn visit_f64_add(&mut self) -> Self::Output {
1708        self.check_fbinary_op(ValType::F64)
1709    }
1710    fn visit_f64_sub(&mut self) -> Self::Output {
1711        self.check_fbinary_op(ValType::F64)
1712    }
1713    fn visit_f64_mul(&mut self) -> Self::Output {
1714        self.check_fbinary_op(ValType::F64)
1715    }
1716    fn visit_f64_div(&mut self) -> Self::Output {
1717        self.check_fbinary_op(ValType::F64)
1718    }
1719    fn visit_f64_min(&mut self) -> Self::Output {
1720        self.check_fbinary_op(ValType::F64)
1721    }
1722    fn visit_f64_max(&mut self) -> Self::Output {
1723        self.check_fbinary_op(ValType::F64)
1724    }
1725    fn visit_f64_copysign(&mut self) -> Self::Output {
1726        self.check_fbinary_op(ValType::F64)
1727    }
1728    fn visit_i32_wrap_i64(&mut self) -> Self::Output {
1729        self.check_conversion_op(ValType::I32, ValType::I64)
1730    }
1731    fn visit_i32_trunc_f32_s(&mut self) -> Self::Output {
1732        self.check_conversion_op(ValType::I32, ValType::F32)
1733    }
1734    fn visit_i32_trunc_f32_u(&mut self) -> Self::Output {
1735        self.check_conversion_op(ValType::I32, ValType::F32)
1736    }
1737    fn visit_i32_trunc_f64_s(&mut self) -> Self::Output {
1738        self.check_conversion_op(ValType::I32, ValType::F64)
1739    }
1740    fn visit_i32_trunc_f64_u(&mut self) -> Self::Output {
1741        self.check_conversion_op(ValType::I32, ValType::F64)
1742    }
1743    fn visit_i64_extend_i32_s(&mut self) -> Self::Output {
1744        self.check_conversion_op(ValType::I64, ValType::I32)
1745    }
1746    fn visit_i64_extend_i32_u(&mut self) -> Self::Output {
1747        self.check_conversion_op(ValType::I64, ValType::I32)
1748    }
1749    fn visit_i64_trunc_f32_s(&mut self) -> Self::Output {
1750        self.check_conversion_op(ValType::I64, ValType::F32)
1751    }
1752    fn visit_i64_trunc_f32_u(&mut self) -> Self::Output {
1753        self.check_conversion_op(ValType::I64, ValType::F32)
1754    }
1755    fn visit_i64_trunc_f64_s(&mut self) -> Self::Output {
1756        self.check_conversion_op(ValType::I64, ValType::F64)
1757    }
1758    fn visit_i64_trunc_f64_u(&mut self) -> Self::Output {
1759        self.check_conversion_op(ValType::I64, ValType::F64)
1760    }
1761    fn visit_f32_convert_i32_s(&mut self) -> Self::Output {
1762        self.check_fconversion_op(ValType::F32, ValType::I32)
1763    }
1764    fn visit_f32_convert_i32_u(&mut self) -> Self::Output {
1765        self.check_fconversion_op(ValType::F32, ValType::I32)
1766    }
1767    fn visit_f32_convert_i64_s(&mut self) -> Self::Output {
1768        self.check_fconversion_op(ValType::F32, ValType::I64)
1769    }
1770    fn visit_f32_convert_i64_u(&mut self) -> Self::Output {
1771        self.check_fconversion_op(ValType::F32, ValType::I64)
1772    }
1773    fn visit_f32_demote_f64(&mut self) -> Self::Output {
1774        self.check_fconversion_op(ValType::F32, ValType::F64)
1775    }
1776    fn visit_f64_convert_i32_s(&mut self) -> Self::Output {
1777        self.check_fconversion_op(ValType::F64, ValType::I32)
1778    }
1779    fn visit_f64_convert_i32_u(&mut self) -> Self::Output {
1780        self.check_fconversion_op(ValType::F64, ValType::I32)
1781    }
1782    fn visit_f64_convert_i64_s(&mut self) -> Self::Output {
1783        self.check_fconversion_op(ValType::F64, ValType::I64)
1784    }
1785    fn visit_f64_convert_i64_u(&mut self) -> Self::Output {
1786        self.check_fconversion_op(ValType::F64, ValType::I64)
1787    }
1788    fn visit_f64_promote_f32(&mut self) -> Self::Output {
1789        self.check_fconversion_op(ValType::F64, ValType::F32)
1790    }
1791    fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {
1792        self.check_conversion_op(ValType::I32, ValType::F32)
1793    }
1794    fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {
1795        self.check_conversion_op(ValType::I64, ValType::F64)
1796    }
1797    fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {
1798        self.check_fconversion_op(ValType::F32, ValType::I32)
1799    }
1800    fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {
1801        self.check_fconversion_op(ValType::F64, ValType::I64)
1802    }
1803    fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output {
1804        self.check_conversion_op(ValType::I32, ValType::F32)
1805    }
1806    fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output {
1807        self.check_conversion_op(ValType::I32, ValType::F32)
1808    }
1809    fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output {
1810        self.check_conversion_op(ValType::I32, ValType::F64)
1811    }
1812    fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output {
1813        self.check_conversion_op(ValType::I32, ValType::F64)
1814    }
1815    fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output {
1816        self.check_conversion_op(ValType::I64, ValType::F32)
1817    }
1818    fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output {
1819        self.check_conversion_op(ValType::I64, ValType::F32)
1820    }
1821    fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output {
1822        self.check_conversion_op(ValType::I64, ValType::F64)
1823    }
1824    fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output {
1825        self.check_conversion_op(ValType::I64, ValType::F64)
1826    }
1827    fn visit_i32_extend8_s(&mut self) -> Self::Output {
1828        self.check_unary_op(ValType::I32)
1829    }
1830    fn visit_i32_extend16_s(&mut self) -> Self::Output {
1831        self.check_unary_op(ValType::I32)
1832    }
1833    fn visit_i64_extend8_s(&mut self) -> Self::Output {
1834        self.check_unary_op(ValType::I64)
1835    }
1836    fn visit_i64_extend16_s(&mut self) -> Self::Output {
1837        self.check_unary_op(ValType::I64)
1838    }
1839    fn visit_i64_extend32_s(&mut self) -> Self::Output {
1840        self.check_unary_op(ValType::I64)
1841    }
1842    fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
1843        self.check_atomic_load(memarg, ValType::I32)
1844    }
1845    fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1846        self.check_atomic_load(memarg, ValType::I32)
1847    }
1848    fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1849        self.check_atomic_load(memarg, ValType::I32)
1850    }
1851    fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
1852        self.check_atomic_load(memarg, ValType::I64)
1853    }
1854    fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output {
1855        self.check_atomic_load(memarg, ValType::I64)
1856    }
1857    fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
1858        self.check_atomic_load(memarg, ValType::I64)
1859    }
1860    fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
1861        self.check_atomic_load(memarg, ValType::I64)
1862    }
1863    fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
1864        self.check_atomic_store(memarg, ValType::I32)
1865    }
1866    fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
1867        self.check_atomic_store(memarg, ValType::I32)
1868    }
1869    fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
1870        self.check_atomic_store(memarg, ValType::I32)
1871    }
1872    fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
1873        self.check_atomic_store(memarg, ValType::I64)
1874    }
1875    fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output {
1876        self.check_atomic_store(memarg, ValType::I64)
1877    }
1878    fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
1879        self.check_atomic_store(memarg, ValType::I64)
1880    }
1881    fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
1882        self.check_atomic_store(memarg, ValType::I64)
1883    }
1884    fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
1885        self.check_atomic_binary_op(memarg, ValType::I32)
1886    }
1887    fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
1888        self.check_atomic_binary_op(memarg, ValType::I32)
1889    }
1890    fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
1891        self.check_atomic_binary_op(memarg, ValType::I32)
1892    }
1893    fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
1894        self.check_atomic_binary_op(memarg, ValType::I32)
1895    }
1896    fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
1897        self.check_atomic_binary_op(memarg, ValType::I32)
1898    }
1899    fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
1900        self.check_atomic_binary_op(memarg, ValType::I32)
1901    }
1902    fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
1903        self.check_atomic_binary_op(memarg, ValType::I32)
1904    }
1905    fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
1906        self.check_atomic_binary_op(memarg, ValType::I32)
1907    }
1908    fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
1909        self.check_atomic_binary_op(memarg, ValType::I32)
1910    }
1911    fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
1912        self.check_atomic_binary_op(memarg, ValType::I32)
1913    }
1914    fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
1915        self.check_atomic_binary_op(memarg, ValType::I32)
1916    }
1917    fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
1918        self.check_atomic_binary_op(memarg, ValType::I32)
1919    }
1920    fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
1921        self.check_atomic_binary_op(memarg, ValType::I32)
1922    }
1923    fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
1924        self.check_atomic_binary_op(memarg, ValType::I32)
1925    }
1926    fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
1927        self.check_atomic_binary_op(memarg, ValType::I32)
1928    }
1929    fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
1930        self.check_atomic_binary_op(memarg, ValType::I64)
1931    }
1932    fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
1933        self.check_atomic_binary_op(memarg, ValType::I64)
1934    }
1935    fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
1936        self.check_atomic_binary_op(memarg, ValType::I64)
1937    }
1938    fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
1939        self.check_atomic_binary_op(memarg, ValType::I64)
1940    }
1941    fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
1942        self.check_atomic_binary_op(memarg, ValType::I64)
1943    }
1944    fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output {
1945        self.check_atomic_binary_op(memarg, ValType::I64)
1946    }
1947    fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output {
1948        self.check_atomic_binary_op(memarg, ValType::I64)
1949    }
1950    fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output {
1951        self.check_atomic_binary_op(memarg, ValType::I64)
1952    }
1953    fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output {
1954        self.check_atomic_binary_op(memarg, ValType::I64)
1955    }
1956    fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output {
1957        self.check_atomic_binary_op(memarg, ValType::I64)
1958    }
1959    fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
1960        self.check_atomic_binary_op(memarg, ValType::I64)
1961    }
1962    fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
1963        self.check_atomic_binary_op(memarg, ValType::I64)
1964    }
1965    fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
1966        self.check_atomic_binary_op(memarg, ValType::I64)
1967    }
1968    fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
1969        self.check_atomic_binary_op(memarg, ValType::I64)
1970    }
1971    fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
1972        self.check_atomic_binary_op(memarg, ValType::I64)
1973    }
1974    fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
1975        self.check_atomic_binary_op(memarg, ValType::I64)
1976    }
1977    fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
1978        self.check_atomic_binary_op(memarg, ValType::I64)
1979    }
1980    fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
1981        self.check_atomic_binary_op(memarg, ValType::I64)
1982    }
1983    fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
1984        self.check_atomic_binary_op(memarg, ValType::I64)
1985    }
1986    fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
1987        self.check_atomic_binary_op(memarg, ValType::I64)
1988    }
1989    fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
1990        self.check_atomic_binary_op(memarg, ValType::I32)
1991    }
1992    fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
1993        self.check_atomic_binary_op(memarg, ValType::I32)
1994    }
1995    fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
1996        self.check_atomic_binary_op(memarg, ValType::I32)
1997    }
1998    fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
1999        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2000    }
2001    fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2002        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2003    }
2004    fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2005        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
2006    }
2007    fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
2008        self.check_atomic_binary_op(memarg, ValType::I64)
2009    }
2010    fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2011        self.check_atomic_binary_op(memarg, ValType::I64)
2012    }
2013    fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2014        self.check_atomic_binary_op(memarg, ValType::I64)
2015    }
2016    fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
2017        self.check_atomic_binary_op(memarg, ValType::I64)
2018    }
2019    fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
2020        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2021    }
2022    fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2023        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2024    }
2025    fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2026        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2027    }
2028    fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
2029        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
2030    }
2031    fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output {
2032        self.check_atomic_binary_op(memarg, ValType::I32)
2033    }
2034    fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output {
2035        let ty = self.check_shared_memarg(memarg)?;
2036        self.pop_operand(Some(ValType::I64))?;
2037        self.pop_operand(Some(ValType::I32))?;
2038        self.pop_operand(Some(ty))?;
2039        self.push_operand(ValType::I32)?;
2040        Ok(())
2041    }
2042    fn visit_memory_atomic_wait64(&mut self, memarg: MemArg) -> Self::Output {
2043        let ty = self.check_shared_memarg(memarg)?;
2044        self.pop_operand(Some(ValType::I64))?;
2045        self.pop_operand(Some(ValType::I64))?;
2046        self.pop_operand(Some(ty))?;
2047        self.push_operand(ValType::I32)?;
2048        Ok(())
2049    }
2050    fn visit_atomic_fence(&mut self) -> Self::Output {
2051        Ok(())
2052    }
2053    fn visit_ref_null(&mut self, ty: ValType) -> Self::Output {
2054        self.features
2055            .check_value_type(ty)
2056            .map_err(|e| BinaryReaderError::new(e, self.offset))?;
2057        if !ty.is_reference_type() {
2058            bail!(self.offset, "invalid non-reference type in ref.null");
2059        }
2060        self.push_operand(ty)?;
2061        Ok(())
2062    }
2063    fn visit_ref_is_null(&mut self) -> Self::Output {
2064        match self.pop_operand(None)? {
2065            None => {}
2066            Some(t) => {
2067                if !t.is_reference_type() {
2068                    bail!(
2069                        self.offset,
2070                        "type mismatch: invalid reference type in ref.is_null"
2071                    );
2072                }
2073            }
2074        }
2075        self.push_operand(ValType::I32)?;
2076        Ok(())
2077    }
2078    fn visit_ref_func(&mut self, function_index: u32) -> Self::Output {
2079        if self.resources.type_of_function(function_index).is_none() {
2080            bail!(
2081                self.offset,
2082                "unknown function {}: function index out of bounds",
2083                function_index,
2084            );
2085        }
2086        if !self.resources.is_function_referenced(function_index) {
2087            bail!(self.offset, "undeclared function reference");
2088        }
2089        self.push_operand(ValType::FuncRef)?;
2090        Ok(())
2091    }
2092    fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output {
2093        let ty = self.check_memarg(memarg)?;
2094        self.pop_operand(Some(ty))?;
2095        self.push_operand(ValType::V128)?;
2096        Ok(())
2097    }
2098    fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output {
2099        let ty = self.check_memarg(memarg)?;
2100        self.pop_operand(Some(ValType::V128))?;
2101        self.pop_operand(Some(ty))?;
2102        Ok(())
2103    }
2104    fn visit_v128_const(&mut self, _value: V128) -> Self::Output {
2105        self.push_operand(ValType::V128)?;
2106        Ok(())
2107    }
2108    fn visit_i8x16_splat(&mut self) -> Self::Output {
2109        self.check_v128_splat(ValType::I32)
2110    }
2111    fn visit_i16x8_splat(&mut self) -> Self::Output {
2112        self.check_v128_splat(ValType::I32)
2113    }
2114    fn visit_i32x4_splat(&mut self) -> Self::Output {
2115        self.check_v128_splat(ValType::I32)
2116    }
2117    fn visit_i64x2_splat(&mut self) -> Self::Output {
2118        self.check_v128_splat(ValType::I64)
2119    }
2120    fn visit_f32x4_splat(&mut self) -> Self::Output {
2121        self.check_floats_enabled()?;
2122        self.check_v128_splat(ValType::F32)
2123    }
2124    fn visit_f64x2_splat(&mut self) -> Self::Output {
2125        self.check_floats_enabled()?;
2126        self.check_v128_splat(ValType::F64)
2127    }
2128    fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output {
2129        self.check_simd_lane_index(lane, 16)?;
2130        self.pop_operand(Some(ValType::V128))?;
2131        self.push_operand(ValType::I32)?;
2132        Ok(())
2133    }
2134    fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output {
2135        self.visit_i8x16_extract_lane_s(lane)
2136    }
2137    fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output {
2138        self.check_simd_lane_index(lane, 8)?;
2139        self.pop_operand(Some(ValType::V128))?;
2140        self.push_operand(ValType::I32)?;
2141        Ok(())
2142    }
2143    fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output {
2144        self.visit_i16x8_extract_lane_s(lane)
2145    }
2146    fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
2147        self.check_simd_lane_index(lane, 4)?;
2148        self.pop_operand(Some(ValType::V128))?;
2149        self.push_operand(ValType::I32)?;
2150        Ok(())
2151    }
2152    fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output {
2153        self.check_simd_lane_index(lane, 16)?;
2154        self.pop_operand(Some(ValType::I32))?;
2155        self.pop_operand(Some(ValType::V128))?;
2156        self.push_operand(ValType::V128)?;
2157        Ok(())
2158    }
2159    fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output {
2160        self.check_simd_lane_index(lane, 8)?;
2161        self.pop_operand(Some(ValType::I32))?;
2162        self.pop_operand(Some(ValType::V128))?;
2163        self.push_operand(ValType::V128)?;
2164        Ok(())
2165    }
2166    fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
2167        self.check_simd_lane_index(lane, 4)?;
2168        self.pop_operand(Some(ValType::I32))?;
2169        self.pop_operand(Some(ValType::V128))?;
2170        self.push_operand(ValType::V128)?;
2171        Ok(())
2172    }
2173    fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
2174        self.check_simd_lane_index(lane, 2)?;
2175        self.pop_operand(Some(ValType::V128))?;
2176        self.push_operand(ValType::I64)?;
2177        Ok(())
2178    }
2179    fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
2180        self.check_simd_lane_index(lane, 2)?;
2181        self.pop_operand(Some(ValType::I64))?;
2182        self.pop_operand(Some(ValType::V128))?;
2183        self.push_operand(ValType::V128)?;
2184        Ok(())
2185    }
2186    fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
2187        self.check_floats_enabled()?;
2188        self.check_simd_lane_index(lane, 4)?;
2189        self.pop_operand(Some(ValType::V128))?;
2190        self.push_operand(ValType::F32)?;
2191        Ok(())
2192    }
2193    fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
2194        self.check_floats_enabled()?;
2195        self.check_simd_lane_index(lane, 4)?;
2196        self.pop_operand(Some(ValType::F32))?;
2197        self.pop_operand(Some(ValType::V128))?;
2198        self.push_operand(ValType::V128)?;
2199        Ok(())
2200    }
2201    fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
2202        self.check_floats_enabled()?;
2203        self.check_simd_lane_index(lane, 2)?;
2204        self.pop_operand(Some(ValType::V128))?;
2205        self.push_operand(ValType::F64)?;
2206        Ok(())
2207    }
2208    fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
2209        self.check_floats_enabled()?;
2210        self.check_simd_lane_index(lane, 2)?;
2211        self.pop_operand(Some(ValType::F64))?;
2212        self.pop_operand(Some(ValType::V128))?;
2213        self.push_operand(ValType::V128)?;
2214        Ok(())
2215    }
2216    fn visit_f32x4_eq(&mut self) -> Self::Output {
2217        self.check_v128_fbinary_op()
2218    }
2219    fn visit_f32x4_ne(&mut self) -> Self::Output {
2220        self.check_v128_fbinary_op()
2221    }
2222    fn visit_f32x4_lt(&mut self) -> Self::Output {
2223        self.check_v128_fbinary_op()
2224    }
2225    fn visit_f32x4_gt(&mut self) -> Self::Output {
2226        self.check_v128_fbinary_op()
2227    }
2228    fn visit_f32x4_le(&mut self) -> Self::Output {
2229        self.check_v128_fbinary_op()
2230    }
2231    fn visit_f32x4_ge(&mut self) -> Self::Output {
2232        self.check_v128_fbinary_op()
2233    }
2234    fn visit_f64x2_eq(&mut self) -> Self::Output {
2235        self.check_v128_fbinary_op()
2236    }
2237    fn visit_f64x2_ne(&mut self) -> Self::Output {
2238        self.check_v128_fbinary_op()
2239    }
2240    fn visit_f64x2_lt(&mut self) -> Self::Output {
2241        self.check_v128_fbinary_op()
2242    }
2243    fn visit_f64x2_gt(&mut self) -> Self::Output {
2244        self.check_v128_fbinary_op()
2245    }
2246    fn visit_f64x2_le(&mut self) -> Self::Output {
2247        self.check_v128_fbinary_op()
2248    }
2249    fn visit_f64x2_ge(&mut self) -> Self::Output {
2250        self.check_v128_fbinary_op()
2251    }
2252    fn visit_f32x4_add(&mut self) -> Self::Output {
2253        self.check_v128_fbinary_op()
2254    }
2255    fn visit_f32x4_sub(&mut self) -> Self::Output {
2256        self.check_v128_fbinary_op()
2257    }
2258    fn visit_f32x4_mul(&mut self) -> Self::Output {
2259        self.check_v128_fbinary_op()
2260    }
2261    fn visit_f32x4_div(&mut self) -> Self::Output {
2262        self.check_v128_fbinary_op()
2263    }
2264    fn visit_f32x4_min(&mut self) -> Self::Output {
2265        self.check_v128_fbinary_op()
2266    }
2267    fn visit_f32x4_max(&mut self) -> Self::Output {
2268        self.check_v128_fbinary_op()
2269    }
2270    fn visit_f32x4_pmin(&mut self) -> Self::Output {
2271        self.check_v128_fbinary_op()
2272    }
2273    fn visit_f32x4_pmax(&mut self) -> Self::Output {
2274        self.check_v128_fbinary_op()
2275    }
2276    fn visit_f64x2_add(&mut self) -> Self::Output {
2277        self.check_v128_fbinary_op()
2278    }
2279    fn visit_f64x2_sub(&mut self) -> Self::Output {
2280        self.check_v128_fbinary_op()
2281    }
2282    fn visit_f64x2_mul(&mut self) -> Self::Output {
2283        self.check_v128_fbinary_op()
2284    }
2285    fn visit_f64x2_div(&mut self) -> Self::Output {
2286        self.check_v128_fbinary_op()
2287    }
2288    fn visit_f64x2_min(&mut self) -> Self::Output {
2289        self.check_v128_fbinary_op()
2290    }
2291    fn visit_f64x2_max(&mut self) -> Self::Output {
2292        self.check_v128_fbinary_op()
2293    }
2294    fn visit_f64x2_pmin(&mut self) -> Self::Output {
2295        self.check_v128_fbinary_op()
2296    }
2297    fn visit_f64x2_pmax(&mut self) -> Self::Output {
2298        self.check_v128_fbinary_op()
2299    }
2300    fn visit_f32x4_relaxed_min(&mut self) -> Self::Output {
2301        self.check_v128_relaxed_binary_op()
2302    }
2303    fn visit_f32x4_relaxed_max(&mut self) -> Self::Output {
2304        self.check_v128_relaxed_binary_op()
2305    }
2306    fn visit_f64x2_relaxed_min(&mut self) -> Self::Output {
2307        self.check_v128_relaxed_binary_op()
2308    }
2309    fn visit_f64x2_relaxed_max(&mut self) -> Self::Output {
2310        self.check_v128_relaxed_binary_op()
2311    }
2312    fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output {
2313        self.check_v128_relaxed_binary_op()
2314    }
2315    fn visit_i16x8_dot_i8x16_i7x16_s(&mut self) -> Self::Output {
2316        self.check_v128_relaxed_binary_op()
2317    }
2318    fn visit_i8x16_eq(&mut self) -> Self::Output {
2319        self.check_v128_binary_op()
2320    }
2321    fn visit_i8x16_ne(&mut self) -> Self::Output {
2322        self.check_v128_binary_op()
2323    }
2324    fn visit_i8x16_lt_s(&mut self) -> Self::Output {
2325        self.check_v128_binary_op()
2326    }
2327    fn visit_i8x16_lt_u(&mut self) -> Self::Output {
2328        self.check_v128_binary_op()
2329    }
2330    fn visit_i8x16_gt_s(&mut self) -> Self::Output {
2331        self.check_v128_binary_op()
2332    }
2333    fn visit_i8x16_gt_u(&mut self) -> Self::Output {
2334        self.check_v128_binary_op()
2335    }
2336    fn visit_i8x16_le_s(&mut self) -> Self::Output {
2337        self.check_v128_binary_op()
2338    }
2339    fn visit_i8x16_le_u(&mut self) -> Self::Output {
2340        self.check_v128_binary_op()
2341    }
2342    fn visit_i8x16_ge_s(&mut self) -> Self::Output {
2343        self.check_v128_binary_op()
2344    }
2345    fn visit_i8x16_ge_u(&mut self) -> Self::Output {
2346        self.check_v128_binary_op()
2347    }
2348    fn visit_i16x8_eq(&mut self) -> Self::Output {
2349        self.check_v128_binary_op()
2350    }
2351    fn visit_i16x8_ne(&mut self) -> Self::Output {
2352        self.check_v128_binary_op()
2353    }
2354    fn visit_i16x8_lt_s(&mut self) -> Self::Output {
2355        self.check_v128_binary_op()
2356    }
2357    fn visit_i16x8_lt_u(&mut self) -> Self::Output {
2358        self.check_v128_binary_op()
2359    }
2360    fn visit_i16x8_gt_s(&mut self) -> Self::Output {
2361        self.check_v128_binary_op()
2362    }
2363    fn visit_i16x8_gt_u(&mut self) -> Self::Output {
2364        self.check_v128_binary_op()
2365    }
2366    fn visit_i16x8_le_s(&mut self) -> Self::Output {
2367        self.check_v128_binary_op()
2368    }
2369    fn visit_i16x8_le_u(&mut self) -> Self::Output {
2370        self.check_v128_binary_op()
2371    }
2372    fn visit_i16x8_ge_s(&mut self) -> Self::Output {
2373        self.check_v128_binary_op()
2374    }
2375    fn visit_i16x8_ge_u(&mut self) -> Self::Output {
2376        self.check_v128_binary_op()
2377    }
2378    fn visit_i32x4_eq(&mut self) -> Self::Output {
2379        self.check_v128_binary_op()
2380    }
2381    fn visit_i32x4_ne(&mut self) -> Self::Output {
2382        self.check_v128_binary_op()
2383    }
2384    fn visit_i32x4_lt_s(&mut self) -> Self::Output {
2385        self.check_v128_binary_op()
2386    }
2387    fn visit_i32x4_lt_u(&mut self) -> Self::Output {
2388        self.check_v128_binary_op()
2389    }
2390    fn visit_i32x4_gt_s(&mut self) -> Self::Output {
2391        self.check_v128_binary_op()
2392    }
2393    fn visit_i32x4_gt_u(&mut self) -> Self::Output {
2394        self.check_v128_binary_op()
2395    }
2396    fn visit_i32x4_le_s(&mut self) -> Self::Output {
2397        self.check_v128_binary_op()
2398    }
2399    fn visit_i32x4_le_u(&mut self) -> Self::Output {
2400        self.check_v128_binary_op()
2401    }
2402    fn visit_i32x4_ge_s(&mut self) -> Self::Output {
2403        self.check_v128_binary_op()
2404    }
2405    fn visit_i32x4_ge_u(&mut self) -> Self::Output {
2406        self.check_v128_binary_op()
2407    }
2408    fn visit_i64x2_eq(&mut self) -> Self::Output {
2409        self.check_v128_binary_op()
2410    }
2411    fn visit_i64x2_ne(&mut self) -> Self::Output {
2412        self.check_v128_binary_op()
2413    }
2414    fn visit_i64x2_lt_s(&mut self) -> Self::Output {
2415        self.check_v128_binary_op()
2416    }
2417    fn visit_i64x2_gt_s(&mut self) -> Self::Output {
2418        self.check_v128_binary_op()
2419    }
2420    fn visit_i64x2_le_s(&mut self) -> Self::Output {
2421        self.check_v128_binary_op()
2422    }
2423    fn visit_i64x2_ge_s(&mut self) -> Self::Output {
2424        self.check_v128_binary_op()
2425    }
2426    fn visit_v128_and(&mut self) -> Self::Output {
2427        self.check_v128_binary_op()
2428    }
2429    fn visit_v128_andnot(&mut self) -> Self::Output {
2430        self.check_v128_binary_op()
2431    }
2432    fn visit_v128_or(&mut self) -> Self::Output {
2433        self.check_v128_binary_op()
2434    }
2435    fn visit_v128_xor(&mut self) -> Self::Output {
2436        self.check_v128_binary_op()
2437    }
2438    fn visit_i8x16_add(&mut self) -> Self::Output {
2439        self.check_v128_binary_op()
2440    }
2441    fn visit_i8x16_add_sat_s(&mut self) -> Self::Output {
2442        self.check_v128_binary_op()
2443    }
2444    fn visit_i8x16_add_sat_u(&mut self) -> Self::Output {
2445        self.check_v128_binary_op()
2446    }
2447    fn visit_i8x16_sub(&mut self) -> Self::Output {
2448        self.check_v128_binary_op()
2449    }
2450    fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output {
2451        self.check_v128_binary_op()
2452    }
2453    fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output {
2454        self.check_v128_binary_op()
2455    }
2456    fn visit_i8x16_min_s(&mut self) -> Self::Output {
2457        self.check_v128_binary_op()
2458    }
2459    fn visit_i8x16_min_u(&mut self) -> Self::Output {
2460        self.check_v128_binary_op()
2461    }
2462    fn visit_i8x16_max_s(&mut self) -> Self::Output {
2463        self.check_v128_binary_op()
2464    }
2465    fn visit_i8x16_max_u(&mut self) -> Self::Output {
2466        self.check_v128_binary_op()
2467    }
2468    fn visit_i16x8_add(&mut self) -> Self::Output {
2469        self.check_v128_binary_op()
2470    }
2471    fn visit_i16x8_add_sat_s(&mut self) -> Self::Output {
2472        self.check_v128_binary_op()
2473    }
2474    fn visit_i16x8_add_sat_u(&mut self) -> Self::Output {
2475        self.check_v128_binary_op()
2476    }
2477    fn visit_i16x8_sub(&mut self) -> Self::Output {
2478        self.check_v128_binary_op()
2479    }
2480    fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output {
2481        self.check_v128_binary_op()
2482    }
2483    fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output {
2484        self.check_v128_binary_op()
2485    }
2486    fn visit_i16x8_mul(&mut self) -> Self::Output {
2487        self.check_v128_binary_op()
2488    }
2489    fn visit_i16x8_min_s(&mut self) -> Self::Output {
2490        self.check_v128_binary_op()
2491    }
2492    fn visit_i16x8_min_u(&mut self) -> Self::Output {
2493        self.check_v128_binary_op()
2494    }
2495    fn visit_i16x8_max_s(&mut self) -> Self::Output {
2496        self.check_v128_binary_op()
2497    }
2498    fn visit_i16x8_max_u(&mut self) -> Self::Output {
2499        self.check_v128_binary_op()
2500    }
2501    fn visit_i32x4_add(&mut self) -> Self::Output {
2502        self.check_v128_binary_op()
2503    }
2504    fn visit_i32x4_sub(&mut self) -> Self::Output {
2505        self.check_v128_binary_op()
2506    }
2507    fn visit_i32x4_mul(&mut self) -> Self::Output {
2508        self.check_v128_binary_op()
2509    }
2510    fn visit_i32x4_min_s(&mut self) -> Self::Output {
2511        self.check_v128_binary_op()
2512    }
2513    fn visit_i32x4_min_u(&mut self) -> Self::Output {
2514        self.check_v128_binary_op()
2515    }
2516    fn visit_i32x4_max_s(&mut self) -> Self::Output {
2517        self.check_v128_binary_op()
2518    }
2519    fn visit_i32x4_max_u(&mut self) -> Self::Output {
2520        self.check_v128_binary_op()
2521    }
2522    fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output {
2523        self.check_v128_binary_op()
2524    }
2525    fn visit_i64x2_add(&mut self) -> Self::Output {
2526        self.check_v128_binary_op()
2527    }
2528    fn visit_i64x2_sub(&mut self) -> Self::Output {
2529        self.check_v128_binary_op()
2530    }
2531    fn visit_i64x2_mul(&mut self) -> Self::Output {
2532        self.check_v128_binary_op()
2533    }
2534    fn visit_i8x16_avgr_u(&mut self) -> Self::Output {
2535        self.check_v128_binary_op()
2536    }
2537    fn visit_i16x8_avgr_u(&mut self) -> Self::Output {
2538        self.check_v128_binary_op()
2539    }
2540    fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output {
2541        self.check_v128_binary_op()
2542    }
2543    fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output {
2544        self.check_v128_binary_op()
2545    }
2546    fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output {
2547        self.check_v128_binary_op()
2548    }
2549    fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output {
2550        self.check_v128_binary_op()
2551    }
2552    fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output {
2553        self.check_v128_binary_op()
2554    }
2555    fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output {
2556        self.check_v128_binary_op()
2557    }
2558    fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output {
2559        self.check_v128_binary_op()
2560    }
2561    fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output {
2562        self.check_v128_binary_op()
2563    }
2564    fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output {
2565        self.check_v128_binary_op()
2566    }
2567    fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output {
2568        self.check_v128_binary_op()
2569    }
2570    fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output {
2571        self.check_v128_binary_op()
2572    }
2573    fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output {
2574        self.check_v128_binary_op()
2575    }
2576    fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output {
2577        self.check_v128_binary_op()
2578    }
2579    fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output {
2580        self.check_v128_binary_op()
2581    }
2582    fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output {
2583        self.check_v128_binary_op()
2584    }
2585    fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output {
2586        self.check_v128_binary_op()
2587    }
2588    fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output {
2589        self.check_v128_binary_op()
2590    }
2591    fn visit_f32x4_ceil(&mut self) -> Self::Output {
2592        self.check_v128_funary_op()
2593    }
2594    fn visit_f32x4_floor(&mut self) -> Self::Output {
2595        self.check_v128_funary_op()
2596    }
2597    fn visit_f32x4_trunc(&mut self) -> Self::Output {
2598        self.check_v128_funary_op()
2599    }
2600    fn visit_f32x4_nearest(&mut self) -> Self::Output {
2601        self.check_v128_funary_op()
2602    }
2603    fn visit_f64x2_ceil(&mut self) -> Self::Output {
2604        self.check_v128_funary_op()
2605    }
2606    fn visit_f64x2_floor(&mut self) -> Self::Output {
2607        self.check_v128_funary_op()
2608    }
2609    fn visit_f64x2_trunc(&mut self) -> Self::Output {
2610        self.check_v128_funary_op()
2611    }
2612    fn visit_f64x2_nearest(&mut self) -> Self::Output {
2613        self.check_v128_funary_op()
2614    }
2615    fn visit_f32x4_abs(&mut self) -> Self::Output {
2616        self.check_v128_funary_op()
2617    }
2618    fn visit_f32x4_neg(&mut self) -> Self::Output {
2619        self.check_v128_funary_op()
2620    }
2621    fn visit_f32x4_sqrt(&mut self) -> Self::Output {
2622        self.check_v128_funary_op()
2623    }
2624    fn visit_f64x2_abs(&mut self) -> Self::Output {
2625        self.check_v128_funary_op()
2626    }
2627    fn visit_f64x2_neg(&mut self) -> Self::Output {
2628        self.check_v128_funary_op()
2629    }
2630    fn visit_f64x2_sqrt(&mut self) -> Self::Output {
2631        self.check_v128_funary_op()
2632    }
2633    fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output {
2634        self.check_v128_funary_op()
2635    }
2636    fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output {
2637        self.check_v128_funary_op()
2638    }
2639    fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output {
2640        self.check_v128_funary_op()
2641    }
2642    fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output {
2643        self.check_v128_funary_op()
2644    }
2645    fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output {
2646        self.check_v128_funary_op()
2647    }
2648    fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output {
2649        self.check_v128_funary_op()
2650    }
2651    fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output {
2652        self.check_v128_funary_op()
2653    }
2654    fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output {
2655        self.check_v128_funary_op()
2656    }
2657    fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output {
2658        self.check_v128_funary_op()
2659    }
2660    fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output {
2661        self.check_v128_funary_op()
2662    }
2663    fn visit_v128_not(&mut self) -> Self::Output {
2664        self.check_v128_unary_op()
2665    }
2666    fn visit_i8x16_abs(&mut self) -> Self::Output {
2667        self.check_v128_unary_op()
2668    }
2669    fn visit_i8x16_neg(&mut self) -> Self::Output {
2670        self.check_v128_unary_op()
2671    }
2672    fn visit_i8x16_popcnt(&mut self) -> Self::Output {
2673        self.check_v128_unary_op()
2674    }
2675    fn visit_i16x8_abs(&mut self) -> Self::Output {
2676        self.check_v128_unary_op()
2677    }
2678    fn visit_i16x8_neg(&mut self) -> Self::Output {
2679        self.check_v128_unary_op()
2680    }
2681    fn visit_i32x4_abs(&mut self) -> Self::Output {
2682        self.check_v128_unary_op()
2683    }
2684    fn visit_i32x4_neg(&mut self) -> Self::Output {
2685        self.check_v128_unary_op()
2686    }
2687    fn visit_i64x2_abs(&mut self) -> Self::Output {
2688        self.check_v128_unary_op()
2689    }
2690    fn visit_i64x2_neg(&mut self) -> Self::Output {
2691        self.check_v128_unary_op()
2692    }
2693    fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output {
2694        self.check_v128_unary_op()
2695    }
2696    fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output {
2697        self.check_v128_unary_op()
2698    }
2699    fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output {
2700        self.check_v128_unary_op()
2701    }
2702    fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output {
2703        self.check_v128_unary_op()
2704    }
2705    fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output {
2706        self.check_v128_unary_op()
2707    }
2708    fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output {
2709        self.check_v128_unary_op()
2710    }
2711    fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output {
2712        self.check_v128_unary_op()
2713    }
2714    fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output {
2715        self.check_v128_unary_op()
2716    }
2717    fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output {
2718        self.check_v128_unary_op()
2719    }
2720    fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output {
2721        self.check_v128_unary_op()
2722    }
2723    fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output {
2724        self.check_v128_unary_op()
2725    }
2726    fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output {
2727        self.check_v128_unary_op()
2728    }
2729    fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output {
2730        self.check_v128_unary_op()
2731    }
2732    fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output {
2733        self.check_v128_unary_op()
2734    }
2735    fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output {
2736        self.check_v128_unary_op()
2737    }
2738    fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output {
2739        self.check_v128_unary_op()
2740    }
2741    fn visit_i32x4_relaxed_trunc_sat_f32x4_s(&mut self) -> Self::Output {
2742        self.check_v128_relaxed_unary_op()
2743    }
2744    fn visit_i32x4_relaxed_trunc_sat_f32x4_u(&mut self) -> Self::Output {
2745        self.check_v128_relaxed_unary_op()
2746    }
2747    fn visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output {
2748        self.check_v128_relaxed_unary_op()
2749    }
2750    fn visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output {
2751        self.check_v128_relaxed_unary_op()
2752    }
2753    fn visit_v128_bitselect(&mut self) -> Self::Output {
2754        self.pop_operand(Some(ValType::V128))?;
2755        self.pop_operand(Some(ValType::V128))?;
2756        self.pop_operand(Some(ValType::V128))?;
2757        self.push_operand(ValType::V128)?;
2758        Ok(())
2759    }
2760    fn visit_f32x4_relaxed_fma(&mut self) -> Self::Output {
2761        self.check_v128_relaxed_ternary_op()
2762    }
2763    fn visit_f32x4_relaxed_fnma(&mut self) -> Self::Output {
2764        self.check_v128_relaxed_ternary_op()
2765    }
2766    fn visit_f64x2_relaxed_fma(&mut self) -> Self::Output {
2767        self.check_v128_relaxed_ternary_op()
2768    }
2769    fn visit_f64x2_relaxed_fnma(&mut self) -> Self::Output {
2770        self.check_v128_relaxed_ternary_op()
2771    }
2772    fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output {
2773        self.check_v128_relaxed_ternary_op()
2774    }
2775    fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output {
2776        self.check_v128_relaxed_ternary_op()
2777    }
2778    fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output {
2779        self.check_v128_relaxed_ternary_op()
2780    }
2781    fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output {
2782        self.check_v128_relaxed_ternary_op()
2783    }
2784    fn visit_i32x4_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output {
2785        self.check_v128_relaxed_ternary_op()
2786    }
2787    fn visit_f32x4_relaxed_dot_bf16x8_add_f32x4(&mut self) -> Self::Output {
2788        self.check_v128_relaxed_ternary_op()
2789    }
2790    fn visit_v128_any_true(&mut self) -> Self::Output {
2791        self.check_v128_bitmask_op()
2792    }
2793    fn visit_i8x16_all_true(&mut self) -> Self::Output {
2794        self.check_v128_bitmask_op()
2795    }
2796    fn visit_i8x16_bitmask(&mut self) -> Self::Output {
2797        self.check_v128_bitmask_op()
2798    }
2799    fn visit_i16x8_all_true(&mut self) -> Self::Output {
2800        self.check_v128_bitmask_op()
2801    }
2802    fn visit_i16x8_bitmask(&mut self) -> Self::Output {
2803        self.check_v128_bitmask_op()
2804    }
2805    fn visit_i32x4_all_true(&mut self) -> Self::Output {
2806        self.check_v128_bitmask_op()
2807    }
2808    fn visit_i32x4_bitmask(&mut self) -> Self::Output {
2809        self.check_v128_bitmask_op()
2810    }
2811    fn visit_i64x2_all_true(&mut self) -> Self::Output {
2812        self.check_v128_bitmask_op()
2813    }
2814    fn visit_i64x2_bitmask(&mut self) -> Self::Output {
2815        self.check_v128_bitmask_op()
2816    }
2817    fn visit_i8x16_shl(&mut self) -> Self::Output {
2818        self.check_v128_shift_op()
2819    }
2820    fn visit_i8x16_shr_s(&mut self) -> Self::Output {
2821        self.check_v128_shift_op()
2822    }
2823    fn visit_i8x16_shr_u(&mut self) -> Self::Output {
2824        self.check_v128_shift_op()
2825    }
2826    fn visit_i16x8_shl(&mut self) -> Self::Output {
2827        self.check_v128_shift_op()
2828    }
2829    fn visit_i16x8_shr_s(&mut self) -> Self::Output {
2830        self.check_v128_shift_op()
2831    }
2832    fn visit_i16x8_shr_u(&mut self) -> Self::Output {
2833        self.check_v128_shift_op()
2834    }
2835    fn visit_i32x4_shl(&mut self) -> Self::Output {
2836        self.check_v128_shift_op()
2837    }
2838    fn visit_i32x4_shr_s(&mut self) -> Self::Output {
2839        self.check_v128_shift_op()
2840    }
2841    fn visit_i32x4_shr_u(&mut self) -> Self::Output {
2842        self.check_v128_shift_op()
2843    }
2844    fn visit_i64x2_shl(&mut self) -> Self::Output {
2845        self.check_v128_shift_op()
2846    }
2847    fn visit_i64x2_shr_s(&mut self) -> Self::Output {
2848        self.check_v128_shift_op()
2849    }
2850    fn visit_i64x2_shr_u(&mut self) -> Self::Output {
2851        self.check_v128_shift_op()
2852    }
2853    fn visit_i8x16_swizzle(&mut self) -> Self::Output {
2854        self.pop_operand(Some(ValType::V128))?;
2855        self.pop_operand(Some(ValType::V128))?;
2856        self.push_operand(ValType::V128)?;
2857        Ok(())
2858    }
2859    fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output {
2860        self.pop_operand(Some(ValType::V128))?;
2861        self.pop_operand(Some(ValType::V128))?;
2862        self.push_operand(ValType::V128)?;
2863        Ok(())
2864    }
2865    fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output {
2866        self.pop_operand(Some(ValType::V128))?;
2867        self.pop_operand(Some(ValType::V128))?;
2868        for i in lanes {
2869            self.check_simd_lane_index(i, 32)?;
2870        }
2871        self.push_operand(ValType::V128)?;
2872        Ok(())
2873    }
2874    fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output {
2875        let ty = self.check_memarg(memarg)?;
2876        self.pop_operand(Some(ty))?;
2877        self.push_operand(ValType::V128)?;
2878        Ok(())
2879    }
2880    fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output {
2881        let ty = self.check_memarg(memarg)?;
2882        self.pop_operand(Some(ty))?;
2883        self.push_operand(ValType::V128)?;
2884        Ok(())
2885    }
2886    fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output {
2887        let ty = self.check_memarg(memarg)?;
2888        self.pop_operand(Some(ty))?;
2889        self.push_operand(ValType::V128)?;
2890        Ok(())
2891    }
2892    fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output {
2893        self.visit_v128_load32_splat(memarg)
2894    }
2895    fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output {
2896        self.check_v128_load_op(memarg)
2897    }
2898    fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output {
2899        self.check_v128_load_op(memarg)
2900    }
2901    fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output {
2902        self.check_v128_load_op(memarg)
2903    }
2904    fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output {
2905        self.check_v128_load_op(memarg)
2906    }
2907    fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output {
2908        self.check_v128_load_op(memarg)
2909    }
2910    fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output {
2911        self.check_v128_load_op(memarg)
2912    }
2913    fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output {
2914        self.check_v128_load_op(memarg)
2915    }
2916    fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output {
2917        self.check_v128_load_op(memarg)
2918    }
2919    fn visit_v128_load8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2920        let idx = self.check_memarg(memarg)?;
2921        self.check_simd_lane_index(lane, 16)?;
2922        self.pop_operand(Some(ValType::V128))?;
2923        self.pop_operand(Some(idx))?;
2924        self.push_operand(ValType::V128)?;
2925        Ok(())
2926    }
2927    fn visit_v128_load16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2928        let idx = self.check_memarg(memarg)?;
2929        self.check_simd_lane_index(lane, 8)?;
2930        self.pop_operand(Some(ValType::V128))?;
2931        self.pop_operand(Some(idx))?;
2932        self.push_operand(ValType::V128)?;
2933        Ok(())
2934    }
2935    fn visit_v128_load32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2936        let idx = self.check_memarg(memarg)?;
2937        self.check_simd_lane_index(lane, 4)?;
2938        self.pop_operand(Some(ValType::V128))?;
2939        self.pop_operand(Some(idx))?;
2940        self.push_operand(ValType::V128)?;
2941        Ok(())
2942    }
2943    fn visit_v128_load64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2944        let idx = self.check_memarg(memarg)?;
2945        self.check_simd_lane_index(lane, 2)?;
2946        self.pop_operand(Some(ValType::V128))?;
2947        self.pop_operand(Some(idx))?;
2948        self.push_operand(ValType::V128)?;
2949        Ok(())
2950    }
2951    fn visit_v128_store8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2952        let idx = self.check_memarg(memarg)?;
2953        self.check_simd_lane_index(lane, 16)?;
2954        self.pop_operand(Some(ValType::V128))?;
2955        self.pop_operand(Some(idx))?;
2956        Ok(())
2957    }
2958    fn visit_v128_store16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2959        let idx = self.check_memarg(memarg)?;
2960        self.check_simd_lane_index(lane, 8)?;
2961        self.pop_operand(Some(ValType::V128))?;
2962        self.pop_operand(Some(idx))?;
2963        Ok(())
2964    }
2965    fn visit_v128_store32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2966        let idx = self.check_memarg(memarg)?;
2967        self.check_simd_lane_index(lane, 4)?;
2968        self.pop_operand(Some(ValType::V128))?;
2969        self.pop_operand(Some(idx))?;
2970        Ok(())
2971    }
2972    fn visit_v128_store64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output {
2973        let idx = self.check_memarg(memarg)?;
2974        self.check_simd_lane_index(lane, 2)?;
2975        self.pop_operand(Some(ValType::V128))?;
2976        self.pop_operand(Some(idx))?;
2977        Ok(())
2978    }
2979    fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output {
2980        let ty = self.check_memory_index(mem)?;
2981        match self.resources.data_count() {
2982            None => bail!(self.offset, "data count section required"),
2983            Some(count) if segment < count => {}
2984            Some(_) => bail!(self.offset, "unknown data segment {}", segment),
2985        }
2986        self.pop_operand(Some(ValType::I32))?;
2987        self.pop_operand(Some(ValType::I32))?;
2988        self.pop_operand(Some(ty))?;
2989        Ok(())
2990    }
2991    fn visit_data_drop(&mut self, segment: u32) -> Self::Output {
2992        match self.resources.data_count() {
2993            None => bail!(self.offset, "data count section required"),
2994            Some(count) if segment < count => {}
2995            Some(_) => bail!(self.offset, "unknown data segment {}", segment),
2996        }
2997        Ok(())
2998    }
2999    fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output {
3000        let dst_ty = self.check_memory_index(dst)?;
3001        let src_ty = self.check_memory_index(src)?;
3002
3003        // The length operand here is the smaller of src/dst, which is
3004        // i32 if one is i32
3005        self.pop_operand(Some(match src_ty {
3006            ValType::I32 => ValType::I32,
3007            _ => dst_ty,
3008        }))?;
3009
3010        // ... and the offset into each memory is required to be
3011        // whatever the indexing type is for that memory
3012        self.pop_operand(Some(src_ty))?;
3013        self.pop_operand(Some(dst_ty))?;
3014        Ok(())
3015    }
3016    fn visit_memory_fill(&mut self, mem: u32) -> Self::Output {
3017        let ty = self.check_memory_index(mem)?;
3018        self.pop_operand(Some(ty))?;
3019        self.pop_operand(Some(ValType::I32))?;
3020        self.pop_operand(Some(ty))?;
3021        Ok(())
3022    }
3023    fn visit_memory_discard(&mut self, mem: u32) -> Self::Output {
3024        let ty = self.check_memory_index(mem)?;
3025        self.pop_operand(Some(ty))?;
3026        self.pop_operand(Some(ty))?;
3027        Ok(())
3028    }
3029    fn visit_table_init(&mut self, segment: u32, table: u32) -> Self::Output {
3030        if table > 0 {}
3031        let table = match self.resources.table_at(table) {
3032            Some(table) => table,
3033            None => bail!(
3034                self.offset,
3035                "unknown table {}: table index out of bounds",
3036                table
3037            ),
3038        };
3039        let segment_ty = match self.resources.element_type_at(segment) {
3040            Some(ty) => ty,
3041            None => bail!(
3042                self.offset,
3043                "unknown elem segment {}: segment index out of bounds",
3044                segment
3045            ),
3046        };
3047        if segment_ty != table.element_type {
3048            bail!(self.offset, "type mismatch");
3049        }
3050        self.pop_operand(Some(ValType::I32))?;
3051        self.pop_operand(Some(ValType::I32))?;
3052        self.pop_operand(Some(ValType::I32))?;
3053        Ok(())
3054    }
3055    fn visit_elem_drop(&mut self, segment: u32) -> Self::Output {
3056        if segment >= self.resources.element_count() {
3057            bail!(
3058                self.offset,
3059                "unknown elem segment {}: segment index out of bounds",
3060                segment
3061            );
3062        }
3063        Ok(())
3064    }
3065    fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output {
3066        if src_table > 0 || dst_table > 0 {}
3067        let (src, dst) = match (
3068            self.resources.table_at(src_table),
3069            self.resources.table_at(dst_table),
3070        ) {
3071            (Some(a), Some(b)) => (a, b),
3072            _ => bail!(self.offset, "table index out of bounds"),
3073        };
3074        if src.element_type != dst.element_type {
3075            bail!(self.offset, "type mismatch");
3076        }
3077        self.pop_operand(Some(ValType::I32))?;
3078        self.pop_operand(Some(ValType::I32))?;
3079        self.pop_operand(Some(ValType::I32))?;
3080        Ok(())
3081    }
3082    fn visit_table_get(&mut self, table: u32) -> Self::Output {
3083        let ty = match self.resources.table_at(table) {
3084            Some(ty) => ty.element_type,
3085            None => bail!(self.offset, "table index out of bounds"),
3086        };
3087        self.pop_operand(Some(ValType::I32))?;
3088        self.push_operand(ty)?;
3089        Ok(())
3090    }
3091    fn visit_table_set(&mut self, table: u32) -> Self::Output {
3092        let ty = match self.resources.table_at(table) {
3093            Some(ty) => ty.element_type,
3094            None => bail!(self.offset, "table index out of bounds"),
3095        };
3096        self.pop_operand(Some(ty))?;
3097        self.pop_operand(Some(ValType::I32))?;
3098        Ok(())
3099    }
3100    fn visit_table_grow(&mut self, table: u32) -> Self::Output {
3101        let ty = match self.resources.table_at(table) {
3102            Some(ty) => ty.element_type,
3103            None => bail!(self.offset, "table index out of bounds"),
3104        };
3105        self.pop_operand(Some(ValType::I32))?;
3106        self.pop_operand(Some(ty))?;
3107        self.push_operand(ValType::I32)?;
3108        Ok(())
3109    }
3110    fn visit_table_size(&mut self, table: u32) -> Self::Output {
3111        if self.resources.table_at(table).is_none() {
3112            bail!(self.offset, "table index out of bounds");
3113        }
3114        self.push_operand(ValType::I32)?;
3115        Ok(())
3116    }
3117    fn visit_table_fill(&mut self, table: u32) -> Self::Output {
3118        let ty = match self.resources.table_at(table) {
3119            Some(ty) => ty.element_type,
3120            None => bail!(self.offset, "table index out of bounds"),
3121        };
3122        self.pop_operand(Some(ValType::I32))?;
3123        self.pop_operand(Some(ty))?;
3124        self.pop_operand(Some(ValType::I32))?;
3125        Ok(())
3126    }
3127}
3128
3129#[derive(Clone)]
3130enum Either<A, B> {
3131    A(A),
3132    B(B),
3133}
3134
3135impl<A, B> Iterator for Either<A, B>
3136where
3137    A: Iterator,
3138    B: Iterator<Item = A::Item>,
3139{
3140    type Item = A::Item;
3141    fn next(&mut self) -> Option<A::Item> {
3142        match self {
3143            Either::A(a) => a.next(),
3144            Either::B(b) => b.next(),
3145        }
3146    }
3147}
3148
3149impl<A, B> DoubleEndedIterator for Either<A, B>
3150where
3151    A: DoubleEndedIterator,
3152    B: DoubleEndedIterator<Item = A::Item>,
3153{
3154    fn next_back(&mut self) -> Option<A::Item> {
3155        match self {
3156            Either::A(a) => a.next_back(),
3157            Either::B(b) => b.next_back(),
3158        }
3159    }
3160}
3161
3162impl<A, B> ExactSizeIterator for Either<A, B>
3163where
3164    A: ExactSizeIterator,
3165    B: ExactSizeIterator<Item = A::Item>,
3166{
3167    fn len(&self) -> usize {
3168        match self {
3169            Either::A(a) => a.len(),
3170            Either::B(b) => b.len(),
3171        }
3172    }
3173}
3174
3175trait PreciseIterator: ExactSizeIterator + DoubleEndedIterator + Clone {}
3176impl<T: ExactSizeIterator + DoubleEndedIterator + Clone> PreciseIterator for T {}
3177
3178impl Locals {
3179    /// Defines another group of `count` local variables of type `ty`.
3180    ///
3181    /// Returns `true` if the definition was successful. Local variable
3182    /// definition is unsuccessful in case the amount of total variables
3183    /// after definition exceeds the allowed maximum number.
3184    fn define(&mut self, count: u32, ty: ValType) -> bool {
3185        match self.num_locals.checked_add(count) {
3186            Some(n) => self.num_locals = n,
3187            None => return false,
3188        }
3189        if self.num_locals > (MAX_WASM_FUNCTION_LOCALS as u32) {
3190            return false;
3191        }
3192        for _ in 0..count {
3193            if self.first.len() >= MAX_LOCALS_TO_TRACK {
3194                break;
3195            }
3196            self.first.push(ty);
3197        }
3198        self.all.push((self.num_locals - 1, ty));
3199        true
3200    }
3201
3202    /// Returns the number of defined local variables.
3203    pub(super) fn len_locals(&self) -> u32 {
3204        self.num_locals
3205    }
3206
3207    /// Returns the type of the local variable at the given index if any.
3208    #[inline]
3209    pub(super) fn get(&self, idx: u32) -> Option<ValType> {
3210        match self.first.get(idx as usize) {
3211            Some(ty) => Some(*ty),
3212            None => self.get_bsearch(idx),
3213        }
3214    }
3215
3216    fn get_bsearch(&self, idx: u32) -> Option<ValType> {
3217        match self.all.binary_search_by_key(&idx, |(idx, _)| *idx) {
3218            // If this index would be inserted at the end of the list, then the
3219            // index is out of bounds and we return an error.
3220            Err(i) if i == self.all.len() => None,
3221
3222            // If `Ok` is returned we found the index exactly, or if `Err` is
3223            // returned the position is the one which is the least index
3224            // greater that `idx`, which is still the type of `idx` according
3225            // to our "compressed" representation. In both cases we access the
3226            // list at index `i`.
3227            Ok(i) | Err(i) => Some(self.all[i].1),
3228        }
3229    }
3230}