cargo / wasmparser / audit
cargo : wasmparser @ 0.244.0
PE Patrick Elsen signed 2026-05-28 published 2026-05-28

src/binary_reader.rs

2,110 lines · rust · 1 line annotation

/* Copyright 2018 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */use crate::prelude::*;use crate::{limits::*, *};use core::fmt;use core::marker;use core::ops::Range;use core::str;pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm";/// A binary reader for WebAssembly modules.#[derive(Debug, Clone)]pub struct BinaryReaderError {    // Wrap the actual error data in a `Box` so that the error is just one    // word. This means that we can continue returning small `Result`s in    // registers.    pub(crate) inner: Box<BinaryReaderErrorInner>,}#[derive(Debug, Clone)]pub(crate) struct BinaryReaderErrorInner {    pub(crate) message: String,    pub(crate) kind: BinaryReaderErrorKind,    pub(crate) offset: usize,    pub(crate) needed_hint: Option<usize>,}#[derive(Debug, Clone, Copy)]pub(crate) enum BinaryReaderErrorKind {    Custom,    Invalid,}/// The result for `BinaryReader` operations.pub type Result<T, E = BinaryReaderError> = core::result::Result<T, E>;impl core::error::Error for BinaryReaderError {}impl fmt::Display for BinaryReaderError {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(            f,            "{} (at offset 0x{:x})",            self.inner.message, self.inner.offset        )    }}impl BinaryReaderError {    #[cold]    pub(crate) fn _new(kind: BinaryReaderErrorKind, message: String, offset: usize) -> Self {        BinaryReaderError {            inner: Box::new(BinaryReaderErrorInner {                kind,                message,                offset,                needed_hint: None,            }),        }    }    #[cold]    pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {        Self::_new(BinaryReaderErrorKind::Custom, message.into(), offset)    }    #[cold]    pub(crate) fn invalid(msg: &'static str, offset: usize) -> Self {        Self::_new(BinaryReaderErrorKind::Invalid, msg.into(), offset)    }    #[cold]    pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: usize) -> Self {        BinaryReaderError::new(args.to_string(), offset)    }    #[cold]    pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self {        let mut err = BinaryReaderError::new("unexpected end-of-file", offset);        err.inner.needed_hint = Some(needed_hint);        err    }    pub(crate) fn kind(&mut self) -> BinaryReaderErrorKind {        self.inner.kind    }    /// Get this error's message.    pub fn message(&self) -> &str {        &self.inner.message    }    /// Get the offset within the Wasm binary where the error occurred.    pub fn offset(&self) -> usize {        self.inner.offset    }    #[cfg(all(feature = "validate", feature = "component-model"))]    pub(crate) fn add_context(&mut self, context: String) {        self.inner.message = format!("{context}\n{}", self.inner.message);    }    pub(crate) fn set_message(&mut self, message: &str) {        self.inner.message = message.to_string();    }}/// A binary reader of the WebAssembly structures and types.#[derive(Clone, Debug, Hash)]pub struct BinaryReader<'a> {    buffer: &'a [u8],    position: usize,    original_offset: usize,    // When the `features` feature is disabled then the `WasmFeatures` type    // still exists but this field is still omitted. When `features` is    // disabled then the only constructor of this type is `BinaryReader::new`    // which documents all known features being active. All known features    // being active isn't represented by `WasmFeatures` when the feature is    // disabled so the field is omitted here to prevent accidentally using the    // wrong listing of features.    //    // Feature accessors are defined by `foreach_wasm_feature!` below with a    // method-per-feature on `BinaryReader` which when the `features` feature    // is disabled returns `true` by default.    #[cfg(feature = "features")]    features: WasmFeatures,}impl<'a> BinaryReader<'a> {    /// Creates a new binary reader which will parse the `data` provided.    ///    /// The `original_offset` provided is used for byte offsets in errors that    /// are generated. That offset is added to the current position in `data`.    /// This can be helpful when `data` is just a window of a view into a larger    /// wasm binary perhaps not even entirely stored locally.    ///    /// The returned binary reader will have all features known to this crate    /// enabled. To reject binaries that aren't valid unless a certain feature    /// is enabled use the [`BinaryReader::new_features`] constructor instead.    pub fn new(data: &[u8], original_offset: usize) -> BinaryReader<'_> {        BinaryReader {            buffer: data,            position: 0,            original_offset,            #[cfg(feature = "features")]            features: WasmFeatures::all(),        }    }    /// Creates a new binary reader which will parse the `data` provided.    ///    /// The `original_offset` provided is used for byte offsets in errors that    /// are generated. That offset is added to the current position in `data`.    /// This can be helpful when `data` is just a window of a view into a larger    /// wasm binary perhaps not even entirely stored locally.    ///    /// The `features` argument provided controls which WebAssembly features are    /// active when parsing this data. Wasm features typically don't affect    /// parsing too much and are generally more applicable during    /// validation, but features and proposals will often reinterpret    /// previously-invalid constructs as now-valid things meaning something    /// slightly different. This means that invalid bytes before a feature may    /// now be interpreted differently after a feature is implemented. This    /// means that the set of activated features can affect what errors are    /// generated and when they are generated.    ///    /// In general it's safe to pass `WasmFeatures::all()` here. There's no    /// downside to enabling all features while parsing and only enabling a    /// subset of features during validation.    ///    /// Note that the activated set of features does not guarantee that    /// `BinaryReader` will return an error for disabled features. For example    /// if SIMD is disabled then SIMD instructions will still be parsed via    /// [`BinaryReader::visit_operator`]. Validation must still be performed to    /// provide a strict guarantee that if a feature is disabled that a binary    /// doesn't leverage the feature. The activated set of features here instead    /// only affects locations where preexisting bytes are reinterpreted in    /// different ways with future proposals, such as the `memarg` moving from a    /// 32-bit offset to a 64-bit offset with the `memory64` proposal.    #[cfg(feature = "features")]    pub fn new_features(        data: &[u8],        original_offset: usize,        features: WasmFeatures,    ) -> BinaryReader<'_> {        BinaryReader {            buffer: data,            position: 0,            original_offset,            features,        }    }    /// "Shrinks" this binary reader to retain only the buffer left-to-parse.    ///    /// The primary purpose of this method is to change the return value of the    /// `range()` method. That method returns the range of the original buffer    /// within the wasm binary so calling `range()` on the returned    /// `BinaryReader` will return a smaller range than if `range()` is called    /// on `self`.    ///    /// Otherwise parsing values from either `self` or the return value should    /// return the same thing.    pub(crate) fn shrink(&self) -> BinaryReader<'a> {        BinaryReader {            buffer: &self.buffer[self.position..],            position: 0,            original_offset: self.original_offset + self.position,            #[cfg(feature = "features")]            features: self.features,        }    }    /// Gets the original position of the binary reader.    #[inline]    pub fn original_position(&self) -> usize {        self.original_offset + self.position    }    /// Returns the currently active set of wasm features that this reader is    /// using while parsing.    ///    /// For more information see [`BinaryReader::new`].    #[cfg(feature = "features")]    pub fn features(&self) -> WasmFeatures {        self.features    }    /// Sets the wasm features active while parsing to the `features` specified.    ///    /// For more information see [`BinaryReader::new`].    #[cfg(feature = "features")]    pub fn set_features(&mut self, features: WasmFeatures) {        self.features = features;    }    /// Returns a range from the starting offset to the end of the buffer.    pub fn range(&self) -> Range<usize> {        self.original_offset..self.original_offset + self.buffer.len()    }    pub(crate) fn remaining_buffer(&self) -> &'a [u8] {        &self.buffer[self.position..]    }    fn ensure_has_byte(&self) -> Result<()> {        if self.position < self.buffer.len() {            Ok(())        } else {            Err(BinaryReaderError::eof(self.original_position(), 1))        }    }    pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result<()> {        if self.position + len <= self.buffer.len() {            Ok(())        } else {            let hint = self.position + len - self.buffer.len();            Err(BinaryReaderError::eof(self.original_position(), hint))        }    }    /// Reads a value of type `T` from this binary reader, advancing the    /// internal position in this reader forward as data is read.    #[inline]    pub fn read<T>(&mut self) -> Result<T>    where        T: FromReader<'a>,    {        T::from_reader(self)    }    pub(crate) fn read_u7(&mut self) -> Result<u8> {        let b = self.read_u8()?;        if (b & 0x80) != 0 {            return Err(BinaryReaderError::new(                "invalid u7",                self.original_position() - 1,            ));        }        Ok(b)    }    pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result<ExternalKind> {        match byte {            0x00 => Ok(ExternalKind::Func),            0x01 => Ok(ExternalKind::Table),            0x02 => Ok(ExternalKind::Memory),            0x03 => Ok(ExternalKind::Global),            0x04 => Ok(ExternalKind::Tag),            0x20 => Ok(ExternalKind::FuncExact),            x => Err(Self::invalid_leading_byte_error(x, "external kind", offset)),        }    }    /// Reads a variable-length 32-bit size from the byte stream while checking    /// against a limit.    pub fn read_size(&mut self, limit: usize, desc: &str) -> Result<usize> {        let pos = self.original_position();        let size = self.read_var_u32()? as usize;        if size > limit {            bail!(pos, "{desc} size is out of bounds");        }        Ok(size)    }    /// Reads a variable-length 32-bit size from the byte stream while checking    /// against a limit.    ///    /// Then reads that many values of type `T` and returns them as an iterator.    ///    /// Note that regardless of how many items are read from the returned    /// iterator the items will still be parsed from this reader.    pub fn read_iter<'me, T>(        &'me mut self,        limit: usize,        desc: &str,    ) -> Result<BinaryReaderIter<'a, 'me, T>>    where        T: FromReader<'a>,    {        let size = self.read_size(limit, desc)?;        Ok(BinaryReaderIter {            remaining: size,            reader: self,            _marker: marker::PhantomData,        })    }    /// Returns whether the `BinaryReader` has reached the end of the file.    #[inline]    pub fn eof(&self) -> bool {        self.position >= self.buffer.len()    }    /// Returns the `BinaryReader`'s current position.    #[inline]    pub fn current_position(&self) -> usize {        self.position    }    /// Returns the number of bytes remaining in the `BinaryReader`.    #[inline]    pub fn bytes_remaining(&self) -> usize {        self.buffer.len() - self.position    }    /// Advances the `BinaryReader` `size` bytes, and returns a slice from the    /// current position of `size` length.    ///    /// # Errors    /// If `size` exceeds the remaining length in `BinaryReader`.    pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {        self.ensure_has_bytes(size)?;        let start = self.position;        self.position += size;        Ok(&self.buffer[start..self.position])    }    /// Reads a length-prefixed list of bytes from this reader and returns a    /// new `BinaryReader` to read that list of bytes.    pub fn read_reader(&mut self) -> Result<BinaryReader<'a>> {        let size = self.read_var_u32()? as usize;        self.skip(|reader| {            reader.read_bytes(size)?;            Ok(())        })    }    /// Advances the `BinaryReader` four bytes and returns a `u32`.    /// # Errors    /// If `BinaryReader` has less than four bytes remaining.    pub fn read_u32(&mut self) -> Result<u32> {        self.ensure_has_bytes(4)?;        let word = u32::from_le_bytes(            self.buffer[self.position..self.position + 4]                .try_into()                .unwrap(),        );        self.position += 4;        Ok(word)    }    /// Advances the `BinaryReader` eight bytes and returns a `u64`.    /// # Errors    /// If `BinaryReader` has less than eight bytes remaining.    pub fn read_u64(&mut self) -> Result<u64> {        self.ensure_has_bytes(8)?;        let word = u64::from_le_bytes(            self.buffer[self.position..self.position + 8]                .try_into()                .unwrap(),        );        self.position += 8;        Ok(word)    }    /// Advances the `BinaryReader` a single byte.    ///    /// # Errors    ///    /// If `BinaryReader` has no bytes remaining.    #[inline]    pub fn read_u8(&mut self) -> Result<u8> {        let b = match self.buffer.get(self.position) {            Some(b) => *b,            None => return Err(self.eof_err()),        };        self.position += 1;        Ok(b)    }    #[cold]    fn eof_err(&self) -> BinaryReaderError {        BinaryReaderError::eof(self.original_position(), 1)    }    /// Advances the `BinaryReader` up to four bytes to parse a variable    /// length integer as a `u32`.    ///    /// # Errors    ///    /// If `BinaryReader` has less than one or up to four bytes remaining, or    /// the integer is larger than 32 bits.    #[inline]
    pub fn read_var_u32(&mut self) -> Result<u32> {        // Optimization for single byte i32.        let byte = self.read_u8()?;        if (byte & 0x80) == 0 {            Ok(u32::from(byte))        } else {            self.read_var_u32_big(byte)        }    }    fn read_var_u32_big(&mut self, byte: u8) -> Result<u32> {        let mut result = (byte & 0x7F) as u32;        let mut shift = 7;        loop {            let byte = self.read_u8()?;            result |= ((byte & 0x7F) as u32) << shift;            if shift >= 25 && (byte >> (32 - shift)) != 0 {                let msg = if byte & 0x80 != 0 {                    "invalid var_u32: integer representation too long"                } else {                    "invalid var_u32: integer too large"                };                // The continuation bit or unused bits are set.                return Err(BinaryReaderError::new(msg, self.original_position() - 1));            }            shift += 7;            if (byte & 0x80) == 0 {                break;            }        }        Ok(result)    }    /// Advances the `BinaryReader` up to four bytes to parse a variable    /// length integer as a `u64`.    ///    /// # Errors    ///    /// If `BinaryReader` has less than one or up to eight bytes remaining, or    /// the integer is larger than 64 bits.    #[inline]    pub fn read_var_u64(&mut self) -> Result<u64> {        // Optimization for single byte u64.        let byte = u64::from(self.read_u8()?);        if (byte & 0x80) == 0 {            Ok(byte)        } else {            self.read_var_u64_big(byte)        }    }    fn read_var_u64_big(&mut self, byte: u64) -> Result<u64> {        let mut result = byte & 0x7F;        let mut shift = 7;        loop {            let byte = u64::from(self.read_u8()?);            result |= (byte & 0x7F) << shift;            if shift >= 57 && (byte >> (64 - shift)) != 0 {                let msg = if byte & 0x80 != 0 {                    "invalid var_u64: integer representation too long"                } else {                    "invalid var_u64: integer too large"                };                // The continuation bit or unused bits are set.                return Err(BinaryReaderError::new(msg, self.original_position() - 1));            }            shift += 7;            if (byte & 0x80) == 0 {                break;            }        }        Ok(result)
Line 441–512

LEB128 decoding for var_u32 and var_u64. Both detect overlong encodings (continuation bit set on the final permitted byte) and integer-too-large (unused high bits non-zero). The shift-25 boundary check for u32 (byte >> (32 - shift) != 0) and the shift-57 boundary check for u64 are correct: at the final byte only the bits that fit in the target width may be set, and any continuation bit there is rejected. The signed variants (read_var_i32, read_var_s33, read_var_i64) apply the analogous sign-and-unused-bit check and sign-extend the result. All decoders advance only via read_u8, which is EOF-bounds-checked. Justifies parser-impl-safe.

    }    /// Executes `f` to skip some data in this binary reader and then returns a    /// reader which will read the skipped data.    pub fn skip(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result<Self> {        let start = self.position;        f(self)?;        let mut ret = self.clone();        ret.buffer = &self.buffer[start..self.position];        ret.position = 0;        ret.original_offset = self.original_offset + start;        Ok(ret)    }    /// Advances the `BinaryReader` past a WebAssembly string. This method does    /// not perform any utf-8 validation.    /// # Errors    /// If `BinaryReader` has less than four bytes, the string's length exceeds    /// the remaining bytes, or the string length    /// exceeds `limits::MAX_WASM_STRING_SIZE`.    pub fn skip_string(&mut self) -> Result<()> {        let len = self.read_var_u32()? as usize;        if len > MAX_WASM_STRING_SIZE {            return Err(BinaryReaderError::new(                "string size out of bounds",                self.original_position() - 1,            ));        }        self.ensure_has_bytes(len)?;        self.position += len;        Ok(())    }    /// Advances the `BinaryReader` up to four bytes to parse a variable    /// length integer as a `i32`.    /// # Errors    /// If `BinaryReader` has less than one or up to four bytes remaining, or    /// the integer is larger than 32 bits.    #[inline]    pub fn read_var_i32(&mut self) -> Result<i32> {        // Optimization for single byte i32.        let byte = self.read_u8()?;        if (byte & 0x80) == 0 {            Ok(((byte as i32) << 25) >> 25)        } else {            self.read_var_i32_big(byte)        }    }    fn read_var_i32_big(&mut self, byte: u8) -> Result<i32> {        let mut result = (byte & 0x7F) as i32;        let mut shift = 7;        loop {            let byte = self.read_u8()?;            result |= ((byte & 0x7F) as i32) << shift;            if shift >= 25 {                let continuation_bit = (byte & 0x80) != 0;                let sign_and_unused_bit = (byte << 1) as i8 >> (32 - shift);                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {                    let msg = if continuation_bit {                        "invalid var_i32: integer representation too long"                    } else {                        "invalid var_i32: integer too large"                    };                    return Err(BinaryReaderError::new(msg, self.original_position() - 1));                }                return Ok(result);            }            shift += 7;            if (byte & 0x80) == 0 {                break;            }        }        let ashift = 32 - shift;        Ok((result << ashift) >> ashift)    }    /// Advances the `BinaryReader` up to four bytes to parse a variable    /// length integer as a signed 33 bit integer, returned as a `i64`.    /// # Errors    /// If `BinaryReader` has less than one or up to five bytes remaining, or    /// the integer is larger than 33 bits.    pub fn read_var_s33(&mut self) -> Result<i64> {        // Optimization for single byte.        let byte = self.read_u8()?;        if (byte & 0x80) == 0 {            return Ok(((byte as i8) << 1) as i64 >> 1);        }        let mut result = (byte & 0x7F) as i64;        let mut shift = 7;        loop {            let byte = self.read_u8()?;            result |= ((byte & 0x7F) as i64) << shift;            if shift >= 25 {                let continuation_bit = (byte & 0x80) != 0;                let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {                    return Err(BinaryReaderError::new(                        "invalid var_s33: integer representation too long",                        self.original_position() - 1,                    ));                }                return Ok(result);            }            shift += 7;            if (byte & 0x80) == 0 {                break;            }        }        let ashift = 64 - shift;        Ok((result << ashift) >> ashift)    }    /// Advances the `BinaryReader` up to eight bytes to parse a variable    /// length integer as a 64 bit integer, returned as a `i64`.    /// # Errors    /// If `BinaryReader` has less than one or up to eight bytes remaining, or    /// the integer is larger than 64 bits.    pub fn read_var_i64(&mut self) -> Result<i64> {        let mut result: i64 = 0;        let mut shift = 0;        loop {            let byte = self.read_u8()?;            result |= i64::from(byte & 0x7F) << shift;            if shift >= 57 {                let continuation_bit = (byte & 0x80) != 0;                let sign_and_unused_bit = ((byte << 1) as i8) >> (64 - shift);                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {                    let msg = if continuation_bit {                        "invalid var_i64: integer representation too long"                    } else {                        "invalid var_i64: integer too large"                    };                    return Err(BinaryReaderError::new(msg, self.original_position() - 1));                }                return Ok(result);            }            shift += 7;            if (byte & 0x80) == 0 {                break;            }        }        let ashift = 64 - shift;        Ok((result << ashift) >> ashift)    }    /// Advances the `BinaryReader` four bytes to parse a 32 bit floating point    /// number, returned as `Ieee32`.    /// # Errors    /// If `BinaryReader` has less than four bytes remaining.    pub fn read_f32(&mut self) -> Result<Ieee32> {        let value = self.read_u32()?;        Ok(Ieee32(value))    }    /// Advances the `BinaryReader` eight bytes to parse a 64 bit floating point    /// number, returned as `Ieee64`.    /// # Errors    /// If `BinaryReader` has less than eight bytes remaining.    pub fn read_f64(&mut self) -> Result<Ieee64> {        let value = self.read_u64()?;        Ok(Ieee64(value))    }    /// (internal) Reads a fixed-size WebAssembly string from the module.    fn internal_read_string(&mut self, len: usize) -> Result<&'a str> {        let bytes = self.read_bytes(len)?;        str::from_utf8(bytes).map_err(|_| {            BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1)        })    }    /// Reads a WebAssembly string from the module.    ///    /// # Errors    ///    /// If `BinaryReader` has less than up to four bytes remaining, the string's    /// length exceeds the remaining bytes, the string's length exceeds    /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8.    pub fn read_string(&mut self) -> Result<&'a str> {        let len = self.read_var_u32()? as usize;        if len > MAX_WASM_STRING_SIZE {            return Err(BinaryReaderError::new(                "string size out of bounds",                self.original_position() - 1,            ));        }        return self.internal_read_string(len);    }    /// Reads a unlimited WebAssembly string from the module.    ///    /// Note that this is similar to [`BinaryReader::read_string`] except that    /// it will not limit the size of the returned string by    /// `limits::MAX_WASM_STRING_SIZE`.    pub fn read_unlimited_string(&mut self) -> Result<&'a str> {        let len = self.read_var_u32()? as usize;        return self.internal_read_string(len);    }    #[cold]    pub(crate) fn invalid_leading_byte<T>(&self, byte: u8, desc: &str) -> Result<T> {        Err(Self::invalid_leading_byte_error(            byte,            desc,            self.original_position() - 1,        ))    }    pub(crate) fn invalid_leading_byte_error(        byte: u8,        desc: &str,        offset: usize,    ) -> BinaryReaderError {        format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}")    }    pub(crate) fn peek(&self) -> Result<u8> {        self.ensure_has_byte()?;        Ok(self.buffer[self.position])    }    pub(crate) fn peek_bytes(&self, len: usize) -> Result<&[u8]> {        self.ensure_has_bytes(len)?;        Ok(&self.buffer[self.position..(self.position + len)])    }    pub(crate) fn read_block_type(&mut self) -> Result<BlockType> {        let b = self.peek()?;        // Block types are encoded as either 0x40, a `valtype`, or `s33`. All        // current `valtype` encodings are negative numbers when encoded with        // sleb128, but it's also required that valtype encodings are in their        // canonical form. For example an overlong encoding of -1 as `0xff 0x7f`        // is not valid and it is required to be `0x7f`. This means that we        // can't simply match on the `s33` that pops out below since reading the        // whole `s33` might read an overlong encoding.        //        // To test for this the first byte `b` is inspected. The highest bit,        // the continuation bit in LEB128 encoding, must be clear. The next bit,        // the sign bit, must be set to indicate that the number is negative. If        // these two conditions hold then we're guaranteed that this is a        // negative number.        //        // After this a value type is read directly instead of looking for an        // indexed value type.        if b & 0x80 == 0 && b & 0x40 != 0 {            if b == 0x40 {                self.position += 1;                return Ok(BlockType::Empty);            }            return Ok(BlockType::Type(self.read()?));        }        // Not empty or a singular type, so read the function type index        let idx = self.read_var_s33()?;        match u32::try_from(idx) {            Ok(idx) => Ok(BlockType::FuncType(idx)),            Err(_) => {                return Err(BinaryReaderError::new(                    "invalid function type",                    self.original_position(),                ));            }        }    }    /// Returns whether there is an `end` opcode followed by eof remaining in    /// this reader.    pub fn is_end_then_eof(&self) -> bool {        self.remaining_buffer() == &[0x0b]    }    pub(crate) fn read_header_version(&mut self) -> Result<u32> {        let magic_number = self.read_bytes(4)?;        if magic_number != WASM_MAGIC_NUMBER {            return Err(BinaryReaderError::new(                format!(                    "magic header not detected: bad magic number - expected={WASM_MAGIC_NUMBER:#x?} actual={magic_number:#x?}"                ),                self.original_position() - 4,            ));        }        self.read_u32()    }}// See documentation on `BinaryReader::features` for more on what's going on// here.macro_rules! define_feature_accessor {    ($feature:ident = $default:expr) => {        impl BinaryReader<'_> {            #[inline]            #[allow(dead_code)]            pub(crate) fn $feature(&self) -> bool {                #[cfg(feature = "features")]                {                    self.features.$feature()                }                #[cfg(not(feature = "features"))]                {                    true                }            }        }    };}super::features::foreach_wasm_feature!(define_feature_accessor);/// Iterator returned from [`BinaryReader::read_iter`].pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> {    remaining: usize,    pub(crate) reader: &'me mut BinaryReader<'a>,    _marker: marker::PhantomData<T>,}impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T>where    T: FromReader<'a>,{    type Item = Result<T>;    fn next(&mut self) -> Option<Result<T>> {        if self.remaining == 0 {            None        } else {            let ret = self.reader.read::<T>();            if ret.is_err() {                self.remaining = 0;            } else {                self.remaining -= 1;            }            Some(ret)        }    }    fn size_hint(&self) -> (usize, Option<usize>) {        (self.remaining, Some(self.remaining))    }}impl<'a, T> Drop for BinaryReaderIter<'a, '_, T>where    T: FromReader<'a>,{    fn drop(&mut self) {        while self.next().is_some() {            // ...        }    }}impl<'a> BinaryReader<'a> {    /// Function that must be called after the last opcode in an expression (instruction sequence)    /// has been processed. Returns an error if there is extra data after the operators.    pub fn finish_expression(&self, stack: &impl FrameStack) -> Result<()> {        if stack.current_frame().is_some() {            bail!(                self.original_position(),                "control frames remain at end of function body or expression"            );        }        if !self.eof() {            bail!(                self.original_position(),                "unexpected data at the end of operators"            );        }        Ok(())    }    #[inline]    fn expect_frame(&mut self, stack: &impl FrameStack, k: FrameKind, found: &str) -> Result<()> {        if stack.current_frame() == Some(k) {            return Ok(());        }        bail!(            self.original_position(),            "`{}` found outside `{:?}` block",            found,            k        );    }    /// Visit the next available operator with the specified [`VisitOperator`] instance    /// that is also a [`FrameStack`].    ///    /// See the documentation for [`OperatorsReader::visit_operator`] for a version that    /// does not require the visitor to implement [`FrameStack`].    pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output>    where        T: VisitOperator<'a> + FrameStack,    {        if visitor.current_frame().is_none() {            bail!(                self.original_position(),                "operators remaining after end of function body or expression"            );        }        let pos = self.original_position();        let code = self.read_u8()?;        Ok(match code {            0x00 => visitor.visit_unreachable(),            0x01 => visitor.visit_nop(),            0x02 => visitor.visit_block(self.read_block_type()?),            0x03 => visitor.visit_loop(self.read_block_type()?),            0x04 => visitor.visit_if(self.read_block_type()?),            0x05 => {                self.expect_frame(visitor, FrameKind::If, "else")?;                visitor.visit_else()            }            0x06 => {                if !self.legacy_exceptions() {                    bail!(                        pos,                        "legacy_exceptions feature required for try instruction"                    );                }                visitor.visit_try(self.read_block_type()?)            }            0x07 => {                if !self.legacy_exceptions() {                    bail!(                        pos,                        "legacy_exceptions feature required for catch instruction"                    );                }                match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch") {                    Ok(()) => (),                    Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch")?,                }                visitor.visit_catch(self.read_var_u32()?)            }            0x08 => visitor.visit_throw(self.read_var_u32()?),            0x09 => visitor.visit_rethrow(self.read_var_u32()?),            0x0a => visitor.visit_throw_ref(),            0x0b => visitor.visit_end(),            0x0c => visitor.visit_br(self.read_var_u32()?),            0x0d => visitor.visit_br_if(self.read_var_u32()?),            0x0e => visitor.visit_br_table(self.read_br_table()?),            0x0f => visitor.visit_return(),            0x10 => visitor.visit_call(self.read_var_u32()?),            0x11 => {                let index = self.read_var_u32()?;                let table = self.read_call_indirect_table_immediate()?;                visitor.visit_call_indirect(index, table)            }            0x12 => visitor.visit_return_call(self.read_var_u32()?),            0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?),            0x14 => visitor.visit_call_ref(self.read()?),            0x15 => visitor.visit_return_call_ref(self.read()?),            0x18 => {                self.expect_frame(visitor, FrameKind::LegacyTry, "delegate")?;                visitor.visit_delegate(self.read_var_u32()?)            }            0x19 => {                if !self.legacy_exceptions() {                    bail!(                        pos,                        "legacy_exceptions feature required for catch_all instruction"                    );                }                match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch_all") {                    Ok(()) => (),                    Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch_all")?,                }                visitor.visit_catch_all()            }            0x1a => visitor.visit_drop(),            0x1b => visitor.visit_select(),            0x1c => {                let result_count = self.read_size(MAX_WASM_SELECT_RESULT_SIZE, "select types")?;                if result_count == 1 {                    visitor.visit_typed_select(self.read()?)                } else {                    let mut results = Vec::new();                    results.reserve_exact(result_count);                    for _ in 0..result_count {                        results.push(self.read()?);                    }                    visitor.visit_typed_select_multi(results)                }            }            0x1f => visitor.visit_try_table(self.read()?),            0x20 => visitor.visit_local_get(self.read_var_u32()?),            0x21 => visitor.visit_local_set(self.read_var_u32()?),            0x22 => visitor.visit_local_tee(self.read_var_u32()?),            0x23 => visitor.visit_global_get(self.read_var_u32()?),            0x24 => visitor.visit_global_set(self.read_var_u32()?),            0x25 => visitor.visit_table_get(self.read_var_u32()?),            0x26 => visitor.visit_table_set(self.read_var_u32()?),            0x28 => visitor.visit_i32_load(self.read_memarg(2)?),            0x29 => visitor.visit_i64_load(self.read_memarg(3)?),            0x2a => visitor.visit_f32_load(self.read_memarg(2)?),            0x2b => visitor.visit_f64_load(self.read_memarg(3)?),            0x2c => visitor.visit_i32_load8_s(self.read_memarg(0)?),            0x2d => visitor.visit_i32_load8_u(self.read_memarg(0)?),            0x2e => visitor.visit_i32_load16_s(self.read_memarg(1)?),            0x2f => visitor.visit_i32_load16_u(self.read_memarg(1)?),            0x30 => visitor.visit_i64_load8_s(self.read_memarg(0)?),            0x31 => visitor.visit_i64_load8_u(self.read_memarg(0)?),            0x32 => visitor.visit_i64_load16_s(self.read_memarg(1)?),            0x33 => visitor.visit_i64_load16_u(self.read_memarg(1)?),            0x34 => visitor.visit_i64_load32_s(self.read_memarg(2)?),            0x35 => visitor.visit_i64_load32_u(self.read_memarg(2)?),            0x36 => visitor.visit_i32_store(self.read_memarg(2)?),            0x37 => visitor.visit_i64_store(self.read_memarg(3)?),            0x38 => visitor.visit_f32_store(self.read_memarg(2)?),            0x39 => visitor.visit_f64_store(self.read_memarg(3)?),            0x3a => visitor.visit_i32_store8(self.read_memarg(0)?),            0x3b => visitor.visit_i32_store16(self.read_memarg(1)?),            0x3c => visitor.visit_i64_store8(self.read_memarg(0)?),            0x3d => visitor.visit_i64_store16(self.read_memarg(1)?),            0x3e => visitor.visit_i64_store32(self.read_memarg(2)?),            0x3f => {                let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;                visitor.visit_memory_size(mem)            }            0x40 => {                let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;                visitor.visit_memory_grow(mem)            }            0x41 => visitor.visit_i32_const(self.read_var_i32()?),            0x42 => visitor.visit_i64_const(self.read_var_i64()?),            0x43 => visitor.visit_f32_const(self.read_f32()?),            0x44 => visitor.visit_f64_const(self.read_f64()?),            0x45 => visitor.visit_i32_eqz(),            0x46 => visitor.visit_i32_eq(),            0x47 => visitor.visit_i32_ne(),            0x48 => visitor.visit_i32_lt_s(),            0x49 => visitor.visit_i32_lt_u(),            0x4a => visitor.visit_i32_gt_s(),            0x4b => visitor.visit_i32_gt_u(),            0x4c => visitor.visit_i32_le_s(),            0x4d => visitor.visit_i32_le_u(),            0x4e => visitor.visit_i32_ge_s(),            0x4f => visitor.visit_i32_ge_u(),            0x50 => visitor.visit_i64_eqz(),            0x51 => visitor.visit_i64_eq(),            0x52 => visitor.visit_i64_ne(),            0x53 => visitor.visit_i64_lt_s(),            0x54 => visitor.visit_i64_lt_u(),            0x55 => visitor.visit_i64_gt_s(),            0x56 => visitor.visit_i64_gt_u(),            0x57 => visitor.visit_i64_le_s(),            0x58 => visitor.visit_i64_le_u(),            0x59 => visitor.visit_i64_ge_s(),            0x5a => visitor.visit_i64_ge_u(),            0x5b => visitor.visit_f32_eq(),            0x5c => visitor.visit_f32_ne(),            0x5d => visitor.visit_f32_lt(),            0x5e => visitor.visit_f32_gt(),            0x5f => visitor.visit_f32_le(),            0x60 => visitor.visit_f32_ge(),            0x61 => visitor.visit_f64_eq(),            0x62 => visitor.visit_f64_ne(),            0x63 => visitor.visit_f64_lt(),            0x64 => visitor.visit_f64_gt(),            0x65 => visitor.visit_f64_le(),            0x66 => visitor.visit_f64_ge(),            0x67 => visitor.visit_i32_clz(),            0x68 => visitor.visit_i32_ctz(),            0x69 => visitor.visit_i32_popcnt(),            0x6a => visitor.visit_i32_add(),            0x6b => visitor.visit_i32_sub(),            0x6c => visitor.visit_i32_mul(),            0x6d => visitor.visit_i32_div_s(),            0x6e => visitor.visit_i32_div_u(),            0x6f => visitor.visit_i32_rem_s(),            0x70 => visitor.visit_i32_rem_u(),            0x71 => visitor.visit_i32_and(),            0x72 => visitor.visit_i32_or(),            0x73 => visitor.visit_i32_xor(),            0x74 => visitor.visit_i32_shl(),            0x75 => visitor.visit_i32_shr_s(),            0x76 => visitor.visit_i32_shr_u(),            0x77 => visitor.visit_i32_rotl(),            0x78 => visitor.visit_i32_rotr(),            0x79 => visitor.visit_i64_clz(),            0x7a => visitor.visit_i64_ctz(),            0x7b => visitor.visit_i64_popcnt(),            0x7c => visitor.visit_i64_add(),            0x7d => visitor.visit_i64_sub(),            0x7e => visitor.visit_i64_mul(),            0x7f => visitor.visit_i64_div_s(),            0x80 => visitor.visit_i64_div_u(),            0x81 => visitor.visit_i64_rem_s(),            0x82 => visitor.visit_i64_rem_u(),            0x83 => visitor.visit_i64_and(),            0x84 => visitor.visit_i64_or(),            0x85 => visitor.visit_i64_xor(),            0x86 => visitor.visit_i64_shl(),            0x87 => visitor.visit_i64_shr_s(),            0x88 => visitor.visit_i64_shr_u(),            0x89 => visitor.visit_i64_rotl(),            0x8a => visitor.visit_i64_rotr(),            0x8b => visitor.visit_f32_abs(),            0x8c => visitor.visit_f32_neg(),            0x8d => visitor.visit_f32_ceil(),            0x8e => visitor.visit_f32_floor(),            0x8f => visitor.visit_f32_trunc(),            0x90 => visitor.visit_f32_nearest(),            0x91 => visitor.visit_f32_sqrt(),            0x92 => visitor.visit_f32_add(),            0x93 => visitor.visit_f32_sub(),            0x94 => visitor.visit_f32_mul(),            0x95 => visitor.visit_f32_div(),            0x96 => visitor.visit_f32_min(),            0x97 => visitor.visit_f32_max(),            0x98 => visitor.visit_f32_copysign(),            0x99 => visitor.visit_f64_abs(),            0x9a => visitor.visit_f64_neg(),            0x9b => visitor.visit_f64_ceil(),            0x9c => visitor.visit_f64_floor(),            0x9d => visitor.visit_f64_trunc(),            0x9e => visitor.visit_f64_nearest(),            0x9f => visitor.visit_f64_sqrt(),            0xa0 => visitor.visit_f64_add(),            0xa1 => visitor.visit_f64_sub(),            0xa2 => visitor.visit_f64_mul(),            0xa3 => visitor.visit_f64_div(),            0xa4 => visitor.visit_f64_min(),            0xa5 => visitor.visit_f64_max(),            0xa6 => visitor.visit_f64_copysign(),            0xa7 => visitor.visit_i32_wrap_i64(),            0xa8 => visitor.visit_i32_trunc_f32_s(),            0xa9 => visitor.visit_i32_trunc_f32_u(),            0xaa => visitor.visit_i32_trunc_f64_s(),            0xab => visitor.visit_i32_trunc_f64_u(),            0xac => visitor.visit_i64_extend_i32_s(),            0xad => visitor.visit_i64_extend_i32_u(),            0xae => visitor.visit_i64_trunc_f32_s(),            0xaf => visitor.visit_i64_trunc_f32_u(),            0xb0 => visitor.visit_i64_trunc_f64_s(),            0xb1 => visitor.visit_i64_trunc_f64_u(),            0xb2 => visitor.visit_f32_convert_i32_s(),            0xb3 => visitor.visit_f32_convert_i32_u(),            0xb4 => visitor.visit_f32_convert_i64_s(),            0xb5 => visitor.visit_f32_convert_i64_u(),            0xb6 => visitor.visit_f32_demote_f64(),            0xb7 => visitor.visit_f64_convert_i32_s(),            0xb8 => visitor.visit_f64_convert_i32_u(),            0xb9 => visitor.visit_f64_convert_i64_s(),            0xba => visitor.visit_f64_convert_i64_u(),            0xbb => visitor.visit_f64_promote_f32(),            0xbc => visitor.visit_i32_reinterpret_f32(),            0xbd => visitor.visit_i64_reinterpret_f64(),            0xbe => visitor.visit_f32_reinterpret_i32(),            0xbf => visitor.visit_f64_reinterpret_i64(),            0xc0 => visitor.visit_i32_extend8_s(),            0xc1 => visitor.visit_i32_extend16_s(),            0xc2 => visitor.visit_i64_extend8_s(),            0xc3 => visitor.visit_i64_extend16_s(),            0xc4 => visitor.visit_i64_extend32_s(),            0xd0 => visitor.visit_ref_null(self.read()?),            0xd1 => visitor.visit_ref_is_null(),            0xd2 => visitor.visit_ref_func(self.read_var_u32()?),            0xd3 => visitor.visit_ref_eq(),            0xd4 => visitor.visit_ref_as_non_null(),            0xd5 => visitor.visit_br_on_null(self.read_var_u32()?),            0xd6 => visitor.visit_br_on_non_null(self.read_var_u32()?),            0xe0 => visitor.visit_cont_new(self.read_var_u32()?),            0xe1 => visitor.visit_cont_bind(self.read_var_u32()?, self.read_var_u32()?),            0xe2 => visitor.visit_suspend(self.read_var_u32()?),            0xe3 => visitor.visit_resume(self.read_var_u32()?, self.read()?),            0xe4 => {                visitor.visit_resume_throw(self.read_var_u32()?, self.read_var_u32()?, self.read()?)            }            0xe5 => visitor.visit_switch(self.read_var_u32()?, self.read_var_u32()?),            0xfb => self.visit_0xfb_operator(pos, visitor)?,            0xfc => self.visit_0xfc_operator(pos, visitor)?,            0xfd => {                #[cfg(feature = "simd")]                if let Some(mut visitor) = visitor.simd_visitor() {                    return self.visit_0xfd_operator(pos, &mut visitor);                }                bail!(pos, "unexpected SIMD opcode: 0x{code:x}")            }            0xfe => self.visit_0xfe_operator(pos, visitor)?,            _ => bail!(pos, "illegal opcode: 0x{code:x}"),        })    }    fn visit_0xfb_operator<T>(        &mut self,        pos: usize,        visitor: &mut T,    ) -> Result<<T as VisitOperator<'a>>::Output>    where        T: VisitOperator<'a>,    {        let code = self.read_var_u32()?;        Ok(match code {            0x0 => {                let type_index = self.read_var_u32()?;                visitor.visit_struct_new(type_index)            }            0x01 => {                let type_index = self.read_var_u32()?;                visitor.visit_struct_new_default(type_index)            }            0x02 => {                let type_index = self.read_var_u32()?;                let field_index = self.read_var_u32()?;                visitor.visit_struct_get(type_index, field_index)            }            0x03 => {                let type_index = self.read_var_u32()?;                let field_index = self.read_var_u32()?;                visitor.visit_struct_get_s(type_index, field_index)            }            0x04 => {                let type_index = self.read_var_u32()?;                let field_index = self.read_var_u32()?;                visitor.visit_struct_get_u(type_index, field_index)            }            0x05 => {                let type_index = self.read_var_u32()?;                let field_index = self.read_var_u32()?;                visitor.visit_struct_set(type_index, field_index)            }            0x06 => {                let type_index = self.read_var_u32()?;                visitor.visit_array_new(type_index)            }            0x07 => {                let type_index = self.read_var_u32()?;                visitor.visit_array_new_default(type_index)            }            0x08 => {                let type_index = self.read_var_u32()?;                let n = self.read_var_u32()?;                visitor.visit_array_new_fixed(type_index, n)            }            0x09 => {                let type_index = self.read_var_u32()?;                let data_index = self.read_var_u32()?;                visitor.visit_array_new_data(type_index, data_index)            }            0x0a => {                let type_index = self.read_var_u32()?;                let elem_index = self.read_var_u32()?;                visitor.visit_array_new_elem(type_index, elem_index)            }            0x0b => {                let type_index = self.read_var_u32()?;                visitor.visit_array_get(type_index)            }            0x0c => {                let type_index = self.read_var_u32()?;                visitor.visit_array_get_s(type_index)            }            0x0d => {                let type_index = self.read_var_u32()?;                visitor.visit_array_get_u(type_index)            }            0x0e => {                let type_index = self.read_var_u32()?;                visitor.visit_array_set(type_index)            }            0x0f => visitor.visit_array_len(),            0x10 => {                let type_index = self.read_var_u32()?;                visitor.visit_array_fill(type_index)            }            0x11 => {                let type_index_dst = self.read_var_u32()?;                let type_index_src = self.read_var_u32()?;                visitor.visit_array_copy(type_index_dst, type_index_src)            }            0x12 => {                let type_index = self.read_var_u32()?;                let data_index = self.read_var_u32()?;                visitor.visit_array_init_data(type_index, data_index)            }            0x13 => {                let type_index = self.read_var_u32()?;                let elem_index = self.read_var_u32()?;                visitor.visit_array_init_elem(type_index, elem_index)            }            0x14 => visitor.visit_ref_test_non_null(self.read()?),            0x15 => visitor.visit_ref_test_nullable(self.read()?),            0x16 => visitor.visit_ref_cast_non_null(self.read()?),            0x17 => visitor.visit_ref_cast_nullable(self.read()?),            0x18 => {                let pos = self.original_position();                let cast_flags = self.read_u8()?;                let relative_depth = self.read_var_u32()?;                let (from_type_nullable, to_type_nullable) = match cast_flags {                    0b00 => (false, false),                    0b01 => (true, false),                    0b10 => (false, true),                    0b11 => (true, true),                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),                };                let from_heap_type = self.read()?;                let from_ref_type =                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                let to_heap_type = self.read()?;                let to_ref_type =                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                visitor.visit_br_on_cast(relative_depth, from_ref_type, to_ref_type)            }            0x19 => {                let pos = self.original_position();                let cast_flags = self.read_u8()?;                let relative_depth = self.read_var_u32()?;                let (from_type_nullable, to_type_nullable) = match cast_flags {                    0 => (false, false),                    1 => (true, false),                    2 => (false, true),                    3 => (true, true),                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),                };                let from_heap_type = self.read()?;                let from_ref_type =                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                let to_heap_type = self.read()?;                let to_ref_type =                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                visitor.visit_br_on_cast_fail(relative_depth, from_ref_type, to_ref_type)            }            0x1a => visitor.visit_any_convert_extern(),            0x1b => visitor.visit_extern_convert_any(),            0x1c => visitor.visit_ref_i31(),            0x1d => visitor.visit_i31_get_s(),            0x1e => visitor.visit_i31_get_u(),            0x20 => {                let type_index = self.read_var_u32()?;                visitor.visit_struct_new_desc(type_index)            }            0x21 => {                let type_index = self.read_var_u32()?;                visitor.visit_struct_new_default_desc(type_index)            }            0x22 => visitor.visit_ref_get_desc(self.read()?),            0x23 => visitor.visit_ref_cast_desc_non_null(self.read()?),            0x24 => visitor.visit_ref_cast_desc_nullable(self.read()?),            0x25 => {                let pos = self.original_position();                let cast_flags = self.read_u8()?;                let relative_depth = self.read_var_u32()?;                let (from_type_nullable, to_type_nullable) = match cast_flags {                    0b00 => (false, false),                    0b01 => (true, false),                    0b10 => (false, true),                    0b11 => (true, true),                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),                };                let from_heap_type = self.read()?;                let from_ref_type =                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                let to_heap_type = self.read()?;                let to_ref_type =                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                visitor.visit_br_on_cast_desc(relative_depth, from_ref_type, to_ref_type)            }            0x26 => {                let pos = self.original_position();                let cast_flags = self.read_u8()?;                let relative_depth = self.read_var_u32()?;                let (from_type_nullable, to_type_nullable) = match cast_flags {                    0 => (false, false),                    1 => (true, false),                    2 => (false, true),                    3 => (true, true),                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),                };                let from_heap_type = self.read()?;                let from_ref_type =                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                let to_heap_type = self.read()?;                let to_ref_type =                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {                        format_err!(pos, "implementation error: type index too large")                    })?;                visitor.visit_br_on_cast_desc_fail(relative_depth, from_ref_type, to_ref_type)            }            _ => bail!(pos, "unknown 0xfb subopcode: 0x{code:x}"),        })    }    fn visit_0xfc_operator<T>(        &mut self,        pos: usize,        visitor: &mut T,    ) -> Result<<T as VisitOperator<'a>>::Output>    where        T: VisitOperator<'a>,    {        let code = self.read_var_u32()?;        Ok(match code {            0x00 => visitor.visit_i32_trunc_sat_f32_s(),            0x01 => visitor.visit_i32_trunc_sat_f32_u(),            0x02 => visitor.visit_i32_trunc_sat_f64_s(),            0x03 => visitor.visit_i32_trunc_sat_f64_u(),            0x04 => visitor.visit_i64_trunc_sat_f32_s(),            0x05 => visitor.visit_i64_trunc_sat_f32_u(),            0x06 => visitor.visit_i64_trunc_sat_f64_s(),            0x07 => visitor.visit_i64_trunc_sat_f64_u(),            0x08 => {                let segment = self.read_var_u32()?;                let mem = self.read_var_u32()?;                visitor.visit_memory_init(segment, mem)            }            0x09 => {                let segment = self.read_var_u32()?;                visitor.visit_data_drop(segment)            }            0x0a => {                let dst = self.read_var_u32()?;                let src = self.read_var_u32()?;                visitor.visit_memory_copy(dst, src)            }            0x0b => {                let mem = self.read_var_u32()?;                visitor.visit_memory_fill(mem)            }            0x0c => {                let segment = self.read_var_u32()?;                let table = self.read_var_u32()?;                visitor.visit_table_init(segment, table)            }            0x0d => {                let segment = self.read_var_u32()?;                visitor.visit_elem_drop(segment)            }            0x0e => {                let dst_table = self.read_var_u32()?;                let src_table = self.read_var_u32()?;                visitor.visit_table_copy(dst_table, src_table)            }            0x0f => {                let table = self.read_var_u32()?;                visitor.visit_table_grow(table)            }            0x10 => {                let table = self.read_var_u32()?;                visitor.visit_table_size(table)            }            0x11 => {                let table = self.read_var_u32()?;                visitor.visit_table_fill(table)            }            0x12 => {                let mem = self.read_var_u32()?;                visitor.visit_memory_discard(mem)            }            0x13 => visitor.visit_i64_add128(),            0x14 => visitor.visit_i64_sub128(),            0x15 => visitor.visit_i64_mul_wide_s(),            0x16 => visitor.visit_i64_mul_wide_u(),            _ => bail!(pos, "unknown 0xfc subopcode: 0x{code:x}"),        })    }    #[cfg(feature = "simd")]    pub(super) fn visit_0xfd_operator<T>(        &mut self,        pos: usize,        visitor: &mut T,    ) -> Result<<T as VisitOperator<'a>>::Output>    where        T: VisitSimdOperator<'a>,    {        let code = self.read_var_u32()?;        Ok(match code {            0x00 => visitor.visit_v128_load(self.read_memarg(4)?),            0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?),            0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?),            0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?),            0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?),            0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?),            0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?),            0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?),            0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?),            0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?),            0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?),            0x0b => visitor.visit_v128_store(self.read_memarg(4)?),            0x0c => visitor.visit_v128_const(self.read_v128()?),            0x0d => {                let mut lanes: [u8; 16] = [0; 16];                for lane in &mut lanes {                    *lane = self.read_lane_index()?                }                visitor.visit_i8x16_shuffle(lanes)            }            0x0e => visitor.visit_i8x16_swizzle(),            0x0f => visitor.visit_i8x16_splat(),            0x10 => visitor.visit_i16x8_splat(),            0x11 => visitor.visit_i32x4_splat(),            0x12 => visitor.visit_i64x2_splat(),            0x13 => visitor.visit_f32x4_splat(),            0x14 => visitor.visit_f64x2_splat(),            0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index()?),            0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index()?),            0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index()?),            0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index()?),            0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index()?),            0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index()?),            0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index()?),            0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index()?),            0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index()?),            0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index()?),            0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index()?),            0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index()?),            0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index()?),            0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index()?),            0x23 => visitor.visit_i8x16_eq(),            0x24 => visitor.visit_i8x16_ne(),            0x25 => visitor.visit_i8x16_lt_s(),            0x26 => visitor.visit_i8x16_lt_u(),            0x27 => visitor.visit_i8x16_gt_s(),            0x28 => visitor.visit_i8x16_gt_u(),            0x29 => visitor.visit_i8x16_le_s(),            0x2a => visitor.visit_i8x16_le_u(),            0x2b => visitor.visit_i8x16_ge_s(),            0x2c => visitor.visit_i8x16_ge_u(),            0x2d => visitor.visit_i16x8_eq(),            0x2e => visitor.visit_i16x8_ne(),            0x2f => visitor.visit_i16x8_lt_s(),            0x30 => visitor.visit_i16x8_lt_u(),            0x31 => visitor.visit_i16x8_gt_s(),            0x32 => visitor.visit_i16x8_gt_u(),            0x33 => visitor.visit_i16x8_le_s(),            0x34 => visitor.visit_i16x8_le_u(),            0x35 => visitor.visit_i16x8_ge_s(),            0x36 => visitor.visit_i16x8_ge_u(),            0x37 => visitor.visit_i32x4_eq(),            0x38 => visitor.visit_i32x4_ne(),            0x39 => visitor.visit_i32x4_lt_s(),            0x3a => visitor.visit_i32x4_lt_u(),            0x3b => visitor.visit_i32x4_gt_s(),            0x3c => visitor.visit_i32x4_gt_u(),            0x3d => visitor.visit_i32x4_le_s(),            0x3e => visitor.visit_i32x4_le_u(),            0x3f => visitor.visit_i32x4_ge_s(),            0x40 => visitor.visit_i32x4_ge_u(),            0x41 => visitor.visit_f32x4_eq(),            0x42 => visitor.visit_f32x4_ne(),            0x43 => visitor.visit_f32x4_lt(),            0x44 => visitor.visit_f32x4_gt(),            0x45 => visitor.visit_f32x4_le(),            0x46 => visitor.visit_f32x4_ge(),            0x47 => visitor.visit_f64x2_eq(),            0x48 => visitor.visit_f64x2_ne(),            0x49 => visitor.visit_f64x2_lt(),            0x4a => visitor.visit_f64x2_gt(),            0x4b => visitor.visit_f64x2_le(),            0x4c => visitor.visit_f64x2_ge(),            0x4d => visitor.visit_v128_not(),            0x4e => visitor.visit_v128_and(),            0x4f => visitor.visit_v128_andnot(),            0x50 => visitor.visit_v128_or(),            0x51 => visitor.visit_v128_xor(),            0x52 => visitor.visit_v128_bitselect(),            0x53 => visitor.visit_v128_any_true(),            0x54 => {                let memarg = self.read_memarg(0)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_load8_lane(memarg, lane)            }            0x55 => {                let memarg = self.read_memarg(1)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_load16_lane(memarg, lane)            }            0x56 => {                let memarg = self.read_memarg(2)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_load32_lane(memarg, lane)            }            0x57 => {                let memarg = self.read_memarg(3)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_load64_lane(memarg, lane)            }            0x58 => {                let memarg = self.read_memarg(0)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_store8_lane(memarg, lane)            }            0x59 => {                let memarg = self.read_memarg(1)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_store16_lane(memarg, lane)            }            0x5a => {                let memarg = self.read_memarg(2)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_store32_lane(memarg, lane)            }            0x5b => {                let memarg = self.read_memarg(3)?;                let lane = self.read_lane_index()?;                visitor.visit_v128_store64_lane(memarg, lane)            }            0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?),            0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?),            0x5e => visitor.visit_f32x4_demote_f64x2_zero(),            0x5f => visitor.visit_f64x2_promote_low_f32x4(),            0x60 => visitor.visit_i8x16_abs(),            0x61 => visitor.visit_i8x16_neg(),            0x62 => visitor.visit_i8x16_popcnt(),            0x63 => visitor.visit_i8x16_all_true(),            0x64 => visitor.visit_i8x16_bitmask(),            0x65 => visitor.visit_i8x16_narrow_i16x8_s(),            0x66 => visitor.visit_i8x16_narrow_i16x8_u(),            0x67 => visitor.visit_f32x4_ceil(),            0x68 => visitor.visit_f32x4_floor(),            0x69 => visitor.visit_f32x4_trunc(),            0x6a => visitor.visit_f32x4_nearest(),            0x6b => visitor.visit_i8x16_shl(),            0x6c => visitor.visit_i8x16_shr_s(),            0x6d => visitor.visit_i8x16_shr_u(),            0x6e => visitor.visit_i8x16_add(),            0x6f => visitor.visit_i8x16_add_sat_s(),            0x70 => visitor.visit_i8x16_add_sat_u(),            0x71 => visitor.visit_i8x16_sub(),            0x72 => visitor.visit_i8x16_sub_sat_s(),            0x73 => visitor.visit_i8x16_sub_sat_u(),            0x74 => visitor.visit_f64x2_ceil(),            0x75 => visitor.visit_f64x2_floor(),            0x76 => visitor.visit_i8x16_min_s(),            0x77 => visitor.visit_i8x16_min_u(),            0x78 => visitor.visit_i8x16_max_s(),            0x79 => visitor.visit_i8x16_max_u(),            0x7a => visitor.visit_f64x2_trunc(),            0x7b => visitor.visit_i8x16_avgr_u(),            0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(),            0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(),            0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(),            0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(),            0x80 => visitor.visit_i16x8_abs(),            0x81 => visitor.visit_i16x8_neg(),            0x82 => visitor.visit_i16x8_q15mulr_sat_s(),            0x83 => visitor.visit_i16x8_all_true(),            0x84 => visitor.visit_i16x8_bitmask(),            0x85 => visitor.visit_i16x8_narrow_i32x4_s(),            0x86 => visitor.visit_i16x8_narrow_i32x4_u(),            0x87 => visitor.visit_i16x8_extend_low_i8x16_s(),            0x88 => visitor.visit_i16x8_extend_high_i8x16_s(),            0x89 => visitor.visit_i16x8_extend_low_i8x16_u(),            0x8a => visitor.visit_i16x8_extend_high_i8x16_u(),            0x8b => visitor.visit_i16x8_shl(),            0x8c => visitor.visit_i16x8_shr_s(),            0x8d => visitor.visit_i16x8_shr_u(),            0x8e => visitor.visit_i16x8_add(),            0x8f => visitor.visit_i16x8_add_sat_s(),            0x90 => visitor.visit_i16x8_add_sat_u(),            0x91 => visitor.visit_i16x8_sub(),            0x92 => visitor.visit_i16x8_sub_sat_s(),            0x93 => visitor.visit_i16x8_sub_sat_u(),            0x94 => visitor.visit_f64x2_nearest(),            0x95 => visitor.visit_i16x8_mul(),            0x96 => visitor.visit_i16x8_min_s(),            0x97 => visitor.visit_i16x8_min_u(),            0x98 => visitor.visit_i16x8_max_s(),            0x99 => visitor.visit_i16x8_max_u(),            0x9b => visitor.visit_i16x8_avgr_u(),            0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(),            0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(),            0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(),            0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(),            0xa0 => visitor.visit_i32x4_abs(),            0xa1 => visitor.visit_i32x4_neg(),            0xa3 => visitor.visit_i32x4_all_true(),            0xa4 => visitor.visit_i32x4_bitmask(),            0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(),            0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(),            0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(),            0xaa => visitor.visit_i32x4_extend_high_i16x8_u(),            0xab => visitor.visit_i32x4_shl(),            0xac => visitor.visit_i32x4_shr_s(),            0xad => visitor.visit_i32x4_shr_u(),            0xae => visitor.visit_i32x4_add(),            0xb1 => visitor.visit_i32x4_sub(),            0xb5 => visitor.visit_i32x4_mul(),            0xb6 => visitor.visit_i32x4_min_s(),            0xb7 => visitor.visit_i32x4_min_u(),            0xb8 => visitor.visit_i32x4_max_s(),            0xb9 => visitor.visit_i32x4_max_u(),            0xba => visitor.visit_i32x4_dot_i16x8_s(),            0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(),            0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(),            0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(),            0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(),            0xc0 => visitor.visit_i64x2_abs(),            0xc1 => visitor.visit_i64x2_neg(),            0xc3 => visitor.visit_i64x2_all_true(),            0xc4 => visitor.visit_i64x2_bitmask(),            0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(),            0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(),            0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(),            0xca => visitor.visit_i64x2_extend_high_i32x4_u(),            0xcb => visitor.visit_i64x2_shl(),            0xcc => visitor.visit_i64x2_shr_s(),            0xcd => visitor.visit_i64x2_shr_u(),            0xce => visitor.visit_i64x2_add(),            0xd1 => visitor.visit_i64x2_sub(),            0xd5 => visitor.visit_i64x2_mul(),            0xd6 => visitor.visit_i64x2_eq(),            0xd7 => visitor.visit_i64x2_ne(),            0xd8 => visitor.visit_i64x2_lt_s(),            0xd9 => visitor.visit_i64x2_gt_s(),            0xda => visitor.visit_i64x2_le_s(),            0xdb => visitor.visit_i64x2_ge_s(),            0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(),            0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(),            0xde => visitor.visit_i64x2_extmul_low_i32x4_u(),            0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(),            0xe0 => visitor.visit_f32x4_abs(),            0xe1 => visitor.visit_f32x4_neg(),            0xe3 => visitor.visit_f32x4_sqrt(),            0xe4 => visitor.visit_f32x4_add(),            0xe5 => visitor.visit_f32x4_sub(),            0xe6 => visitor.visit_f32x4_mul(),            0xe7 => visitor.visit_f32x4_div(),            0xe8 => visitor.visit_f32x4_min(),            0xe9 => visitor.visit_f32x4_max(),            0xea => visitor.visit_f32x4_pmin(),            0xeb => visitor.visit_f32x4_pmax(),            0xec => visitor.visit_f64x2_abs(),            0xed => visitor.visit_f64x2_neg(),            0xef => visitor.visit_f64x2_sqrt(),            0xf0 => visitor.visit_f64x2_add(),            0xf1 => visitor.visit_f64x2_sub(),            0xf2 => visitor.visit_f64x2_mul(),            0xf3 => visitor.visit_f64x2_div(),            0xf4 => visitor.visit_f64x2_min(),            0xf5 => visitor.visit_f64x2_max(),            0xf6 => visitor.visit_f64x2_pmin(),            0xf7 => visitor.visit_f64x2_pmax(),            0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(),            0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(),            0xfa => visitor.visit_f32x4_convert_i32x4_s(),            0xfb => visitor.visit_f32x4_convert_i32x4_u(),            0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(),            0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(),            0xfe => visitor.visit_f64x2_convert_low_i32x4_s(),            0xff => visitor.visit_f64x2_convert_low_i32x4_u(),            0x100 => visitor.visit_i8x16_relaxed_swizzle(),            0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(),            0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(),            0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(),            0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(),            0x105 => visitor.visit_f32x4_relaxed_madd(),            0x106 => visitor.visit_f32x4_relaxed_nmadd(),            0x107 => visitor.visit_f64x2_relaxed_madd(),            0x108 => visitor.visit_f64x2_relaxed_nmadd(),            0x109 => visitor.visit_i8x16_relaxed_laneselect(),            0x10a => visitor.visit_i16x8_relaxed_laneselect(),            0x10b => visitor.visit_i32x4_relaxed_laneselect(),            0x10c => visitor.visit_i64x2_relaxed_laneselect(),            0x10d => visitor.visit_f32x4_relaxed_min(),            0x10e => visitor.visit_f32x4_relaxed_max(),            0x10f => visitor.visit_f64x2_relaxed_min(),            0x110 => visitor.visit_f64x2_relaxed_max(),            0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(),            0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(),            0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(),            _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"),        })    }    fn visit_0xfe_operator<T>(        &mut self,        pos: usize,        visitor: &mut T,    ) -> Result<<T as VisitOperator<'a>>::Output>    where        T: VisitOperator<'a>,    {        let code = self.read_var_u32()?;        Ok(match code {            0x00 => visitor.visit_memory_atomic_notify(self.read_memarg(2)?),            0x01 => visitor.visit_memory_atomic_wait32(self.read_memarg(2)?),            0x02 => visitor.visit_memory_atomic_wait64(self.read_memarg(3)?),            0x03 => {                if self.read_u8()? != 0 {                    bail!(pos, "nonzero byte after `atomic.fence`");                }                visitor.visit_atomic_fence()            }            0x10 => visitor.visit_i32_atomic_load(self.read_memarg(2)?),            0x11 => visitor.visit_i64_atomic_load(self.read_memarg(3)?),            0x12 => visitor.visit_i32_atomic_load8_u(self.read_memarg(0)?),            0x13 => visitor.visit_i32_atomic_load16_u(self.read_memarg(1)?),            0x14 => visitor.visit_i64_atomic_load8_u(self.read_memarg(0)?),            0x15 => visitor.visit_i64_atomic_load16_u(self.read_memarg(1)?),            0x16 => visitor.visit_i64_atomic_load32_u(self.read_memarg(2)?),            0x17 => visitor.visit_i32_atomic_store(self.read_memarg(2)?),            0x18 => visitor.visit_i64_atomic_store(self.read_memarg(3)?),            0x19 => visitor.visit_i32_atomic_store8(self.read_memarg(0)?),            0x1a => visitor.visit_i32_atomic_store16(self.read_memarg(1)?),            0x1b => visitor.visit_i64_atomic_store8(self.read_memarg(0)?),            0x1c => visitor.visit_i64_atomic_store16(self.read_memarg(1)?),            0x1d => visitor.visit_i64_atomic_store32(self.read_memarg(2)?),            0x1e => visitor.visit_i32_atomic_rmw_add(self.read_memarg(2)?),            0x1f => visitor.visit_i64_atomic_rmw_add(self.read_memarg(3)?),            0x20 => visitor.visit_i32_atomic_rmw8_add_u(self.read_memarg(0)?),            0x21 => visitor.visit_i32_atomic_rmw16_add_u(self.read_memarg(1)?),            0x22 => visitor.visit_i64_atomic_rmw8_add_u(self.read_memarg(0)?),            0x23 => visitor.visit_i64_atomic_rmw16_add_u(self.read_memarg(1)?),            0x24 => visitor.visit_i64_atomic_rmw32_add_u(self.read_memarg(2)?),            0x25 => visitor.visit_i32_atomic_rmw_sub(self.read_memarg(2)?),            0x26 => visitor.visit_i64_atomic_rmw_sub(self.read_memarg(3)?),            0x27 => visitor.visit_i32_atomic_rmw8_sub_u(self.read_memarg(0)?),            0x28 => visitor.visit_i32_atomic_rmw16_sub_u(self.read_memarg(1)?),            0x29 => visitor.visit_i64_atomic_rmw8_sub_u(self.read_memarg(0)?),            0x2a => visitor.visit_i64_atomic_rmw16_sub_u(self.read_memarg(1)?),            0x2b => visitor.visit_i64_atomic_rmw32_sub_u(self.read_memarg(2)?),            0x2c => visitor.visit_i32_atomic_rmw_and(self.read_memarg(2)?),            0x2d => visitor.visit_i64_atomic_rmw_and(self.read_memarg(3)?),            0x2e => visitor.visit_i32_atomic_rmw8_and_u(self.read_memarg(0)?),            0x2f => visitor.visit_i32_atomic_rmw16_and_u(self.read_memarg(1)?),            0x30 => visitor.visit_i64_atomic_rmw8_and_u(self.read_memarg(0)?),            0x31 => visitor.visit_i64_atomic_rmw16_and_u(self.read_memarg(1)?),            0x32 => visitor.visit_i64_atomic_rmw32_and_u(self.read_memarg(2)?),            0x33 => visitor.visit_i32_atomic_rmw_or(self.read_memarg(2)?),            0x34 => visitor.visit_i64_atomic_rmw_or(self.read_memarg(3)?),            0x35 => visitor.visit_i32_atomic_rmw8_or_u(self.read_memarg(0)?),            0x36 => visitor.visit_i32_atomic_rmw16_or_u(self.read_memarg(1)?),            0x37 => visitor.visit_i64_atomic_rmw8_or_u(self.read_memarg(0)?),            0x38 => visitor.visit_i64_atomic_rmw16_or_u(self.read_memarg(1)?),            0x39 => visitor.visit_i64_atomic_rmw32_or_u(self.read_memarg(2)?),            0x3a => visitor.visit_i32_atomic_rmw_xor(self.read_memarg(2)?),            0x3b => visitor.visit_i64_atomic_rmw_xor(self.read_memarg(3)?),            0x3c => visitor.visit_i32_atomic_rmw8_xor_u(self.read_memarg(0)?),            0x3d => visitor.visit_i32_atomic_rmw16_xor_u(self.read_memarg(1)?),            0x3e => visitor.visit_i64_atomic_rmw8_xor_u(self.read_memarg(0)?),            0x3f => visitor.visit_i64_atomic_rmw16_xor_u(self.read_memarg(1)?),            0x40 => visitor.visit_i64_atomic_rmw32_xor_u(self.read_memarg(2)?),            0x41 => visitor.visit_i32_atomic_rmw_xchg(self.read_memarg(2)?),            0x42 => visitor.visit_i64_atomic_rmw_xchg(self.read_memarg(3)?),            0x43 => visitor.visit_i32_atomic_rmw8_xchg_u(self.read_memarg(0)?),            0x44 => visitor.visit_i32_atomic_rmw16_xchg_u(self.read_memarg(1)?),            0x45 => visitor.visit_i64_atomic_rmw8_xchg_u(self.read_memarg(0)?),            0x46 => visitor.visit_i64_atomic_rmw16_xchg_u(self.read_memarg(1)?),            0x47 => visitor.visit_i64_atomic_rmw32_xchg_u(self.read_memarg(2)?),            0x48 => visitor.visit_i32_atomic_rmw_cmpxchg(self.read_memarg(2)?),            0x49 => visitor.visit_i64_atomic_rmw_cmpxchg(self.read_memarg(3)?),            0x4a => visitor.visit_i32_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),            0x4b => visitor.visit_i32_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),            0x4c => visitor.visit_i64_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),            0x4d => visitor.visit_i64_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),            0x4e => visitor.visit_i64_atomic_rmw32_cmpxchg_u(self.read_memarg(2)?),            // Decode shared-everything-threads proposal.            0x4f => visitor.visit_global_atomic_get(self.read_ordering()?, self.read_var_u32()?),            0x50 => visitor.visit_global_atomic_set(self.read_ordering()?, self.read_var_u32()?),            0x51 => {                visitor.visit_global_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?)            }            0x52 => {                visitor.visit_global_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?)            }            0x53 => {                visitor.visit_global_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?)            }            0x54 => visitor.visit_global_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),            0x55 => {                visitor.visit_global_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?)            }            0x56 => {                visitor.visit_global_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)            }            0x57 => {                visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)            }            0x58 => visitor.visit_table_atomic_get(self.read_ordering()?, self.read_var_u32()?),            0x59 => visitor.visit_table_atomic_set(self.read_ordering()?, self.read_var_u32()?),            0x5a => {                visitor.visit_table_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)            }            0x5b => {                visitor.visit_table_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)            }            0x5c => visitor.visit_struct_atomic_get(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x5d => visitor.visit_struct_atomic_get_s(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x5e => visitor.visit_struct_atomic_get_u(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x5f => visitor.visit_struct_atomic_set(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x60 => visitor.visit_struct_atomic_rmw_add(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x61 => visitor.visit_struct_atomic_rmw_sub(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x62 => visitor.visit_struct_atomic_rmw_and(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x63 => visitor.visit_struct_atomic_rmw_or(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x64 => visitor.visit_struct_atomic_rmw_xor(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x65 => visitor.visit_struct_atomic_rmw_xchg(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x66 => visitor.visit_struct_atomic_rmw_cmpxchg(                self.read_ordering()?,                self.read_var_u32()?,                self.read_var_u32()?,            ),            0x67 => visitor.visit_array_atomic_get(self.read_ordering()?, self.read_var_u32()?),            0x68 => visitor.visit_array_atomic_get_s(self.read_ordering()?, self.read_var_u32()?),            0x69 => visitor.visit_array_atomic_get_u(self.read_ordering()?, self.read_var_u32()?),            0x6a => visitor.visit_array_atomic_set(self.read_ordering()?, self.read_var_u32()?),            0x6b => visitor.visit_array_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?),            0x6c => visitor.visit_array_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?),            0x6d => visitor.visit_array_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?),            0x6e => visitor.visit_array_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),            0x6f => visitor.visit_array_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?),            0x70 => {                visitor.visit_array_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)            }            0x71 => {                visitor.visit_array_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)            }            0x72 => visitor.visit_ref_i31_shared(),            _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"),        })    }    fn read_memarg(&mut self, max_align: u8) -> Result<MemArg> {        let flags_pos = self.original_position();        let mut flags = self.read_var_u32()?;        let memory = if self.multi_memory() && flags & (1 << 6) != 0 {            flags ^= 1 << 6;            self.read_var_u32()?        } else {            0        };        let max_flag_bits = if self.multi_memory() { 6 } else { 5 };        if flags >= (1 << max_flag_bits) {            return Err(BinaryReaderError::new(                "malformed memop alignment: alignment too large",                flags_pos,            ));        }        let align = flags as u8;        let offset = if self.memory64() {            self.read_var_u64()?        } else {            u64::from(self.read_var_u32()?)        };        Ok(MemArg {            align,            max_align,            offset,            memory,        })    }    fn read_ordering(&mut self) -> Result<Ordering> {        let byte = self.read_var_u32()?;        match byte {            0 => Ok(Ordering::SeqCst),            1 => Ok(Ordering::AcqRel),            x => Err(BinaryReaderError::new(                &format!("invalid atomic consistency ordering {x}"),                self.original_position() - 1,            )),        }    }    fn read_br_table(&mut self) -> Result<BrTable<'a>> {        let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?;        let reader = self.skip(|reader| {            for _ in 0..cnt {                reader.read_var_u32()?;            }            Ok(())        })?;        let default = self.read_var_u32()?;        Ok(BrTable {            reader,            cnt: cnt as u32,            default,        })    }    #[cfg(feature = "simd")]    fn read_lane_index(&mut self) -> Result<u8> {        self.read_u8()    }    #[cfg(feature = "simd")]    fn read_v128(&mut self) -> Result<V128> {        let mut bytes = [0; 16];        bytes.clone_from_slice(self.read_bytes(16)?);        Ok(V128(bytes))    }    fn read_memory_index_or_zero_if_not_multi_memory(&mut self) -> Result<u32> {        if self.multi_memory() {            self.read_var_u32()        } else {            // Before bulk memory this byte was required to be a single zero            // byte, not a LEB-encoded zero, so require a precise zero byte.            match self.read_u8()? {                0 => Ok(0),                _ => bail!(self.original_position() - 1, "zero byte expected"),            }        }    }    fn read_call_indirect_table_immediate(&mut self) -> Result<u32> {        // If the `call_indirect_overlong` feature is enabled, then read this        // immediate as a LEB. This feature is enabled as part of the        // `reference_types` feature or the `lime1` feature.        if self.call_indirect_overlong() {            return self.read_var_u32();        }        // Before reference types this byte was required to be a single zero        // byte, not a LEB-encoded zero, so require a precise zero byte.        match self.read_u8()? {            0 => Ok(0),            _ => bail!(self.original_position() - 1, "zero byte expected"),        }    }}