diff --git a/src/graph.rs b/src/graph.rs index ba48e98..6907144 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -18,11 +18,16 @@ impl From<&elements::ImportEntry> for ImportedOrDeclared { } } -pub type FuncOrigin = ImportedOrDeclared>; +pub type FuncOrigin = ImportedOrDeclared; pub type GlobalOrigin = ImportedOrDeclared>; pub type MemoryOrigin = ImportedOrDeclared; pub type TableOrigin = ImportedOrDeclared; +pub struct FuncBody { + pub locals: Vec, + pub code: Vec, +} + pub struct Func { pub type_ref: EntryRef, pub origin: FuncOrigin, @@ -37,6 +42,9 @@ pub struct Global { pub enum Instruction { Plain(elements::Instruction), Call(EntryRef), + CallIndirect(EntryRef, u8), + GetGlobal(EntryRef), + SetGlobal(EntryRef), } pub struct Memory { @@ -93,11 +101,41 @@ pub struct Module { impl Module { + fn map_instructions(&self, instructions: &[elements::Instruction]) -> Vec { + 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 { + 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() + } + pub fn from_elements(module: &elements::Module) -> Self { let mut idx = 0; let mut res = Module::default(); + let mut imported_functions = 0; + for section in module.sections() { match section { elements::Section::Type(type_section) => { @@ -111,6 +149,7 @@ impl Module { type_ref: res.types.get(f as usize).expect("validated; qed").clone(), origin: entry.into(), }); + imported_functions += 1; }, elements::External::Memory(m) => { res.memory.push(Memory { @@ -138,8 +177,11 @@ impl Module { 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()), + origin: ImportedOrDeclared::Declared(FuncBody { + locals: Vec::new(), + // code will be populated later + code: Vec::new(), + }), }); }; }, @@ -161,11 +203,11 @@ impl Module { }, elements::Section::Global(global_section) => { for g in global_section.entries() { + let init_code = res.map_instructions(g.init_expr().code()); 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()), + origin: ImportedOrDeclared::Declared(init_code), }); } }, @@ -205,9 +247,10 @@ impl Module { // SegmentLocation::WithIndex(element_segment.index(), Vec::new()) // }; - // TODO: transform instructions - // TODO: update parity-wasm and uncomment the above - let location = SegmentLocation::Default(Vec::new()); + // TODO: update parity-wasm and uncomment the above instead + let location = SegmentLocation::Default( + res.map_instructions(element_segment.offset().code()) + ); res.elements.push(ElementSegment { value: element_segment.members().to_vec(), @@ -215,18 +258,35 @@ impl Module { }); } }, + 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"), + } + } + }, elements::Section::Data(data_section) => { for data_segment in data_section.entries() { - // TODO: transform instructions - // TODO: update parity-wasm and uncomment the above - let location = SegmentLocation::Default(Vec::new()); + // 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()) + ); res.data.push(DataSegment { value: data_segment.value().to_vec(), location: location, }); } - } + }, _ => { res.other.insert(idx, section.clone()); } diff --git a/src/ref_list.rs b/src/ref_list.rs index df10547..4679fe7 100644 --- a/src/ref_list.rs +++ b/src/ref_list.rs @@ -45,6 +45,12 @@ impl ::std::ops::Deref for Entry { } } +impl ::std::ops::DerefMut for Entry { + fn deref_mut(&mut self) -> &mut T { + &mut self.val + } +} + pub struct EntryRef(Rc>>); impl Clone for EntryRef {