Files
wasm-utils/src/symbols.rs

158 lines
4.1 KiB
Rust
Raw Normal View History

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
}