tabify all

This commit is contained in:
NikVolf
2017-05-19 16:54:53 +03:00
parent 360c308e09
commit f2d99ce888
11 changed files with 904 additions and 904 deletions
+11 -11
View File
@@ -5,18 +5,18 @@ use std::env;
fn main() {
wasm_utils::init_log();
wasm_utils::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let module = wasm_utils::externalize(
parity_wasm::deserialize_file(&args[1]).expect("Module to deserialize ok"),
vec!["_free", "_malloc"],
);
let module = wasm_utils::externalize(
parity_wasm::deserialize_file(&args[1]).expect("Module to deserialize ok"),
vec!["_free", "_malloc"],
);
parity_wasm::serialize_to_file(&args[2], module).expect("Module to serialize ok");
parity_wasm::serialize_to_file(&args[2], module).expect("Module to serialize ok");
}
+10 -10
View File
@@ -5,18 +5,18 @@ use std::env;
fn main() {
wasm_utils::init_log();
wasm_utils::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
// Loading module
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
// Loading module
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
let result = wasm_utils::inject_gas_counter(module);
let result = wasm_utils::inject_gas_counter(module);
parity_wasm::serialize_to_file(&args[2], result).expect("Module serialization to succeed")
parity_wasm::serialize_to_file(&args[2], result).expect("Module serialization to succeed")
}
+12 -12
View File
@@ -5,20 +5,20 @@ use std::env;
fn main() {
wasm_utils::init_log();
wasm_utils::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() < 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let args = env::args().collect::<Vec<_>>();
if args.len() < 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let mut module = parity_wasm::deserialize_file(&args[1]).unwrap();
let mut module = parity_wasm::deserialize_file(&args[1]).unwrap();
// Invoke optimizer
// Contract is supposed to have only these functions as public api
// All other symbols not usable by this list is optimized away
wasm_utils::optimize(&mut module, vec!["_call"]).expect("Optimizer to finish without errors");
// Invoke optimizer
// Contract is supposed to have only these functions as public api
// All other symbols not usable by this list is optimized away
wasm_utils::optimize(&mut module, vec!["_call"]).expect("Optimizer to finish without errors");
parity_wasm::serialize_to_file(&args[2], module).unwrap();
parity_wasm::serialize_to_file(&args[2], module).unwrap();
}
+13 -13
View File
@@ -2,26 +2,26 @@ use parity_wasm::interpreter::{self, ModuleInstance};
use runtime::Runtime;
pub struct Arena {
pub runtime: Runtime,
pub runtime: Runtime,
}
#[derive(Debug)]
pub struct Error;
impl Arena {
pub fn alloc(&self, size: u32) -> Result<u32, Error> {
// todo: maybe use unsafe cell since it has nothing to do with threads
let previous_top = self.runtime.env().dynamic_top.get();
self.runtime.env().dynamic_top.set(previous_top + size);
Ok(previous_top)
}
pub fn alloc(&self, size: u32) -> Result<u32, Error> {
// todo: maybe use unsafe cell since it has nothing to do with threads
let previous_top = self.runtime.env().dynamic_top.get();
self.runtime.env().dynamic_top.set(previous_top + size);
Ok(previous_top)
}
}
impl interpreter::UserFunctionInterface for Arena {
fn call(&mut self, _module: &ModuleInstance, context: interpreter::CallerContext) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
let amount = context.value_stack.pop_as::<i32>()?;
self.alloc(amount as u32)
.map(|val| Some((val as i32).into()))
.map_err(|e| interpreter::Error::Trap(format!("Allocator failure: {}", "todo: format arg")))
}
fn call(&mut self, _module: &ModuleInstance, context: interpreter::CallerContext) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
let amount = context.value_stack.pop_as::<i32>()?;
self.alloc(amount as u32)
.map(|val| Some((val as i32).into()))
.map_err(|e| interpreter::Error::Trap(format!("Allocator failure: {}", "todo: format arg")))
}
}
+38 -38
View File
@@ -4,66 +4,66 @@ use runtime;
use WasmMemoryPtr;
fn write_u32(dst: &mut [u8], val: u32) {
dst[0] = (val & 0x000000ff) as u8;
dst[1] = ((val & 0x0000ff00) >> 8) as u8;
dst[2] = ((val & 0x00ff0000) >> 16) as u8;
dst[3] = ((val & 0xff000000) >> 24) as u8;
dst[0] = (val & 0x000000ff) as u8;
dst[1] = ((val & 0x0000ff00) >> 8) as u8;
dst[2] = ((val & 0x00ff0000) >> 16) as u8;
dst[3] = ((val & 0xff000000) >> 24) as u8;
}
#[derive(Debug)]
pub enum Error {
Allocator(runtime::ErrorAlloc),
Interpreter(interpreter::Error),
Allocator(runtime::ErrorAlloc),
Interpreter(interpreter::Error),
}
impl From<runtime::ErrorAlloc> for Error {
fn from(err: runtime::ErrorAlloc) -> Self {
Error::Allocator(err)
}
fn from(err: runtime::ErrorAlloc) -> Self {
Error::Allocator(err)
}
}
impl From<interpreter::Error> for Error {
fn from(err: interpreter::Error) -> Self {
Error::Interpreter(err)
}
fn from(err: interpreter::Error) -> Self {
Error::Interpreter(err)
}
}
pub fn init(
memory: &interpreter::MemoryInstance,
runtime: &mut runtime::Runtime,
input: &[u8],
memory: &interpreter::MemoryInstance,
runtime: &mut runtime::Runtime,
input: &[u8],
) -> Result<WasmMemoryPtr, Error> {
let mut input_ptr_slc = [0u8; 4];
let mut input_length = [0u8; 4];
let mut input_ptr_slc = [0u8; 4];
let mut input_length = [0u8; 4];
let descriptor_ptr = runtime.alloc(16)?;
let descriptor_ptr = runtime.alloc(16)?;
println!("descriptor_ptr: {}", descriptor_ptr);
println!("descriptor_ptr: {}", descriptor_ptr);
if input.len() > 0 {
let input_ptr = runtime.alloc(input.len() as u32)?;
write_u32(&mut input_ptr_slc, input_ptr);
write_u32(&mut input_length, input.len() as u32);
memory.set(input_ptr, input)?;
println!("input_ptr: {}", input_ptr);
} else {
write_u32(&mut input_ptr_slc, 0);
write_u32(&mut input_length, 0);
}
if input.len() > 0 {
let input_ptr = runtime.alloc(input.len() as u32)?;
write_u32(&mut input_ptr_slc, input_ptr);
write_u32(&mut input_length, input.len() as u32);
memory.set(input_ptr, input)?;
println!("input_ptr: {}", input_ptr);
} else {
write_u32(&mut input_ptr_slc, 0);
write_u32(&mut input_length, 0);
}
memory.set(descriptor_ptr, &input_ptr_slc)?;
memory.set(descriptor_ptr+4, &input_length)?;
memory.set(descriptor_ptr, &input_ptr_slc)?;
memory.set(descriptor_ptr+4, &input_length)?;
// zero result ptr/len
memory.set(descriptor_ptr+8, &[0u8; 4])?;
memory.set(descriptor_ptr+12, &[0u8; 4])?;
// zero result ptr/len
memory.set(descriptor_ptr+8, &[0u8; 4])?;
memory.set(descriptor_ptr+12, &[0u8; 4])?;
println!("descriptor: {:?}", memory.get(descriptor_ptr, 16));
println!("descriptor: {:?}", memory.get(descriptor_ptr, 16));
Ok(descriptor_ptr as i32)
Ok(descriptor_ptr as i32)
}
fn _read_u32(slc: &[u8]) -> u32 {
use std::ops::Shl;
(slc[0] as u32) + (slc[1] as u32).shl(8) + (slc[2] as u32).shl(16) + (slc[3] as u32).shl(24)
use std::ops::Shl;
(slc[0] as u32) + (slc[1] as u32).shl(8) + (slc[2] as u32).shl(16) + (slc[3] as u32).shl(24)
}
+59 -59
View File
@@ -1,6 +1,6 @@
/*
Rust contract demo runner
Rust contract demo runner
*/
@@ -19,81 +19,81 @@ pub const DEFAULT_MEMORY_INDEX: interpreter::ItemIndex = interpreter::ItemIndex:
pub type WasmMemoryPtr = i32;
fn main() {
// First, load wasm contract as a module
wasm_utils::init_log();
// First, load wasm contract as a module
wasm_utils::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 2 {
println!("Usage: {} contract.wasm", args[0]);
return;
}
let args = env::args().collect::<Vec<_>>();
if args.len() != 2 {
println!("Usage: {} contract.wasm", args[0]);
return;
}
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
let program = parity_wasm::interpreter::ProgramInstance::new()
.expect("Program instance to be created");
let program = parity_wasm::interpreter::ProgramInstance::new()
.expect("Program instance to be created");
// Add module to the programm
let module_instance = program.add_module("contract", module).expect("Module to be added successfully");
// Add module to the programm
let module_instance = program.add_module("contract", module).expect("Module to be added successfully");
{
let env_instance = program.module("env").expect("env module to exist");
let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0))
.expect("liner memory to exist");
let env_instance = program.module("env").expect("env module to exist");
let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0))
.expect("liner memory to exist");
// Second, create runtime and program instance
let mut runtime = runtime::Runtime::with_params(
env_memory.clone(), // memory shared ptr
5*1024*1024, // default stack space
65536, // runner arbitrary gas limit
);
// Second, create runtime and program instance
let mut runtime = runtime::Runtime::with_params(
env_memory.clone(), // memory shared ptr
5*1024*1024, // default stack space
65536, // runner arbitrary gas limit
);
// Initialize call descriptor
let descriptor = call_args::init(
&*env_memory,
&mut runtime,
&[3u8; 128],
).expect("call descriptor initialization to succeed");
// Initialize call descriptor
let descriptor = call_args::init(
&*env_memory,
&mut runtime,
&[3u8; 128],
).expect("call descriptor initialization to succeed");
// create native env module with native add && sub implementations
let functions = interpreter::UserFunctions {
executor: &mut runtime,
functions: vec![
interpreter::UserFunction {
name: "_storage_read".to_owned(),
params: vec![elements::ValueType::I32, elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "_storage_write".to_owned(),
params: vec![elements::ValueType::I32, elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "_malloc".to_owned(),
params: vec![elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "gas".to_owned(),
params: vec![elements::ValueType::I32],
result: None,
},
interpreter::UserFunction {
name: "_free".to_owned(),
params: vec![elements::ValueType::I32],
result: None,
},
interpreter::UserFunction {
name: "_storage_read".to_owned(),
params: vec![elements::ValueType::I32, elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "_storage_write".to_owned(),
params: vec![elements::ValueType::I32, elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "_malloc".to_owned(),
params: vec![elements::ValueType::I32],
result: Some(elements::ValueType::I32),
},
interpreter::UserFunction {
name: "gas".to_owned(),
params: vec![elements::ValueType::I32],
result: None,
},
interpreter::UserFunction {
name: "_free".to_owned(),
params: vec![elements::ValueType::I32],
result: None,
},
],
};
let native_env_instance = Arc::new(interpreter::env_native_module(env_instance, functions).unwrap());
// Form ExecutionParams (payload + env link)
// Form ExecutionParams (payload + env link)
let params = interpreter::ExecutionParams::with_external("env".into(), native_env_instance)
.add_argument(interpreter::RuntimeValue::I32(descriptor));
.add_argument(interpreter::RuntimeValue::I32(descriptor));
module_instance.execute_export("_call", params)
.expect("_call to execute successfully")
.expect("_call function to return result ptr");
}
module_instance.execute_export("_call", params)
.expect("_call to execute successfully")
.expect("_call function to return result ptr");
}
}
+11 -11
View File
@@ -13,15 +13,15 @@ pub fn call() {
/* This produces the following code (after injecting gas counter & optimizing)
(module
(type (;0;) (func))
(type (;1;) (func (param i32)))
(import "env" "memory" (memory (;0;) 256 256))
(import "env" "table" (table (;0;) 0 0 anyfunc))
(import "env" "gas" (func (;0;) (type 1)))
(func (;1;) (type 0)
i32.const 2
call 0
nop)
(export "_call" (func 1))
(data (i32.const 1212) "\1c\05"))
(type (;0;) (func))
(type (;1;) (func (param i32)))
(import "env" "memory" (memory (;0;) 256 256))
(import "env" "table" (table (;0;) 0 0 anyfunc))
(import "env" "gas" (func (;0;) (type 1)))
(func (;1;) (type 0)
i32.const 2
call 0
nop)
(export "_call" (func 1))
(data (i32.const 1212) "\1c\05"))
*/
+81 -81
View File
@@ -3,99 +3,99 @@ use parity_wasm::{elements, builder};
type Insertion = (usize, u32, u32, String);
pub fn update_call_index(opcodes: &mut elements::Opcodes, original_imports: usize, inserts: &[Insertion]) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
update_call_index(block, original_imports, inserts)
},
&mut Call(ref mut call_index) => {
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;
}
},
_ => { }
}
}
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
update_call_index(block, original_imports, inserts)
},
&mut Call(ref mut call_index) => {
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;
}
},
_ => { }
}
}
}
pub fn externalize(
module: elements::Module,
replaced_funcs: Vec<&str>,
module: elements::Module,
replaced_funcs: Vec<&str>,
) -> elements::Module {
// Save import functions number for later
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();
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();
// 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");
// 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");
if let &elements::Internal::Function(func_idx) = export.1.internal() {
let type_ref = module
.functions_section().expect("Functions section to exist")
.entries()[func_idx as usize - import_funcs_total]
.type_ref();
if let &elements::Internal::Function(func_idx) = export.1.internal() {
let type_ref = module
.functions_section().expect("Functions section to exist")
.entries()[func_idx as usize - import_funcs_total]
.type_ref();
Some((export.0, func_idx, type_ref, export.1.field().to_owned()))
} else {
None
}
})
.collect();
Some((export.0, func_idx, type_ref, export.1.field().to_owned()))
} else {
None
}
})
.collect();
replaces.sort_by_key(|e| e.0);
replaces.sort_by_key(|e| e.0);
// 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()
);
}
// 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()
);
}
// Back to mutable access
let mut module = mbuilder.build();
// Back to mutable access
let mut module = mbuilder.build();
// 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() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
},
_ => {}
}
}
},
_ => { }
}
}
// 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() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
},
_ => {}
}
}
},
_ => { }
}
}
module
module
}
+80 -80
View File
@@ -2,98 +2,98 @@ use parity_wasm::{elements, builder};
pub fn update_call_index(opcodes: &mut elements::Opcodes, inserted_index: u32) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
update_call_index(block, inserted_index)
},
&mut Call(ref mut call_index) => {
if *call_index >= inserted_index { *call_index += 1}
},
_ => { }
}
}
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
update_call_index(block, inserted_index)
},
&mut Call(ref mut call_index) => {
if *call_index >= inserted_index { *call_index += 1}
},
_ => { }
}
}
}
pub fn inject_counter(opcodes: &mut elements::Opcodes, gas_func: u32) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
inject_counter(block, gas_func)
},
_ => { }
}
}
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
inject_counter(block, gas_func)
},
_ => { }
}
}
let ops = opcodes.elements_mut().len() as u32;
opcodes.elements_mut().insert(0, I32Const(ops as i32));
opcodes.elements_mut().insert(1, Call(gas_func));
let ops = opcodes.elements_mut().len() as u32;
opcodes.elements_mut().insert(0, I32Const(ops as i32));
opcodes.elements_mut().insert(1, Call(gas_func));
}
pub fn inject_gas_counter(module: elements::Module) -> elements::Module {
// Injecting gas counting external
let mut mbuilder = builder::from_module(module);
let import_sig = mbuilder.push_signature(
builder::signature()
.param().i32()
.build_sig()
);
// Injecting gas counting external
let mut mbuilder = builder::from_module(module);
let import_sig = mbuilder.push_signature(
builder::signature()
.param().i32()
.build_sig()
);
let mut gas_func = mbuilder.push_import(
builder::import()
.module("env")
.field("gas")
.external().func(import_sig)
.build()
);
let mut gas_func = mbuilder.push_import(
builder::import()
.module("env")
.field("gas")
.external().func(import_sig)
.build()
);
// back to plain module
let mut module = mbuilder.build();
// back to plain module
let mut module = mbuilder.build();
assert!(module.global_section().is_some());
assert!(module.global_section().is_some());
// calculate actual function index of the imported definition
// (substract all imports that are NOT functions)
// calculate actual function index of the imported definition
// (substract all imports that are NOT functions)
for import_entry in module.import_section().expect("Builder should have insert the import section").entries() {
match *import_entry.external() {
elements::External::Function(_) => {},
_ => { gas_func -= 1; }
}
}
for import_entry in module.import_section().expect("Builder should have insert the import section").entries() {
match *import_entry.external() {
elements::External::Function(_) => {},
_ => { gas_func -= 1; }
}
}
// Updating calling addresses (all calls to function index >= `gas_func` should be incremented)
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(), gas_func);
inject_counter(func_body.code_mut(), gas_func);
}
},
&mut elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= gas_func { *func_index += 1}
},
_ => {}
}
}
},
&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 >= gas_func { *func_index += 1}
}
}
},
_ => { }
}
}
// Updating calling addresses (all calls to function index >= `gas_func` should be incremented)
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(), gas_func);
inject_counter(func_body.code_mut(), gas_func);
}
},
&mut elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= gas_func { *func_index += 1}
},
_ => {}
}
}
},
&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 >= gas_func { *func_index += 1}
}
}
},
_ => { }
}
}
module
module
}
+462 -462
View File
File diff suppressed because it is too large Load Diff
+127 -127
View File
@@ -3,150 +3,150 @@ use std::collections::HashSet;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Symbol {
Type(usize),
Import(usize),
Global(usize),
Function(usize),
Export(usize),
Type(usize),
Import(usize),
Global(usize),
Function(usize),
Export(usize),
}
pub fn resolve_function(module: &elements::Module, index: u32) -> Symbol {
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;
},
_ => {}
}
}
}
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;
},
_ => {}
}
}
}
Symbol::Function(index as usize - functions as usize)
Symbol::Function(index as usize - functions as usize)
}
pub fn resolve_global(module: &elements::Module, index: u32) -> Symbol {
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;
},
_ => {}
}
}
}
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;
},
_ => {}
}
}
}
Symbol::Global(index as usize - globals as usize)
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::*;
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);
},
_ => { },
}
}
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::*;
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; }
};
trace!("Processing symbol {:?}", next);
// 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; }
};
trace!("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);
}
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);
}
}
_ => {}
}
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);
}
stop.insert(next);
}
}