diff --git a/crates/wasm-mutate/src/info.rs b/crates/wasm-mutate/src/info.rs index 51120ff64b..515ae95f22 100644 --- a/crates/wasm-mutate/src/info.rs +++ b/crates/wasm-mutate/src/info.rs @@ -250,6 +250,10 @@ impl<'a> ModuleInfo<'a> { self.raw_sections[self.exports.unwrap()] } + pub fn get_data_section(&self) -> RawSection<'a> { + self.raw_sections[self.data.unwrap()] + } + pub fn has_exports(&self) -> bool { self.exports != None } diff --git a/crates/wasm-mutate/src/lib.rs b/crates/wasm-mutate/src/lib.rs index a702b3485a..1374cadb45 100644 --- a/crates/wasm-mutate/src/lib.rs +++ b/crates/wasm-mutate/src/lib.rs @@ -17,14 +17,10 @@ mod mutators; pub use error::*; use crate::mutators::{ - codemotion::CodemotionMutator, - custom::RemoveCustomSection, - function_body_unreachable::FunctionBodyUnreachable, - peephole::PeepholeMutator, - remove_export::RemoveExportMutator, - remove_item::{Item, RemoveItemMutator}, - rename_export::RenameExportMutator, - snip_function::SnipMutator, + codemotion::CodemotionMutator, custom::RemoveCustomSection, + function_body_unreachable::FunctionBodyUnreachable, modify_data::ModifyDataMutator, + peephole::PeepholeMutator, remove_export::RemoveExportMutator, remove_item::RemoveItemMutator, + rename_export::RenameExportMutator, snip_function::SnipMutator, Item, }; use info::ModuleInfo; use mutators::Mutator; @@ -173,7 +169,7 @@ pub struct WasmMutate<'wasm> { // Note: this is only exposed via the programmatic interface, not via the // CLI. #[cfg_attr(feature = "clap", clap(skip = None))] - raw_mutate_func: Option) -> Result<()>>>, + raw_mutate_func: Option, usize) -> Result<()>>>, #[cfg_attr(feature = "clap", clap(skip = None))] rng: Option, @@ -239,7 +235,7 @@ impl<'wasm> WasmMutate<'wasm> { /// to get raw bytes from `libFuzzer`, for example. pub fn raw_mutate_func( &mut self, - raw_mutate_func: Option) -> Result<()>>>, + raw_mutate_func: Option, usize) -> Result<()>>>, ) -> &mut Self { self.raw_mutate_func = raw_mutate_func; self @@ -259,8 +255,7 @@ impl<'wasm> WasmMutate<'wasm> { &'a mut self, input_wasm: &'wasm [u8], ) -> Result>> + 'a>> { - self.info = Some(ModuleInfo::new(input_wasm)?); - self.rng = Some(SmallRng::seed_from_u64(self.seed)); + self.setup(input_wasm)?; // This macro just expands the logic to return an iterator form the // mutators @@ -287,12 +282,21 @@ impl<'wasm> WasmMutate<'wasm> { RemoveItemMutator(Item::Data), RemoveItemMutator(Item::Element), RemoveItemMutator(Item::Tag), + ModifyDataMutator { + max_data_size: 10 << 20, // 10MB + }, ) ); Err(Error::no_mutations_applicable()) } + fn setup(&mut self, input_wasm: &'wasm [u8]) -> Result<()> { + self.info = Some(ModuleInfo::new(input_wasm)?); + self.rng = Some(SmallRng::seed_from_u64(self.seed)); + Ok(()) + } + pub(crate) fn rng(&mut self) -> &mut SmallRng { self.rng.as_mut().unwrap() } @@ -300,6 +304,46 @@ impl<'wasm> WasmMutate<'wasm> { pub(crate) fn info(&self) -> &ModuleInfo<'wasm> { self.info.as_ref().unwrap() } + + fn raw_mutate(&mut self, data: &mut Vec, max_size: usize) -> Result<()> { + // If a raw mutation function is configured then that's prioritized. + if let Some(mutate) = &self.raw_mutate_func { + return mutate(data, max_size); + } + + // If no raw mutation function is configured then we apply a naive + // default heuristic. For now that heuristic is to simply replace a + // subslice of data with a random slice of other data. + // + // First up start/end indices are picked. + let a = self.rng().gen_range(0, data.len() + 1); + let b = self.rng().gen_range(0, data.len() + 1); + let start = a.min(b); + let end = a.max(b); + + // Next a length of the replacement is chosen. Note that the replacement + // is always smaller than the input if reduction is requested, otherwise + // we choose some arbitrary length of bytes to insert. + let max_size = if self.reduce || self.rng().gen() { + 0 + } else { + max_size + }; + let len = self + .rng() + .gen_range(0, end - start + max_size.saturating_sub(data.len()) + 1); + + // With parameters chosen the `Vec::splice` method is used to replace + // the data in the input. + data.splice( + start..end, + self.rng() + .sample_iter(rand::distributions::Standard) + .take(len), + ); + + Ok(()) + } } #[cfg(test)] diff --git a/crates/wasm-mutate/src/mutators.rs b/crates/wasm-mutate/src/mutators.rs index 71d132de13..50ccc94ab8 100644 --- a/crates/wasm-mutate/src/mutators.rs +++ b/crates/wasm-mutate/src/mutators.rs @@ -23,6 +23,7 @@ pub mod codemotion; pub mod custom; pub mod function_body_unreachable; +pub mod modify_data; pub mod peephole; pub mod remove_export; pub mod remove_item; @@ -30,6 +31,10 @@ pub mod rename_export; pub mod snip_function; pub mod start; +mod translate; +pub use self::translate::Item; +use self::translate::{DefaultTranslator, Translator}; + use std::borrow::Cow; use super::Result; @@ -100,60 +105,65 @@ pub trait Mutator { pub type OperatorAndByteOffset<'a> = (Operator<'a>, usize); #[cfg(test)] -pub(crate) fn match_mutation(original: &str, mutator: T, expected: &str) +fn match_mutation(original: &str, mutator: T, expected: &str) where T: Mutator + Copy, { - use crate::info::ModuleInfo; - use crate::ErrorKind; - use rand::{prelude::SmallRng, SeedableRng}; - use wasmparser::WasmFeatures; - - let mut wasmmutate = WasmMutate::default(); - let original = &wat::parse_str(original).unwrap(); - - let expected = &wat::parse_str(expected).unwrap(); - let expected_text = wasmprinter::print_bytes(expected).unwrap(); - - let info = ModuleInfo::new(original).unwrap(); - wasmmutate.info = Some(info); - let rnd = SmallRng::seed_from_u64(0); - wasmmutate.rng = Some(rnd); - - let can_mutate = mutator.can_mutate(&wasmmutate); - - assert!(can_mutate); - - let attempts = 100; - - for _ in 0..attempts { - let mutation = match mutator - .mutate(&mut wasmmutate) - .and_then(|mut mutation| mutation.next().unwrap()) - { - Ok(mutation) => mutation, - Err(e) if matches!(e.kind(), ErrorKind::NoMutationsApplicable) => continue, - Err(e) => panic!("mutation error: {}", e), - }; - - let mutation_bytes = mutation.finish(); - - let mut validator = wasmparser::Validator::new(); - validator.wasm_features(WasmFeatures { - multi_memory: true, - ..WasmFeatures::default() - }); - crate::validate(&mut validator, &mutation_bytes); - - // If it fails, it is probably an invalid - // reformatting expected - let text = wasmprinter::print_bytes(mutation_bytes).unwrap(); - assert_eq!(text.trim(), expected_text.trim()); - return; - } + WasmMutate::default().match_mutation(original, mutator, expected) +} - panic!( - "never found any applicable mutations after {} attempts", - attempts - ); +impl WasmMutate<'_> { + #[cfg(test)] + fn match_mutation(&mut self, original: &str, mutator: T, expected: &str) + where + T: Mutator + Copy, + { + use crate::ErrorKind; + use wasmparser::WasmFeatures; + + let original = &wat::parse_str(original).unwrap(); + + let expected = &wat::parse_str(expected).unwrap(); + let expected_text = wasmprinter::print_bytes(expected).unwrap(); + + let mut config = self.clone(); + config.setup(&original).unwrap(); + + let can_mutate = mutator.can_mutate(&config); + + assert!(can_mutate); + + let attempts = 100; + + for _ in 0..attempts { + let mutation = match mutator + .mutate(&mut config) + .and_then(|mut mutation| mutation.next().unwrap()) + { + Ok(mutation) => mutation, + Err(e) if matches!(e.kind(), ErrorKind::NoMutationsApplicable) => continue, + Err(e) => panic!("mutation error: {}", e), + }; + + let mutation_bytes = mutation.finish(); + + let mut validator = wasmparser::Validator::new(); + validator.wasm_features(WasmFeatures { + multi_memory: true, + ..WasmFeatures::default() + }); + crate::validate(&mut validator, &mutation_bytes); + + // If it fails, it is probably an invalid + // reformatting expected + let text = wasmprinter::print_bytes(mutation_bytes).unwrap(); + assert_eq!(text.trim(), expected_text.trim()); + return; + } + + panic!( + "never found any applicable mutations after {} attempts", + attempts + ); + } } diff --git a/crates/wasm-mutate/src/mutators/modify_data.rs b/crates/wasm-mutate/src/mutators/modify_data.rs new file mode 100644 index 0000000000..050a61a8a1 --- /dev/null +++ b/crates/wasm-mutate/src/mutators/modify_data.rs @@ -0,0 +1,89 @@ +use super::Mutator; +use crate::{Result, WasmMutate}; + +use crate::mutators::{DefaultTranslator, Translator}; +use rand::Rng; +use wasm_encoder::{DataSection, DataSegment, DataSegmentMode, Module}; +use wasmparser::{DataKind, DataSectionReader}; + +/// Mutator that modifies a data segment, either adding or removing bytes. +#[derive(Clone, Copy)] +pub struct ModifyDataMutator { + pub max_data_size: usize, +} + +impl Mutator for ModifyDataMutator { + fn mutate<'a>( + self, + config: &'a mut WasmMutate, + ) -> Result> + 'a>> { + let mut new_section = DataSection::new(); + let mut reader = DataSectionReader::new(config.info().get_data_section().data, 0)?; + + // Select an arbitrary data segment to modify. + let data_to_modify = config.rng().gen_range(0, reader.get_count()); + + // Iterate over all data segments in the old data section and re-add + // them to the `new_section` one-by-one. + for i in 0..reader.get_count() { + let data = reader.read()?; + let offset; + // Preserve the mode of the data segment + let mode = match &data.kind { + DataKind::Active { + memory_index, + init_expr, + } => { + offset = DefaultTranslator.translate_init_expr(init_expr)?; + DataSegmentMode::Active { + memory_index: *memory_index, + offset: &offset, + } + } + DataKind::Passive => DataSegmentMode::Passive, + }; + // If this is the correct data segment apply the mutation, + // otherwise preserve the data. + let mut data = data.data.to_vec(); + if i == data_to_modify { + config.raw_mutate(&mut data, self.max_data_size)?; + } + new_section.segment(DataSegment { mode, data }); + } + + Ok(Box::new(std::iter::once(Ok(config + .info() + .replace_section( + config.info().data.unwrap(), + &new_section, + ))))) + } + + fn can_mutate<'a>(&self, config: &'a WasmMutate) -> bool { + // Modifying a data segment doesn't preserve the semantics of the + // original module and also only works if there's actually some data. + !config.preserve_semantics && config.info().num_data() > 0 + } +} + +#[cfg(test)] +mod tests { + use super::ModifyDataMutator; + use crate::WasmMutate; + use std::sync::Arc; + + #[test] + fn test_remove_export_mutator() { + let mut config = WasmMutate::default(); + config.raw_mutate_func(Some(Arc::new(|data, _| { + assert_eq!(data, b"x"); + *data = "y".to_string().into_bytes(); + Ok(()) + }))); + config.match_mutation( + r#"(module (data "x"))"#, + ModifyDataMutator { max_data_size: 100 }, + r#"(module (data "y"))"#, + ); + } +} diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 03d91f5191..44fa932c95 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -7,7 +7,7 @@ //! mutator largely translates between `wasmparser` structures and //! `wasm_encoder` structures. -use super::Mutator; +use crate::mutators::{translate, Item, Mutator, Translator}; use crate::Error; use crate::{ModuleInfo, Result, WasmMutate}; use rand::Rng; @@ -20,18 +20,6 @@ use wasmparser::*; #[derive(Copy, Clone)] pub struct RemoveItemMutator(pub Item); -#[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)] -pub enum Item { - Function, - Table, - Memory, - Tag, - Global, - Type, - Data, - Element, -} - impl Mutator for RemoveItemMutator { fn can_mutate(&self, config: &WasmMutate) -> bool { self.0.can_mutate(config) @@ -414,6 +402,12 @@ impl RemoveItem { module.section(&result); Ok(()) } +} + +impl Translator for RemoveItem { + fn as_obj(&mut self) -> &mut dyn Translator { + self + } /// This is "the point" of this type. This function remaps an `idx` /// provided, in the `item` index space, to a new index. @@ -450,886 +444,33 @@ impl RemoveItem { } } - fn translate_type_def(&mut self, ty: TypeDef, s: &mut TypeSection) -> Result<()> { - match ty { - TypeDef::Func(f) => { - s.function( - f.params - .iter() - .map(|t| self.translate_type(t)) - .collect::>>()?, - f.returns - .iter() - .map(|t| self.translate_type(t)) - .collect::>>()?, - ); - Ok(()) - } - - // Module linking is not supported at this time. - TypeDef::Instance(_) | TypeDef::Module(_) => Err(Error::no_mutations_applicable()), - } - } - - fn translate_table_type( - &mut self, - ty: &wasmparser::TableType, - ) -> Result { - Ok(wasm_encoder::TableType { - element_type: self.translate_type(&ty.element_type)?, - minimum: ty.initial, - maximum: ty.maximum, - }) - } - - fn translate_memory_type( - &mut self, - ty: &wasmparser::MemoryType, - ) -> Result { - Ok(wasm_encoder::MemoryType { - memory64: ty.memory64, - minimum: ty.initial, - maximum: ty.maximum, - }) - } - - fn translate_global_type( - &mut self, - ty: &wasmparser::GlobalType, - ) -> Result { - Ok(wasm_encoder::GlobalType { - val_type: self.translate_type(&ty.content_type)?, - mutable: ty.mutable, - }) - } - - fn translate_tag_type(&mut self, ty: &wasmparser::TagType) -> Result { - Ok(wasm_encoder::TagType { - kind: TagKind::Exception, - func_type_idx: self.remap(Item::Type, ty.type_index)?, - }) - } - - fn translate_type(&mut self, ty: &Type) -> Result { - match ty { - Type::I32 => Ok(ValType::I32), - Type::I64 => Ok(ValType::I64), - Type::F32 => Ok(ValType::F32), - Type::F64 => Ok(ValType::F64), - Type::V128 => Ok(ValType::V128), - Type::FuncRef => Ok(ValType::FuncRef), - Type::ExternRef => Ok(ValType::ExternRef), - - // not supported in wasm-encoder - Type::ExnRef => Err(Error::no_mutations_applicable()), - - // Shouldn't ever show up as these are used in different contexts - // within wasmparser. - Type::Func | Type::EmptyBlockType => Err(Error::no_mutations_applicable()), - } - } - - fn translate_global(&mut self, global: Global, s: &mut GlobalSection) -> Result<()> { - let ty = self.translate_global_type(&global.ty)?; - let insn = self.translate_init_expr(&global.init_expr)?; - s.global(ty, &insn); - Ok(()) - } - - fn translate_init_expr(&mut self, e: &InitExpr<'_>) -> Result> { - let mut e = e.get_operators_reader(); - let op = e.read()?; - let op = self.translate_op(&op)?; - match e.read()? { - Operator::End if e.eof() => {} - _ => return Err(Error::no_mutations_applicable()), - } - Ok(op) - } - - fn translate_element( - &mut self, - element: wasmparser::Element<'_>, - s: &mut ElementSection, - ) -> Result<()> { - let offset; - let mode = match &element.kind { - ElementKind::Active { - table_index, - init_expr, - } => { - offset = self.translate_init_expr(init_expr)?; - ElementMode::Active { - table: Some(self.remap(Item::Table, *table_index)?), - offset: &offset, - } - } - ElementKind::Passive => ElementMode::Passive, - ElementKind::Declared => ElementMode::Declared, - }; - let element_type = self.translate_type(&element.ty)?; - let mut functions = Vec::new(); - let mut exprs = Vec::new(); - let mut reader = element.items.get_items_reader()?; - for _ in 0..reader.get_count() { - match reader.read()? { - ElementItem::Func(idx) => { - functions.push(self.remap(Item::Function, idx)?); - } - ElementItem::Expr(expr) => match self.translate_init_expr(&expr)? { - Instruction::RefFunc(n) => { - exprs.push(wasm_encoder::Element::Func(n)); - } - Instruction::RefNull(_) => { - exprs.push(wasm_encoder::Element::Null); - } - _ => return Err(Error::no_mutations_applicable()), - }, - } - } - s.segment(ElementSegment { - mode, - element_type, - elements: if reader.uses_exprs() { - Elements::Expressions(&exprs) - } else { - Elements::Functions(&functions) - }, - }); - Ok(()) - } - - fn translate_data(&mut self, data: wasmparser::Data<'_>, s: &mut DataSection) -> Result<()> { - let offset; - let mode = match &data.kind { - DataKind::Active { - memory_index, - init_expr, - } => { - offset = self.translate_init_expr(init_expr)?; - DataSegmentMode::Active { - memory_index: self.remap(Item::Memory, *memory_index)?, - offset: &offset, - } - } - DataKind::Passive => DataSegmentMode::Passive, - }; - s.segment(DataSegment { - mode, - data: data.data.iter().copied(), - }); - Ok(()) - } - - fn translate_code(&mut self, body: FunctionBody<'_>, s: &mut CodeSection) -> Result<()> { - let locals = body - .get_locals_reader()? - .into_iter() - .map(|local| { - let (cnt, ty) = local?; - Ok((cnt, self.translate_type(&ty)?)) - }) - .collect::>>()?; - let mut func = Function::new(locals); - - for op in body.get_operators_reader()? { - let op = op?; - func.instruction(&self.translate_op(&op)?); - } - s.function(&func); - Ok(()) - } - - /// This is a pretty gnarly function that translates from `wasmparser` - /// operators to `wasm_encoder` operators. It's quite large because there's - /// quite a few wasm instructions. The theory though is that at least each - /// individual case is pretty self-contained. fn translate_op(&mut self, op: &Operator<'_>) -> Result> { - use wasm_encoder::Instruction as I; - use wasmparser::Operator as O; - Ok(match op { - O::Unreachable => I::Unreachable, - O::Nop => I::Nop, - - O::Block { ty } => I::Block(self.translate_block_type(ty)?), - O::Loop { ty } => I::Loop(self.translate_block_type(ty)?), - O::If { ty } => I::If(self.translate_block_type(ty)?), - O::Else => I::Else, - - O::Try { ty } => I::Try(self.translate_block_type(ty)?), - O::Catch { index } => I::Catch(self.remap(Item::Tag, *index)?), - O::Throw { index } => I::Throw(self.remap(Item::Tag, *index)?), - O::Rethrow { relative_depth } => I::Rethrow(*relative_depth), - O::End => I::End, - O::Br { relative_depth } => I::Br(*relative_depth), - O::BrIf { relative_depth } => I::BrIf(*relative_depth), - O::BrTable { table } => I::BrTable( - table - .targets() - .collect::, wasmparser::BinaryReaderError>>()? - .into(), - table.default(), - ), - - O::Return => I::Return, - O::Call { function_index } => I::Call(self.remap(Item::Function, *function_index)?), - O::CallIndirect { index, table_index } => I::CallIndirect { - ty: self.remap(Item::Type, *index)?, - table: self.remap(Item::Table, *table_index)?, - }, - O::Delegate { relative_depth } => I::Delegate(*relative_depth), - O::CatchAll => I::CatchAll, - O::Drop => I::Drop, - O::Select => I::Select, - O::TypedSelect { ty } => I::TypedSelect(self.translate_type(ty)?), - - O::LocalGet { local_index } => I::LocalGet(*local_index), - O::LocalSet { local_index } => I::LocalSet(*local_index), - O::LocalTee { local_index } => I::LocalTee(*local_index), - - O::GlobalGet { global_index } => I::GlobalGet(self.remap(Item::Global, *global_index)?), - O::GlobalSet { global_index } => I::GlobalSet(self.remap(Item::Global, *global_index)?), - - O::I32Load { memarg } => I::I32Load(self.memarg(memarg)?), - O::I64Load { memarg } => I::I64Load(self.memarg(memarg)?), - O::F32Load { memarg } => I::F32Load(self.memarg(memarg)?), - O::F64Load { memarg } => I::F64Load(self.memarg(memarg)?), - O::I32Load8S { memarg } => I::I32Load8_S(self.memarg(memarg)?), - O::I32Load8U { memarg } => I::I32Load8_U(self.memarg(memarg)?), - O::I32Load16S { memarg } => I::I32Load16_S(self.memarg(memarg)?), - O::I32Load16U { memarg } => I::I32Load16_U(self.memarg(memarg)?), - O::I64Load8S { memarg } => I::I64Load8_S(self.memarg(memarg)?), - O::I64Load8U { memarg } => I::I64Load8_U(self.memarg(memarg)?), - O::I64Load16S { memarg } => I::I64Load16_S(self.memarg(memarg)?), - O::I64Load16U { memarg } => I::I64Load16_U(self.memarg(memarg)?), - O::I64Load32S { memarg } => I::I64Load32_S(self.memarg(memarg)?), - O::I64Load32U { memarg } => I::I64Load32_U(self.memarg(memarg)?), - O::I32Store { memarg } => I::I32Store(self.memarg(memarg)?), - O::I64Store { memarg } => I::I64Store(self.memarg(memarg)?), - O::F32Store { memarg } => I::F32Store(self.memarg(memarg)?), - O::F64Store { memarg } => I::F64Store(self.memarg(memarg)?), - O::I32Store8 { memarg } => I::I32Store8(self.memarg(memarg)?), - O::I32Store16 { memarg } => I::I32Store16(self.memarg(memarg)?), - O::I64Store8 { memarg } => I::I64Store8(self.memarg(memarg)?), - O::I64Store16 { memarg } => I::I64Store16(self.memarg(memarg)?), - O::I64Store32 { memarg } => I::I64Store32(self.memarg(memarg)?), - - O::MemorySize { mem, .. } => I::MemorySize(self.remap(Item::Memory, *mem)?), - O::MemoryGrow { mem, .. } => I::MemoryGrow(self.remap(Item::Memory, *mem)?), - - O::I32Const { value } => I::I32Const(*value), - O::I64Const { value } => I::I64Const(*value), - O::F32Const { value } => I::F32Const(f32::from_bits(value.bits())), - O::F64Const { value } => I::F64Const(f64::from_bits(value.bits())), - - O::RefNull { ty } => I::RefNull(self.translate_type(ty)?), - O::RefIsNull => I::RefIsNull, - O::RefFunc { function_index } => { - // The reason for this is that in the code section instructions - // such as `ref.func 0` are only valid if function 0 is - // otherwise referenced somewhere in the module via things like - // globals, exports, element segments, etc. This means that - // removal of a global funcref *could* make `ref.func 0` - // invalid where it was valid before. To prevent creating an - // invalid module this block guards against this by recognizing - // when we're in the code section and on seeing a `ref.func` - // instruction it'll return an error if the index isn't - // otherwise referenced (probably because we removed the one - // item that referenced it). - let idx = *function_index; - match self.function_reference_action { - Funcref::Save => { - self.referenced_functions.insert(idx); - } - Funcref::Skip => {} - Funcref::RequireReferenced => { - if !self.referenced_functions.contains(&idx) { - return Err(Error::no_mutations_applicable()); - } + // The reason for this is that in the code section instructions + // such as `ref.func 0` are only valid if function 0 is + // otherwise referenced somewhere in the module via things like + // globals, exports, element segments, etc. This means that + // removal of a global funcref *could* make `ref.func 0` + // invalid where it was valid before. To prevent creating an + // invalid module this block guards against this by recognizing + // when we're in the code section and on seeing a `ref.func` + // instruction it'll return an error if the index isn't + // otherwise referenced (probably because we removed the one + // item that referenced it). + if let Operator::RefFunc { function_index } = op { + let idx = *function_index; + match self.function_reference_action { + Funcref::Save => { + self.referenced_functions.insert(idx); + } + Funcref::Skip => {} + Funcref::RequireReferenced => { + if !self.referenced_functions.contains(&idx) { + return Err(Error::no_mutations_applicable()); } } - - I::RefFunc(self.remap(Item::Function, idx)?) } - - O::I32Eqz => I::I32Eqz, - O::I32Eq => I::I32Eq, - O::I32Ne => I::I32Ne, - O::I32LtS => I::I32LtS, - O::I32LtU => I::I32LtU, - O::I32GtS => I::I32GtS, - O::I32GtU => I::I32GtU, - O::I32LeS => I::I32LeS, - O::I32LeU => I::I32LeU, - O::I32GeS => I::I32GeS, - O::I32GeU => I::I32GeU, - O::I64Eqz => I::I64Eqz, - O::I64Eq => I::I64Eq, - O::I64Ne => I::I64Ne, - O::I64LtS => I::I64LtS, - O::I64LtU => I::I64LtU, - O::I64GtS => I::I64GtS, - O::I64GtU => I::I64GtU, - O::I64LeS => I::I64LeS, - O::I64LeU => I::I64LeU, - O::I64GeS => I::I64GeS, - O::I64GeU => I::I64GeU, - O::F32Eq => I::F32Eq, - O::F32Ne => I::F32Ne, - O::F32Lt => I::F32Lt, - O::F32Gt => I::F32Gt, - O::F32Le => I::F32Le, - O::F32Ge => I::F32Ge, - O::F64Eq => I::F64Eq, - O::F64Ne => I::F64Ne, - O::F64Lt => I::F64Lt, - O::F64Gt => I::F64Gt, - O::F64Le => I::F64Le, - O::F64Ge => I::F64Ge, - O::I32Clz => I::I32Clz, - O::I32Ctz => I::I32Ctz, - O::I32Popcnt => I::I32Popcnt, - O::I32Add => I::I32Add, - O::I32Sub => I::I32Sub, - O::I32Mul => I::I32Mul, - O::I32DivS => I::I32DivS, - O::I32DivU => I::I32DivU, - O::I32RemS => I::I32RemS, - O::I32RemU => I::I32RemU, - O::I32And => I::I32And, - O::I32Or => I::I32Or, - O::I32Xor => I::I32Xor, - O::I32Shl => I::I32Shl, - O::I32ShrS => I::I32ShrS, - O::I32ShrU => I::I32ShrU, - O::I32Rotl => I::I32Rotl, - O::I32Rotr => I::I32Rotr, - O::I64Clz => I::I64Clz, - O::I64Ctz => I::I64Ctz, - O::I64Popcnt => I::I64Popcnt, - O::I64Add => I::I64Add, - O::I64Sub => I::I64Sub, - O::I64Mul => I::I64Mul, - O::I64DivS => I::I64DivS, - O::I64DivU => I::I64DivU, - O::I64RemS => I::I64RemS, - O::I64RemU => I::I64RemU, - O::I64And => I::I64And, - O::I64Or => I::I64Or, - O::I64Xor => I::I64Xor, - O::I64Shl => I::I64Shl, - O::I64ShrS => I::I64ShrS, - O::I64ShrU => I::I64ShrU, - O::I64Rotl => I::I64Rotl, - O::I64Rotr => I::I64Rotr, - O::F32Abs => I::F32Abs, - O::F32Neg => I::F32Neg, - O::F32Ceil => I::F32Ceil, - O::F32Floor => I::F32Floor, - O::F32Trunc => I::F32Trunc, - O::F32Nearest => I::F32Nearest, - O::F32Sqrt => I::F32Sqrt, - O::F32Add => I::F32Add, - O::F32Sub => I::F32Sub, - O::F32Mul => I::F32Mul, - O::F32Div => I::F32Div, - O::F32Min => I::F32Min, - O::F32Max => I::F32Max, - O::F32Copysign => I::F32Copysign, - O::F64Abs => I::F64Abs, - O::F64Neg => I::F64Neg, - O::F64Ceil => I::F64Ceil, - O::F64Floor => I::F64Floor, - O::F64Trunc => I::F64Trunc, - O::F64Nearest => I::F64Nearest, - O::F64Sqrt => I::F64Sqrt, - O::F64Add => I::F64Add, - O::F64Sub => I::F64Sub, - O::F64Mul => I::F64Mul, - O::F64Div => I::F64Div, - O::F64Min => I::F64Min, - O::F64Max => I::F64Max, - O::F64Copysign => I::F64Copysign, - O::I32WrapI64 => I::I32WrapI64, - O::I32TruncF32S => I::I32TruncF32S, - O::I32TruncF32U => I::I32TruncF32U, - O::I32TruncF64S => I::I32TruncF64S, - O::I32TruncF64U => I::I32TruncF64U, - O::I64ExtendI32S => I::I64ExtendI32S, - O::I64ExtendI32U => I::I64ExtendI32U, - O::I64TruncF32S => I::I64TruncF32S, - O::I64TruncF32U => I::I64TruncF32U, - O::I64TruncF64S => I::I64TruncF64S, - O::I64TruncF64U => I::I64TruncF64U, - O::F32ConvertI32S => I::F32ConvertI32S, - O::F32ConvertI32U => I::F32ConvertI32U, - O::F32ConvertI64S => I::F32ConvertI64S, - O::F32ConvertI64U => I::F32ConvertI64U, - O::F32DemoteF64 => I::F32DemoteF64, - O::F64ConvertI32S => I::F64ConvertI32S, - O::F64ConvertI32U => I::F64ConvertI32U, - O::F64ConvertI64S => I::F64ConvertI64S, - O::F64ConvertI64U => I::F64ConvertI64U, - O::F64PromoteF32 => I::F64PromoteF32, - O::I32ReinterpretF32 => I::I32ReinterpretF32, - O::I64ReinterpretF64 => I::I64ReinterpretF64, - O::F32ReinterpretI32 => I::F32ReinterpretI32, - O::F64ReinterpretI64 => I::F64ReinterpretI64, - O::I32Extend8S => I::I32Extend8S, - O::I32Extend16S => I::I32Extend16S, - O::I64Extend8S => I::I64Extend8S, - O::I64Extend16S => I::I64Extend16S, - O::I64Extend32S => I::I64Extend32S, - - O::I32TruncSatF32S => I::I32TruncSatF32S, - O::I32TruncSatF32U => I::I32TruncSatF32U, - O::I32TruncSatF64S => I::I32TruncSatF64S, - O::I32TruncSatF64U => I::I32TruncSatF64U, - O::I64TruncSatF32S => I::I64TruncSatF32S, - O::I64TruncSatF32U => I::I64TruncSatF32U, - O::I64TruncSatF64S => I::I64TruncSatF64S, - O::I64TruncSatF64U => I::I64TruncSatF64U, - - O::MemoryInit { segment, mem } => I::MemoryInit { - data: self.remap(Item::Data, *segment)?, - mem: self.remap(Item::Memory, *mem)?, - }, - O::DataDrop { segment } => I::DataDrop(self.remap(Item::Data, *segment)?), - O::MemoryCopy { src, dst } => I::MemoryCopy { - src: self.remap(Item::Memory, *src)?, - dst: self.remap(Item::Memory, *dst)?, - }, - O::MemoryFill { mem, .. } => I::MemoryFill(self.remap(Item::Memory, *mem)?), - - O::TableInit { segment, table } => I::TableInit { - segment: self.remap(Item::Element, *segment)?, - table: self.remap(Item::Table, *table)?, - }, - O::ElemDrop { segment } => I::ElemDrop { - segment: self.remap(Item::Element, *segment)?, - }, - O::TableCopy { - dst_table, - src_table, - } => I::TableCopy { - dst: self.remap(Item::Table, *dst_table)?, - src: self.remap(Item::Table, *src_table)?, - }, - O::TableFill { table } => I::TableFill { - table: self.remap(Item::Table, *table)?, - }, - O::TableGet { table } => I::TableGet { - table: self.remap(Item::Table, *table)?, - }, - O::TableSet { table } => I::TableSet { - table: self.remap(Item::Table, *table)?, - }, - O::TableGrow { table } => I::TableGrow { - table: self.remap(Item::Table, *table)?, - }, - O::TableSize { table } => I::TableSize { - table: self.remap(Item::Table, *table)?, - }, - - O::V128Load { memarg } => I::V128Load { - memarg: self.memarg(memarg)?, - }, - O::V128Load8x8S { memarg } => I::V128Load8x8S { - memarg: self.memarg(memarg)?, - }, - O::V128Load8x8U { memarg } => I::V128Load8x8U { - memarg: self.memarg(memarg)?, - }, - O::V128Load16x4S { memarg } => I::V128Load16x4S { - memarg: self.memarg(memarg)?, - }, - O::V128Load16x4U { memarg } => I::V128Load16x4U { - memarg: self.memarg(memarg)?, - }, - O::V128Load32x2S { memarg } => I::V128Load32x2S { - memarg: self.memarg(memarg)?, - }, - O::V128Load32x2U { memarg } => I::V128Load32x2U { - memarg: self.memarg(memarg)?, - }, - O::V128Load8Splat { memarg } => I::V128Load8Splat { - memarg: self.memarg(memarg)?, - }, - O::V128Load16Splat { memarg } => I::V128Load16Splat { - memarg: self.memarg(memarg)?, - }, - O::V128Load32Splat { memarg } => I::V128Load32Splat { - memarg: self.memarg(memarg)?, - }, - O::V128Load64Splat { memarg } => I::V128Load64Splat { - memarg: self.memarg(memarg)?, - }, - O::V128Load32Zero { memarg } => I::V128Load32Zero { - memarg: self.memarg(memarg)?, - }, - O::V128Load64Zero { memarg } => I::V128Load64Zero { - memarg: self.memarg(memarg)?, - }, - O::V128Store { memarg } => I::V128Store { - memarg: self.memarg(memarg)?, - }, - O::V128Load8Lane { memarg, lane } => I::V128Load8Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Load16Lane { memarg, lane } => I::V128Load16Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Load32Lane { memarg, lane } => I::V128Load32Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Load64Lane { memarg, lane } => I::V128Load64Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Store8Lane { memarg, lane } => I::V128Store8Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Store16Lane { memarg, lane } => I::V128Store16Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Store32Lane { memarg, lane } => I::V128Store32Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - O::V128Store64Lane { memarg, lane } => I::V128Store64Lane { - memarg: self.memarg(memarg)?, - lane: *lane, - }, - - O::V128Const { value } => I::V128Const(value.i128()), - O::I8x16Shuffle { lanes } => I::I8x16Shuffle { lanes: *lanes }, - O::I8x16ExtractLaneS { lane } => I::I8x16ExtractLaneS { lane: *lane }, - O::I8x16ExtractLaneU { lane } => I::I8x16ExtractLaneU { lane: *lane }, - O::I8x16ReplaceLane { lane } => I::I8x16ReplaceLane { lane: *lane }, - O::I16x8ExtractLaneS { lane } => I::I16x8ExtractLaneS { lane: *lane }, - O::I16x8ExtractLaneU { lane } => I::I16x8ExtractLaneU { lane: *lane }, - O::I16x8ReplaceLane { lane } => I::I16x8ReplaceLane { lane: *lane }, - O::I32x4ExtractLane { lane } => I::I32x4ExtractLane { lane: *lane }, - O::I32x4ReplaceLane { lane } => I::I32x4ReplaceLane { lane: *lane }, - O::I64x2ExtractLane { lane } => I::I64x2ExtractLane { lane: *lane }, - O::I64x2ReplaceLane { lane } => I::I64x2ReplaceLane { lane: *lane }, - O::F32x4ExtractLane { lane } => I::F32x4ExtractLane { lane: *lane }, - O::F32x4ReplaceLane { lane } => I::F32x4ReplaceLane { lane: *lane }, - O::F64x2ExtractLane { lane } => I::F64x2ExtractLane { lane: *lane }, - O::F64x2ReplaceLane { lane } => I::F64x2ReplaceLane { lane: *lane }, - - O::I8x16Swizzle => I::I8x16Swizzle, - O::I8x16Splat => I::I8x16Splat, - O::I16x8Splat => I::I16x8Splat, - O::I32x4Splat => I::I32x4Splat, - O::I64x2Splat => I::I64x2Splat, - O::F32x4Splat => I::F32x4Splat, - O::F64x2Splat => I::F64x2Splat, - O::I8x16Eq => I::I8x16Eq, - O::I8x16Ne => I::I8x16Ne, - O::I8x16LtS => I::I8x16LtS, - O::I8x16LtU => I::I8x16LtU, - O::I8x16GtS => I::I8x16GtS, - O::I8x16GtU => I::I8x16GtU, - O::I8x16LeS => I::I8x16LeS, - O::I8x16LeU => I::I8x16LeU, - O::I8x16GeS => I::I8x16GeS, - O::I8x16GeU => I::I8x16GeU, - O::I16x8Eq => I::I16x8Eq, - O::I16x8Ne => I::I16x8Ne, - O::I16x8LtS => I::I16x8LtS, - O::I16x8LtU => I::I16x8LtU, - O::I16x8GtS => I::I16x8GtS, - O::I16x8GtU => I::I16x8GtU, - O::I16x8LeS => I::I16x8LeS, - O::I16x8LeU => I::I16x8LeU, - O::I16x8GeS => I::I16x8GeS, - O::I16x8GeU => I::I16x8GeU, - O::I32x4Eq => I::I32x4Eq, - O::I32x4Ne => I::I32x4Ne, - O::I32x4LtS => I::I32x4LtS, - O::I32x4LtU => I::I32x4LtU, - O::I32x4GtS => I::I32x4GtS, - O::I32x4GtU => I::I32x4GtU, - O::I32x4LeS => I::I32x4LeS, - O::I32x4LeU => I::I32x4LeU, - O::I32x4GeS => I::I32x4GeS, - O::I32x4GeU => I::I32x4GeU, - O::I64x2Eq => I::I64x2Eq, - O::I64x2Ne => I::I64x2Ne, - O::I64x2LtS => I::I64x2LtS, - O::I64x2GtS => I::I64x2GtS, - O::I64x2LeS => I::I64x2LeS, - O::I64x2GeS => I::I64x2GeS, - O::F32x4Eq => I::F32x4Eq, - O::F32x4Ne => I::F32x4Ne, - O::F32x4Lt => I::F32x4Lt, - O::F32x4Gt => I::F32x4Gt, - O::F32x4Le => I::F32x4Le, - O::F32x4Ge => I::F32x4Ge, - O::F64x2Eq => I::F64x2Eq, - O::F64x2Ne => I::F64x2Ne, - O::F64x2Lt => I::F64x2Lt, - O::F64x2Gt => I::F64x2Gt, - O::F64x2Le => I::F64x2Le, - O::F64x2Ge => I::F64x2Ge, - O::V128Not => I::V128Not, - O::V128And => I::V128And, - O::V128AndNot => I::V128AndNot, - O::V128Or => I::V128Or, - O::V128Xor => I::V128Xor, - O::V128Bitselect => I::V128Bitselect, - O::V128AnyTrue => I::V128AnyTrue, - O::I8x16Abs => I::I8x16Abs, - O::I8x16Neg => I::I8x16Neg, - O::I8x16Popcnt => I::I8x16Popcnt, - O::I8x16AllTrue => I::I8x16AllTrue, - O::I8x16Bitmask => I::I8x16Bitmask, - O::I8x16NarrowI16x8S => I::I8x16NarrowI16x8S, - O::I8x16NarrowI16x8U => I::I8x16NarrowI16x8U, - O::I8x16Shl => I::I8x16Shl, - O::I8x16ShrS => I::I8x16ShrS, - O::I8x16ShrU => I::I8x16ShrU, - O::I8x16Add => I::I8x16Add, - O::I8x16AddSatS => I::I8x16AddSatS, - O::I8x16AddSatU => I::I8x16AddSatU, - O::I8x16Sub => I::I8x16Sub, - O::I8x16SubSatS => I::I8x16SubSatS, - O::I8x16SubSatU => I::I8x16SubSatU, - O::I8x16MinS => I::I8x16MinS, - O::I8x16MinU => I::I8x16MinU, - O::I8x16MaxS => I::I8x16MaxS, - O::I8x16MaxU => I::I8x16MaxU, - O::I8x16RoundingAverageU => I::I8x16RoundingAverageU, - O::I16x8ExtAddPairwiseI8x16S => I::I16x8ExtAddPairwiseI8x16S, - O::I16x8ExtAddPairwiseI8x16U => I::I16x8ExtAddPairwiseI8x16U, - O::I16x8Abs => I::I16x8Abs, - O::I16x8Neg => I::I16x8Neg, - O::I16x8Q15MulrSatS => I::I16x8Q15MulrSatS, - O::I16x8AllTrue => I::I16x8AllTrue, - O::I16x8Bitmask => I::I16x8Bitmask, - O::I16x8NarrowI32x4S => I::I16x8NarrowI32x4S, - O::I16x8NarrowI32x4U => I::I16x8NarrowI32x4U, - O::I16x8ExtendLowI8x16S => I::I16x8ExtendLowI8x16S, - O::I16x8ExtendHighI8x16S => I::I16x8ExtendHighI8x16S, - O::I16x8ExtendLowI8x16U => I::I16x8ExtendLowI8x16U, - O::I16x8ExtendHighI8x16U => I::I16x8ExtendHighI8x16U, - O::I16x8Shl => I::I16x8Shl, - O::I16x8ShrS => I::I16x8ShrS, - O::I16x8ShrU => I::I16x8ShrU, - O::I16x8Add => I::I16x8Add, - O::I16x8AddSatS => I::I16x8AddSatS, - O::I16x8AddSatU => I::I16x8AddSatU, - O::I16x8Sub => I::I16x8Sub, - O::I16x8SubSatS => I::I16x8SubSatS, - O::I16x8SubSatU => I::I16x8SubSatU, - O::I16x8Mul => I::I16x8Mul, - O::I16x8MinS => I::I16x8MinS, - O::I16x8MinU => I::I16x8MinU, - O::I16x8MaxS => I::I16x8MaxS, - O::I16x8MaxU => I::I16x8MaxU, - O::I16x8RoundingAverageU => I::I16x8RoundingAverageU, - O::I16x8ExtMulLowI8x16S => I::I16x8ExtMulLowI8x16S, - O::I16x8ExtMulHighI8x16S => I::I16x8ExtMulHighI8x16S, - O::I16x8ExtMulLowI8x16U => I::I16x8ExtMulLowI8x16U, - O::I16x8ExtMulHighI8x16U => I::I16x8ExtMulHighI8x16U, - O::I32x4ExtAddPairwiseI16x8S => I::I32x4ExtAddPairwiseI16x8S, - O::I32x4ExtAddPairwiseI16x8U => I::I32x4ExtAddPairwiseI16x8U, - O::I32x4Abs => I::I32x4Abs, - O::I32x4Neg => I::I32x4Neg, - O::I32x4AllTrue => I::I32x4AllTrue, - O::I32x4Bitmask => I::I32x4Bitmask, - O::I32x4ExtendLowI16x8S => I::I32x4ExtendLowI16x8S, - O::I32x4ExtendHighI16x8S => I::I32x4ExtendHighI16x8S, - O::I32x4ExtendLowI16x8U => I::I32x4ExtendLowI16x8U, - O::I32x4ExtendHighI16x8U => I::I32x4ExtendHighI16x8U, - O::I32x4Shl => I::I32x4Shl, - O::I32x4ShrS => I::I32x4ShrS, - O::I32x4ShrU => I::I32x4ShrU, - O::I32x4Add => I::I32x4Add, - O::I32x4Sub => I::I32x4Sub, - O::I32x4Mul => I::I32x4Mul, - O::I32x4MinS => I::I32x4MinS, - O::I32x4MinU => I::I32x4MinU, - O::I32x4MaxS => I::I32x4MaxS, - O::I32x4MaxU => I::I32x4MaxU, - O::I32x4DotI16x8S => I::I32x4DotI16x8S, - O::I32x4ExtMulLowI16x8S => I::I32x4ExtMulLowI16x8S, - O::I32x4ExtMulHighI16x8S => I::I32x4ExtMulHighI16x8S, - O::I32x4ExtMulLowI16x8U => I::I32x4ExtMulLowI16x8U, - O::I32x4ExtMulHighI16x8U => I::I32x4ExtMulHighI16x8U, - O::I64x2Abs => I::I64x2Abs, - O::I64x2Neg => I::I64x2Neg, - O::I64x2AllTrue => I::I64x2AllTrue, - O::I64x2Bitmask => I::I64x2Bitmask, - O::I64x2ExtendLowI32x4S => I::I64x2ExtendLowI32x4S, - O::I64x2ExtendHighI32x4S => I::I64x2ExtendHighI32x4S, - O::I64x2ExtendLowI32x4U => I::I64x2ExtendLowI32x4U, - O::I64x2ExtendHighI32x4U => I::I64x2ExtendHighI32x4U, - O::I64x2Shl => I::I64x2Shl, - O::I64x2ShrS => I::I64x2ShrS, - O::I64x2ShrU => I::I64x2ShrU, - O::I64x2Add => I::I64x2Add, - O::I64x2Sub => I::I64x2Sub, - O::I64x2Mul => I::I64x2Mul, - O::I64x2ExtMulLowI32x4S => I::I64x2ExtMulLowI32x4S, - O::I64x2ExtMulHighI32x4S => I::I64x2ExtMulHighI32x4S, - O::I64x2ExtMulLowI32x4U => I::I64x2ExtMulLowI32x4U, - O::I64x2ExtMulHighI32x4U => I::I64x2ExtMulHighI32x4U, - O::F32x4Ceil => I::F32x4Ceil, - O::F32x4Floor => I::F32x4Floor, - O::F32x4Trunc => I::F32x4Trunc, - O::F32x4Nearest => I::F32x4Nearest, - O::F32x4Abs => I::F32x4Abs, - O::F32x4Neg => I::F32x4Neg, - O::F32x4Sqrt => I::F32x4Sqrt, - O::F32x4Add => I::F32x4Add, - O::F32x4Sub => I::F32x4Sub, - O::F32x4Mul => I::F32x4Mul, - O::F32x4Div => I::F32x4Div, - O::F32x4Min => I::F32x4Min, - O::F32x4Max => I::F32x4Max, - O::F32x4PMin => I::F32x4PMin, - O::F32x4PMax => I::F32x4PMax, - O::F64x2Ceil => I::F64x2Ceil, - O::F64x2Floor => I::F64x2Floor, - O::F64x2Trunc => I::F64x2Trunc, - O::F64x2Nearest => I::F64x2Nearest, - O::F64x2Abs => I::F64x2Abs, - O::F64x2Neg => I::F64x2Neg, - O::F64x2Sqrt => I::F64x2Sqrt, - O::F64x2Add => I::F64x2Add, - O::F64x2Sub => I::F64x2Sub, - O::F64x2Mul => I::F64x2Mul, - O::F64x2Div => I::F64x2Div, - O::F64x2Min => I::F64x2Min, - O::F64x2Max => I::F64x2Max, - O::F64x2PMin => I::F64x2PMin, - O::F64x2PMax => I::F64x2PMax, - O::I32x4TruncSatF32x4S => I::I32x4TruncSatF32x4S, - O::I32x4TruncSatF32x4U => I::I32x4TruncSatF32x4U, - O::F32x4ConvertI32x4S => I::F32x4ConvertI32x4S, - O::F32x4ConvertI32x4U => I::F32x4ConvertI32x4U, - O::I32x4TruncSatF64x2SZero => I::I32x4TruncSatF64x2SZero, - O::I32x4TruncSatF64x2UZero => I::I32x4TruncSatF64x2UZero, - O::F64x2ConvertLowI32x4S => I::F64x2ConvertLowI32x4S, - O::F64x2ConvertLowI32x4U => I::F64x2ConvertLowI32x4U, - O::F32x4DemoteF64x2Zero => I::F32x4DemoteF64x2Zero, - O::F64x2PromoteLowF32x4 => I::F64x2PromoteLowF32x4, - O::I8x16SwizzleRelaxed => I::I8x16SwizzleRelaxed, - O::I32x4TruncSatF32x4SRelaxed => I::I32x4TruncSatF32x4SRelaxed, - O::I32x4TruncSatF32x4URelaxed => I::I32x4TruncSatF32x4URelaxed, - O::I32x4TruncSatF64x2SZeroRelaxed => I::I32x4TruncSatF64x2SZeroRelaxed, - O::I32x4TruncSatF64x2UZeroRelaxed => I::I32x4TruncSatF64x2UZeroRelaxed, - O::F32x4FmaRelaxed => I::F32x4FmaRelaxed, - O::F32x4FmsRelaxed => I::F32x4FmsRelaxed, - O::F64x2FmaRelaxed => I::F64x2FmaRelaxed, - O::F64x2FmsRelaxed => I::F64x2FmsRelaxed, - O::I8x16LaneSelect => I::I8x16LaneSelect, - O::I16x8LaneSelect => I::I16x8LaneSelect, - O::I32x4LaneSelect => I::I32x4LaneSelect, - O::I64x2LaneSelect => I::I64x2LaneSelect, - O::F32x4MinRelaxed => I::F32x4MinRelaxed, - O::F32x4MaxRelaxed => I::F32x4MaxRelaxed, - O::F64x2MinRelaxed => I::F64x2MinRelaxed, - O::F64x2MaxRelaxed => I::F64x2MaxRelaxed, - - // Note that these cases are not supported in `wasm_encoder` yet, - // and in general `wasmparser` often parses more things than - // `wasm_encoder` supports. If these are seen we simply say that - // this mutation isn't applicable because `wasm-encoder` can't - // create the new function anyway. - O::MemoryAtomicNotify { .. } - | O::MemoryAtomicWait32 { .. } - | O::MemoryAtomicWait64 { .. } - | O::I32AtomicLoad { .. } - | O::I64AtomicLoad { .. } - | O::I32AtomicLoad8U { .. } - | O::I32AtomicLoad16U { .. } - | O::I64AtomicLoad8U { .. } - | O::I64AtomicLoad16U { .. } - | O::I64AtomicLoad32U { .. } - | O::I32AtomicStore { .. } - | O::I64AtomicStore { .. } - | O::I32AtomicStore8 { .. } - | O::I32AtomicStore16 { .. } - | O::I64AtomicStore8 { .. } - | O::I64AtomicStore16 { .. } - | O::I64AtomicStore32 { .. } - | O::I32AtomicRmwAdd { .. } - | O::I64AtomicRmwAdd { .. } - | O::I32AtomicRmw8AddU { .. } - | O::I32AtomicRmw16AddU { .. } - | O::I64AtomicRmw8AddU { .. } - | O::I64AtomicRmw16AddU { .. } - | O::I64AtomicRmw32AddU { .. } - | O::I32AtomicRmwSub { .. } - | O::I64AtomicRmwSub { .. } - | O::I32AtomicRmw8SubU { .. } - | O::I32AtomicRmw16SubU { .. } - | O::I64AtomicRmw8SubU { .. } - | O::I64AtomicRmw16SubU { .. } - | O::I64AtomicRmw32SubU { .. } - | O::I32AtomicRmwAnd { .. } - | O::I64AtomicRmwAnd { .. } - | O::I32AtomicRmw8AndU { .. } - | O::I32AtomicRmw16AndU { .. } - | O::I64AtomicRmw8AndU { .. } - | O::I64AtomicRmw16AndU { .. } - | O::I64AtomicRmw32AndU { .. } - | O::I32AtomicRmwOr { .. } - | O::I64AtomicRmwOr { .. } - | O::I32AtomicRmw8OrU { .. } - | O::I32AtomicRmw16OrU { .. } - | O::I64AtomicRmw8OrU { .. } - | O::I64AtomicRmw16OrU { .. } - | O::I64AtomicRmw32OrU { .. } - | O::I32AtomicRmwXor { .. } - | O::I64AtomicRmwXor { .. } - | O::I32AtomicRmw8XorU { .. } - | O::I32AtomicRmw16XorU { .. } - | O::I64AtomicRmw8XorU { .. } - | O::I64AtomicRmw16XorU { .. } - | O::I64AtomicRmw32XorU { .. } - | O::I32AtomicRmwXchg { .. } - | O::I64AtomicRmwXchg { .. } - | O::I32AtomicRmw8XchgU { .. } - | O::I32AtomicRmw16XchgU { .. } - | O::I64AtomicRmw8XchgU { .. } - | O::I64AtomicRmw16XchgU { .. } - | O::I64AtomicRmw32XchgU { .. } - | O::I32AtomicRmwCmpxchg { .. } - | O::I64AtomicRmwCmpxchg { .. } - | O::I32AtomicRmw8CmpxchgU { .. } - | O::I32AtomicRmw16CmpxchgU { .. } - | O::I64AtomicRmw8CmpxchgU { .. } - | O::I64AtomicRmw16CmpxchgU { .. } - | O::I64AtomicRmw32CmpxchgU { .. } - | O::ReturnCall { .. } - | O::ReturnCallIndirect { .. } - | O::AtomicFence { .. } => return Err(Error::no_mutations_applicable()), - }) - } - - fn translate_block_type(&mut self, ty: &TypeOrFuncType) -> Result { - match ty { - TypeOrFuncType::Type(Type::EmptyBlockType) => Ok(BlockType::Empty), - TypeOrFuncType::Type(ty) => Ok(BlockType::Result(self.translate_type(ty)?)), - TypeOrFuncType::FuncType(f) => Ok(BlockType::FunctionType(self.remap(Item::Type, *f)?)), } - } - - fn memarg(&mut self, memarg: &MemoryImmediate) -> Result { - Ok(MemArg { - offset: memarg.offset, - align: memarg.align.into(), - memory_index: self.remap(Item::Memory, memarg.memory)?, - }) + translate::op(self, op) } } diff --git a/crates/wasm-mutate/src/mutators/rename_export.rs b/crates/wasm-mutate/src/mutators/rename_export.rs index c4c1340f70..70f3273f21 100644 --- a/crates/wasm-mutate/src/mutators/rename_export.rs +++ b/crates/wasm-mutate/src/mutators/rename_export.rs @@ -2,7 +2,7 @@ use super::Mutator; use crate::{Result, WasmMutate}; -use rand::{Rng, RngCore}; +use rand::Rng; use wasm_encoder::{Export, ExportSection, Module}; use wasmparser::ExportSectionReader; @@ -13,45 +13,28 @@ use wasmparser::ExportSectionReader; #[derive(Clone, Copy)] pub struct RenameExportMutator { /// The maximum length of the generated export entry - pub max_name_size: u32, + pub max_name_size: usize, } impl RenameExportMutator { /// Copied and transformed from wasm-smith name generation - fn limited_string( - &self, - config: &mut WasmMutate, - max_name_size: u32, - result: &mut String, - ) -> crate::Result<()> { - let size = config.rng().gen_range(1, max_name_size); - let mut str = vec![0u8; size as usize]; - - if let Some(fillfunc) = &config.raw_mutate_func { - fillfunc(&mut str)?; - } else { - config.rng().fill_bytes(&mut str); - } - - match std::str::from_utf8(&str) { - Ok(s) => result.push_str(s), - Err(e) => { - let i = e.valid_up_to(); - let valid = &str[0..i]; - let s = unsafe { - debug_assert!(std::str::from_utf8(valid).is_ok()); - std::str::from_utf8_unchecked(valid) - }; - result.push_str(s); + fn limited_string(&self, config: &mut WasmMutate, original: &str) -> crate::Result { + loop { + let mut bytes = original.as_bytes().to_vec(); + config.raw_mutate(&mut bytes, self.max_name_size)?; + + match std::str::from_utf8(&bytes) { + Ok(_) => {} + Err(e) => { + let i = e.valid_up_to(); + bytes.drain(i..); + } + }; + if bytes.len() > self.max_name_size { + continue; } - }; - - // Add one symbol at a time until it is not contained in the export field names - while config.info().export_names.contains(result) { - let _ = &self.limited_string(config, 2, result)?; + return Ok(String::from_utf8(bytes).unwrap()); } - - Ok(()) } } @@ -74,8 +57,7 @@ impl Mutator for RenameExportMutator { // otherwise bypass String::from(export.field) } else { - let mut new_name = String::default(); - self.limited_string(config, self.max_name_size, &mut new_name)?; + let new_name = self.limited_string(config, export.field)?; log::debug!("Renaming export {:?} by {:?}", export, new_name); new_name }; @@ -119,14 +101,21 @@ impl Mutator for RenameExportMutator { #[cfg(test)] mod tests { - use super::RenameExportMutator; + use crate::WasmMutate; + use std::sync::Arc; #[test] fn test_rename_export_mutator() { // From https://developer.mozilla.org/en-US/docs/WebAssembly/Text_format_to_wasm - crate::mutators::match_mutation( + let mut config = WasmMutate::default(); + config.raw_mutate_func(Some(Arc::new(|data, _| { + assert_eq!(data, b"exported_func"); + *data = Vec::new(); + Ok(()) + }))); + config.match_mutation( r#" (module (func (export "exported_func") (result i32) diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs new file mode 100644 index 0000000000..5f0ba5c28f --- /dev/null +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -0,0 +1,956 @@ +use crate::{Error, Result}; +use wasm_encoder::*; +use wasmparser::*; + +#[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)] +pub enum Item { + Function, + Table, + Memory, + Tag, + Global, + Type, + Data, + Element, +} + +pub trait Translator { + fn as_obj(&mut self) -> &mut dyn Translator; + + fn translate_type_def(&mut self, ty: TypeDef, s: &mut TypeSection) -> Result<()> { + type_def(self.as_obj(), ty, s) + } + + fn translate_table_type( + &mut self, + ty: &wasmparser::TableType, + ) -> Result { + table_type(self.as_obj(), ty) + } + + fn translate_memory_type( + &mut self, + ty: &wasmparser::MemoryType, + ) -> Result { + memory_type(self.as_obj(), ty) + } + + fn translate_global_type( + &mut self, + ty: &wasmparser::GlobalType, + ) -> Result { + global_type(self.as_obj(), ty) + } + + fn translate_tag_type(&mut self, ty: &wasmparser::TagType) -> Result { + tag_type(self.as_obj(), ty) + } + + fn translate_ty(&mut self, t: &Type) -> Result { + ty(self.as_obj(), t) + } + + fn translate_global(&mut self, g: Global, s: &mut GlobalSection) -> Result<()> { + global(self.as_obj(), g, s) + } + + fn translate_init_expr(&mut self, e: &InitExpr<'_>) -> Result> { + init_expr(self.as_obj(), e) + } + + fn translate_element( + &mut self, + e: wasmparser::Element<'_>, + s: &mut ElementSection, + ) -> Result<()> { + element(self.as_obj(), e, s) + } + + fn translate_data(&mut self, d: wasmparser::Data<'_>, s: &mut DataSection) -> Result<()> { + data(self.as_obj(), d, s) + } + + fn translate_code(&mut self, body: FunctionBody<'_>, s: &mut CodeSection) -> Result<()> { + code(self.as_obj(), body, s) + } + + fn translate_op(&mut self, e: &Operator<'_>) -> Result> { + op(self.as_obj(), e) + } + + fn translate_block_type(&mut self, ty: &TypeOrFuncType) -> Result { + block_type(self.as_obj(), ty) + } + + fn translate_memarg(&mut self, arg: &MemoryImmediate) -> Result { + memarg(self.as_obj(), arg) + } + + fn remap(&mut self, item: Item, idx: u32) -> Result { + drop(item); + Ok(idx) + } +} + +pub struct DefaultTranslator; + +impl Translator for DefaultTranslator { + fn as_obj(&mut self) -> &mut dyn Translator { + self + } +} +pub fn type_def(t: &mut dyn Translator, ty: TypeDef, s: &mut TypeSection) -> Result<()> { + match ty { + TypeDef::Func(f) => { + s.function( + f.params + .iter() + .map(|ty| t.translate_ty(ty)) + .collect::>>()?, + f.returns + .iter() + .map(|ty| t.translate_ty(ty)) + .collect::>>()?, + ); + Ok(()) + } + + // Module linking is not supported at this time. + TypeDef::Instance(_) | TypeDef::Module(_) => Err(Error::no_mutations_applicable()), + } +} + +pub fn table_type( + t: &mut dyn Translator, + ty: &wasmparser::TableType, +) -> Result { + Ok(wasm_encoder::TableType { + element_type: t.translate_ty(&ty.element_type)?, + minimum: ty.initial, + maximum: ty.maximum, + }) +} + +pub fn memory_type( + _t: &mut dyn Translator, + ty: &wasmparser::MemoryType, +) -> Result { + Ok(wasm_encoder::MemoryType { + memory64: ty.memory64, + minimum: ty.initial, + maximum: ty.maximum, + }) +} + +pub fn global_type( + t: &mut dyn Translator, + ty: &wasmparser::GlobalType, +) -> Result { + Ok(wasm_encoder::GlobalType { + val_type: t.translate_ty(&ty.content_type)?, + mutable: ty.mutable, + }) +} + +pub fn tag_type(t: &mut dyn Translator, ty: &wasmparser::TagType) -> Result { + Ok(wasm_encoder::TagType { + kind: TagKind::Exception, + func_type_idx: t.remap(Item::Type, ty.type_index)?, + }) +} + +pub fn ty(_t: &mut dyn Translator, ty: &Type) -> Result { + match ty { + Type::I32 => Ok(ValType::I32), + Type::I64 => Ok(ValType::I64), + Type::F32 => Ok(ValType::F32), + Type::F64 => Ok(ValType::F64), + Type::V128 => Ok(ValType::V128), + Type::FuncRef => Ok(ValType::FuncRef), + Type::ExternRef => Ok(ValType::ExternRef), + + // not supported in wasm-encoder + Type::ExnRef => Err(Error::no_mutations_applicable()), + + // Shouldn't ever show up as these are used in different contexts + // within wasmparser. + Type::Func | Type::EmptyBlockType => Err(Error::no_mutations_applicable()), + } +} + +pub fn global(t: &mut dyn Translator, global: Global, s: &mut GlobalSection) -> Result<()> { + let ty = t.translate_global_type(&global.ty)?; + let insn = t.translate_init_expr(&global.init_expr)?; + s.global(ty, &insn); + Ok(()) +} + +pub fn init_expr(t: &mut dyn Translator, e: &InitExpr<'_>) -> Result> { + let mut e = e.get_operators_reader(); + let op = e.read()?; + let op = t.translate_op(&op)?; + match e.read()? { + Operator::End if e.eof() => {} + _ => return Err(Error::no_mutations_applicable()), + } + Ok(op) +} + +pub fn element( + t: &mut dyn Translator, + element: wasmparser::Element<'_>, + s: &mut ElementSection, +) -> Result<()> { + let offset; + let mode = match &element.kind { + ElementKind::Active { + table_index, + init_expr, + } => { + offset = t.translate_init_expr(init_expr)?; + ElementMode::Active { + table: Some(t.remap(Item::Table, *table_index)?), + offset: &offset, + } + } + ElementKind::Passive => ElementMode::Passive, + ElementKind::Declared => ElementMode::Declared, + }; + let element_type = t.translate_ty(&element.ty)?; + let mut functions = Vec::new(); + let mut exprs = Vec::new(); + let mut reader = element.items.get_items_reader()?; + for _ in 0..reader.get_count() { + match reader.read()? { + ElementItem::Func(idx) => { + functions.push(t.remap(Item::Function, idx)?); + } + ElementItem::Expr(expr) => match t.translate_init_expr(&expr)? { + Instruction::RefFunc(n) => { + exprs.push(wasm_encoder::Element::Func(n)); + } + Instruction::RefNull(_) => { + exprs.push(wasm_encoder::Element::Null); + } + _ => return Err(Error::no_mutations_applicable()), + }, + } + } + s.segment(ElementSegment { + mode, + element_type, + elements: if reader.uses_exprs() { + Elements::Expressions(&exprs) + } else { + Elements::Functions(&functions) + }, + }); + Ok(()) +} + +/// This is a pretty gnarly function that translates from `wasmparser` +/// operators to `wasm_encoder` operators. It's quite large because there's +/// quite a few wasm instructions. The theory though is that at least each +/// individual case is pretty self-contained. +pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result> { + use wasm_encoder::Instruction as I; + use wasmparser::Operator as O; + Ok(match op { + O::Unreachable => I::Unreachable, + O::Nop => I::Nop, + + O::Block { ty } => I::Block(t.translate_block_type(ty)?), + O::Loop { ty } => I::Loop(t.translate_block_type(ty)?), + O::If { ty } => I::If(t.translate_block_type(ty)?), + O::Else => I::Else, + + O::Try { ty } => I::Try(t.translate_block_type(ty)?), + O::Catch { index } => I::Catch(t.remap(Item::Tag, *index)?), + O::Throw { index } => I::Throw(t.remap(Item::Tag, *index)?), + O::Rethrow { relative_depth } => I::Rethrow(*relative_depth), + O::End => I::End, + O::Br { relative_depth } => I::Br(*relative_depth), + O::BrIf { relative_depth } => I::BrIf(*relative_depth), + O::BrTable { table } => I::BrTable( + table + .targets() + .collect::, wasmparser::BinaryReaderError>>()? + .into(), + table.default(), + ), + + O::Return => I::Return, + O::Call { function_index } => I::Call(t.remap(Item::Function, *function_index)?), + O::CallIndirect { index, table_index } => I::CallIndirect { + ty: t.remap(Item::Type, *index)?, + table: t.remap(Item::Table, *table_index)?, + }, + O::Delegate { relative_depth } => I::Delegate(*relative_depth), + O::CatchAll => I::CatchAll, + O::Drop => I::Drop, + O::Select => I::Select, + O::TypedSelect { ty } => I::TypedSelect(t.translate_ty(ty)?), + + O::LocalGet { local_index } => I::LocalGet(*local_index), + O::LocalSet { local_index } => I::LocalSet(*local_index), + O::LocalTee { local_index } => I::LocalTee(*local_index), + + O::GlobalGet { global_index } => I::GlobalGet(t.remap(Item::Global, *global_index)?), + O::GlobalSet { global_index } => I::GlobalSet(t.remap(Item::Global, *global_index)?), + + O::I32Load { memarg } => I::I32Load(t.translate_memarg(memarg)?), + O::I64Load { memarg } => I::I64Load(t.translate_memarg(memarg)?), + O::F32Load { memarg } => I::F32Load(t.translate_memarg(memarg)?), + O::F64Load { memarg } => I::F64Load(t.translate_memarg(memarg)?), + O::I32Load8S { memarg } => I::I32Load8_S(t.translate_memarg(memarg)?), + O::I32Load8U { memarg } => I::I32Load8_U(t.translate_memarg(memarg)?), + O::I32Load16S { memarg } => I::I32Load16_S(t.translate_memarg(memarg)?), + O::I32Load16U { memarg } => I::I32Load16_U(t.translate_memarg(memarg)?), + O::I64Load8S { memarg } => I::I64Load8_S(t.translate_memarg(memarg)?), + O::I64Load8U { memarg } => I::I64Load8_U(t.translate_memarg(memarg)?), + O::I64Load16S { memarg } => I::I64Load16_S(t.translate_memarg(memarg)?), + O::I64Load16U { memarg } => I::I64Load16_U(t.translate_memarg(memarg)?), + O::I64Load32S { memarg } => I::I64Load32_S(t.translate_memarg(memarg)?), + O::I64Load32U { memarg } => I::I64Load32_U(t.translate_memarg(memarg)?), + O::I32Store { memarg } => I::I32Store(t.translate_memarg(memarg)?), + O::I64Store { memarg } => I::I64Store(t.translate_memarg(memarg)?), + O::F32Store { memarg } => I::F32Store(t.translate_memarg(memarg)?), + O::F64Store { memarg } => I::F64Store(t.translate_memarg(memarg)?), + O::I32Store8 { memarg } => I::I32Store8(t.translate_memarg(memarg)?), + O::I32Store16 { memarg } => I::I32Store16(t.translate_memarg(memarg)?), + O::I64Store8 { memarg } => I::I64Store8(t.translate_memarg(memarg)?), + O::I64Store16 { memarg } => I::I64Store16(t.translate_memarg(memarg)?), + O::I64Store32 { memarg } => I::I64Store32(t.translate_memarg(memarg)?), + + O::MemorySize { mem, .. } => I::MemorySize(t.remap(Item::Memory, *mem)?), + O::MemoryGrow { mem, .. } => I::MemoryGrow(t.remap(Item::Memory, *mem)?), + + O::I32Const { value } => I::I32Const(*value), + O::I64Const { value } => I::I64Const(*value), + O::F32Const { value } => I::F32Const(f32::from_bits(value.bits())), + O::F64Const { value } => I::F64Const(f64::from_bits(value.bits())), + + O::RefNull { ty } => I::RefNull(t.translate_ty(ty)?), + O::RefIsNull => I::RefIsNull, + O::RefFunc { function_index } => I::RefFunc(t.remap(Item::Function, *function_index)?), + + O::I32Eqz => I::I32Eqz, + O::I32Eq => I::I32Eq, + O::I32Ne => I::I32Ne, + O::I32LtS => I::I32LtS, + O::I32LtU => I::I32LtU, + O::I32GtS => I::I32GtS, + O::I32GtU => I::I32GtU, + O::I32LeS => I::I32LeS, + O::I32LeU => I::I32LeU, + O::I32GeS => I::I32GeS, + O::I32GeU => I::I32GeU, + O::I64Eqz => I::I64Eqz, + O::I64Eq => I::I64Eq, + O::I64Ne => I::I64Ne, + O::I64LtS => I::I64LtS, + O::I64LtU => I::I64LtU, + O::I64GtS => I::I64GtS, + O::I64GtU => I::I64GtU, + O::I64LeS => I::I64LeS, + O::I64LeU => I::I64LeU, + O::I64GeS => I::I64GeS, + O::I64GeU => I::I64GeU, + O::F32Eq => I::F32Eq, + O::F32Ne => I::F32Ne, + O::F32Lt => I::F32Lt, + O::F32Gt => I::F32Gt, + O::F32Le => I::F32Le, + O::F32Ge => I::F32Ge, + O::F64Eq => I::F64Eq, + O::F64Ne => I::F64Ne, + O::F64Lt => I::F64Lt, + O::F64Gt => I::F64Gt, + O::F64Le => I::F64Le, + O::F64Ge => I::F64Ge, + O::I32Clz => I::I32Clz, + O::I32Ctz => I::I32Ctz, + O::I32Popcnt => I::I32Popcnt, + O::I32Add => I::I32Add, + O::I32Sub => I::I32Sub, + O::I32Mul => I::I32Mul, + O::I32DivS => I::I32DivS, + O::I32DivU => I::I32DivU, + O::I32RemS => I::I32RemS, + O::I32RemU => I::I32RemU, + O::I32And => I::I32And, + O::I32Or => I::I32Or, + O::I32Xor => I::I32Xor, + O::I32Shl => I::I32Shl, + O::I32ShrS => I::I32ShrS, + O::I32ShrU => I::I32ShrU, + O::I32Rotl => I::I32Rotl, + O::I32Rotr => I::I32Rotr, + O::I64Clz => I::I64Clz, + O::I64Ctz => I::I64Ctz, + O::I64Popcnt => I::I64Popcnt, + O::I64Add => I::I64Add, + O::I64Sub => I::I64Sub, + O::I64Mul => I::I64Mul, + O::I64DivS => I::I64DivS, + O::I64DivU => I::I64DivU, + O::I64RemS => I::I64RemS, + O::I64RemU => I::I64RemU, + O::I64And => I::I64And, + O::I64Or => I::I64Or, + O::I64Xor => I::I64Xor, + O::I64Shl => I::I64Shl, + O::I64ShrS => I::I64ShrS, + O::I64ShrU => I::I64ShrU, + O::I64Rotl => I::I64Rotl, + O::I64Rotr => I::I64Rotr, + O::F32Abs => I::F32Abs, + O::F32Neg => I::F32Neg, + O::F32Ceil => I::F32Ceil, + O::F32Floor => I::F32Floor, + O::F32Trunc => I::F32Trunc, + O::F32Nearest => I::F32Nearest, + O::F32Sqrt => I::F32Sqrt, + O::F32Add => I::F32Add, + O::F32Sub => I::F32Sub, + O::F32Mul => I::F32Mul, + O::F32Div => I::F32Div, + O::F32Min => I::F32Min, + O::F32Max => I::F32Max, + O::F32Copysign => I::F32Copysign, + O::F64Abs => I::F64Abs, + O::F64Neg => I::F64Neg, + O::F64Ceil => I::F64Ceil, + O::F64Floor => I::F64Floor, + O::F64Trunc => I::F64Trunc, + O::F64Nearest => I::F64Nearest, + O::F64Sqrt => I::F64Sqrt, + O::F64Add => I::F64Add, + O::F64Sub => I::F64Sub, + O::F64Mul => I::F64Mul, + O::F64Div => I::F64Div, + O::F64Min => I::F64Min, + O::F64Max => I::F64Max, + O::F64Copysign => I::F64Copysign, + O::I32WrapI64 => I::I32WrapI64, + O::I32TruncF32S => I::I32TruncF32S, + O::I32TruncF32U => I::I32TruncF32U, + O::I32TruncF64S => I::I32TruncF64S, + O::I32TruncF64U => I::I32TruncF64U, + O::I64ExtendI32S => I::I64ExtendI32S, + O::I64ExtendI32U => I::I64ExtendI32U, + O::I64TruncF32S => I::I64TruncF32S, + O::I64TruncF32U => I::I64TruncF32U, + O::I64TruncF64S => I::I64TruncF64S, + O::I64TruncF64U => I::I64TruncF64U, + O::F32ConvertI32S => I::F32ConvertI32S, + O::F32ConvertI32U => I::F32ConvertI32U, + O::F32ConvertI64S => I::F32ConvertI64S, + O::F32ConvertI64U => I::F32ConvertI64U, + O::F32DemoteF64 => I::F32DemoteF64, + O::F64ConvertI32S => I::F64ConvertI32S, + O::F64ConvertI32U => I::F64ConvertI32U, + O::F64ConvertI64S => I::F64ConvertI64S, + O::F64ConvertI64U => I::F64ConvertI64U, + O::F64PromoteF32 => I::F64PromoteF32, + O::I32ReinterpretF32 => I::I32ReinterpretF32, + O::I64ReinterpretF64 => I::I64ReinterpretF64, + O::F32ReinterpretI32 => I::F32ReinterpretI32, + O::F64ReinterpretI64 => I::F64ReinterpretI64, + O::I32Extend8S => I::I32Extend8S, + O::I32Extend16S => I::I32Extend16S, + O::I64Extend8S => I::I64Extend8S, + O::I64Extend16S => I::I64Extend16S, + O::I64Extend32S => I::I64Extend32S, + + O::I32TruncSatF32S => I::I32TruncSatF32S, + O::I32TruncSatF32U => I::I32TruncSatF32U, + O::I32TruncSatF64S => I::I32TruncSatF64S, + O::I32TruncSatF64U => I::I32TruncSatF64U, + O::I64TruncSatF32S => I::I64TruncSatF32S, + O::I64TruncSatF32U => I::I64TruncSatF32U, + O::I64TruncSatF64S => I::I64TruncSatF64S, + O::I64TruncSatF64U => I::I64TruncSatF64U, + + O::MemoryInit { segment, mem } => I::MemoryInit { + data: t.remap(Item::Data, *segment)?, + mem: t.remap(Item::Memory, *mem)?, + }, + O::DataDrop { segment } => I::DataDrop(t.remap(Item::Data, *segment)?), + O::MemoryCopy { src, dst } => I::MemoryCopy { + src: t.remap(Item::Memory, *src)?, + dst: t.remap(Item::Memory, *dst)?, + }, + O::MemoryFill { mem, .. } => I::MemoryFill(t.remap(Item::Memory, *mem)?), + + O::TableInit { segment, table } => I::TableInit { + segment: t.remap(Item::Element, *segment)?, + table: t.remap(Item::Table, *table)?, + }, + O::ElemDrop { segment } => I::ElemDrop { + segment: t.remap(Item::Element, *segment)?, + }, + O::TableCopy { + dst_table, + src_table, + } => I::TableCopy { + dst: t.remap(Item::Table, *dst_table)?, + src: t.remap(Item::Table, *src_table)?, + }, + O::TableFill { table } => I::TableFill { + table: t.remap(Item::Table, *table)?, + }, + O::TableGet { table } => I::TableGet { + table: t.remap(Item::Table, *table)?, + }, + O::TableSet { table } => I::TableSet { + table: t.remap(Item::Table, *table)?, + }, + O::TableGrow { table } => I::TableGrow { + table: t.remap(Item::Table, *table)?, + }, + O::TableSize { table } => I::TableSize { + table: t.remap(Item::Table, *table)?, + }, + + O::V128Load { memarg } => I::V128Load { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load8x8S { memarg } => I::V128Load8x8S { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load8x8U { memarg } => I::V128Load8x8U { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load16x4S { memarg } => I::V128Load16x4S { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load16x4U { memarg } => I::V128Load16x4U { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load32x2S { memarg } => I::V128Load32x2S { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load32x2U { memarg } => I::V128Load32x2U { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load8Splat { memarg } => I::V128Load8Splat { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load16Splat { memarg } => I::V128Load16Splat { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load32Splat { memarg } => I::V128Load32Splat { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load64Splat { memarg } => I::V128Load64Splat { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load32Zero { memarg } => I::V128Load32Zero { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load64Zero { memarg } => I::V128Load64Zero { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Store { memarg } => I::V128Store { + memarg: t.translate_memarg(memarg)?, + }, + O::V128Load8Lane { memarg, lane } => I::V128Load8Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Load16Lane { memarg, lane } => I::V128Load16Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Load32Lane { memarg, lane } => I::V128Load32Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Load64Lane { memarg, lane } => I::V128Load64Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Store8Lane { memarg, lane } => I::V128Store8Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Store16Lane { memarg, lane } => I::V128Store16Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Store32Lane { memarg, lane } => I::V128Store32Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + O::V128Store64Lane { memarg, lane } => I::V128Store64Lane { + memarg: t.translate_memarg(memarg)?, + lane: *lane, + }, + + O::V128Const { value } => I::V128Const(value.i128()), + O::I8x16Shuffle { lanes } => I::I8x16Shuffle { lanes: *lanes }, + O::I8x16ExtractLaneS { lane } => I::I8x16ExtractLaneS { lane: *lane }, + O::I8x16ExtractLaneU { lane } => I::I8x16ExtractLaneU { lane: *lane }, + O::I8x16ReplaceLane { lane } => I::I8x16ReplaceLane { lane: *lane }, + O::I16x8ExtractLaneS { lane } => I::I16x8ExtractLaneS { lane: *lane }, + O::I16x8ExtractLaneU { lane } => I::I16x8ExtractLaneU { lane: *lane }, + O::I16x8ReplaceLane { lane } => I::I16x8ReplaceLane { lane: *lane }, + O::I32x4ExtractLane { lane } => I::I32x4ExtractLane { lane: *lane }, + O::I32x4ReplaceLane { lane } => I::I32x4ReplaceLane { lane: *lane }, + O::I64x2ExtractLane { lane } => I::I64x2ExtractLane { lane: *lane }, + O::I64x2ReplaceLane { lane } => I::I64x2ReplaceLane { lane: *lane }, + O::F32x4ExtractLane { lane } => I::F32x4ExtractLane { lane: *lane }, + O::F32x4ReplaceLane { lane } => I::F32x4ReplaceLane { lane: *lane }, + O::F64x2ExtractLane { lane } => I::F64x2ExtractLane { lane: *lane }, + O::F64x2ReplaceLane { lane } => I::F64x2ReplaceLane { lane: *lane }, + + O::I8x16Swizzle => I::I8x16Swizzle, + O::I8x16Splat => I::I8x16Splat, + O::I16x8Splat => I::I16x8Splat, + O::I32x4Splat => I::I32x4Splat, + O::I64x2Splat => I::I64x2Splat, + O::F32x4Splat => I::F32x4Splat, + O::F64x2Splat => I::F64x2Splat, + O::I8x16Eq => I::I8x16Eq, + O::I8x16Ne => I::I8x16Ne, + O::I8x16LtS => I::I8x16LtS, + O::I8x16LtU => I::I8x16LtU, + O::I8x16GtS => I::I8x16GtS, + O::I8x16GtU => I::I8x16GtU, + O::I8x16LeS => I::I8x16LeS, + O::I8x16LeU => I::I8x16LeU, + O::I8x16GeS => I::I8x16GeS, + O::I8x16GeU => I::I8x16GeU, + O::I16x8Eq => I::I16x8Eq, + O::I16x8Ne => I::I16x8Ne, + O::I16x8LtS => I::I16x8LtS, + O::I16x8LtU => I::I16x8LtU, + O::I16x8GtS => I::I16x8GtS, + O::I16x8GtU => I::I16x8GtU, + O::I16x8LeS => I::I16x8LeS, + O::I16x8LeU => I::I16x8LeU, + O::I16x8GeS => I::I16x8GeS, + O::I16x8GeU => I::I16x8GeU, + O::I32x4Eq => I::I32x4Eq, + O::I32x4Ne => I::I32x4Ne, + O::I32x4LtS => I::I32x4LtS, + O::I32x4LtU => I::I32x4LtU, + O::I32x4GtS => I::I32x4GtS, + O::I32x4GtU => I::I32x4GtU, + O::I32x4LeS => I::I32x4LeS, + O::I32x4LeU => I::I32x4LeU, + O::I32x4GeS => I::I32x4GeS, + O::I32x4GeU => I::I32x4GeU, + O::I64x2Eq => I::I64x2Eq, + O::I64x2Ne => I::I64x2Ne, + O::I64x2LtS => I::I64x2LtS, + O::I64x2GtS => I::I64x2GtS, + O::I64x2LeS => I::I64x2LeS, + O::I64x2GeS => I::I64x2GeS, + O::F32x4Eq => I::F32x4Eq, + O::F32x4Ne => I::F32x4Ne, + O::F32x4Lt => I::F32x4Lt, + O::F32x4Gt => I::F32x4Gt, + O::F32x4Le => I::F32x4Le, + O::F32x4Ge => I::F32x4Ge, + O::F64x2Eq => I::F64x2Eq, + O::F64x2Ne => I::F64x2Ne, + O::F64x2Lt => I::F64x2Lt, + O::F64x2Gt => I::F64x2Gt, + O::F64x2Le => I::F64x2Le, + O::F64x2Ge => I::F64x2Ge, + O::V128Not => I::V128Not, + O::V128And => I::V128And, + O::V128AndNot => I::V128AndNot, + O::V128Or => I::V128Or, + O::V128Xor => I::V128Xor, + O::V128Bitselect => I::V128Bitselect, + O::V128AnyTrue => I::V128AnyTrue, + O::I8x16Abs => I::I8x16Abs, + O::I8x16Neg => I::I8x16Neg, + O::I8x16Popcnt => I::I8x16Popcnt, + O::I8x16AllTrue => I::I8x16AllTrue, + O::I8x16Bitmask => I::I8x16Bitmask, + O::I8x16NarrowI16x8S => I::I8x16NarrowI16x8S, + O::I8x16NarrowI16x8U => I::I8x16NarrowI16x8U, + O::I8x16Shl => I::I8x16Shl, + O::I8x16ShrS => I::I8x16ShrS, + O::I8x16ShrU => I::I8x16ShrU, + O::I8x16Add => I::I8x16Add, + O::I8x16AddSatS => I::I8x16AddSatS, + O::I8x16AddSatU => I::I8x16AddSatU, + O::I8x16Sub => I::I8x16Sub, + O::I8x16SubSatS => I::I8x16SubSatS, + O::I8x16SubSatU => I::I8x16SubSatU, + O::I8x16MinS => I::I8x16MinS, + O::I8x16MinU => I::I8x16MinU, + O::I8x16MaxS => I::I8x16MaxS, + O::I8x16MaxU => I::I8x16MaxU, + O::I8x16RoundingAverageU => I::I8x16RoundingAverageU, + O::I16x8ExtAddPairwiseI8x16S => I::I16x8ExtAddPairwiseI8x16S, + O::I16x8ExtAddPairwiseI8x16U => I::I16x8ExtAddPairwiseI8x16U, + O::I16x8Abs => I::I16x8Abs, + O::I16x8Neg => I::I16x8Neg, + O::I16x8Q15MulrSatS => I::I16x8Q15MulrSatS, + O::I16x8AllTrue => I::I16x8AllTrue, + O::I16x8Bitmask => I::I16x8Bitmask, + O::I16x8NarrowI32x4S => I::I16x8NarrowI32x4S, + O::I16x8NarrowI32x4U => I::I16x8NarrowI32x4U, + O::I16x8ExtendLowI8x16S => I::I16x8ExtendLowI8x16S, + O::I16x8ExtendHighI8x16S => I::I16x8ExtendHighI8x16S, + O::I16x8ExtendLowI8x16U => I::I16x8ExtendLowI8x16U, + O::I16x8ExtendHighI8x16U => I::I16x8ExtendHighI8x16U, + O::I16x8Shl => I::I16x8Shl, + O::I16x8ShrS => I::I16x8ShrS, + O::I16x8ShrU => I::I16x8ShrU, + O::I16x8Add => I::I16x8Add, + O::I16x8AddSatS => I::I16x8AddSatS, + O::I16x8AddSatU => I::I16x8AddSatU, + O::I16x8Sub => I::I16x8Sub, + O::I16x8SubSatS => I::I16x8SubSatS, + O::I16x8SubSatU => I::I16x8SubSatU, + O::I16x8Mul => I::I16x8Mul, + O::I16x8MinS => I::I16x8MinS, + O::I16x8MinU => I::I16x8MinU, + O::I16x8MaxS => I::I16x8MaxS, + O::I16x8MaxU => I::I16x8MaxU, + O::I16x8RoundingAverageU => I::I16x8RoundingAverageU, + O::I16x8ExtMulLowI8x16S => I::I16x8ExtMulLowI8x16S, + O::I16x8ExtMulHighI8x16S => I::I16x8ExtMulHighI8x16S, + O::I16x8ExtMulLowI8x16U => I::I16x8ExtMulLowI8x16U, + O::I16x8ExtMulHighI8x16U => I::I16x8ExtMulHighI8x16U, + O::I32x4ExtAddPairwiseI16x8S => I::I32x4ExtAddPairwiseI16x8S, + O::I32x4ExtAddPairwiseI16x8U => I::I32x4ExtAddPairwiseI16x8U, + O::I32x4Abs => I::I32x4Abs, + O::I32x4Neg => I::I32x4Neg, + O::I32x4AllTrue => I::I32x4AllTrue, + O::I32x4Bitmask => I::I32x4Bitmask, + O::I32x4ExtendLowI16x8S => I::I32x4ExtendLowI16x8S, + O::I32x4ExtendHighI16x8S => I::I32x4ExtendHighI16x8S, + O::I32x4ExtendLowI16x8U => I::I32x4ExtendLowI16x8U, + O::I32x4ExtendHighI16x8U => I::I32x4ExtendHighI16x8U, + O::I32x4Shl => I::I32x4Shl, + O::I32x4ShrS => I::I32x4ShrS, + O::I32x4ShrU => I::I32x4ShrU, + O::I32x4Add => I::I32x4Add, + O::I32x4Sub => I::I32x4Sub, + O::I32x4Mul => I::I32x4Mul, + O::I32x4MinS => I::I32x4MinS, + O::I32x4MinU => I::I32x4MinU, + O::I32x4MaxS => I::I32x4MaxS, + O::I32x4MaxU => I::I32x4MaxU, + O::I32x4DotI16x8S => I::I32x4DotI16x8S, + O::I32x4ExtMulLowI16x8S => I::I32x4ExtMulLowI16x8S, + O::I32x4ExtMulHighI16x8S => I::I32x4ExtMulHighI16x8S, + O::I32x4ExtMulLowI16x8U => I::I32x4ExtMulLowI16x8U, + O::I32x4ExtMulHighI16x8U => I::I32x4ExtMulHighI16x8U, + O::I64x2Abs => I::I64x2Abs, + O::I64x2Neg => I::I64x2Neg, + O::I64x2AllTrue => I::I64x2AllTrue, + O::I64x2Bitmask => I::I64x2Bitmask, + O::I64x2ExtendLowI32x4S => I::I64x2ExtendLowI32x4S, + O::I64x2ExtendHighI32x4S => I::I64x2ExtendHighI32x4S, + O::I64x2ExtendLowI32x4U => I::I64x2ExtendLowI32x4U, + O::I64x2ExtendHighI32x4U => I::I64x2ExtendHighI32x4U, + O::I64x2Shl => I::I64x2Shl, + O::I64x2ShrS => I::I64x2ShrS, + O::I64x2ShrU => I::I64x2ShrU, + O::I64x2Add => I::I64x2Add, + O::I64x2Sub => I::I64x2Sub, + O::I64x2Mul => I::I64x2Mul, + O::I64x2ExtMulLowI32x4S => I::I64x2ExtMulLowI32x4S, + O::I64x2ExtMulHighI32x4S => I::I64x2ExtMulHighI32x4S, + O::I64x2ExtMulLowI32x4U => I::I64x2ExtMulLowI32x4U, + O::I64x2ExtMulHighI32x4U => I::I64x2ExtMulHighI32x4U, + O::F32x4Ceil => I::F32x4Ceil, + O::F32x4Floor => I::F32x4Floor, + O::F32x4Trunc => I::F32x4Trunc, + O::F32x4Nearest => I::F32x4Nearest, + O::F32x4Abs => I::F32x4Abs, + O::F32x4Neg => I::F32x4Neg, + O::F32x4Sqrt => I::F32x4Sqrt, + O::F32x4Add => I::F32x4Add, + O::F32x4Sub => I::F32x4Sub, + O::F32x4Mul => I::F32x4Mul, + O::F32x4Div => I::F32x4Div, + O::F32x4Min => I::F32x4Min, + O::F32x4Max => I::F32x4Max, + O::F32x4PMin => I::F32x4PMin, + O::F32x4PMax => I::F32x4PMax, + O::F64x2Ceil => I::F64x2Ceil, + O::F64x2Floor => I::F64x2Floor, + O::F64x2Trunc => I::F64x2Trunc, + O::F64x2Nearest => I::F64x2Nearest, + O::F64x2Abs => I::F64x2Abs, + O::F64x2Neg => I::F64x2Neg, + O::F64x2Sqrt => I::F64x2Sqrt, + O::F64x2Add => I::F64x2Add, + O::F64x2Sub => I::F64x2Sub, + O::F64x2Mul => I::F64x2Mul, + O::F64x2Div => I::F64x2Div, + O::F64x2Min => I::F64x2Min, + O::F64x2Max => I::F64x2Max, + O::F64x2PMin => I::F64x2PMin, + O::F64x2PMax => I::F64x2PMax, + O::I32x4TruncSatF32x4S => I::I32x4TruncSatF32x4S, + O::I32x4TruncSatF32x4U => I::I32x4TruncSatF32x4U, + O::F32x4ConvertI32x4S => I::F32x4ConvertI32x4S, + O::F32x4ConvertI32x4U => I::F32x4ConvertI32x4U, + O::I32x4TruncSatF64x2SZero => I::I32x4TruncSatF64x2SZero, + O::I32x4TruncSatF64x2UZero => I::I32x4TruncSatF64x2UZero, + O::F64x2ConvertLowI32x4S => I::F64x2ConvertLowI32x4S, + O::F64x2ConvertLowI32x4U => I::F64x2ConvertLowI32x4U, + O::F32x4DemoteF64x2Zero => I::F32x4DemoteF64x2Zero, + O::F64x2PromoteLowF32x4 => I::F64x2PromoteLowF32x4, + O::I8x16SwizzleRelaxed => I::I8x16SwizzleRelaxed, + O::I32x4TruncSatF32x4SRelaxed => I::I32x4TruncSatF32x4SRelaxed, + O::I32x4TruncSatF32x4URelaxed => I::I32x4TruncSatF32x4URelaxed, + O::I32x4TruncSatF64x2SZeroRelaxed => I::I32x4TruncSatF64x2SZeroRelaxed, + O::I32x4TruncSatF64x2UZeroRelaxed => I::I32x4TruncSatF64x2UZeroRelaxed, + O::F32x4FmaRelaxed => I::F32x4FmaRelaxed, + O::F32x4FmsRelaxed => I::F32x4FmsRelaxed, + O::F64x2FmaRelaxed => I::F64x2FmaRelaxed, + O::F64x2FmsRelaxed => I::F64x2FmsRelaxed, + O::I8x16LaneSelect => I::I8x16LaneSelect, + O::I16x8LaneSelect => I::I16x8LaneSelect, + O::I32x4LaneSelect => I::I32x4LaneSelect, + O::I64x2LaneSelect => I::I64x2LaneSelect, + O::F32x4MinRelaxed => I::F32x4MinRelaxed, + O::F32x4MaxRelaxed => I::F32x4MaxRelaxed, + O::F64x2MinRelaxed => I::F64x2MinRelaxed, + O::F64x2MaxRelaxed => I::F64x2MaxRelaxed, + + // Note that these cases are not supported in `wasm_encoder` yet, + // and in general `wasmparser` often parses more things than + // `wasm_encoder` supports. If these are seen we simply say that + // this mutation isn't applicable because `wasm-encoder` can't + // create the new function anyway. + O::MemoryAtomicNotify { .. } + | O::MemoryAtomicWait32 { .. } + | O::MemoryAtomicWait64 { .. } + | O::I32AtomicLoad { .. } + | O::I64AtomicLoad { .. } + | O::I32AtomicLoad8U { .. } + | O::I32AtomicLoad16U { .. } + | O::I64AtomicLoad8U { .. } + | O::I64AtomicLoad16U { .. } + | O::I64AtomicLoad32U { .. } + | O::I32AtomicStore { .. } + | O::I64AtomicStore { .. } + | O::I32AtomicStore8 { .. } + | O::I32AtomicStore16 { .. } + | O::I64AtomicStore8 { .. } + | O::I64AtomicStore16 { .. } + | O::I64AtomicStore32 { .. } + | O::I32AtomicRmwAdd { .. } + | O::I64AtomicRmwAdd { .. } + | O::I32AtomicRmw8AddU { .. } + | O::I32AtomicRmw16AddU { .. } + | O::I64AtomicRmw8AddU { .. } + | O::I64AtomicRmw16AddU { .. } + | O::I64AtomicRmw32AddU { .. } + | O::I32AtomicRmwSub { .. } + | O::I64AtomicRmwSub { .. } + | O::I32AtomicRmw8SubU { .. } + | O::I32AtomicRmw16SubU { .. } + | O::I64AtomicRmw8SubU { .. } + | O::I64AtomicRmw16SubU { .. } + | O::I64AtomicRmw32SubU { .. } + | O::I32AtomicRmwAnd { .. } + | O::I64AtomicRmwAnd { .. } + | O::I32AtomicRmw8AndU { .. } + | O::I32AtomicRmw16AndU { .. } + | O::I64AtomicRmw8AndU { .. } + | O::I64AtomicRmw16AndU { .. } + | O::I64AtomicRmw32AndU { .. } + | O::I32AtomicRmwOr { .. } + | O::I64AtomicRmwOr { .. } + | O::I32AtomicRmw8OrU { .. } + | O::I32AtomicRmw16OrU { .. } + | O::I64AtomicRmw8OrU { .. } + | O::I64AtomicRmw16OrU { .. } + | O::I64AtomicRmw32OrU { .. } + | O::I32AtomicRmwXor { .. } + | O::I64AtomicRmwXor { .. } + | O::I32AtomicRmw8XorU { .. } + | O::I32AtomicRmw16XorU { .. } + | O::I64AtomicRmw8XorU { .. } + | O::I64AtomicRmw16XorU { .. } + | O::I64AtomicRmw32XorU { .. } + | O::I32AtomicRmwXchg { .. } + | O::I64AtomicRmwXchg { .. } + | O::I32AtomicRmw8XchgU { .. } + | O::I32AtomicRmw16XchgU { .. } + | O::I64AtomicRmw8XchgU { .. } + | O::I64AtomicRmw16XchgU { .. } + | O::I64AtomicRmw32XchgU { .. } + | O::I32AtomicRmwCmpxchg { .. } + | O::I64AtomicRmwCmpxchg { .. } + | O::I32AtomicRmw8CmpxchgU { .. } + | O::I32AtomicRmw16CmpxchgU { .. } + | O::I64AtomicRmw8CmpxchgU { .. } + | O::I64AtomicRmw16CmpxchgU { .. } + | O::I64AtomicRmw32CmpxchgU { .. } + | O::ReturnCall { .. } + | O::ReturnCallIndirect { .. } + | O::AtomicFence { .. } => return Err(Error::no_mutations_applicable()), + }) +} + +pub fn block_type(t: &mut dyn Translator, ty: &TypeOrFuncType) -> Result { + match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) => Ok(BlockType::Empty), + TypeOrFuncType::Type(ty) => Ok(BlockType::Result(t.translate_ty(ty)?)), + TypeOrFuncType::FuncType(f) => Ok(BlockType::FunctionType(t.remap(Item::Type, *f)?)), + } +} + +pub fn memarg(t: &mut dyn Translator, memarg: &MemoryImmediate) -> Result { + Ok(MemArg { + offset: memarg.offset, + align: memarg.align.into(), + memory_index: t.remap(Item::Memory, memarg.memory)?, + }) +} + +pub fn data(t: &mut dyn Translator, data: wasmparser::Data<'_>, s: &mut DataSection) -> Result<()> { + let offset; + let mode = match &data.kind { + DataKind::Active { + memory_index, + init_expr, + } => { + offset = t.translate_init_expr(init_expr)?; + DataSegmentMode::Active { + memory_index: t.remap(Item::Memory, *memory_index)?, + offset: &offset, + } + } + DataKind::Passive => DataSegmentMode::Passive, + }; + s.segment(DataSegment { + mode, + data: data.data.iter().copied(), + }); + Ok(()) +} + +pub fn code(t: &mut dyn Translator, body: FunctionBody<'_>, s: &mut CodeSection) -> Result<()> { + let locals = body + .get_locals_reader()? + .into_iter() + .map(|local| { + let (cnt, ty) = local?; + Ok((cnt, t.translate_ty(&ty)?)) + }) + .collect::>>()?; + let mut func = Function::new(locals); + + for op in body.get_operators_reader()? { + let op = op?; + func.instruction(&t.translate_op(&op)?); + } + s.function(&func); + Ok(()) +}