diff --git a/build/src/main.rs b/build/src/main.rs index 71b23b9..681f45f 100644 --- a/build/src/main.rs +++ b/build/src/main.rs @@ -6,9 +6,11 @@ extern crate clap; extern crate parity_wasm; use std::{fs, io}; +use std::io::Write; use std::path::PathBuf; use clap::{App, Arg}; +use parity_wasm::elements; #[derive(Debug)] pub enum Error { @@ -58,6 +60,14 @@ pub fn process_output(target_dir: &str, bin_name: &str) -> Result<(), Error> { Ok(()) } +fn has_ctor(module: &elements::Module) -> bool { + if let Some(ref section) = module.export_section() { + section.entries().iter().find(|e| "_create" == e.field()).is_some() + } else { + false + } +} + fn main() { wasm_utils::init_log(); @@ -102,10 +112,6 @@ fn main() { ); } - if !matches.is_present("skip_optimization") { - wasm_utils::optimize(&mut module, vec!["_call", "setTempRet0"]).expect("Optimizer to finish without errors"); - } - if let Some(runtime_type) = matches.value_of("runtime_type") { let runtime_type: &[u8] = runtime_type.as_bytes(); if runtime_type.len() != 4 { @@ -116,5 +122,26 @@ fn main() { module = wasm_utils::inject_runtime_type(module, &runtime_type, runtime_version); } - parity_wasm::serialize_to_file(&path, module).unwrap(); + let mut ctor_module = module.clone(); + + if !matches.is_present("skip_optimization") { + wasm_utils::optimize(&mut module, vec!["_call", "setTempRet0"]).expect("Optimizer to finish without errors"); + } + + let raw_module = parity_wasm::serialize(module).expect("Failed to serialize module"); + + let mut file = fs::File::create(&path).expect("Failed to create file");; + file.write_all(&raw_module).expect("Failed to write module to file"); + + // will pack into constructor + if has_ctor(&ctor_module) { + if !matches.is_present("skip_optimization") { + wasm_utils::optimize(&mut ctor_module, vec!["_create", "setTempRet0"]).expect("Optimizer to finish without errors"); + } + wasm_utils::pack_instance(raw_module, &mut ctor_module); + + let ctor_path = wasm_path(target_dir, &format!("{}_ctor", wasm_binary)); + parity_wasm::serialize_to_file(ctor_path, ctor_module); + } + } diff --git a/pack/.gitignore b/pack/.gitignore deleted file mode 100644 index f2f9e58..0000000 --- a/pack/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock \ No newline at end of file diff --git a/pack/Cargo.toml b/pack/Cargo.toml deleted file mode 100644 index 71b99c0..0000000 --- a/pack/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "wasm-pack" -version = "0.1.0" -authors = ["NikVolf "] - -[dependencies] -parity-wasm = "0.12" -wasm-utils = { path = "../" } -clap = "2.24" diff --git a/pack/src/main.rs b/pack/src/main.rs deleted file mode 100644 index b8b1e09..0000000 --- a/pack/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -extern crate parity_wasm; -extern crate wasm_utils; -extern crate clap; - -use clap::{App, Arg}; - -fn main() { - wasm_utils::init_log(); - - let matches = App::new("wasm-opt") - .arg(Arg::with_name("input") - .index(1) - .required(true) - .help("Input WASM file")) - .arg(Arg::with_name("output") - .index(2) - .required(true) - .help("Output WASM file")) - .get_matches(); - - let input = matches.value_of("input").expect("is required; qed"); - let output = matches.value_of("output").expect("is required; qed"); - - // doing serialization roundtrip to make sure the input is a valid wasm module - let module = parity_wasm::deserialize_file(&input).expect("Failed to load wasm module from file"); - let bytes = parity_wasm::serialize(module).expect("Failed to serialize wasm module"); - - // Wrap contract code into the wasm module that returns it - let packed_module = wasm_utils::pack_instance(bytes); - - parity_wasm::serialize_to_file(&output, packed_module).unwrap(); -} diff --git a/src/pack.rs b/src/pack.rs index fd2062a..04c8fe4 100644 --- a/src/pack.rs +++ b/src/pack.rs @@ -1,35 +1,83 @@ -use parity_wasm::{elements, builder}; - -pub fn pack_instance(raw_module: Vec) -> elements::Module { +use parity_wasm::{serialize,elements, builder, deserialize_buffer}; +use self::elements::{ External, Section, ResizableLimits, Opcode, DataSegment, InitExpr, Internal }; +/// TODO: desc +pub fn pack_instance(raw_module: Vec, ctor_module: &mut elements::Module) { let raw_len = raw_module.len(); let mem_required = (raw_len / (64 * 1024) + 1) as u32; - let module = builder::module() - .import() - .module("env") - .field("memory") - .external() - .memory(mem_required as u32, Some(mem_required as u32)) - .build() - .data() - .offset(elements::Opcode::I32Const(0)) - .value(raw_module) - .build() - .function() - .signature().param().i32().build() - .body().with_opcodes(elements::Opcodes::new(vec![ - elements::Opcode::GetLocal(0), - elements::Opcode::I32Const(raw_len as i32), - elements::Opcode::I32Store(0, 12), - elements::Opcode::End, - ])).build() - .build() - .export() - .field("_call") - .internal().func(0) - .build() - .build(); + // Func + let create_func_id = { + let export_section = ctor_module.export_section().expect("No export section found"); + let found_entry = export_section.entries().iter() + .find(|entry| "_create" == entry.field()).expect("No export with name _create found"); - module -} \ No newline at end of file + let function_index: usize = match found_entry.internal() { + &Internal::Function(index) => index as usize, + _ => panic!("_create export is not a function"), + }; + + let import_section_len: usize = match ctor_module.import_section() { + Some(import) => + import.entries().iter().filter(|entry| match entry.external() { + &External::Function(_) => true, + _ => false, + }).count(), + None => 0, + }; + + // Calculates a function index within module's function section + function_index - import_section_len + }; + + let mut code_data_address = 0i32; + for section in ctor_module.sections_mut() { + match section { + &mut Section::Data(ref mut data_section) => { + let (index, offset) = if let Some(ref entry) = data_section.entries().iter().last() { + if let Opcode::I32Const(offst) = entry.offset().code()[0] { + let len = entry.value().len() as i32; + let offst = offst as i32; + (entry.index(), offst + len + len % 32) + } else { + (0, 0) + } + } else { + (0, 0) + }; + let code_data = DataSegment::new(index, InitExpr::new(vec![Opcode::I32Const(offset),Opcode::End]), raw_module.clone()); + data_section.entries_mut().push(code_data); + code_data_address = offset; + }, + _ => {;} + } + } + + for section in ctor_module.sections_mut() { + match section { + &mut Section::Export(ref mut export_section) => { + for entry in export_section.entries_mut().iter_mut() { + if "_create" == entry.field() { + // change _create export name into default _call + *entry.field_mut() = "_call".to_owned(); + } + } + } + + &mut Section::Code(ref mut code_section) => { + let code = code_section.bodies_mut()[create_func_id].code_mut().elements_mut(); + code.pop(); + code.extend([ + Opcode::GetLocal(0), + Opcode::I32Const(code_data_address), + Opcode::I32Store(0, 8), + Opcode::GetLocal(0), + Opcode::I32Const(raw_len as i32), + Opcode::I32Store(0, 12), + Opcode::End].iter().cloned()); + }, + + _ => {;}, + } + }; +}