use crate::log::debug; use crate::{conversion, ParseError, Result}; use alloc::{boxed::Box, format, vec::Vec}; use core::fmt::Debug; use tinywasm_types::{Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, ValType}; use wasmparser::{Payload, Validator}; #[derive(Debug, Clone)] pub struct CodeSection { pub locals: Box<[ValType]>, pub body: Box<[Instruction]>, } #[derive(Default)] pub struct ModuleReader { pub version: Option, pub start_func: Option, pub func_types: Vec, // map from local function index to type index pub code_type_addrs: Vec, pub exports: Vec, pub code: Vec, pub globals: Vec, pub table_types: Vec, pub memory_types: Vec, pub imports: Vec, pub data: Vec, pub elements: Vec, // pub element_section: Option>, pub end_reached: bool, } impl Debug for ModuleReader { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("ModuleReader") .field("version", &self.version) .field("func_types", &self.func_types) .field("func_addrs", &self.code_type_addrs) .field("code", &self.code) .field("exports", &self.exports) .field("globals", &self.globals) .field("table_types", &self.table_types) .field("memory_types", &self.memory_types) .field("import_section", &self.imports) // .field("element_section", &self.element_section) // .field("data_section", &self.data_section) .finish() } } impl ModuleReader { pub fn new() -> ModuleReader { Self::default() } pub fn process_payload(&mut self, payload: Payload, validator: &mut Validator) -> Result<()> { use wasmparser::Payload::*; match 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)), } } StartSection { func, range } => { if self.start_func.is_some() { return Err(ParseError::DuplicateSection("Start section".into())); } debug!("Found start section"); validator.start_section(func, &range)?; self.start_func = Some(func); } TypeSection(reader) => { if !self.func_types.is_empty() { return Err(ParseError::DuplicateSection("Type section".into())); } debug!("Found type section"); validator.type_section(&reader)?; self.func_types = reader .into_iter() .map(|t| conversion::convert_module_type(t?)) .collect::>>()?; } FunctionSection(reader) => { if !self.code_type_addrs.is_empty() { return Err(ParseError::DuplicateSection("Function section".into())); } debug!("Found function section"); validator.function_section(&reader)?; self.code_type_addrs = reader.into_iter().map(|f| Ok(f?)).collect::>>()?; } GlobalSection(reader) => { if !self.globals.is_empty() { return Err(ParseError::DuplicateSection("Global section".into())); } debug!("Found global section"); validator.global_section(&reader)?; self.globals = conversion::convert_module_globals(reader)?; } TableSection(reader) => { if !self.table_types.is_empty() { return Err(ParseError::DuplicateSection("Table section".into())); } debug!("Found table section"); validator.table_section(&reader)?; self.table_types = conversion::convert_module_tables(reader)?; } MemorySection(reader) => { if !self.memory_types.is_empty() { return Err(ParseError::DuplicateSection("Memory section".into())); } debug!("Found memory section"); validator.memory_section(&reader)?; self.memory_types = conversion::convert_module_memories(reader)?; } ElementSection(reader) => { debug!("Found element section"); validator.element_section(&reader)?; self.elements = conversion::convert_module_elements(reader)?; } DataSection(reader) => { if !self.data.is_empty() { return Err(ParseError::DuplicateSection("Data section".into())); } debug!("Found data section"); validator.data_section(&reader)?; self.data = conversion::convert_module_data_sections(reader)?; } CodeSectionStart { count, range, .. } => { debug!("Found code section ({} functions)", count); if !self.code.is_empty() { return Err(ParseError::DuplicateSection("Code section".into())); } validator.code_section_start(count, &range)?; } CodeSectionEntry(function) => { debug!("Found code section entry"); let v = validator.code_section_entry(&function)?; let func_validator = v.into_validator(Default::default()); self.code.push(conversion::convert_module_code(function, func_validator)?); } ImportSection(reader) => { if !self.imports.is_empty() { return Err(ParseError::DuplicateSection("Import section".into())); } debug!("Found import section"); validator.import_section(&reader)?; self.imports = conversion::convert_module_imports(reader)?; } ExportSection(reader) => { if !self.exports.is_empty() { return Err(ParseError::DuplicateSection("Export section".into())); } debug!("Found export section"); validator.export_section(&reader)?; self.exports = reader.into_iter().map(|e| conversion::convert_module_export(e?)).collect::>>()?; } End(offset) => { debug!("Reached end of module"); if self.end_reached { return Err(ParseError::DuplicateSection("End section".into())); } validator.end(offset)?; self.end_reached = true; } CustomSection(_reader) => { debug!("Found custom section"); debug!("Skipping custom section: {:?}", _reader.name()); } // TagSection(tag) => { // debug!("Found tag section"); // validator.tag_section(&tag)?; // } UnknownSection { .. } => return Err(ParseError::UnsupportedSection("Unknown section".into())), section => return Err(ParseError::UnsupportedSection(format!("Unsupported section: {:?}", section))), }; Ok(()) } }