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

Integrate Ivan's arg parsing code into --invoke #1056

Merged
merged 4 commits into from
Dec 11, 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 @@ -2,6 +2,7 @@

## **[Unreleased]**

- [#1056](https://github.com/wasmerio/wasmer/pull/1056) Improved `--invoke` args parsing (supporting `i32`, `i64`, `f32` and `f32`) in Wasmer CLI
- [#1054](https://github.com/wasmerio/wasmer/pull/1054) Improve `--invoke` output in Wasmer CLI
- [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box<Any + Send> instead of Box<Any>.
- [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend.
Expand Down
22 changes: 7 additions & 15 deletions src/bin/wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use wasmer_runtime_core::{
backend::{Backend, Compiler, CompilerConfig, Features, MemoryBoundCheckMode},
debug,
loader::{Instance as LoadedInstance, LocalLoader},
Module,
};
#[cfg(feature = "wasi")]
use wasmer_wasi;
Expand Down Expand Up @@ -246,18 +247,9 @@ struct Run {

impl Run {
/// Used with the `invoke` argument
fn parse_args(&self) -> Result<Vec<Value>, String> {
let mut args: Vec<Value> = Vec::new();
for arg in self.args.iter() {
let x = arg.as_str().parse().map_err(|_| {
format!(
"Can't parse the provided argument {:?} as a integer",
arg.as_str()
)
})?;
args.push(Value::I32(x));
}
Ok(args)
fn parse_args(&self, module: &Module, fn_name: &str) -> Result<Vec<Value>, String> {
utils::parse_args(module, fn_name, &self.args)
.map_err(|e| format!("Invoke failed: {:?}", e))
}
}

Expand Down Expand Up @@ -493,7 +485,7 @@ fn execute_wasi(

if let Some(invoke_fn) = options.invoke.as_ref() {
eprintln!("WARNING: Invoking aribtrary functions with WASI is not officially supported in the WASI standard yet. Use this feature at your own risk!");
let args = options.parse_args()?;
let args = options.parse_args(&module, invoke_fn)?;
let invoke_result = instance
.dyn_func(invoke_fn)
.map_err(|e| format!("Invoke failed: {:?}", e))?
Expand Down Expand Up @@ -825,12 +817,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
.instantiate(&import_object)
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;

let args = options.parse_args()?;

let invoke_fn = match options.invoke.as_ref() {
Some(fun) => fun,
_ => "main",
};
let args = options.parse_args(&module, invoke_fn)?;

let result = instance
.dyn_func(&invoke_fn)
.map_err(|e| format!("{:?}", e))?
Expand Down
115 changes: 115 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,121 @@
//! Utility functions for the WebAssembly module

use wasmer_runtime::{types::Type, Module, Value};
use wasmer_runtime_core::{backend::SigRegistry, module::ExportIndex};

/// Detect if a provided binary is a Wasm file
pub fn is_wasm_binary(binary: &[u8]) -> bool {
binary.starts_with(&[b'\0', b'a', b's', b'm'])
}

#[derive(Debug, Clone)]
pub enum InvokeError {
CouldNotFindFunction,
ExportNotFunction,
WrongNumArgs { expected: u16, found: u16 },
CouldNotParseArg(String),
}

/// Parses arguments for the `--invoke` flag on the run command
pub fn parse_args(
module: &Module,
fn_name: &str,
args: &[String],
) -> Result<Vec<Value>, InvokeError> {
let export_index = module
.info()
.exports
.get(fn_name)
.ok_or(InvokeError::CouldNotFindFunction)?;

let signature = if let ExportIndex::Func(func_index) = export_index {
let sig_index = module
.info()
.func_assoc
.get(*func_index)
.expect("broken invariant, incorrect func index");
SigRegistry.lookup_signature_ref(&module.info().signatures[*sig_index])
} else {
return Err(InvokeError::ExportNotFunction);
};

let parameter_types = signature.params();
let mut arg_error = None;

if args.len() != parameter_types.len() {
return Err(InvokeError::WrongNumArgs {
expected: parameter_types.len() as _,
found: args.len() as _,
});
} else {
args.iter()
.enumerate()
.try_fold(
Vec::with_capacity(args.len()),
|mut accumulator, (nth, argument)| {
if let Some(value) = match parameter_types[nth] {
Type::I32 => argument
.parse::<i32>()
.map(|v| Some(Value::I32(v)))
.unwrap_or_else(|_| {
arg_error = Some(InvokeError::CouldNotParseArg(format!(
"Failed to parse `{:?}` as an `i32`",
argument
)));
None
}),
Type::I64 => argument
.parse::<i64>()
.map(|v| Some(Value::I64(v)))
.unwrap_or_else(|_| {
arg_error = Some(InvokeError::CouldNotParseArg(format!(
"Failed to parse `{:?}` as an `i64`",
argument
)));
None
}),
Type::V128 => argument
.parse::<u128>()
.map(|v| Some(Value::V128(v)))
.unwrap_or_else(|_| {
arg_error = Some(InvokeError::CouldNotParseArg(format!(
"Failed to parse `{:?}` as an `i128`",
argument
)));
None
}),
Type::F32 => argument
.parse::<f32>()
.map(|v| Some(Value::F32(v)))
.unwrap_or_else(|_| {
arg_error = Some(InvokeError::CouldNotParseArg(format!(
"Failed to parse `{:?}` as an `f32`",
argument
)));
None
}),
Type::F64 => argument
.parse::<f64>()
.map(|v| Some(Value::F64(v)))
.unwrap_or_else(|_| {
arg_error = Some(InvokeError::CouldNotParseArg(format!(
"Failed to parse `{:?}` as an `f64`",
argument
)));
None
}),
} {
accumulator.push(value);

Some(accumulator)
} else {
None
}
},
)
.map_or_else(
|| Err(arg_error.unwrap()),
|arguments: Vec<Value>| Ok(arguments),
)
}
}