Integrate Ivan's arg parsing code into --invoke

Co-authored-by: Ivan Enderlin <ivan.enderlin@hoa-project.net>
This commit is contained in:
Mark McCaskey 2019-12-10 17:12:35 -08:00
parent c783b7ce90
commit 0a9c41b313
2 changed files with 106 additions and 15 deletions

View File

@ -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;
@ -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))
}
}
@ -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))?
@ -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))?

View File

@ -1,6 +1,105 @@
//! 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, Copy)]
pub enum InvokeError {
CouldNotFindFunction,
ExportNotFunction,
WrongNumArgs { expected: u16, found: u16 },
CouldNotParseArgs,
}
/// 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();
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(|_| {
eprintln!("Failed to parse `{:?}` as an `i32`", argument);
None
}),
Type::I64 => argument
.parse::<i64>()
.map(|v| Some(Value::I64(v)))
.unwrap_or_else(|_| {
eprintln!("Failed to parse `{:?}` as an `i64`", argument);
None
}),
Type::V128 => argument
.parse::<u128>()
.map(|v| Some(Value::V128(v)))
.unwrap_or_else(|_| {
eprintln!("Failed to parse `{:?}` as an `i64`", argument);
None
}),
Type::F32 => argument
.parse::<f32>()
.map(|v| Some(Value::F32(v)))
.unwrap_or_else(|_| {
eprintln!("Failed to parse `{:?}` as an `f32`", argument);
None
}),
Type::F64 => argument
.parse::<f64>()
.map(|v| Some(Value::F64(v)))
.unwrap_or_else(|_| {
eprintln!("Failed to parse `{:?}` as an `f64`", argument);
None
}),
} {
accumulator.push(value);
Some(accumulator)
} else {
None
}
},
)
.map_or_else(
|| Err(InvokeError::CouldNotParseArgs),
|arguments: Vec<Value>| Ok(arguments),
)
}
}