From 7d4dfd8ec65c78eb8154d89aa77dd71ac65015f6 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 5 Apr 2026 20:49:40 +0200 Subject: chore: cleanup --- crates/parser/src/conversion.rs | 77 ++++++++----------- crates/parser/src/lib.rs | 81 +++++++------------- crates/parser/src/module.rs | 89 ++++++++-------------- crates/parser/src/visit.rs | 32 ++------ crates/tinywasm/Cargo.toml | 4 - crates/tinywasm/src/imports.rs | 27 +++---- crates/tinywasm/src/instance.rs | 46 +++-------- crates/tinywasm/src/interpreter/executor.rs | 10 +-- .../tinywasm/src/interpreter/stack/call_stack.rs | 6 +- .../tinywasm/src/interpreter/stack/value_stack.rs | 8 +- crates/tinywasm/src/module.rs | 9 +-- crates/types/src/instructions.rs | 4 +- crates/types/src/lib.rs | 36 ++------- 13 files changed, 142 insertions(+), 287 deletions(-) diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index b62e670..570d0a1 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -70,38 +70,33 @@ pub(crate) fn convert_module_imports<'a, T: IntoIterator) -> Result { - Ok(Import { - module: import.module.to_string().into_boxed_str(), - name: import.name.to_string().into_boxed_str(), - kind: match import.ty { - wasmparser::TypeRef::Func(ty) => ImportKind::Function(ty), - wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType { - element_type: convert_reftype(ty.element_type), - size_initial: ty.initial.try_into().map_err(|_| { - crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial)) - })?, - size_max: match ty.maximum { - Some(max) => Some(max.try_into().map_err(|_| { - crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {max}")) - })?), - None => None, - }, - }), - wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)), - wasmparser::TypeRef::Global(ty) => { - ImportKind::Global(GlobalType { mutable: ty.mutable, ty: convert_valtype(&ty.content_type) }) - } - wasmparser::TypeRef::Tag(ty) => { - return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {ty:?}"))); - } - _ => { - return Err(crate::ParseError::UnsupportedOperator(format!( - "Unsupported import kind: {:?}", - import.ty - ))); - } - }, - }) + let kind = match import.ty { + wasmparser::TypeRef::Func(ty) => ImportKind::Function(ty), + wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType { + element_type: convert_reftype(ty.element_type), + size_initial: ty.initial.try_into().map_err(|_| { + crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial)) + })?, + size_max: match ty.maximum { + Some(max) => Some(max.try_into().map_err(|_| { + crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {max}")) + })?), + None => None, + }, + }), + wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)), + wasmparser::TypeRef::Global(ty) => { + ImportKind::Global(GlobalType { mutable: ty.mutable, ty: convert_valtype(&ty.content_type) }) + } + wasmparser::TypeRef::Tag(ty) => { + return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {ty:?}"))); + } + _ => { + return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {:?}", import.ty))); + } + }; + + Ok(Import { module: import.module.into(), name: import.name.into(), kind }) } pub(crate) fn convert_module_memories>>( @@ -130,21 +125,16 @@ pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result Some( - max.try_into() - .map_err(|_| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {max}")))?, - ), - None => None, - }; - + let size_max = table.ty.maximum.map(|max| max.try_into()).transpose(); + let size_max = + size_max.map_err(|e| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {e}")))?; Ok(TableType { element_type: convert_reftype(table.ty.element_type), size_initial, size_max }) } pub(crate) fn convert_module_globals( globals: wasmparser::SectionLimited<'_, wasmparser::Global<'_>>, ) -> Result> { - let globals = globals + globals .into_iter() .map(|global| { let global = global?; @@ -152,8 +142,7 @@ pub(crate) fn convert_module_globals( let ops = global.init_expr.get_operators_reader(); Ok(Global { init: process_const_operators(ops)?, ty: GlobalType { mutable: global.ty.mutable, ty } }) }) - .collect::>>()?; - Ok(globals) + .collect::>>() } pub(crate) fn convert_module_export(export: wasmparser::Export<'_>) -> Result { @@ -215,7 +204,6 @@ pub(crate) fn convert_module_code( pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result { let mut types = ty.types(); - if types.len() != 1 { return Err(crate::ParseError::UnsupportedOperator( "Expected exactly one type in the type section".to_string(), @@ -225,7 +213,6 @@ pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result let ty = types.next().unwrap().unwrap_func(); let params = ty.params().iter().map(convert_valtype).collect::>().into_boxed_slice(); let results = ty.results().iter().map(convert_valtype).collect::>().into_boxed_slice(); - Ok(FuncType { params, results }) } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 2d46857..a0c0c7e 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -36,7 +36,7 @@ mod optimize; mod visit; pub use error::*; use module::ModuleReader; -use wasmparser::{Validator, WasmFeaturesInflated}; +use wasmparser::{Validator, WasmFeatures}; pub use tinywasm_types::TinyWasmModule; @@ -79,56 +79,32 @@ impl Parser { } fn create_validator(_options: ParserOptions) -> Validator { - let features = WasmFeaturesInflated { - bulk_memory: true, - floats: true, - multi_value: true, - mutable_global: true, - reference_types: true, - sign_extension: true, - saturating_float_to_int: true, - function_references: true, - tail_call: true, - multi_memory: true, - simd: true, - memory64: true, - custom_page_sizes: true, - bulk_memory_opt: true, - call_indirect_overlong: true, - wide_arithmetic: true, - relaxed_simd: true, - - compact_imports: false, - cm_map: false, - custom_descriptors: false, - cm_threading: false, - extended_const: false, - gc_types: true, - stack_switching: false, - component_model: false, - exceptions: false, - gc: false, - memory_control: false, - threads: false, - shared_everything_threads: false, - legacy_exceptions: false, - cm_async: false, - cm_async_builtins: false, - cm_async_stackful: false, - cm_nested_names: false, - cm_values: false, - cm_error_context: false, - cm_fixed_length_lists: false, - cm_gc: false, - }; - Validator::new_with_features(features.into()) + let features = WasmFeatures::CALL_INDIRECT_OVERLONG + | WasmFeatures::BULK_MEMORY_OPT + | WasmFeatures::RELAXED_SIMD + | WasmFeatures::GC_TYPES + | WasmFeatures::REFERENCE_TYPES + | WasmFeatures::MUTABLE_GLOBAL + | WasmFeatures::MULTI_VALUE + | WasmFeatures::FLOATS + | WasmFeatures::BULK_MEMORY + | WasmFeatures::SATURATING_FLOAT_TO_INT + | WasmFeatures::SIGN_EXTENSION + | WasmFeatures::FUNCTION_REFERENCES + | WasmFeatures::TAIL_CALL + | WasmFeatures::MULTI_MEMORY + | WasmFeatures::SIMD + | WasmFeatures::MEMORY64 + | WasmFeatures::CUSTOM_PAGE_SIZES + | WasmFeatures::WIDE_ARITHMETIC; + Validator::new_with_features(features) } /// Parse a [`TinyWasmModule`] from bytes pub fn parse_module_bytes(&self, wasm: impl AsRef<[u8]>) -> Result { let wasm = wasm.as_ref(); let mut validator = Self::create_validator(self.options.clone()); - let mut reader = ModuleReader::new(); + let mut reader = ModuleReader::default(); for payload in wasmparser::Parser::new(0).parse_all(wasm) { reader.process_payload(payload?, &mut validator)?; @@ -144,21 +120,16 @@ impl Parser { #[cfg(feature = "std")] /// Parse a [`TinyWasmModule`] from a file. Requires `std` feature. pub fn parse_module_file(&self, path: impl AsRef + Clone) -> Result { - use alloc::format; - let f = crate::std::fs::File::open(&path) - .map_err(|e| ParseError::Other(format!("Error opening file {:?}: {}", path.as_ref(), e)))?; - - let mut reader = crate::std::io::BufReader::new(f); - self.parse_module_stream(&mut reader) + let file = crate::std::fs::File::open(&path) + .map_err(|e| ParseError::Other(alloc::format!("Error opening file {:?}: {}", path.as_ref(), e)))?; + self.parse_module_stream(&mut crate::std::io::BufReader::new(file)) } #[cfg(feature = "std")] /// Parse a [`TinyWasmModule`] from a stream. Requires `std` feature. pub fn parse_module_stream(&self, mut stream: impl std::io::Read) -> Result { - use alloc::format; - let mut validator = Self::create_validator(self.options.clone()); - let mut reader = ModuleReader::new(); + let mut reader = ModuleReader::default(); let mut buffer = alloc::vec::Vec::new(); let mut parser = wasmparser::Parser::new(0); let mut eof = false; @@ -170,7 +141,7 @@ impl Parser { buffer.extend((0..hint).map(|_| 0u8)); let read_bytes = stream .read(&mut buffer[len..]) - .map_err(|e| ParseError::Other(format!("Error reading from stream: {e}")))?; + .map_err(|e| ParseError::Other(alloc::format!("Error reading from stream: {e}")))?; buffer.truncate(len + read_bytes); eof = read_bytes == 0; } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 29e556c..cb29e21 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -2,10 +2,7 @@ use crate::log::debug; use crate::{ParseError, ParserOptions, Result, conversion, optimize}; use alloc::string::ToString; use alloc::{format, vec::Vec}; -use tinywasm_types::{ - ArcSlice, Data, Element, Export, FuncType, Global, Import, ImportKind, Instruction, MemoryType, TableType, - TinyWasmModule, ValueCounts, ValueCountsSmall, WasmFunction, WasmFunctionData, -}; +use tinywasm_types::*; use wasmparser::{FuncValidatorAllocations, Payload, Validator}; pub(crate) type Code = (Vec, WasmFunctionData, ValueCounts); @@ -30,23 +27,16 @@ pub(crate) struct ModuleReader { } impl ModuleReader { - pub(crate) fn new() -> Self { - Self::default() - } - pub(crate) fn process_payload(&mut self, payload: Payload<'_>, validator: &mut Validator) -> Result<()> { - use wasmparser::Payload::*; - match payload { - Version { num, encoding, range } => { + Payload::Version { num, encoding, range } => { validator.version(num, encoding, &range)?; self.version = Some(num); - match encoding { - wasmparser::Encoding::Module => {} - wasmparser::Encoding::Component => return Err(ParseError::InvalidEncoding(encoding)), + if let wasmparser::Encoding::Component = encoding { + return Err(ParseError::InvalidEncoding(encoding)); } } - StartSection { func, range } => { + Payload::StartSection { func, range } => { if self.start_func.is_some() { return Err(ParseError::DuplicateSection("Start section".into())); } @@ -55,7 +45,7 @@ impl ModuleReader { validator.start_section(func, &range)?; self.start_func = Some(func); } - TypeSection(reader) => { + Payload::TypeSection(reader) => { if !self.func_types.is_empty() { return Err(ParseError::DuplicateSection("Type section".into())); } @@ -68,7 +58,7 @@ impl ModuleReader { .collect::>>()?; } - GlobalSection(reader) => { + Payload::GlobalSection(reader) => { if !self.globals.is_empty() { return Err(ParseError::DuplicateSection("Global section".into())); } @@ -77,7 +67,7 @@ impl ModuleReader { validator.global_section(&reader)?; self.globals = conversion::convert_module_globals(reader)?; } - TableSection(reader) => { + Payload::TableSection(reader) => { if !self.table_types.is_empty() { return Err(ParseError::DuplicateSection("Table section".into())); } @@ -85,7 +75,7 @@ impl ModuleReader { validator.table_section(&reader)?; self.table_types = conversion::convert_module_tables(reader)?; } - MemorySection(reader) => { + Payload::MemorySection(reader) => { if !self.memory_types.is_empty() { return Err(ParseError::DuplicateSection("Memory section".into())); } @@ -94,12 +84,12 @@ impl ModuleReader { validator.memory_section(&reader)?; self.memory_types = conversion::convert_module_memories(reader)?; } - ElementSection(reader) => { + Payload::ElementSection(reader) => { debug!("Found element section"); validator.element_section(&reader)?; self.elements = conversion::convert_module_elements(reader)?; } - DataSection(reader) => { + Payload::DataSection(reader) => { if !self.data.is_empty() { return Err(ParseError::DuplicateSection("Data section".into())); } @@ -108,14 +98,14 @@ impl ModuleReader { validator.data_section(&reader)?; self.data = conversion::convert_module_data_sections(reader)?; } - DataCountSection { count, range } => { + Payload::DataCountSection { count, range } => { debug!("Found data count section"); if !self.data.is_empty() { return Err(ParseError::DuplicateSection("Data count section".into())); } validator.data_count_section(count, &range)?; } - FunctionSection(reader) => { + Payload::FunctionSection(reader) => { if !self.code_type_addrs.is_empty() { return Err(ParseError::DuplicateSection("Function section".into())); } @@ -124,7 +114,7 @@ impl ModuleReader { validator.function_section(&reader)?; self.code_type_addrs = reader.into_iter().map(|f| Ok(f?)).collect::>>()?; } - CodeSectionStart { count, range, .. } => { + Payload::CodeSectionStart { count, range, .. } => { debug!("Found code section ({count} functions)"); if !self.code.is_empty() { return Err(ParseError::DuplicateSection("Code section".into())); @@ -132,7 +122,7 @@ impl ModuleReader { self.code.reserve(count as usize); validator.code_section_start(&range)?; } - CodeSectionEntry(function) => { + Payload::CodeSectionEntry(function) => { debug!("Found code section entry"); let v = validator.code_section_entry(&function)?; let func_validator = v.into_validator(self.func_validator_allocations.take().unwrap_or_default()); @@ -140,7 +130,7 @@ impl ModuleReader { self.code.push(code); self.func_validator_allocations = Some(allocations); } - ImportSection(reader) => { + Payload::ImportSection(reader) => { if !self.imports.is_empty() { return Err(ParseError::DuplicateSection("Import section".into())); } @@ -149,7 +139,7 @@ impl ModuleReader { validator.import_section(&reader)?; self.imports = conversion::convert_module_imports(reader.into_imports())?; } - ExportSection(reader) => { + Payload::ExportSection(reader) => { if !self.exports.is_empty() { return Err(ParseError::DuplicateSection("Export section".into())); } @@ -159,7 +149,7 @@ impl ModuleReader { self.exports = reader.into_iter().map(|e| conversion::convert_module_export(e?)).collect::>>()?; } - End(offset) => { + Payload::End(offset) => { debug!("Reached end of module"); if self.end_reached { return Err(ParseError::DuplicateSection("End section".into())); @@ -168,14 +158,13 @@ impl ModuleReader { validator.end(offset)?; self.end_reached = true; } - CustomSection(_reader) => { + Payload::CustomSection(_reader) => { debug!("Found custom section"); debug!("Skipping custom section: {:?}", _reader.name()); } - UnknownSection { .. } => return Err(ParseError::UnsupportedSection("Unknown section".into())), + Payload::UnknownSection { .. } => return Err(ParseError::UnsupportedSection("Unknown section".into())), section => return Err(ParseError::UnsupportedSection(format!("Unsupported section: {section:?}"))), }; - Ok(()) } @@ -188,38 +177,22 @@ impl ModuleReader { return Err(ParseError::Other("Code and code type address count mismatch".to_string())); } - let imported_func_count = - self.imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count() as u32; - - let funcs = self - .code - .into_iter() - .zip(self.code_type_addrs) - .enumerate() - .map(|(func_idx, ((instructions, mut data, locals), ty_idx))| { + let imported_func_count = self.imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count(); + let funcs = self.code.into_iter().zip(self.code_type_addrs).enumerate().map( + |(func_idx, ((instructions, mut data, locals), ty_idx))| { let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(); - let params = ValueCountsSmall::from(&ty.params); - let locals = ValueCountsSmall { - c32: u16::try_from(locals.c32).unwrap_or_else(|_| unreachable!("local count exceeds u16")), - c64: u16::try_from(locals.c64).unwrap_or_else(|_| unreachable!("local count exceeds u16")), - c128: u16::try_from(locals.c128).unwrap_or_else(|_| unreachable!("local count exceeds u16")), - cref: u16::try_from(locals.cref).unwrap_or_else(|_| unreachable!("local count exceeds u16")), - }; - let self_func_addr = imported_func_count + func_idx as u32; - let instructions = optimize::optimize_instructions(instructions, &mut data, self_func_addr, options); - + let params = ValueCounts::from(&ty.params); + let self_func = (imported_func_count + func_idx) as u32; + let instructions = optimize::optimize_instructions(instructions, &mut data, self_func, options); WasmFunction { instructions: ArcSlice::from(instructions), data, locals, params, ty } - }) - .collect::>(); - - let globals = self.globals; - let table_types = self.table_types; + }, + ); Ok(TinyWasmModule { - funcs: funcs.into(), + funcs: funcs.collect(), func_types: self.func_types.into(), - globals: globals.into(), - table_types: table_types.into(), + globals: self.globals.into(), + table_types: self.table_types.into(), imports: self.imports.into(), start_func: self.start_func, data: self.data.into(), diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 076f7c1..8313d9f 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -75,7 +75,7 @@ impl VisitSimdOperator<'_> for ValidateThenVisit<'_, R> pub(crate) fn process_operators_and_validate( validator: FuncValidator, body: FunctionBody<'_>, - local_addr_map: Vec, + local_addr_map: Vec, ) -> Result<(Vec, WasmFunctionData, FuncValidatorAllocations)> { let mut reader = body.get_operators_reader()?; let remaining = reader.get_binary_reader().bytes_remaining(); @@ -148,7 +148,7 @@ pub(crate) struct FunctionBuilder { instructions: Vec, data: FunctionDataBuilder, ctx_stack: Vec, - local_addr_map: Vec, + local_addr_map: Vec, errors: Vec, } @@ -244,13 +244,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_local_get(&mut self, idx: u32) -> Self::Output { - let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else { - self.errors.push(crate::ParseError::UnsupportedOperator( - "Local index is too large, tinywasm does not support local indexes that large".to_string(), - )); - return; - }; - + let resolved_idx = self.local_addr_map[idx as usize]; if let Some(t) = self.validator.get_local_type(idx) { match t { wasmparser::ValType::I32 | wasmparser::ValType::F32 => { @@ -270,13 +264,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_local_set(&mut self, idx: u32) -> Self::Output { - let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else { - self.errors.push(crate::ParseError::UnsupportedOperator( - "Local index is too large, tinywasm does not support local indexes that large".to_string(), - )); - return; - }; - + let resolved_idx = self.local_addr_map[idx as usize]; if let Some(Some(t)) = self.validator.get_operand_type(0) { self.instructions.push(match t { wasmparser::ValType::I32 => Instruction::LocalSet32(resolved_idx), @@ -290,13 +278,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_local_tee(&mut self, idx: u32) -> Self::Output { - let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else { - self.errors.push(crate::ParseError::UnsupportedOperator( - "Local index is too large, tinywasm does not support local indexes that large".to_string(), - )); - return; - }; - + let resolved_idx = self.local_addr_map[idx as usize]; if let Some(Some(t)) = self.validator.get_operand_type(0) { self.instructions.push(match t { wasmparser::ValType::I32 => Instruction::LocalTee32(resolved_idx), @@ -472,7 +454,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild fn visit_typed_select_multi(&mut self, tys: Vec) -> Self::Output { let (c32, c64, c128, cref) = Self::label_keep_counts(&tys); - self.instructions.push(Instruction::SelectMulti(tinywasm_types::ValueCountsSmall { c32, c64, c128, cref })); + self.instructions.push(Instruction::SelectMulti(tinywasm_types::ValueCounts { c32, c64, c128, cref })); } fn visit_typed_select(&mut self, ty: wasmparser::ValType) -> Self::Output { @@ -588,7 +570,7 @@ impl FunctionBuilder { self.validator.simd_visitor(offset) } - pub(crate) fn new(instr_capacity: usize, validator: FuncValidator, local_addr_map: Vec) -> Self { + pub(crate) fn new(instr_capacity: usize, validator: FuncValidator, local_addr_map: Vec) -> Self { Self { validator, local_addr_map, diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index f11b3ad..00a47cf 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -90,7 +90,6 @@ harness=false [[test]] name="test-wasm-memory64" harness=false -test=false [[test]] name="test-wasm-extended-const" @@ -100,17 +99,14 @@ test=false [[test]] name="test-wasm-relaxed-simd" harness=false -test=false [[test]] name="test-wasm-simd" harness=false -test=false [[test]] name="test-wasm-wide-arithmetic" harness=false -test=false [[test]] name="test-wast" diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index d55536f..9e8de16 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -159,18 +159,18 @@ impl Extern { ty: &tinywasm_types::FuncType, func: impl Fn(FuncContext<'_>, &[WasmValue]) -> Result> + 'static, ) -> Self { - let _ty = ty.clone(); + let ty_inner = ty.clone(); let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result> { - let _ty = _ty.clone(); + let ty = ty_inner.clone(); let result = func(ctx, args)?; - if result.len() != _ty.results.len() { - return Err(crate::Error::InvalidHostFnReturn { expected: _ty.clone(), actual: result }); + if result.len() != ty.results.len() { + return Err(crate::Error::InvalidHostFnReturn { expected: ty.clone(), actual: result }); }; - result.iter().zip(_ty.results.iter()).try_for_each(|(val, ty)| { - if val.val_type() != *ty { - return Err(crate::Error::InvalidHostFnReturn { expected: _ty.clone(), actual: result.clone() }); + result.iter().zip(ty.results.iter()).try_for_each(|(val, res_ty)| { + if val.val_type() != *res_ty { + return Err(crate::Error::InvalidHostFnReturn { expected: ty.clone(), actual: result.clone() }); } Ok(()) })?; @@ -344,20 +344,17 @@ impl Imports { fn compare_table_types(import: &Import, expected: &TableType, actual: &TableType) -> Result<()> { Self::compare_types(import, &actual.element_type, &expected.element_type)?; - if actual.size_initial > expected.size_initial { return Err(LinkingError::incompatible_import_type(import).into()); } match (expected.size_max, actual.size_max) { - (None, Some(_)) => return Err(LinkingError::incompatible_import_type(import).into()), + (None, Some(_)) => Err(LinkingError::incompatible_import_type(import).into()), (Some(expected_max), Some(actual_max)) if actual_max < expected_max => { - return Err(LinkingError::incompatible_import_type(import).into()); + Err(LinkingError::incompatible_import_type(import).into()) } - _ => {} + _ => Ok(()), } - - Ok(()) } fn compare_memory_types( @@ -394,9 +391,7 @@ impl Imports { let mut imports = ResolvedImports::new(); for import in &*module.0.imports { - let val = self.take(store, import).ok_or_else(|| LinkingError::unknown_import(import))?; - - match val { + match self.take(store, import).ok_or_else(|| LinkingError::unknown_import(import))? { // A link to something that needs to be added to the store ResolvedExtern::Extern(ex) => match (ex, &import.kind) { (Extern::Global { ty, val }, ImportKind::Global(import_ty)) => { diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 2782402..b95a94d 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -14,25 +14,18 @@ use crate::{Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut #[cfg_attr(feature = "debug", derive(Debug))] pub struct ModuleInstance(pub(crate) Rc); -#[expect(dead_code)] #[cfg_attr(feature = "debug", derive(Debug))] pub(crate) struct ModuleInstanceInner { - pub(crate) failed_to_instantiate: bool, - pub(crate) store_id: usize, pub(crate) idx: ModuleInstanceAddr, - pub(crate) types: ArcSlice, - pub(crate) func_addrs: Box<[FuncAddr]>, pub(crate) table_addrs: Box<[TableAddr]>, pub(crate) mem_addrs: Box<[MemAddr]>, pub(crate) global_addrs: Box<[GlobalAddr]>, pub(crate) elem_addrs: Box<[ElemAddr]>, pub(crate) data_addrs: Box<[DataAddr]>, - pub(crate) func_start: Option, - pub(crate) imports: ArcSlice, pub(crate) exports: ArcSlice, } @@ -107,7 +100,6 @@ impl ModuleInstanceInner { impl ModuleInstance { /// Get the module instance's address - #[inline] pub fn id(&self) -> ModuleInstanceAddr { self.0.idx } @@ -116,24 +108,18 @@ impl ModuleInstance { /// /// See pub fn instantiate(store: &mut Store, module: Module, imports: Option) -> Result { - // This doesn't completely follow the steps in the spec, but the end result is the same - // Constant expressions are evaluated directly where they are used, so we - // don't need to create a auxiliary frame etc. - let idx = store.next_module_instance_idx(); let mut addrs = imports.unwrap_or_default().link(store, &module, idx)?; addrs.funcs.extend(store.init_funcs(&module.0.funcs, idx)?); addrs.tables.extend(store.init_tables(&module.0.table_types, idx)?); addrs.memories.extend(store.init_memories(&module.0.memory_types, idx)?); - let global_addrs = store.init_globals(addrs.globals, &module.0.globals, &addrs.funcs, idx)?; let (elem_addrs, elem_trapped) = store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.0.elements, idx)?; let (data_addrs, data_trapped) = store.init_data(&addrs.memories, &module.0.data, idx)?; let instance = ModuleInstanceInner { - failed_to_instantiate: elem_trapped.is_some() || data_trapped.is_some(), store_id: store.id(), idx, types: module.0.func_types.clone(), @@ -144,7 +130,6 @@ impl ModuleInstance { elem_addrs, data_addrs, func_start: module.0.start_func, - imports: module.0.imports.clone(), exports: module.0.exports.clone(), }; @@ -166,7 +151,6 @@ impl ModuleInstance { ExternalKind::Memory => self.0.mem_addrs.get(exports.index as usize)?, ExternalKind::Global => self.0.global_addrs.get(exports.index as usize)?, }; - Some(ExternVal::new(exports.kind, *addr)) } @@ -186,11 +170,11 @@ impl ModuleInstance { } /// Get a typed exported function by name - pub fn exported_func(&self, store: &Store, name: &str) -> Result> - where - P: IntoWasmValueTuple, - R: FromWasmValueTuple, - { + pub fn exported_func( + &self, + store: &Store, + name: &str, + ) -> Result> { let func = self.exported_func_untyped(store, name)?; Ok(FuncHandleTyped { func, marker: core::marker::PhantomData }) } @@ -201,7 +185,6 @@ impl ModuleInstance { let ExternVal::Memory(mem_addr) = export else { return Err(Error::Other(format!("Export is not a memory: {name}"))); }; - self.memory(store, mem_addr) } @@ -211,26 +194,23 @@ impl ModuleInstance { let ExternVal::Memory(mem_addr) = export else { return Err(Error::Other(format!("Export is not a memory: {name}"))); }; - self.memory_mut(store, mem_addr) } /// Get a memory by address pub fn memory<'a>(&self, store: &'a Store, addr: MemAddr) -> Result> { - let mem = store.state.get_mem(self.0.resolve_mem_addr(addr)); - Ok(MemoryRef(mem)) + Ok(MemoryRef(store.state.get_mem(self.0.resolve_mem_addr(addr)))) } /// Get a memory by address (mutable) pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result> { - let mem = store.state.get_mem_mut(self.0.resolve_mem_addr(addr)); - Ok(MemoryRefMut(mem)) + Ok(MemoryRefMut(store.state.get_mem_mut(self.0.resolve_mem_addr(addr)))) } /// Get the start function of the module /// /// Returns None if the module has no start function - /// If no start function is specified, also checks for a _start function in the exports + /// If no start function is specified, also checks for a `_start` function in the exports /// /// See pub fn start_func(&self, store: &Store) -> Result> { @@ -251,23 +231,19 @@ impl ModuleInstance { }; let func_addr = self.0.resolve_func_addr(func_index); - let func_inst = store.state.get_func(func_addr); - let ty = func_inst.func.ty(); - + let ty = store.state.get_func(func_addr).func.ty(); Ok(Some(FuncHandle { module_addr: self.id(), addr: func_addr, ty: ty.clone() })) } /// Invoke the start function of the module /// - /// Returns None if the module has no start function + /// Returns `None` if the module has no start function /// /// See pub fn start(&self, store: &mut Store) -> Result> { let Some(func) = self.start_func(store)? else { return Ok(None); }; - - let _ = func.call(store, &[])?; - Ok(Some(())) + func.call(store, &[]).map(|_| Some(())) } } diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 8316421..f739906 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -818,7 +818,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { } fn exec_return(&mut self) -> bool { - let result_counts = ValueCountsSmall::from(self.func.ty.results.iter()); + let result_counts = ValueCounts::from(self.func.ty.results.iter()); self.store.stack.values.truncate_keep_counts(self.cf.locals_base, result_counts); let Some(cf) = self.store.stack.call_stack.pop() else { return true }; @@ -1188,12 +1188,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { impl<'store> Executor<'store, false> { #[inline(always)] pub(crate) fn run_to_completion(&mut self) -> Result<()> { - loop { - // for some reason, using a iteration count of 4096 here seems to be a sweet spot for performance - if self.exec::<1024>()?.is_some() { - return Ok(()); - } + if self.exec::<{ usize::MAX }>()?.is_some() { + return Ok(()); } + unreachable!(); } #[cfg(feature = "std")] diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index a91f938..dfc71bc 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -1,7 +1,7 @@ use crate::{Result, Trap, unlikely}; use alloc::vec::Vec; -use tinywasm_types::{FuncAddr, ModuleInstanceAddr, ValueCountsSmall}; +use tinywasm_types::{FuncAddr, ModuleInstanceAddr, ValueCounts}; #[cfg_attr(feature = "debug", derive(Debug))] pub(crate) struct CallStack { @@ -39,7 +39,7 @@ pub(crate) struct CallFrame { pub(crate) module_addr: ModuleInstanceAddr, pub(crate) func_addr: FuncAddr, pub(crate) locals_base: StackBase, - pub(crate) stack_offset: ValueCountsSmall, + pub(crate) stack_offset: ValueCounts, } #[derive(Clone, Copy, Default)] @@ -56,7 +56,7 @@ impl CallFrame { func_addr: FuncAddr, module_addr: ModuleInstanceAddr, locals_base: StackBase, - stack_offset: ValueCountsSmall, + stack_offset: ValueCounts, ) -> Self { Self { instr_ptr: 0, func_addr, module_addr, locals_base, stack_offset } } diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 87d8452..b67ab09 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -1,6 +1,6 @@ use alloc::boxed::Box; use alloc::vec::Vec; -use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, ValueCountsSmall, WasmValue}; +use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, ValueCounts, WasmValue}; use crate::{Result, Trap, engine::Config, interpreter::*, unlikely}; @@ -195,7 +195,7 @@ impl ValueStack { } #[inline] - pub(crate) fn select_multi(&mut self, counts: ValueCountsSmall) { + pub(crate) fn select_multi(&mut self, counts: ValueCounts) { let condition = self.pop::() != 0; self.stack_32.select_many(counts.c32 as usize, condition); self.stack_64.select_many(counts.c64 as usize, condition); @@ -257,7 +257,7 @@ impl ValueStack { val_types.into_iter().map(|val_type| self.pop_wasmvalue(*val_type)) } - pub(crate) fn enter_locals(&mut self, params: &ValueCountsSmall, locals: &ValueCountsSmall) -> Result { + pub(crate) fn enter_locals(&mut self, params: &ValueCounts, locals: &ValueCounts) -> Result { let locals_base32 = if params.c32 == 0 && locals.c32 == 0 { self.stack_32.len as u32 } else { @@ -282,7 +282,7 @@ impl ValueStack { Ok(StackBase { s32: locals_base32, s64: locals_base64, s128: locals_base128, sref: locals_baseref }) } - pub(crate) fn truncate_keep_counts(&mut self, base: StackBase, keep: ValueCountsSmall) { + pub(crate) fn truncate_keep_counts(&mut self, base: StackBase, keep: ValueCounts) { if keep.c32 == 0 && keep.c64 == 0 && keep.c128 == 0 && keep.cref == 0 { self.stack_32.len = base.s32 as usize; self.stack_64.len = base.s64 as usize; diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs index d6c5210..1ce3ff0 100644 --- a/crates/tinywasm/src/module.rs +++ b/crates/tinywasm/src/module.rs @@ -24,24 +24,21 @@ impl Module { #[cfg(feature = "parser")] /// Parse a module from bytes. Requires `parser` feature. pub fn parse_bytes(wasm: &[u8]) -> Result { - let parser = tinywasm_parser::Parser::new(); - let data = parser.parse_module_bytes(wasm)?; + let data = tinywasm_parser::Parser::new().parse_module_bytes(wasm)?; Ok(data.into()) } #[cfg(all(feature = "parser", feature = "std"))] /// Parse a module from a file. Requires `parser` and `std` features. pub fn parse_file(path: impl AsRef + Clone) -> Result { - let parser = tinywasm_parser::Parser::new(); - let data = parser.parse_module_file(path)?; + let data = tinywasm_parser::Parser::new().parse_module_file(path)?; Ok(data.into()) } #[cfg(all(feature = "parser", feature = "std"))] /// Parse a module from a stream. Requires `parser` and `std` features. pub fn parse_stream(stream: impl crate::std::io::Read) -> Result { - let parser = tinywasm_parser::Parser::new(); - let data = parser.parse_module_stream(stream)?; + let data = tinywasm_parser::Parser::new().parse_module_stream(stream)?; Ok(data.into()) } diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 78b52b8..0cbcad7 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -1,4 +1,4 @@ -use super::{FuncAddr, GlobalAddr, LocalAddr, TableAddr, TypeAddr, ValType, ValueCountsSmall}; +use super::{FuncAddr, GlobalAddr, LocalAddr, TableAddr, TypeAddr, ValType, ValueCounts}; use crate::{ConstIdx, DataAddr, ElemAddr, ExternAddr, MemAddr}; /// Represents a memory immediate in a WebAssembly memory instruction. @@ -92,7 +92,7 @@ pub enum Instruction { Drop64, Select64, Drop128, Select128, DropRef, SelectRef, - SelectMulti(ValueCountsSmall), + SelectMulti(ValueCounts), // > Variable Instructions // See diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index a56dc9f..e9d2729 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -208,16 +208,6 @@ pub struct FuncType { #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct ValueCounts { - pub c32: u32, - pub c64: u32, - pub c128: u32, - pub cref: u32, -} - -#[derive(Default, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "debug", derive(Debug))] -#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] -pub struct ValueCountsSmall { pub c32: u16, pub c64: u16, pub c128: u16, @@ -240,30 +230,14 @@ impl<'a, T: IntoIterator> From for ValueCounts { } } -impl<'a, T: IntoIterator> From for ValueCountsSmall { - #[inline] - fn from(types: T) -> Self { - let mut counts = Self::default(); - for ty in types { - match ty { - ValType::I32 | ValType::F32 => counts.c32 += 1, - ValType::I64 | ValType::F64 => counts.c64 += 1, - ValType::V128 => counts.c128 += 1, - ValType::RefExtern | ValType::RefFunc => counts.cref += 1, - } - } - counts - } -} - #[derive(Clone, PartialEq, Default)] #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct WasmFunction { pub instructions: ArcSlice, pub data: WasmFunctionData, - pub locals: ValueCountsSmall, - pub params: ValueCountsSmall, + pub locals: ValueCounts, + pub params: ValueCounts, pub ty: FuncType, } @@ -298,6 +272,12 @@ impl Deref for ArcSlice { } } +impl FromIterator for ArcSlice { + fn from_iter>(iter: I) -> Self { + Self(Arc::from_iter(iter)) + } +} + #[cfg(feature = "archive")] impl serde::Serialize for ArcSlice { fn serialize(&self, serializer: S) -> Result { -- cgit v1.3.1