diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 8e23c7c13..c48aa89e8 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -16,17 +16,17 @@ use crate::{ use std::mem; use std::rc::Rc; -pub(crate) struct InstanceInner { +pub struct InstanceInner { #[allow(dead_code)] pub(crate) backing: LocalBacking, import_backing: ImportBacking, - vmctx: Box, + pub vmctx: Box, } /// A WebAssembly instance pub struct Instance { pub module: Rc, - inner: Box, + pub inner: Box, #[allow(dead_code)] imports: Box, } @@ -138,6 +138,33 @@ impl Instance { Ok(returns) } + + pub fn get_signature(&self, name: &str) -> CallResult<&FuncSig> { + let export_index = + self.module + .exports + .get(name) + .ok_or_else(|| CallError::NoSuchExport { + name: name.to_string(), + })?; + + let func_index = if let ExportIndex::Func(func_index) = export_index { + *func_index + } else { + return Err(CallError::ExportNotFunc { + name: name.to_string(), + } + .into()); + }; + + let sig_index = *self + .module + .func_assoc + .get(func_index) + .expect("broken invariant, incorrect func index"); + + Ok(self.module.sig_registry.lookup_func_sig(sig_index)) + } } impl InstanceInner { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7ba636795..4c26d3de6 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -70,10 +70,10 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't compile module: {:?}", e))?; let (_abi, import_object) = if wasmer_emscripten::is_emscripten_module(&module) { - let emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(); + let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(); ( InstanceABI::Emscripten, - wasmer_emscripten::generate_emscripten_env(&emscripten_globals), + wasmer_emscripten::generate_emscripten_env(&mut emscripten_globals), ) } else { ( diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index 5053a33da..265263be9 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -1,14 +1,16 @@ pub mod utils; +use std::{mem::size_of, panic, slice}; use wasmer_runtime::{ self as runtime, + error::CallError, error::{CallResult, Result}, import::ImportObject, instance::Instance, module::Module, + types::{FuncSig, Type, Value}, }; -use std::panic; use wasmer_emscripten::is_emscripten_module; pub struct ResultObject { @@ -85,7 +87,7 @@ pub fn run_instance( module: &Module, instance: &mut Instance, _path: &str, - _args: Vec<&str>, + args: Vec<&str>, ) -> CallResult<()> { let main_name = if is_emscripten_module(module) { "_main" @@ -93,9 +95,120 @@ pub fn run_instance( "main" }; - // TODO handle args - instance.call(main_name, &[])?; + // Get main arguments. + let main_args = get_main_args(main_name, args, instance).unwrap(); + + // Call main function with the arguments. + instance.call(main_name, &main_args)?; + // TODO atinit and atexit for emscripten Ok(()) } + +/// Passes arguments from the host to the WebAssembly instance. +fn get_main_args( + main_name: &str, + args: Vec<&str>, + instance: &mut Instance, +) -> CallResult> { + // Getting main function signature. + let func_sig = instance.get_signature(main_name)?; + let params = &func_sig.params; + + // Check for a () or (i32, i32) sig. + match params.as_slice() { + &[Type::I32, Type::I32] => { + // Copy strings into wasm memory and get addresses to them. + let string_addresses = args + .iter() + .map(|string| copy_string_into_wasm(instance, (*string).to_string()).unwrap()) + .collect(); + + // Create a wasm array to the strings. + let array = create_wasm_array(instance, string_addresses).unwrap(); + + Ok(vec![ + Value::I32(array as i32), + Value::I32(args.len() as i32), + ]) + } + &[] => Ok(vec![]), + _ => Err(CallError::Signature { + expected: FuncSig { + params: vec![Type::I32, Type::I32], + returns: vec![], + }, + found: params.to_vec(), + } + .into()), + } +} + +/// Copy rust string to wasm instance. +fn copy_string_into_wasm(instance: &mut Instance, string: String) -> CallResult { + let string_len = string.len(); + + let space_offset = instance + .call("_malloc", &[Value::I32((string_len as i32) + 1)]) + .unwrap(); + + let space_offset = match space_offset.as_slice() { + &[Value::I32(res)] => Some(res as u32), + _ => None, + }.unwrap(); + + let raw_memory = instance.inner.vmctx.memory(0)[space_offset as usize] as *mut u8; + + let slice = unsafe { slice::from_raw_parts_mut(raw_memory, string_len) }; + + for (byte, loc) in string.bytes().zip(slice.iter_mut()) { + *loc = byte; + } + + unsafe { *raw_memory.add(string_len) = 0 }; + + Ok(space_offset) +} + +/// Create a pointer to an array of items in a wasm memory +fn create_wasm_array(instance: &mut Instance, values: Vec) -> CallResult { + let values_len = values.len(); + + // Space to store pointers to values + let values_offset = instance + .call( + "_malloc", + &[Value::I32((size_of::() * values.len()) as i32)], + ) + .unwrap(); + + let values_offset = match values_offset.as_slice() { + &[Value::I32(res)] => Some(res as u32), + _ => None, + }.unwrap(); + + let raw_memory = instance.inner.vmctx.memory(0)[values_offset as usize] as *mut u32; + + let slice = unsafe { slice::from_raw_parts_mut(raw_memory, values_len) }; + + for (value, loc) in values.iter().zip(slice.iter_mut()) { + *loc = value.clone(); + } + + // Space to store pointer to array + let array_offset = instance + .call("_malloc", &[Value::I32(size_of::() as i32)]) + .unwrap(); + + let array_offset = match array_offset.as_slice() { + &[Value::I32(res)] => Some(res as u32), + _ => None, + }.unwrap(); + + let raw_memory = instance.inner.vmctx.memory(0)[values_offset as usize] as *mut u32; + + unsafe { *raw_memory = values_offset }; + + Ok(array_offset) +}