diff --git a/CHANGELOG.md b/CHANGELOG.md index 3921ac8b4..c4deaceb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file. Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli. - [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends - [#381](https://github.com/wasmerio/wasmer/pull/381) Allow retrieving propagated user errors. - [#379](https://github.com/wasmerio/wasmer/pull/379) Fix small return types from imported functions. diff --git a/examples/exit.wat b/examples/exit.wat new file mode 100644 index 000000000..b2f832cb3 --- /dev/null +++ b/examples/exit.wat @@ -0,0 +1,11 @@ +(module + (import "wasi_unstable" "proc_exit" (func $proc_exit (param i32))) + (export "_start" (func $_start)) + + (memory 10) + (export "memory" (memory 0)) + + (func $_start + (call $proc_exit (i32.const 7)) + ) +) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 4ab012045..6774fab58 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -11,12 +11,15 @@ use std::str::FromStr; use hashbrown::HashMap; use structopt::StructOpt; -use wasmer::webassembly::InstanceABI; use wasmer::*; use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend:llvm")] use wasmer_llvm_backend::LLVMCompiler; -use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}; +use wasmer_runtime::{ + cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}, + error::RuntimeError, + Func, Value, +}; use wasmer_runtime_core::{ self, backend::{Compiler, CompilerConfig}, @@ -301,60 +304,81 @@ fn execute_wasm(options: &Run) -> Result<(), String> { }; // TODO: refactor this - let (abi, import_object, _em_globals) = if wasmer_emscripten::is_emscripten_module(&module) { + if wasmer_emscripten::is_emscripten_module(&module) { let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module); - ( - InstanceABI::Emscripten, - wasmer_emscripten::generate_emscripten_env(&mut emscripten_globals), - Some(emscripten_globals), // TODO Em Globals is here to extend, lifetime, find better solution + let import_object = wasmer_emscripten::generate_emscripten_env(&mut emscripten_globals); + let mut instance = module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate module: {:?}", e))?; + + wasmer_emscripten::run_emscripten_instance( + &module, + &mut instance, + if let Some(cn) = &options.command_name { + cn + } else { + options.path.to_str().unwrap() + }, + options.args.iter().map(|arg| arg.as_str()).collect(), ) + .map_err(|e| format!("{:?}", e))?; } else { if cfg!(feature = "wasi") && wasmer_wasi::is_wasi_module(&module) { - ( - InstanceABI::WASI, - wasmer_wasi::generate_import_object( - if let Some(cn) = &options.command_name { - [cn.clone()] - } else { - [options.path.to_str().unwrap().to_owned()] - } - .iter() - .chain(options.args.iter()) - .cloned() - .map(|arg| arg.into_bytes()) + let import_object = wasmer_wasi::generate_import_object( + if let Some(cn) = &options.command_name { + [cn.clone()] + } else { + [options.path.to_str().unwrap().to_owned()] + } + .iter() + .chain(options.args.iter()) + .cloned() + .map(|arg| arg.into_bytes()) + .collect(), + env::vars() + .map(|(k, v)| format!("{}={}", k, v).into_bytes()) .collect(), - env::vars() - .map(|(k, v)| format!("{}={}", k, v).into_bytes()) - .collect(), - options.pre_opened_directories.clone(), - ), - None, - ) + options.pre_opened_directories.clone(), + ); + + let instance = module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate module: {:?}", e))?; + + let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; + + let result = start.call(); + + if let Err(ref err) = result { + match err { + RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg), + RuntimeError::Error { data } => { + if let Some(error_code) = data.downcast_ref::() { + std::process::exit(error_code.code as i32) + } + } + } + panic!("error: {:?}", err) + } } else { - ( - InstanceABI::None, - wasmer_runtime_core::import::ImportObject::new(), - None, - ) + let import_object = wasmer_runtime_core::import::ImportObject::new(); + let instance = module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate module: {:?}", e))?; + + let args: Vec = options + .args + .iter() + .map(|arg| arg.as_str()) + .map(|x| Value::I32(x.parse().unwrap())) + .collect(); + instance + .dyn_func("main") + .map_err(|e| format!("{:?}", e))? + .call(&args) + .map_err(|e| format!("{:?}", e))?; } - }; - - let mut instance = module - .instantiate(&import_object) - .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - - webassembly::run_instance( - &module, - &mut instance, - abi, - if let Some(cn) = &options.command_name { - cn - } else { - options.path.to_str().unwrap() - }, - options.args.iter().map(|arg| arg.as_str()).collect(), - ) - .map_err(|e| format!("{:?}", e))?; + } Ok(()) } diff --git a/src/webassembly.rs b/src/webassembly.rs index 354136ead..3d051f078 100644 --- a/src/webassembly.rs +++ b/src/webassembly.rs @@ -77,40 +77,3 @@ pub fn compile(buffer_source: &[u8]) -> Result { let module = runtime::compile(buffer_source)?; Ok(module) } - -// /// The same as `compile` but takes a `CompilerConfig` for the purpose of -// /// changing the compiler's behavior -// pub fn compile_with_config_with( -// buffer_source: &[u8], -// compiler_config: CompilerConfig, -// ) -> Result { -// let module = runtime::compile_with_config(buffer_source, compiler_config)?; -// Ok(module) -// } - -/// Performs common instance operations needed when an instance is first run -/// including data setup, handling arguments and calling a main function -pub fn run_instance( - module: &Module, - instance: &mut Instance, - abi: InstanceABI, - path: &str, - args: Vec<&str>, -) -> CallResult<()> { - match abi { - InstanceABI::Emscripten => { - run_emscripten_instance(module, instance, path, args)?; - } - InstanceABI::WASI => { - instance.call("_start", &[])?; - } - InstanceABI::None => { - let args: Vec = args - .into_iter() - .map(|x| Value::I32(x.parse().unwrap())) - .collect(); - instance.call("main", &args)?; - } - } - Ok(()) -}