diff --git a/Cargo.toml b/Cargo.toml index 1564f03..771705e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["NikVolf "] [dependencies] -parity-wasm = "0.15" +parity-wasm = "0.18" log = "0.3" env_logger = "0.4" lazy_static = "0.2" @@ -14,6 +14,7 @@ byteorder = "1" [dev-dependencies] tempdir = "0.3" +pwasm-emscripten = { git = "https://github.com/paritytech/parity-wasm", path = "pwasm-emscripten" } [lib] diff --git a/build/Cargo.lock b/build/Cargo.lock index d5dcbf5..3f9003c 100644 --- a/build/Cargo.lock +++ b/build/Cargo.lock @@ -123,7 +123,7 @@ dependencies = [ [[package]] name = "parity-wasm" -version = "0.15.4" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -275,7 +275,7 @@ version = "0.1.0" dependencies = [ "clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-utils 0.1.0", ] @@ -290,7 +290,7 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -321,7 +321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "235801e9531998c4bb307f4ea6833c9f40a4cf132895219ac8c2cd25a9b310f7" +"checksum parity-wasm 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f02e35fda913b8873799b817dcab145d1f935a900722ab7274027949d9947a56" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" diff --git a/build/Cargo.toml b/build/Cargo.toml index 00febda..6871035 100644 --- a/build/Cargo.toml +++ b/build/Cargo.toml @@ -7,7 +7,7 @@ authors = ["NikVolf "] glob = "0.2" wasm-utils = { path = "../" } clap = "2.24" -parity-wasm = "0.15" +parity-wasm = "0.18" [dev-dependencies] tempdir = "0.3" diff --git a/build/src/main.rs b/build/src/main.rs index 0c6c406..dfdb7d8 100644 --- a/build/src/main.rs +++ b/build/src/main.rs @@ -5,6 +5,8 @@ extern crate wasm_utils; extern crate clap; extern crate parity_wasm; +mod source; + use std::{fs, io}; use std::io::Write; use std::path::PathBuf; @@ -12,7 +14,7 @@ use std::path::PathBuf; use clap::{App, Arg}; use parity_wasm::elements; -use wasm_utils::{CREATE_SYMBOL, CALL_SYMBOL}; +use wasm_utils::{CREATE_SYMBOL, CALL_SYMBOL, underscore_funcs}; #[derive(Debug)] pub enum Error { @@ -28,21 +30,26 @@ impl From for Error { } } -pub fn wasm_path(target_dir: &str, bin_name: &str) -> String { - let mut path = PathBuf::from(target_dir); - path.push(format!("{}.wasm", bin_name)); +pub fn wasm_path(input: &source::SourceInput) -> String { + let mut path = PathBuf::from(input.target_dir()); + path.push(format!("{}.wasm", input.final_name())); path.to_string_lossy().to_string() } -pub fn process_output(target_dir: &str, bin_name: &str) -> Result<(), Error> { - let mut cargo_path = PathBuf::from(target_dir); - let wasm_name = bin_name.to_string().replace("-", "_"); - cargo_path.push("wasm32-unknown-emscripten"); +pub fn process_output(input: &source::SourceInput) -> Result<(), Error> { + let mut cargo_path = PathBuf::from(input.target_dir()); + let wasm_name = input.bin_name().to_string().replace("-", "_"); + cargo_path.push( + match input.target() { + source::SourceTarget::Emscripten => source::EMSCRIPTEN_TRIPLET, + source::SourceTarget::Unknown => source::UNKNOWN_TRIPLET, + } + ); cargo_path.push("release"); cargo_path.push(format!("{}.wasm", wasm_name)); - let mut target_path = PathBuf::from(target_dir); - target_path.push(format!("{}.wasm", bin_name)); + let mut target_path = PathBuf::from(input.target_dir()); + target_path.push(format!("{}.wasm", input.final_name())); fs::copy(cargo_path, target_path)?; Ok(()) @@ -79,17 +86,48 @@ fn main() { .help("Injects RUNTIME_VERSION global export") .takes_value(true) .long("runtime-version")) + .arg(Arg::with_name("source_target") + .help("Cargo target type kind ('wasm32-unknown-unknown' or 'wasm32-unknown-emscripten'") + .takes_value(true) + .long("target")) + .arg(Arg::with_name("final_name") + .help("Final wasm binary name") + .takes_value(true) + .long("final")) + .arg(Arg::with_name("save_raw") + .help("Save intermediate raw bytecode to path") + .takes_value(true) + .long("save-raw")) .get_matches(); let target_dir = matches.value_of("target").expect("is required; qed"); let wasm_binary = matches.value_of("wasm").expect("is required; qed"); + let mut source_input = source::SourceInput::new(target_dir, wasm_binary); - process_output(target_dir, wasm_binary).expect("Failed to process cargo target directory"); + let source_target_val = matches.value_of("source_target").unwrap_or_else(|| source::EMSCRIPTEN_TRIPLET); + if source_target_val == source::UNKNOWN_TRIPLET { + source_input = source_input.unknown() + } else if source_target_val == source::EMSCRIPTEN_TRIPLET { + source_input = source_input.emscripten() + } else { + println!("--target can be: '{}' or '{}'", source::EMSCRIPTEN_TRIPLET, source::UNKNOWN_TRIPLET); + ::std::process::exit(1); + } - let path = wasm_path(target_dir, wasm_binary); + if let Some(final_name) = matches.value_of("final_name") { + source_input = source_input.with_final(final_name); + } + + process_output(&source_input).expect("Failed to process cargo target directory"); + + let path = wasm_path(&source_input); let mut module = parity_wasm::deserialize_file(&path).unwrap(); + if let source::SourceTarget::Unknown = source_input.target() { + module = underscore_funcs(module) + } + if let Some(runtime_type) = matches.value_of("runtime_type") { let runtime_type: &[u8] = runtime_type.as_bytes(); if runtime_type.len() != 4 { @@ -106,6 +144,11 @@ fn main() { wasm_utils::optimize(&mut module, vec![CALL_SYMBOL]).expect("Optimizer to finish without errors"); } + if let Some(save_raw_path) = matches.value_of("save_raw") { + parity_wasm::serialize_to_file(save_raw_path, module.clone()) + .expect("Failed to write intermediate module"); + } + let raw_module = parity_wasm::serialize(module).expect("Failed to serialize module"); // If module has an exported function with name=CREATE_SYMBOL @@ -121,7 +164,6 @@ fn main() { let mut file = fs::File::create(&path).expect("Failed to create file"); file.write_all(&raw_module).expect("Failed to write module to file"); } - } #[cfg(test)] @@ -132,6 +174,7 @@ mod tests { use std::fs; use super::process_output; + use super::source::SourceInput; #[test] fn processes_cargo_output() { @@ -148,11 +191,13 @@ mod tests { f.write(b"\0asm").expect("write file failed"); } - process_output(&tmp_dir.path().to_string_lossy(), "example-wasm").expect("process output failed"); + let path = tmp_dir.path().to_string_lossy(); + let input = SourceInput::new(&path, "example-wasm"); + + process_output(&input).expect("process output failed"); assert!( fs::metadata(tmp_dir.path().join("example-wasm.wasm")).expect("metadata failed").is_file() ) } - } diff --git a/build/src/source.rs b/build/src/source.rs new file mode 100644 index 0000000..627bed6 --- /dev/null +++ b/build/src/source.rs @@ -0,0 +1,62 @@ +//! Configuration of source binaries + +pub const UNKNOWN_TRIPLET: &str = "wasm32-unknown-unknown"; +pub const EMSCRIPTEN_TRIPLET: &str = "wasm32-unknown-emscripten"; + +/// Target configiration of previous build step +#[derive(Debug, Clone, Copy)] +pub enum SourceTarget { + Emscripten, + Unknown, +} + +/// Configuration of previous build step (cargo compilation) +#[derive(Debug)] +pub struct SourceInput<'a> { + target_dir: &'a str, + bin_name: &'a str, + final_name: &'a str, + target: SourceTarget, +} + +impl<'a> SourceInput<'a> { + pub fn new<'b>(target_dir: &'b str, bin_name: &'b str) -> SourceInput<'b> { + SourceInput { + target_dir: target_dir, + bin_name: bin_name, + final_name: bin_name, + target: SourceTarget::Emscripten, + } + } + + pub fn unknown(mut self) -> Self { + self.target = SourceTarget::Unknown; + self + } + + pub fn emscripten(mut self) -> Self { + self.target = SourceTarget::Emscripten; + self + } + + pub fn with_final(mut self, final_name: &'a str) -> Self { + self.final_name = final_name; + self + } + + pub fn target_dir(&self) -> &str { + self.target_dir + } + + pub fn bin_name(&self) -> &str { + self.bin_name + } + + pub fn final_name(&self) -> &str { + self.final_name + } + + pub fn target(&self) -> SourceTarget { + self.target + } +} \ No newline at end of file diff --git a/ext/Cargo.toml b/ext/Cargo.toml index 63bf8c5..2e7f8da 100644 --- a/ext/Cargo.toml +++ b/ext/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" authors = ["NikVolf "] [dependencies] -parity-wasm = "0.15" +parity-wasm = "0.18" wasm-utils = { path = "../" } \ No newline at end of file diff --git a/gas/Cargo.toml b/gas/Cargo.toml index 0cd6b75..2fe122b 100644 --- a/gas/Cargo.toml +++ b/gas/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" authors = ["NikVolf "] [dependencies] -parity-wasm = "0.15" +parity-wasm = "0.18" wasm-utils = { path = "../" } \ No newline at end of file diff --git a/prune/Cargo.toml b/prune/Cargo.toml index 3832b1e..b04bed8 100644 --- a/prune/Cargo.toml +++ b/prune/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["NikVolf "] [dependencies] -parity-wasm = "0.15" +parity-wasm = "0.18" wasm-utils = { path = "../" } clap = "2.24" diff --git a/src/ext.rs b/src/ext.rs index c38aebf..10572e7 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -1,4 +1,5 @@ use parity_wasm::{elements, builder}; +use optimizer::{import_section, export_section}; type Insertion = (usize, u32, u32, String); @@ -18,6 +19,50 @@ pub fn update_call_index(opcodes: &mut elements::Opcodes, original_imports: usiz } } +pub fn memory_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::MemorySection> { + for section in module.sections_mut() { + match section { + &mut elements::Section::Memory(ref mut sect) => { + return Some(sect); + }, + _ => { } + } + } + None +} + +pub fn externalize_mem(mut module: elements::Module) -> elements::Module { + let entry = memory_section(&mut module) + .expect("Memory section to exist") + .entries_mut() + .pop() + .expect("Own memory entry to exist in memory section"); + + import_section(&mut module).expect("Import section to exist").entries_mut().push( + elements::ImportEntry::new( + "env".to_owned(), + "memory".to_owned(), + elements::External::Memory(entry), + ) + ); + + module +} + +pub fn underscore_funcs(mut module: elements::Module) -> elements::Module { + for entry in import_section(&mut module).expect("Import section to exist").entries_mut() { + if let elements::External::Function(_) = *entry.external() { + entry.field_mut().insert(0, '_'); + } + } + for entry in export_section(&mut module).expect("Import section to exist").entries_mut() { + if let elements::Internal::Function(_) = *entry.internal() { + entry.field_mut().insert(0, '_'); + } + } + module +} + pub fn externalize( module: elements::Module, replaced_funcs: Vec<&str>, diff --git a/src/lib.rs b/src/lib.rs index 1e994a3..afdb5e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ mod runtime_type; pub use optimizer::{optimize, Error as OptimizerError}; pub use gas::inject_gas_counter; pub use logger::init_log; -pub use ext::externalize; +pub use ext::{externalize, externalize_mem, underscore_funcs}; pub use pack::pack_instance; pub use nondeterminism_check::is_deterministic; pub use runtime_type::inject_runtime_type; diff --git a/src/pack.rs b/src/pack.rs index 6bc64e8..8e0b4a1 100644 --- a/src/pack.rs +++ b/src/pack.rs @@ -129,8 +129,8 @@ pub fn pack_instance(raw_module: Vec, mut ctor_module: elements::Module) -> #[cfg(test)] mod test { + extern crate pwasm_emscripten; extern crate parity_wasm; - extern crate byteorder; use parity_wasm::builder; use parity_wasm::interpreter; @@ -139,6 +139,7 @@ mod test { use super::*; use super::super::optimize; use byteorder::{ByteOrder, LittleEndian}; + use self::pwasm_emscripten::program_with_emscripten_env; #[test] fn call_returns_code() { @@ -194,14 +195,13 @@ mod test { let raw_module = parity_wasm::serialize(module).unwrap(); let ctor_module = pack_instance(raw_module.clone(), ctor_module).expect("Packing failed"); - let program = parity_wasm::DefaultProgramInstance::new().expect("Program instance failed to load"); + let program = program_with_emscripten_env(Default::default()).expect("Wasm program to be created"); let env_instance = program.module("env").expect("Wasm program to contain env module"); let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0)).expect("Linear memory to exist in wasm runtime"); - let execution_params = interpreter::ExecutionParams::default(); let constructor_module = program.add_module("contract", ctor_module, None).expect("Failed to initialize module"); - let _ = constructor_module.execute_export(CALL_SYMBOL, execution_params.add_argument(RuntimeValue::I32(1024))); + let _ = constructor_module.execute_export(CALL_SYMBOL, vec![RuntimeValue::I32(1024)].into()); let pointer = LittleEndian::read_u32(&env_memory.get(1024 + 8, 4).unwrap()); let len = LittleEndian::read_u32(&env_memory.get(1024 + 12, 4).unwrap()); @@ -212,10 +212,9 @@ mod test { let contract_module: elements::Module = parity_wasm::deserialize_buffer(contract_code).expect("Constructed contract module is not valid"); - let program = parity_wasm::DefaultProgramInstance::new().expect("Program2 instance failed to load"); + let program = program_with_emscripten_env(Default::default()).expect("Wasm program to be created"); let contract_module_instance = program.add_module("contract", contract_module, None).expect("Failed to initialize constructed contract module"); - let execution_params = interpreter::ExecutionParams::default(); - contract_module_instance.execute_export(CALL_SYMBOL, execution_params).expect("Constructed contract failed to execute"); + contract_module_instance.execute_export(CALL_SYMBOL, Default::default()).expect("Constructed contract failed to execute"); } }