summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wasmparser-0.48.2/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/wasmparser-0.48.2/src
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasmparser-0.48.2/src')
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/binary_reader.rs1775
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/lib.rs131
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/limits.rs34
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/module_resources.rs370
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/operators_validator.rs1896
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/parser.rs1185
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/primitives.rs690
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs245
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs28
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs157
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs301
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs104
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs86
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs108
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs109
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs42
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs75
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs91
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/mod.rs100
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/module.rs512
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs233
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/operators.rs171
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs192
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs115
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs123
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs31
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs28
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs90
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs103
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/tests.rs529
-rw-r--r--third_party/rust/wasmparser-0.48.2/src/validator.rs946
31 files changed, 10600 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs
new file mode 100644
index 0000000000..3cb6bdc1f1
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs
@@ -0,0 +1,1775 @@
+/* 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 std::boxed::Box;
+use std::convert::TryInto;
+use std::str;
+use std::vec::Vec;
+
+use crate::limits::{
+ MAX_WASM_FUNCTION_LOCALS, MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS,
+ MAX_WASM_FUNCTION_SIZE, MAX_WASM_STRING_SIZE,
+};
+
+use crate::primitives::{
+ BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32,
+ Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType,
+ ResizableLimits, Result, SIMDLaneIndex, SectionCode, TableType, Type, TypeOrFuncType, V128,
+};
+
+const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
+
+fn is_name(name: &str, expected: &'static str) -> bool {
+ name == expected
+}
+
+fn is_name_prefix(name: &str, prefix: &'static str) -> bool {
+ name.starts_with(prefix)
+}
+
+const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm";
+const WASM_EXPERIMENTAL_VERSION: u32 = 0xd;
+const WASM_SUPPORTED_VERSION: u32 = 0x1;
+
+pub(crate) struct SectionHeader<'a> {
+ pub code: SectionCode<'a>,
+ pub payload_start: usize,
+ pub payload_len: usize,
+}
+
+/// Bytecode range in the WebAssembly module.
+#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct Range {
+ /// The start bound of the range.
+ pub start: usize,
+ /// The end bound of the range.
+ pub end: usize,
+}
+
+impl Range {
+ /// Constructs a new instance of `Range`.
+ ///
+ /// # Panics
+ /// If `start` is greater than `end`.
+ pub fn new(start: usize, end: usize) -> Range {
+ assert!(start <= end);
+ Range { start, end }
+ }
+
+ /// Returns a new slice between `start` and `end - 1` from `data`.
+ pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] {
+ &data[self.start..self.end]
+ }
+}
+
+/// A binary reader of the WebAssembly structures and types.
+#[derive(Clone, Debug)]
+pub struct BinaryReader<'a> {
+ pub(crate) buffer: &'a [u8],
+ pub(crate) position: usize,
+ pub(crate) original_offset: usize,
+}
+
+impl<'a> BinaryReader<'a> {
+ /// Constructs `BinaryReader` type.
+ ///
+ /// # Examples
+ /// ```
+ /// let fn_body = &vec![0x41, 0x00, 0x10, 0x00, 0x0B];
+ /// let mut reader = wasmparser::BinaryReader::new(fn_body);
+ /// while !reader.eof() {
+ /// let op = reader.read_operator();
+ /// println!("{:?}", op)
+ /// }
+ /// ```
+ pub fn new(data: &[u8]) -> BinaryReader {
+ BinaryReader {
+ buffer: data,
+ position: 0,
+ original_offset: 0,
+ }
+ }
+
+ /// Constructs a `BinaryReader` with an explicit starting offset.
+ pub fn new_with_offset(data: &[u8], original_offset: usize) -> BinaryReader {
+ BinaryReader {
+ buffer: data,
+ position: 0,
+ original_offset,
+ }
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.original_offset + self.position
+ }
+
+ /// Returns a range from the starting offset to the end of the buffer.
+ pub fn range(&self) -> Range {
+ Range {
+ start: self.original_offset,
+ end: self.original_offset + self.buffer.len(),
+ }
+ }
+
+ fn ensure_has_byte(&self) -> Result<()> {
+ if self.position < self.buffer.len() {
+ Ok(())
+ } else {
+ Err(BinaryReaderError {
+ message: "Unexpected EOF",
+ offset: self.original_position(),
+ })
+ }
+ }
+
+ fn ensure_has_bytes(&self, len: usize) -> Result<()> {
+ if self.position + len <= self.buffer.len() {
+ Ok(())
+ } else {
+ Err(BinaryReaderError {
+ message: "Unexpected EOF",
+ offset: self.original_position(),
+ })
+ }
+ }
+
+ fn read_var_u1(&mut self) -> Result<u32> {
+ let b = self.read_u8()?;
+ if (b & 0xFE) != 0 {
+ return Err(BinaryReaderError {
+ message: "Invalid var_u1",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(b)
+ }
+
+ fn read_var_i7(&mut self) -> Result<i32> {
+ let b = self.read_u8()?;
+ if (b & 0x80) != 0 {
+ return Err(BinaryReaderError {
+ message: "Invalid var_i7",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok((b << 25) as i32 >> 25)
+ }
+
+ pub(crate) fn read_var_u7(&mut self) -> Result<u32> {
+ let b = self.read_u8()?;
+ if (b & 0x80) != 0 {
+ return Err(BinaryReaderError {
+ message: "Invalid var_u7",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(b)
+ }
+
+ pub fn read_type(&mut self) -> Result<Type> {
+ let code = self.read_var_i7()?;
+ match code {
+ -0x01 => Ok(Type::I32),
+ -0x02 => Ok(Type::I64),
+ -0x03 => Ok(Type::F32),
+ -0x04 => Ok(Type::F64),
+ -0x05 => Ok(Type::V128),
+ -0x10 => Ok(Type::AnyFunc),
+ -0x11 => Ok(Type::AnyRef),
+ -0x12 => Ok(Type::NullRef),
+ -0x20 => Ok(Type::Func),
+ -0x40 => Ok(Type::EmptyBlockType),
+ _ => Err(BinaryReaderError {
+ message: "Invalid type",
+ offset: self.original_position() - 1,
+ }),
+ }
+ }
+
+ /// Read a `count` indicating the number of times to call `read_local_decl`.
+ pub fn read_local_count(&mut self) -> Result<usize> {
+ let local_count = self.read_var_u32()? as usize;
+ if local_count > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "local_count is out of bounds",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(local_count)
+ }
+
+ /// Read a `(count, value_type)` declaration of local variables of the same type.
+ pub fn read_local_decl(&mut self, locals_total: &mut usize) -> Result<(u32, Type)> {
+ let count = self.read_var_u32()?;
+ let value_type = self.read_type()?;
+ *locals_total =
+ locals_total
+ .checked_add(count as usize)
+ .ok_or_else(|| BinaryReaderError {
+ message: "locals_total is out of bounds",
+ offset: self.original_position() - 1,
+ })?;
+ if *locals_total > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "locals_total is out of bounds",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok((count, value_type))
+ }
+
+ pub(crate) fn read_external_kind(&mut self) -> Result<ExternalKind> {
+ let code = self.read_u8()?;
+ match code {
+ 0 => Ok(ExternalKind::Function),
+ 1 => Ok(ExternalKind::Table),
+ 2 => Ok(ExternalKind::Memory),
+ 3 => Ok(ExternalKind::Global),
+ _ => Err(BinaryReaderError {
+ message: "Invalid external kind",
+ offset: self.original_position() - 1,
+ }),
+ }
+ }
+
+ pub(crate) fn read_func_type(&mut self) -> Result<FuncType> {
+ let form = self.read_type()?;
+ let params_len = self.read_var_u32()? as usize;
+ if params_len > MAX_WASM_FUNCTION_PARAMS {
+ return Err(BinaryReaderError {
+ message: "function params size is out of bound",
+ offset: self.original_position() - 1,
+ });
+ }
+ let mut params: Vec<Type> = Vec::with_capacity(params_len);
+ for _ in 0..params_len {
+ params.push(self.read_type()?);
+ }
+ let returns_len = self.read_var_u32()? as usize;
+ if returns_len > MAX_WASM_FUNCTION_RETURNS {
+ return Err(BinaryReaderError {
+ message: "function returns size is out of bound",
+ offset: self.original_position() - 1,
+ });
+ }
+ let mut returns: Vec<Type> = Vec::with_capacity(returns_len);
+ for _ in 0..returns_len {
+ returns.push(self.read_type()?);
+ }
+ Ok(FuncType {
+ form,
+ params: params.into_boxed_slice(),
+ returns: returns.into_boxed_slice(),
+ })
+ }
+
+ fn read_resizable_limits(&mut self, max_present: bool) -> Result<ResizableLimits> {
+ let initial = self.read_var_u32()?;
+ let maximum = if max_present {
+ Some(self.read_var_u32()?)
+ } else {
+ None
+ };
+ Ok(ResizableLimits { initial, maximum })
+ }
+
+ pub(crate) fn read_table_type(&mut self) -> Result<TableType> {
+ let element_type = self.read_type()?;
+ let flags = self.read_var_u32()?;
+ if (flags & !0x1) != 0 {
+ return Err(BinaryReaderError {
+ message: "invalid table resizable limits flags",
+ offset: self.original_position() - 1,
+ });
+ }
+ let limits = self.read_resizable_limits((flags & 0x1) != 0)?;
+ Ok(TableType {
+ element_type,
+ limits,
+ })
+ }
+
+ pub(crate) fn read_memory_type(&mut self) -> Result<MemoryType> {
+ let flags = self.read_var_u32()?;
+ if (flags & !0x3) != 0 {
+ return Err(BinaryReaderError {
+ message: "invalid table resizable limits flags",
+ offset: self.original_position() - 1,
+ });
+ }
+ let limits = self.read_resizable_limits((flags & 0x1) != 0)?;
+ let shared = (flags & 0x2) != 0;
+ Ok(MemoryType { limits, shared })
+ }
+
+ pub(crate) fn read_global_type(&mut self) -> Result<GlobalType> {
+ Ok(GlobalType {
+ content_type: self.read_type()?,
+ mutable: self.read_var_u1()? != 0,
+ })
+ }
+
+ fn read_memarg(&mut self) -> Result<MemoryImmediate> {
+ Ok(MemoryImmediate {
+ flags: self.read_var_u32()?,
+ offset: self.read_var_u32()?,
+ })
+ }
+
+ pub(crate) fn read_section_code(&mut self, id: u32, offset: usize) -> Result<SectionCode<'a>> {
+ match id {
+ 0 => {
+ let name = self.read_string()?;
+ let kind = if is_name(name, "name") {
+ CustomSectionKind::Name
+ } else if is_name(name, "producers") {
+ CustomSectionKind::Producers
+ } else if is_name(name, "sourceMappingURL") {
+ CustomSectionKind::SourceMappingURL
+ } else if is_name_prefix(name, "reloc.") {
+ CustomSectionKind::Reloc
+ } else if is_name(name, "linking") {
+ CustomSectionKind::Linking
+ } else {
+ CustomSectionKind::Unknown
+ };
+ Ok(SectionCode::Custom { name, kind })
+ }
+ 1 => Ok(SectionCode::Type),
+ 2 => Ok(SectionCode::Import),
+ 3 => Ok(SectionCode::Function),
+ 4 => Ok(SectionCode::Table),
+ 5 => Ok(SectionCode::Memory),
+ 6 => Ok(SectionCode::Global),
+ 7 => Ok(SectionCode::Export),
+ 8 => Ok(SectionCode::Start),
+ 9 => Ok(SectionCode::Element),
+ 10 => Ok(SectionCode::Code),
+ 11 => Ok(SectionCode::Data),
+ 12 => Ok(SectionCode::DataCount),
+ _ => Err(BinaryReaderError {
+ message: "Invalid section code",
+ offset,
+ }),
+ }
+ }
+
+ fn read_br_table(&mut self) -> Result<BrTable<'a>> {
+ let targets_len = self.read_var_u32()? as usize;
+ if targets_len > MAX_WASM_BR_TABLE_SIZE {
+ return Err(BinaryReaderError {
+ message: "br_table size is out of bound",
+ offset: self.original_position() - 1,
+ });
+ }
+ let start = self.position;
+ for _ in 0..targets_len {
+ self.skip_var_32()?;
+ }
+ self.skip_var_32()?;
+ Ok(BrTable {
+ buffer: &self.buffer[start..self.position],
+ cnt: targets_len as usize,
+ })
+ }
+
+ /// Returns whether the `BinaryReader` has reached the end of the file.
+ pub fn eof(&self) -> bool {
+ self.position >= self.buffer.len()
+ }
+
+ /// Returns the `BinaryReader`'s current position.
+ pub fn current_position(&self) -> usize {
+ self.position
+ }
+
+ /// Returns the number of bytes remaining in the `BinaryReader`.
+ 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])
+ }
+
+ /// 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, and returns the data as
+ /// a `u32`.
+ /// # Errors
+ /// If `BinaryReader` has no bytes remaining.
+ pub fn read_u8(&mut self) -> Result<u32> {
+ self.ensure_has_byte()?;
+ let b = u32::from(self.buffer[self.position]);
+ self.position += 1;
+ Ok(b)
+ }
+
+ /// Advances the `BinaryReader` up to two bytes to parse a variable
+ /// length integer as a `u8`.
+ /// # Errors
+ /// If `BinaryReader` has less than one or two bytes remaining, or the
+ /// integer is larger than eight bits.
+ pub fn read_var_u8(&mut self) -> Result<u32> {
+ // Optimization for single byte i32.
+ let byte = self.read_u8()?;
+ if (byte & 0x80) == 0 {
+ return Ok(byte);
+ }
+
+ let result = (self.read_u8()? << 7) | (byte & 0x7F);
+ if result >= 0x100 {
+ return Err(BinaryReaderError {
+ message: "Invalid var_u8",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(result)
+ }
+
+ /// 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.
+ pub fn read_var_u32(&mut self) -> Result<u32> {
+ // Optimization for single byte i32.
+ let byte = self.read_u8()?;
+ if (byte & 0x80) == 0 {
+ return Ok(byte);
+ }
+
+ let mut result = byte & 0x7F;
+ let mut shift = 7;
+ loop {
+ let byte = self.read_u8()?;
+ result |= ((byte & 0x7F) as u32) << shift;
+ if shift >= 25 && (byte >> (32 - shift)) != 0 {
+ // The continuation bit or unused bits are set.
+ return Err(BinaryReaderError {
+ message: "Invalid var_u32",
+ offset: self.original_position() - 1,
+ });
+ }
+ shift += 7;
+ if (byte & 0x80) == 0 {
+ break;
+ }
+ }
+ Ok(result)
+ }
+
+ /// Advances the `BinaryReader` up to four bytes over a variable length 32
+ /// bit integer, discarding the result.
+ /// # Errors
+ /// If `BinaryReader` has less than one or up to four bytes remaining, or
+ /// the integer is larger than 32 bits.
+ pub fn skip_var_32(&mut self) -> Result<()> {
+ for _ in 0..5 {
+ let byte = self.read_u8()?;
+ if (byte & 0x80) == 0 {
+ return Ok(());
+ }
+ }
+ Err(BinaryReaderError {
+ message: "Invalid var_32",
+ offset: self.original_position() - 1,
+ })
+ }
+
+ /// Alias method for `BinaryReader::skip_var_u32`.
+ pub fn skip_type(&mut self) -> Result<()> {
+ self.skip_var_32()
+ }
+
+ /// Advances the `BinaryReader` `len` bytes, skipping the result.
+ /// # Errors
+ /// If `BinaryReader` has less than `len` bytes remaining.
+ pub fn skip_bytes(&mut self, len: usize) -> Result<()> {
+ self.ensure_has_bytes(len)?;
+ self.position += len;
+ Ok(())
+ }
+
+ /// 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 {
+ message: "string size in out of bounds",
+ offset: self.original_position() - 1,
+ });
+ }
+ self.skip_bytes(len)
+ }
+
+ pub(crate) fn skip_to(&mut self, position: usize) {
+ assert!(
+ self.position <= position && position <= self.buffer.len(),
+ "skip_to allowed only into region past current position"
+ );
+ self.position = position;
+ }
+
+ /// 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.
+ pub fn read_var_i32(&mut self) -> Result<i32> {
+ // Optimization for single byte i32.
+ let byte = self.read_u8()?;
+ if (byte & 0x80) == 0 {
+ return Ok(((byte as i32) << 25) >> 25);
+ }
+
+ 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) {
+ return Err(BinaryReaderError {
+ message: "Invalid var_i32",
+ offset: 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 {
+ message: "Invalid var_s33",
+ offset: 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) {
+ return Err(BinaryReaderError {
+ message: "Invalid var_i64",
+ offset: 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 four bytes to parse a variable
+ /// length integer as a 32 bit floating point integer, returned as `Ieee32`.
+ /// # Errors
+ /// If `BinaryReader` has less than one or up to four bytes remaining, or
+ /// the integer is larger than 32 bits.
+ pub fn read_f32(&mut self) -> Result<Ieee32> {
+ let value = self.read_u32()?;
+ Ok(Ieee32(value))
+ }
+
+ /// Advances the `BinaryReader` up to four bytes to parse a variable
+ /// length integer as a 32 bit floating point integer, returned as `Ieee32`.
+ /// # Errors
+ /// If `BinaryReader` has less than one or up to four bytes remaining, or
+ /// the integer is larger than 32 bits.
+ pub fn read_f64(&mut self) -> Result<Ieee64> {
+ let value = self.read_u64()?;
+ Ok(Ieee64(value))
+ }
+
+ /// 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 {
+ message: "string size in out of bounds",
+ offset: self.original_position() - 1,
+ });
+ }
+ let bytes = self.read_bytes(len)?;
+ str::from_utf8(bytes).map_err(|_| BinaryReaderError {
+ message: "non-utf8 string",
+ offset: self.original_position() - 1,
+ })
+ }
+
+ fn read_memarg_of_align(&mut self, max_align: u32) -> Result<MemoryImmediate> {
+ let imm = self.read_memarg()?;
+ if imm.flags > max_align {
+ return Err(BinaryReaderError {
+ message: "Unexpected memarg alignment",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(imm)
+ }
+
+ fn read_0xfe_operator(&mut self) -> Result<Operator<'a>> {
+ let code = self.read_u8()? as u8;
+ Ok(match code {
+ 0x00 => Operator::AtomicNotify {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x01 => Operator::I32AtomicWait {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x02 => Operator::I64AtomicWait {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x03 => Operator::AtomicFence {
+ flags: self.read_u8()? as u8,
+ },
+ 0x10 => Operator::I32AtomicLoad {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x11 => Operator::I64AtomicLoad {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x12 => Operator::I32AtomicLoad8U {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x13 => Operator::I32AtomicLoad16U {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x14 => Operator::I64AtomicLoad8U {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x15 => Operator::I64AtomicLoad16U {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x16 => Operator::I64AtomicLoad32U {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x17 => Operator::I32AtomicStore {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x18 => Operator::I64AtomicStore {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x19 => Operator::I32AtomicStore8 {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x1a => Operator::I32AtomicStore16 {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x1b => Operator::I64AtomicStore8 {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x1c => Operator::I64AtomicStore16 {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x1d => Operator::I64AtomicStore32 {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x1e => Operator::I32AtomicRmwAdd {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x1f => Operator::I64AtomicRmwAdd {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x20 => Operator::I32AtomicRmw8AddU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x21 => Operator::I32AtomicRmw16AddU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x22 => Operator::I64AtomicRmw8AddU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x23 => Operator::I64AtomicRmw16AddU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x24 => Operator::I64AtomicRmw32AddU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x25 => Operator::I32AtomicRmwSub {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x26 => Operator::I64AtomicRmwSub {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x27 => Operator::I32AtomicRmw8SubU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x28 => Operator::I32AtomicRmw16SubU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x29 => Operator::I64AtomicRmw8SubU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x2a => Operator::I64AtomicRmw16SubU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x2b => Operator::I64AtomicRmw32SubU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x2c => Operator::I32AtomicRmwAnd {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x2d => Operator::I64AtomicRmwAnd {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x2e => Operator::I32AtomicRmw8AndU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x2f => Operator::I32AtomicRmw16AndU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x30 => Operator::I64AtomicRmw8AndU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x31 => Operator::I64AtomicRmw16AndU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x32 => Operator::I64AtomicRmw32AndU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x33 => Operator::I32AtomicRmwOr {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x34 => Operator::I64AtomicRmwOr {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x35 => Operator::I32AtomicRmw8OrU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x36 => Operator::I32AtomicRmw16OrU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x37 => Operator::I64AtomicRmw8OrU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x38 => Operator::I64AtomicRmw16OrU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x39 => Operator::I64AtomicRmw32OrU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x3a => Operator::I32AtomicRmwXor {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x3b => Operator::I64AtomicRmwXor {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x3c => Operator::I32AtomicRmw8XorU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x3d => Operator::I32AtomicRmw16XorU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x3e => Operator::I64AtomicRmw8XorU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x3f => Operator::I64AtomicRmw16XorU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x40 => Operator::I64AtomicRmw32XorU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x41 => Operator::I32AtomicRmwXchg {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x42 => Operator::I64AtomicRmwXchg {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x43 => Operator::I32AtomicRmw8XchgU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x44 => Operator::I32AtomicRmw16XchgU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x45 => Operator::I64AtomicRmw8XchgU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x46 => Operator::I64AtomicRmw16XchgU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x47 => Operator::I64AtomicRmw32XchgU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x48 => Operator::I32AtomicRmwCmpxchg {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0x49 => Operator::I64AtomicRmwCmpxchg {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0x4a => Operator::I32AtomicRmw8CmpxchgU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x4b => Operator::I32AtomicRmw16CmpxchgU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x4c => Operator::I64AtomicRmw8CmpxchgU {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0x4d => Operator::I64AtomicRmw16CmpxchgU {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0x4e => Operator::I64AtomicRmw32CmpxchgU {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+
+ _ => {
+ return Err(BinaryReaderError {
+ message: "Unknown 0xFE opcode",
+ offset: self.original_position() - 1,
+ });
+ }
+ })
+ }
+
+ fn read_blocktype(&mut self) -> Result<TypeOrFuncType> {
+ let position = self.position;
+ if let Ok(ty) = self.read_type() {
+ Ok(TypeOrFuncType::Type(ty))
+ } else {
+ self.position = position;
+ let idx = self.read_var_s33()?;
+ if idx < 0 || idx > (std::u32::MAX as i64) {
+ return Err(BinaryReaderError {
+ message: "invalid function type",
+ offset: position,
+ });
+ }
+ Ok(TypeOrFuncType::FuncType(idx as u32))
+ }
+ }
+
+ /// Reads the next available `Operator`.
+ /// # Errors
+ /// If `BinaryReader` has less bytes remaining than required to parse
+ /// the `Operator`.
+ pub fn read_operator(&mut self) -> Result<Operator<'a>> {
+ let code = self.read_u8()? as u8;
+ Ok(match code {
+ 0x00 => Operator::Unreachable,
+ 0x01 => Operator::Nop,
+ 0x02 => Operator::Block {
+ ty: self.read_blocktype()?,
+ },
+ 0x03 => Operator::Loop {
+ ty: self.read_blocktype()?,
+ },
+ 0x04 => Operator::If {
+ ty: self.read_blocktype()?,
+ },
+ 0x05 => Operator::Else,
+ 0x0b => Operator::End,
+ 0x0c => Operator::Br {
+ relative_depth: self.read_var_u32()?,
+ },
+ 0x0d => Operator::BrIf {
+ relative_depth: self.read_var_u32()?,
+ },
+ 0x0e => Operator::BrTable {
+ table: self.read_br_table()?,
+ },
+ 0x0f => Operator::Return,
+ 0x10 => Operator::Call {
+ function_index: self.read_var_u32()?,
+ },
+ 0x11 => Operator::CallIndirect {
+ index: self.read_var_u32()?,
+ table_index: self.read_var_u32()?,
+ },
+ 0x1a => Operator::Drop,
+ 0x1b => Operator::Select,
+ 0x1c => {
+ let results = self.read_var_u32()?;
+ if results != 1 {
+ return Err(BinaryReaderError {
+ message: "bad number of results",
+ offset: self.position,
+ });
+ }
+ Operator::TypedSelect {
+ ty: self.read_type()?,
+ }
+ }
+ 0x20 => Operator::LocalGet {
+ local_index: self.read_var_u32()?,
+ },
+ 0x21 => Operator::LocalSet {
+ local_index: self.read_var_u32()?,
+ },
+ 0x22 => Operator::LocalTee {
+ local_index: self.read_var_u32()?,
+ },
+ 0x23 => Operator::GlobalGet {
+ global_index: self.read_var_u32()?,
+ },
+ 0x24 => Operator::GlobalSet {
+ global_index: self.read_var_u32()?,
+ },
+ 0x25 => Operator::TableGet {
+ table: self.read_var_u32()?,
+ },
+ 0x26 => Operator::TableSet {
+ table: self.read_var_u32()?,
+ },
+ 0x28 => Operator::I32Load {
+ memarg: self.read_memarg()?,
+ },
+ 0x29 => Operator::I64Load {
+ memarg: self.read_memarg()?,
+ },
+ 0x2a => Operator::F32Load {
+ memarg: self.read_memarg()?,
+ },
+ 0x2b => Operator::F64Load {
+ memarg: self.read_memarg()?,
+ },
+ 0x2c => Operator::I32Load8S {
+ memarg: self.read_memarg()?,
+ },
+ 0x2d => Operator::I32Load8U {
+ memarg: self.read_memarg()?,
+ },
+ 0x2e => Operator::I32Load16S {
+ memarg: self.read_memarg()?,
+ },
+ 0x2f => Operator::I32Load16U {
+ memarg: self.read_memarg()?,
+ },
+ 0x30 => Operator::I64Load8S {
+ memarg: self.read_memarg()?,
+ },
+ 0x31 => Operator::I64Load8U {
+ memarg: self.read_memarg()?,
+ },
+ 0x32 => Operator::I64Load16S {
+ memarg: self.read_memarg()?,
+ },
+ 0x33 => Operator::I64Load16U {
+ memarg: self.read_memarg()?,
+ },
+ 0x34 => Operator::I64Load32S {
+ memarg: self.read_memarg()?,
+ },
+ 0x35 => Operator::I64Load32U {
+ memarg: self.read_memarg()?,
+ },
+ 0x36 => Operator::I32Store {
+ memarg: self.read_memarg()?,
+ },
+ 0x37 => Operator::I64Store {
+ memarg: self.read_memarg()?,
+ },
+ 0x38 => Operator::F32Store {
+ memarg: self.read_memarg()?,
+ },
+ 0x39 => Operator::F64Store {
+ memarg: self.read_memarg()?,
+ },
+ 0x3a => Operator::I32Store8 {
+ memarg: self.read_memarg()?,
+ },
+ 0x3b => Operator::I32Store16 {
+ memarg: self.read_memarg()?,
+ },
+ 0x3c => Operator::I64Store8 {
+ memarg: self.read_memarg()?,
+ },
+ 0x3d => Operator::I64Store16 {
+ memarg: self.read_memarg()?,
+ },
+ 0x3e => Operator::I64Store32 {
+ memarg: self.read_memarg()?,
+ },
+ 0x3f => Operator::MemorySize {
+ reserved: self.read_var_u1()?,
+ },
+ 0x40 => Operator::MemoryGrow {
+ reserved: self.read_var_u1()?,
+ },
+ 0x41 => Operator::I32Const {
+ value: self.read_var_i32()?,
+ },
+ 0x42 => Operator::I64Const {
+ value: self.read_var_i64()?,
+ },
+ 0x43 => Operator::F32Const {
+ value: self.read_f32()?,
+ },
+ 0x44 => Operator::F64Const {
+ value: self.read_f64()?,
+ },
+ 0x45 => Operator::I32Eqz,
+ 0x46 => Operator::I32Eq,
+ 0x47 => Operator::I32Ne,
+ 0x48 => Operator::I32LtS,
+ 0x49 => Operator::I32LtU,
+ 0x4a => Operator::I32GtS,
+ 0x4b => Operator::I32GtU,
+ 0x4c => Operator::I32LeS,
+ 0x4d => Operator::I32LeU,
+ 0x4e => Operator::I32GeS,
+ 0x4f => Operator::I32GeU,
+ 0x50 => Operator::I64Eqz,
+ 0x51 => Operator::I64Eq,
+ 0x52 => Operator::I64Ne,
+ 0x53 => Operator::I64LtS,
+ 0x54 => Operator::I64LtU,
+ 0x55 => Operator::I64GtS,
+ 0x56 => Operator::I64GtU,
+ 0x57 => Operator::I64LeS,
+ 0x58 => Operator::I64LeU,
+ 0x59 => Operator::I64GeS,
+ 0x5a => Operator::I64GeU,
+ 0x5b => Operator::F32Eq,
+ 0x5c => Operator::F32Ne,
+ 0x5d => Operator::F32Lt,
+ 0x5e => Operator::F32Gt,
+ 0x5f => Operator::F32Le,
+ 0x60 => Operator::F32Ge,
+ 0x61 => Operator::F64Eq,
+ 0x62 => Operator::F64Ne,
+ 0x63 => Operator::F64Lt,
+ 0x64 => Operator::F64Gt,
+ 0x65 => Operator::F64Le,
+ 0x66 => Operator::F64Ge,
+ 0x67 => Operator::I32Clz,
+ 0x68 => Operator::I32Ctz,
+ 0x69 => Operator::I32Popcnt,
+ 0x6a => Operator::I32Add,
+ 0x6b => Operator::I32Sub,
+ 0x6c => Operator::I32Mul,
+ 0x6d => Operator::I32DivS,
+ 0x6e => Operator::I32DivU,
+ 0x6f => Operator::I32RemS,
+ 0x70 => Operator::I32RemU,
+ 0x71 => Operator::I32And,
+ 0x72 => Operator::I32Or,
+ 0x73 => Operator::I32Xor,
+ 0x74 => Operator::I32Shl,
+ 0x75 => Operator::I32ShrS,
+ 0x76 => Operator::I32ShrU,
+ 0x77 => Operator::I32Rotl,
+ 0x78 => Operator::I32Rotr,
+ 0x79 => Operator::I64Clz,
+ 0x7a => Operator::I64Ctz,
+ 0x7b => Operator::I64Popcnt,
+ 0x7c => Operator::I64Add,
+ 0x7d => Operator::I64Sub,
+ 0x7e => Operator::I64Mul,
+ 0x7f => Operator::I64DivS,
+ 0x80 => Operator::I64DivU,
+ 0x81 => Operator::I64RemS,
+ 0x82 => Operator::I64RemU,
+ 0x83 => Operator::I64And,
+ 0x84 => Operator::I64Or,
+ 0x85 => Operator::I64Xor,
+ 0x86 => Operator::I64Shl,
+ 0x87 => Operator::I64ShrS,
+ 0x88 => Operator::I64ShrU,
+ 0x89 => Operator::I64Rotl,
+ 0x8a => Operator::I64Rotr,
+ 0x8b => Operator::F32Abs,
+ 0x8c => Operator::F32Neg,
+ 0x8d => Operator::F32Ceil,
+ 0x8e => Operator::F32Floor,
+ 0x8f => Operator::F32Trunc,
+ 0x90 => Operator::F32Nearest,
+ 0x91 => Operator::F32Sqrt,
+ 0x92 => Operator::F32Add,
+ 0x93 => Operator::F32Sub,
+ 0x94 => Operator::F32Mul,
+ 0x95 => Operator::F32Div,
+ 0x96 => Operator::F32Min,
+ 0x97 => Operator::F32Max,
+ 0x98 => Operator::F32Copysign,
+ 0x99 => Operator::F64Abs,
+ 0x9a => Operator::F64Neg,
+ 0x9b => Operator::F64Ceil,
+ 0x9c => Operator::F64Floor,
+ 0x9d => Operator::F64Trunc,
+ 0x9e => Operator::F64Nearest,
+ 0x9f => Operator::F64Sqrt,
+ 0xa0 => Operator::F64Add,
+ 0xa1 => Operator::F64Sub,
+ 0xa2 => Operator::F64Mul,
+ 0xa3 => Operator::F64Div,
+ 0xa4 => Operator::F64Min,
+ 0xa5 => Operator::F64Max,
+ 0xa6 => Operator::F64Copysign,
+ 0xa7 => Operator::I32WrapI64,
+ 0xa8 => Operator::I32TruncF32S,
+ 0xa9 => Operator::I32TruncF32U,
+ 0xaa => Operator::I32TruncF64S,
+ 0xab => Operator::I32TruncF64U,
+ 0xac => Operator::I64ExtendI32S,
+ 0xad => Operator::I64ExtendI32U,
+ 0xae => Operator::I64TruncF32S,
+ 0xaf => Operator::I64TruncF32U,
+ 0xb0 => Operator::I64TruncF64S,
+ 0xb1 => Operator::I64TruncF64U,
+ 0xb2 => Operator::F32ConvertI32S,
+ 0xb3 => Operator::F32ConvertI32U,
+ 0xb4 => Operator::F32ConvertI64S,
+ 0xb5 => Operator::F32ConvertI64U,
+ 0xb6 => Operator::F32DemoteF64,
+ 0xb7 => Operator::F64ConvertI32S,
+ 0xb8 => Operator::F64ConvertI32U,
+ 0xb9 => Operator::F64ConvertI64S,
+ 0xba => Operator::F64ConvertI64U,
+ 0xbb => Operator::F64PromoteF32,
+ 0xbc => Operator::I32ReinterpretF32,
+ 0xbd => Operator::I64ReinterpretF64,
+ 0xbe => Operator::F32ReinterpretI32,
+ 0xbf => Operator::F64ReinterpretI64,
+
+ 0xc0 => Operator::I32Extend8S,
+ 0xc1 => Operator::I32Extend16S,
+ 0xc2 => Operator::I64Extend8S,
+ 0xc3 => Operator::I64Extend16S,
+ 0xc4 => Operator::I64Extend32S,
+
+ 0xd0 => Operator::RefNull,
+ 0xd1 => Operator::RefIsNull,
+ 0xd2 => Operator::RefFunc {
+ function_index: self.read_var_u32()?,
+ },
+
+ 0xfc => self.read_0xfc_operator()?,
+ 0xfd => self.read_0xfd_operator()?,
+ 0xfe => self.read_0xfe_operator()?,
+
+ _ => {
+ return Err(BinaryReaderError {
+ message: "Unknown opcode",
+ offset: self.original_position() - 1,
+ });
+ }
+ })
+ }
+
+ fn read_0xfc_operator(&mut self) -> Result<Operator<'a>> {
+ let code = self.read_u8()? as u8;
+ Ok(match code {
+ 0x00 => Operator::I32TruncSatF32S,
+ 0x01 => Operator::I32TruncSatF32U,
+ 0x02 => Operator::I32TruncSatF64S,
+ 0x03 => Operator::I32TruncSatF64U,
+ 0x04 => Operator::I64TruncSatF32S,
+ 0x05 => Operator::I64TruncSatF32U,
+ 0x06 => Operator::I64TruncSatF64S,
+ 0x07 => Operator::I64TruncSatF64U,
+
+ 0x08 => {
+ let segment = self.read_var_u32()?;
+ let mem = self.read_u8()?;
+ if mem != 0 {
+ return Err(BinaryReaderError {
+ message: "reserved byte must be zero",
+ offset: self.original_position() - 1,
+ });
+ }
+ Operator::MemoryInit { segment }
+ }
+ 0x09 => {
+ let segment = self.read_var_u32()?;
+ Operator::DataDrop { segment }
+ }
+ 0x0a => {
+ let dst = self.read_u8()?;
+ if dst != 0 {
+ return Err(BinaryReaderError {
+ message: "reserved byte must be zero",
+ offset: self.original_position() - 1,
+ });
+ }
+ let src = self.read_u8()?;
+ if src != 0 {
+ return Err(BinaryReaderError {
+ message: "reserved byte must be zero",
+ offset: self.original_position() - 1,
+ });
+ }
+ Operator::MemoryCopy
+ }
+ 0x0b => {
+ let mem = self.read_u8()?;
+ if mem != 0 {
+ return Err(BinaryReaderError {
+ message: "reserved byte must be zero",
+ offset: self.original_position() - 1,
+ });
+ }
+ Operator::MemoryFill
+ }
+ 0x0c => {
+ let segment = self.read_var_u32()?;
+ let table = self.read_var_u32()?;
+ Operator::TableInit { segment, table }
+ }
+ 0x0d => {
+ let segment = self.read_var_u32()?;
+ Operator::ElemDrop { segment }
+ }
+ 0x0e => {
+ let dst_table = self.read_var_u32()?;
+ let src_table = self.read_var_u32()?;
+ Operator::TableCopy {
+ src_table,
+ dst_table,
+ }
+ }
+
+ 0x0f => {
+ let table = self.read_var_u32()?;
+ Operator::TableGrow { table }
+ }
+ 0x10 => {
+ let table = self.read_var_u32()?;
+ Operator::TableSize { table }
+ }
+
+ 0x11 => {
+ let table = self.read_var_u32()?;
+ Operator::TableFill { table }
+ }
+
+ _ => {
+ return Err(BinaryReaderError {
+ message: "Unknown 0xfc opcode",
+ offset: self.original_position() - 1,
+ });
+ }
+ })
+ }
+
+ fn read_lane_index(&mut self, max: u32) -> Result<SIMDLaneIndex> {
+ let index = self.read_u8()?;
+ if index >= max {
+ return Err(BinaryReaderError {
+ message: "invalid lane index",
+ offset: self.original_position() - 1,
+ });
+ }
+ Ok(index as SIMDLaneIndex)
+ }
+
+ 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_0xfd_operator(&mut self) -> Result<Operator<'a>> {
+ let code = self.read_var_u8()? as u8;
+ Ok(match code {
+ 0x00 => Operator::V128Load {
+ memarg: self.read_memarg()?,
+ },
+ 0x01 => Operator::V128Store {
+ memarg: self.read_memarg()?,
+ },
+ 0x02 => Operator::V128Const {
+ value: self.read_v128()?,
+ },
+ 0x04 => Operator::I8x16Splat,
+ 0x05 => Operator::I8x16ExtractLaneS {
+ lane: self.read_lane_index(16)?,
+ },
+ 0x06 => Operator::I8x16ExtractLaneU {
+ lane: self.read_lane_index(16)?,
+ },
+ 0x07 => Operator::I8x16ReplaceLane {
+ lane: self.read_lane_index(16)?,
+ },
+ 0x08 => Operator::I16x8Splat,
+ 0x09 => Operator::I16x8ExtractLaneS {
+ lane: self.read_lane_index(8)?,
+ },
+ 0x0a => Operator::I16x8ExtractLaneU {
+ lane: self.read_lane_index(8)?,
+ },
+ 0x0b => Operator::I16x8ReplaceLane {
+ lane: self.read_lane_index(8)?,
+ },
+ 0x0c => Operator::I32x4Splat,
+ 0x0d => Operator::I32x4ExtractLane {
+ lane: self.read_lane_index(4)?,
+ },
+ 0x0e => Operator::I32x4ReplaceLane {
+ lane: self.read_lane_index(4)?,
+ },
+ 0x0f => Operator::I64x2Splat,
+ 0x10 => Operator::I64x2ExtractLane {
+ lane: self.read_lane_index(2)?,
+ },
+ 0x11 => Operator::I64x2ReplaceLane {
+ lane: self.read_lane_index(2)?,
+ },
+ 0x12 => Operator::F32x4Splat,
+ 0x13 => Operator::F32x4ExtractLane {
+ lane: self.read_lane_index(4)?,
+ },
+ 0x14 => Operator::F32x4ReplaceLane {
+ lane: self.read_lane_index(4)?,
+ },
+ 0x15 => Operator::F64x2Splat,
+ 0x16 => Operator::F64x2ExtractLane {
+ lane: self.read_lane_index(2)?,
+ },
+ 0x17 => Operator::F64x2ReplaceLane {
+ lane: self.read_lane_index(2)?,
+ },
+ 0x18 => Operator::I8x16Eq,
+ 0x19 => Operator::I8x16Ne,
+ 0x1a => Operator::I8x16LtS,
+ 0x1b => Operator::I8x16LtU,
+ 0x1c => Operator::I8x16GtS,
+ 0x1d => Operator::I8x16GtU,
+ 0x1e => Operator::I8x16LeS,
+ 0x1f => Operator::I8x16LeU,
+ 0x20 => Operator::I8x16GeS,
+ 0x21 => Operator::I8x16GeU,
+ 0x22 => Operator::I16x8Eq,
+ 0x23 => Operator::I16x8Ne,
+ 0x24 => Operator::I16x8LtS,
+ 0x25 => Operator::I16x8LtU,
+ 0x26 => Operator::I16x8GtS,
+ 0x27 => Operator::I16x8GtU,
+ 0x28 => Operator::I16x8LeS,
+ 0x29 => Operator::I16x8LeU,
+ 0x2a => Operator::I16x8GeS,
+ 0x2b => Operator::I16x8GeU,
+ 0x2c => Operator::I32x4Eq,
+ 0x2d => Operator::I32x4Ne,
+ 0x2e => Operator::I32x4LtS,
+ 0x2f => Operator::I32x4LtU,
+ 0x30 => Operator::I32x4GtS,
+ 0x31 => Operator::I32x4GtU,
+ 0x32 => Operator::I32x4LeS,
+ 0x33 => Operator::I32x4LeU,
+ 0x34 => Operator::I32x4GeS,
+ 0x35 => Operator::I32x4GeU,
+ 0x40 => Operator::F32x4Eq,
+ 0x41 => Operator::F32x4Ne,
+ 0x42 => Operator::F32x4Lt,
+ 0x43 => Operator::F32x4Gt,
+ 0x44 => Operator::F32x4Le,
+ 0x45 => Operator::F32x4Ge,
+ 0x46 => Operator::F64x2Eq,
+ 0x47 => Operator::F64x2Ne,
+ 0x48 => Operator::F64x2Lt,
+ 0x49 => Operator::F64x2Gt,
+ 0x4a => Operator::F64x2Le,
+ 0x4b => Operator::F64x2Ge,
+ 0x4c => Operator::V128Not,
+ 0x4d => Operator::V128And,
+ 0x4e => Operator::V128Or,
+ 0x4f => Operator::V128Xor,
+ 0x50 => Operator::V128Bitselect,
+ 0x51 => Operator::I8x16Neg,
+ 0x52 => Operator::I8x16AnyTrue,
+ 0x53 => Operator::I8x16AllTrue,
+ 0x54 => Operator::I8x16Shl,
+ 0x55 => Operator::I8x16ShrS,
+ 0x56 => Operator::I8x16ShrU,
+ 0x57 => Operator::I8x16Add,
+ 0x58 => Operator::I8x16AddSaturateS,
+ 0x59 => Operator::I8x16AddSaturateU,
+ 0x5a => Operator::I8x16Sub,
+ 0x5b => Operator::I8x16SubSaturateS,
+ 0x5c => Operator::I8x16SubSaturateU,
+ 0x5d => Operator::I8x16Mul,
+ 0x62 => Operator::I16x8Neg,
+ 0x63 => Operator::I16x8AnyTrue,
+ 0x64 => Operator::I16x8AllTrue,
+ 0x65 => Operator::I16x8Shl,
+ 0x66 => Operator::I16x8ShrS,
+ 0x67 => Operator::I16x8ShrU,
+ 0x68 => Operator::I16x8Add,
+ 0x69 => Operator::I16x8AddSaturateS,
+ 0x6a => Operator::I16x8AddSaturateU,
+ 0x6b => Operator::I16x8Sub,
+ 0x6c => Operator::I16x8SubSaturateS,
+ 0x6d => Operator::I16x8SubSaturateU,
+ 0x6e => Operator::I16x8Mul,
+ 0x73 => Operator::I32x4Neg,
+ 0x74 => Operator::I32x4AnyTrue,
+ 0x75 => Operator::I32x4AllTrue,
+ 0x76 => Operator::I32x4Shl,
+ 0x77 => Operator::I32x4ShrS,
+ 0x78 => Operator::I32x4ShrU,
+ 0x79 => Operator::I32x4Add,
+ 0x7c => Operator::I32x4Sub,
+ 0x7f => Operator::I32x4Mul,
+ 0x84 => Operator::I64x2Neg,
+ 0x85 => Operator::I64x2AnyTrue,
+ 0x86 => Operator::I64x2AllTrue,
+ 0x87 => Operator::I64x2Shl,
+ 0x88 => Operator::I64x2ShrS,
+ 0x89 => Operator::I64x2ShrU,
+ 0x8a => Operator::I64x2Add,
+ 0x8d => Operator::I64x2Sub,
+ 0x90 => Operator::I64x2Mul,
+ 0x95 => Operator::F32x4Abs,
+ 0x96 => Operator::F32x4Neg,
+ 0x97 => Operator::F32x4Sqrt,
+ 0x9a => Operator::F32x4Add,
+ 0x9b => Operator::F32x4Sub,
+ 0x9c => Operator::F32x4Mul,
+ 0x9d => Operator::F32x4Div,
+ 0x9e => Operator::F32x4Min,
+ 0x9f => Operator::F32x4Max,
+ 0xa0 => Operator::F64x2Abs,
+ 0xa1 => Operator::F64x2Neg,
+ 0xa2 => Operator::F64x2Sqrt,
+ 0xa5 => Operator::F64x2Add,
+ 0xa6 => Operator::F64x2Sub,
+ 0xa7 => Operator::F64x2Mul,
+ 0xa8 => Operator::F64x2Div,
+ 0xa9 => Operator::F64x2Min,
+ 0xaa => Operator::F64x2Max,
+ 0xab => Operator::I32x4TruncSatF32x4S,
+ 0xac => Operator::I32x4TruncSatF32x4U,
+ 0xad => Operator::I64x2TruncSatF64x2S,
+ 0xae => Operator::I64x2TruncSatF64x2U,
+ 0xaf => Operator::F32x4ConvertI32x4S,
+ 0xb0 => Operator::F32x4ConvertI32x4U,
+ 0xb1 => Operator::F64x2ConvertI64x2S,
+ 0xb2 => Operator::F64x2ConvertI64x2U,
+ 0xc0 => Operator::V8x16Swizzle,
+ 0x03 | 0xc1 => {
+ let mut lanes = [0 as SIMDLaneIndex; 16];
+ for lane in &mut lanes {
+ *lane = self.read_lane_index(32)?
+ }
+ Operator::V8x16Shuffle { lanes }
+ }
+ 0xc2 => Operator::V8x16LoadSplat {
+ memarg: self.read_memarg_of_align(0)?,
+ },
+ 0xc3 => Operator::V16x8LoadSplat {
+ memarg: self.read_memarg_of_align(1)?,
+ },
+ 0xc4 => Operator::V32x4LoadSplat {
+ memarg: self.read_memarg_of_align(2)?,
+ },
+ 0xc5 => Operator::V64x2LoadSplat {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xc6 => Operator::I8x16NarrowI16x8S,
+ 0xc7 => Operator::I8x16NarrowI16x8U,
+ 0xc8 => Operator::I16x8NarrowI32x4S,
+ 0xc9 => Operator::I16x8NarrowI32x4U,
+ 0xca => Operator::I16x8WidenLowI8x16S,
+ 0xcb => Operator::I16x8WidenHighI8x16S,
+ 0xcc => Operator::I16x8WidenLowI8x16U,
+ 0xcd => Operator::I16x8WidenHighI8x16U,
+ 0xce => Operator::I32x4WidenLowI16x8S,
+ 0xcf => Operator::I32x4WidenHighI16x8S,
+ 0xd0 => Operator::I32x4WidenLowI16x8U,
+ 0xd1 => Operator::I32x4WidenHighI16x8U,
+ 0xd2 => Operator::I16x8Load8x8S {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd3 => Operator::I16x8Load8x8U {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd4 => Operator::I32x4Load16x4S {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd5 => Operator::I32x4Load16x4U {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd6 => Operator::I64x2Load32x2S {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd7 => Operator::I64x2Load32x2U {
+ memarg: self.read_memarg_of_align(3)?,
+ },
+ 0xd8 => Operator::V128AndNot,
+ 0xd9 => Operator::I8x16RoundingAverageU,
+ 0xda => Operator::I16x8RoundingAverageU,
+ _ => {
+ return Err(BinaryReaderError {
+ message: "Unknown 0xfd opcode",
+ offset: self.original_position() - 1,
+ });
+ }
+ })
+ }
+
+ pub(crate) fn read_file_header(&mut self) -> Result<u32> {
+ let magic_number = self.read_bytes(4)?;
+ if magic_number != WASM_MAGIC_NUMBER {
+ return Err(BinaryReaderError {
+ message: "Bad magic number",
+ offset: self.original_position() - 4,
+ });
+ }
+ let version = self.read_u32()?;
+ if version != WASM_SUPPORTED_VERSION && version != WASM_EXPERIMENTAL_VERSION {
+ return Err(BinaryReaderError {
+ message: "Bad version number",
+ offset: self.original_position() - 4,
+ });
+ }
+ Ok(version)
+ }
+
+ pub(crate) fn read_section_header(&mut self) -> Result<SectionHeader<'a>> {
+ let id_position = self.position;
+ let id = self.read_var_u7()?;
+ let payload_len = self.read_var_u32()? as usize;
+ let payload_start = self.position;
+ let code = self.read_section_code(id, id_position)?;
+ Ok(SectionHeader {
+ code,
+ payload_start,
+ payload_len,
+ })
+ }
+
+ pub(crate) fn read_name_type(&mut self) -> Result<NameType> {
+ let code = self.read_var_u7()?;
+ match code {
+ 0 => Ok(NameType::Module),
+ 1 => Ok(NameType::Function),
+ 2 => Ok(NameType::Local),
+ _ => Err(BinaryReaderError {
+ message: "Invalid name type",
+ offset: self.original_position() - 1,
+ }),
+ }
+ }
+
+ pub(crate) fn read_linking_type(&mut self) -> Result<LinkingType> {
+ let ty = self.read_var_u32()?;
+ Ok(match ty {
+ 1 => LinkingType::StackPointer(self.read_var_u32()?),
+ _ => {
+ return Err(BinaryReaderError {
+ message: "Invalid linking type",
+ offset: self.original_position() - 1,
+ });
+ }
+ })
+ }
+
+ pub(crate) fn read_reloc_type(&mut self) -> Result<RelocType> {
+ let code = self.read_var_u7()?;
+ match code {
+ 0 => Ok(RelocType::FunctionIndexLEB),
+ 1 => Ok(RelocType::TableIndexSLEB),
+ 2 => Ok(RelocType::TableIndexI32),
+ 3 => Ok(RelocType::GlobalAddrLEB),
+ 4 => Ok(RelocType::GlobalAddrSLEB),
+ 5 => Ok(RelocType::GlobalAddrI32),
+ 6 => Ok(RelocType::TypeIndexLEB),
+ 7 => Ok(RelocType::GlobalIndexLEB),
+ _ => Err(BinaryReaderError {
+ message: "Invalid reloc type",
+ offset: self.original_position() - 1,
+ }),
+ }
+ }
+
+ pub(crate) fn skip_init_expr(&mut self) -> Result<()> {
+ // TODO add skip_operator() method and/or validate init_expr operators.
+ loop {
+ if let Operator::End = self.read_operator()? {
+ return Ok(());
+ }
+ }
+ }
+}
+
+impl<'a> BrTable<'a> {
+ /// Returns the number of `br_table` entries, not including the default
+ /// label
+ pub fn len(&self) -> usize {
+ self.cnt
+ }
+
+ /// Returns whether `BrTable` doesn't have any labels apart from the default one.
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Reads br_table entries.
+ ///
+ /// # Examples
+ /// ```rust
+ /// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00];
+ /// let mut reader = wasmparser::BinaryReader::new(&buf);
+ /// let op = reader.read_operator().unwrap();
+ /// if let wasmparser::Operator::BrTable { ref table } = op {
+ /// let br_table_depths = table.read_table().unwrap();
+ /// assert!(br_table_depths.0 == vec![1,2].into_boxed_slice() &&
+ /// br_table_depths.1 == 0);
+ /// } else {
+ /// unreachable!();
+ /// }
+ /// ```
+ pub fn read_table(&self) -> Result<(Box<[u32]>, u32)> {
+ let mut reader = BinaryReader::new(self.buffer);
+ let mut table = Vec::new();
+ while !reader.eof() {
+ table.push(reader.read_var_u32()?);
+ }
+ let default_target = table.pop().ok_or_else(|| BinaryReaderError {
+ message: "br_table missing default target",
+ offset: reader.original_position(),
+ })?;
+ Ok((table.into_boxed_slice(), default_target))
+ }
+}
+
+/// Iterator for `BrTable`.
+///
+/// #Examples
+/// ```rust
+/// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00];
+/// let mut reader = wasmparser::BinaryReader::new(&buf);
+/// let op = reader.read_operator().unwrap();
+/// if let wasmparser::Operator::BrTable { ref table } = op {
+/// for depth in table {
+/// println!("BrTable depth: {}", depth);
+/// }
+/// }
+/// ```
+#[derive(Clone, Debug)]
+pub struct BrTableIterator<'a> {
+ reader: BinaryReader<'a>,
+}
+
+impl<'a> IntoIterator for &'a BrTable<'a> {
+ type Item = u32;
+ type IntoIter = BrTableIterator<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ BrTableIterator {
+ reader: BinaryReader::new(self.buffer),
+ }
+ }
+}
+
+impl<'a> Iterator for BrTableIterator<'a> {
+ type Item = u32;
+
+ fn next(&mut self) -> Option<u32> {
+ if self.reader.eof() {
+ return None;
+ }
+ self.reader.read_var_u32().ok()
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/lib.rs b/third_party/rust/wasmparser-0.48.2/src/lib.rs
new file mode 100644
index 0000000000..e581b932da
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/lib.rs
@@ -0,0 +1,131 @@
+/* Copyright 2017 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.
+ */
+
+//! A simple event-driven library for parsing WebAssembly binary files
+//! (or streams).
+//!
+//! The parser library reports events as they happend and only stores
+//! parsing information for a brief period of time, making it very fast
+//! and memory-efficient. The event-driven model, however, has some drawbacks.
+//! If you need random access to the entire WebAssembly data-structure,
+//! this is not the right library for you. You could however, build such
+//! a data-structure using this library.
+
+pub use crate::binary_reader::BinaryReader;
+pub use crate::binary_reader::Range;
+use crate::binary_reader::SectionHeader;
+
+pub use crate::parser::ElemSectionEntryTable;
+pub use crate::parser::LocalName;
+pub use crate::parser::NameEntry;
+pub use crate::parser::Parser;
+pub use crate::parser::ParserInput;
+pub use crate::parser::ParserState;
+pub use crate::parser::RelocEntry;
+pub use crate::parser::WasmDecoder;
+
+pub use crate::primitives::BinaryReaderError;
+pub use crate::primitives::BrTable;
+pub use crate::primitives::CustomSectionKind;
+pub use crate::primitives::ExternalKind;
+pub use crate::primitives::FuncType;
+pub use crate::primitives::GlobalType;
+pub use crate::primitives::Ieee32;
+pub use crate::primitives::Ieee64;
+pub use crate::primitives::ImportSectionEntryType;
+pub use crate::primitives::LinkingType;
+pub use crate::primitives::MemoryImmediate;
+pub use crate::primitives::MemoryType;
+pub use crate::primitives::NameType;
+pub use crate::primitives::Naming;
+pub use crate::primitives::Operator;
+pub use crate::primitives::RelocType;
+pub use crate::primitives::ResizableLimits;
+pub use crate::primitives::Result;
+pub use crate::primitives::SectionCode;
+pub use crate::primitives::TableType;
+pub use crate::primitives::Type;
+pub use crate::primitives::TypeOrFuncType;
+pub use crate::primitives::V128;
+
+pub use crate::validator::validate;
+pub use crate::validator::validate_function_body;
+pub use crate::validator::ValidatingOperatorParser;
+pub use crate::validator::ValidatingParser;
+pub use crate::validator::ValidatingParserConfig;
+
+pub use crate::module_resources::WasmFuncType;
+pub use crate::module_resources::WasmGlobalType;
+pub use crate::module_resources::WasmMemoryType;
+pub use crate::module_resources::WasmModuleResources;
+pub use crate::module_resources::WasmTableType;
+pub use crate::module_resources::WasmType;
+
+pub(crate) use crate::module_resources::{wasm_func_type_inputs, wasm_func_type_outputs};
+
+pub use crate::operators_validator::OperatorValidatorConfig;
+
+pub use crate::readers::CodeSectionReader;
+pub use crate::readers::CustomSectionContent;
+pub use crate::readers::Data;
+pub use crate::readers::DataKind;
+pub use crate::readers::DataSectionReader;
+pub use crate::readers::Element;
+pub use crate::readers::ElementItem;
+pub use crate::readers::ElementItems;
+pub use crate::readers::ElementItemsReader;
+pub use crate::readers::ElementKind;
+pub use crate::readers::ElementSectionReader;
+pub use crate::readers::Export;
+pub use crate::readers::ExportSectionReader;
+pub use crate::readers::FunctionBody;
+pub use crate::readers::FunctionSectionReader;
+pub use crate::readers::Global;
+pub use crate::readers::GlobalSectionReader;
+pub use crate::readers::Import;
+pub use crate::readers::ImportSectionReader;
+pub use crate::readers::InitExpr;
+pub use crate::readers::LinkingSectionReader;
+pub use crate::readers::LocalsReader;
+pub use crate::readers::MemorySectionReader;
+pub use crate::readers::ModuleReader;
+pub use crate::readers::Name;
+pub use crate::readers::NameSectionReader;
+pub use crate::readers::NamingReader;
+pub use crate::readers::OperatorsReader;
+pub use crate::readers::ProducersField;
+pub use crate::readers::ProducersFieldValue;
+pub use crate::readers::ProducersFieldValuesReader;
+pub use crate::readers::ProducersSectionReader;
+pub use crate::readers::Reloc;
+pub use crate::readers::RelocSectionReader;
+pub use crate::readers::Section;
+pub use crate::readers::SectionContent;
+pub use crate::readers::SectionIterator;
+pub use crate::readers::SectionIteratorLimited;
+pub use crate::readers::SectionReader;
+pub use crate::readers::SectionWithLimitedItems;
+pub use crate::readers::TableSectionReader;
+pub use crate::readers::TypeSectionReader;
+
+mod binary_reader;
+mod limits;
+mod module_resources;
+mod operators_validator;
+mod parser;
+mod primitives;
+mod readers;
+mod tests;
+mod validator;
diff --git a/third_party/rust/wasmparser-0.48.2/src/limits.rs b/third_party/rust/wasmparser-0.48.2/src/limits.rs
new file mode 100644
index 0000000000..38594a6362
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/limits.rs
@@ -0,0 +1,34 @@
+/* Copyright 2017 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.
+ */
+
+// The following limits are imposed by wasmparser on WebAssembly modules.
+// The limits are agreed upon with other engines for consistency.
+pub const MAX_WASM_TYPES: usize = 1_000_000;
+pub const MAX_WASM_FUNCTIONS: usize = 1_000_000;
+pub const _MAX_WASM_IMPORTS: usize = 100_000;
+pub const _MAX_WASM_EXPORTS: usize = 100_000;
+pub const MAX_WASM_GLOBALS: usize = 1_000_000;
+pub const _MAX_WASM_DATA_SEGMENTS: usize = 100_000;
+pub const MAX_WASM_MEMORY_PAGES: usize = 65536;
+pub const MAX_WASM_STRING_SIZE: usize = 100_000;
+pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
+pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024;
+pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000;
+pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000;
+pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000;
+pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000;
+pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000;
+pub const MAX_WASM_TABLES: usize = 1;
+pub const MAX_WASM_MEMORIES: usize = 1;
diff --git a/third_party/rust/wasmparser-0.48.2/src/module_resources.rs b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs
new file mode 100644
index 0000000000..09b193757d
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs
@@ -0,0 +1,370 @@
+/* Copyright 2019 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.
+ */
+
+/// Types that qualify as Wasm types for validation purposes.
+///
+/// Must be comparable with `wasmparser` given Wasm types and
+/// must be comparable to themselves.
+pub trait WasmType: PartialEq<crate::Type> + PartialEq + Eq {
+ /// Converts the custom type into a `wasmparser` known type.
+ ///
+ /// # Note
+ ///
+ /// This interface is required as bridge until transitioning is complete.
+ fn to_parser_type(&self) -> crate::Type;
+}
+
+/// Types that qualify as Wasm function types for validation purposes.
+pub trait WasmFuncType {
+ /// A type that is comparable with Wasm types.
+ type Type: WasmType;
+
+ /// Returns the number of input types.
+ fn len_inputs(&self) -> usize;
+ /// Returns the number of output types.
+ fn len_outputs(&self) -> usize;
+ /// Returns the type at given index if any.
+ ///
+ /// # Note
+ ///
+ /// The returned type may be wrapped by the user crate and thus
+ /// the actually returned type only has to be comparable to a Wasm type.
+ fn input_at(&self, at: u32) -> Option<&Self::Type>;
+ /// Returns the type at given index if any.
+ ///
+ /// # Note
+ ///
+ /// The returned type may be wrapped by the user crate and thus
+ /// the actually returned type only has to be comparable to a Wasm type.
+ fn output_at(&self, at: u32) -> Option<&Self::Type>;
+}
+
+/// Iterator over the inputs of a Wasm function type.
+pub(crate) struct WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ /// The iterated-over function type.
+ func_type: &'a F,
+ /// The current starting index.
+ start: u32,
+ /// The current ending index.
+ end: u32,
+}
+
+impl<'a, F, T> WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn new(func_type: &'a F) -> Self {
+ Self {
+ func_type,
+ start: 0,
+ end: func_type.len_inputs() as u32,
+ }
+ }
+}
+
+impl<'a, F, T> Iterator for WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.start == self.end {
+ return None;
+ }
+ let ty = self
+ .func_type
+ .input_at(self.start)
+ // Expected since `self.start != self.end`.
+ .expect("we expect to receive an input type at this point");
+ self.start += 1;
+ Some(ty)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.start == self.end {
+ return None;
+ }
+ let ty = self
+ .func_type
+ .input_at(self.end)
+ // Expected since `self.start != self.end`.
+ .expect("we expect to receive an input type at this point");
+ self.end -= 1;
+ Some(ty)
+ }
+}
+
+impl<'a, F, T> ExactSizeIterator for WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn len(&self) -> usize {
+ (self.end as usize) - (self.start as usize)
+ }
+}
+
+/// Iterator over the outputs of a Wasm function type.
+pub(crate) struct WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ /// The iterated-over function type.
+ func_type: &'a F,
+ /// The current starting index.
+ start: u32,
+ /// The current ending index.
+ end: u32,
+}
+
+impl<'a, F, T> WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn new(func_type: &'a F) -> Self {
+ Self {
+ func_type,
+ start: 0,
+ end: func_type.len_outputs() as u32,
+ }
+ }
+}
+
+impl<'a, F, T> Iterator for WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.start == self.end {
+ return None;
+ }
+ let ty = self
+ .func_type
+ .output_at(self.start)
+ // Expected since `self.start != self.end`.
+ .expect("we expect to receive an input type at this point");
+ self.start += 1;
+ Some(ty)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.start == self.end {
+ return None;
+ }
+ let ty = self
+ .func_type
+ .output_at(self.end)
+ // Expected since `self.start != self.end`.
+ .expect("we expect to receive an input type at this point");
+ self.end -= 1;
+ Some(ty)
+ }
+}
+
+impl<'a, F, T> ExactSizeIterator for WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ fn len(&self) -> usize {
+ (self.end as usize) - (self.start as usize)
+ }
+}
+
+/// Returns an iterator over the input types of a Wasm function type.
+pub(crate) fn wasm_func_type_inputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeInputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ WasmFuncTypeInputs::new(func_type)
+}
+
+/// Returns an iterator over the output types of a Wasm function type.
+pub(crate) fn wasm_func_type_outputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeOutputs<'a, F, T>
+where
+ F: WasmFuncType<Type = T>,
+ T: WasmType + 'a,
+{
+ WasmFuncTypeOutputs::new(func_type)
+}
+
+/// Types that qualify as Wasm table types for validation purposes.
+pub trait WasmTableType {
+ /// A type that is comparable with Wasm types.
+ type Type: WasmType;
+
+ /// Returns the element type of the table.
+ fn element_type(&self) -> &Self::Type;
+ /// Returns the initial limit of the table.
+ fn initial_limit(&self) -> u32;
+ /// Returns the maximum limit of the table if any.
+ fn maximum_limit(&self) -> Option<u32>;
+}
+
+/// Types that qualify as Wasm memory types for validation purposes.
+pub trait WasmMemoryType {
+ /// Returns `true` if the linear memory is shared.
+ fn is_shared(&self) -> bool;
+ /// Returns the initial limit of the linear memory.
+ fn initial_limit(&self) -> u32;
+ /// Returns the maximum limit of the linear memory if any.
+ fn maximum_limit(&self) -> Option<u32>;
+}
+
+/// Types that qualify as Wasm global types for validation purposes.
+pub trait WasmGlobalType {
+ /// A type that is comparable with Wasm types.
+ type Type: WasmType;
+
+ /// Returns `true` if the global variable is mutable.
+ fn is_mutable(&self) -> bool;
+ /// Returns the content type of the global variable.
+ fn content_type(&self) -> &Self::Type;
+}
+
+/// Types that qualify as Wasm valiation database.
+///
+/// # Note
+///
+/// The `wasmparser` crate provides a builtin validation framework but allows
+/// users of this crate to also feed the parsed Wasm into their own data
+/// structure while parsing and also validate at the same time without
+/// the need of an additional parsing or validation step or copying data around.
+pub trait WasmModuleResources {
+ /// The function type used for validation.
+ type FuncType: WasmFuncType;
+ /// The table type used for validation.
+ type TableType: WasmTableType;
+ /// The memory type used for validation.
+ type MemoryType: WasmMemoryType;
+ /// The global type used for validation.
+ type GlobalType: WasmGlobalType;
+
+ /// Returns the type at given index.
+ fn type_at(&self, at: u32) -> Option<&Self::FuncType>;
+ /// Returns the table at given index if any.
+ fn table_at(&self, at: u32) -> Option<&Self::TableType>;
+ /// Returns the linear memory at given index.
+ fn memory_at(&self, at: u32) -> Option<&Self::MemoryType>;
+ /// Returns the global variable at given index.
+ fn global_at(&self, at: u32) -> Option<&Self::GlobalType>;
+ /// Returns the function signature ID at given index.
+ fn func_type_id_at(&self, at: u32) -> Option<u32>;
+
+ /// Returns the number of elements.
+ fn element_count(&self) -> u32;
+ /// Returns the number of bytes in the Wasm data section.
+ fn data_count(&self) -> u32;
+}
+
+impl WasmType for crate::Type {
+ fn to_parser_type(&self) -> crate::Type {
+ *self
+ }
+}
+
+impl WasmFuncType for crate::FuncType {
+ type Type = crate::Type;
+
+ fn len_inputs(&self) -> usize {
+ self.params.len()
+ }
+
+ fn len_outputs(&self) -> usize {
+ self.returns.len()
+ }
+
+ fn input_at(&self, at: u32) -> Option<&Self::Type> {
+ self.params.get(at as usize)
+ }
+
+ fn output_at(&self, at: u32) -> Option<&Self::Type> {
+ self.returns.get(at as usize)
+ }
+}
+
+impl WasmGlobalType for crate::GlobalType {
+ type Type = crate::Type;
+
+ fn is_mutable(&self) -> bool {
+ self.mutable
+ }
+
+ fn content_type(&self) -> &Self::Type {
+ &self.content_type
+ }
+}
+
+impl WasmTableType for crate::TableType {
+ type Type = crate::Type;
+
+ fn element_type(&self) -> &Self::Type {
+ &self.element_type
+ }
+
+ fn initial_limit(&self) -> u32 {
+ self.limits.initial
+ }
+
+ fn maximum_limit(&self) -> Option<u32> {
+ self.limits.maximum
+ }
+}
+
+impl WasmMemoryType for crate::MemoryType {
+ fn is_shared(&self) -> bool {
+ self.shared
+ }
+
+ fn initial_limit(&self) -> u32 {
+ self.limits.initial
+ }
+ fn maximum_limit(&self) -> Option<u32> {
+ self.limits.maximum
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs
new file mode 100644
index 0000000000..71f9bc319c
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs
@@ -0,0 +1,1896 @@
+/* Copyright 2019 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 std::cmp::min;
+use std::result;
+use std::str;
+
+use crate::primitives::{MemoryImmediate, Operator, SIMDLaneIndex, Type, TypeOrFuncType};
+use crate::{
+ wasm_func_type_inputs, wasm_func_type_outputs, WasmFuncType, WasmGlobalType, WasmMemoryType,
+ WasmModuleResources, WasmTableType, WasmType,
+};
+
+/// Test if `subtype` is a subtype of `supertype`.
+pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
+ match supertype {
+ Type::AnyRef => {
+ subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef
+ }
+ Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef,
+ _ => subtype == supertype,
+ }
+}
+
+#[derive(Debug)]
+struct BlockState {
+ start_types: Vec<Type>,
+ return_types: Vec<Type>,
+ stack_starts_at: usize,
+ jump_to_top: bool,
+ is_else_allowed: bool,
+ is_dead_code: bool,
+ polymorphic_values: Option<usize>,
+}
+
+impl BlockState {
+ fn is_stack_polymorphic(&self) -> bool {
+ self.polymorphic_values.is_some()
+ }
+}
+
+#[derive(Debug)]
+struct FuncState {
+ local_types: Vec<Type>,
+ blocks: Vec<BlockState>,
+ stack_types: Vec<Type>,
+ end_function: bool,
+}
+
+impl FuncState {
+ fn block_at(&self, depth: usize) -> &BlockState {
+ assert!(depth < self.blocks.len());
+ &self.blocks[self.blocks.len() - 1 - depth]
+ }
+ fn last_block(&self) -> &BlockState {
+ self.blocks.last().unwrap()
+ }
+ fn assert_stack_type_at(&self, index: usize, expected: Type) -> bool {
+ let stack_starts_at = self.last_block().stack_starts_at;
+ if self.last_block().is_stack_polymorphic()
+ && stack_starts_at + index >= self.stack_types.len()
+ {
+ return true;
+ }
+ assert!(stack_starts_at + index < self.stack_types.len());
+ is_subtype_supertype(
+ self.stack_types[self.stack_types.len() - 1 - index],
+ expected,
+ )
+ }
+ fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool {
+ assert!(depth < self.blocks.len());
+ let blocks_end = self.blocks.len();
+ let block_offset = blocks_end - 1 - depth;
+ for i in block_offset..blocks_end {
+ if self.blocks[i].is_stack_polymorphic() {
+ return true;
+ }
+ }
+ let block_starts_at = self.blocks[block_offset].stack_starts_at;
+ self.stack_types.len() >= block_starts_at + minimal_len
+ }
+ fn assert_last_block_stack_len_exact(&self, len: usize) -> bool {
+ let block_starts_at = self.last_block().stack_starts_at;
+ if self.last_block().is_stack_polymorphic() {
+ let polymorphic_values = self.last_block().polymorphic_values.unwrap();
+ self.stack_types.len() + polymorphic_values <= block_starts_at + len
+ } else {
+ self.stack_types.len() == block_starts_at + len
+ }
+ }
+ fn remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
+ if remove_count == 0 {
+ return Ok(());
+ }
+ let last_block = self.blocks.last_mut().unwrap();
+ if last_block.is_stack_polymorphic() {
+ let len = self.stack_types.len();
+ let remove_non_polymorphic = len
+ .checked_sub(last_block.stack_starts_at)
+ .ok_or("invalid block signature")?
+ .min(remove_count);
+ self.stack_types.truncate(len - remove_non_polymorphic);
+ let polymorphic_values = last_block.polymorphic_values.unwrap();
+ let remove_polymorphic = min(remove_count - remove_non_polymorphic, polymorphic_values);
+ last_block.polymorphic_values = Some(polymorphic_values - remove_polymorphic);
+ } else {
+ assert!(self.stack_types.len() >= last_block.stack_starts_at + remove_count);
+ let keep = self.stack_types.len() - remove_count;
+ self.stack_types.truncate(keep);
+ }
+ Ok(())
+ }
+ fn push_block<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>(
+ &mut self,
+ ty: TypeOrFuncType,
+ block_type: BlockType,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ let (start_types, return_types) = match ty {
+ TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
+ TypeOrFuncType::Type(ty) => (vec![], vec![ty]),
+ TypeOrFuncType::FuncType(idx) => {
+ let ty = resources
+ .type_at(idx)
+ // Note: This was an out-of-bounds memory access before
+ // the change to return `Option` at `type_at`. So
+ // I assumed that invalid indices at this point are
+ // bugs.
+ .expect("function type index is out of bounds");
+ (
+ wasm_func_type_inputs(ty)
+ .map(WasmType::to_parser_type)
+ .collect::<Vec<_>>(),
+ wasm_func_type_outputs(ty)
+ .map(WasmType::to_parser_type)
+ .collect::<Vec<_>>(),
+ )
+ }
+ };
+ if block_type == BlockType::If {
+ let last_block = self.blocks.last().unwrap();
+ if !last_block.is_stack_polymorphic()
+ || self.stack_types.len() > last_block.stack_starts_at
+ {
+ self.stack_types.pop();
+ }
+ assert!(self.stack_types.len() >= last_block.stack_starts_at);
+ }
+ for (i, ty) in start_types.iter().rev().enumerate() {
+ if !self.assert_stack_type_at(i, *ty) {
+ return Err("stack operand type mismatch");
+ }
+ }
+ let stack_starts_at = self.stack_types.len() - start_types.len();
+ self.blocks.push(BlockState {
+ start_types,
+ return_types,
+ stack_starts_at,
+ jump_to_top: block_type == BlockType::Loop,
+ is_else_allowed: block_type == BlockType::If,
+ is_dead_code: false,
+ polymorphic_values: None,
+ });
+ Ok(())
+ }
+ fn pop_block(&mut self) {
+ assert!(self.blocks.len() > 1);
+ let last_block = self.blocks.pop().unwrap();
+ if last_block.is_stack_polymorphic() {
+ assert!(
+ self.stack_types.len()
+ <= last_block.return_types.len() + last_block.stack_starts_at
+ );
+ } else {
+ assert!(
+ self.stack_types.len()
+ == last_block.return_types.len() + last_block.stack_starts_at
+ );
+ }
+ let keep = last_block.stack_starts_at;
+ self.stack_types.truncate(keep);
+ self.stack_types.extend_from_slice(&last_block.return_types);
+ }
+ fn reset_block(&mut self) {
+ assert!(self.last_block().is_else_allowed);
+ let last_block = self.blocks.last_mut().unwrap();
+ let keep = last_block.stack_starts_at;
+ self.stack_types.truncate(keep);
+ self.stack_types
+ .extend(last_block.start_types.iter().cloned());
+ last_block.is_else_allowed = false;
+ last_block.polymorphic_values = None;
+ }
+ fn change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
+ self.remove_frame_stack_types(remove_count)
+ }
+ fn change_frame_with_type(
+ &mut self,
+ remove_count: usize,
+ ty: Type,
+ ) -> OperatorValidatorResult<()> {
+ self.remove_frame_stack_types(remove_count)?;
+ self.stack_types.push(ty);
+ Ok(())
+ }
+ fn change_frame_with_types<I>(
+ &mut self,
+ remove_count: usize,
+ new_items: I,
+ ) -> OperatorValidatorResult<()>
+ where
+ I: Iterator<Item = Type>,
+ {
+ self.remove_frame_stack_types(remove_count)?;
+ self.stack_types.extend(new_items);
+ Ok(())
+ }
+ fn change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()> {
+ let types = self.block_at(depth).return_types.clone();
+ let last_block = self.blocks.last_mut().unwrap();
+ let keep = last_block.stack_starts_at;
+ self.stack_types.truncate(keep);
+ self.stack_types.extend_from_slice(&types);
+ last_block.polymorphic_values = None;
+ Ok(())
+ }
+ fn change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()> {
+ self.remove_frame_stack_types(3)?;
+ if ty.is_none() {
+ let last_block = self.blocks.last_mut().unwrap();
+ assert!(last_block.is_stack_polymorphic());
+ last_block.polymorphic_values = Some(last_block.polymorphic_values.unwrap() + 1);
+ return Ok(());
+ }
+ self.stack_types.push(ty.unwrap());
+ Ok(())
+ }
+ fn start_dead_code(&mut self) {
+ let last_block = self.blocks.last_mut().unwrap();
+ let keep = last_block.stack_starts_at;
+ self.stack_types.truncate(keep);
+ last_block.is_dead_code = true;
+ last_block.polymorphic_values = Some(0);
+ }
+ fn end_function(&mut self) {
+ self.end_function = true;
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum BlockType {
+ Block,
+ Loop,
+ If,
+}
+
+pub enum FunctionEnd {
+ No,
+ Yes,
+}
+
+type OperatorValidatorResult<T> = result::Result<T, &'static str>;
+
+#[derive(Copy, Clone, Debug)]
+pub struct OperatorValidatorConfig {
+ pub enable_threads: bool,
+ pub enable_reference_types: bool,
+ pub enable_simd: bool,
+ pub enable_bulk_memory: bool,
+ pub enable_multi_value: bool,
+
+ #[cfg(feature = "deterministic")]
+ pub deterministic_only: bool,
+}
+
+pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig =
+ OperatorValidatorConfig {
+ enable_threads: false,
+ enable_reference_types: false,
+ enable_simd: false,
+ enable_bulk_memory: false,
+ enable_multi_value: false,
+
+ #[cfg(feature = "deterministic")]
+ deterministic_only: true,
+ };
+
+#[derive(Debug)]
+pub(crate) struct OperatorValidator {
+ func_state: FuncState,
+ config: OperatorValidatorConfig,
+}
+
+impl OperatorValidator {
+ pub fn new<F, T>(
+ func_type: &F,
+ locals: &[(u32, Type)],
+ config: OperatorValidatorConfig,
+ ) -> OperatorValidator
+ where
+ F: WasmFuncType<Type = T>,
+ T: WasmType,
+ {
+ let local_types = {
+ let mut local_types = wasm_func_type_inputs(func_type)
+ .map(WasmType::to_parser_type)
+ .collect::<Vec<_>>();
+ for local in locals {
+ for _ in 0..local.0 {
+ local_types.push(local.1);
+ }
+ }
+ local_types
+ };
+ let mut blocks = Vec::new();
+ let last_returns = wasm_func_type_outputs(func_type)
+ .map(WasmType::to_parser_type)
+ .collect::<Vec<_>>();
+ blocks.push(BlockState {
+ start_types: vec![],
+ return_types: last_returns,
+ stack_starts_at: 0,
+ jump_to_top: false,
+ is_else_allowed: false,
+ is_dead_code: false,
+ polymorphic_values: None,
+ });
+
+ OperatorValidator {
+ func_state: FuncState {
+ local_types,
+ blocks,
+ stack_types: Vec::new(),
+ end_function: false,
+ },
+ config,
+ }
+ }
+
+ pub fn is_dead_code(&self) -> bool {
+ self.func_state.last_block().is_dead_code
+ }
+
+ fn check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()> {
+ if !self.func_state.assert_block_stack_len(0, require_count) {
+ Err("not enough operands")
+ } else {
+ Ok(())
+ }
+ }
+
+ fn check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()> {
+ self.check_frame_size(1)?;
+ if !self.func_state.assert_stack_type_at(0, operand) {
+ return Err("stack operand type mismatch");
+ }
+ Ok(())
+ }
+
+ fn check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()> {
+ self.check_frame_size(2)?;
+ if !self.func_state.assert_stack_type_at(1, operand1) {
+ return Err("stack operand type mismatch");
+ }
+ if !self.func_state.assert_stack_type_at(0, operand2) {
+ return Err("stack operand type mismatch");
+ }
+ Ok(())
+ }
+
+ fn check_operands_3(
+ &self,
+ operand1: Type,
+ operand2: Type,
+ operand3: Type,
+ ) -> OperatorValidatorResult<()> {
+ self.check_frame_size(3)?;
+ if !self.func_state.assert_stack_type_at(2, operand1) {
+ return Err("stack operand type mismatch");
+ }
+ if !self.func_state.assert_stack_type_at(1, operand2) {
+ return Err("stack operand type mismatch");
+ }
+ if !self.func_state.assert_stack_type_at(0, operand3) {
+ return Err("stack operand type mismatch");
+ }
+ Ok(())
+ }
+
+ fn check_operands<I>(&self, expected_types: I) -> OperatorValidatorResult<()>
+ where
+ I: ExactSizeIterator<Item = Type>,
+ {
+ let len = expected_types.len();
+ self.check_frame_size(len)?;
+ for (i, expected_type) in expected_types.enumerate() {
+ if !self
+ .func_state
+ .assert_stack_type_at(len - 1 - i, expected_type)
+ {
+ return Err("stack operand type mismatch");
+ }
+ }
+ Ok(())
+ }
+
+ fn check_block_return_types(
+ &self,
+ block: &BlockState,
+ reserve_items: usize,
+ ) -> OperatorValidatorResult<()> {
+ if !self.config.enable_multi_value && block.return_types.len() > 1 {
+ return Err("blocks, loops, and ifs may only return at most one \
+ value when multi-value is not enabled");
+ }
+ let len = block.return_types.len();
+ for i in 0..len {
+ if !self
+ .func_state
+ .assert_stack_type_at(len - 1 - i + reserve_items, block.return_types[i])
+ {
+ return Err("stack item type does not match block item type");
+ }
+ }
+ Ok(())
+ }
+
+ fn check_block_return(&self) -> OperatorValidatorResult<()> {
+ let len = self.func_state.last_block().return_types.len();
+ if !self.func_state.assert_last_block_stack_len_exact(len) {
+ return Err("stack size does not match block type");
+ }
+ self.check_block_return_types(self.func_state.last_block(), 0)
+ }
+
+ fn check_jump_from_block(
+ &self,
+ relative_depth: u32,
+ reserve_items: usize,
+ ) -> OperatorValidatorResult<()> {
+ if relative_depth as usize >= self.func_state.blocks.len() {
+ return Err("invalid block depth");
+ }
+ let block = self.func_state.block_at(relative_depth as usize);
+ if block.jump_to_top {
+ if !self.func_state.assert_block_stack_len(0, reserve_items) {
+ return Err("stack size does not match target loop type");
+ }
+ return Ok(());
+ }
+
+ let len = block.return_types.len();
+ if !self
+ .func_state
+ .assert_block_stack_len(0, len + reserve_items)
+ {
+ return Err("stack size does not match target block type");
+ }
+ self.check_block_return_types(block, reserve_items)
+ }
+
+ fn match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()> {
+ if depth1 as usize >= self.func_state.blocks.len() {
+ return Err("invalid block depth");
+ }
+ if depth2 as usize >= self.func_state.blocks.len() {
+ return Err("invalid block depth");
+ }
+ let block1 = self.func_state.block_at(depth1 as usize);
+ let block2 = self.func_state.block_at(depth2 as usize);
+ let return_types1 = &block1.return_types;
+ let return_types2 = &block2.return_types;
+ if block1.jump_to_top || block2.jump_to_top {
+ if block1.jump_to_top {
+ if !block2.jump_to_top && !return_types2.is_empty() {
+ return Err("block types do not match");
+ }
+ } else if !return_types1.is_empty() {
+ return Err("block types do not match");
+ }
+ } else if *return_types1 != *return_types2 {
+ return Err("block types do not match");
+ }
+ Ok(())
+ }
+
+ fn check_memory_index<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+ >(
+ &self,
+ memory_index: u32,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ if resources.memory_at(memory_index).is_none() {
+ return Err("no linear memories are present");
+ }
+ Ok(())
+ }
+
+ fn check_shared_memory_index<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+ >(
+ &self,
+ memory_index: u32,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ match resources.memory_at(memory_index) {
+ Some(memory) if !memory.is_shared() => {
+ return Err("atomic accesses require shared memory")
+ }
+ None => return Err("no linear memories are present"),
+ _ => Ok(()),
+ }
+ }
+
+ fn check_memarg<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>(
+ &self,
+ memarg: MemoryImmediate,
+ max_align: u32,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ self.check_memory_index(0, resources)?;
+ let align = memarg.flags;
+ if align > max_align {
+ return Err("alignment must not be larger than natural");
+ }
+ Ok(())
+ }
+
+ #[cfg(feature = "deterministic")]
+ fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
+ if !self.config.deterministic_only {
+ return Err("deterministic_only support is not enabled");
+ }
+ Ok(())
+ }
+
+ #[inline(always)]
+ #[cfg(not(feature = "deterministic"))]
+ fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
+ Ok(())
+ }
+
+ fn check_threads_enabled(&self) -> OperatorValidatorResult<()> {
+ if !self.config.enable_threads {
+ return Err("threads support is not enabled");
+ }
+ Ok(())
+ }
+
+ fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> {
+ if !self.config.enable_reference_types {
+ return Err("reference types support is not enabled");
+ }
+ Ok(())
+ }
+
+ fn check_simd_enabled(&self) -> OperatorValidatorResult<()> {
+ if !self.config.enable_simd {
+ return Err("SIMD support is not enabled");
+ }
+ Ok(())
+ }
+
+ fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> {
+ if !self.config.enable_bulk_memory {
+ return Err("bulk memory support is not enabled");
+ }
+ Ok(())
+ }
+
+ fn check_shared_memarg_wo_align<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+ >(
+ &self,
+ _: MemoryImmediate,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ self.check_shared_memory_index(0, resources)?;
+ Ok(())
+ }
+
+ fn check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()> {
+ if index >= max {
+ return Err("SIMD index out of bounds");
+ }
+ Ok(())
+ }
+
+ fn check_block_type<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>(
+ &self,
+ ty: TypeOrFuncType,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<()> {
+ match ty {
+ TypeOrFuncType::Type(Type::EmptyBlockType)
+ | TypeOrFuncType::Type(Type::I32)
+ | TypeOrFuncType::Type(Type::I64)
+ | TypeOrFuncType::Type(Type::F32)
+ | TypeOrFuncType::Type(Type::F64) => Ok(()),
+ TypeOrFuncType::Type(Type::AnyRef) | TypeOrFuncType::Type(Type::AnyFunc) => {
+ self.check_reference_types_enabled()
+ }
+ TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(),
+ TypeOrFuncType::FuncType(idx) => match resources.type_at(idx) {
+ None => Err("type index out of bounds"),
+ Some(ty) if !self.config.enable_multi_value => {
+ if ty.len_outputs() > 1 {
+ return Err("blocks, loops, and ifs may only return at most one \
+ value when multi-value is not enabled");
+ }
+ if ty.len_inputs() > 0 {
+ return Err("blocks, loops, and ifs accept no parameters \
+ when multi-value is not enabled");
+ }
+ Ok(())
+ }
+ Some(_) => Ok(()),
+ },
+ _ => Err("invalid block return type"),
+ }
+ }
+
+ fn check_block_params<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+ >(
+ &self,
+ ty: TypeOrFuncType,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ skip: usize,
+ ) -> OperatorValidatorResult<()> {
+ if let TypeOrFuncType::FuncType(idx) = ty {
+ let func_ty = resources
+ .type_at(idx)
+ // Note: This was an out-of-bounds memory access before
+ // the change to return `Option` at `type_at`. So
+ // I assumed that invalid indices at this point are
+ // bugs.
+ .expect("function type index is out of bounds");
+ let len = func_ty.len_inputs();
+ self.check_frame_size(len + skip)?;
+ for (i, ty) in wasm_func_type_inputs(func_ty).enumerate() {
+ if !self
+ .func_state
+ .assert_stack_type_at(len - 1 - i + skip, ty.to_parser_type())
+ {
+ return Err("stack operand type mismatch for block");
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn check_select(&self) -> OperatorValidatorResult<Option<Type>> {
+ self.check_frame_size(3)?;
+ let func_state = &self.func_state;
+ let last_block = func_state.last_block();
+
+ let ty = if last_block.is_stack_polymorphic() {
+ match func_state.stack_types.len() - last_block.stack_starts_at {
+ 0 => return Ok(None),
+ 1 => {
+ self.check_operands_1(Type::I32)?;
+ return Ok(None);
+ }
+ 2 => {
+ self.check_operands_1(Type::I32)?;
+ func_state.stack_types[func_state.stack_types.len() - 2]
+ }
+ _ => {
+ let ty = func_state.stack_types[func_state.stack_types.len() - 3];
+ self.check_operands_2(ty, Type::I32)?;
+ ty
+ }
+ }
+ } else {
+ let ty = func_state.stack_types[func_state.stack_types.len() - 3];
+ self.check_operands_2(ty, Type::I32)?;
+ ty
+ };
+
+ if !ty.is_valid_for_old_select() {
+ return Err("invalid type for select");
+ }
+
+ Ok(Some(ty))
+ }
+
+ pub(crate) fn process_operator<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+ >(
+ &mut self,
+ operator: &Operator,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> OperatorValidatorResult<FunctionEnd> {
+ if self.func_state.end_function {
+ return Err("unexpected operator");
+ }
+ match *operator {
+ Operator::Unreachable => self.func_state.start_dead_code(),
+ Operator::Nop => (),
+ Operator::Block { ty } => {
+ self.check_block_type(ty, resources)?;
+ self.check_block_params(ty, resources, 0)?;
+ self.func_state
+ .push_block(ty, BlockType::Block, resources)?;
+ }
+ Operator::Loop { ty } => {
+ self.check_block_type(ty, resources)?;
+ self.check_block_params(ty, resources, 0)?;
+ self.func_state.push_block(ty, BlockType::Loop, resources)?;
+ }
+ Operator::If { ty } => {
+ self.check_block_type(ty, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.check_block_params(ty, resources, 1)?;
+ self.func_state.push_block(ty, BlockType::If, resources)?;
+ }
+ Operator::Else => {
+ if !self.func_state.last_block().is_else_allowed {
+ return Err("unexpected else: if block is not started");
+ }
+ self.check_block_return()?;
+ self.func_state.reset_block()
+ }
+ Operator::End => {
+ self.check_block_return()?;
+ if self.func_state.blocks.len() == 1 {
+ self.func_state.end_function();
+ return Ok(FunctionEnd::Yes);
+ }
+
+ let last_block = &self.func_state.last_block();
+ if last_block.is_else_allowed && last_block.start_types != last_block.return_types {
+ return Err("else is expected: if block has a type that can't be implemented with a no-op");
+ }
+ self.func_state.pop_block()
+ }
+ Operator::Br { relative_depth } => {
+ self.check_jump_from_block(relative_depth, 0)?;
+ self.func_state.start_dead_code()
+ }
+ Operator::BrIf { relative_depth } => {
+ self.check_operands_1(Type::I32)?;
+ self.check_jump_from_block(relative_depth, 1)?;
+ if self.func_state.last_block().is_stack_polymorphic() {
+ self.func_state
+ .change_frame_to_exact_types_from(relative_depth as usize)?;
+ } else {
+ self.func_state.change_frame(1)?;
+ }
+ }
+ Operator::BrTable { ref table } => {
+ self.check_operands_1(Type::I32)?;
+ let mut depth0: Option<u32> = None;
+ for relative_depth in table {
+ if depth0.is_none() {
+ self.check_jump_from_block(relative_depth, 1)?;
+ depth0 = Some(relative_depth);
+ continue;
+ }
+ self.match_block_return(relative_depth, depth0.unwrap())?;
+ }
+ self.func_state.start_dead_code()
+ }
+ Operator::Return => {
+ let depth = (self.func_state.blocks.len() - 1) as u32;
+ self.check_jump_from_block(depth, 0)?;
+ self.func_state.start_dead_code()
+ }
+ Operator::Call { function_index } => match resources.func_type_id_at(function_index) {
+ Some(type_index) => {
+ let ty = resources
+ .type_at(type_index)
+ // Note: This was an out-of-bounds memory access before
+ // the change to return `Option` at `type_at`. So
+ // I assumed that invalid indices at this point are
+ // bugs.
+ .expect("function type index is out of bounds");
+ self.check_operands(wasm_func_type_inputs(ty).map(WasmType::to_parser_type))?;
+ self.func_state.change_frame_with_types(
+ ty.len_inputs(),
+ wasm_func_type_outputs(ty).map(WasmType::to_parser_type),
+ )?;
+ }
+ None => return Err("function index out of bounds"),
+ },
+ Operator::CallIndirect { index, table_index } => {
+ if resources.table_at(table_index).is_none() {
+ return Err("table index out of bounds");
+ }
+ match resources.type_at(index) {
+ None => return Err("type index out of bounds"),
+ Some(ty) => {
+ let types = {
+ let mut types = Vec::with_capacity(ty.len_inputs() + 1);
+ types.extend(wasm_func_type_inputs(ty).map(WasmType::to_parser_type));
+ types.push(Type::I32);
+ types
+ };
+ self.check_operands(types.into_iter())?;
+ self.func_state.change_frame_with_types(
+ ty.len_inputs() + 1,
+ wasm_func_type_outputs(ty).map(WasmType::to_parser_type),
+ )?;
+ }
+ }
+ }
+ Operator::Drop => {
+ self.check_frame_size(1)?;
+ self.func_state.change_frame(1)?;
+ }
+ Operator::Select => {
+ let ty = self.check_select()?;
+ self.func_state.change_frame_after_select(ty)?;
+ }
+ Operator::TypedSelect { ty } => {
+ self.check_operands_3(Type::I32, ty, ty)?;
+ self.func_state.change_frame_after_select(Some(ty))?;
+ }
+ Operator::LocalGet { local_index } => {
+ if local_index as usize >= self.func_state.local_types.len() {
+ return Err("local index out of bounds");
+ }
+ let local_type = self.func_state.local_types[local_index as usize];
+ self.func_state.change_frame_with_type(0, local_type)?;
+ }
+ Operator::LocalSet { local_index } => {
+ if local_index as usize >= self.func_state.local_types.len() {
+ return Err("local index out of bounds");
+ }
+ let local_type = self.func_state.local_types[local_index as usize];
+ self.check_operands_1(local_type)?;
+ self.func_state.change_frame(1)?;
+ }
+ Operator::LocalTee { local_index } => {
+ if local_index as usize >= self.func_state.local_types.len() {
+ return Err("local index out of bounds");
+ }
+ let local_type = self.func_state.local_types[local_index as usize];
+ self.check_operands_1(local_type)?;
+ self.func_state.change_frame_with_type(1, local_type)?;
+ }
+ Operator::GlobalGet { global_index } => {
+ if let Some(ty) = resources.global_at(global_index) {
+ self.func_state
+ .change_frame_with_type(0, ty.content_type().to_parser_type())?;
+ } else {
+ return Err("global index out of bounds");
+ };
+ }
+ Operator::GlobalSet { global_index } => {
+ if let Some(ty) = resources.global_at(global_index) {
+ if !ty.is_mutable() {
+ return Err("global expected to be mutable");
+ }
+ self.check_operands_1(ty.content_type().to_parser_type())?;
+ self.func_state.change_frame(1)?;
+ } else {
+ return Err("global index out of bounds");
+ };
+ }
+ Operator::I32Load { memarg } => {
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64Load { memarg } => {
+ self.check_memarg(memarg, 3, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::F32Load { memarg } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F64Load { memarg } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_memarg(memarg, 3, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::I32Load8S { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Load8U { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Load16S { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Load16U { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64Load8S { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Load8U { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Load16S { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Load16U { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Load32S { memarg } => {
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Load32U { memarg } => {
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I32Store { memarg } => {
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I64Store { memarg } => {
+ self.check_memarg(memarg, 3, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::F32Store { memarg } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_2(Type::I32, Type::F32)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::F64Store { memarg } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_memarg(memarg, 3, resources)?;
+ self.check_operands_2(Type::I32, Type::F64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I32Store8 { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I32Store16 { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I64Store8 { memarg } => {
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I64Store16 { memarg } => {
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I64Store32 { memarg } => {
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::MemorySize {
+ reserved: memory_index,
+ } => {
+ self.check_memory_index(memory_index, resources)?;
+ self.func_state.change_frame_with_type(0, Type::I32)?;
+ }
+ Operator::MemoryGrow {
+ reserved: memory_index,
+ } => {
+ self.check_memory_index(memory_index, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Const { .. } => self.func_state.change_frame_with_type(0, Type::I32)?,
+ Operator::I64Const { .. } => self.func_state.change_frame_with_type(0, Type::I64)?,
+ Operator::F32Const { .. } => {
+ self.check_non_deterministic_enabled()?;
+ self.func_state.change_frame_with_type(0, Type::F32)?;
+ }
+ Operator::F64Const { .. } => {
+ self.check_non_deterministic_enabled()?;
+ self.func_state.change_frame_with_type(0, Type::F64)?;
+ }
+ Operator::I32Eqz => {
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Eq
+ | Operator::I32Ne
+ | Operator::I32LtS
+ | Operator::I32LtU
+ | Operator::I32GtS
+ | Operator::I32GtU
+ | Operator::I32LeS
+ | Operator::I32LeU
+ | Operator::I32GeS
+ | Operator::I32GeU => {
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I64Eqz => {
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64Eq
+ | Operator::I64Ne
+ | Operator::I64LtS
+ | Operator::I64LtU
+ | Operator::I64GtS
+ | Operator::I64GtU
+ | Operator::I64LeS
+ | Operator::I64LeU
+ | Operator::I64GeS
+ | Operator::I64GeU => {
+ self.check_operands_2(Type::I64, Type::I64)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::F32Eq
+ | Operator::F32Ne
+ | Operator::F32Lt
+ | Operator::F32Gt
+ | Operator::F32Le
+ | Operator::F32Ge => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_2(Type::F32, Type::F32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::F64Eq
+ | Operator::F64Ne
+ | Operator::F64Lt
+ | Operator::F64Gt
+ | Operator::F64Le
+ | Operator::F64Ge => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_2(Type::F64, Type::F64)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => {
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32Add
+ | Operator::I32Sub
+ | Operator::I32Mul
+ | Operator::I32DivS
+ | Operator::I32DivU
+ | Operator::I32RemS
+ | Operator::I32RemU
+ | Operator::I32And
+ | Operator::I32Or
+ | Operator::I32Xor
+ | Operator::I32Shl
+ | Operator::I32ShrS
+ | Operator::I32ShrU
+ | Operator::I32Rotl
+ | Operator::I32Rotr => {
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => {
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64Add
+ | Operator::I64Sub
+ | Operator::I64Mul
+ | Operator::I64DivS
+ | Operator::I64DivU
+ | Operator::I64RemS
+ | Operator::I64RemU
+ | Operator::I64And
+ | Operator::I64Or
+ | Operator::I64Xor
+ | Operator::I64Shl
+ | Operator::I64ShrS
+ | Operator::I64ShrU
+ | Operator::I64Rotl
+ | Operator::I64Rotr => {
+ self.check_operands_2(Type::I64, Type::I64)?;
+ self.func_state.change_frame_with_type(2, Type::I64)?;
+ }
+ Operator::F32Abs
+ | Operator::F32Neg
+ | Operator::F32Ceil
+ | Operator::F32Floor
+ | Operator::F32Trunc
+ | Operator::F32Nearest
+ | Operator::F32Sqrt => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F32Add
+ | Operator::F32Sub
+ | Operator::F32Mul
+ | Operator::F32Div
+ | Operator::F32Min
+ | Operator::F32Max
+ | Operator::F32Copysign => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_2(Type::F32, Type::F32)?;
+ self.func_state.change_frame_with_type(2, Type::F32)?;
+ }
+ Operator::F64Abs
+ | Operator::F64Neg
+ | Operator::F64Ceil
+ | Operator::F64Floor
+ | Operator::F64Trunc
+ | Operator::F64Nearest
+ | Operator::F64Sqrt => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::F64Add
+ | Operator::F64Sub
+ | Operator::F64Mul
+ | Operator::F64Div
+ | Operator::F64Min
+ | Operator::F64Max
+ | Operator::F64Copysign => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_2(Type::F64, Type::F64)?;
+ self.func_state.change_frame_with_type(2, Type::F64)?;
+ }
+ Operator::I32WrapI64 => {
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32TruncF32S | Operator::I32TruncF32U => {
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32TruncF64S | Operator::I32TruncF64U => {
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64ExtendI32S | Operator::I64ExtendI32U => {
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64TruncF32S | Operator::I64TruncF32U => {
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64TruncF64S | Operator::I64TruncF64U => {
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::F32ConvertI32S | Operator::F32ConvertI32U => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F32ConvertI64S | Operator::F32ConvertI64U => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F32DemoteF64 => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F64ConvertI32S | Operator::F64ConvertI32U => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::F64ConvertI64S | Operator::F64ConvertI64U => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::F64PromoteF32 => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::I32ReinterpretF32 => {
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64ReinterpretF64 => {
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::F32ReinterpretI32 => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F64ReinterpretI64 => {
+ self.check_non_deterministic_enabled()?;
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => {
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => {
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => {
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => {
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I32Extend16S | Operator::I32Extend8S => {
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+
+ Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => {
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+
+ Operator::I32AtomicLoad { memarg }
+ | Operator::I32AtomicLoad16U { memarg }
+ | Operator::I32AtomicLoad8U { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I64AtomicLoad { memarg }
+ | Operator::I64AtomicLoad32U { memarg }
+ | Operator::I64AtomicLoad16U { memarg }
+ | Operator::I64AtomicLoad8U { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I32AtomicStore { memarg }
+ | Operator::I32AtomicStore16 { memarg }
+ | Operator::I32AtomicStore8 { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I64AtomicStore { memarg }
+ | Operator::I64AtomicStore32 { memarg }
+ | Operator::I64AtomicStore16 { memarg }
+ | Operator::I64AtomicStore8 { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::I32AtomicRmwAdd { memarg }
+ | Operator::I32AtomicRmwSub { memarg }
+ | Operator::I32AtomicRmwAnd { memarg }
+ | Operator::I32AtomicRmwOr { memarg }
+ | Operator::I32AtomicRmwXor { memarg }
+ | Operator::I32AtomicRmw16AddU { memarg }
+ | Operator::I32AtomicRmw16SubU { memarg }
+ | Operator::I32AtomicRmw16AndU { memarg }
+ | Operator::I32AtomicRmw16OrU { memarg }
+ | Operator::I32AtomicRmw16XorU { memarg }
+ | Operator::I32AtomicRmw8AddU { memarg }
+ | Operator::I32AtomicRmw8SubU { memarg }
+ | Operator::I32AtomicRmw8AndU { memarg }
+ | Operator::I32AtomicRmw8OrU { memarg }
+ | Operator::I32AtomicRmw8XorU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I64AtomicRmwAdd { memarg }
+ | Operator::I64AtomicRmwSub { memarg }
+ | Operator::I64AtomicRmwAnd { memarg }
+ | Operator::I64AtomicRmwOr { memarg }
+ | Operator::I64AtomicRmwXor { memarg }
+ | Operator::I64AtomicRmw32AddU { memarg }
+ | Operator::I64AtomicRmw32SubU { memarg }
+ | Operator::I64AtomicRmw32AndU { memarg }
+ | Operator::I64AtomicRmw32OrU { memarg }
+ | Operator::I64AtomicRmw32XorU { memarg }
+ | Operator::I64AtomicRmw16AddU { memarg }
+ | Operator::I64AtomicRmw16SubU { memarg }
+ | Operator::I64AtomicRmw16AndU { memarg }
+ | Operator::I64AtomicRmw16OrU { memarg }
+ | Operator::I64AtomicRmw16XorU { memarg }
+ | Operator::I64AtomicRmw8AddU { memarg }
+ | Operator::I64AtomicRmw8SubU { memarg }
+ | Operator::I64AtomicRmw8AndU { memarg }
+ | Operator::I64AtomicRmw8OrU { memarg }
+ | Operator::I64AtomicRmw8XorU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame_with_type(2, Type::I64)?;
+ }
+ Operator::I32AtomicRmwXchg { memarg }
+ | Operator::I32AtomicRmw16XchgU { memarg }
+ | Operator::I32AtomicRmw8XchgU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I32AtomicRmwCmpxchg { memarg }
+ | Operator::I32AtomicRmw16CmpxchgU { memarg }
+ | Operator::I32AtomicRmw8CmpxchgU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(3, Type::I32)?;
+ }
+ Operator::I64AtomicRmwXchg { memarg }
+ | Operator::I64AtomicRmw32XchgU { memarg }
+ | Operator::I64AtomicRmw16XchgU { memarg }
+ | Operator::I64AtomicRmw8XchgU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I64)?;
+ self.func_state.change_frame_with_type(2, Type::I64)?;
+ }
+ Operator::I64AtomicRmwCmpxchg { memarg }
+ | Operator::I64AtomicRmw32CmpxchgU { memarg }
+ | Operator::I64AtomicRmw16CmpxchgU { memarg }
+ | Operator::I64AtomicRmw8CmpxchgU { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_3(Type::I32, Type::I64, Type::I64)?;
+ self.func_state.change_frame_with_type(3, Type::I64)?;
+ }
+ Operator::AtomicNotify { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_2(Type::I32, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::I32AtomicWait { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_3(Type::I32, Type::I32, Type::I64)?;
+ self.func_state.change_frame_with_type(3, Type::I32)?;
+ }
+ Operator::I64AtomicWait { memarg } => {
+ self.check_threads_enabled()?;
+ self.check_shared_memarg_wo_align(memarg, resources)?;
+ self.check_operands_3(Type::I32, Type::I64, Type::I64)?;
+ self.func_state.change_frame_with_type(3, Type::I32)?;
+ }
+ Operator::AtomicFence { ref flags } => {
+ self.check_threads_enabled()?;
+ if *flags != 0 {
+ return Err("non-zero flags for fence not supported yet");
+ }
+ }
+ Operator::RefNull => {
+ self.check_reference_types_enabled()?;
+ self.func_state.change_frame_with_type(0, Type::NullRef)?;
+ }
+ Operator::RefIsNull => {
+ self.check_reference_types_enabled()?;
+ self.check_operands_1(Type::AnyRef)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::RefFunc { function_index } => {
+ self.check_reference_types_enabled()?;
+ if resources.func_type_id_at(function_index).is_none() {
+ return Err("function index out of bounds");
+ }
+ self.func_state.change_frame_with_type(0, Type::AnyFunc)?;
+ }
+ Operator::V128Load { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 4, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V128Store { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 4, resources)?;
+ self.check_operands_2(Type::I32, Type::V128)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::V128Const { .. } => {
+ self.check_simd_enabled()?;
+ self.func_state.change_frame_with_type(0, Type::V128)?;
+ }
+ Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => {
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::I64x2Splat => {
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::I64)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::F32x4Splat => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::F32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::F64x2Splat => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::F64)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 16)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 8)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I32x4ExtractLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 4)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I8x16ReplaceLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 16)?;
+ self.check_operands_2(Type::V128, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::I16x8ReplaceLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 8)?;
+ self.check_operands_2(Type::V128, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::I32x4ReplaceLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 4)?;
+ self.check_operands_2(Type::V128, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::I64x2ExtractLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 2)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::I64)?;
+ }
+ Operator::I64x2ReplaceLane { lane } => {
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 2)?;
+ self.check_operands_2(Type::V128, Type::I64)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::F32x4ExtractLane { lane } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 4)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::F32)?;
+ }
+ Operator::F32x4ReplaceLane { lane } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 4)?;
+ self.check_operands_2(Type::V128, Type::F32)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::F64x2ExtractLane { lane } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 2)?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::F64)?;
+ }
+ Operator::F64x2ReplaceLane { lane } => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_simd_lane_index(lane, 2)?;
+ self.check_operands_2(Type::V128, Type::F64)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::F32x4Eq
+ | Operator::F32x4Ne
+ | Operator::F32x4Lt
+ | Operator::F32x4Gt
+ | Operator::F32x4Le
+ | Operator::F32x4Ge
+ | Operator::F64x2Eq
+ | Operator::F64x2Ne
+ | Operator::F64x2Lt
+ | Operator::F64x2Gt
+ | Operator::F64x2Le
+ | Operator::F64x2Ge
+ | Operator::F32x4Add
+ | Operator::F32x4Sub
+ | Operator::F32x4Mul
+ | Operator::F32x4Div
+ | Operator::F32x4Min
+ | Operator::F32x4Max
+ | Operator::F64x2Add
+ | Operator::F64x2Sub
+ | Operator::F64x2Mul
+ | Operator::F64x2Div
+ | Operator::F64x2Min
+ | Operator::F64x2Max => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_operands_2(Type::V128, Type::V128)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::I8x16Eq
+ | Operator::I8x16Ne
+ | Operator::I8x16LtS
+ | Operator::I8x16LtU
+ | Operator::I8x16GtS
+ | Operator::I8x16GtU
+ | Operator::I8x16LeS
+ | Operator::I8x16LeU
+ | Operator::I8x16GeS
+ | Operator::I8x16GeU
+ | Operator::I16x8Eq
+ | Operator::I16x8Ne
+ | Operator::I16x8LtS
+ | Operator::I16x8LtU
+ | Operator::I16x8GtS
+ | Operator::I16x8GtU
+ | Operator::I16x8LeS
+ | Operator::I16x8LeU
+ | Operator::I16x8GeS
+ | Operator::I16x8GeU
+ | Operator::I32x4Eq
+ | Operator::I32x4Ne
+ | Operator::I32x4LtS
+ | Operator::I32x4LtU
+ | Operator::I32x4GtS
+ | Operator::I32x4GtU
+ | Operator::I32x4LeS
+ | Operator::I32x4LeU
+ | Operator::I32x4GeS
+ | Operator::I32x4GeU
+ | Operator::V128And
+ | Operator::V128AndNot
+ | Operator::V128Or
+ | Operator::V128Xor
+ | Operator::I8x16Add
+ | Operator::I8x16AddSaturateS
+ | Operator::I8x16AddSaturateU
+ | Operator::I8x16Sub
+ | Operator::I8x16SubSaturateS
+ | Operator::I8x16SubSaturateU
+ | Operator::I8x16Mul
+ | Operator::I16x8Add
+ | Operator::I16x8AddSaturateS
+ | Operator::I16x8AddSaturateU
+ | Operator::I16x8Sub
+ | Operator::I16x8SubSaturateS
+ | Operator::I16x8SubSaturateU
+ | Operator::I16x8Mul
+ | Operator::I32x4Add
+ | Operator::I32x4Sub
+ | Operator::I32x4Mul
+ | Operator::I64x2Add
+ | Operator::I64x2Sub
+ | Operator::I64x2Mul
+ | Operator::I8x16RoundingAverageU
+ | Operator::I16x8RoundingAverageU
+ | Operator::I8x16NarrowI16x8S
+ | Operator::I8x16NarrowI16x8U
+ | Operator::I16x8NarrowI32x4S
+ | Operator::I16x8NarrowI32x4U => {
+ self.check_simd_enabled()?;
+ self.check_operands_2(Type::V128, Type::V128)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::F32x4Abs
+ | Operator::F32x4Neg
+ | Operator::F32x4Sqrt
+ | Operator::F64x2Abs
+ | Operator::F64x2Neg
+ | Operator::F64x2Sqrt
+ | Operator::F32x4ConvertI32x4S
+ | Operator::F32x4ConvertI32x4U
+ | Operator::F64x2ConvertI64x2S
+ | Operator::F64x2ConvertI64x2U => {
+ self.check_non_deterministic_enabled()?;
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V128Not
+ | Operator::I8x16Neg
+ | Operator::I16x8Neg
+ | Operator::I32x4Neg
+ | Operator::I64x2Neg
+ | Operator::I32x4TruncSatF32x4S
+ | Operator::I32x4TruncSatF32x4U
+ | Operator::I64x2TruncSatF64x2S
+ | Operator::I64x2TruncSatF64x2U
+ | Operator::I16x8WidenLowI8x16S
+ | Operator::I16x8WidenHighI8x16S
+ | Operator::I16x8WidenLowI8x16U
+ | Operator::I16x8WidenHighI8x16U
+ | Operator::I32x4WidenLowI16x8S
+ | Operator::I32x4WidenHighI16x8S
+ | Operator::I32x4WidenLowI16x8U
+ | Operator::I32x4WidenHighI16x8U => {
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V128Bitselect => {
+ self.check_simd_enabled()?;
+ self.check_operands_3(Type::V128, Type::V128, Type::V128)?;
+ self.func_state.change_frame_with_type(3, Type::V128)?;
+ }
+ Operator::I8x16AnyTrue
+ | Operator::I8x16AllTrue
+ | Operator::I16x8AnyTrue
+ | Operator::I16x8AllTrue
+ | Operator::I32x4AnyTrue
+ | Operator::I32x4AllTrue
+ | Operator::I64x2AnyTrue
+ | Operator::I64x2AllTrue => {
+ self.check_simd_enabled()?;
+ self.check_operands_1(Type::V128)?;
+ self.func_state.change_frame_with_type(1, Type::I32)?;
+ }
+ Operator::I8x16Shl
+ | Operator::I8x16ShrS
+ | Operator::I8x16ShrU
+ | Operator::I16x8Shl
+ | Operator::I16x8ShrS
+ | Operator::I16x8ShrU
+ | Operator::I32x4Shl
+ | Operator::I32x4ShrS
+ | Operator::I32x4ShrU
+ | Operator::I64x2Shl
+ | Operator::I64x2ShrS
+ | Operator::I64x2ShrU => {
+ self.check_simd_enabled()?;
+ self.check_operands_2(Type::V128, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::V8x16Swizzle => {
+ self.check_simd_enabled()?;
+ self.check_operands_2(Type::V128, Type::V128)?;
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::V8x16Shuffle { ref lanes } => {
+ self.check_simd_enabled()?;
+ self.check_operands_2(Type::V128, Type::V128)?;
+ for i in lanes {
+ self.check_simd_lane_index(*i, 32)?;
+ }
+ self.func_state.change_frame_with_type(2, Type::V128)?;
+ }
+ Operator::V8x16LoadSplat { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 0, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V16x8LoadSplat { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 1, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V32x4LoadSplat { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 2, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+ Operator::V64x2LoadSplat { memarg }
+ | Operator::I16x8Load8x8S { memarg }
+ | Operator::I16x8Load8x8U { memarg }
+ | Operator::I32x4Load16x4S { memarg }
+ | Operator::I32x4Load16x4U { memarg }
+ | Operator::I64x2Load32x2S { memarg }
+ | Operator::I64x2Load32x2U { memarg } => {
+ self.check_simd_enabled()?;
+ self.check_memarg(memarg, 3, resources)?;
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, Type::V128)?;
+ }
+
+ Operator::MemoryInit { segment } => {
+ self.check_bulk_memory_enabled()?;
+ if segment >= resources.data_count() {
+ return Err("segment index out of bounds");
+ }
+ self.check_memory_index(0, resources)?;
+ self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
+ self.func_state.change_frame(3)?;
+ }
+ Operator::DataDrop { segment } => {
+ self.check_bulk_memory_enabled()?;
+ if segment >= resources.data_count() {
+ return Err("segment index out of bounds");
+ }
+ }
+ Operator::MemoryCopy | Operator::MemoryFill => {
+ self.check_bulk_memory_enabled()?;
+ self.check_memory_index(0, resources)?;
+ self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
+ self.func_state.change_frame(3)?;
+ }
+ Operator::TableInit { segment, table } => {
+ self.check_bulk_memory_enabled()?;
+ if segment >= resources.element_count() {
+ return Err("segment index out of bounds");
+ }
+ if table > 0 {
+ self.check_reference_types_enabled()?;
+ }
+ if resources.table_at(table).is_none() {
+ return Err("table index out of bounds");
+ }
+ self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
+ self.func_state.change_frame(3)?;
+ }
+ Operator::ElemDrop { segment } => {
+ self.check_bulk_memory_enabled()?;
+ if segment >= resources.element_count() {
+ return Err("segment index out of bounds");
+ }
+ }
+ Operator::TableCopy {
+ src_table,
+ dst_table,
+ } => {
+ self.check_bulk_memory_enabled()?;
+ if src_table > 0 || dst_table > 0 {
+ self.check_reference_types_enabled()?;
+ }
+ if resources.table_at(src_table).is_none()
+ || resources.table_at(dst_table).is_none()
+ {
+ return Err("table index out of bounds");
+ }
+ self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
+ self.func_state.change_frame(3)?;
+ }
+ Operator::TableGet { table } => {
+ self.check_reference_types_enabled()?;
+ let ty = match resources.table_at(table) {
+ Some(ty) => ty.element_type().to_parser_type(),
+ None => return Err("table index out of bounds"),
+ };
+ self.check_operands_1(Type::I32)?;
+ self.func_state.change_frame_with_type(1, ty)?;
+ }
+ Operator::TableSet { table } => {
+ self.check_reference_types_enabled()?;
+ let ty = match resources.table_at(table) {
+ Some(ty) => ty.element_type().to_parser_type(),
+ None => return Err("table index out of bounds"),
+ };
+ self.check_operands_2(Type::I32, ty)?;
+ self.func_state.change_frame(2)?;
+ }
+ Operator::TableGrow { table } => {
+ self.check_reference_types_enabled()?;
+ let ty = match resources.table_at(table) {
+ Some(ty) => ty.element_type().to_parser_type(),
+ None => return Err("table index out of bounds"),
+ };
+ self.check_operands_2(ty, Type::I32)?;
+ self.func_state.change_frame_with_type(2, Type::I32)?;
+ }
+ Operator::TableSize { table } => {
+ self.check_reference_types_enabled()?;
+ if resources.table_at(table).is_none() {
+ return Err("table index out of bounds");
+ }
+ self.func_state.change_frame_with_type(0, Type::I32)?;
+ }
+ Operator::TableFill { table } => {
+ self.check_bulk_memory_enabled()?;
+ let ty = match resources.table_at(table) {
+ Some(ty) => ty.element_type().to_parser_type(),
+ None => return Err("table index out of bounds"),
+ };
+ self.check_operands_3(Type::I32, ty, Type::I32)?;
+ self.func_state.change_frame(3)?;
+ }
+ }
+ Ok(FunctionEnd::No)
+ }
+
+ pub(crate) fn process_end_function(&self) -> OperatorValidatorResult<()> {
+ if !self.func_state.end_function {
+ return Err("expected end of function");
+ }
+ Ok(())
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/parser.rs b/third_party/rust/wasmparser-0.48.2/src/parser.rs
new file mode 100644
index 0000000000..9906c6244c
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/parser.rs
@@ -0,0 +1,1185 @@
+/* Copyright 2017 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.
+ */
+// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md
+
+use std::boxed::Box;
+use std::vec::Vec;
+
+use crate::limits::{
+ MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_STRING_SIZE, MAX_WASM_TABLE_ENTRIES,
+};
+
+use crate::primitives::{
+ BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType,
+ ImportSectionEntryType, LinkingType, MemoryType, Naming, Operator, RelocType, Result,
+ SectionCode, TableType, Type,
+};
+
+use crate::readers::{
+ CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
+ ElementKind, ElementSectionReader, Export, ExportSectionReader, FunctionBody,
+ FunctionSectionReader, Global, GlobalSectionReader, Import, ImportSectionReader,
+ LinkingSectionReader, MemorySectionReader, ModuleReader, Name, NameSectionReader, NamingReader,
+ OperatorsReader, Reloc, RelocSectionReader, Section, SectionReader, TableSectionReader,
+ TypeSectionReader,
+};
+
+use crate::binary_reader::{BinaryReader, Range};
+
+const MAX_DATA_CHUNK_SIZE: usize = MAX_WASM_STRING_SIZE;
+
+#[derive(Debug)]
+pub struct LocalName<'a> {
+ pub index: u32,
+ pub locals: Box<[Naming<'a>]>,
+}
+
+#[derive(Debug)]
+pub enum NameEntry<'a> {
+ Module(&'a str),
+ Function(Box<[Naming<'a>]>),
+ Local(Box<[LocalName<'a>]>),
+}
+
+#[derive(Debug)]
+pub struct RelocEntry {
+ pub ty: RelocType,
+ pub offset: u32,
+ pub index: u32,
+ pub addend: Option<u32>,
+}
+
+enum InitExpressionContinuationSection {
+ Global,
+ Element,
+ Data,
+}
+
+#[derive(Debug)]
+pub enum ParserState<'a> {
+ Error(BinaryReaderError),
+ Initial,
+ BeginWasm {
+ version: u32,
+ },
+ EndWasm,
+ BeginSection {
+ code: SectionCode<'a>,
+ range: Range,
+ },
+ EndSection,
+ SkippingSection,
+ ReadingCustomSection(CustomSectionKind),
+ ReadingSectionRawData,
+ SectionRawData(&'a [u8]),
+
+ TypeSectionEntry(FuncType),
+ ImportSectionEntry {
+ module: &'a str,
+ field: &'a str,
+ ty: ImportSectionEntryType,
+ },
+ FunctionSectionEntry(u32),
+ TableSectionEntry(TableType),
+ MemorySectionEntry(MemoryType),
+ ExportSectionEntry {
+ field: &'a str,
+ kind: ExternalKind,
+ index: u32,
+ },
+ NameSectionEntry(NameEntry<'a>),
+ StartSectionEntry(u32),
+ DataCountSectionEntry(u32),
+
+ BeginInitExpressionBody,
+ InitExpressionOperator(Operator<'a>),
+ EndInitExpressionBody,
+
+ BeginFunctionBody {
+ range: Range,
+ },
+ FunctionBodyLocals {
+ locals: Box<[(u32, Type)]>,
+ },
+ CodeOperator(Operator<'a>),
+ EndFunctionBody,
+ SkippingFunctionBody,
+
+ BeginElementSectionEntry {
+ /// `None` means this is a passive or defined entry
+ table: ElemSectionEntryTable,
+ ty: Type,
+ },
+ ElementSectionEntryBody(Box<[ElementItem]>),
+ EndElementSectionEntry,
+
+ BeginPassiveDataSectionEntry,
+ BeginActiveDataSectionEntry(u32),
+ EndDataSectionEntry,
+ BeginDataSectionEntryBody(u32),
+ DataSectionEntryBodyChunk(&'a [u8]),
+ EndDataSectionEntryBody,
+
+ BeginGlobalSectionEntry(GlobalType),
+ EndGlobalSectionEntry,
+
+ RelocSectionHeader(SectionCode<'a>),
+ RelocSectionEntry(RelocEntry),
+ LinkingSectionEntry(LinkingType),
+
+ SourceMappingURL(&'a str),
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum ElemSectionEntryTable {
+ Passive,
+ Declared,
+ Active(u32),
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum ParserInput {
+ Default,
+ SkipSection,
+ SkipFunctionBody,
+ ReadCustomSection,
+ ReadSectionRawData,
+}
+
+pub trait WasmDecoder<'a> {
+ fn read(&mut self) -> &ParserState<'a>;
+ fn push_input(&mut self, input: ParserInput);
+ fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>;
+ fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
+ where
+ 'a: 'b;
+ fn last_state(&self) -> &ParserState<'a>;
+}
+
+enum ParserSectionReader<'a> {
+ None,
+ CodeSectionReader(CodeSectionReader<'a>),
+ DataSectionReader(DataSectionReader<'a>),
+ ElementSectionReader(ElementSectionReader<'a>),
+ ExportSectionReader(ExportSectionReader<'a>),
+ FunctionSectionReader(FunctionSectionReader<'a>),
+ GlobalSectionReader(GlobalSectionReader<'a>),
+ ImportSectionReader(ImportSectionReader<'a>),
+ MemorySectionReader(MemorySectionReader<'a>),
+ TableSectionReader(TableSectionReader<'a>),
+ TypeSectionReader(TypeSectionReader<'a>),
+ NameSectionReader(NameSectionReader<'a>),
+ LinkingSectionReader(LinkingSectionReader<'a>),
+ RelocSectionReader(RelocSectionReader<'a>),
+}
+
+macro_rules! section_reader {
+ ($self:ident, $ty_and_name:ident) => {
+ if let ParserSectionReader::$ty_and_name(ref mut reader) = $self.section_reader {
+ reader
+ } else {
+ panic!("expected {} reader", stringify!($ty_and_name));
+ }
+ };
+}
+
+macro_rules! start_section_reader {
+ ($self:ident, $ty_and_name:ident, $factory:ident) => {{
+ let reader = $self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .$factory()?;
+ $self.section_entries_left = reader.get_count();
+ $self.section_reader = ParserSectionReader::$ty_and_name(reader);
+ }};
+}
+
+/// The `Parser` type. A simple event-driven parser of WebAssembly binary
+/// format. The `read(&mut self)` is used to iterate through WebAssembly records.
+pub struct Parser<'a> {
+ data: &'a [u8],
+ state: ParserState<'a>,
+ module_reader: Option<ModuleReader<'a>>,
+ current_section: Option<Section<'a>>,
+ section_reader: ParserSectionReader<'a>,
+ element_items: Option<ElementItems<'a>>,
+ current_function_body: Option<FunctionBody<'a>>,
+ init_expr_continuation: Option<InitExpressionContinuationSection>,
+ current_data_segment: Option<&'a [u8]>,
+ binary_reader: Option<BinaryReader<'a>>,
+ operators_reader: Option<OperatorsReader<'a>>,
+ section_entries_left: u32,
+}
+
+impl<'a> Parser<'a> {
+ /// Constructs `Parser` type.
+ ///
+ /// # Examples
+ /// ```
+ /// let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// let mut parser = wasmparser::Parser::new(data);
+ /// ```
+ pub fn new(data: &[u8]) -> Parser {
+ Parser {
+ data,
+ state: ParserState::Initial,
+ module_reader: None,
+ current_section: None,
+ section_reader: ParserSectionReader::None,
+ element_items: None,
+ current_function_body: None,
+ init_expr_continuation: None,
+ current_data_segment: None,
+ binary_reader: None,
+ operators_reader: None,
+ section_entries_left: 0,
+ }
+ }
+
+ pub fn eof(&self) -> bool {
+ match self.state {
+ ParserState::EndWasm => true,
+ ParserState::BeginWasm { .. } | ParserState::EndSection => {
+ self.module_reader.as_ref().expect("module reader").eof()
+ }
+ _ => false, // in-process of reading
+ }
+ }
+
+ pub fn current_position(&self) -> usize {
+ if let ParserState::Initial = self.state {
+ return 0;
+ }
+ if self.binary_reader.is_some() {
+ return self
+ .binary_reader
+ .as_ref()
+ .expect("binary reader")
+ .original_position();
+ }
+ if self.operators_reader.is_some() {
+ return self
+ .operators_reader
+ .as_ref()
+ .expect("operators reader")
+ .original_position();
+ }
+ match self.section_reader {
+ ParserSectionReader::CodeSectionReader(ref reader) => {
+ return reader.original_position()
+ }
+ ParserSectionReader::DataSectionReader(ref reader) => {
+ return reader.original_position()
+ }
+ ParserSectionReader::ElementSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::ExportSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::FunctionSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::GlobalSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::ImportSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::MemorySectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::TableSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::TypeSectionReader(ref reader) => {
+ return reader.original_position()
+ }
+ ParserSectionReader::NameSectionReader(ref reader) => {
+ return reader.original_position()
+ }
+ ParserSectionReader::LinkingSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ ParserSectionReader::RelocSectionReader(ref reader) => {
+ return reader.original_position();
+ }
+ _ => (),
+ };
+ // TODO might not cover all cases
+ self.module_reader
+ .as_ref()
+ .expect("module reader")
+ .current_position()
+ }
+
+ fn read_module(&mut self) -> Result<()> {
+ let module_reader = ModuleReader::new(self.data)?;
+ let version = module_reader.get_version();
+ self.module_reader = Some(module_reader);
+ self.state = ParserState::BeginWasm { version };
+ Ok(())
+ }
+
+ fn read_section_header(&mut self) -> Result<()> {
+ let section = self.module_reader.as_mut().expect("module reader").read()?;
+ let code = section.code;
+ let range = section.range();
+ self.current_section = Some(section);
+ self.state = ParserState::BeginSection { code, range };
+ Ok(())
+ }
+
+ fn read_type_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let type_entry = section_reader!(self, TypeSectionReader).read()?;
+ self.state = ParserState::TypeSectionEntry(type_entry);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_import_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Import { module, field, ty } = section_reader!(self, ImportSectionReader).read()?;
+ self.state = ParserState::ImportSectionEntry { module, field, ty };
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_function_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let func_type = section_reader!(self, FunctionSectionReader).read()?;
+ self.state = ParserState::FunctionSectionEntry(func_type);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_memory_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let memory_type = section_reader!(self, MemorySectionReader).read()?;
+ self.state = ParserState::MemorySectionEntry(memory_type);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_global_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Global { ty, init_expr } = section_reader!(self, GlobalSectionReader).read()?;
+ self.state = ParserState::BeginGlobalSectionEntry(ty);
+ self.operators_reader = Some(init_expr.get_operators_reader());
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_init_expression_body(&mut self, cont: InitExpressionContinuationSection) {
+ self.state = ParserState::BeginInitExpressionBody;
+ self.init_expr_continuation = Some(cont);
+ }
+
+ fn read_init_expression_operator(&mut self) -> Result<()> {
+ let op = self
+ .operators_reader
+ .as_mut()
+ .expect("operator reader")
+ .read()?;
+ if let Operator::End = op {
+ self.operators_reader = None;
+ self.state = ParserState::EndInitExpressionBody;
+ return Ok(());
+ }
+ self.state = ParserState::InitExpressionOperator(op);
+ Ok(())
+ }
+
+ fn read_export_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Export { field, kind, index } = section_reader!(self, ExportSectionReader).read()?;
+ self.state = ParserState::ExportSectionEntry { field, kind, index };
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_element_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Element { kind, items, ty } = section_reader!(self, ElementSectionReader).read()?;
+ let table = match kind {
+ ElementKind::Passive => ElemSectionEntryTable::Passive,
+ ElementKind::Declared => ElemSectionEntryTable::Declared,
+ ElementKind::Active {
+ table_index,
+ init_expr,
+ } => {
+ self.operators_reader = Some(init_expr.get_operators_reader());
+ ElemSectionEntryTable::Active(table_index)
+ }
+ };
+ self.state = ParserState::BeginElementSectionEntry { table, ty };
+ self.element_items = Some(items);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_element_entry_body(&mut self) -> Result<()> {
+ let mut reader = self
+ .element_items
+ .take()
+ .expect("element items")
+ .get_items_reader()?;
+ let num_elements = reader.get_count() as usize;
+ if num_elements > MAX_WASM_TABLE_ENTRIES {
+ return Err(BinaryReaderError {
+ message: "num_elements is out of bounds",
+ offset: 0, // reader.position - 1, // TODO offset
+ });
+ }
+ let mut elements = Vec::with_capacity(num_elements);
+ for _ in 0..num_elements {
+ elements.push(reader.read()?);
+ }
+ self.state = ParserState::ElementSectionEntryBody(elements.into_boxed_slice());
+ Ok(())
+ }
+
+ fn read_function_body(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ self.current_function_body = None;
+ return self.check_section_end();
+ }
+ let function_body = section_reader!(self, CodeSectionReader).read()?;
+ let range = function_body.range();
+ self.state = ParserState::BeginFunctionBody { range };
+ self.current_function_body = Some(function_body);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_function_body_locals(&mut self) -> Result<()> {
+ let function_body = self.current_function_body.as_mut().expect("function body");
+ let mut reader = function_body.get_locals_reader()?;
+ let local_count = reader.get_count() as usize;
+ if local_count > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "local_count is out of bounds",
+ offset: reader.original_position() - 1,
+ });
+ }
+ let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
+ let mut locals_total: usize = 0;
+ for _ in 0..local_count {
+ let (count, ty) = reader.read()?;
+ locals_total =
+ locals_total
+ .checked_add(count as usize)
+ .ok_or_else(|| BinaryReaderError {
+ message: "locals_total is out of bounds",
+ offset: reader.original_position() - 1,
+ })?;
+ if locals_total > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "locals_total is out of bounds",
+ offset: reader.original_position() - 1,
+ });
+ }
+ locals.push((count, ty));
+ }
+ self.operators_reader = Some(function_body.get_operators_reader()?);
+ self.state = ParserState::FunctionBodyLocals {
+ locals: locals.into_boxed_slice(),
+ };
+ Ok(())
+ }
+
+ fn read_code_operator(&mut self) -> Result<()> {
+ if self
+ .operators_reader
+ .as_ref()
+ .expect("operator reader")
+ .eof()
+ {
+ if let ParserState::CodeOperator(Operator::End) = self.state {
+ self.state = ParserState::EndFunctionBody;
+ self.operators_reader = None;
+ self.current_function_body = None;
+ return Ok(());
+ }
+ let reader = self.operators_reader.as_ref().expect("operator reader");
+ return Err(BinaryReaderError {
+ message: "Expected end of function marker",
+ offset: reader.original_position(),
+ });
+ }
+ let reader = self.operators_reader.as_mut().expect("operator reader");
+ let op = reader.read()?;
+ self.state = ParserState::CodeOperator(op);
+ Ok(())
+ }
+
+ fn read_table_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let table_entry = section_reader!(self, TableSectionReader).read()?;
+ self.state = ParserState::TableSectionEntry(table_entry);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_data_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Data { kind, data } = section_reader!(self, DataSectionReader).read()?;
+ match kind {
+ DataKind::Passive => {
+ self.state = ParserState::BeginPassiveDataSectionEntry;
+ }
+ DataKind::Active {
+ memory_index,
+ init_expr,
+ } => {
+ self.state = ParserState::BeginActiveDataSectionEntry(memory_index);
+ self.operators_reader = Some(init_expr.get_operators_reader());
+ }
+ }
+ self.current_data_segment = Some(data);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_data_entry_body(&mut self) -> Result<()> {
+ let size = self.current_data_segment.expect("data entry").len();
+ self.state = ParserState::BeginDataSectionEntryBody(size as u32);
+ Ok(())
+ }
+
+ fn read_naming<'b>(
+ mut naming_reader: NamingReader<'a>,
+ limit: usize,
+ ) -> Result<Box<[Naming<'b>]>>
+ where
+ 'a: 'b,
+ {
+ let count = naming_reader.get_count() as usize;
+ if count > limit {
+ return Err(BinaryReaderError {
+ message: "name map size is out of bound",
+ offset: naming_reader.original_position() - 1,
+ });
+ }
+ let mut result = Vec::with_capacity(count);
+ for _ in 0..count {
+ result.push(naming_reader.read()?);
+ }
+ Ok(result.into_boxed_slice())
+ }
+
+ fn read_name_entry(&mut self) -> Result<()> {
+ if section_reader!(self, NameSectionReader).eof() {
+ return self.position_to_section_end();
+ }
+ let entry = match section_reader!(self, NameSectionReader).read()? {
+ Name::Module(name) => NameEntry::Module(name.get_name()?),
+ Name::Function(func) => {
+ NameEntry::Function(Self::read_naming(func.get_map()?, MAX_WASM_FUNCTIONS)?)
+ }
+ Name::Local(locals) => {
+ let mut reader = locals.get_function_local_reader()?;
+ let funcs_len = reader.get_count() as usize;
+ if funcs_len > MAX_WASM_FUNCTIONS {
+ return Err(BinaryReaderError {
+ message: "function count is out of bounds",
+ offset: reader.original_position() - 1,
+ });
+ }
+ let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len);
+ for _ in 0..funcs_len {
+ let func = reader.read()?;
+ funcs.push(LocalName {
+ index: func.func_index,
+ locals: Self::read_naming(func.get_map()?, MAX_WASM_FUNCTION_LOCALS)?,
+ });
+ }
+ NameEntry::Local(funcs.into_boxed_slice())
+ }
+ };
+ self.state = ParserState::NameSectionEntry(entry);
+ Ok(())
+ }
+
+ fn read_source_mapping(&mut self) -> Result<()> {
+ let url = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_sourcemappingurl_section_content()?;
+ self.state = ParserState::SourceMappingURL(url);
+ Ok(())
+ }
+
+ // See https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
+ fn read_reloc_header(&mut self) -> Result<()> {
+ let section_code = section_reader!(self, RelocSectionReader).get_section_code();
+ self.state = ParserState::RelocSectionHeader(section_code);
+ Ok(())
+ }
+
+ fn read_reloc_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let Reloc {
+ ty,
+ offset,
+ index,
+ addend,
+ } = section_reader!(self, RelocSectionReader).read()?;
+ self.state = ParserState::RelocSectionEntry(RelocEntry {
+ ty,
+ offset,
+ index,
+ addend,
+ });
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_linking_entry(&mut self) -> Result<()> {
+ if self.section_entries_left == 0 {
+ return self.check_section_end();
+ }
+ let entry = section_reader!(self, LinkingSectionReader).read()?;
+ self.state = ParserState::LinkingSectionEntry(entry);
+ self.section_entries_left -= 1;
+ Ok(())
+ }
+
+ fn read_section_body(&mut self) -> Result<()> {
+ match self.state {
+ ParserState::BeginSection {
+ code: SectionCode::Type,
+ ..
+ } => {
+ start_section_reader!(self, TypeSectionReader, get_type_section_reader);
+ self.read_type_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Import,
+ ..
+ } => {
+ start_section_reader!(self, ImportSectionReader, get_import_section_reader);
+ self.read_import_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Function,
+ ..
+ } => {
+ start_section_reader!(self, FunctionSectionReader, get_function_section_reader);
+ self.read_function_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Memory,
+ ..
+ } => {
+ start_section_reader!(self, MemorySectionReader, get_memory_section_reader);
+ self.read_memory_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Global,
+ ..
+ } => {
+ start_section_reader!(self, GlobalSectionReader, get_global_section_reader);
+ self.read_global_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Export,
+ ..
+ } => {
+ start_section_reader!(self, ExportSectionReader, get_export_section_reader);
+ self.read_export_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Element,
+ ..
+ } => {
+ start_section_reader!(self, ElementSectionReader, get_element_section_reader);
+ self.read_element_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Code,
+ ..
+ } => {
+ start_section_reader!(self, CodeSectionReader, get_code_section_reader);
+ self.read_function_body()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Table,
+ ..
+ } => {
+ start_section_reader!(self, TableSectionReader, get_table_section_reader);
+ self.read_table_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Data,
+ ..
+ } => {
+ start_section_reader!(self, DataSectionReader, get_data_section_reader);
+ self.read_data_entry()?;
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Start,
+ ..
+ } => {
+ let func_index = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_start_section_content()?;
+ self.state = ParserState::StartSectionEntry(func_index);
+ }
+ ParserState::BeginSection {
+ code: SectionCode::DataCount,
+ ..
+ } => {
+ let func_index = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_data_count_section_content()?;
+ self.state = ParserState::DataCountSectionEntry(func_index);
+ }
+ ParserState::BeginSection {
+ code: SectionCode::Custom { .. },
+ ..
+ } => {
+ self.create_custom_section_binary_reader();
+ self.read_section_body_bytes()?;
+ }
+ _ => unreachable!(),
+ }
+ Ok(())
+ }
+
+ fn create_custom_section_binary_reader(&mut self) {
+ let reader = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_binary_reader();
+ self.binary_reader = Some(reader);
+ }
+
+ fn read_custom_section_body(&mut self) -> Result<()> {
+ match self.state {
+ ParserState::ReadingCustomSection(CustomSectionKind::Name) => {
+ let reader = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_name_section_reader()?;
+ self.section_reader = ParserSectionReader::NameSectionReader(reader);
+ self.read_name_entry()?;
+ }
+ ParserState::ReadingCustomSection(CustomSectionKind::SourceMappingURL) => {
+ self.read_source_mapping()?;
+ }
+ ParserState::ReadingCustomSection(CustomSectionKind::Reloc) => {
+ start_section_reader!(self, RelocSectionReader, get_reloc_section_reader);
+ self.read_reloc_header()?;
+ }
+ ParserState::ReadingCustomSection(CustomSectionKind::Linking) => {
+ start_section_reader!(self, LinkingSectionReader, get_linking_section_reader);
+ self.read_linking_entry()?;
+ }
+ ParserState::ReadingCustomSection(CustomSectionKind::Producers)
+ | ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => {
+ self.create_custom_section_binary_reader();
+ self.read_section_body_bytes()?;
+ }
+ _ => unreachable!(),
+ }
+ Ok(())
+ }
+
+ fn position_to_section_end(&mut self) -> Result<()> {
+ self.current_section = None;
+ self.binary_reader = None;
+ self.state = ParserState::EndSection;
+ Ok(())
+ }
+
+ fn check_section_end(&mut self) -> Result<()> {
+ match self.section_reader {
+ ParserSectionReader::CodeSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::DataSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::ElementSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::ExportSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::FunctionSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::GlobalSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::ImportSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::MemorySectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::TableSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::TypeSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::LinkingSectionReader(ref reader) => reader.ensure_end()?,
+ ParserSectionReader::RelocSectionReader(ref reader) => reader.ensure_end()?,
+ _ => unreachable!(),
+ }
+ self.position_to_section_end()
+ }
+
+ fn read_section_body_bytes(&mut self) -> Result<()> {
+ if self.binary_reader.as_ref().expect("binary reader").eof() {
+ self.state = ParserState::EndSection;
+ self.binary_reader = None;
+ return Ok(());
+ }
+ let binary_reader = self.binary_reader.as_mut().expect("binary reader");
+ let to_read = if binary_reader.buffer.len() - binary_reader.position < MAX_DATA_CHUNK_SIZE {
+ binary_reader.buffer.len() - binary_reader.position
+ } else {
+ MAX_DATA_CHUNK_SIZE
+ };
+ let bytes = binary_reader.read_bytes(to_read)?;
+ self.state = ParserState::SectionRawData(bytes);
+ Ok(())
+ }
+
+ fn read_data_chunk(&mut self) -> Result<()> {
+ let data = self.current_data_segment.expect("data");
+ if data.is_empty() {
+ self.state = ParserState::EndDataSectionEntryBody;
+ self.current_data_segment = None;
+ return Ok(());
+ }
+ let to_read = if data.len() > MAX_DATA_CHUNK_SIZE {
+ MAX_DATA_CHUNK_SIZE
+ } else {
+ data.len()
+ };
+ let (head, tail) = data.split_at(to_read);
+ self.current_data_segment = Some(tail);
+ self.state = ParserState::DataSectionEntryBodyChunk(head);
+ Ok(())
+ }
+
+ fn read_next_section(&mut self) -> Result<()> {
+ if self.module_reader.as_ref().expect("module_reader").eof() {
+ self.current_section = None;
+ self.state = ParserState::EndWasm;
+ } else {
+ self.read_section_header()?;
+ }
+ Ok(())
+ }
+
+ fn read_wrapped(&mut self) -> Result<()> {
+ match self.state {
+ ParserState::EndWasm => panic!("Parser in end state"),
+ ParserState::Error(_) => panic!("Parser in error state"),
+ ParserState::Initial => self.read_module()?,
+ ParserState::BeginWasm { .. } | ParserState::EndSection => self.read_next_section()?,
+ ParserState::BeginSection { .. } => self.read_section_body()?,
+ ParserState::SkippingSection => {
+ self.position_to_section_end()?;
+ self.read_next_section()?;
+ }
+ ParserState::TypeSectionEntry(_) => self.read_type_entry()?,
+ ParserState::ImportSectionEntry { .. } => self.read_import_entry()?,
+ ParserState::FunctionSectionEntry(_) => self.read_function_entry()?,
+ ParserState::MemorySectionEntry(_) => self.read_memory_entry()?,
+ ParserState::TableSectionEntry(_) => self.read_table_entry()?,
+ ParserState::ExportSectionEntry { .. } => self.read_export_entry()?,
+ ParserState::BeginGlobalSectionEntry(_) => {
+ self.read_init_expression_body(InitExpressionContinuationSection::Global)
+ }
+ ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
+ ParserState::BeginElementSectionEntry {
+ table: ElemSectionEntryTable::Active(_),
+ ..
+ } => self.read_init_expression_body(InitExpressionContinuationSection::Element),
+ ParserState::BeginElementSectionEntry { .. } => self.read_element_entry_body()?,
+ ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => {
+ self.read_init_expression_operator()?
+ }
+ ParserState::BeginPassiveDataSectionEntry => self.read_data_entry_body()?,
+ ParserState::BeginActiveDataSectionEntry(_) => {
+ self.read_init_expression_body(InitExpressionContinuationSection::Data)
+ }
+ ParserState::EndInitExpressionBody => {
+ match self.init_expr_continuation {
+ Some(InitExpressionContinuationSection::Global) => {
+ self.state = ParserState::EndGlobalSectionEntry
+ }
+ Some(InitExpressionContinuationSection::Element) => {
+ self.read_element_entry_body()?
+ }
+ Some(InitExpressionContinuationSection::Data) => self.read_data_entry_body()?,
+ None => unreachable!(),
+ }
+ self.init_expr_continuation = None;
+ }
+ ParserState::BeginFunctionBody { .. } => self.read_function_body_locals()?,
+ ParserState::FunctionBodyLocals { .. } | ParserState::CodeOperator(_) => {
+ self.read_code_operator()?
+ }
+ ParserState::EndFunctionBody => self.read_function_body()?,
+ ParserState::SkippingFunctionBody => {
+ self.current_function_body = None;
+ self.read_function_body()?;
+ }
+ ParserState::EndDataSectionEntry => self.read_data_entry()?,
+ ParserState::BeginDataSectionEntryBody(_)
+ | ParserState::DataSectionEntryBodyChunk(_) => self.read_data_chunk()?,
+ ParserState::EndDataSectionEntryBody => {
+ self.state = ParserState::EndDataSectionEntry;
+ }
+ ParserState::ElementSectionEntryBody(_) => {
+ self.state = ParserState::EndElementSectionEntry;
+ }
+ ParserState::EndElementSectionEntry => self.read_element_entry()?,
+ ParserState::StartSectionEntry(_) => self.position_to_section_end()?,
+ ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?,
+ ParserState::NameSectionEntry(_) => self.read_name_entry()?,
+ ParserState::SourceMappingURL(_) => self.position_to_section_end()?,
+ ParserState::RelocSectionHeader(_) => {
+ let mut reader = self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_binary_reader();
+ self.section_entries_left = reader.read_var_u32()?;
+ self.binary_reader = Some(reader);
+ self.read_reloc_entry()?;
+ }
+ ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?,
+ ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?,
+ ParserState::ReadingCustomSection(_) => self.read_custom_section_body()?,
+ ParserState::ReadingSectionRawData | ParserState::SectionRawData(_) => {
+ self.read_section_body_bytes()?
+ }
+ }
+ Ok(())
+ }
+
+ fn skip_section(&mut self) {
+ match self.state {
+ ParserState::Initial
+ | ParserState::EndWasm
+ | ParserState::Error(_)
+ | ParserState::BeginWasm { .. }
+ | ParserState::EndSection => panic!("Invalid reader state during skip section"),
+ _ => self.state = ParserState::SkippingSection,
+ }
+ }
+
+ fn skip_function_body(&mut self) {
+ match self.state {
+ ParserState::BeginFunctionBody { .. }
+ | ParserState::FunctionBodyLocals { .. }
+ | ParserState::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody,
+ _ => panic!("Invalid reader state during skip function body"),
+ }
+ }
+
+ fn read_custom_section(&mut self) {
+ match self.state {
+ ParserState::BeginSection {
+ code: SectionCode::Custom { kind, .. },
+ ..
+ } => {
+ self.state = ParserState::ReadingCustomSection(kind);
+ }
+ _ => panic!("Invalid reader state during reading custom section"),
+ }
+ }
+
+ fn read_raw_section_data(&mut self) {
+ match self.state {
+ ParserState::BeginSection { .. } => {
+ self.binary_reader = Some(
+ self.current_section
+ .as_ref()
+ .expect("section")
+ .get_binary_reader(),
+ );
+ self.state = ParserState::ReadingSectionRawData;
+ }
+ _ => panic!("Invalid reader state during reading raw section data"),
+ }
+ }
+}
+
+impl<'a> WasmDecoder<'a> for Parser<'a> {
+ /// Reads next record from the WebAssembly binary data. The methods returns
+ /// reference to current state of the parser. See `ParserState` num.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::WasmDecoder;
+ /// let mut parser = wasmparser::Parser::new(data);
+ /// {
+ /// let state = parser.read();
+ /// println!("First state {:?}", state);
+ /// }
+ /// {
+ /// let state = parser.read();
+ /// println!("Second state {:?}", state);
+ /// }
+ /// ```
+ fn read(&mut self) -> &ParserState<'a> {
+ let result = self.read_wrapped();
+ if result.is_err() {
+ self.state = ParserState::Error(result.err().unwrap());
+ }
+ &self.state
+ }
+
+ fn push_input(&mut self, input: ParserInput) {
+ match input {
+ ParserInput::Default => (),
+ ParserInput::SkipSection => self.skip_section(),
+ ParserInput::SkipFunctionBody => self.skip_function_body(),
+ ParserInput::ReadCustomSection => self.read_custom_section(),
+ ParserInput::ReadSectionRawData => self.read_raw_section_data(),
+ }
+ }
+
+ /// Creates a BinaryReader when current state is ParserState::BeginSection
+ /// or ParserState::BeginFunctionBody.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80,
+ /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0,
+ /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb];
+ /// use wasmparser::{WasmDecoder, Parser, ParserState};
+ /// let mut parser = Parser::new(data);
+ /// let mut types = Vec::new();
+ /// let mut function_types = Vec::new();
+ /// let mut function_readers = Vec::new();
+ /// loop {
+ /// match parser.read() {
+ /// ParserState::Error(_) |
+ /// ParserState::EndWasm => break,
+ /// ParserState::TypeSectionEntry(ty) => {
+ /// types.push(ty.clone());
+ /// }
+ /// ParserState::FunctionSectionEntry(id) => {
+ /// function_types.push(id.clone());
+ /// }
+ /// ParserState::BeginFunctionBody {..} => {
+ /// let reader = parser.create_binary_reader();
+ /// function_readers.push(reader);
+ /// }
+ /// _ => continue
+ /// }
+ /// }
+ /// for (i, reader) in function_readers.iter_mut().enumerate() {
+ /// // Access the function type through the types table.
+ /// let ty = &types[function_types[i] as usize];
+ /// println!("\nFunction {} of type {:?}", i, ty);
+ /// // Read the local declarations required by the function body.
+ /// let local_decls_len = reader.read_local_count().unwrap();
+ /// let mut local_decls = Vec::with_capacity(local_decls_len);
+ /// let mut local_count = ty.params.len();
+ /// for _ in 0..local_decls_len {
+ /// let local_decl = reader.read_local_decl(&mut local_count).unwrap();
+ /// local_decls.push(local_decl);
+ /// }
+ /// println!("Function locals: vars {:?}; total {} ", local_decls, local_count);
+ /// // Read the operations of the function body.
+ /// while let Ok(ref op) = reader.read_operator() {
+ /// println!(" {:?}", op);
+ /// }
+ /// }
+ /// ```
+ fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
+ where
+ 'a: 'b,
+ {
+ match self.state {
+ ParserState::BeginSection { .. } => self
+ .current_section
+ .as_ref()
+ .expect("section")
+ .get_binary_reader(),
+ ParserState::BeginFunctionBody { .. } | ParserState::FunctionBodyLocals { .. } => self
+ .current_function_body
+ .as_ref()
+ .expect("function body")
+ .get_binary_reader(),
+ _ => panic!("Invalid reader state during get binary reader operation"),
+ }
+ }
+
+ /// Reads next record from the WebAssembly binary data. It also allows to
+ /// control how parser will treat the next record(s). The method accepts the
+ /// `ParserInput` parameter that allows e.g. to skip section or function
+ /// operators. The methods returns reference to current state of the parser.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::WasmDecoder;
+ /// let mut parser = wasmparser::Parser::new(data);
+ /// let mut next_input = wasmparser::ParserInput::Default;
+ /// loop {
+ /// let state = parser.read_with_input(next_input);
+ /// match *state {
+ /// wasmparser::ParserState::EndWasm => break,
+ /// wasmparser::ParserState::BeginWasm { .. } |
+ /// wasmparser::ParserState::EndSection =>
+ /// next_input = wasmparser::ParserInput::Default,
+ /// wasmparser::ParserState::BeginSection { ref code, .. } => {
+ /// println!("Found section: {:?}", code);
+ /// next_input = wasmparser::ParserInput::SkipSection;
+ /// },
+ /// _ => unreachable!()
+ /// }
+ /// }
+ /// ```
+ fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> {
+ self.push_input(input);
+ self.read()
+ }
+
+ fn last_state(&self) -> &ParserState<'a> {
+ &self.state
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/primitives.rs b/third_party/rust/wasmparser-0.48.2/src/primitives.rs
new file mode 100644
index 0000000000..d7d2218aa4
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/primitives.rs
@@ -0,0 +1,690 @@
+/* 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 std::error::Error;
+use std::fmt;
+use std::result;
+
+#[derive(Debug, Copy, Clone)]
+pub struct BinaryReaderError {
+ pub message: &'static str,
+ pub offset: usize,
+}
+
+pub type Result<T> = result::Result<T, BinaryReaderError>;
+
+impl Error for BinaryReaderError {}
+
+impl fmt::Display for BinaryReaderError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} (at offset {})", self.message, self.offset)
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CustomSectionKind {
+ Unknown,
+ Name,
+ Producers,
+ SourceMappingURL,
+ Reloc,
+ Linking,
+}
+
+/// Section code as defined [here].
+///
+/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum SectionCode<'a> {
+ Custom {
+ name: &'a str,
+ kind: CustomSectionKind,
+ },
+ Type, // Function signature declarations
+ Import, // Import declarations
+ Function, // Function declarations
+ Table, // Indirect function table and other tables
+ Memory, // Memory attributes
+ Global, // Global declarations
+ Export, // Exports
+ Start, // Start function declaration
+ Element, // Elements section
+ Code, // Function bodies (code)
+ Data, // Data segments
+ DataCount, // Count of passive data segments
+}
+
+/// Types as defined [here].
+///
+/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#types
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Type {
+ I32,
+ I64,
+ F32,
+ F64,
+ V128,
+ AnyFunc,
+ AnyRef,
+ NullRef,
+ Func,
+ EmptyBlockType,
+}
+
+impl Type {
+ pub(crate) fn is_valid_for_old_select(self) -> bool {
+ match self {
+ Type::I32 | Type::I64 | Type::F32 | Type::F64 => true,
+ _ => false,
+ }
+ }
+}
+
+/// Either a value type or a function type.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum TypeOrFuncType {
+ /// A value type.
+ ///
+ /// When used as the type for a block, this type is the optional result
+ /// type: `[] -> [t?]`.
+ Type(Type),
+
+ /// A function type (referenced as an index into the types section).
+ FuncType(u32),
+}
+
+/// External types as defined [here].
+///
+/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types
+#[derive(Debug, Copy, Clone)]
+pub enum ExternalKind {
+ Function,
+ Table,
+ Memory,
+ Global,
+}
+
+#[derive(Debug, Clone)]
+pub struct FuncType {
+ pub form: Type,
+ pub params: Box<[Type]>,
+ pub returns: Box<[Type]>,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ResizableLimits {
+ pub initial: u32,
+ pub maximum: Option<u32>,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct TableType {
+ pub element_type: Type,
+ pub limits: ResizableLimits,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct MemoryType {
+ pub limits: ResizableLimits,
+ pub shared: bool,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct GlobalType {
+ pub content_type: Type,
+ pub mutable: bool,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum ImportSectionEntryType {
+ Function(u32),
+ Table(TableType),
+ Memory(MemoryType),
+ Global(GlobalType),
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct MemoryImmediate {
+ pub flags: u32,
+ pub offset: u32,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct Naming<'a> {
+ pub index: u32,
+ pub name: &'a str,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum NameType {
+ Module,
+ Function,
+ Local,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum LinkingType {
+ StackPointer(u32),
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum RelocType {
+ FunctionIndexLEB,
+ TableIndexSLEB,
+ TableIndexI32,
+ GlobalAddrLEB,
+ GlobalAddrSLEB,
+ GlobalAddrI32,
+ TypeIndexLEB,
+ GlobalIndexLEB,
+}
+
+/// A br_table entries representation.
+#[derive(Debug, Clone)]
+pub struct BrTable<'a> {
+ pub(crate) buffer: &'a [u8],
+ pub(crate) cnt: usize,
+}
+
+/// An IEEE binary32 immediate floating point value, represented as a u32
+/// containing the bitpattern.
+///
+/// All bit patterns are allowed.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct Ieee32(pub(crate) u32);
+
+impl Ieee32 {
+ pub fn bits(self) -> u32 {
+ self.0
+ }
+}
+
+/// An IEEE binary64 immediate floating point value, represented as a u64
+/// containing the bitpattern.
+///
+/// All bit patterns are allowed.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct Ieee64(pub(crate) u64);
+
+impl Ieee64 {
+ pub fn bits(self) -> u64 {
+ self.0
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct V128(pub(crate) [u8; 16]);
+
+impl V128 {
+ pub fn bytes(&self) -> &[u8; 16] {
+ &self.0
+ }
+}
+
+pub type SIMDLaneIndex = u8;
+
+/// Instructions as defined [here].
+///
+/// [here]: https://webassembly.github.io/spec/core/binary/instructions.html
+#[derive(Debug, Clone)]
+pub enum Operator<'a> {
+ Unreachable,
+ Nop,
+ Block { ty: TypeOrFuncType },
+ Loop { ty: TypeOrFuncType },
+ If { ty: TypeOrFuncType },
+ Else,
+ End,
+ Br { relative_depth: u32 },
+ BrIf { relative_depth: u32 },
+ BrTable { table: BrTable<'a> },
+ Return,
+ Call { function_index: u32 },
+ CallIndirect { index: u32, table_index: u32 },
+ Drop,
+ Select,
+ TypedSelect { ty: Type },
+ LocalGet { local_index: u32 },
+ LocalSet { local_index: u32 },
+ LocalTee { local_index: u32 },
+ GlobalGet { global_index: u32 },
+ GlobalSet { global_index: u32 },
+ I32Load { memarg: MemoryImmediate },
+ I64Load { memarg: MemoryImmediate },
+ F32Load { memarg: MemoryImmediate },
+ F64Load { memarg: MemoryImmediate },
+ I32Load8S { memarg: MemoryImmediate },
+ I32Load8U { memarg: MemoryImmediate },
+ I32Load16S { memarg: MemoryImmediate },
+ I32Load16U { memarg: MemoryImmediate },
+ I64Load8S { memarg: MemoryImmediate },
+ I64Load8U { memarg: MemoryImmediate },
+ I64Load16S { memarg: MemoryImmediate },
+ I64Load16U { memarg: MemoryImmediate },
+ I64Load32S { memarg: MemoryImmediate },
+ I64Load32U { memarg: MemoryImmediate },
+ I32Store { memarg: MemoryImmediate },
+ I64Store { memarg: MemoryImmediate },
+ F32Store { memarg: MemoryImmediate },
+ F64Store { memarg: MemoryImmediate },
+ I32Store8 { memarg: MemoryImmediate },
+ I32Store16 { memarg: MemoryImmediate },
+ I64Store8 { memarg: MemoryImmediate },
+ I64Store16 { memarg: MemoryImmediate },
+ I64Store32 { memarg: MemoryImmediate },
+ MemorySize { reserved: u32 },
+ MemoryGrow { reserved: u32 },
+ I32Const { value: i32 },
+ I64Const { value: i64 },
+ F32Const { value: Ieee32 },
+ F64Const { value: Ieee64 },
+ RefNull,
+ RefIsNull,
+ RefFunc { function_index: u32 },
+ I32Eqz,
+ I32Eq,
+ I32Ne,
+ I32LtS,
+ I32LtU,
+ I32GtS,
+ I32GtU,
+ I32LeS,
+ I32LeU,
+ I32GeS,
+ I32GeU,
+ I64Eqz,
+ I64Eq,
+ I64Ne,
+ I64LtS,
+ I64LtU,
+ I64GtS,
+ I64GtU,
+ I64LeS,
+ I64LeU,
+ I64GeS,
+ I64GeU,
+ F32Eq,
+ F32Ne,
+ F32Lt,
+ F32Gt,
+ F32Le,
+ F32Ge,
+ F64Eq,
+ F64Ne,
+ F64Lt,
+ F64Gt,
+ F64Le,
+ F64Ge,
+ I32Clz,
+ I32Ctz,
+ I32Popcnt,
+ I32Add,
+ I32Sub,
+ I32Mul,
+ I32DivS,
+ I32DivU,
+ I32RemS,
+ I32RemU,
+ I32And,
+ I32Or,
+ I32Xor,
+ I32Shl,
+ I32ShrS,
+ I32ShrU,
+ I32Rotl,
+ I32Rotr,
+ I64Clz,
+ I64Ctz,
+ I64Popcnt,
+ I64Add,
+ I64Sub,
+ I64Mul,
+ I64DivS,
+ I64DivU,
+ I64RemS,
+ I64RemU,
+ I64And,
+ I64Or,
+ I64Xor,
+ I64Shl,
+ I64ShrS,
+ I64ShrU,
+ I64Rotl,
+ I64Rotr,
+ F32Abs,
+ F32Neg,
+ F32Ceil,
+ F32Floor,
+ F32Trunc,
+ F32Nearest,
+ F32Sqrt,
+ F32Add,
+ F32Sub,
+ F32Mul,
+ F32Div,
+ F32Min,
+ F32Max,
+ F32Copysign,
+ F64Abs,
+ F64Neg,
+ F64Ceil,
+ F64Floor,
+ F64Trunc,
+ F64Nearest,
+ F64Sqrt,
+ F64Add,
+ F64Sub,
+ F64Mul,
+ F64Div,
+ F64Min,
+ F64Max,
+ F64Copysign,
+ I32WrapI64,
+ I32TruncF32S,
+ I32TruncF32U,
+ I32TruncF64S,
+ I32TruncF64U,
+ I64ExtendI32S,
+ I64ExtendI32U,
+ I64TruncF32S,
+ I64TruncF32U,
+ I64TruncF64S,
+ I64TruncF64U,
+ F32ConvertI32S,
+ F32ConvertI32U,
+ F32ConvertI64S,
+ F32ConvertI64U,
+ F32DemoteF64,
+ F64ConvertI32S,
+ F64ConvertI32U,
+ F64ConvertI64S,
+ F64ConvertI64U,
+ F64PromoteF32,
+ I32ReinterpretF32,
+ I64ReinterpretF64,
+ F32ReinterpretI32,
+ F64ReinterpretI64,
+ I32Extend8S,
+ I32Extend16S,
+ I64Extend8S,
+ I64Extend16S,
+ I64Extend32S,
+
+ // 0xFC operators
+ // Non-trapping Float-to-int Conversions
+ I32TruncSatF32S,
+ I32TruncSatF32U,
+ I32TruncSatF64S,
+ I32TruncSatF64U,
+ I64TruncSatF32S,
+ I64TruncSatF32U,
+ I64TruncSatF64S,
+ I64TruncSatF64U,
+
+ // 0xFC operators
+ // bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
+ MemoryInit { segment: u32 },
+ DataDrop { segment: u32 },
+ MemoryCopy,
+ MemoryFill,
+ TableInit { segment: u32, table: u32 },
+ ElemDrop { segment: u32 },
+ TableCopy { dst_table: u32, src_table: u32 },
+ TableFill { table: u32 },
+ TableGet { table: u32 },
+ TableSet { table: u32 },
+ TableGrow { table: u32 },
+ TableSize { table: u32 },
+
+ // 0xFE operators
+ // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
+ AtomicNotify { memarg: MemoryImmediate },
+ I32AtomicWait { memarg: MemoryImmediate },
+ I64AtomicWait { memarg: MemoryImmediate },
+ AtomicFence { flags: u8 },
+ I32AtomicLoad { memarg: MemoryImmediate },
+ I64AtomicLoad { memarg: MemoryImmediate },
+ I32AtomicLoad8U { memarg: MemoryImmediate },
+ I32AtomicLoad16U { memarg: MemoryImmediate },
+ I64AtomicLoad8U { memarg: MemoryImmediate },
+ I64AtomicLoad16U { memarg: MemoryImmediate },
+ I64AtomicLoad32U { memarg: MemoryImmediate },
+ I32AtomicStore { memarg: MemoryImmediate },
+ I64AtomicStore { memarg: MemoryImmediate },
+ I32AtomicStore8 { memarg: MemoryImmediate },
+ I32AtomicStore16 { memarg: MemoryImmediate },
+ I64AtomicStore8 { memarg: MemoryImmediate },
+ I64AtomicStore16 { memarg: MemoryImmediate },
+ I64AtomicStore32 { memarg: MemoryImmediate },
+ I32AtomicRmwAdd { memarg: MemoryImmediate },
+ I64AtomicRmwAdd { memarg: MemoryImmediate },
+ I32AtomicRmw8AddU { memarg: MemoryImmediate },
+ I32AtomicRmw16AddU { memarg: MemoryImmediate },
+ I64AtomicRmw8AddU { memarg: MemoryImmediate },
+ I64AtomicRmw16AddU { memarg: MemoryImmediate },
+ I64AtomicRmw32AddU { memarg: MemoryImmediate },
+ I32AtomicRmwSub { memarg: MemoryImmediate },
+ I64AtomicRmwSub { memarg: MemoryImmediate },
+ I32AtomicRmw8SubU { memarg: MemoryImmediate },
+ I32AtomicRmw16SubU { memarg: MemoryImmediate },
+ I64AtomicRmw8SubU { memarg: MemoryImmediate },
+ I64AtomicRmw16SubU { memarg: MemoryImmediate },
+ I64AtomicRmw32SubU { memarg: MemoryImmediate },
+ I32AtomicRmwAnd { memarg: MemoryImmediate },
+ I64AtomicRmwAnd { memarg: MemoryImmediate },
+ I32AtomicRmw8AndU { memarg: MemoryImmediate },
+ I32AtomicRmw16AndU { memarg: MemoryImmediate },
+ I64AtomicRmw8AndU { memarg: MemoryImmediate },
+ I64AtomicRmw16AndU { memarg: MemoryImmediate },
+ I64AtomicRmw32AndU { memarg: MemoryImmediate },
+ I32AtomicRmwOr { memarg: MemoryImmediate },
+ I64AtomicRmwOr { memarg: MemoryImmediate },
+ I32AtomicRmw8OrU { memarg: MemoryImmediate },
+ I32AtomicRmw16OrU { memarg: MemoryImmediate },
+ I64AtomicRmw8OrU { memarg: MemoryImmediate },
+ I64AtomicRmw16OrU { memarg: MemoryImmediate },
+ I64AtomicRmw32OrU { memarg: MemoryImmediate },
+ I32AtomicRmwXor { memarg: MemoryImmediate },
+ I64AtomicRmwXor { memarg: MemoryImmediate },
+ I32AtomicRmw8XorU { memarg: MemoryImmediate },
+ I32AtomicRmw16XorU { memarg: MemoryImmediate },
+ I64AtomicRmw8XorU { memarg: MemoryImmediate },
+ I64AtomicRmw16XorU { memarg: MemoryImmediate },
+ I64AtomicRmw32XorU { memarg: MemoryImmediate },
+ I32AtomicRmwXchg { memarg: MemoryImmediate },
+ I64AtomicRmwXchg { memarg: MemoryImmediate },
+ I32AtomicRmw8XchgU { memarg: MemoryImmediate },
+ I32AtomicRmw16XchgU { memarg: MemoryImmediate },
+ I64AtomicRmw8XchgU { memarg: MemoryImmediate },
+ I64AtomicRmw16XchgU { memarg: MemoryImmediate },
+ I64AtomicRmw32XchgU { memarg: MemoryImmediate },
+ I32AtomicRmwCmpxchg { memarg: MemoryImmediate },
+ I64AtomicRmwCmpxchg { memarg: MemoryImmediate },
+ I32AtomicRmw8CmpxchgU { memarg: MemoryImmediate },
+ I32AtomicRmw16CmpxchgU { memarg: MemoryImmediate },
+ I64AtomicRmw8CmpxchgU { memarg: MemoryImmediate },
+ I64AtomicRmw16CmpxchgU { memarg: MemoryImmediate },
+ I64AtomicRmw32CmpxchgU { memarg: MemoryImmediate },
+
+ // 0xFD operators
+ // SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md
+ V128Load { memarg: MemoryImmediate },
+ V128Store { memarg: MemoryImmediate },
+ V128Const { value: V128 },
+ I8x16Splat,
+ I8x16ExtractLaneS { lane: SIMDLaneIndex },
+ I8x16ExtractLaneU { lane: SIMDLaneIndex },
+ I8x16ReplaceLane { lane: SIMDLaneIndex },
+ I16x8Splat,
+ I16x8ExtractLaneS { lane: SIMDLaneIndex },
+ I16x8ExtractLaneU { lane: SIMDLaneIndex },
+ I16x8ReplaceLane { lane: SIMDLaneIndex },
+ I32x4Splat,
+ I32x4ExtractLane { lane: SIMDLaneIndex },
+ I32x4ReplaceLane { lane: SIMDLaneIndex },
+ I64x2Splat,
+ I64x2ExtractLane { lane: SIMDLaneIndex },
+ I64x2ReplaceLane { lane: SIMDLaneIndex },
+ F32x4Splat,
+ F32x4ExtractLane { lane: SIMDLaneIndex },
+ F32x4ReplaceLane { lane: SIMDLaneIndex },
+ F64x2Splat,
+ F64x2ExtractLane { lane: SIMDLaneIndex },
+ F64x2ReplaceLane { lane: SIMDLaneIndex },
+ I8x16Eq,
+ I8x16Ne,
+ I8x16LtS,
+ I8x16LtU,
+ I8x16GtS,
+ I8x16GtU,
+ I8x16LeS,
+ I8x16LeU,
+ I8x16GeS,
+ I8x16GeU,
+ I16x8Eq,
+ I16x8Ne,
+ I16x8LtS,
+ I16x8LtU,
+ I16x8GtS,
+ I16x8GtU,
+ I16x8LeS,
+ I16x8LeU,
+ I16x8GeS,
+ I16x8GeU,
+ I32x4Eq,
+ I32x4Ne,
+ I32x4LtS,
+ I32x4LtU,
+ I32x4GtS,
+ I32x4GtU,
+ I32x4LeS,
+ I32x4LeU,
+ I32x4GeS,
+ I32x4GeU,
+ F32x4Eq,
+ F32x4Ne,
+ F32x4Lt,
+ F32x4Gt,
+ F32x4Le,
+ F32x4Ge,
+ F64x2Eq,
+ F64x2Ne,
+ F64x2Lt,
+ F64x2Gt,
+ F64x2Le,
+ F64x2Ge,
+ V128Not,
+ V128And,
+ V128AndNot,
+ V128Or,
+ V128Xor,
+ V128Bitselect,
+ I8x16Neg,
+ I8x16AnyTrue,
+ I8x16AllTrue,
+ I8x16Shl,
+ I8x16ShrS,
+ I8x16ShrU,
+ I8x16Add,
+ I8x16AddSaturateS,
+ I8x16AddSaturateU,
+ I8x16Sub,
+ I8x16SubSaturateS,
+ I8x16SubSaturateU,
+ I8x16Mul,
+ I16x8Neg,
+ I16x8AnyTrue,
+ I16x8AllTrue,
+ I16x8Shl,
+ I16x8ShrS,
+ I16x8ShrU,
+ I16x8Add,
+ I16x8AddSaturateS,
+ I16x8AddSaturateU,
+ I16x8Sub,
+ I16x8SubSaturateS,
+ I16x8SubSaturateU,
+ I16x8Mul,
+ I32x4Neg,
+ I32x4AnyTrue,
+ I32x4AllTrue,
+ I32x4Shl,
+ I32x4ShrS,
+ I32x4ShrU,
+ I32x4Add,
+ I32x4Sub,
+ I32x4Mul,
+ I64x2Neg,
+ I64x2AnyTrue,
+ I64x2AllTrue,
+ I64x2Shl,
+ I64x2ShrS,
+ I64x2ShrU,
+ I64x2Add,
+ I64x2Sub,
+ I64x2Mul,
+ F32x4Abs,
+ F32x4Neg,
+ F32x4Sqrt,
+ F32x4Add,
+ F32x4Sub,
+ F32x4Mul,
+ F32x4Div,
+ F32x4Min,
+ F32x4Max,
+ F64x2Abs,
+ F64x2Neg,
+ F64x2Sqrt,
+ F64x2Add,
+ F64x2Sub,
+ F64x2Mul,
+ F64x2Div,
+ F64x2Min,
+ F64x2Max,
+ I32x4TruncSatF32x4S,
+ I32x4TruncSatF32x4U,
+ I64x2TruncSatF64x2S,
+ I64x2TruncSatF64x2U,
+ F32x4ConvertI32x4S,
+ F32x4ConvertI32x4U,
+ F64x2ConvertI64x2S,
+ F64x2ConvertI64x2U,
+ V8x16Swizzle,
+ V8x16Shuffle { lanes: [SIMDLaneIndex; 16] },
+ V8x16LoadSplat { memarg: MemoryImmediate },
+ V16x8LoadSplat { memarg: MemoryImmediate },
+ V32x4LoadSplat { memarg: MemoryImmediate },
+ V64x2LoadSplat { memarg: MemoryImmediate },
+ I8x16NarrowI16x8S,
+ I8x16NarrowI16x8U,
+ I16x8NarrowI32x4S,
+ I16x8NarrowI32x4U,
+ I16x8WidenLowI8x16S,
+ I16x8WidenHighI8x16S,
+ I16x8WidenLowI8x16U,
+ I16x8WidenHighI8x16U,
+ I32x4WidenLowI16x8S,
+ I32x4WidenHighI16x8S,
+ I32x4WidenLowI16x8U,
+ I32x4WidenHighI16x8U,
+ I16x8Load8x8S { memarg: MemoryImmediate },
+ I16x8Load8x8U { memarg: MemoryImmediate },
+ I32x4Load16x4S { memarg: MemoryImmediate },
+ I32x4Load16x4U { memarg: MemoryImmediate },
+ I64x2Load32x2S { memarg: MemoryImmediate },
+ I64x2Load32x2U { memarg: MemoryImmediate },
+ I8x16RoundingAverageU,
+ I16x8RoundingAverageU,
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs
new file mode 100644
index 0000000000..fac9c6e229
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs
@@ -0,0 +1,245 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, OperatorsReader, Range, Result, SectionIteratorLimited,
+ SectionReader, SectionWithLimitedItems, Type,
+};
+
+#[derive(Debug)]
+pub struct FunctionBody<'a> {
+ offset: usize,
+ data: &'a [u8],
+}
+
+impl<'a> FunctionBody<'a> {
+ pub fn new(offset: usize, data: &'a [u8]) -> Self {
+ Self { offset, data }
+ }
+
+ pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
+ where
+ 'a: 'b,
+ {
+ BinaryReader::new_with_offset(self.data, self.offset)
+ }
+
+ fn skip_locals(reader: &mut BinaryReader) -> Result<()> {
+ let count = reader.read_var_u32()?;
+ for _ in 0..count {
+ reader.skip_var_32()?;
+ reader.skip_type()?;
+ }
+ Ok(())
+ }
+
+ pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>>
+ where
+ 'a: 'b,
+ {
+ let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
+ let count = reader.read_var_u32()?;
+ Ok(LocalsReader { reader, count })
+ }
+
+ pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>>
+ where
+ 'a: 'b,
+ {
+ let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
+ Self::skip_locals(&mut reader)?;
+ let pos = reader.position;
+ Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
+ }
+
+ pub fn range(&self) -> Range {
+ Range {
+ start: self.offset,
+ end: self.offset + self.data.len(),
+ }
+ }
+}
+
+pub struct LocalsReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> LocalsReader<'a> {
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn read(&mut self) -> Result<(u32, Type)> {
+ let count = self.reader.read_var_u32()?;
+ let value_type = self.reader.read_type()?;
+ Ok((count, value_type))
+ }
+}
+
+pub struct CodeSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> IntoIterator for LocalsReader<'a> {
+ type Item = Result<(u32, Type)>;
+ type IntoIter = LocalsIterator<'a>;
+ fn into_iter(self) -> Self::IntoIter {
+ let count = self.count;
+ LocalsIterator {
+ reader: self,
+ left: count,
+ err: false,
+ }
+ }
+}
+
+pub struct LocalsIterator<'a> {
+ reader: LocalsReader<'a>,
+ left: u32,
+ err: bool,
+}
+
+impl<'a> Iterator for LocalsIterator<'a> {
+ type Item = Result<(u32, Type)>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.left == 0 {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ self.left -= 1;
+ Some(result)
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let count = self.reader.get_count() as usize;
+ (count, Some(count))
+ }
+}
+
+impl<'a> CodeSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(CodeSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ fn verify_body_end(&self, end: usize) -> Result<()> {
+ if self.reader.buffer.len() < end {
+ return Err(BinaryReaderError {
+ message: "Function body extends past end of the code section",
+ offset: self.reader.original_offset + self.reader.buffer.len(),
+ });
+ }
+ Ok(())
+ }
+
+ /// Reads content of the code section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("code section");
+ /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
+ /// for _ in 0..code_reader.get_count() {
+ /// let body = code_reader.read().expect("function body");
+ /// let mut binary_reader = body.get_binary_reader();
+ /// assert!(binary_reader.read_local_count().expect("local count") == 0);
+ /// let op = binary_reader.read_operator().expect("first operator");
+ /// println!("First operator: {:?}", op);
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>>
+ where
+ 'a: 'b,
+ {
+ let size = self.reader.read_var_u32()? as usize;
+ let body_start = self.reader.position;
+ let body_end = body_start + size;
+ self.verify_body_end(body_end)?;
+ self.reader.skip_to(body_end);
+ Ok(FunctionBody {
+ offset: self.reader.original_offset + body_start,
+ data: &self.reader.buffer[body_start..body_end],
+ })
+ }
+}
+
+impl<'a> SectionReader for CodeSectionReader<'a> {
+ type Item = FunctionBody<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ CodeSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ CodeSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ CodeSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for CodeSectionReader<'a> {
+ type Item = Result<FunctionBody<'a>>;
+ type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>;
+
+ /// Implements iterator over the code section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("code section");
+ /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
+ /// for body in code_reader {
+ /// let mut binary_reader = body.expect("b").get_binary_reader();
+ /// assert!(binary_reader.read_local_count().expect("local count") == 0);
+ /// let op = binary_reader.read_operator().expect("first operator");
+ /// println!("First operator: {:?}", op);
+ /// }
+ /// ```
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs
new file mode 100644
index 0000000000..ac0f9db0f7
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs
@@ -0,0 +1,28 @@
+/* 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 super::{BinaryReader, BinaryReaderError, Result};
+
+pub(crate) fn read_data_count_section_content(data: &[u8], offset: usize) -> Result<u32> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ if !reader.eof() {
+ return Err(BinaryReaderError {
+ message: "Unexpected content in the data count section",
+ offset: offset + reader.position,
+ });
+ }
+ Ok(count)
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs
new file mode 100644
index 0000000000..29b7d8284e
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs
@@ -0,0 +1,157 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Data<'a> {
+ pub kind: DataKind<'a>,
+ pub data: &'a [u8],
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum DataKind<'a> {
+ Passive,
+ Active {
+ memory_index: u32,
+ init_expr: InitExpr<'a>,
+ },
+}
+
+pub struct DataSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> DataSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<DataSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(DataSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ fn verify_data_end(&self, end: usize) -> Result<()> {
+ if self.reader.buffer.len() < end {
+ return Err(BinaryReaderError {
+ message: "Data segment extends past end of the data section",
+ offset: self.reader.original_offset + self.reader.buffer.len(),
+ });
+ }
+ Ok(())
+ }
+
+ /// Reads content of the data section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x05, 0x03, 0x01, 0x00, 0x02,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b,
+ /// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00];
+ /// use wasmparser::{ModuleReader, DataKind};
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("memory section");
+ /// let section = reader.read().expect("code section");
+ /// let section = reader.read().expect("data section");
+ /// let mut data_reader = section.get_data_section_reader().expect("data section reader");
+ /// for _ in 0..data_reader.get_count() {
+ /// let data = data_reader.read().expect("data");
+ /// println!("Data: {:?}", data);
+ /// if let DataKind::Active { init_expr, .. } = data.kind {
+ /// let mut init_expr_reader = init_expr.get_binary_reader();
+ /// let op = init_expr_reader.read_operator().expect("op");
+ /// println!("Init const: {:?}", op);
+ /// }
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Data<'b>>
+ where
+ 'a: 'b,
+ {
+ let flags = self.reader.read_var_u32()?;
+ let kind = if flags == 1 {
+ DataKind::Passive
+ } else {
+ let memory_index = match flags {
+ 0 => 0,
+ 2 => self.reader.read_var_u32()?,
+ _ => {
+ return Err(BinaryReaderError {
+ message: "invalid flags byte in data segment",
+ offset: self.reader.original_position() - 1,
+ });
+ }
+ };
+ let init_expr = {
+ let expr_offset = self.reader.position;
+ self.reader.skip_init_expr()?;
+ let data = &self.reader.buffer[expr_offset..self.reader.position];
+ InitExpr::new(data, self.reader.original_offset + expr_offset)
+ };
+ DataKind::Active {
+ memory_index,
+ init_expr,
+ }
+ };
+ let data_len = self.reader.read_var_u32()? as usize;
+ let data_end = self.reader.position + data_len;
+ self.verify_data_end(data_end)?;
+ let data = &self.reader.buffer[self.reader.position..data_end];
+ self.reader.skip_to(data_end);
+ Ok(Data { kind, data })
+ }
+}
+
+impl<'a> SectionReader for DataSectionReader<'a> {
+ type Item = Data<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ DataSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ DataSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for DataSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ DataSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for DataSectionReader<'a> {
+ type Item = Result<Data<'a>>;
+ type IntoIter = SectionIteratorLimited<DataSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs
new file mode 100644
index 0000000000..ef45113a3f
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs
@@ -0,0 +1,301 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems, Type,
+};
+use crate::{ExternalKind, Operator};
+
+#[derive(Clone)]
+pub struct Element<'a> {
+ pub kind: ElementKind<'a>,
+ pub items: ElementItems<'a>,
+ pub ty: Type,
+}
+
+#[derive(Clone)]
+pub enum ElementKind<'a> {
+ Passive,
+ Active {
+ table_index: u32,
+ init_expr: InitExpr<'a>,
+ },
+ Declared,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ElementItems<'a> {
+ exprs: bool,
+ offset: usize,
+ data: &'a [u8],
+}
+
+#[derive(Debug)]
+pub enum ElementItem {
+ Null,
+ Func(u32),
+}
+
+impl<'a> ElementItems<'a> {
+ pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>>
+ where
+ 'a: 'b,
+ {
+ ElementItemsReader::new(self.data, self.offset, self.exprs)
+ }
+}
+
+pub struct ElementItemsReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+ exprs: bool,
+}
+
+impl<'a> ElementItemsReader<'a> {
+ pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(ElementItemsReader {
+ reader,
+ count,
+ exprs,
+ })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn uses_exprs(&self) -> bool {
+ self.exprs
+ }
+
+ pub fn read(&mut self) -> Result<ElementItem> {
+ if self.exprs {
+ let offset = self.reader.original_position();
+ let ret = match self.reader.read_operator()? {
+ Operator::RefNull => ElementItem::Null,
+ Operator::RefFunc { function_index } => ElementItem::Func(function_index),
+ _ => {
+ return Err(BinaryReaderError {
+ message: "invalid passive segment",
+ offset,
+ })
+ }
+ };
+ match self.reader.read_operator()? {
+ Operator::End => {}
+ _ => {
+ return Err(BinaryReaderError {
+ message: "invalid passive segment",
+ offset,
+ })
+ }
+ }
+ Ok(ret)
+ } else {
+ self.reader.read_var_u32().map(ElementItem::Func)
+ }
+ }
+}
+
+impl<'a> IntoIterator for ElementItemsReader<'a> {
+ type Item = Result<ElementItem>;
+ type IntoIter = ElementItemsIterator<'a>;
+ fn into_iter(self) -> Self::IntoIter {
+ let count = self.count;
+ ElementItemsIterator {
+ reader: self,
+ left: count,
+ err: false,
+ }
+ }
+}
+
+pub struct ElementItemsIterator<'a> {
+ reader: ElementItemsReader<'a>,
+ left: u32,
+ err: bool,
+}
+
+impl<'a> Iterator for ElementItemsIterator<'a> {
+ type Item = Result<ElementItem>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.left == 0 {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ self.left -= 1;
+ Some(result)
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let count = self.reader.get_count() as usize;
+ (count, Some(count))
+ }
+}
+
+pub struct ElementSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> ElementSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<ElementSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(ElementSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the element section.
+ ///
+ /// # Examples
+ /// ```no-run
+ /// # let data: &[u8] = &[];
+ /// use wasmparser::{ModuleReader, ElementKind};
+ ///use wasmparser::Result;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("table section");
+ /// let section = reader.read().expect("element section");
+ /// let mut element_reader = section.get_element_section_reader().expect("element section reader");
+ /// for _ in 0..element_reader.get_count() {
+ /// let element = element_reader.read().expect("element");
+ /// if let ElementKind::Active { init_expr, .. } = element.kind {
+ /// let mut init_expr_reader = init_expr.get_binary_reader();
+ /// let op = init_expr_reader.read_operator().expect("op");
+ /// println!("Init const: {:?}", op);
+ /// }
+ /// let mut items_reader = element.items.get_items_reader().expect("items reader");
+ /// for _ in 0..items_reader.get_count() {
+ /// let item = items_reader.read().expect("item");
+ /// println!(" Item: {:?}", item);
+ /// }
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Element<'b>>
+ where
+ 'a: 'b,
+ {
+ let flags = self.reader.read_var_u32()?;
+ if (flags & !0b111) != 0 {
+ return Err(BinaryReaderError {
+ message: "invalid flags byte in element segment",
+ offset: self.reader.original_position() - 1,
+ });
+ }
+ let kind = if flags & 0b001 != 0 {
+ if flags & 0b010 != 0 {
+ ElementKind::Declared
+ } else {
+ ElementKind::Passive
+ }
+ } else {
+ let table_index = if flags & 0b010 == 0 {
+ 0
+ } else {
+ self.reader.read_var_u32()?
+ };
+ let init_expr = {
+ let expr_offset = self.reader.position;
+ self.reader.skip_init_expr()?;
+ let data = &self.reader.buffer[expr_offset..self.reader.position];
+ InitExpr::new(data, self.reader.original_offset + expr_offset)
+ };
+ ElementKind::Active {
+ table_index,
+ init_expr,
+ }
+ };
+ let exprs = flags & 0b100 != 0;
+ let ty = if flags & 0b011 != 0 {
+ if exprs {
+ self.reader.read_type()?
+ } else {
+ match self.reader.read_external_kind()? {
+ ExternalKind::Function => Type::AnyFunc,
+ _ => {
+ return Err(BinaryReaderError {
+ message: "only the function external type is supported in elem segment",
+ offset: self.reader.original_position() - 1,
+ });
+ }
+ }
+ }
+ } else {
+ Type::AnyFunc
+ };
+ let data_start = self.reader.position;
+ let items_count = self.reader.read_var_u32()?;
+ if exprs {
+ for _ in 0..items_count {
+ self.reader.skip_init_expr()?;
+ }
+ } else {
+ for _ in 0..items_count {
+ self.reader.skip_var_32()?;
+ }
+ }
+ let data_end = self.reader.position;
+ let items = ElementItems {
+ offset: self.reader.original_offset + data_start,
+ data: &self.reader.buffer[data_start..data_end],
+ exprs,
+ };
+ Ok(Element { kind, items, ty })
+ }
+}
+
+impl<'a> SectionReader for ElementSectionReader<'a> {
+ type Item = Element<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ ElementSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ ElementSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for ElementSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ ElementSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for ElementSectionReader<'a> {
+ type Item = Result<Element<'a>>;
+ type IntoIter = SectionIteratorLimited<ElementSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs
new file mode 100644
index 0000000000..636ac2bcf3
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs
@@ -0,0 +1,104 @@
+/* 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 super::{
+ BinaryReader, ExternalKind, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Export<'a> {
+ pub field: &'a str,
+ pub kind: ExternalKind,
+ pub index: u32,
+}
+
+pub struct ExportSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> ExportSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<ExportSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(ExportSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the export section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x07, 0x5, 0x01, 0x01, 0x65, 0x00, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("export section");
+ /// let mut export_reader = section.get_export_section_reader().expect("export section reader");
+ /// for _ in 0..export_reader.get_count() {
+ /// let export = export_reader.read().expect("export");
+ /// println!("Export: {:?}", export);
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Export<'b>>
+ where
+ 'a: 'b,
+ {
+ let field = self.reader.read_string()?;
+ let kind = self.reader.read_external_kind()?;
+ let index = self.reader.read_var_u32()?;
+ Ok(Export { field, kind, index })
+ }
+}
+
+impl<'a> SectionReader for ExportSectionReader<'a> {
+ type Item = Export<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ ExportSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ ExportSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ ExportSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for ExportSectionReader<'a> {
+ type Item = Result<Export<'a>>;
+ type IntoIter = SectionIteratorLimited<ExportSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs
new file mode 100644
index 0000000000..c81bb4d9ed
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs
@@ -0,0 +1,86 @@
+/* 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 super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
+
+pub struct FunctionSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> FunctionSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<FunctionSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(FunctionSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads function type index from the function section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let mut function_reader = section.get_function_section_reader().expect("function section reader");
+ /// for _ in 0..function_reader.get_count() {
+ /// let ty = function_reader.read().expect("function type index");
+ /// println!("Function type index: {}", ty);
+ /// }
+ /// ```
+ pub fn read(&mut self) -> Result<u32> {
+ self.reader.read_var_u32()
+ }
+}
+
+impl<'a> SectionReader for FunctionSectionReader<'a> {
+ type Item = u32;
+ fn read(&mut self) -> Result<Self::Item> {
+ FunctionSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ FunctionSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ FunctionSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for FunctionSectionReader<'a> {
+ type Item = Result<u32>;
+ type IntoIter = SectionIteratorLimited<FunctionSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs
new file mode 100644
index 0000000000..15a85a7c36
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs
@@ -0,0 +1,108 @@
+/* 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 super::{
+ BinaryReader, GlobalType, InitExpr, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Global<'a> {
+ pub ty: GlobalType,
+ pub init_expr: InitExpr<'a>,
+}
+
+pub struct GlobalSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> GlobalSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<GlobalSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(GlobalSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the global section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x06, 0x8, 0x01, 0x7F, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0B,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("global section");
+ /// let mut global_reader = section.get_global_section_reader().expect("global section reader");
+ /// for _ in 0..global_reader.get_count() {
+ /// let global = global_reader.read().expect("global");
+ /// println!("Global: {:?}", global);
+ /// let mut init_expr_reader = global.init_expr.get_binary_reader();
+ /// let op = init_expr_reader.read_operator().expect("op");
+ /// println!("Init const: {:?}", op);
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Global<'b>>
+ where
+ 'a: 'b,
+ {
+ let ty = self.reader.read_global_type()?;
+ let expr_offset = self.reader.position;
+ self.reader.skip_init_expr()?;
+ let data = &self.reader.buffer[expr_offset..self.reader.position];
+ let init_expr = InitExpr::new(data, self.reader.original_offset + expr_offset);
+ Ok(Global { ty, init_expr })
+ }
+}
+
+impl<'a> SectionReader for GlobalSectionReader<'a> {
+ type Item = Global<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ GlobalSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ GlobalSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for GlobalSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ GlobalSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for GlobalSectionReader<'a> {
+ type Item = Result<Global<'a>>;
+ type IntoIter = SectionIteratorLimited<GlobalSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs
new file mode 100644
index 0000000000..92fd5f5e99
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs
@@ -0,0 +1,109 @@
+/* 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 super::{
+ BinaryReader, ExternalKind, ImportSectionEntryType, Result, SectionIteratorLimited,
+ SectionReader, SectionWithLimitedItems,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Import<'a> {
+ pub module: &'a str,
+ pub field: &'a str,
+ pub ty: ImportSectionEntryType,
+}
+
+pub struct ImportSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> ImportSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<ImportSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(ImportSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the import section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00,
+ /// # 0x02, 0x07, 0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00,
+ /// # 0x03, 0x02, 0x01, 0x00, 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("import section");
+ /// let mut import_reader = section.get_import_section_reader().expect("import section reader");
+ /// for _ in 0..import_reader.get_count() {
+ /// let import = import_reader.read().expect("import");
+ /// println!("Import: {:?}", import);
+ /// }
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Import<'b>>
+ where
+ 'a: 'b,
+ {
+ let module = self.reader.read_string()?;
+ let field = self.reader.read_string()?;
+ let kind = self.reader.read_external_kind()?;
+ let ty = match kind {
+ ExternalKind::Function => ImportSectionEntryType::Function(self.reader.read_var_u32()?),
+ ExternalKind::Table => ImportSectionEntryType::Table(self.reader.read_table_type()?),
+ ExternalKind::Memory => ImportSectionEntryType::Memory(self.reader.read_memory_type()?),
+ ExternalKind::Global => ImportSectionEntryType::Global(self.reader.read_global_type()?),
+ };
+ Ok(Import { module, field, ty })
+ }
+}
+
+impl<'a> SectionReader for ImportSectionReader<'a> {
+ type Item = Import<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ ImportSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ ImportSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ ImportSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for ImportSectionReader<'a> {
+ type Item = Result<Import<'a>>;
+ type IntoIter = SectionIteratorLimited<ImportSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs
new file mode 100644
index 0000000000..98c301d350
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs
@@ -0,0 +1,42 @@
+/* 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 super::{BinaryReader, OperatorsReader};
+
+#[derive(Debug, Copy, Clone)]
+pub struct InitExpr<'a> {
+ offset: usize,
+ data: &'a [u8],
+}
+
+impl<'a> InitExpr<'a> {
+ pub fn new(data: &[u8], offset: usize) -> InitExpr {
+ InitExpr { offset, data }
+ }
+
+ pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
+ where
+ 'a: 'b,
+ {
+ BinaryReader::new_with_offset(self.data, self.offset)
+ }
+
+ pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b>
+ where
+ 'a: 'b,
+ {
+ OperatorsReader::new(self.data, self.offset)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs
new file mode 100644
index 0000000000..4181cde2dd
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs
@@ -0,0 +1,75 @@
+/* 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 super::{
+ BinaryReader, LinkingType, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+pub struct LinkingSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> LinkingSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<LinkingSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(LinkingSectionReader { reader, count })
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn read<'b>(&mut self) -> Result<LinkingType>
+ where
+ 'a: 'b,
+ {
+ Ok(self.reader.read_linking_type()?)
+ }
+}
+
+impl<'a> SectionReader for LinkingSectionReader<'a> {
+ type Item = LinkingType;
+ fn read(&mut self) -> Result<Self::Item> {
+ LinkingSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ LinkingSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for LinkingSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ LinkingSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for LinkingSectionReader<'a> {
+ type Item = Result<LinkingType>;
+ type IntoIter = SectionIteratorLimited<LinkingSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs
new file mode 100644
index 0000000000..6e9dcb9dd0
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs
@@ -0,0 +1,91 @@
+/* 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 super::{
+ BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+pub struct MemorySectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> MemorySectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<MemorySectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(MemorySectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the memory section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x05, 0x03, 0x01, 0x00, 0x02,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("memory section");
+ /// let mut memory_reader = section.get_memory_section_reader().expect("memory section reader");
+ /// for _ in 0..memory_reader.get_count() {
+ /// let memory = memory_reader.read().expect("memory");
+ /// println!("Memory: {:?}", memory);
+ /// }
+ /// ```
+ pub fn read(&mut self) -> Result<MemoryType> {
+ self.reader.read_memory_type()
+ }
+}
+
+impl<'a> SectionReader for MemorySectionReader<'a> {
+ type Item = MemoryType;
+ fn read(&mut self) -> Result<Self::Item> {
+ MemorySectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ MemorySectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for MemorySectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ MemorySectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for MemorySectionReader<'a> {
+ type Item = Result<MemoryType>;
+ type IntoIter = SectionIteratorLimited<MemorySectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs
new file mode 100644
index 0000000000..6eca50d9ff
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs
@@ -0,0 +1,100 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType,
+ ImportSectionEntryType, LinkingType, MemoryType, NameType, Naming, Operator, Range, RelocType,
+ Result, SectionCode, TableType, Type,
+};
+
+use super::SectionHeader;
+
+pub use self::code_section::CodeSectionReader;
+pub use self::code_section::FunctionBody;
+pub use self::code_section::LocalsReader;
+use self::data_count_section::read_data_count_section_content;
+pub use self::data_section::Data;
+pub use self::data_section::DataKind;
+pub use self::data_section::DataSectionReader;
+pub use self::element_section::Element;
+pub use self::element_section::ElementItem;
+pub use self::element_section::ElementItems;
+pub use self::element_section::ElementItemsReader;
+pub use self::element_section::ElementKind;
+pub use self::element_section::ElementSectionReader;
+pub use self::export_section::Export;
+pub use self::export_section::ExportSectionReader;
+pub use self::function_section::FunctionSectionReader;
+pub use self::global_section::Global;
+pub use self::global_section::GlobalSectionReader;
+pub use self::import_section::Import;
+pub use self::import_section::ImportSectionReader;
+pub use self::init_expr::InitExpr;
+pub use self::memory_section::MemorySectionReader;
+pub use self::module::CustomSectionContent;
+pub use self::module::ModuleReader;
+pub use self::module::Section;
+pub use self::module::SectionContent;
+use self::start_section::read_start_section_content;
+pub use self::table_section::TableSectionReader;
+pub use self::type_section::TypeSectionReader;
+
+pub use self::section_reader::SectionIterator;
+pub use self::section_reader::SectionIteratorLimited;
+pub use self::section_reader::SectionReader;
+pub use self::section_reader::SectionWithLimitedItems;
+
+pub use self::name_section::FunctionName;
+pub use self::name_section::LocalName;
+pub use self::name_section::ModuleName;
+pub use self::name_section::Name;
+pub use self::name_section::NameSectionReader;
+pub use self::name_section::NamingReader;
+
+pub use self::producers_section::ProducersField;
+pub use self::producers_section::ProducersFieldValue;
+pub use self::producers_section::ProducersFieldValuesReader;
+pub use self::producers_section::ProducersSectionReader;
+
+pub use self::linking_section::LinkingSectionReader;
+
+pub use self::reloc_section::Reloc;
+pub use self::reloc_section::RelocSectionReader;
+
+use self::sourcemappingurl_section::read_sourcemappingurl_section_content;
+
+pub use self::operators::OperatorsReader;
+
+mod code_section;
+mod data_count_section;
+mod data_section;
+mod element_section;
+mod export_section;
+mod function_section;
+mod global_section;
+mod import_section;
+mod init_expr;
+mod linking_section;
+mod memory_section;
+mod module;
+mod name_section;
+mod operators;
+mod producers_section;
+mod reloc_section;
+mod section_reader;
+mod sourcemappingurl_section;
+mod start_section;
+mod table_section;
+mod type_section;
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/module.rs b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs
new file mode 100644
index 0000000000..2eb63d61e5
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs
@@ -0,0 +1,512 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, CustomSectionKind, Range, Result, SectionCode, SectionHeader,
+};
+
+use super::{
+ read_data_count_section_content, read_sourcemappingurl_section_content,
+ read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader,
+ ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader,
+ LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader,
+ RelocSectionReader, TableSectionReader, TypeSectionReader,
+};
+
+#[derive(Debug)]
+pub struct Section<'a> {
+ pub code: SectionCode<'a>,
+ offset: usize,
+ data: &'a [u8],
+}
+
+impl<'a> Section<'a> {
+ /// Creates reader for the type section. Available when the reader just read
+ /// the type section.
+ pub fn get_type_section_reader<'b>(&self) -> Result<TypeSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Type => TypeSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_type_section_reader"),
+ }
+ }
+
+ /// Creates reader for the function section. Available when the reader just read
+ /// the function section.
+ pub fn get_function_section_reader<'b>(&self) -> Result<FunctionSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Function => FunctionSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_function_section_reader"),
+ }
+ }
+
+ /// Creates reader for the code section. Available when the reader just read
+ /// the code section.
+ pub fn get_code_section_reader<'b>(&self) -> Result<CodeSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Code => CodeSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_function_section_reader"),
+ }
+ }
+
+ /// Creates reader for the export section. Available when the reader just read
+ /// the export section.
+ pub fn get_export_section_reader<'b>(&self) -> Result<ExportSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Export => ExportSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_export_section_reader"),
+ }
+ }
+
+ /// Creates reader for the import section. Available when the reader just read
+ /// the import section.
+ pub fn get_import_section_reader<'b>(&self) -> Result<ImportSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Import => ImportSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_import_section_reader"),
+ }
+ }
+
+ /// Creates reader for the global section. Available when the reader just read
+ /// the global section.
+ pub fn get_global_section_reader<'b>(&self) -> Result<GlobalSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Global => GlobalSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_global_section_reader"),
+ }
+ }
+
+ /// Creates reader for the memory section. Available when the reader just read
+ /// the memory section.
+ pub fn get_memory_section_reader<'b>(&self) -> Result<MemorySectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Memory => MemorySectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_memory_section_reader"),
+ }
+ }
+
+ /// Creates reader for the data section. Available when the reader just read
+ /// the data section.
+ pub fn get_data_section_reader<'b>(&self) -> Result<DataSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Data => DataSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_data_section_reader"),
+ }
+ }
+
+ /// Creates reader for the table section. Available when the reader just read
+ /// the table section.
+ pub fn get_table_section_reader<'b>(&self) -> Result<TableSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Table => TableSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_table_section_reader"),
+ }
+ }
+
+ /// Creates reader for the element section. Available when the reader just read
+ /// the element section.
+ pub fn get_element_section_reader<'b>(&self) -> Result<ElementSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Element => ElementSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_element_section_reader"),
+ }
+ }
+
+ pub fn get_name_section_reader<'b>(&self) -> Result<NameSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Custom {
+ kind: CustomSectionKind::Name,
+ ..
+ } => NameSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_name_section_reader"),
+ }
+ }
+
+ pub fn get_producers_section_reader<'b>(&self) -> Result<ProducersSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Custom {
+ kind: CustomSectionKind::Producers,
+ ..
+ } => ProducersSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_producers_section_reader"),
+ }
+ }
+
+ pub fn get_linking_section_reader<'b>(&self) -> Result<LinkingSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Custom {
+ kind: CustomSectionKind::Linking,
+ ..
+ } => LinkingSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_linking_section_reader"),
+ }
+ }
+
+ pub fn get_reloc_section_reader<'b>(&self) -> Result<RelocSectionReader<'b>>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Custom {
+ kind: CustomSectionKind::Reloc,
+ ..
+ } => RelocSectionReader::new(self.data, self.offset),
+ _ => panic!("Invalid state for get_reloc_section_reader"),
+ }
+ }
+
+ pub fn get_start_section_content(&self) -> Result<u32> {
+ match self.code {
+ SectionCode::Start => read_start_section_content(self.data, self.offset),
+ _ => panic!("Invalid state for get_start_section_content"),
+ }
+ }
+
+ pub fn get_data_count_section_content(&self) -> Result<u32> {
+ match self.code {
+ SectionCode::DataCount => read_data_count_section_content(self.data, self.offset),
+ _ => panic!("Invalid state for get_data_count_section_content"),
+ }
+ }
+
+ pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b str>
+ where
+ 'a: 'b,
+ {
+ match self.code {
+ SectionCode::Custom {
+ kind: CustomSectionKind::SourceMappingURL,
+ ..
+ } => read_sourcemappingurl_section_content(self.data, self.offset),
+ _ => panic!("Invalid state for get_start_section_content"),
+ }
+ }
+
+ pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
+ where
+ 'a: 'b,
+ {
+ BinaryReader::new_with_offset(self.data, self.offset)
+ }
+
+ pub fn range(&self) -> Range {
+ Range {
+ start: self.offset,
+ end: self.offset + self.data.len(),
+ }
+ }
+
+ pub fn content<'b>(&self) -> Result<SectionContent<'b>>
+ where
+ 'a: 'b,
+ {
+ let c = match self.code {
+ SectionCode::Type => SectionContent::Type(self.get_type_section_reader()?),
+ SectionCode::Function => SectionContent::Function(self.get_function_section_reader()?),
+ SectionCode::Code => SectionContent::Code(self.get_code_section_reader()?),
+ SectionCode::Export => SectionContent::Export(self.get_export_section_reader()?),
+ SectionCode::Import => SectionContent::Import(self.get_import_section_reader()?),
+ SectionCode::Global => SectionContent::Global(self.get_global_section_reader()?),
+ SectionCode::Memory => SectionContent::Memory(self.get_memory_section_reader()?),
+ SectionCode::Data => SectionContent::Data(self.get_data_section_reader()?),
+ SectionCode::Table => SectionContent::Table(self.get_table_section_reader()?),
+ SectionCode::Element => SectionContent::Element(self.get_element_section_reader()?),
+ SectionCode::Start => SectionContent::Start(self.get_start_section_content()?),
+ SectionCode::DataCount => {
+ SectionContent::DataCount(self.get_data_count_section_content()?)
+ }
+ SectionCode::Custom { kind, name } => {
+ // The invalid custom section may cause trouble during
+ // content() call. The spec recommends to ignore erroneous
+ // content in custom section.
+ // Return None in the content field if invalid.
+ let binary = self.get_binary_reader();
+ let content = match kind {
+ CustomSectionKind::Name => self
+ .get_name_section_reader()
+ .ok()
+ .map(CustomSectionContent::Name),
+ CustomSectionKind::Producers => self
+ .get_producers_section_reader()
+ .ok()
+ .map(CustomSectionContent::Producers),
+ CustomSectionKind::Linking => self
+ .get_linking_section_reader()
+ .ok()
+ .map(CustomSectionContent::Linking),
+ CustomSectionKind::Reloc => self
+ .get_reloc_section_reader()
+ .ok()
+ .map(CustomSectionContent::Reloc),
+ CustomSectionKind::SourceMappingURL => self
+ .get_sourcemappingurl_section_content()
+ .ok()
+ .map(CustomSectionContent::SourceMappingURL),
+ _ => None,
+ };
+ SectionContent::Custom {
+ name,
+ binary,
+ content,
+ }
+ }
+ };
+ Ok(c)
+ }
+}
+
+pub enum SectionContent<'a> {
+ Type(TypeSectionReader<'a>),
+ Function(FunctionSectionReader<'a>),
+ Code(CodeSectionReader<'a>),
+ Export(ExportSectionReader<'a>),
+ Import(ImportSectionReader<'a>),
+ Global(GlobalSectionReader<'a>),
+ Memory(MemorySectionReader<'a>),
+ Data(DataSectionReader<'a>),
+ Table(TableSectionReader<'a>),
+ Element(ElementSectionReader<'a>),
+ Start(u32),
+ DataCount(u32),
+ Custom {
+ name: &'a str,
+ binary: BinaryReader<'a>,
+ content: Option<CustomSectionContent<'a>>,
+ },
+}
+
+pub enum CustomSectionContent<'a> {
+ Name(NameSectionReader<'a>),
+ Producers(ProducersSectionReader<'a>),
+ Linking(LinkingSectionReader<'a>),
+ Reloc(RelocSectionReader<'a>),
+ SourceMappingURL(&'a str),
+}
+
+/// Reads top-level WebAssembly file structure: header and sections.
+pub struct ModuleReader<'a> {
+ reader: BinaryReader<'a>,
+ version: u32,
+ read_ahead: Option<(usize, SectionHeader<'a>)>,
+}
+
+impl<'a> ModuleReader<'a> {
+ pub fn new(data: &[u8]) -> Result<ModuleReader> {
+ let mut reader = BinaryReader::new(data);
+ let version = reader.read_file_header()?;
+ Ok(ModuleReader {
+ reader,
+ version,
+ read_ahead: None,
+ })
+ }
+
+ pub fn get_version(&self) -> u32 {
+ self.version
+ }
+
+ pub fn current_position(&self) -> usize {
+ match self.read_ahead {
+ Some((position, _)) => position,
+ _ => self.reader.current_position(),
+ }
+ }
+
+ pub fn eof(&self) -> bool {
+ self.read_ahead.is_none() && self.reader.eof()
+ }
+
+ fn verify_section_end(&self, end: usize) -> Result<()> {
+ if self.reader.buffer.len() < end {
+ return Err(BinaryReaderError {
+ message: "Section body extends past end of file",
+ offset: self.reader.buffer.len(),
+ });
+ }
+ if self.reader.position > end {
+ return Err(BinaryReaderError {
+ message: "Section header is too big to fit into section body",
+ offset: end,
+ });
+ }
+ Ok(())
+ }
+
+ /// Reads next top-level record from the WebAssembly binary data.
+ /// The methods returns reference to current state of the reader.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("reader");
+ /// let section = reader.read().expect("section #1");
+ /// println!("First section {:?}", section);
+ /// let section = reader.read().expect("section #2");
+ /// println!("Second section {:?}", section);
+ /// assert!(!reader.eof(), "there are more sections");
+ /// ```
+ pub fn read<'b>(&mut self) -> Result<Section<'b>>
+ where
+ 'a: 'b,
+ {
+ let SectionHeader {
+ code,
+ payload_start,
+ payload_len,
+ } = match self.read_ahead.take() {
+ Some((_, section_header)) => section_header,
+ None => self.reader.read_section_header()?,
+ };
+ let payload_end = payload_start + payload_len;
+ self.verify_section_end(payload_end)?;
+ let body_start = self.reader.position;
+ self.reader.skip_to(payload_end);
+ Ok(Section {
+ code,
+ offset: body_start,
+ data: &self.reader.buffer[body_start..payload_end],
+ })
+ }
+
+ fn ensure_read_ahead(&mut self) -> Result<()> {
+ if self.read_ahead.is_none() && !self.eof() {
+ let position = self.reader.current_position();
+ self.read_ahead = Some((position, self.reader.read_section_header()?));
+ }
+ Ok(())
+ }
+
+ /// Skips custom sections.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x00, 0x8, 0x03, 0x63, 0x61, 0x74, 0x01, 0x02, 0x03, 0x04,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// use wasmparser::SectionCode;
+ /// let mut reader = ModuleReader::new(data).expect("reader");
+ /// while { reader.skip_custom_sections(); !reader.eof() } {
+ /// let section = reader.read().expect("section");
+ /// if let SectionCode::Custom {..} = section.code { panic!("no custom"); }
+ /// println!("Section {:?}", section);
+ /// }
+ /// ```
+ pub fn skip_custom_sections(&mut self) -> Result<()> {
+ loop {
+ self.ensure_read_ahead()?;
+ match self.read_ahead {
+ Some((
+ _,
+ SectionHeader {
+ code: SectionCode::Custom { .. },
+ payload_start,
+ payload_len,
+ },
+ )) => {
+ self.verify_section_end(payload_start + payload_len)?;
+ // Skip section
+ self.read_ahead = None;
+ self.reader.skip_to(payload_start + payload_len);
+ }
+ _ => break,
+ };
+ }
+ Ok(())
+ }
+}
+
+impl<'a> IntoIterator for ModuleReader<'a> {
+ type Item = Result<Section<'a>>;
+ type IntoIter = ModuleIterator<'a>;
+ fn into_iter(self) -> Self::IntoIter {
+ ModuleIterator {
+ reader: self,
+ err: false,
+ }
+ }
+}
+
+pub struct ModuleIterator<'a> {
+ reader: ModuleReader<'a>,
+ err: bool,
+}
+
+impl<'a> Iterator for ModuleIterator<'a> {
+ type Item = Result<Section<'a>>;
+
+ /// Iterates sections from the WebAssembly binary data. Stops at first error.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// for section in ModuleReader::new(data).expect("reader") {
+ /// println!("Section {:?}", section);
+ /// }
+ /// ```
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.reader.eof() {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ Some(result)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs
new file mode 100644
index 0000000000..f657c69fc7
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs
@@ -0,0 +1,233 @@
+/* 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 super::{
+ BinaryReader, BinaryReaderError, NameType, Naming, Result, SectionIterator, SectionReader,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct ModuleName<'a> {
+ data: &'a [u8],
+ offset: usize,
+}
+
+impl<'a> ModuleName<'a> {
+ pub fn get_name<'b>(&self) -> Result<&'b str>
+ where
+ 'a: 'b,
+ {
+ let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
+ reader.read_string()
+ }
+}
+
+pub struct NamingReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> NamingReader<'a> {
+ fn new(data: &'a [u8], offset: usize) -> Result<NamingReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(NamingReader { reader, count })
+ }
+
+ fn skip(reader: &mut BinaryReader) -> Result<()> {
+ let count = reader.read_var_u32()?;
+ for _ in 0..count {
+ reader.skip_var_32()?;
+ reader.skip_string()?;
+ }
+ Ok(())
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn read<'b>(&mut self) -> Result<Naming<'b>>
+ where
+ 'a: 'b,
+ {
+ let index = self.reader.read_var_u32()?;
+ let name = self.reader.read_string()?;
+ Ok(Naming { index, name })
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct FunctionName<'a> {
+ data: &'a [u8],
+ offset: usize,
+}
+
+impl<'a> FunctionName<'a> {
+ pub fn get_map<'b>(&self) -> Result<NamingReader<'b>>
+ where
+ 'a: 'b,
+ {
+ NamingReader::new(self.data, self.offset)
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct FunctionLocalName<'a> {
+ pub func_index: u32,
+ data: &'a [u8],
+ offset: usize,
+}
+
+impl<'a> FunctionLocalName<'a> {
+ pub fn get_map<'b>(&self) -> Result<NamingReader<'b>>
+ where
+ 'a: 'b,
+ {
+ NamingReader::new(self.data, self.offset)
+ }
+}
+
+pub struct FunctionLocalReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> FunctionLocalReader<'a> {
+ fn new(data: &'a [u8], offset: usize) -> Result<FunctionLocalReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(FunctionLocalReader { reader, count })
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn read<'b>(&mut self) -> Result<FunctionLocalName<'b>>
+ where
+ 'a: 'b,
+ {
+ let func_index = self.reader.read_var_u32()?;
+ let start = self.reader.position;
+ NamingReader::skip(&mut self.reader)?;
+ let end = self.reader.position;
+ Ok(FunctionLocalName {
+ func_index,
+ data: &self.reader.buffer[start..end],
+ offset: self.reader.original_offset + start,
+ })
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct LocalName<'a> {
+ data: &'a [u8],
+ offset: usize,
+}
+
+impl<'a> LocalName<'a> {
+ pub fn get_function_local_reader<'b>(&self) -> Result<FunctionLocalReader<'b>>
+ where
+ 'a: 'b,
+ {
+ FunctionLocalReader::new(self.data, self.offset)
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum Name<'a> {
+ Module(ModuleName<'a>),
+ Function(FunctionName<'a>),
+ Local(LocalName<'a>),
+}
+
+pub struct NameSectionReader<'a> {
+ reader: BinaryReader<'a>,
+}
+
+impl<'a> NameSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<NameSectionReader<'a>> {
+ Ok(NameSectionReader {
+ reader: BinaryReader::new_with_offset(data, offset),
+ })
+ }
+
+ fn verify_section_end(&self, end: usize) -> Result<()> {
+ if self.reader.buffer.len() < end {
+ return Err(BinaryReaderError {
+ message: "Name entry extends past end of the code section",
+ offset: self.reader.original_offset + self.reader.buffer.len(),
+ });
+ }
+ Ok(())
+ }
+
+ pub fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn read<'b>(&mut self) -> Result<Name<'b>>
+ where
+ 'a: 'b,
+ {
+ let ty = self.reader.read_name_type()?;
+ let payload_len = self.reader.read_var_u32()? as usize;
+ let payload_start = self.reader.position;
+ let payload_end = payload_start + payload_len;
+ self.verify_section_end(payload_end)?;
+ let offset = self.reader.original_offset + payload_start;
+ let data = &self.reader.buffer[payload_start..payload_end];
+ self.reader.skip_to(payload_end);
+ Ok(match ty {
+ NameType::Module => Name::Module(ModuleName { data, offset }),
+ NameType::Function => Name::Function(FunctionName { data, offset }),
+ NameType::Local => Name::Local(LocalName { data, offset }),
+ })
+ }
+}
+
+impl<'a> SectionReader for NameSectionReader<'a> {
+ type Item = Name<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ NameSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ NameSectionReader::eof(self)
+ }
+ fn original_position(&self) -> usize {
+ NameSectionReader::original_position(self)
+ }
+}
+
+impl<'a> IntoIterator for NameSectionReader<'a> {
+ type Item = Result<Name<'a>>;
+ type IntoIter = SectionIterator<NameSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIterator::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs
new file mode 100644
index 0000000000..0ecac8d5fb
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs
@@ -0,0 +1,171 @@
+/* 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 super::{BinaryReader, BinaryReaderError, Operator, Result};
+
+#[derive(Clone)]
+pub struct OperatorsReader<'a> {
+ pub(crate) reader: BinaryReader<'a>,
+}
+
+impl<'a> OperatorsReader<'a> {
+ pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b>
+ where
+ 'a: 'b,
+ {
+ OperatorsReader {
+ reader: BinaryReader::new_with_offset(data, offset),
+ }
+ }
+
+ pub fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn ensure_end(&self) -> Result<()> {
+ if self.eof() {
+ return Ok(());
+ }
+ Err(BinaryReaderError {
+ message: "Unexpected data at the end of operators",
+ offset: self.reader.original_position(),
+ })
+ }
+
+ pub fn read<'b>(&mut self) -> Result<Operator<'b>>
+ where
+ 'a: 'b,
+ {
+ self.reader.read_operator()
+ }
+
+ pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b>
+ where
+ 'a: 'b,
+ {
+ OperatorsIteratorWithOffsets {
+ reader: self,
+ err: false,
+ }
+ }
+
+ pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)>
+ where
+ 'a: 'b,
+ {
+ let pos = self.reader.original_position();
+ Ok((self.read()?, pos))
+ }
+}
+
+impl<'a> IntoIterator for OperatorsReader<'a> {
+ type Item = Result<Operator<'a>>;
+ type IntoIter = OperatorsIterator<'a>;
+
+ /// Reads content of the code section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::{ModuleReader, Result, Operator};
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("code section");
+ /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
+ /// for _ in 0..code_reader.get_count() {
+ /// let body = code_reader.read().expect("function body");
+ /// let mut op_reader = body.get_operators_reader().expect("op reader");
+ /// let ops = op_reader.into_iter().collect::<Result<Vec<Operator>>>().expect("ops");
+ /// assert!(
+ /// if let [Operator::Nop, Operator::End] = ops.as_slice() { true } else { false },
+ /// "found {:?}",
+ /// ops
+ /// );
+ /// }
+ /// ```
+ fn into_iter(self) -> Self::IntoIter {
+ OperatorsIterator {
+ reader: self,
+ err: false,
+ }
+ }
+}
+
+pub struct OperatorsIterator<'a> {
+ reader: OperatorsReader<'a>,
+ err: bool,
+}
+
+impl<'a> Iterator for OperatorsIterator<'a> {
+ type Item = Result<Operator<'a>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.reader.eof() {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ Some(result)
+ }
+}
+
+pub struct OperatorsIteratorWithOffsets<'a> {
+ reader: OperatorsReader<'a>,
+ err: bool,
+}
+
+impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> {
+ type Item = Result<(Operator<'a>, usize)>;
+
+ /// Reads content of the code section with offsets.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b];
+ /// use wasmparser::{ModuleReader, Result, Operator};
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("code section");
+ /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
+ /// for _ in 0..code_reader.get_count() {
+ /// let body = code_reader.read().expect("function body");
+ /// let mut op_reader = body.get_operators_reader().expect("op reader");
+ /// let ops = op_reader.into_iter_with_offsets().collect::<Result<Vec<(Operator, usize)>>>().expect("ops");
+ /// assert!(
+ /// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false },
+ /// "found {:?}",
+ /// ops
+ /// );
+ /// }
+ /// ```
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.reader.eof() {
+ return None;
+ }
+ let result = self.reader.read_with_offset();
+ self.err = result.is_err();
+ Some(result)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs
new file mode 100644
index 0000000000..a65769c1d9
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs
@@ -0,0 +1,192 @@
+/* Copyright 2019 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 super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems};
+
+#[derive(Debug, Copy, Clone)]
+pub struct ProducersFieldValue<'a> {
+ pub name: &'a str,
+ pub version: &'a str,
+}
+
+pub struct ProducersFieldValuesReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> ProducersFieldValuesReader<'a> {
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> {
+ for _ in 0..values_count {
+ reader.skip_string()?;
+ reader.skip_string()?;
+ }
+ Ok(())
+ }
+
+ pub fn read<'b>(&mut self) -> Result<ProducersFieldValue<'b>>
+ where
+ 'a: 'b,
+ {
+ let name = self.reader.read_string()?;
+ let version = self.reader.read_string()?;
+ Ok(ProducersFieldValue { name, version })
+ }
+}
+
+impl<'a> IntoIterator for ProducersFieldValuesReader<'a> {
+ type Item = Result<ProducersFieldValue<'a>>;
+ type IntoIter = ProducersFieldValuesIterator<'a>;
+ fn into_iter(self) -> Self::IntoIter {
+ let count = self.count;
+ ProducersFieldValuesIterator {
+ reader: self,
+ left: count,
+ err: false,
+ }
+ }
+}
+
+pub struct ProducersFieldValuesIterator<'a> {
+ reader: ProducersFieldValuesReader<'a>,
+ left: u32,
+ err: bool,
+}
+
+impl<'a> Iterator for ProducersFieldValuesIterator<'a> {
+ type Item = Result<ProducersFieldValue<'a>>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.left == 0 {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ self.left -= 1;
+ Some(result)
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let count = self.reader.get_count() as usize;
+ (count, Some(count))
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ProducersField<'a> {
+ pub name: &'a str,
+ values_count: u32,
+ values_data: &'a [u8],
+ values_offset: usize,
+}
+
+impl<'a> ProducersField<'a> {
+ pub fn get_producer_field_values_reader<'b>(&self) -> Result<ProducersFieldValuesReader<'b>>
+ where
+ 'a: 'b,
+ {
+ Ok(ProducersFieldValuesReader {
+ reader: BinaryReader::new_with_offset(self.values_data, self.values_offset),
+ count: self.values_count,
+ })
+ }
+}
+
+pub struct ProducersSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> ProducersSectionReader<'a> {
+ /// Creates reader for the producers section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
+ /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30];
+ /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result};
+ /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader");
+ /// let field = reader.read().expect("producers field");
+ /// assert!(field.name == "language");
+ /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader");
+ /// let value = values_reader.into_iter().collect::<Result<Vec<ProducersFieldValue>>>().expect("values");
+ /// assert!(value.len() == 2);
+ /// assert!(value[0].name == "wat" && value[0].version == "1");
+ /// assert!(value[1].name == "C" && value[1].version == "9.0");
+ /// ```
+ pub fn new(data: &'a [u8], offset: usize) -> Result<ProducersSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(ProducersSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn read<'b>(&mut self) -> Result<ProducersField<'b>>
+ where
+ 'a: 'b,
+ {
+ let name = self.reader.read_string()?;
+ let values_count = self.reader.read_var_u32()?;
+ let values_start = self.reader.position;
+ ProducersFieldValuesReader::skip(&mut self.reader, values_count)?;
+ let values_end = self.reader.position;
+ Ok(ProducersField {
+ name,
+ values_count,
+ values_data: &self.reader.buffer[values_start..values_end],
+ values_offset: self.reader.original_offset + values_start,
+ })
+ }
+}
+
+impl<'a> SectionReader for ProducersSectionReader<'a> {
+ type Item = ProducersField<'a>;
+ fn read(&mut self) -> Result<Self::Item> {
+ ProducersSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ ProducersSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ ProducersSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for ProducersSectionReader<'a> {
+ type Item = Result<ProducersField<'a>>;
+ type IntoIter = SectionIteratorLimited<ProducersSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs
new file mode 100644
index 0000000000..2758294cb0
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs
@@ -0,0 +1,115 @@
+/* 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 super::{
+ BinaryReader, RelocType, Result, SectionCode, SectionIteratorLimited, SectionReader,
+ SectionWithLimitedItems,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Reloc {
+ pub ty: RelocType,
+ pub offset: u32,
+ pub index: u32,
+ pub addend: Option<u32>,
+}
+
+pub struct RelocSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ section_code: SectionCode<'a>,
+ count: u32,
+}
+
+impl<'a> RelocSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<RelocSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+
+ let section_id_position = reader.position;
+ let section_id = reader.read_var_u7()?;
+ let section_code = reader.read_section_code(section_id, section_id_position)?;
+
+ let count = reader.read_var_u32()?;
+ Ok(RelocSectionReader {
+ reader,
+ section_code,
+ count,
+ })
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ pub fn get_section_code<'b>(&self) -> SectionCode<'b>
+ where
+ 'a: 'b,
+ {
+ self.section_code
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn read(&mut self) -> Result<Reloc> {
+ let ty = self.reader.read_reloc_type()?;
+ let offset = self.reader.read_var_u32()?;
+ let index = self.reader.read_var_u32()?;
+ let addend = match ty {
+ RelocType::FunctionIndexLEB
+ | RelocType::TableIndexSLEB
+ | RelocType::TableIndexI32
+ | RelocType::TypeIndexLEB
+ | RelocType::GlobalIndexLEB => None,
+ RelocType::GlobalAddrLEB | RelocType::GlobalAddrSLEB | RelocType::GlobalAddrI32 => {
+ Some(self.reader.read_var_u32()?)
+ }
+ };
+ Ok(Reloc {
+ ty,
+ offset,
+ index,
+ addend,
+ })
+ }
+}
+
+impl<'a> SectionReader for RelocSectionReader<'a> {
+ type Item = Reloc;
+ fn read(&mut self) -> Result<Self::Item> {
+ RelocSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ RelocSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for RelocSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ RelocSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for RelocSectionReader<'a> {
+ type Item = Result<Reloc>;
+ type IntoIter = SectionIteratorLimited<RelocSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs
new file mode 100644
index 0000000000..6ec9cd791d
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs
@@ -0,0 +1,123 @@
+/* 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 super::{BinaryReaderError, Result};
+
+pub trait SectionReader {
+ type Item;
+ fn read(&mut self) -> Result<Self::Item>;
+ fn eof(&self) -> bool;
+ fn original_position(&self) -> usize;
+ fn ensure_end(&self) -> Result<()> {
+ if self.eof() {
+ return Ok(());
+ }
+ Err(BinaryReaderError {
+ message: "Unexpected data at the end of the section",
+ offset: self.original_position(),
+ })
+ }
+}
+
+pub trait SectionWithLimitedItems {
+ fn get_count(&self) -> u32;
+}
+
+pub struct SectionIterator<R>
+where
+ R: SectionReader,
+{
+ reader: R,
+ err: bool,
+}
+
+impl<R> SectionIterator<R>
+where
+ R: SectionReader,
+{
+ pub fn new(reader: R) -> SectionIterator<R> {
+ SectionIterator { reader, err: false }
+ }
+}
+
+impl<R> Iterator for SectionIterator<R>
+where
+ R: SectionReader,
+{
+ type Item = Result<R::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.err || self.reader.eof() {
+ return None;
+ }
+ let result = self.reader.read();
+ self.err = result.is_err();
+ Some(result)
+ }
+}
+
+pub struct SectionIteratorLimited<R>
+where
+ R: SectionReader + SectionWithLimitedItems,
+{
+ reader: R,
+ left: u32,
+ end: bool,
+}
+
+impl<R> SectionIteratorLimited<R>
+where
+ R: SectionReader + SectionWithLimitedItems,
+{
+ pub fn new(reader: R) -> SectionIteratorLimited<R> {
+ let left = reader.get_count();
+ SectionIteratorLimited {
+ reader,
+ left,
+ end: false,
+ }
+ }
+}
+
+impl<R> Iterator for SectionIteratorLimited<R>
+where
+ R: SectionReader + SectionWithLimitedItems,
+{
+ type Item = Result<R::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.end {
+ return None;
+ }
+ if self.left == 0 {
+ return match self.reader.ensure_end() {
+ Ok(()) => None,
+ Err(err) => {
+ self.end = true;
+ Some(Err(err))
+ }
+ };
+ }
+ let result = self.reader.read();
+ self.end = result.is_err();
+ self.left -= 1;
+ Some(result)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let count = self.reader.get_count() as usize;
+ (count, Some(count))
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs
new file mode 100644
index 0000000000..6f6e5eef21
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs
@@ -0,0 +1,31 @@
+/* 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 super::{BinaryReader, BinaryReaderError, Result};
+
+pub(crate) fn read_sourcemappingurl_section_content<'a>(
+ data: &'a [u8],
+ offset: usize,
+) -> Result<&'a str> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let url = reader.read_string()?;
+ if !reader.eof() {
+ return Err(BinaryReaderError {
+ message: "Unexpected content in the sourceMappingURL section",
+ offset: offset + reader.position,
+ });
+ }
+ Ok(url)
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs
new file mode 100644
index 0000000000..81da40b58f
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs
@@ -0,0 +1,28 @@
+/* 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 super::{BinaryReader, BinaryReaderError, Result};
+
+pub(crate) fn read_start_section_content(data: &[u8], offset: usize) -> Result<u32> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let start_index = reader.read_var_u32()?;
+ if !reader.eof() {
+ return Err(BinaryReaderError {
+ message: "Unexpected content in the start section",
+ offset: offset + reader.position,
+ });
+ }
+ Ok(start_index)
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs
new file mode 100644
index 0000000000..322e23656f
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs
@@ -0,0 +1,90 @@
+/* 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 super::{
+ BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType,
+};
+
+pub struct TableSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> TableSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<TableSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(TableSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the table section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("type section");
+ /// let section = reader.read().expect("function section");
+ /// let section = reader.read().expect("table section");
+ /// let mut table_reader = section.get_table_section_reader().expect("table section reader");
+ /// for _ in 0..table_reader.get_count() {
+ /// let table = table_reader.read().expect("table");
+ /// println!("Table: {:?}", table);
+ /// }
+ /// ```
+ pub fn read(&mut self) -> Result<TableType> {
+ self.reader.read_table_type()
+ }
+}
+
+impl<'a> SectionReader for TableSectionReader<'a> {
+ type Item = TableType;
+ fn read(&mut self) -> Result<Self::Item> {
+ TableSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ TableSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for TableSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ TableSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for TableSectionReader<'a> {
+ type Item = Result<TableType>;
+ type IntoIter = SectionIteratorLimited<TableSectionReader<'a>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs
new file mode 100644
index 0000000000..51fd6eea36
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs
@@ -0,0 +1,103 @@
+/* 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 super::{
+ BinaryReader, FuncType, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems,
+};
+
+pub struct TypeSectionReader<'a> {
+ reader: BinaryReader<'a>,
+ count: u32,
+}
+
+impl<'a> TypeSectionReader<'a> {
+ pub fn new(data: &'a [u8], offset: usize) -> Result<TypeSectionReader<'a>> {
+ let mut reader = BinaryReader::new_with_offset(data, offset);
+ let count = reader.read_var_u32()?;
+ Ok(TypeSectionReader { reader, count })
+ }
+
+ pub fn original_position(&self) -> usize {
+ self.reader.original_position()
+ }
+
+ pub fn get_count(&self) -> u32 {
+ self.count
+ }
+
+ /// Reads content of the type section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("section");
+ /// let mut type_reader = section.get_type_section_reader().expect("type section reader");
+ /// for _ in 0..type_reader.get_count() {
+ /// let ty = type_reader.read().expect("type");
+ /// println!("Type {:?}", ty);
+ /// }
+ /// ```
+ pub fn read(&mut self) -> Result<FuncType> {
+ self.reader.read_func_type()
+ }
+}
+
+impl<'a> SectionReader for TypeSectionReader<'a> {
+ type Item = FuncType;
+ fn read(&mut self) -> Result<Self::Item> {
+ TypeSectionReader::read(self)
+ }
+ fn eof(&self) -> bool {
+ self.reader.eof()
+ }
+ fn original_position(&self) -> usize {
+ TypeSectionReader::original_position(self)
+ }
+}
+
+impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> {
+ fn get_count(&self) -> u32 {
+ TypeSectionReader::get_count(self)
+ }
+}
+
+impl<'a> IntoIterator for TypeSectionReader<'a> {
+ type Item = Result<FuncType>;
+ type IntoIter = SectionIteratorLimited<TypeSectionReader<'a>>;
+
+ /// Implements iterator over the type section.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
+ /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+ /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
+ /// use wasmparser::ModuleReader;
+ /// use wasmparser::{Result, FuncType};
+ /// let mut reader = ModuleReader::new(data).expect("module reader");
+ /// let section = reader.read().expect("section");
+ /// let mut type_reader = section.get_type_section_reader().expect("type section reader");
+ /// for ty in type_reader {
+ /// println!("Type {:?}", ty);
+ /// }
+ /// ```
+ fn into_iter(self) -> Self::IntoIter {
+ SectionIteratorLimited::new(self)
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/tests.rs b/third_party/rust/wasmparser-0.48.2/src/tests.rs
new file mode 100644
index 0000000000..527ace1993
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/tests.rs
@@ -0,0 +1,529 @@
+/* Copyright 2017 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.
+ */
+
+#[cfg(test)]
+mod simple_tests {
+ use crate::operators_validator::OperatorValidatorConfig;
+ use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder};
+ use crate::primitives::{Operator, SectionCode};
+ use crate::validator::{ValidatingParser, ValidatingParserConfig};
+ use std::fs::{read_dir, File};
+ use std::io::prelude::*;
+ use std::path::PathBuf;
+
+ const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ enable_threads: true,
+ enable_reference_types: true,
+ enable_simd: true,
+ enable_bulk_memory: true,
+ enable_multi_value: true,
+
+ #[cfg(feature = "deterministic")]
+ deterministic_only: true,
+ },
+ });
+
+ fn read_file_data(path: &PathBuf) -> Vec<u8> {
+ println!("Parsing {:?}", path);
+ let mut data = Vec::new();
+ let mut f = File::open(path).ok().unwrap();
+ f.read_to_end(&mut data).unwrap();
+ data
+ }
+
+ #[allow(dead_code)]
+ fn scan_tests_files(prefix: &str) -> Vec<PathBuf> {
+ let mut files = Vec::new();
+
+ for entry in read_dir("tests/").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+
+ let path = dir.path();
+ let file = path.to_str().unwrap();
+
+ if file.starts_with(prefix) {
+ files.push(path);
+ }
+ }
+
+ return files;
+ }
+
+ #[test]
+ fn it_works() {
+ for entry in read_dir("tests").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = Parser::new(data.as_slice());
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => panic!("Error: {:?}", err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn validator_not_fails() {
+ for entry in read_dir("tests").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG);
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => panic!("Error: {:?}", err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn validator_fails() {
+ for entry in read_dir("tests/invalid").unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file() {
+ continue;
+ }
+ let data = read_file_data(&dir.path());
+ let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG);
+ let mut max_iteration = 100000000;
+ let mut error = false;
+ loop {
+ let state = parser.read();
+ if let ParserState::Error(_) = *state {
+ error = true;
+ break;
+ }
+ if let ParserState::EndWasm = *state {
+ break;
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ if !error {
+ panic!("fail is expected");
+ }
+ }
+ }
+
+ macro_rules! expect_state {
+ ($state:expr, $expected:pat) => {{
+ {
+ let state: &ParserState = $state;
+ match *state {
+ $expected => (),
+ _ => panic!("Unexpected state during testing: {:?}", state),
+ }
+ }
+ }};
+ }
+
+ #[test]
+ fn default_read() {
+ let data = read_file_data(&PathBuf::from("tests/simple.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(), ParserState::BeginWasm { .. });
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read(), ParserState::TypeSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, .. });
+ expect_state!(parser.read(), ParserState::FunctionSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(), ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read(), ParserState::FunctionBodyLocals { .. });
+ expect_state!(parser.read(), ParserState::CodeOperator(_));
+ expect_state!(parser.read(), ParserState::CodeOperator(Operator::End));
+ expect_state!(parser.read(), ParserState::EndFunctionBody);
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::EndWasm);
+ }
+
+ #[test]
+ fn default_read_with_input() {
+ let data = read_file_data(&PathBuf::from("tests/simple.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(), ParserState::BeginWasm { .. });
+ expect_state!(parser.read_with_input(ParserInput::Default),
+ ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read(), ParserState::TypeSectionEntry(_));
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, ..});
+ expect_state!(
+ parser.read_with_input(ParserInput::ReadSectionRawData),
+ ParserState::SectionRawData(_)
+ );
+ expect_state!(parser.read(), ParserState::EndSection);
+ expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(), ParserState::BeginFunctionBody { .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::EndSection
+ );
+ expect_state!(parser.read(), ParserState::EndWasm);
+ }
+
+ #[test]
+ fn skipping() {
+ let data = read_file_data(&PathBuf::from("tests/naming.wasm"));
+ let mut parser = Parser::new(data.as_slice());
+
+ expect_state!(parser.read(),
+ ParserState::BeginWasm { .. });
+ expect_state!(parser.read_with_input(ParserInput::Default),
+ ParserState::BeginSection { code: SectionCode::Type, .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Import, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Function, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Global, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Export, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Element, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Code, .. });
+ expect_state!(parser.read(),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::BeginFunctionBody { .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipFunctionBody),
+ ParserState::EndSection
+ );
+ expect_state!(parser.read(),
+ ParserState::BeginSection { code: SectionCode::Custom { .. }, ..});
+ expect_state!(parser.read_with_input(ParserInput::SkipSection),
+ ParserState::BeginSection { code: SectionCode::Custom { .. }, .. });
+ expect_state!(
+ parser.read_with_input(ParserInput::SkipSection),
+ ParserState::EndWasm
+ );
+ }
+
+ #[cfg(feature = "deterministic")]
+ fn run_deterministic_enabled_test(path: &PathBuf) {
+ let data = read_file_data(path);
+
+ let config = Some(ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ deterministic_only: false,
+ enable_threads: true,
+ enable_reference_types: true,
+ enable_simd: true,
+ enable_bulk_memory: true,
+ enable_multi_value: true,
+ },
+ });
+
+ let mut parser = ValidatingParser::new(data.as_slice(), config);
+ let mut error = false;
+
+ loop {
+ let state = parser.read();
+ if let ParserState::Error(_) = *state {
+ error = true;
+ break;
+ }
+ if let ParserState::EndWasm = *state {
+ break;
+ }
+ }
+
+ assert!(error);
+ }
+
+ #[cfg(feature = "deterministic")]
+ #[test]
+ fn deterministic_enabled() {
+ // `float_exprs.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_exprs.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(96, tests_count);
+
+ // `float_memory.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_memory.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(6, tests_count);
+
+ // `float_misc.*.wasm`
+ let mut tests_count = 0;
+ for path in scan_tests_files("tests/float_misc.") {
+ run_deterministic_enabled_test(&path);
+ tests_count += 1;
+ }
+ assert_eq!(1, tests_count);
+ }
+}
+
+#[cfg(test)]
+mod wast_tests {
+ use crate::operators_validator::OperatorValidatorConfig;
+ use crate::parser::{ParserState, WasmDecoder};
+ use crate::validator::{ValidatingParser, ValidatingParserConfig};
+ use crate::BinaryReaderError;
+ use std::fs::{read, read_dir};
+ use std::str;
+
+ const SPEC_TESTS_PATH: &str = "testsuite";
+
+ fn default_config() -> ValidatingParserConfig {
+ ValidatingParserConfig {
+ operator_config: OperatorValidatorConfig {
+ enable_threads: false,
+ enable_reference_types: false,
+ enable_simd: false,
+ enable_bulk_memory: false,
+ enable_multi_value: false,
+
+ #[cfg(feature = "deterministic")]
+ deterministic_only: true,
+ },
+ }
+ }
+
+ fn validate_module(
+ mut module: wast::Module,
+ config: ValidatingParserConfig,
+ ) -> Result<(), BinaryReaderError> {
+ let data = module.encode().unwrap();
+ let mut parser = ValidatingParser::new(data.as_slice(), Some(config));
+ let mut max_iteration = 100000000;
+ loop {
+ let state = parser.read();
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(err) => return Err(err),
+ _ => (),
+ }
+ max_iteration -= 1;
+ if max_iteration == 0 {
+ panic!("Max iterations exceeded");
+ }
+ }
+ Ok(())
+ }
+
+ fn run_wabt_scripts<F>(
+ filename: &str,
+ wast: &[u8],
+ config: ValidatingParserConfig,
+ skip_test: F,
+ ) where
+ F: Fn(&str, u64) -> bool,
+ {
+ println!("Parsing {:?}", filename);
+ // Check if we need to skip entire wast file test/parsing.
+ if skip_test(filename, /* line = */ 0) {
+ println!("{}: skipping", filename);
+ return;
+ }
+
+ let contents = str::from_utf8(wast).unwrap();
+ let buf = wast::parser::ParseBuffer::new(&contents)
+ .map_err(|mut e| {
+ e.set_path(filename.as_ref());
+ e
+ })
+ .unwrap();
+ let wast = wast::parser::parse::<wast::Wast>(&buf)
+ .map_err(|mut e| {
+ e.set_path(filename.as_ref());
+ e
+ })
+ .unwrap();
+
+ for directive in wast.directives {
+ use wast::WastDirective::*;
+ let (line, _col) = directive.span().linecol_in(&contents);
+ let line = line + 1;
+ if skip_test(filename, line as u64) {
+ println!("{}:{}: skipping", filename, line);
+ continue;
+ }
+ match directive {
+ Module(module) | AssertUnlinkable { module, .. } => {
+ if let Err(err) = validate_module(module, config.clone()) {
+ panic!("{}:{}: invalid module: {}", filename, line, err.message);
+ }
+ }
+ AssertInvalid { module, .. }
+ | AssertMalformed {
+ module: wast::QuoteModule::Module(module),
+ ..
+ } => {
+ // TODO diffentiate between assert_invalid and assert_malformed
+ if let Ok(_) = validate_module(module, config.clone()) {
+ panic!(
+ "{}:{}: invalid module was successfully parsed",
+ filename, line
+ );
+ }
+ // TODO: Check the assert_invalid or assert_malformed message
+ }
+
+ AssertMalformed {
+ module: wast::QuoteModule::Quote(_),
+ ..
+ }
+ | Register { .. }
+ | Invoke { .. }
+ | AssertTrap { .. }
+ | AssertReturn { .. }
+ | AssertReturnFunc { .. }
+ | AssertExhaustion { .. } => {}
+ }
+ }
+ }
+
+ fn run_proposal_tests<F>(name: &str, config: ValidatingParserConfig, skip_test: F)
+ where
+ F: Fn(&str, u64) -> bool,
+ {
+ let proposal_dir = format!("{}/proposals/{}", SPEC_TESTS_PATH, name);
+ for entry in read_dir(&proposal_dir).unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file()
+ || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast")
+ {
+ continue;
+ }
+
+ let data = read(&dir.path()).expect("wast data");
+ run_wabt_scripts(
+ dir.file_name().to_str().expect("name"),
+ &data,
+ config,
+ |name, line| skip_test(name, line),
+ );
+ }
+ }
+
+ #[test]
+ fn run_proposals_tests() {
+ run_proposal_tests(
+ "simd",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_simd = true;
+ config
+ },
+ |name, line| match (name, line) {
+ // FIXME(WebAssembly/simd#140) needs a few updates to the
+ // `*.wast` file to successfully parse it (or so I think)
+ ("simd_lane.wast", _) => true,
+ ("simd_load_extend.wast", _) => true,
+ ("simd_f32x4_arith.wast", _) => true,
+ ("simd_f64x2_arith.wast", _) => true,
+ ("simd_f32x4.wast", _) => true,
+ ("simd_f64x2.wast", _) => true,
+ ("simd_const.wast", _) => true,
+ ("simd_load_splat.wast", _) => true,
+ _ => false,
+ },
+ );
+
+ run_proposal_tests(
+ "multi-value",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_multi_value = true;
+ config
+ },
+ |_name, _line| false,
+ );
+
+ run_proposal_tests(
+ "reference-types",
+ {
+ let mut config: ValidatingParserConfig = default_config();
+ config.operator_config.enable_reference_types = true;
+ config.operator_config.enable_bulk_memory = true;
+ config
+ },
+ |name, line| match (name, line) {
+ ("br_table.wast", _) | ("select.wast", _) => true,
+ _ => false,
+ },
+ );
+ }
+
+ #[test]
+ fn run_spec_tests() {
+ for entry in read_dir(SPEC_TESTS_PATH).unwrap() {
+ let dir = entry.unwrap();
+ if !dir.file_type().unwrap().is_file()
+ || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast")
+ {
+ continue;
+ }
+
+ let data = read(&dir.path()).expect("wast data");
+ run_wabt_scripts(
+ dir.file_name().to_str().expect("name"),
+ &data,
+ default_config(),
+ |_, _| false,
+ );
+ }
+ }
+}
diff --git a/third_party/rust/wasmparser-0.48.2/src/validator.rs b/third_party/rust/wasmparser-0.48.2/src/validator.rs
new file mode 100644
index 0000000000..2fae3112bd
--- /dev/null
+++ b/third_party/rust/wasmparser-0.48.2/src/validator.rs
@@ -0,0 +1,946 @@
+/* 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 std::collections::HashSet;
+use std::result;
+use std::str;
+
+use crate::limits::{
+ MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_GLOBALS, MAX_WASM_MEMORIES,
+ MAX_WASM_MEMORY_PAGES, MAX_WASM_TABLES, MAX_WASM_TYPES,
+};
+
+use crate::binary_reader::BinaryReader;
+
+use crate::primitives::{
+ BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryType,
+ Operator, ResizableLimits, Result, SectionCode, TableType, Type,
+};
+
+use crate::operators_validator::{
+ is_subtype_supertype, FunctionEnd, OperatorValidator, OperatorValidatorConfig,
+ DEFAULT_OPERATOR_VALIDATOR_CONFIG,
+};
+use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder};
+use crate::{ElemSectionEntryTable, ElementItem};
+use crate::{WasmFuncType, WasmGlobalType, WasmMemoryType, WasmModuleResources, WasmTableType};
+
+use crate::readers::FunctionBody;
+
+type ValidatorResult<'a, T> = result::Result<T, ParserState<'a>>;
+
+struct InitExpressionState {
+ ty: Type,
+ global_count: usize,
+ function_count: usize,
+ validated: bool,
+}
+
+#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+enum SectionOrderState {
+ Initial,
+ Type,
+ Import,
+ Function,
+ Table,
+ Memory,
+ Global,
+ Export,
+ Start,
+ Element,
+ DataCount,
+ Code,
+ Data,
+}
+
+impl SectionOrderState {
+ pub fn from_section_code(code: &SectionCode) -> Option<SectionOrderState> {
+ match *code {
+ SectionCode::Type => Some(SectionOrderState::Type),
+ SectionCode::Import => Some(SectionOrderState::Import),
+ SectionCode::Function => Some(SectionOrderState::Function),
+ SectionCode::Table => Some(SectionOrderState::Table),
+ SectionCode::Memory => Some(SectionOrderState::Memory),
+ SectionCode::Global => Some(SectionOrderState::Global),
+ SectionCode::Export => Some(SectionOrderState::Export),
+ SectionCode::Start => Some(SectionOrderState::Start),
+ SectionCode::Element => Some(SectionOrderState::Element),
+ SectionCode::Code => Some(SectionOrderState::Code),
+ SectionCode::Data => Some(SectionOrderState::Data),
+ SectionCode::DataCount => Some(SectionOrderState::DataCount),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct ValidatingParserConfig {
+ pub operator_config: OperatorValidatorConfig,
+}
+
+const DEFAULT_VALIDATING_PARSER_CONFIG: ValidatingParserConfig = ValidatingParserConfig {
+ operator_config: DEFAULT_OPERATOR_VALIDATOR_CONFIG,
+};
+
+struct ValidatingParserResources {
+ types: Vec<FuncType>,
+ tables: Vec<TableType>,
+ memories: Vec<MemoryType>,
+ globals: Vec<GlobalType>,
+ element_count: u32,
+ data_count: Option<u32>,
+ func_type_indices: Vec<u32>,
+}
+
+impl<'a> WasmModuleResources for ValidatingParserResources {
+ type FuncType = crate::FuncType;
+ type TableType = crate::TableType;
+ type MemoryType = crate::MemoryType;
+ type GlobalType = crate::GlobalType;
+
+ fn type_at(&self, at: u32) -> Option<&Self::FuncType> {
+ self.types.get(at as usize)
+ }
+
+ fn table_at(&self, at: u32) -> Option<&Self::TableType> {
+ self.tables.get(at as usize)
+ }
+
+ fn memory_at(&self, at: u32) -> Option<&Self::MemoryType> {
+ self.memories.get(at as usize)
+ }
+
+ fn global_at(&self, at: u32) -> Option<&Self::GlobalType> {
+ self.globals.get(at as usize)
+ }
+
+ fn func_type_id_at(&self, at: u32) -> Option<u32> {
+ self.func_type_indices.get(at as usize).copied()
+ }
+
+ fn element_count(&self) -> u32 {
+ self.element_count
+ }
+
+ fn data_count(&self) -> u32 {
+ self.data_count.unwrap_or(0)
+ }
+}
+
+pub struct ValidatingParser<'a> {
+ parser: Parser<'a>,
+ validation_error: Option<ParserState<'a>>,
+ read_position: Option<usize>,
+ section_order_state: SectionOrderState,
+ resources: ValidatingParserResources,
+ current_func_index: u32,
+ func_imports_count: u32,
+ init_expression_state: Option<InitExpressionState>,
+ data_found: u32,
+ exported_names: HashSet<String>,
+ current_operator_validator: Option<OperatorValidator>,
+ config: ValidatingParserConfig,
+}
+
+impl<'a> ValidatingParser<'a> {
+ pub fn new(bytes: &[u8], config: Option<ValidatingParserConfig>) -> ValidatingParser {
+ ValidatingParser {
+ parser: Parser::new(bytes),
+ validation_error: None,
+ read_position: None,
+ section_order_state: SectionOrderState::Initial,
+ resources: ValidatingParserResources {
+ types: Vec::new(),
+ tables: Vec::new(),
+ memories: Vec::new(),
+ globals: Vec::new(),
+ element_count: 0,
+ data_count: None,
+ func_type_indices: Vec::new(),
+ },
+ current_func_index: 0,
+ func_imports_count: 0,
+ current_operator_validator: None,
+ init_expression_state: None,
+ data_found: 0,
+ exported_names: HashSet::new(),
+ config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG),
+ }
+ }
+
+ pub fn get_resources(
+ &self,
+ ) -> &dyn WasmModuleResources<
+ FuncType = crate::FuncType,
+ TableType = crate::TableType,
+ MemoryType = crate::MemoryType,
+ GlobalType = crate::GlobalType,
+ > {
+ &self.resources
+ }
+
+ fn set_validation_error(&mut self, message: &'static str) {
+ self.validation_error = Some(ParserState::Error(BinaryReaderError {
+ message,
+ offset: self.read_position.unwrap(),
+ }))
+ }
+
+ fn create_error<T>(&self, message: &'static str) -> ValidatorResult<'a, T> {
+ Err(ParserState::Error(BinaryReaderError {
+ message,
+ offset: self.read_position.unwrap(),
+ }))
+ }
+
+ fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
+ match ty {
+ Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
+ Type::NullRef | Type::AnyFunc | Type::AnyRef => {
+ if !self.config.operator_config.enable_reference_types {
+ return self.create_error("reference types support is not enabled");
+ }
+ Ok(())
+ }
+ Type::V128 => {
+ if !self.config.operator_config.enable_simd {
+ return self.create_error("SIMD support is not enabled");
+ }
+ Ok(())
+ }
+ _ => self.create_error("invalid value type"),
+ }
+ }
+
+ fn check_value_types(&self, types: &[Type]) -> ValidatorResult<'a, ()> {
+ for ty in types {
+ self.check_value_type(*ty)?;
+ }
+ Ok(())
+ }
+
+ fn check_limits(&self, limits: &ResizableLimits) -> ValidatorResult<'a, ()> {
+ if limits.maximum.is_some() && limits.initial > limits.maximum.unwrap() {
+ return self.create_error("maximum limits less than initial");
+ }
+ Ok(())
+ }
+
+ fn check_func_type(&self, func_type: &FuncType) -> ValidatorResult<'a, ()> {
+ if let Type::Func = func_type.form {
+ self.check_value_types(&*func_type.params)?;
+ self.check_value_types(&*func_type.returns)?;
+ if !self.config.operator_config.enable_multi_value && func_type.returns.len() > 1 {
+ self.create_error("func type returns multiple values")
+ } else {
+ Ok(())
+ }
+ } else {
+ self.create_error("type signature is not a func")
+ }
+ }
+
+ fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> {
+ match table_type.element_type {
+ Type::AnyFunc => {}
+ _ => {
+ if !self.config.operator_config.enable_reference_types {
+ return self.create_error("element is not anyfunc");
+ }
+ }
+ }
+ self.check_limits(&table_type.limits)
+ }
+
+ fn check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()> {
+ self.check_limits(&memory_type.limits)?;
+ let initial = memory_type.limits.initial;
+ if initial as usize > MAX_WASM_MEMORY_PAGES {
+ return self.create_error("memory initial value exceeds limit");
+ }
+ let maximum = memory_type.limits.maximum;
+ if maximum.is_some() && maximum.unwrap() as usize > MAX_WASM_MEMORY_PAGES {
+ return self.create_error("memory maximum value exceeds limit");
+ }
+ Ok(())
+ }
+
+ fn check_global_type(&self, global_type: GlobalType) -> ValidatorResult<'a, ()> {
+ self.check_value_type(global_type.content_type)
+ }
+
+ fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> {
+ match *import_type {
+ ImportSectionEntryType::Function(type_index) => {
+ if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
+ return self.create_error("functions count out of bounds");
+ }
+ if type_index as usize >= self.resources.types.len() {
+ return self.create_error("type index out of bounds");
+ }
+ Ok(())
+ }
+ ImportSectionEntryType::Table(ref table_type) => {
+ if !self.config.operator_config.enable_reference_types
+ && self.resources.tables.len() >= MAX_WASM_TABLES
+ {
+ return self.create_error("tables count must be at most 1");
+ }
+ self.check_table_type(table_type)
+ }
+ ImportSectionEntryType::Memory(ref memory_type) => {
+ if self.resources.memories.len() >= MAX_WASM_MEMORIES {
+ return self.create_error("memory count must be at most 1");
+ }
+ self.check_memory_type(memory_type)
+ }
+ ImportSectionEntryType::Global(global_type) => {
+ if self.resources.globals.len() >= MAX_WASM_GLOBALS {
+ return self.create_error("functions count out of bounds");
+ }
+ self.check_global_type(global_type)
+ }
+ }
+ }
+
+ fn check_init_expression_operator(&self, operator: &Operator) -> ValidatorResult<'a, ()> {
+ let state = self.init_expression_state.as_ref().unwrap();
+ if state.validated {
+ return self.create_error("only one init_expr operator is expected");
+ }
+ let ty = match *operator {
+ Operator::I32Const { .. } => Type::I32,
+ Operator::I64Const { .. } => Type::I64,
+ Operator::F32Const { .. } => Type::F32,
+ Operator::F64Const { .. } => Type::F64,
+ Operator::RefNull => {
+ if !self.config.operator_config.enable_reference_types {
+ return self.create_error("reference types support is not enabled");
+ }
+ Type::NullRef
+ }
+ Operator::V128Const { .. } => {
+ if !self.config.operator_config.enable_simd {
+ return self.create_error("SIMD support is not enabled");
+ }
+ Type::V128
+ }
+ Operator::GlobalGet { global_index } => {
+ if global_index as usize >= state.global_count {
+ return self.create_error("init_expr global index out of bounds");
+ }
+ self.resources.globals[global_index as usize].content_type
+ }
+ Operator::RefFunc { function_index } => {
+ if function_index as usize >= state.function_count {
+ return self.create_error("init_expr function index out of bounds");
+ }
+ Type::AnyFunc
+ }
+ _ => return self.create_error("invalid init_expr operator"),
+ };
+ if !is_subtype_supertype(ty, state.ty) {
+ return self.create_error("invalid init_expr type");
+ }
+ Ok(())
+ }
+
+ fn check_export_entry(
+ &self,
+ field: &str,
+ kind: ExternalKind,
+ index: u32,
+ ) -> ValidatorResult<'a, ()> {
+ if self.exported_names.contains(field) {
+ return self.create_error("non-unique export name");
+ }
+ match kind {
+ ExternalKind::Function => {
+ if index as usize >= self.resources.func_type_indices.len() {
+ return self.create_error("exported function index out of bounds");
+ }
+ }
+ ExternalKind::Table => {
+ if index as usize >= self.resources.tables.len() {
+ return self.create_error("exported table index out of bounds");
+ }
+ }
+ ExternalKind::Memory => {
+ if index as usize >= self.resources.memories.len() {
+ return self.create_error("exported memory index out of bounds");
+ }
+ }
+ ExternalKind::Global => {
+ if index as usize >= self.resources.globals.len() {
+ return self.create_error("exported global index out of bounds");
+ }
+ }
+ };
+ Ok(())
+ }
+
+ fn check_start(&self, func_index: u32) -> ValidatorResult<'a, ()> {
+ if func_index as usize >= self.resources.func_type_indices.len() {
+ return self.create_error("start function index out of bounds");
+ }
+ let type_index = self.resources.func_type_indices[func_index as usize];
+ let ty = &self.resources.types[type_index as usize];
+ if !ty.params.is_empty() || !ty.returns.is_empty() {
+ return self.create_error("invlid start function type");
+ }
+ Ok(())
+ }
+
+ fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> {
+ let order_state = SectionOrderState::from_section_code(code);
+ Ok(match self.section_order_state {
+ SectionOrderState::Initial => match order_state {
+ Some(section) => section,
+ _ => SectionOrderState::Initial,
+ },
+ previous => {
+ if let Some(order_state_unwraped) = order_state {
+ if previous >= order_state_unwraped {
+ return self.create_error("section out of order");
+ }
+ order_state_unwraped
+ } else {
+ previous
+ }
+ }
+ })
+ }
+
+ fn process_state(&mut self) {
+ match *self.parser.last_state() {
+ ParserState::BeginWasm { version } => {
+ if version != 1 {
+ self.set_validation_error("bad wasm file version");
+ }
+ }
+ ParserState::BeginSection { ref code, .. } => {
+ let check = self.process_begin_section(code);
+ if check.is_err() {
+ self.validation_error = check.err();
+ } else {
+ self.section_order_state = check.ok().unwrap();
+ }
+ }
+ ParserState::TypeSectionEntry(ref func_type) => {
+ let check = self.check_func_type(func_type);
+ if check.is_err() {
+ self.validation_error = check.err();
+ } else if self.resources.types.len() > MAX_WASM_TYPES {
+ self.set_validation_error("types count is out of bounds");
+ } else {
+ self.resources.types.push(func_type.clone());
+ }
+ }
+ ParserState::ImportSectionEntry { ref ty, .. } => {
+ let check = self.check_import_entry(ty);
+ if check.is_err() {
+ self.validation_error = check.err();
+ } else {
+ match *ty {
+ ImportSectionEntryType::Function(type_index) => {
+ self.func_imports_count += 1;
+ self.resources.func_type_indices.push(type_index);
+ }
+ ImportSectionEntryType::Table(ref table_type) => {
+ self.resources.tables.push(table_type.clone());
+ }
+ ImportSectionEntryType::Memory(ref memory_type) => {
+ self.resources.memories.push(memory_type.clone());
+ }
+ ImportSectionEntryType::Global(ref global_type) => {
+ self.resources.globals.push(global_type.clone());
+ }
+ }
+ }
+ }
+ ParserState::FunctionSectionEntry(type_index) => {
+ if type_index as usize >= self.resources.types.len() {
+ self.set_validation_error("func type index out of bounds");
+ } else if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
+ self.set_validation_error("functions count out of bounds");
+ } else {
+ self.resources.func_type_indices.push(type_index);
+ }
+ }
+ ParserState::TableSectionEntry(ref table_type) => {
+ if !self.config.operator_config.enable_reference_types
+ && self.resources.tables.len() >= MAX_WASM_TABLES
+ {
+ self.set_validation_error("tables count must be at most 1");
+ } else {
+ self.validation_error = self.check_table_type(table_type).err();
+ self.resources.tables.push(table_type.clone());
+ }
+ }
+ ParserState::MemorySectionEntry(ref memory_type) => {
+ if self.resources.memories.len() >= MAX_WASM_MEMORIES {
+ self.set_validation_error("memories count must be at most 1");
+ } else {
+ self.validation_error = self.check_memory_type(memory_type).err();
+ self.resources.memories.push(memory_type.clone());
+ }
+ }
+ ParserState::BeginGlobalSectionEntry(global_type) => {
+ if self.resources.globals.len() >= MAX_WASM_GLOBALS {
+ self.set_validation_error("globals count out of bounds");
+ } else {
+ self.validation_error = self.check_global_type(global_type).err();
+ self.init_expression_state = Some(InitExpressionState {
+ ty: global_type.content_type,
+ global_count: self.resources.globals.len(),
+ function_count: self.resources.func_type_indices.len(),
+ validated: false,
+ });
+ self.resources.globals.push(global_type);
+ }
+ }
+ ParserState::BeginInitExpressionBody => {
+ assert!(self.init_expression_state.is_some());
+ }
+ ParserState::InitExpressionOperator(ref operator) => {
+ self.validation_error = self.check_init_expression_operator(operator).err();
+ self.init_expression_state.as_mut().unwrap().validated = true;
+ }
+ ParserState::EndInitExpressionBody => {
+ if !self.init_expression_state.as_ref().unwrap().validated {
+ self.set_validation_error("init_expr is empty");
+ }
+ self.init_expression_state = None;
+ }
+ ParserState::ExportSectionEntry { field, kind, index } => {
+ self.validation_error = self.check_export_entry(field, kind, index).err();
+ self.exported_names.insert(String::from(field));
+ }
+ ParserState::StartSectionEntry(func_index) => {
+ self.validation_error = self.check_start(func_index).err();
+ }
+ ParserState::DataCountSectionEntry(count) => {
+ self.resources.data_count = Some(count);
+ }
+ ParserState::BeginElementSectionEntry { table, ty } => {
+ self.resources.element_count += 1;
+ if let ElemSectionEntryTable::Active(table_index) = table {
+ let table = match self.resources.tables.get(table_index as usize) {
+ Some(t) => t,
+ None => {
+ self.set_validation_error("element section table index out of bounds");
+ return;
+ }
+ };
+ if !is_subtype_supertype(ty, table.element_type) {
+ self.set_validation_error("element_type != table type");
+ return;
+ }
+ if !self.config.operator_config.enable_reference_types && ty != Type::AnyFunc {
+ self.set_validation_error("element_type != anyfunc is not supported yet");
+ return;
+ }
+ self.init_expression_state = Some(InitExpressionState {
+ ty: Type::I32,
+ global_count: self.resources.globals.len(),
+ function_count: self.resources.func_type_indices.len(),
+ validated: false,
+ });
+ }
+ }
+ ParserState::ElementSectionEntryBody(ref indices) => {
+ for item in &**indices {
+ if let ElementItem::Func(func_index) = item {
+ if *func_index as usize >= self.resources.func_type_indices.len() {
+ self.set_validation_error("element func index out of bounds");
+ break;
+ }
+ }
+ }
+ }
+ ParserState::BeginFunctionBody { .. } => {
+ let index = (self.current_func_index + self.func_imports_count) as usize;
+ if index as usize >= self.resources.func_type_indices.len() {
+ self.set_validation_error("func type is not defined");
+ }
+ }
+ ParserState::FunctionBodyLocals { ref locals } => {
+ let index = (self.current_func_index + self.func_imports_count) as usize;
+ let func_type =
+ &self.resources.types[self.resources.func_type_indices[index] as usize];
+ let operator_config = self.config.operator_config;
+ self.current_operator_validator =
+ Some(OperatorValidator::new(func_type, locals, operator_config));
+ }
+ ParserState::CodeOperator(ref operator) => {
+ let check = self
+ .current_operator_validator
+ .as_mut()
+ .unwrap()
+ .process_operator(operator, &self.resources);
+
+ if let Err(err) = check {
+ self.set_validation_error(err);
+ }
+ }
+ ParserState::EndFunctionBody => {
+ let check = self
+ .current_operator_validator
+ .as_ref()
+ .unwrap()
+ .process_end_function();
+ if let Err(err) = check {
+ self.set_validation_error(err);
+ }
+ self.current_func_index += 1;
+ self.current_operator_validator = None;
+ }
+ ParserState::BeginDataSectionEntryBody(_) => {
+ self.data_found += 1;
+ }
+ ParserState::BeginActiveDataSectionEntry(memory_index) => {
+ if memory_index as usize >= self.resources.memories.len() {
+ self.set_validation_error("data section memory index out of bounds");
+ } else {
+ self.init_expression_state = Some(InitExpressionState {
+ ty: Type::I32,
+ global_count: self.resources.globals.len(),
+ function_count: self.resources.func_type_indices.len(),
+ validated: false,
+ });
+ }
+ }
+ ParserState::EndWasm => {
+ if self.resources.func_type_indices.len()
+ != self.current_func_index as usize + self.func_imports_count as usize
+ {
+ self.set_validation_error(
+ "function and code section have inconsistent lengths",
+ );
+ }
+ if let Some(data_count) = self.resources.data_count {
+ if data_count != self.data_found {
+ self.set_validation_error("data count section and passive data mismatch");
+ }
+ }
+ }
+ _ => (),
+ };
+ }
+
+ pub fn create_validating_operator_parser<'b>(&mut self) -> ValidatingOperatorParser<'b>
+ where
+ 'a: 'b,
+ {
+ let func_body_offset = match *self.last_state() {
+ ParserState::BeginFunctionBody { .. } => self.parser.current_position(),
+ _ => panic!("Invalid reader state"),
+ };
+ self.read();
+ let operator_validator = match *self.last_state() {
+ ParserState::FunctionBodyLocals { ref locals } => {
+ let index = (self.current_func_index + self.func_imports_count) as usize;
+ let func_type =
+ &self.resources.types[self.resources.func_type_indices[index] as usize];
+ let operator_config = self.config.operator_config;
+ OperatorValidator::new(func_type, locals, operator_config)
+ }
+ _ => panic!("Invalid reader state"),
+ };
+ let reader = self.create_binary_reader();
+ ValidatingOperatorParser::new(operator_validator, reader, func_body_offset)
+ }
+}
+
+impl<'a> WasmDecoder<'a> for ValidatingParser<'a> {
+ fn read(&mut self) -> &ParserState<'a> {
+ if self.validation_error.is_some() {
+ panic!("Parser in error state: validation");
+ }
+ self.read_position = Some(self.parser.current_position());
+ self.parser.read();
+ self.process_state();
+ self.last_state()
+ }
+
+ fn push_input(&mut self, input: ParserInput) {
+ match input {
+ ParserInput::SkipSection => panic!("Not supported"),
+ ParserInput::ReadSectionRawData => panic!("Not supported"),
+ ParserInput::SkipFunctionBody => {
+ self.current_func_index += 1;
+ self.parser.push_input(input);
+ }
+ _ => self.parser.push_input(input),
+ }
+ }
+
+ fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> {
+ self.push_input(input);
+ self.read()
+ }
+
+ fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
+ where
+ 'a: 'b,
+ {
+ if let ParserState::BeginSection { .. } = *self.parser.last_state() {
+ panic!("Not supported");
+ }
+ self.parser.create_binary_reader()
+ }
+
+ fn last_state(&self) -> &ParserState<'a> {
+ if self.validation_error.is_some() {
+ self.validation_error.as_ref().unwrap()
+ } else {
+ self.parser.last_state()
+ }
+ }
+}
+
+pub struct ValidatingOperatorParser<'b> {
+ operator_validator: OperatorValidator,
+ reader: BinaryReader<'b>,
+ func_body_offset: usize,
+ end_function: bool,
+}
+
+impl<'b> ValidatingOperatorParser<'b> {
+ pub(crate) fn new<'c>(
+ operator_validator: OperatorValidator,
+ reader: BinaryReader<'c>,
+ func_body_offset: usize,
+ ) -> ValidatingOperatorParser<'c>
+ where
+ 'b: 'c,
+ {
+ ValidatingOperatorParser {
+ operator_validator,
+ reader,
+ func_body_offset,
+ end_function: false,
+ }
+ }
+
+ pub fn eof(&self) -> bool {
+ self.end_function
+ }
+
+ pub fn current_position(&self) -> usize {
+ self.reader.current_position()
+ }
+
+ pub fn is_dead_code(&self) -> bool {
+ self.operator_validator.is_dead_code()
+ }
+
+ /// Creates a BinaryReader when current state is ParserState::BeginSection
+ /// or ParserState::BeginFunctionBody.
+ ///
+ /// # Examples
+ /// ```
+ /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80,
+ /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0,
+ /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83,
+ /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb];
+ /// use wasmparser::{WasmDecoder, ParserState, ValidatingParser};
+ /// let mut parser = ValidatingParser::new(data, None);
+ /// let mut i = 0;
+ /// loop {
+ /// {
+ /// match *parser.read() {
+ /// ParserState::Error(_) |
+ /// ParserState::EndWasm => break,
+ /// ParserState::BeginFunctionBody {..} => (),
+ /// _ => continue
+ /// }
+ /// }
+ /// let mut reader = parser.create_validating_operator_parser();
+ /// println!("Function {}", i);
+ /// i += 1;
+ /// while !reader.eof() {
+ /// let read = reader.next(parser.get_resources());
+ /// if let Ok(ref op) = read {
+ /// println!(" {:?}", op);
+ /// } else {
+ /// panic!(" Bad wasm code {:?}", read.err());
+ /// }
+ /// }
+ /// }
+ /// ```
+ pub fn next<'c, F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>(
+ &mut self,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ ) -> Result<Operator<'c>>
+ where
+ 'b: 'c,
+ {
+ let op = self.reader.read_operator()?;
+ match self.operator_validator.process_operator(&op, resources) {
+ Err(err) => {
+ return Err(BinaryReaderError {
+ message: err,
+ offset: self.func_body_offset + self.reader.current_position(),
+ });
+ }
+ Ok(FunctionEnd::Yes) => {
+ self.end_function = true;
+ if !self.reader.eof() {
+ return Err(BinaryReaderError {
+ message: "unexpected end of function",
+ offset: self.func_body_offset + self.reader.current_position(),
+ });
+ }
+ }
+ _ => (),
+ };
+ Ok(op)
+ }
+}
+
+/// Test whether the given buffer contains a valid WebAssembly function.
+/// The resources parameter contains all needed data to validate the operators.
+pub fn validate_function_body<
+ F: WasmFuncType,
+ T: WasmTableType,
+ M: WasmMemoryType,
+ G: WasmGlobalType,
+>(
+ bytes: &[u8],
+ offset: usize,
+ func_index: u32,
+ resources: &dyn WasmModuleResources<
+ FuncType = F,
+ TableType = T,
+ MemoryType = M,
+ GlobalType = G,
+ >,
+ operator_config: Option<OperatorValidatorConfig>,
+) -> Result<()> {
+ let operator_config = operator_config.unwrap_or(DEFAULT_OPERATOR_VALIDATOR_CONFIG);
+ let function_body = FunctionBody::new(offset, bytes);
+ let mut locals_reader = function_body.get_locals_reader()?;
+ let local_count = locals_reader.get_count() as usize;
+ if local_count > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "locals exceed maximum",
+ offset: locals_reader.original_position(),
+ });
+ }
+ let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
+ let mut locals_total: usize = 0;
+ for _ in 0..local_count {
+ let (count, ty) = locals_reader.read()?;
+ locals_total =
+ locals_total
+ .checked_add(count as usize)
+ .ok_or_else(|| BinaryReaderError {
+ message: "locals overflow",
+ offset: locals_reader.original_position(),
+ })?;
+ if locals_total > MAX_WASM_FUNCTION_LOCALS {
+ return Err(BinaryReaderError {
+ message: "locals exceed maximum",
+ offset: locals_reader.original_position(),
+ });
+ }
+ locals.push((count, ty));
+ }
+ let operators_reader = function_body.get_operators_reader()?;
+ let func_type_index = resources
+ .func_type_id_at(func_index)
+ // Note: This was an out-of-bounds access before the change to return `Option`
+ // so I assumed it is considered a bug to access a non-existing function
+ // id here and went with panicking instead of returning a proper error.
+ .expect("the function index of the validated function itself is out of bounds");
+ let func_type = resources
+ .type_at(func_type_index)
+ // Note: This was an out-of-bounds access before the change to return `Option`
+ // so I assumed it is considered a bug to access a non-existing function
+ // id here and went with panicking instead of returning a proper error.
+ .expect("the function type indexof the validated function itself is out of bounds");
+ let mut operator_validator = OperatorValidator::new(func_type, &locals, operator_config);
+ let mut eof_found = false;
+ let mut last_op = 0;
+ for item in operators_reader.into_iter_with_offsets() {
+ let (ref op, offset) = item?;
+ match operator_validator
+ .process_operator(op, resources)
+ .map_err(|message| BinaryReaderError { message, offset })?
+ {
+ FunctionEnd::Yes => {
+ eof_found = true;
+ }
+ FunctionEnd::No => {
+ last_op = offset;
+ }
+ }
+ }
+ if !eof_found {
+ return Err(BinaryReaderError {
+ message: "end of function not found",
+ offset: last_op,
+ });
+ }
+ Ok(())
+}
+
+/// Test whether the given buffer contains a valid WebAssembly module,
+/// analogous to WebAssembly.validate in the JS API.
+pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()> {
+ let mut parser = ValidatingParser::new(bytes, config);
+ let mut parser_input = None;
+ let mut func_ranges = Vec::new();
+ loop {
+ let next_input = parser_input.take().unwrap_or(ParserInput::Default);
+ let state = parser.read_with_input(next_input);
+ match *state {
+ ParserState::EndWasm => break,
+ ParserState::Error(e) => return Err(e),
+ ParserState::BeginFunctionBody { range } => {
+ parser_input = Some(ParserInput::SkipFunctionBody);
+ func_ranges.push(range);
+ }
+ _ => (),
+ }
+ }
+ let operator_config = config.map(|c| c.operator_config);
+ for (i, range) in func_ranges.into_iter().enumerate() {
+ let function_body = range.slice(bytes);
+ let function_index = i as u32 + parser.func_imports_count;
+ validate_function_body(
+ function_body,
+ range.start,
+ function_index,
+ &parser.resources,
+ operator_config,
+ )?;
+ }
+ Ok(())
+}
+
+#[test]
+fn test_validate() {
+ assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None).is_ok());
+ assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0], None).is_err());
+}