use alloc::string::String; use wasmi::TrapKind; use { alloc::format, wasm_sys::SysCall, wasmi::{ Error, Externals, FuncInstance, FuncRef, ImportsBuilder, ModuleImportResolver, ModuleInstance, RuntimeArgs, RuntimeValue, Signature, Trap, ValueType, }, }; mod wasm_sys; struct HostFunctions; impl HostFunctions { fn check_signature(&self, index: usize, signature: &Signature) -> bool { let (params, ret_ty): (&[ValueType], Option) = match index.into() { SysCall::KILL => (&[], None), SysCall::EMPTY => (&[], None), _ => return false, }; signature.params() == params && signature.return_type() == ret_ty } } impl Externals for HostFunctions { fn invoke_index( &mut self, index: usize, args: RuntimeArgs, ) -> Result, Trap> { match index.into() { // Take in one arg discard the rest SysCall::KILL => { info!("Program run at runtime called a system call"); debug!("Runtime arguments: {:?}", args); Ok(None) } // Do nothing SysCall::EMPTY => Ok(None), SysCall::EXIT => Ok(None), SysCall::CONSOLE_RESET => Ok(None), SysCall::CONSOLE_IN => { info!("In"); Ok(None) } SysCall::CONSOLE_OUT => { // Eventually change this to 2- ptr and len if args.len() != 1 { return Err(Trap::new(TrapKind::UnexpectedSignature)); } let arg: u64 = args.nth(0); let buf = unsafe { String::from_utf8_unchecked(arg.to_le_bytes().to_vec()) }; println!["{}", buf]; Ok(None) } SysCall::CONSOLE_GET_TITLE => Ok(None), SysCall::CONSOLE_SET_TITLE => Ok(None), _ => panic!("Unimplemented function at {}", index), } } } impl ModuleImportResolver for HostFunctions { fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { let index = match field_name { "kill" => SysCall::KILL as usize, "empty" => SysCall::EMPTY as usize, "exit" => SysCall::EXIT as usize, "console_out" => SysCall::CONSOLE_OUT as usize, _ => { return Err(Error::Instantiation(format!( "Export {} not found", field_name ))) } }; if !self.check_signature(index, signature) { return Err(Error::Instantiation(format!( "Export {} has a bad signature", field_name ))); } Ok(FuncInstance::alloc_host( Signature::new(&[][..], None), index, )) } } pub fn evaluate() { // let wasm_binary = include_bytes!("bin/console_out_test.wasm"); let wasm_binary = include_bytes!("bin/rust.wasm"); // Load wasm binary and prepare it for instantiation. let module = wasmi::Module::from_buffer(&wasm_binary).expect("failed to load wasm"); let imports = ImportsBuilder::new().with_resolver("env", &HostFunctions); // Instantiate a module with empty imports and // assert that there is no `start` function. let instance = ModuleInstance::new(&module, &imports) // .expect("failed to instantiate wasm module") .unwrap() .assert_no_start(); // Finally, invoke the exported function "test" with no parameters // and empty external function executor. let result: i32 = instance .invoke_export("_start", &[], &mut HostFunctions) .expect("failed to execute export") .unwrap() .try_into() .unwrap(); println!("{:?}", result); }