2018-05-15 08:22:29 +08:00
|
|
|
#[cfg(features = "std")]
|
|
|
|
use std::collections::{HashSet as Set};
|
|
|
|
#[cfg(not(features = "std"))]
|
|
|
|
use std::collections::{BTreeSet as Set};
|
|
|
|
use std::vec::Vec;
|
|
|
|
|
2017-05-04 15:59:22 +03:00
|
|
|
use parity_wasm::elements;
|
|
|
|
|
2018-05-15 08:22:29 +08:00
|
|
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
|
2017-05-04 15:59:22 +03:00
|
|
|
pub enum Symbol {
|
2017-05-19 16:54:53 +03:00
|
|
|
Type(usize),
|
|
|
|
Import(usize),
|
|
|
|
Global(usize),
|
|
|
|
Function(usize),
|
|
|
|
Export(usize),
|
2017-05-04 15:59:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn resolve_function(module: &elements::Module, index: u32) -> Symbol {
|
2017-05-19 16:54:53 +03:00
|
|
|
let mut functions = 0;
|
|
|
|
if let Some(import_section) = module.import_section() {
|
|
|
|
for (item_index, item) in import_section.entries().iter().enumerate() {
|
|
|
|
match item.external() {
|
|
|
|
&elements::External::Function(_) => {
|
|
|
|
if functions == index {
|
|
|
|
return Symbol::Import(item_index as usize);
|
|
|
|
}
|
|
|
|
functions += 1;
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
Symbol::Function(index as usize - functions as usize)
|
2017-05-04 15:59:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn resolve_global(module: &elements::Module, index: u32) -> Symbol {
|
2017-05-19 16:54:53 +03:00
|
|
|
let mut globals = 0;
|
|
|
|
if let Some(import_section) = module.import_section() {
|
|
|
|
for (item_index, item) in import_section.entries().iter().enumerate() {
|
|
|
|
match item.external() {
|
|
|
|
&elements::External::Global(_) => {
|
|
|
|
if globals == index {
|
|
|
|
return Symbol::Import(item_index as usize);
|
|
|
|
}
|
|
|
|
globals += 1;
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
Symbol::Global(index as usize - globals as usize)
|
2017-05-04 15:59:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push_code_symbols(module: &elements::Module, opcodes: &[elements::Opcode], dest: &mut Vec<Symbol>) {
|
2017-05-19 16:54:53 +03:00
|
|
|
use parity_wasm::elements::Opcode::*;
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
for opcode in opcodes {
|
|
|
|
match opcode {
|
|
|
|
&Call(idx) => {
|
|
|
|
dest.push(resolve_function(module, idx));
|
|
|
|
},
|
2017-06-14 15:26:56 +03:00
|
|
|
&CallIndirect(idx, _) => {
|
|
|
|
dest.push(Symbol::Type(idx as usize));
|
|
|
|
},
|
2017-05-19 16:54:53 +03:00
|
|
|
&GetGlobal(idx) | &SetGlobal(idx) => {
|
|
|
|
dest.push(resolve_global(module, idx))
|
|
|
|
},
|
|
|
|
_ => { },
|
2018-05-15 08:22:29 +08:00
|
|
|
}
|
2017-05-19 16:54:53 +03:00
|
|
|
}
|
2017-05-04 15:59:22 +03:00
|
|
|
}
|
|
|
|
|
2018-05-15 08:22:29 +08:00
|
|
|
pub fn expand_symbols(module: &elements::Module, set: &mut Set<Symbol>) {
|
2017-05-19 16:54:53 +03:00
|
|
|
use self::Symbol::*;
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
// symbols that were already processed
|
2018-05-15 08:22:29 +08:00
|
|
|
let mut stop: Set<Symbol> = Set::new();
|
2017-05-19 16:54:53 +03:00
|
|
|
let mut fringe = set.iter().cloned().collect::<Vec<Symbol>>();
|
|
|
|
loop {
|
|
|
|
let next = match fringe.pop() {
|
2018-05-15 08:22:29 +08:00
|
|
|
Some(s) if stop.contains(&s) => { continue; }
|
2017-05-19 16:54:53 +03:00
|
|
|
Some(s) => s,
|
|
|
|
_ => { break; }
|
|
|
|
};
|
|
|
|
trace!("Processing symbol {:?}", next);
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
match next {
|
|
|
|
Export(idx) => {
|
|
|
|
let entry = &module.export_section().expect("Export section to exist").entries()[idx];
|
|
|
|
match entry.internal() {
|
|
|
|
&elements::Internal::Function(func_idx) => {
|
2018-05-15 08:22:29 +08:00
|
|
|
let symbol = resolve_function(module, func_idx);
|
2017-05-19 16:54:53 +03:00
|
|
|
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);
|
|
|
|
}
|
2018-05-15 08:22:29 +08:00
|
|
|
set.insert(symbol);
|
2017-05-19 16:54:53 +03:00
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
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);
|
|
|
|
}
|
2018-05-15 08:22:29 +08:00
|
|
|
set.insert(type_symbol);
|
2017-05-19 16:54:53 +03:00
|
|
|
},
|
2018-05-15 08:22:29 +08:00
|
|
|
_ => {}
|
2017-05-19 16:54:53 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
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);
|
|
|
|
}
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-06-06 16:54:22 +03:00
|
|
|
let signature = &module.function_section().expect("Functions section to exist").entries()[idx];
|
2017-05-19 16:54:53 +03:00
|
|
|
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);
|
2018-05-15 08:22:29 +08:00
|
|
|
}
|
2017-05-19 16:54:53 +03:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2017-05-04 15:59:22 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
stop.insert(next);
|
|
|
|
}
|
2018-05-15 08:22:29 +08:00
|
|
|
}
|