From 518669e44c7701bd70c68d718b18680b5e1fe76a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 4 May 2017 15:59:22 +0300 Subject: [PATCH] optimizer decompose --- .gitignore | 2 + Cargo.toml | 21 +++++++ gas/Cargo.toml | 3 +- opt/src/main.rs | 150 +----------------------------------------------- src/lib.rs | 3 + src/symbols.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 179 insertions(+), 148 deletions(-) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/symbols.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cb117fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..860b957 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wasm-utils" +version = "0.1.0" +authors = ["NikVolf "] + +[dependencies] +parity-wasm = { git="https://github.com/nikvolf/parity-wasm" } + +[lib] + +[[bin]] +name = "wasm-opt" +path = "opt/src/main.rs" + +[[bin]] +name = "wasm-ext" +path = "ext/src/main.rs" + +[[bin]] +name = "wasm-gas" +path = "gas/src/main.rs" \ No newline at end of file diff --git a/gas/Cargo.toml b/gas/Cargo.toml index 9a6e489..f0b865e 100644 --- a/gas/Cargo.toml +++ b/gas/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" authors = ["NikVolf "] [dependencies] -parity-wasm = { git="https://github.com/nikvolf/parity-wasm" } \ No newline at end of file +parity-wasm = { git="https://github.com/nikvolf/parity-wasm" } +wasm-utils = { path = "../" } \ No newline at end of file diff --git a/opt/src/main.rs b/opt/src/main.rs index c08e8a0..a1710ea 100644 --- a/opt/src/main.rs +++ b/opt/src/main.rs @@ -1,154 +1,10 @@ extern crate parity_wasm; +extern crate wasm_utils; use std::env; use std::collections::HashSet; use parity_wasm::elements; - -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] -enum Symbol { - Type(usize), - Import(usize), - Global(usize), - Function(usize), - Export(usize), -} - -fn resolve_function(module: &elements::Module, index: u32) -> Symbol { - let mut functions = 0; - for (item_index, item) in module.import_section().expect("Functions section to exist").entries().iter().enumerate() { - match item.external() { - &elements::External::Function(_) => { - if functions == index { - return Symbol::Import(item_index as usize); - } - functions += 1; - }, - _ => {} - } - } - - Symbol::Function(index as usize - functions as usize) -} - -fn resolve_global(module: &elements::Module, index: u32) -> Symbol { - let mut globals = 0; - for (item_index, item) in module.import_section().expect("Functions section to exist").entries().iter().enumerate() { - match item.external() { - &elements::External::Global(_) => { - if globals == index { - return Symbol::Import(item_index as usize); - } - globals += 1; - }, - _ => {} - } - } - - Symbol::Global(index as usize - globals as usize) -} - -fn push_code_symbols(module: &elements::Module, opcodes: &[elements::Opcode], dest: &mut Vec) { - use parity_wasm::elements::Opcode::*; - - for opcode in opcodes { - match opcode { - &Call(idx) => { - dest.push(resolve_function(module, idx)); - }, - &GetGlobal(idx) | &SetGlobal(idx) => { - dest.push(resolve_global(module, idx)) - }, - &If(_, ref block) | &Loop(_, ref block) | &Block(_, ref block) => { - push_code_symbols(module, block.elements(), dest); - }, - _ => { }, - } - } -} - -fn expand_symbols(module: &elements::Module, set: &mut HashSet) { - use Symbol::*; - - // symbols that were already processed - let mut stop: HashSet = HashSet::new(); - let mut fringe = set.iter().cloned().collect::>(); - loop { - let next = match fringe.pop() { - Some(s) if stop.contains(&s) => { continue; } - Some(s) => s, - _ => { break; } - }; - println!("Processing symbol {:?}", next); - - match next { - Export(idx) => { - let entry = &module.export_section().expect("Export section to exist").entries()[idx]; - match entry.internal() { - &elements::Internal::Function(func_idx) => { - let symbol = resolve_function(module, func_idx); - if !stop.contains(&symbol) { - fringe.push(symbol); - } - set.insert(symbol); - }, - &elements::Internal::Global(global_idx) => { - let symbol = resolve_global(module, global_idx); - if !stop.contains(&symbol) { - fringe.push(symbol); - } - set.insert(symbol); - }, - _ => {} - } - }, - Import(idx) => { - let entry = &module.import_section().expect("Import section to exist").entries()[idx]; - match entry.external() { - &elements::External::Function(type_idx) => { - let type_symbol = Symbol::Type(type_idx as usize); - if !stop.contains(&type_symbol) { - fringe.push(type_symbol); - } - set.insert(type_symbol); - }, - _ => {} - } - }, - Function(idx) => { - let body = &module.code_section().expect("Code section to exist").bodies()[idx]; - let mut code_symbols = Vec::new(); - push_code_symbols(module, body.code().elements(), &mut code_symbols); - for symbol in code_symbols.drain(..) { - if !stop.contains(&symbol) { - fringe.push(symbol); - } - set.insert(symbol); - } - - let signature = &module.functions_section().expect("Functions section to exist").entries()[idx]; - let type_symbol = Symbol::Type(signature.type_ref() as usize); - if !stop.contains(&type_symbol) { - fringe.push(type_symbol); - } - set.insert(type_symbol); - }, - Global(idx) => { - let entry = &module.global_section().expect("Global section to exist").entries()[idx]; - let mut code_symbols = Vec::new(); - push_code_symbols(module, entry.init_expr().code(), &mut code_symbols); - for symbol in code_symbols.drain(..) { - if !stop.contains(&symbol) { - fringe.push(symbol); - } - set.insert(symbol); - } - } - _ => {} - } - - stop.insert(next); - } -} +use wasm_utils::symbols::{Symbol, expand_symbols, push_code_symbols, resolve_function}; pub fn update_call_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) { use parity_wasm::elements::Opcode::*; @@ -260,7 +116,7 @@ pub fn type_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elem fn main() { let args = env::args().collect::>(); - if args.len() != 3 { + if args.len() < 3 { println!("Usage: {} input_file.wasm output_file.wasm", args[0]); return; } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..148f964 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +extern crate parity_wasm; + +pub mod symbols; \ No newline at end of file diff --git a/src/symbols.rs b/src/symbols.rs new file mode 100644 index 0000000..f76f9e8 --- /dev/null +++ b/src/symbols.rs @@ -0,0 +1,148 @@ +use parity_wasm::elements; +use std::collections::HashSet; + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +pub enum Symbol { + Type(usize), + Import(usize), + Global(usize), + Function(usize), + Export(usize), +} + +pub fn resolve_function(module: &elements::Module, index: u32) -> Symbol { + let mut functions = 0; + for (item_index, item) in module.import_section().expect("Functions section to exist").entries().iter().enumerate() { + match item.external() { + &elements::External::Function(_) => { + if functions == index { + return Symbol::Import(item_index as usize); + } + functions += 1; + }, + _ => {} + } + } + + Symbol::Function(index as usize - functions as usize) +} + +pub fn resolve_global(module: &elements::Module, index: u32) -> Symbol { + let mut globals = 0; + for (item_index, item) in module.import_section().expect("Functions section to exist").entries().iter().enumerate() { + match item.external() { + &elements::External::Global(_) => { + if globals == index { + return Symbol::Import(item_index as usize); + } + globals += 1; + }, + _ => {} + } + } + + Symbol::Global(index as usize - globals as usize) +} + +pub fn push_code_symbols(module: &elements::Module, opcodes: &[elements::Opcode], dest: &mut Vec) { + use parity_wasm::elements::Opcode::*; + + for opcode in opcodes { + match opcode { + &Call(idx) => { + dest.push(resolve_function(module, idx)); + }, + &GetGlobal(idx) | &SetGlobal(idx) => { + dest.push(resolve_global(module, idx)) + }, + &If(_, ref block) | &Loop(_, ref block) | &Block(_, ref block) => { + push_code_symbols(module, block.elements(), dest); + }, + _ => { }, + } + } +} + +pub fn expand_symbols(module: &elements::Module, set: &mut HashSet) { + use self::Symbol::*; + + // symbols that were already processed + let mut stop: HashSet = HashSet::new(); + let mut fringe = set.iter().cloned().collect::>(); + loop { + let next = match fringe.pop() { + Some(s) if stop.contains(&s) => { continue; } + Some(s) => s, + _ => { break; } + }; + println!("Processing symbol {:?}", next); + + match next { + Export(idx) => { + let entry = &module.export_section().expect("Export section to exist").entries()[idx]; + match entry.internal() { + &elements::Internal::Function(func_idx) => { + let symbol = resolve_function(module, func_idx); + if !stop.contains(&symbol) { + fringe.push(symbol); + } + set.insert(symbol); + }, + &elements::Internal::Global(global_idx) => { + let symbol = resolve_global(module, global_idx); + if !stop.contains(&symbol) { + fringe.push(symbol); + } + set.insert(symbol); + }, + _ => {} + } + }, + Import(idx) => { + let entry = &module.import_section().expect("Import section to exist").entries()[idx]; + match entry.external() { + &elements::External::Function(type_idx) => { + let type_symbol = Symbol::Type(type_idx as usize); + if !stop.contains(&type_symbol) { + fringe.push(type_symbol); + } + set.insert(type_symbol); + }, + _ => {} + } + }, + Function(idx) => { + let body = &module.code_section().expect("Code section to exist").bodies()[idx]; + let mut code_symbols = Vec::new(); + push_code_symbols(module, body.code().elements(), &mut code_symbols); + for symbol in code_symbols.drain(..) { + if !stop.contains(&symbol) { + fringe.push(symbol); + } + set.insert(symbol); + } + + let signature = &module.functions_section().expect("Functions section to exist").entries()[idx]; + let type_symbol = Symbol::Type(signature.type_ref() as usize); + if !stop.contains(&type_symbol) { + fringe.push(type_symbol); + } + set.insert(type_symbol); + }, + Global(idx) => { + let entry = &module.global_section().expect("Global section to exist").entries()[idx]; + let mut code_symbols = Vec::new(); + push_code_symbols(module, entry.init_expr().code(), &mut code_symbols); + for symbol in code_symbols.drain(..) { + if !stop.contains(&symbol) { + fringe.push(symbol); + } + set.insert(symbol); + } + } + _ => {} + } + + stop.insert(next); + } +} \ No newline at end of file