2019-01-21 17:04:31 +03:00
|
|
|
//! Wasm binary graph format
|
|
|
|
|
|
|
|
use parity_wasm::elements;
|
2019-01-22 12:19:29 +03:00
|
|
|
use super::ref_list::{RefList, EntryRef};
|
2019-01-21 17:04:31 +03:00
|
|
|
|
|
|
|
enum ImportedOrDeclared<T=()> {
|
|
|
|
Imported(String, String),
|
|
|
|
Declared(T),
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:56:30 +03:00
|
|
|
impl<T> From<&elements::ImportEntry> for ImportedOrDeclared<T> {
|
|
|
|
fn from(v: &elements::ImportEntry) -> Self {
|
|
|
|
ImportedOrDeclared::Imported(v.module().to_owned(), v.field().to_owned())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
type FuncOrigin = ImportedOrDeclared<Vec<Instruction>>;
|
|
|
|
type GlobalOrigin = ImportedOrDeclared<Vec<Instruction>>;
|
|
|
|
type MemoryOrigin = ImportedOrDeclared;
|
|
|
|
type TableOrigin = ImportedOrDeclared;
|
|
|
|
|
|
|
|
struct Func {
|
2019-01-22 12:19:29 +03:00
|
|
|
type_ref: EntryRef<elements::Type>,
|
2019-01-21 17:04:31 +03:00
|
|
|
origin: FuncOrigin,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Global {
|
|
|
|
content: elements::ValueType,
|
|
|
|
is_mut: bool,
|
|
|
|
origin: GlobalOrigin,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Instruction {
|
|
|
|
Plain(elements::Instruction),
|
2019-01-22 12:19:29 +03:00
|
|
|
Call(EntryRef<Func>),
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct Memory {
|
|
|
|
limits: elements::ResizableLimits,
|
|
|
|
origin: MemoryOrigin,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Table {
|
|
|
|
origin: TableOrigin,
|
2019-01-21 17:56:30 +03:00
|
|
|
limits: elements::ResizableLimits,
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
struct DataSegment {
|
|
|
|
offset_expr: Vec<Instruction>,
|
|
|
|
data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ElementSegment {
|
|
|
|
offset_expr: Vec<Instruction>,
|
|
|
|
data: Vec<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Export {
|
2019-01-22 12:19:29 +03:00
|
|
|
Func(EntryRef<Func>),
|
|
|
|
Global(EntryRef<Global>),
|
|
|
|
Table(EntryRef<Table>),
|
|
|
|
Memory(EntryRef<Memory>),
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct Module {
|
2019-01-22 12:19:29 +03:00
|
|
|
types: RefList<elements::Type>,
|
|
|
|
funcs: RefList<Func>,
|
|
|
|
tables: RefList<Table>,
|
|
|
|
memory: RefList<Memory>,
|
|
|
|
globals: RefList<Global>,
|
2019-01-21 17:04:31 +03:00
|
|
|
elements: Vec<ElementSegment>,
|
|
|
|
data: Vec<DataSegment>,
|
|
|
|
exports: Vec<Export>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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) => {
|
2019-01-22 12:19:29 +03:00
|
|
|
res.types = RefList::from_slice(type_section.types());
|
2019-01-21 17:56:30 +03:00
|
|
|
},
|
|
|
|
elements::Section::Import(import_section) => {
|
|
|
|
for entry in import_section.entries() {
|
|
|
|
match *entry.external() {
|
|
|
|
elements::External::Function(f) => {
|
|
|
|
res.funcs.push(Func {
|
2019-01-22 12:19:29 +03:00
|
|
|
type_ref: res.types.get(f as usize).expect("validated; qed").clone(),
|
2019-01-21 17:56:30 +03:00
|
|
|
origin: entry.into(),
|
2019-01-22 12:19:29 +03:00
|
|
|
});
|
2019-01-21 17:56:30 +03:00
|
|
|
},
|
|
|
|
elements::External::Memory(m) => {
|
|
|
|
res.memory.push(Memory {
|
|
|
|
limits: m.limits().clone(),
|
|
|
|
origin: entry.into(),
|
2019-01-22 12:19:29 +03:00
|
|
|
});
|
2019-01-21 17:56:30 +03:00
|
|
|
},
|
|
|
|
elements::External::Global(g) => {
|
|
|
|
res.globals.push(Global {
|
|
|
|
content: g.content_type(),
|
|
|
|
is_mut: g.is_mutable(),
|
|
|
|
origin: entry.into(),
|
2019-01-22 12:19:29 +03:00
|
|
|
});
|
2019-01-21 17:56:30 +03:00
|
|
|
},
|
|
|
|
elements::External::Table(t) => {
|
|
|
|
res.tables.push(Table {
|
|
|
|
limits: t.limits().clone(),
|
|
|
|
origin: entry.into(),
|
2019-01-22 12:19:29 +03:00
|
|
|
});
|
2019-01-21 17:56:30 +03:00
|
|
|
},
|
2019-01-22 12:19:29 +03:00
|
|
|
};
|
2019-01-21 17:56:30 +03:00
|
|
|
}
|
2019-01-21 17:04:31 +03:00
|
|
|
},
|
2019-01-22 12:58:29 +03:00
|
|
|
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()),
|
|
|
|
});
|
|
|
|
};
|
|
|
|
},
|
2019-01-21 17:04:31 +03:00
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-22 12:58:29 +03:00
|
|
|
fn parse(wasm: &[u8]) -> Module {
|
|
|
|
Module::from_elements(&::parity_wasm::deserialize_buffer(wasm).expect("failed to parse wasm"))
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
2019-01-22 12:58:29 +03:00
|
|
|
extern crate wabt;
|
|
|
|
use parity_wasm;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn smoky() {
|
|
|
|
let wasm = wabt::wat2wasm(r#"
|
|
|
|
(module
|
|
|
|
(type (func))
|
|
|
|
(func (type 0))
|
|
|
|
)
|
|
|
|
"#).expect("Failed to read fixture");
|
|
|
|
|
|
|
|
let f = super::parse(&wasm[..]);
|
|
|
|
|
|
|
|
assert_eq!(f.types.len(), 1);
|
|
|
|
assert_eq!(f.funcs.len(), 1);
|
|
|
|
}
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|