diff options
| author | Henry <mail@henrygressmann.de> | 2026-04-05 20:49:40 +0200 |
|---|---|---|
| committer | Henry <mail@henrygressmann.de> | 2026-04-05 20:49:40 +0200 |
| commit | 7d4dfd8ec65c78eb8154d89aa77dd71ac65015f6 (patch) | |
| tree | 7db6f65b35553a9994a3790e885721bdcbddf1ca /crates/parser/src | |
| parent | 66c9f7ab06dd67ac6e62321dd33943de7f9f9e57 (diff) | |
chore: cleanup
Diffstat (limited to 'crates/parser/src')
| -rw-r--r-- | crates/parser/src/conversion.rs | 77 | ||||
| -rw-r--r-- | crates/parser/src/lib.rs | 81 | ||||
| -rw-r--r-- | crates/parser/src/module.rs | 89 | ||||
| -rw-r--r-- | crates/parser/src/visit.rs | 32 |
4 files changed, 96 insertions, 183 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<Item = wasmparser::Resu } pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Import> { - 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<T: IntoIterator<Item = wasmparser::Result<wasmparser::MemoryType>>>( @@ -130,21 +125,16 @@ pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result<Table crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.ty.initial)) })?; - let size_max = match table.ty.maximum { - Some(max) => 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<Vec<Global>> { - 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::<Result<Vec<_>>>()?; - Ok(globals) + .collect::<Result<Vec<_>>>() } pub(crate) fn convert_module_export(export: wasmparser::Export<'_>) -> Result<Export> { @@ -215,7 +204,6 @@ pub(crate) fn convert_module_code( pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result<FuncType> { 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<FuncType> let ty = types.next().unwrap().unwrap_func(); let params = ty.params().iter().map(convert_valtype).collect::<Vec<ValType>>().into_boxed_slice(); let results = ty.results().iter().map(convert_valtype).collect::<Vec<ValType>>().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<TinyWasmModule> { 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<crate::std::path::Path> + Clone) -> Result<TinyWasmModule> { - 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<TinyWasmModule> { - 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<Instruction>, 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::<Result<Vec<FuncType>>>()?; } - 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::<Result<Vec<_>>>()?; } - 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::<Result<Vec<_>>>()?; } - 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::<Vec<_>>(); - - 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<R: WasmModuleResources> VisitSimdOperator<'_> for ValidateThenVisit<'_, R> pub(crate) fn process_operators_and_validate<R: WasmModuleResources>( validator: FuncValidator<R>, body: FunctionBody<'_>, - local_addr_map: Vec<u32>, + local_addr_map: Vec<u16>, ) -> Result<(Vec<Instruction>, 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<R: WasmModuleResources> { instructions: Vec<Instruction>, data: FunctionDataBuilder, ctx_stack: Vec<LoweringCtx>, - local_addr_map: Vec<u32>, + local_addr_map: Vec<u16>, errors: Vec<crate::ParseError>, } @@ -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<wasmparser::ValType>) -> 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<R: WasmModuleResources> FunctionBuilder<R> { self.validator.simd_visitor(offset) } - pub(crate) fn new(instr_capacity: usize, validator: FuncValidator<R>, local_addr_map: Vec<u32>) -> Self { + pub(crate) fn new(instr_capacity: usize, validator: FuncValidator<R>, local_addr_map: Vec<u16>) -> Self { Self { validator, local_addr_map, |
