Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hook up wasi exit code to wasmer cli #383

Merged
merged 6 commits into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions examples/exit.wat
Original file line number Diff line number Diff line change
@@ -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))
)
)
120 changes: 72 additions & 48 deletions src/bin/wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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,
)
} else {
(
InstanceABI::None,
wasmer_runtime_core::import::ImportObject::new(),
None,
)
}
};
options.pre_opened_directories.clone(),
);

let mut instance = module
.instantiate(&import_object)
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;
let instance = module
.instantiate(&import_object)
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;

webassembly::run_instance(
lachlansneff marked this conversation as resolved.
Show resolved Hide resolved
&module,
&mut instance,
abi,
if let Some(cn) = &options.command_name {
cn
let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't seem to be agreement on _start function yet (see linked wasi issue):
#362

This is a little out of scope of this PR but maybe we could only call _start if it exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wasn't sure what to do for that. Maybe we should keep as is and make a different pr for that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think a separate PR.


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::<wasmer_wasi::ExitCode>() {
std::process::exit(error_code.code as i32)
}
}
}
panic!("error: {:?}", err)
}
} else {
options.path.to_str().unwrap()
},
options.args.iter().map(|arg| arg.as_str()).collect(),
)
.map_err(|e| format!("{:?}", e))?;
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<Value> = 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))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also sort of unrelated to this PR, I hope this becomes a command:
#281 (comment)
wasmer call file.wasm function_name arg1 arg2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, we should make an issue for that.

}
}

Ok(())
}
Expand Down
37 changes: 0 additions & 37 deletions src/webassembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,40 +77,3 @@ pub fn compile(buffer_source: &[u8]) -> Result<Module> {
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<Module> {
// 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<Value> = args
.into_iter()
.map(|x| Value::I32(x.parse().unwrap()))
.collect();
instance.call("main", &args)?;
}
}
Ok(())
}