//! Wasm binary graph format use parity_wasm::elements; use super::ref_list::{RefList, EntryRef}; use std::vec::Vec; use std::borrow::ToOwned; use std::string::String; enum ImportedOrDeclared { Imported(String, String), Declared(T), } impl From<&elements::ImportEntry> for ImportedOrDeclared { fn from(v: &elements::ImportEntry) -> Self { ImportedOrDeclared::Imported(v.module().to_owned(), v.field().to_owned()) } } type FuncOrigin = ImportedOrDeclared>; type GlobalOrigin = ImportedOrDeclared>; type MemoryOrigin = ImportedOrDeclared; type TableOrigin = ImportedOrDeclared; struct Func { type_ref: EntryRef, origin: FuncOrigin, } struct Global { content: elements::ValueType, is_mut: bool, origin: GlobalOrigin, } enum Instruction { Plain(elements::Instruction), Call(EntryRef), } struct Memory { limits: elements::ResizableLimits, origin: MemoryOrigin, } struct Table { origin: TableOrigin, limits: elements::ResizableLimits, } struct DataSegment { offset_expr: Vec, data: Vec, } struct ElementSegment { offset_expr: Vec, data: Vec, } enum ExportLocal { Func(EntryRef), Global(EntryRef), Table(EntryRef), Memory(EntryRef), } struct Export { name: String, local: ExportLocal, } #[derive(Default)] struct Module { types: RefList, funcs: RefList, memory: RefList, tables: RefList
, globals: RefList, start: Option>, exports: Vec, elements: Vec, data: Vec, } impl Module { fn from_elements(module: &elements::Module) -> Self { let mut res = Module::default(); for section in module.sections() { match section { elements::Section::Type(type_section) => { res.types = RefList::from_slice(type_section.types()); }, elements::Section::Import(import_section) => { for entry in import_section.entries() { match *entry.external() { elements::External::Function(f) => { res.funcs.push(Func { type_ref: res.types.get(f as usize).expect("validated; qed").clone(), origin: entry.into(), }); }, elements::External::Memory(m) => { res.memory.push(Memory { limits: m.limits().clone(), origin: entry.into(), }); }, elements::External::Global(g) => { res.globals.push(Global { content: g.content_type(), is_mut: g.is_mutable(), origin: entry.into(), }); }, elements::External::Table(t) => { res.tables.push(Table { limits: t.limits().clone(), origin: entry.into(), }); }, }; } }, elements::Section::Function(function_section) => { for f in function_section.entries() { res.funcs.push(Func { type_ref: res.types.get(f.type_ref() as usize).expect("validated; qed").clone(), // code will be populated later origin: ImportedOrDeclared::Declared(Vec::new()), }); }; }, elements::Section::Table(table_section) => { for t in table_section.entries() { res.tables.push(Table { limits: t.limits().clone(), origin: ImportedOrDeclared::Declared(()), }); } }, elements::Section::Memory(table_section) => { for t in table_section.entries() { res.memory.push(Memory { limits: t.limits().clone(), origin: ImportedOrDeclared::Declared(()), }); } }, elements::Section::Global(global_section) => { for g in global_section.entries() { res.globals.push(Global { content: g.global_type().content_type(), is_mut: g.global_type().is_mutable(), // TODO: init expr origin: ImportedOrDeclared::Declared(Vec::new()), }); } }, elements::Section::Export(export_section) => { for e in export_section.entries() { let local = match e.internal() { &elements::Internal::Function(func_idx) => { ExportLocal::Func(res.funcs.clone_ref(func_idx as usize)) }, &elements::Internal::Global(global_idx) => { ExportLocal::Global(res.globals.clone_ref(global_idx as usize)) }, &elements::Internal::Memory(mem_idx) => { ExportLocal::Memory(res.memory.clone_ref(mem_idx as usize)) }, &elements::Internal::Table(table_idx) => { ExportLocal::Table(res.tables.clone_ref(table_idx as usize)) }, }; res.exports.push(Export { local: local, name: e.field().to_owned() }) } }, _ => continue, } } res } } fn parse(wasm: &[u8]) -> Module { Module::from_elements(&::parity_wasm::deserialize_buffer(wasm).expect("failed to parse wasm")) } #[cfg(test)] mod tests { extern crate wabt; use parity_wasm; #[test] fn smoky() { let wasm = wabt::wat2wasm(r#" (module (type (func)) (func (type 0)) (memory 0 1) (export "simple" (func 0)) ) "#).expect("Failed to read fixture"); let f = super::parse(&wasm[..]); assert_eq!(f.types.len(), 1); assert_eq!(f.funcs.len(), 1); assert_eq!(f.tables.len(), 0); assert_eq!(f.memory.len(), 1); assert_eq!(f.exports.len(), 1); assert_eq!(f.types.get_ref(0).link_count(), 1); assert_eq!(f.funcs.get_ref(0).link_count(), 1); } }