2018-05-15 08:22:29 +08:00
|
|
|
use std::string::String;
|
|
|
|
use std::vec::Vec;
|
|
|
|
use std::borrow::ToOwned;
|
|
|
|
|
2017-05-05 16:05:21 +03:00
|
|
|
use parity_wasm::{elements, builder};
|
2017-12-27 12:12:09 +03:00
|
|
|
use optimizer::{import_section, export_section};
|
2018-02-05 18:20:34 +03:00
|
|
|
use byteorder::{LittleEndian, ByteOrder};
|
2017-05-05 16:05:21 +03:00
|
|
|
|
|
|
|
type Insertion = (usize, u32, u32, String);
|
|
|
|
|
2018-06-29 19:01:06 +08:00
|
|
|
pub fn update_call_index(instructions: &mut elements::Instructions, original_imports: usize, inserts: &[Insertion]) {
|
|
|
|
use parity_wasm::elements::Instruction::*;
|
|
|
|
for instruction in instructions.elements_mut().iter_mut() {
|
|
|
|
if let &mut Call(ref mut call_index) = instruction {
|
2018-05-29 22:46:11 -04:00
|
|
|
if let Some(pos) = inserts.iter().position(|x| x.1 == *call_index) {
|
|
|
|
*call_index = (original_imports + pos) as u32;
|
|
|
|
} else if *call_index as usize > original_imports {
|
|
|
|
*call_index += inserts.len() as u32;
|
|
|
|
}
|
2017-05-19 16:54:53 +03:00
|
|
|
}
|
|
|
|
}
|
2017-05-05 16:05:21 +03:00
|
|
|
}
|
|
|
|
|
2017-12-26 14:03:08 +03:00
|
|
|
pub fn memory_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::MemorySection> {
|
2018-05-29 22:46:11 -04:00
|
|
|
for section in module.sections_mut() {
|
|
|
|
if let &mut elements::Section::Memory(ref mut sect) = section {
|
|
|
|
return Some(sect);
|
2017-12-26 14:03:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2018-02-05 19:43:36 +03:00
|
|
|
pub fn externalize_mem(mut module: elements::Module, adjust_pages: Option<u32>, max_pages: u32) -> elements::Module {
|
2018-02-05 18:20:34 +03:00
|
|
|
let mut entry = memory_section(&mut module)
|
2017-12-26 14:03:08 +03:00
|
|
|
.expect("Memory section to exist")
|
|
|
|
.entries_mut()
|
|
|
|
.pop()
|
|
|
|
.expect("Own memory entry to exist in memory section");
|
|
|
|
|
2018-02-05 18:20:34 +03:00
|
|
|
if let Some(adjust_pages) = adjust_pages {
|
2018-02-05 19:43:36 +03:00
|
|
|
assert!(adjust_pages <= max_pages);
|
|
|
|
entry = elements::MemoryType::new(adjust_pages, Some(max_pages));
|
2018-02-05 18:20:34 +03:00
|
|
|
}
|
|
|
|
|
2018-03-24 17:35:39 +03:00
|
|
|
if entry.limits().maximum().is_none() {
|
|
|
|
entry = elements::MemoryType::new(entry.limits().initial(), Some(max_pages));
|
|
|
|
}
|
|
|
|
|
2018-04-18 18:34:26 +03:00
|
|
|
let mut builder = builder::from_module(module);
|
|
|
|
builder.push_import(
|
2017-12-26 16:03:59 +03:00
|
|
|
elements::ImportEntry::new(
|
|
|
|
"env".to_owned(),
|
|
|
|
"memory".to_owned(),
|
|
|
|
elements::External::Memory(entry),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2018-04-18 18:34:26 +03:00
|
|
|
builder.build()
|
2017-12-26 14:03:08 +03:00
|
|
|
}
|
|
|
|
|
2018-01-30 15:21:17 +03:00
|
|
|
fn foreach_public_func_name<F>(mut module: elements::Module, f: F) -> elements::Module
|
|
|
|
where F: Fn(&mut String)
|
|
|
|
{
|
|
|
|
import_section(&mut module).map(|is| {
|
|
|
|
for entry in is.entries_mut() {
|
|
|
|
if let elements::External::Function(_) = *entry.external() {
|
|
|
|
f(entry.field_mut())
|
|
|
|
}
|
2017-12-27 12:12:09 +03:00
|
|
|
}
|
2018-01-30 15:21:17 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
export_section(&mut module).map(|es| {
|
|
|
|
for entry in es.entries_mut() {
|
|
|
|
if let elements::Internal::Function(_) = *entry.internal() {
|
|
|
|
f(entry.field_mut())
|
|
|
|
}
|
2017-12-27 12:12:09 +03:00
|
|
|
}
|
2018-01-30 15:21:17 +03:00
|
|
|
});
|
|
|
|
|
2017-12-27 12:12:09 +03:00
|
|
|
module
|
|
|
|
}
|
|
|
|
|
2018-01-30 15:31:03 +03:00
|
|
|
pub fn underscore_funcs(module: elements::Module) -> elements::Module {
|
2018-01-30 15:21:17 +03:00
|
|
|
foreach_public_func_name(module, |n| n.insert(0, '_'))
|
|
|
|
}
|
|
|
|
|
2018-01-30 15:31:03 +03:00
|
|
|
pub fn ununderscore_funcs(module: elements::Module) -> elements::Module {
|
2018-01-30 15:21:17 +03:00
|
|
|
foreach_public_func_name(module, |n| { n.remove(0); })
|
|
|
|
}
|
|
|
|
|
2018-02-05 18:20:34 +03:00
|
|
|
pub fn shrink_unknown_stack(
|
|
|
|
mut module: elements::Module,
|
|
|
|
// for example, `shrink_amount = (1MB - 64KB)` will limit stack to 64KB
|
|
|
|
shrink_amount: u32,
|
|
|
|
) -> (elements::Module, u32) {
|
|
|
|
let mut new_stack_top = 0;
|
|
|
|
for section in module.sections_mut() {
|
|
|
|
match section {
|
|
|
|
&mut elements::Section::Data(ref mut data_section) => {
|
|
|
|
for ref mut data_segment in data_section.entries_mut() {
|
2018-06-29 19:01:06 +08:00
|
|
|
if data_segment.offset().code() == &[elements::Instruction::I32Const(4), elements::Instruction::End] {
|
2018-02-05 18:20:34 +03:00
|
|
|
assert_eq!(data_segment.value().len(), 4);
|
|
|
|
let current_val = LittleEndian::read_u32(data_segment.value());
|
|
|
|
let new_val = current_val - shrink_amount;
|
|
|
|
LittleEndian::write_u32(data_segment.value_mut(), new_val);
|
|
|
|
new_stack_top = new_val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(module, new_stack_top)
|
|
|
|
}
|
|
|
|
|
2017-05-05 16:05:21 +03:00
|
|
|
pub fn externalize(
|
2017-05-19 16:54:53 +03:00
|
|
|
module: elements::Module,
|
|
|
|
replaced_funcs: Vec<&str>,
|
2017-05-05 16:05:21 +03:00
|
|
|
) -> elements::Module {
|
|
|
|
// Save import functions number for later
|
2017-05-19 16:54:53 +03:00
|
|
|
let import_funcs_total = module
|
|
|
|
.import_section().expect("Import section to exist")
|
|
|
|
.entries()
|
|
|
|
.iter()
|
|
|
|
.filter(|e| if let &elements::External::Function(_) = e.external() { true } else { false })
|
|
|
|
.count();
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
// First, we find functions indices that are to be rewired to externals
|
|
|
|
// Triple is (function_index (callable), type_index, function_name)
|
|
|
|
let mut replaces: Vec<Insertion> = replaced_funcs
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|f| {
|
|
|
|
let export = module
|
|
|
|
.export_section().expect("Export section to exist")
|
|
|
|
.entries().iter().enumerate()
|
|
|
|
.find(|&(_, entry)| entry.field() == f)
|
|
|
|
.expect("All functions of interest to exist");
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
if let &elements::Internal::Function(func_idx) = export.1.internal() {
|
|
|
|
let type_ref = module
|
2017-06-06 16:54:22 +03:00
|
|
|
.function_section().expect("Functions section to exist")
|
2017-05-19 16:54:53 +03:00
|
|
|
.entries()[func_idx as usize - import_funcs_total]
|
|
|
|
.type_ref();
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
Some((export.0, func_idx, type_ref, export.1.field().to_owned()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
replaces.sort_by_key(|e| e.0);
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
// Second, we duplicate them as import definitions
|
|
|
|
let mut mbuilder = builder::from_module(module);
|
|
|
|
for &(_, _, type_ref, ref field) in replaces.iter() {
|
|
|
|
mbuilder.push_import(
|
|
|
|
builder::import()
|
|
|
|
.module("env")
|
|
|
|
.field(field)
|
|
|
|
.external().func(type_ref)
|
|
|
|
.build()
|
|
|
|
);
|
|
|
|
}
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
// Back to mutable access
|
|
|
|
let mut module = mbuilder.build();
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
// Third, rewire all calls to imported functions and update all other calls indices
|
|
|
|
for section in module.sections_mut() {
|
|
|
|
match section {
|
|
|
|
&mut elements::Section::Code(ref mut code_section) => {
|
|
|
|
for ref mut func_body in code_section.bodies_mut() {
|
|
|
|
update_call_index(func_body.code_mut(), import_funcs_total, &replaces);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
&mut elements::Section::Export(ref mut export_section) => {
|
|
|
|
for ref mut export in export_section.entries_mut() {
|
2018-05-29 22:46:11 -04:00
|
|
|
if let &mut elements::Internal::Function(ref mut func_index) = export.internal_mut() {
|
|
|
|
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
|
2017-07-25 18:47:03 +03:00
|
|
|
}
|
2017-05-19 16:54:53 +03:00
|
|
|
}
|
2017-07-25 18:47:03 +03:00
|
|
|
},
|
|
|
|
&mut elements::Section::Element(ref mut elements_section) => {
|
|
|
|
for ref mut segment in elements_section.entries_mut() {
|
|
|
|
// update all indirect call addresses initial values
|
|
|
|
for func_index in segment.members_mut() {
|
|
|
|
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2017-05-19 16:54:53 +03:00
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
}
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2017-05-19 16:54:53 +03:00
|
|
|
module
|
2017-05-05 16:05:21 +03:00
|
|
|
|
2018-05-15 08:22:29 +08:00
|
|
|
}
|