mirror of
https://github.com/fluencelabs/wasm-utils
synced 2025-06-30 23:11:41 +00:00
optimizer decompose
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Cargo.lock
|
||||||
|
target
|
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasm-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["NikVolf <nikvolf@gmail.com>"]
|
||||||
|
|
||||||
|
[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"
|
@ -4,4 +4,5 @@ version = "0.1.0"
|
|||||||
authors = ["NikVolf <nikvolf@gmail.com>"]
|
authors = ["NikVolf <nikvolf@gmail.com>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-wasm = { git="https://github.com/nikvolf/parity-wasm" }
|
parity-wasm = { git="https://github.com/nikvolf/parity-wasm" }
|
||||||
|
wasm-utils = { path = "../" }
|
150
opt/src/main.rs
150
opt/src/main.rs
@ -1,154 +1,10 @@
|
|||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
|
extern crate wasm_utils;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use parity_wasm::elements;
|
use parity_wasm::elements;
|
||||||
|
use wasm_utils::symbols::{Symbol, expand_symbols, push_code_symbols, resolve_function};
|
||||||
#[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<Symbol>) {
|
|
||||||
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<Symbol>) {
|
|
||||||
use Symbol::*;
|
|
||||||
|
|
||||||
// symbols that were already processed
|
|
||||||
let mut stop: HashSet<Symbol> = HashSet::new();
|
|
||||||
let mut fringe = set.iter().cloned().collect::<Vec<Symbol>>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_call_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) {
|
pub fn update_call_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) {
|
||||||
use parity_wasm::elements::Opcode::*;
|
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() {
|
fn main() {
|
||||||
|
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 3 {
|
if args.len() < 3 {
|
||||||
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
extern crate parity_wasm;
|
||||||
|
|
||||||
|
pub mod symbols;
|
148
src/symbols.rs
Normal file
148
src/symbols.rs
Normal file
@ -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<Symbol>) {
|
||||||
|
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<Symbol>) {
|
||||||
|
use self::Symbol::*;
|
||||||
|
|
||||||
|
// symbols that were already processed
|
||||||
|
let mut stop: HashSet<Symbol> = HashSet::new();
|
||||||
|
let mut fringe = set.iter().cloned().collect::<Vec<Symbol>>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user