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-22 14:31:21 +03:00
|
|
|
use std::vec::Vec;
|
|
|
|
use std::borrow::ToOwned;
|
|
|
|
use std::string::String;
|
2019-01-22 16:11:04 +03:00
|
|
|
use std::collections::BTreeMap;
|
2019-01-21 17:04:31 +03:00
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub enum ImportedOrDeclared<T=()> {
|
2019-01-21 17:04:31 +03:00
|
|
|
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-22 20:30:50 +03:00
|
|
|
pub type FuncOrigin = ImportedOrDeclared<FuncBody>;
|
2019-01-22 18:28:15 +03:00
|
|
|
pub type GlobalOrigin = ImportedOrDeclared<Vec<Instruction>>;
|
|
|
|
pub type MemoryOrigin = ImportedOrDeclared;
|
|
|
|
pub type TableOrigin = ImportedOrDeclared;
|
2019-01-21 17:04:31 +03:00
|
|
|
|
2019-01-22 20:30:50 +03:00
|
|
|
pub struct FuncBody {
|
|
|
|
pub locals: Vec<elements::Local>,
|
|
|
|
pub code: Vec<Instruction>,
|
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Func {
|
|
|
|
pub type_ref: EntryRef<elements::Type>,
|
|
|
|
pub origin: FuncOrigin,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Global {
|
|
|
|
pub content: elements::ValueType,
|
|
|
|
pub is_mut: bool,
|
|
|
|
pub origin: GlobalOrigin,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub enum Instruction {
|
2019-01-21 17:04:31 +03:00
|
|
|
Plain(elements::Instruction),
|
2019-01-22 12:19:29 +03:00
|
|
|
Call(EntryRef<Func>),
|
2019-01-22 20:30:50 +03:00
|
|
|
CallIndirect(EntryRef<elements::Type>, u8),
|
|
|
|
GetGlobal(EntryRef<Global>),
|
|
|
|
SetGlobal(EntryRef<Global>),
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Memory {
|
|
|
|
pub limits: elements::ResizableLimits,
|
|
|
|
pub origin: MemoryOrigin,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Table {
|
|
|
|
pub origin: TableOrigin,
|
|
|
|
pub limits: elements::ResizableLimits,
|
2019-01-21 17:56:30 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub enum SegmentLocation {
|
2019-01-22 15:15:17 +03:00
|
|
|
Passive,
|
|
|
|
Default(Vec<Instruction>),
|
|
|
|
WithIndex(u32, Vec<Instruction>),
|
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct DataSegment {
|
|
|
|
pub location: SegmentLocation,
|
|
|
|
pub value: Vec<u8>,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct ElementSegment {
|
|
|
|
pub location: SegmentLocation,
|
|
|
|
pub value: Vec<u32>,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub enum ExportLocal {
|
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
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Export {
|
|
|
|
pub name: String,
|
|
|
|
pub local: ExportLocal,
|
2019-01-22 14:42:57 +03:00
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
#[derive(Default)]
|
2019-01-22 18:28:15 +03:00
|
|
|
pub struct Module {
|
|
|
|
pub types: RefList<elements::Type>,
|
|
|
|
pub funcs: RefList<Func>,
|
|
|
|
pub memory: RefList<Memory>,
|
|
|
|
pub tables: RefList<Table>,
|
|
|
|
pub globals: RefList<Global>,
|
|
|
|
pub start: Option<EntryRef<Func>>,
|
|
|
|
pub exports: Vec<Export>,
|
|
|
|
pub elements: Vec<ElementSegment>,
|
|
|
|
pub data: Vec<DataSegment>,
|
|
|
|
pub other: BTreeMap<usize, elements::Section>,
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Module {
|
|
|
|
|
2019-01-22 20:30:50 +03:00
|
|
|
fn map_instructions(&self, instructions: &[elements::Instruction]) -> Vec<Instruction> {
|
|
|
|
use parity_wasm::elements::Instruction::*;
|
|
|
|
instructions.iter().map(|instruction| match instruction {
|
|
|
|
Call(func_idx) => Instruction::Call(self.funcs.clone_ref(*func_idx as usize)),
|
|
|
|
CallIndirect(type_idx, arg2) =>
|
|
|
|
Instruction::CallIndirect(
|
|
|
|
self.types.clone_ref(*type_idx as usize),
|
|
|
|
*arg2,
|
|
|
|
),
|
|
|
|
SetGlobal(global_idx) =>
|
|
|
|
Instruction::SetGlobal(self.globals.clone_ref(*global_idx as usize)),
|
|
|
|
GetGlobal(global_idx) =>
|
|
|
|
Instruction::GetGlobal(self.globals.clone_ref(*global_idx as usize)),
|
|
|
|
other_instruction => Instruction::Plain(other_instruction.clone()),
|
|
|
|
}).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_instructions(&self, instructions: &[Instruction]) -> Vec<elements::Instruction> {
|
|
|
|
use parity_wasm::elements::Instruction::*;
|
|
|
|
instructions.iter().map(|instruction| match instruction {
|
|
|
|
Instruction::Call(func_ref) => Call(func_ref.order().expect("detached instruction!") as u32),
|
|
|
|
Instruction::CallIndirect(type_ref, arg2) => CallIndirect(type_ref.order().expect("detached instruction!") as u32, *arg2),
|
|
|
|
Instruction::SetGlobal(global_ref) => SetGlobal(global_ref.order().expect("detached instruction!") as u32),
|
|
|
|
Instruction::GetGlobal(global_ref) => GetGlobal(global_ref.order().expect("detached instruction!") as u32),
|
|
|
|
Instruction::Plain(plain) => plain.clone(),
|
|
|
|
}).collect()
|
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub fn from_elements(module: &elements::Module) -> Self {
|
2019-01-21 17:04:31 +03:00
|
|
|
|
2019-01-22 16:11:04 +03:00
|
|
|
let mut idx = 0;
|
2019-01-21 17:04:31 +03:00
|
|
|
let mut res = Module::default();
|
|
|
|
|
2019-01-22 20:30:50 +03:00
|
|
|
let mut imported_functions = 0;
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
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-22 20:30:50 +03:00
|
|
|
imported_functions += 1;
|
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(),
|
2019-01-22 20:30:50 +03:00
|
|
|
origin: ImportedOrDeclared::Declared(FuncBody {
|
|
|
|
locals: Vec::new(),
|
|
|
|
// code will be populated later
|
|
|
|
code: Vec::new(),
|
|
|
|
}),
|
2019-01-22 12:58:29 +03:00
|
|
|
});
|
|
|
|
};
|
|
|
|
},
|
2019-01-22 13:03:11 +03:00
|
|
|
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(()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2019-01-22 14:31:21 +03:00
|
|
|
elements::Section::Global(global_section) => {
|
|
|
|
for g in global_section.entries() {
|
2019-01-22 20:30:50 +03:00
|
|
|
let init_code = res.map_instructions(g.init_expr().code());
|
2019-01-22 14:31:21 +03:00
|
|
|
res.globals.push(Global {
|
|
|
|
content: g.global_type().content_type(),
|
|
|
|
is_mut: g.global_type().is_mutable(),
|
2019-01-22 20:30:50 +03:00
|
|
|
origin: ImportedOrDeclared::Declared(init_code),
|
2019-01-22 14:31:21 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
elements::Section::Export(export_section) => {
|
|
|
|
for e in export_section.entries() {
|
2019-01-22 14:42:57 +03:00
|
|
|
let local = match e.internal() {
|
2019-01-22 14:31:21 +03:00
|
|
|
&elements::Internal::Function(func_idx) => {
|
2019-01-22 14:42:57 +03:00
|
|
|
ExportLocal::Func(res.funcs.clone_ref(func_idx as usize))
|
2019-01-22 14:31:21 +03:00
|
|
|
},
|
|
|
|
&elements::Internal::Global(global_idx) => {
|
2019-01-22 14:42:57 +03:00
|
|
|
ExportLocal::Global(res.globals.clone_ref(global_idx as usize))
|
2019-01-22 14:31:21 +03:00
|
|
|
},
|
|
|
|
&elements::Internal::Memory(mem_idx) => {
|
2019-01-22 14:42:57 +03:00
|
|
|
ExportLocal::Memory(res.memory.clone_ref(mem_idx as usize))
|
2019-01-22 14:31:21 +03:00
|
|
|
},
|
|
|
|
&elements::Internal::Table(table_idx) => {
|
2019-01-22 14:42:57 +03:00
|
|
|
ExportLocal::Table(res.tables.clone_ref(table_idx as usize))
|
2019-01-22 14:31:21 +03:00
|
|
|
},
|
2019-01-22 14:42:57 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
res.exports.push(Export { local: local, name: e.field().to_owned() })
|
2019-01-22 14:31:21 +03:00
|
|
|
}
|
|
|
|
},
|
2019-01-22 15:15:17 +03:00
|
|
|
elements::Section::Start(start_func) => {
|
|
|
|
res.start = Some(res.funcs.clone_ref(*start_func as usize));
|
|
|
|
},
|
|
|
|
elements::Section::Element(element_section) => {
|
|
|
|
for element_segment in element_section.entries() {
|
|
|
|
|
|
|
|
// let location = if element_segment.passive() {
|
|
|
|
// SegmentLocation::Passive
|
|
|
|
// } else if element_segment.index() == 0 {
|
|
|
|
// SegmentLocation::Default(Vec::new())
|
|
|
|
// } else {
|
|
|
|
// SegmentLocation::WithIndex(element_segment.index(), Vec::new())
|
|
|
|
// };
|
|
|
|
|
2019-01-22 20:30:50 +03:00
|
|
|
// TODO: update parity-wasm and uncomment the above instead
|
|
|
|
let location = SegmentLocation::Default(
|
|
|
|
res.map_instructions(element_segment.offset().code())
|
|
|
|
);
|
2019-01-22 15:15:17 +03:00
|
|
|
|
|
|
|
res.elements.push(ElementSegment {
|
|
|
|
value: element_segment.members().to_vec(),
|
|
|
|
location: location,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2019-01-22 20:30:50 +03:00
|
|
|
elements::Section::Code(code_section) => {
|
|
|
|
let mut idx = 0;
|
|
|
|
for func_body in code_section.bodies() {
|
|
|
|
let code = res.map_instructions(func_body.code().elements());
|
|
|
|
|
|
|
|
let mut func = res.funcs.get_ref(imported_functions + idx).write();
|
|
|
|
match func.origin {
|
|
|
|
ImportedOrDeclared::Declared(ref mut body) => {
|
|
|
|
body.code = code;
|
|
|
|
body.locals = func_body.locals().iter().cloned().collect();
|
|
|
|
},
|
|
|
|
_ => unreachable!("All declared functions added after imported; qed"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2019-01-22 15:15:17 +03:00
|
|
|
elements::Section::Data(data_section) => {
|
|
|
|
for data_segment in data_section.entries() {
|
2019-01-22 20:30:50 +03:00
|
|
|
// TODO: update parity-wasm and use the same logic as in
|
|
|
|
// commented element segment branch
|
|
|
|
let location = SegmentLocation::Default(
|
|
|
|
res.map_instructions(data_segment.offset().code())
|
|
|
|
);
|
2019-01-22 15:15:17 +03:00
|
|
|
|
|
|
|
res.data.push(DataSegment {
|
|
|
|
value: data_segment.value().to_vec(),
|
|
|
|
location: location,
|
|
|
|
});
|
|
|
|
}
|
2019-01-22 20:30:50 +03:00
|
|
|
},
|
2019-01-22 16:11:04 +03:00
|
|
|
_ => {
|
|
|
|
res.other.insert(idx, section.clone());
|
|
|
|
}
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
idx += 1;
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2019-01-22 16:11:04 +03:00
|
|
|
fn generate(&self) -> elements::Module {
|
|
|
|
use self::ImportedOrDeclared::*;
|
|
|
|
|
|
|
|
let mut idx = 0;
|
|
|
|
let mut sections = Vec::new();
|
|
|
|
|
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.types.len() > 0 {
|
|
|
|
// TYPE SECTION (1)
|
|
|
|
let mut type_section = elements::TypeSection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let types = type_section.types_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for type_entry in self.types.iter() {
|
|
|
|
types.push(type_entry.read().clone())
|
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
sections.push(elements::Section::Type(type_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
|
2019-01-22 16:40:28 +03:00
|
|
|
// IMPORT SECTION (2)
|
|
|
|
let mut import_section = elements::ImportSection::default();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
let add = {
|
2019-01-22 18:21:30 +03:00
|
|
|
let imports = import_section.entries_mut();
|
2019-01-22 16:40:28 +03:00
|
|
|
for func in self.funcs.iter() {
|
|
|
|
match func.read().origin {
|
|
|
|
Imported(ref module, ref field) => {
|
|
|
|
imports.push(
|
|
|
|
elements::ImportEntry::new(
|
|
|
|
module.to_owned(),
|
|
|
|
field.to_owned(),
|
|
|
|
elements::External::Function(
|
|
|
|
func.read().type_ref.order()
|
|
|
|
.expect("detached func encountered somehow!") as u32
|
|
|
|
),
|
|
|
|
)
|
2019-01-22 16:11:04 +03:00
|
|
|
)
|
2019-01-22 16:40:28 +03:00
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 16:40:28 +03:00
|
|
|
for global in self.globals.iter() {
|
|
|
|
match global.read().origin {
|
|
|
|
Imported(ref module, ref field) => {
|
|
|
|
imports.push(
|
|
|
|
elements::ImportEntry::new(
|
|
|
|
module.to_owned(),
|
|
|
|
field.to_owned(),
|
|
|
|
elements::External::Global(
|
|
|
|
elements::GlobalType::new(
|
|
|
|
global.read().content,
|
|
|
|
global.read().is_mut,
|
|
|
|
)
|
|
|
|
),
|
|
|
|
)
|
2019-01-22 16:11:04 +03:00
|
|
|
)
|
2019-01-22 16:40:28 +03:00
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 16:40:28 +03:00
|
|
|
for memory in self.memory.iter() {
|
|
|
|
match memory.read().origin {
|
|
|
|
Imported(ref module, ref field) => {
|
|
|
|
imports.push(
|
|
|
|
elements::ImportEntry::new(
|
|
|
|
module.to_owned(),
|
|
|
|
field.to_owned(),
|
|
|
|
elements::External::Memory(
|
|
|
|
elements::MemoryType::new(
|
|
|
|
memory.read().limits.initial(),
|
|
|
|
memory.read().limits.maximum(),
|
|
|
|
)
|
|
|
|
),
|
|
|
|
)
|
2019-01-22 16:11:04 +03:00
|
|
|
)
|
2019-01-22 16:40:28 +03:00
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for table in self.tables.iter() {
|
|
|
|
match table.read().origin {
|
|
|
|
Imported(ref module, ref field) => {
|
|
|
|
imports.push(
|
|
|
|
elements::ImportEntry::new(
|
|
|
|
module.to_owned(),
|
|
|
|
field.to_owned(),
|
|
|
|
elements::External::Table(
|
|
|
|
elements::TableType::new(
|
|
|
|
table.read().limits.initial(),
|
|
|
|
table.read().limits.maximum(),
|
|
|
|
)
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:11:04 +03:00
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
imports.len() > 0
|
|
|
|
};
|
2019-01-22 16:11:04 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if add {
|
|
|
|
sections.push(elements::Section::Import(import_section));
|
|
|
|
idx += 1;
|
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.funcs.len() > 0 {
|
|
|
|
// FUNC SECTION (3)
|
|
|
|
let mut func_section = elements::FunctionSection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let funcs = func_section.entries_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for func in self.funcs.iter() {
|
|
|
|
match func.read().origin {
|
|
|
|
Declared(_) => {
|
|
|
|
funcs.push(elements::Func::new(
|
|
|
|
func.read().type_ref.order()
|
|
|
|
.expect("detached func encountered somehow!") as u32
|
|
|
|
));
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sections.push(elements::Section::Function(func_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.tables.len() > 0 {
|
|
|
|
// TABLE SECTION (4)
|
|
|
|
let mut table_section = elements::TableSection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let tables = table_section.entries_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for table in self.tables.iter() {
|
|
|
|
match table.read().origin {
|
|
|
|
Declared(_) => {
|
|
|
|
tables.push(elements::TableType::new(
|
|
|
|
table.read().limits.initial(),
|
|
|
|
table.read().limits.maximum(),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
}
|
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
sections.push(elements::Section::Table(table_section));
|
|
|
|
idx += 1;
|
|
|
|
|
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
2019-01-22 16:40:28 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.memory.len() > 0 {
|
|
|
|
// MEMORY SECTION (5)
|
|
|
|
let mut memory_section = elements::MemorySection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let memories = memory_section.entries_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for memory in self.memory.iter() {
|
|
|
|
match memory.read().origin {
|
|
|
|
Declared(_) => {
|
|
|
|
memories.push(elements::MemoryType::new(
|
|
|
|
memory.read().limits.initial(),
|
|
|
|
memory.read().limits.maximum(),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sections.push(elements::Section::Memory(memory_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.globals.len() > 0 {
|
|
|
|
// GLOBAL SECTION (6)
|
|
|
|
let mut global_section = elements::GlobalSection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let globals = global_section.entries_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for global in self.globals.iter() {
|
|
|
|
match global.read().origin {
|
2019-01-22 20:37:36 +03:00
|
|
|
Declared(ref init_code) => {
|
2019-01-22 17:14:37 +03:00
|
|
|
globals.push(elements::GlobalEntry::new(
|
|
|
|
elements::GlobalType::new(global.read().content, global.read().is_mut),
|
2019-01-22 20:37:36 +03:00
|
|
|
elements::InitExpr::new(self.generate_instructions(&init_code[..])),
|
2019-01-22 17:14:37 +03:00
|
|
|
));
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
}
|
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
sections.push(elements::Section::Global(global_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.exports.len() > 0 {
|
2019-01-22 18:21:30 +03:00
|
|
|
// EXPORT SECTION (7)
|
2019-01-22 17:14:37 +03:00
|
|
|
let mut export_section = elements::ExportSection::default();
|
|
|
|
{
|
2019-01-22 18:21:30 +03:00
|
|
|
let exports = export_section.entries_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for export in self.exports.iter() {
|
|
|
|
let internal = match export.local {
|
|
|
|
ExportLocal::Func(ref func_ref) => {
|
|
|
|
elements::Internal::Function(func_ref.order().expect("detached func ref") as u32)
|
|
|
|
},
|
|
|
|
ExportLocal::Global(ref global_ref) => {
|
|
|
|
elements::Internal::Global(global_ref.order().expect("detached global ref") as u32)
|
|
|
|
},
|
|
|
|
ExportLocal::Table(ref table_ref) => {
|
|
|
|
elements::Internal::Table(table_ref.order().expect("detached table ref") as u32)
|
|
|
|
},
|
|
|
|
ExportLocal::Memory(ref memory_ref) => {
|
|
|
|
elements::Internal::Memory(memory_ref.order().expect("detached memory ref") as u32)
|
|
|
|
},
|
|
|
|
};
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
exports.push(elements::ExportEntry::new(export.name.to_owned(), internal));
|
2019-01-22 16:40:28 +03:00
|
|
|
}
|
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
sections.push(elements::Section::Export(export_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 18:21:30 +03:00
|
|
|
if let Some(ref func_ref) = self.start {
|
|
|
|
// START SECTION (8)
|
|
|
|
sections.push(elements::Section::Start(
|
|
|
|
func_ref.order().expect("detached start func") as u32
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.elements.len() > 0 {
|
|
|
|
// START SECTION (9)
|
|
|
|
let mut element_section = elements::ElementSection::default();
|
|
|
|
{
|
|
|
|
let element_segments = element_section.entries_mut();
|
|
|
|
|
|
|
|
for element in self.elements.iter() {
|
|
|
|
match element.location {
|
|
|
|
SegmentLocation::Default(ref offset_expr) => {
|
|
|
|
element_segments.push(
|
|
|
|
elements::ElementSegment::new(
|
|
|
|
0,
|
2019-01-22 20:37:36 +03:00
|
|
|
elements::InitExpr::new(self.generate_instructions(&offset_expr[..])),
|
2019-01-22 18:21:30 +03:00
|
|
|
element.value.clone(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
_ => unreachable!("Other segment location types are never added"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sections.push(elements::Section::Element(element_section));
|
|
|
|
idx += 1;
|
|
|
|
|
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
if self.funcs.len() > 0 {
|
|
|
|
// CODE SECTION (10)
|
|
|
|
let mut code_section = elements::CodeSection::default();
|
|
|
|
{
|
2019-01-22 18:28:15 +03:00
|
|
|
let funcs = code_section.bodies_mut();
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
for func in self.funcs.iter() {
|
|
|
|
match func.read().origin {
|
2019-01-22 20:37:36 +03:00
|
|
|
Declared(ref body) => {
|
2019-01-22 17:14:37 +03:00
|
|
|
funcs.push(elements::FuncBody::new(
|
2019-01-22 20:37:36 +03:00
|
|
|
body.locals.clone(),
|
|
|
|
elements::Instructions::new(self.generate_instructions(&body.code[..])),
|
2019-01-22 17:14:37 +03:00
|
|
|
));
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
}
|
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
sections.push(elements::Section::Code(code_section));
|
|
|
|
idx += 1;
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 17:14:37 +03:00
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
2019-01-22 16:40:28 +03:00
|
|
|
|
2019-01-22 18:21:30 +03:00
|
|
|
|
|
|
|
if self.data.len() > 0 {
|
|
|
|
// DATA SECTION (11)
|
|
|
|
let mut data_section = elements::DataSection::default();
|
|
|
|
{
|
|
|
|
let data_segments = data_section.entries_mut();
|
|
|
|
|
|
|
|
for data_entry in self.data.iter() {
|
|
|
|
match data_entry.location {
|
|
|
|
SegmentLocation::Default(ref offset_expr) => {
|
|
|
|
data_segments.push(
|
|
|
|
elements::DataSegment::new(
|
|
|
|
0,
|
2019-01-22 20:37:36 +03:00
|
|
|
elements::InitExpr::new(self.generate_instructions(&offset_expr[..])),
|
2019-01-22 18:21:30 +03:00
|
|
|
data_entry.value.clone(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
_ => unreachable!("Other segment location types are never added"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sections.push(elements::Section::Data(data_section));
|
|
|
|
idx += 1;
|
|
|
|
|
|
|
|
custom_round(&self.other, &mut idx, &mut sections);
|
|
|
|
}
|
|
|
|
|
2019-01-22 16:11:04 +03:00
|
|
|
elements::Module::new(sections)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn custom_round(
|
|
|
|
map: &BTreeMap<usize, elements::Section>,
|
|
|
|
idx: &mut usize,
|
|
|
|
sections: &mut Vec<elements::Section>,
|
|
|
|
) {
|
|
|
|
while let Some(other_section) = map.get(&idx) {
|
|
|
|
sections.push(other_section.clone());
|
|
|
|
*idx += 1;
|
|
|
|
}
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub fn parse(wasm: &[u8]) -> Module {
|
2019-01-22 12:58:29 +03:00
|
|
|
Module::from_elements(&::parity_wasm::deserialize_buffer(wasm).expect("failed to parse wasm"))
|
|
|
|
}
|
|
|
|
|
2019-01-22 18:28:15 +03:00
|
|
|
pub fn generate(f: &Module) -> Vec<u8> {
|
2019-01-22 17:14:37 +03:00
|
|
|
let pm = f.generate();
|
|
|
|
::parity_wasm::serialize(pm).expect("failed to generate wasm")
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
2019-01-22 12:58:29 +03:00
|
|
|
extern crate wabt;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn smoky() {
|
|
|
|
let wasm = wabt::wat2wasm(r#"
|
|
|
|
(module
|
|
|
|
(type (func))
|
|
|
|
(func (type 0))
|
2019-01-22 13:03:11 +03:00
|
|
|
(memory 0 1)
|
2019-01-22 14:31:21 +03:00
|
|
|
(export "simple" (func 0))
|
2019-01-22 12:58:29 +03:00
|
|
|
)
|
|
|
|
"#).expect("Failed to read fixture");
|
|
|
|
|
|
|
|
let f = super::parse(&wasm[..]);
|
|
|
|
|
|
|
|
assert_eq!(f.types.len(), 1);
|
|
|
|
assert_eq!(f.funcs.len(), 1);
|
2019-01-22 13:03:11 +03:00
|
|
|
assert_eq!(f.tables.len(), 0);
|
|
|
|
assert_eq!(f.memory.len(), 1);
|
2019-01-22 14:31:21 +03:00
|
|
|
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);
|
2019-01-22 12:58:29 +03:00
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[ignore]
|
|
|
|
fn simple_round_trip() {
|
|
|
|
let wat = r#"
|
|
|
|
(module
|
|
|
|
(type (func))
|
2019-01-22 18:21:30 +03:00
|
|
|
(import "env" "f1" (func (type 0)))
|
2019-01-22 17:14:37 +03:00
|
|
|
(memory 0 1)
|
|
|
|
(export "simple" (func 0))
|
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let wasm = wabt::wat2wasm(wat).expect("Failed to read fixture");
|
|
|
|
|
|
|
|
let f = super::parse(&wasm[..]);
|
|
|
|
let wasm_new = super::generate(&f);
|
|
|
|
|
|
|
|
let wat_new = wabt::wasm2wat(&wasm_new).expect("Failed to generate expectation");
|
|
|
|
|
2019-01-22 18:21:30 +03:00
|
|
|
if &wasm_new[..] != &wasm[..] {
|
|
|
|
panic!(
|
|
|
|
"{}\n != \n{}", wat, wat_new
|
|
|
|
);
|
|
|
|
}
|
2019-01-22 17:14:37 +03:00
|
|
|
}
|
|
|
|
|
2019-01-21 17:04:31 +03:00
|
|
|
}
|