use crate::r#ref::HostRef; use crate::runtime::Store; use crate::types::{ ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability, TableType, ValType, }; use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use anyhow::Result; use wasmparser::{validate, ExternalKind, ImportSectionEntryType, ModuleReader, SectionCode}; fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType { assert!(!mt.shared); MemoryType::new(Limits::new( mt.limits.initial, mt.limits.maximum.unwrap_or(::core::u32::MAX), )) } fn into_global_type(gt: &wasmparser::GlobalType) -> GlobalType { let mutability = if gt.mutable { Mutability::Var } else { Mutability::Const }; GlobalType::new(into_valtype(>.content_type), mutability) } fn into_valtype(ty: &wasmparser::Type) -> ValType { use wasmparser::Type::*; match ty { I32 => ValType::I32, I64 => ValType::I64, F32 => ValType::F32, F64 => ValType::F64, V128 => ValType::V128, AnyFunc => ValType::FuncRef, AnyRef => ValType::AnyRef, _ => unimplemented!("types in into_valtype"), } } fn into_func_type(mt: wasmparser::FuncType) -> FuncType { assert!(mt.form == wasmparser::Type::Func); let params = mt.params.iter().map(into_valtype).collect::>(); let returns = mt.returns.iter().map(into_valtype).collect::>(); FuncType::new(params.into_boxed_slice(), returns.into_boxed_slice()) } fn into_table_type(tt: wasmparser::TableType) -> TableType { assert!( tt.element_type == wasmparser::Type::AnyFunc || tt.element_type == wasmparser::Type::AnyRef ); let ty = into_valtype(&tt.element_type); let limits = Limits::new( tt.limits.initial, tt.limits.maximum.unwrap_or(::core::u32::MAX), ); TableType::new(ty, limits) } fn read_imports_and_exports(binary: &[u8]) -> Result<(Box<[ImportType]>, Box<[ExportType]>)> { let mut reader = ModuleReader::new(binary)?; let mut imports = Vec::new(); let mut exports = Vec::new(); let mut memories = Vec::new(); let mut tables = Vec::new(); let mut func_sig = Vec::new(); let mut sigs = Vec::new(); let mut globals = Vec::new(); while !reader.eof() { let section = reader.read()?; match section.code { SectionCode::Memory => { let section = section.get_memory_section_reader()?; memories.reserve_exact(section.get_count() as usize); for entry in section { memories.push(into_memory_type(entry?)); } } SectionCode::Type => { let section = section.get_type_section_reader()?; sigs.reserve_exact(section.get_count() as usize); for entry in section { sigs.push(into_func_type(entry?)); } } SectionCode::Function => { let section = section.get_function_section_reader()?; func_sig.reserve_exact(section.get_count() as usize); for entry in section { func_sig.push(entry?); } } SectionCode::Global => { let section = section.get_global_section_reader()?; globals.reserve_exact(section.get_count() as usize); for entry in section { globals.push(into_global_type(&entry?.ty)); } } SectionCode::Table => { let section = section.get_table_section_reader()?; tables.reserve_exact(section.get_count() as usize); for entry in section { tables.push(into_table_type(entry?)) } } SectionCode::Import => { let section = section.get_import_section_reader()?; imports.reserve_exact(section.get_count() as usize); for entry in section { let entry = entry?; let module = String::from(entry.module).into(); let name = String::from(entry.field).into(); let r#type = match entry.ty { ImportSectionEntryType::Function(index) => { func_sig.push(index); let sig = &sigs[index as usize]; ExternType::ExternFunc(sig.clone()) } ImportSectionEntryType::Table(tt) => { let table = into_table_type(tt); tables.push(table.clone()); ExternType::ExternTable(table) } ImportSectionEntryType::Memory(mt) => { let memory = into_memory_type(mt); memories.push(memory.clone()); ExternType::ExternMemory(memory) } ImportSectionEntryType::Global(gt) => { let global = into_global_type(>); globals.push(global.clone()); ExternType::ExternGlobal(global) } }; imports.push(ImportType::new(module, name, r#type)); } } SectionCode::Export => { let section = section.get_export_section_reader()?; exports.reserve_exact(section.get_count() as usize); for entry in section { let entry = entry?; let name = String::from(entry.field).into(); let r#type = match entry.kind { ExternalKind::Function => { let sig_index = func_sig[entry.index as usize] as usize; let sig = &sigs[sig_index]; ExternType::ExternFunc(sig.clone()) } ExternalKind::Table => { ExternType::ExternTable(tables[entry.index as usize].clone()) } ExternalKind::Memory => { ExternType::ExternMemory(memories[entry.index as usize].clone()) } ExternalKind::Global => { ExternType::ExternGlobal(globals[entry.index as usize].clone()) } }; exports.push(ExportType::new(name, r#type)); } } _ => { // skip other sections } } } Ok((imports.into_boxed_slice(), exports.into_boxed_slice())) } #[derive(Clone)] pub struct Module { store: HostRef, binary: Box<[u8]>, imports: Box<[ImportType]>, exports: Box<[ExportType]>, } impl Module { pub fn new(store: &HostRef, binary: &[u8]) -> Result { let (imports, exports) = read_imports_and_exports(binary)?; Ok(Module { store: store.clone(), binary: binary.into(), imports, exports, }) } pub(crate) fn binary(&self) -> &[u8] { &self.binary } pub fn validate(_store: &Store, binary: &[u8]) -> bool { validate(binary, None).is_ok() } pub fn imports(&self) -> &[ImportType] { &self.imports } pub fn exports(&self) -> &[ExportType] { &self.exports } }