From 8afdf0558ae4256d9faf57dde6441b72a087be34 Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Thu, 20 Jun 2024 20:04:16 +0300 Subject: [PATCH] Add parsing methods (#1627) Co-authored-by: Alex Crichton --- crates/wasm-encoder/Cargo.toml | 3 + crates/wasm-encoder/src/core/code.rs | 181 +++++++++++++++++- crates/wasm-encoder/src/core/custom.rs | 10 + crates/wasm-encoder/src/core/data.rs | 32 ++++ crates/wasm-encoder/src/core/elements.rs | 48 +++++ crates/wasm-encoder/src/core/exports.rs | 20 ++ crates/wasm-encoder/src/core/functions.rs | 13 ++ crates/wasm-encoder/src/core/globals.rs | 24 +++ crates/wasm-encoder/src/core/imports.rs | 25 +++ crates/wasm-encoder/src/core/memories.rs | 14 ++ crates/wasm-encoder/src/core/tables.rs | 31 +++ crates/wasm-encoder/src/core/tags.rs | 14 ++ crates/wasm-encoder/src/core/types.rs | 25 +++ crates/wasm-encoder/src/lib.rs | 1 + crates/wasm-mutate/src/mutators/translate.rs | 8 - crates/wasm-smith/src/core.rs | 82 ++------ crates/wasm-smith/src/core/code_builder.rs | 8 +- crates/wasmparser/Cargo.toml | 3 + .../wasmparser/src/readers/core/operators.rs | 24 +++ crates/wit-component/src/encoding.rs | 4 +- crates/wit-component/src/gc.rs | 14 +- crates/wit-component/src/linking.rs | 4 +- 22 files changed, 478 insertions(+), 110 deletions(-) diff --git a/crates/wasm-encoder/Cargo.toml b/crates/wasm-encoder/Cargo.toml index 6a7478dfac..7472bd7b13 100644 --- a/crates/wasm-encoder/Cargo.toml +++ b/crates/wasm-encoder/Cargo.toml @@ -13,6 +13,9 @@ A low-level WebAssembly encoder. """ rust-version.workspace = true +[package.metadata.docs.rs] +all-features = true + [lints] workspace = true diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index e8887fb24a..25de73be66 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -103,6 +103,30 @@ impl CodeSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the code to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::CodeSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for code in section { + self.parse(code?)?; + } + Ok(self) + } + + /// Parses a single [`wasmparser::Code`] and adds it to this section. + #[cfg(feature = "wasmparser")] + pub fn parse(&mut self, func: wasmparser::FunctionBody<'_>) -> wasmparser::Result<&mut Self> { + let mut f = Function::new_parsed_locals(&func)?; + let mut reader = func.get_operators_reader()?; + while !reader.eof() { + f.parse(&mut reader)?; + } + Ok(self.function(&f)) + } } impl Encode for CodeSection { @@ -214,6 +238,18 @@ impl Function { Function::new(locals_collected) } + /// Create a new [`Function`] by parsing the locals declarations from the + /// provided [`wasmparser::FunctionBody`]. + #[cfg(feature = "wasmparser")] + pub fn new_parsed_locals(func: &wasmparser::FunctionBody<'_>) -> wasmparser::Result { + let mut locals = Vec::new(); + for pair in func.get_locals_reader()? { + let (cnt, ty) = pair?; + locals.push((cnt, ty.try_into().unwrap())); + } + Ok(Function::new(locals)) + } + /// Write an instruction into this function body. pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self { instruction.encode(&mut self.bytes); @@ -237,6 +273,15 @@ impl Function { pub fn byte_len(&self) -> usize { self.bytes.len() } + + /// Parses a single instruction from `reader` and adds it to `self`. + #[cfg(feature = "wasmparser")] + pub fn parse( + &mut self, + reader: &mut wasmparser::OperatorsReader<'_>, + ) -> wasmparser::Result<&mut Self> { + Ok(self.instruction(&reader.read()?.try_into().unwrap())) + } } impl Encode for Function { @@ -276,6 +321,17 @@ impl Encode for MemArg { } } +#[cfg(feature = "wasmparser")] +impl From for MemArg { + fn from(arg: wasmparser::MemArg) -> MemArg { + MemArg { + offset: arg.offset, + align: arg.align.into(), + memory_index: arg.memory, + } + } +} + /// The memory ordering for atomic instructions. /// /// For an in-depth explanation of memory orderings, see the C++ documentation @@ -304,6 +360,16 @@ impl Encode for Ordering { } } +#[cfg(feature = "wasmparser")] +impl From for Ordering { + fn from(arg: wasmparser::Ordering) -> Ordering { + match arg { + wasmparser::Ordering::SeqCst => Ordering::SeqCst, + wasmparser::Ordering::AcqRel => Ordering::AcqRel, + } + } +} + /// Describe an unchecked SIMD lane index. pub type Lane = u8; @@ -328,6 +394,18 @@ impl Encode for BlockType { } } +#[cfg(feature = "wasmparser")] +impl TryFrom for BlockType { + type Error = (); + fn try_from(arg: wasmparser::BlockType) -> Result { + match arg { + wasmparser::BlockType::Empty => Ok(BlockType::Empty), + wasmparser::BlockType::FuncType(n) => Ok(BlockType::FunctionType(n)), + wasmparser::BlockType::Type(t) => Ok(BlockType::Result(t.try_into()?)), + } + } +} + /// WebAssembly instructions. #[derive(Clone, Debug)] #[non_exhaustive] @@ -350,14 +428,14 @@ pub enum Instruction<'a> { Call(u32), CallRef(u32), CallIndirect { - ty: u32, - table: u32, + type_index: u32, + table_index: u32, }, ReturnCallRef(u32), ReturnCall(u32), ReturnCallIndirect { - ty: u32, - table: u32, + type_index: u32, + table_index: u32, }, TryTable(BlockType, Cow<'a, [Catch]>), Throw(u32), @@ -1119,10 +1197,13 @@ impl Encode for Instruction<'_> { sink.push(0x14); ty.encode(sink); } - Instruction::CallIndirect { ty, table } => { + Instruction::CallIndirect { + type_index, + table_index, + } => { sink.push(0x11); - ty.encode(sink); - table.encode(sink); + type_index.encode(sink); + table_index.encode(sink); } Instruction::ReturnCallRef(ty) => { sink.push(0x15); @@ -1133,10 +1214,13 @@ impl Encode for Instruction<'_> { sink.push(0x12); f.encode(sink); } - Instruction::ReturnCallIndirect { ty, table } => { + Instruction::ReturnCallIndirect { + type_index, + table_index, + } => { sink.push(0x13); - ty.encode(sink); - table.encode(sink); + type_index.encode(sink); + table_index.encode(sink); } Instruction::Delegate(l) => { sink.push(0x18); @@ -3278,6 +3362,64 @@ impl Encode for Instruction<'_> { } } +#[cfg(feature = "wasmparser")] +impl TryFrom> for Instruction<'_> { + type Error = (); + + fn try_from(arg: wasmparser::Operator<'_>) -> Result { + use Instruction::*; + + macro_rules! define_match { + ($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + match arg { + $( + wasmparser::Operator::$op $({ $($arg),* })? => { + $( + $(let $arg = define_match!(map $arg $arg);)* + )? + Ok(define_match!(mk $op $($($arg)*)?)) + } + )* + } + }; + + // No-payload instructions are named the same in wasmparser as they are in + // wasm-encoder + (mk $op:ident) => ($op); + + // Instructions which need "special care" to map from wasmparser to + // wasm-encoder + (mk BrTable $arg:ident) => ({BrTable($arg.0, $arg.1)}); + (mk TryTable $arg:ident) => ({TryTable($arg.0, $arg.1)}); + + // Catch-all for the translation of one payload argument which is typically + // represented as a tuple-enum in wasm-encoder. + (mk $op:ident $arg:ident) => ($op($arg)); + + // Catch-all of everything else where the wasmparser fields are simply + // translated to wasm-encoder fields. + (mk $op:ident $($arg:ident)*) => ($op { $($arg),* }); + + // Special-case BrTable/TryTable conversion of arguments. + (map $arg:ident targets) => (( + $arg.targets().map(|i| i.unwrap()).collect::>().into(), + $arg.default(), + )); + (map $arg:ident try_table) => (( + $arg.ty.try_into().unwrap(), + $arg.catches.into_iter().map(|i| i.into()).collect::>().into(), + )); + + // Everything else is converted with `TryFrom`/`From`. Note that the + // fallibility here has to do with how indexes are represented in + // `wasmparser` which we know when reading directly we'll never hit the + // erroneous cases here, hence the unwrap. + (map $arg:ident $other:ident) => {$other.try_into().unwrap()}; + } + wasmparser::for_each_operator!(define_match) + } +} + #[derive(Clone, Debug)] #[allow(missing_docs)] pub enum Catch { @@ -3312,6 +3454,18 @@ impl Encode for Catch { } } +#[cfg(feature = "wasmparser")] +impl From for Catch { + fn from(arg: wasmparser::Catch) -> Catch { + match arg { + wasmparser::Catch::One { tag, label } => Catch::One { tag, label }, + wasmparser::Catch::OneRef { tag, label } => Catch::OneRef { tag, label }, + wasmparser::Catch::All { label } => Catch::All { label }, + wasmparser::Catch::AllRef { label } => Catch::AllRef { label }, + } + } +} + /// A constant expression. /// /// Usable in contexts such as offsets or initializers. @@ -3494,6 +3648,13 @@ pub enum ConstExprConversionError { CanonicalizedTypeReference, } +#[cfg(feature = "wasmparser")] +impl From for ConstExprConversionError { + fn from(err: wasmparser::BinaryReaderError) -> ConstExprConversionError { + ConstExprConversionError::ParseError(err) + } +} + #[cfg(feature = "wasmparser")] impl std::fmt::Display for ConstExprConversionError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/wasm-encoder/src/core/custom.rs b/crates/wasm-encoder/src/core/custom.rs index 870ee62617..75cae490c5 100644 --- a/crates/wasm-encoder/src/core/custom.rs +++ b/crates/wasm-encoder/src/core/custom.rs @@ -44,6 +44,16 @@ impl Section for RawCustomSection<'_> { } } +#[cfg(feature = "wasmparser")] +impl<'a> From> for CustomSection<'a> { + fn from(section: wasmparser::CustomSectionReader<'a>) -> Self { + CustomSection { + data: section.data().into(), + name: section.name().into(), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/wasm-encoder/src/core/data.rs b/crates/wasm-encoder/src/core/data.rs index 6f408befe5..7f8dd795d1 100644 --- a/crates/wasm-encoder/src/core/data.rs +++ b/crates/wasm-encoder/src/core/data.rs @@ -151,6 +151,38 @@ impl DataSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the data to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::DataSectionReader<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + for data in section { + self.parse(data?)?; + } + Ok(self) + } + + /// Parses a single [`wasmparser::Data`] and adds it to this section. + #[cfg(feature = "wasmparser")] + pub fn parse( + &mut self, + data: wasmparser::Data<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + match data.kind { + wasmparser::DataKind::Active { + memory_index, + offset_expr, + } => Ok(self.active( + memory_index, + &ConstExpr::try_from(offset_expr)?, + data.data.iter().copied(), + )), + wasmparser::DataKind::Passive => Ok(self.passive(data.data.iter().copied())), + } + } } impl Encode for DataSection { diff --git a/crates/wasm-encoder/src/core/elements.rs b/crates/wasm-encoder/src/core/elements.rs index 28a1031ed8..8d24c4e363 100644 --- a/crates/wasm-encoder/src/core/elements.rs +++ b/crates/wasm-encoder/src/core/elements.rs @@ -206,6 +206,54 @@ impl ElementSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the elements to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::ElementSectionReader<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + for element in section { + self.parse(element?)?; + } + Ok(self) + } + + /// Parses the single [`wasmparser::Element`] provided and adds it to this + /// section. + #[cfg(feature = "wasmparser")] + pub fn parse( + &mut self, + element: wasmparser::Element<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + let mut funcs; + let mut exprs; + let elements = match element.items { + wasmparser::ElementItems::Functions(f) => { + funcs = Vec::new(); + for func in f { + funcs.push(func?); + } + Elements::Functions(&funcs) + } + wasmparser::ElementItems::Expressions(ty, e) => { + exprs = Vec::new(); + for expr in e { + exprs.push(ConstExpr::try_from(expr?)?); + } + Elements::Expressions(ty.try_into().unwrap(), &exprs) + } + }; + match element.kind { + wasmparser::ElementKind::Active { + table_index, + offset_expr, + } => Ok(self.active(table_index, &ConstExpr::try_from(offset_expr)?, elements)), + wasmparser::ElementKind::Passive => Ok(self.passive(elements)), + wasmparser::ElementKind::Declared => Ok(self.declared(elements)), + } + } } impl Encode for ElementSection { diff --git a/crates/wasm-encoder/src/core/exports.rs b/crates/wasm-encoder/src/core/exports.rs index fc2dc9c392..7b06fabc06 100644 --- a/crates/wasm-encoder/src/core/exports.rs +++ b/crates/wasm-encoder/src/core/exports.rs @@ -83,6 +83,26 @@ impl ExportSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the exports to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::ExportSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for export in section { + self.parse(export?); + } + Ok(self) + } + + /// Parses the single [`wasmparser::Export`] provided and adds it to this + /// section. + #[cfg(feature = "wasmparser")] + pub fn parse(&mut self, export: wasmparser::Export<'_>) -> &mut Self { + self.export(export.name, export.kind.into(), export.index) + } } impl Encode for ExportSection { diff --git a/crates/wasm-encoder/src/core/functions.rs b/crates/wasm-encoder/src/core/functions.rs index e21d8c10a7..3cc053ba5b 100644 --- a/crates/wasm-encoder/src/core/functions.rs +++ b/crates/wasm-encoder/src/core/functions.rs @@ -48,6 +48,19 @@ impl FunctionSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the functions to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::FunctionSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for func in section { + self.function(func?); + } + Ok(self) + } } impl Encode for FunctionSection { diff --git a/crates/wasm-encoder/src/core/globals.rs b/crates/wasm-encoder/src/core/globals.rs index 291ca80472..f208f63f1f 100644 --- a/crates/wasm-encoder/src/core/globals.rs +++ b/crates/wasm-encoder/src/core/globals.rs @@ -60,6 +60,30 @@ impl GlobalSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the globals to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::GlobalSectionReader<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + for global in section { + self.parse(global?)?; + } + Ok(self) + } + + /// Parses the single [`wasmparser::Global`] provided and adds it to this + /// section. + #[cfg(feature = "wasmparser")] + pub fn parse( + &mut self, + global: wasmparser::Global<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + self.global(global.ty.try_into().unwrap(), &global.init_expr.try_into()?); + Ok(self) + } } impl Encode for GlobalSection { diff --git a/crates/wasm-encoder/src/core/imports.rs b/crates/wasm-encoder/src/core/imports.rs index d4db2e65c5..5eac839cde 100644 --- a/crates/wasm-encoder/src/core/imports.rs +++ b/crates/wasm-encoder/src/core/imports.rs @@ -142,6 +142,31 @@ impl ImportSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the imports to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::ImportSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for import in section { + self.parse(import?); + } + Ok(self) + } + + /// Parses the single [`wasmparser::Import`] provided and adds it to this + /// section. + #[cfg(feature = "wasmparser")] + pub fn parse(&mut self, import: wasmparser::Import<'_>) -> &mut Self { + self.import( + import.module, + import.name, + EntityType::try_from(import.ty).unwrap(), + ); + self + } } impl Encode for ImportSection { diff --git a/crates/wasm-encoder/src/core/memories.rs b/crates/wasm-encoder/src/core/memories.rs index d64ef01210..b3942dfa09 100644 --- a/crates/wasm-encoder/src/core/memories.rs +++ b/crates/wasm-encoder/src/core/memories.rs @@ -51,6 +51,20 @@ impl MemorySection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the memories to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::MemorySectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for memory in section { + let memory = memory?; + self.memory(memory.into()); + } + Ok(self) + } } impl Encode for MemorySection { diff --git a/crates/wasm-encoder/src/core/tables.rs b/crates/wasm-encoder/src/core/tables.rs index 7467f5f7e7..24bfe03a0e 100644 --- a/crates/wasm-encoder/src/core/tables.rs +++ b/crates/wasm-encoder/src/core/tables.rs @@ -62,6 +62,37 @@ impl TableSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the tables to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::TableSectionReader<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + for table in section { + self.parse(table?)?; + } + Ok(self) + } + + /// Parses a single [`wasmparser::Table`] and adds it to this section. + #[cfg(feature = "wasmparser")] + pub fn parse( + &mut self, + table: wasmparser::Table<'_>, + ) -> Result<&mut Self, crate::ConstExprConversionError> { + let ty = table.ty.try_into().unwrap(); + match table.init { + wasmparser::TableInit::RefNull => { + self.table(ty); + } + wasmparser::TableInit::Expr(e) => { + self.table_with_init(ty, &e.try_into()?); + } + } + Ok(self) + } } impl Encode for TableSection { diff --git a/crates/wasm-encoder/src/core/tags.rs b/crates/wasm-encoder/src/core/tags.rs index 9b4c728a8c..2d6a88d995 100644 --- a/crates/wasm-encoder/src/core/tags.rs +++ b/crates/wasm-encoder/src/core/tags.rs @@ -46,6 +46,20 @@ impl TagSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the tags to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::TagSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for tag in section { + let tag = tag?; + self.tag(tag.into()); + } + Ok(self) + } } impl Encode for TagSection { diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 0fa12f68fc..0f53326b08 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -757,6 +757,31 @@ impl TypeSection { self.num_added += 1; self } + + /// Parses the input `section` given from the `wasmparser` crate and adds + /// all the types to this section. + #[cfg(feature = "wasmparser")] + pub fn parse_section( + &mut self, + section: wasmparser::TypeSectionReader<'_>, + ) -> wasmparser::Result<&mut Self> { + for rec_group in section { + self.parse(rec_group?); + } + Ok(self) + } + + /// Parses a single [`wasmparser::RecGroup`] and adds it to this section. + #[cfg(feature = "wasmparser")] + pub fn parse(&mut self, rec_group: wasmparser::RecGroup) -> &mut Self { + if rec_group.is_explicit_rec_group() { + self.rec(rec_group.into_types().map(|t| t.try_into().unwrap())); + } else { + let ty = rec_group.into_types().next().unwrap(); + self.subtype(&SubType::try_from(ty).unwrap()); + } + self + } } impl Encode for TypeSection { diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index 930c63ec9d..ae30a643dd 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -68,6 +68,7 @@ //! assert!(wasmparser::validate(&wasm_bytes).is_ok()); //! ``` +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![deny(missing_docs, missing_debug_implementations)] mod component; diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index 839879bc71..706e7629ad 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -399,14 +399,6 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result (I::V128Const($arg.i128())); (build TryTable $table:ident) => (unimplemented_try_table()); (build $op:ident $arg:ident) => (I::$op($arg)); - (build CallIndirect $ty:ident $table:ident) => (I::CallIndirect { - ty: $ty, - table: $table, - }); - (build ReturnCallIndirect $ty:ident $table:ident) => (I::ReturnCallIndirect { - ty: $ty, - table: $table, - }); (build $op:ident $($arg:ident)*) => (I::$op { $($arg),* }); } diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index 29514f7ac0..096a1ef7eb 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -1673,59 +1673,6 @@ impl Module { #[cfg(feature = "wasmparser")] fn _required_exports(&mut self, u: &mut Unstructured, example_module: &[u8]) -> Result<()> { - fn convert_heap_type(ty: &wasmparser::HeapType) -> HeapType { - use wasmparser::AbstractHeapType::*; - match ty { - wasmparser::HeapType::Concrete(_) => { - panic!("Unable to handle concrete types in exports") - } - wasmparser::HeapType::Abstract { shared, ty } => { - let ty = match ty { - Func => AbstractHeapType::Func, - Extern => AbstractHeapType::Extern, - Any => AbstractHeapType::Any, - None => AbstractHeapType::None, - NoExtern => AbstractHeapType::NoExtern, - NoFunc => AbstractHeapType::NoFunc, - Eq => AbstractHeapType::Eq, - Struct => AbstractHeapType::Struct, - Array => AbstractHeapType::Array, - I31 => AbstractHeapType::I31, - Exn => AbstractHeapType::Exn, - NoExn => AbstractHeapType::NoExn, - }; - HeapType::Abstract { - shared: *shared, - ty, - } - } - } - } - - fn convert_val_type(ty: &wasmparser::ValType) -> ValType { - match ty { - wasmparser::ValType::I32 => ValType::I32, - wasmparser::ValType::I64 => ValType::I64, - wasmparser::ValType::F32 => ValType::F32, - wasmparser::ValType::F64 => ValType::F64, - wasmparser::ValType::V128 => ValType::V128, - wasmparser::ValType::Ref(r) => ValType::Ref(RefType { - nullable: r.is_nullable(), - heap_type: convert_heap_type(&r.heap_type()), - }), - } - } - - fn convert_export_kind(kind: &wasmparser::ExternalKind) -> ExportKind { - match kind { - wasmparser::ExternalKind::Func => ExportKind::Func, - wasmparser::ExternalKind::Table => ExportKind::Table, - wasmparser::ExternalKind::Memory => ExportKind::Memory, - wasmparser::ExternalKind::Global => ExportKind::Global, - wasmparser::ExternalKind::Tag => ExportKind::Tag, - } - } - let mut required_exports: Vec = vec![]; let mut validator = wasmparser::Validator::new(); let exports_types = validator @@ -1776,13 +1723,15 @@ impl Module { let new_type = Rc::new(FuncType { params: func_type .params() - .into_iter() - .map(convert_val_type) + .iter() + .copied() + .map(|t| t.try_into().unwrap()) .collect(), results: func_type .results() - .into_iter() - .map(convert_val_type) + .iter() + .copied() + .map(|t| t.try_into().unwrap()) .collect(), }); self.rec_groups.push(self.types.len()..self.types.len() + 1); @@ -1803,15 +1752,9 @@ impl Module { } } // For globals, add a new global. - wasmparser::types::EntityType::Global(global_type) => self - .add_arbitrary_global_of_type( - GlobalType { - val_type: convert_val_type(&global_type.content_type), - mutable: global_type.mutable, - shared: global_type.shared, - }, - u, - )?, + wasmparser::types::EntityType::Global(global_type) => { + self.add_arbitrary_global_of_type(global_type.try_into().unwrap(), u)? + } wasmparser::types::EntityType::Table(_) | wasmparser::types::EntityType::Memory(_) | wasmparser::types::EntityType::Tag(_) => { @@ -1821,11 +1764,8 @@ impl Module { ) } }; - self.exports.push(( - export.name.to_string(), - convert_export_kind(&export.kind), - new_index, - )); + self.exports + .push((export.name.to_string(), export.kind.into(), new_index)); self.export_names.insert(export.name.to_string()); } diff --git a/crates/wasm-smith/src/core/code_builder.rs b/crates/wasm-smith/src/core/code_builder.rs index d93ce0c012..97fdaa36f2 100644 --- a/crates/wasm-smith/src/core/code_builder.rs +++ b/crates/wasm-smith/src/core/code_builder.rs @@ -2091,8 +2091,8 @@ fn call_indirect( builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); instructions.push(Instruction::CallIndirect { - ty: *type_idx as u32, - table, + type_index: *type_idx as u32, + table_index: table, }); Ok(()) } @@ -2228,8 +2228,8 @@ fn return_call_indirect( builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); instructions.push(Instruction::ReturnCallIndirect { - ty: *type_idx as u32, - table, + type_index: *type_idx as u32, + table_index: table, }); Ok(()) } diff --git a/crates/wasmparser/Cargo.toml b/crates/wasmparser/Cargo.toml index d65cd46767..117681d72e 100644 --- a/crates/wasmparser/Cargo.toml +++ b/crates/wasmparser/Cargo.toml @@ -16,6 +16,9 @@ rust-version.workspace = true [lints] workspace = true +[package.metadata.docs.rs] +all-features = true + [dependencies] bitflags = "2.4.1" indexmap = { workspace = true, optional = true } diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 69f8baec40..ff3ef8430a 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -78,6 +78,12 @@ impl Ieee32 { } } +impl From for f32 { + fn from(bits: Ieee32) -> f32 { + f32::from_bits(bits.bits()) + } +} + /// An IEEE binary64 immediate floating point value, represented as a u64 /// containing the bit pattern. /// @@ -92,6 +98,12 @@ impl Ieee64 { } } +impl From for f64 { + fn from(bits: Ieee64) -> f64 { + f64::from_bits(bits.bits()) + } +} + /// Represents a 128-bit vector value. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct V128(pub(crate) [u8; 16]); @@ -108,6 +120,18 @@ impl V128 { } } +impl From for i128 { + fn from(bits: V128) -> i128 { + bits.i128() + } +} + +impl From for u128 { + fn from(bits: V128) -> u128 { + u128::from_le_bytes(bits.0) + } +} + /// Represents the memory ordering for atomic instructions. /// /// For an in-depth explanation of memory orderings, see the C++ documentation diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 56eecf06a4..f045cb8366 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -1334,8 +1334,8 @@ impl<'a> EncodingState<'a> { } func.instruction(&Instruction::I32Const(func_index as i32)); func.instruction(&Instruction::CallIndirect { - ty: type_index, - table: 0, + type_index, + table_index: 0, }); func.instruction(&Instruction::End); code.function(&func); diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs index bb857f94e2..0fa13d85f4 100644 --- a/crates/wit-component/src/gc.rs +++ b/crates/wit-component/src/gc.rs @@ -568,13 +568,7 @@ impl<'a> Module<'a> { let mut num_memories = 0; for (i, mem) in self.live_memories() { map.memories.push(i); - let ty = wasm_encoder::MemoryType { - minimum: mem.ty.initial, - maximum: mem.ty.maximum, - shared: mem.ty.shared, - memory64: mem.ty.memory64, - page_size_log2: mem.ty.page_size_log2, - }; + let ty = mem.ty.into(); match &mem.def { Definition::Import(m, n) => { imports.import(m, n, ty); @@ -1165,12 +1159,6 @@ macro_rules! define_encode { (mk BrTable $arg:ident) => ({ BrTable($arg.0, $arg.1) }); - (mk CallIndirect $ty:ident $table:ident) => ({ - CallIndirect { ty: $ty, table: $table } - }); - (mk ReturnCallIndirect $ty:ident $table:ident) => ( - ReturnCallIndirect { ty: $ty, table: $table } - ); (mk TryTable $try_table:ident) => ({ let _ = $try_table; unimplemented_try_table() diff --git a/crates/wit-component/src/linking.rs b/crates/wit-component/src/linking.rs index e3923c1e3c..855fc0f3a6 100644 --- a/crates/wit-component/src/linking.rs +++ b/crates/wit-component/src/linking.rs @@ -434,8 +434,8 @@ fn make_env_module<'a>( } function.instruction(&Ins::I32Const(i32::try_from(table_offset).unwrap())); function.instruction(&Ins::CallIndirect { - ty: u32::try_from(index).unwrap(), - table: 0, + type_index: u32::try_from(index).unwrap(), + table_index: 0, }); function.instruction(&Ins::End); code.function(&function);