From 07fe0bb39ea0a019bb73e6b78cc94d8d2539ac16 Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 12 Jun 2020 00:05:04 +0300 Subject: [PATCH] repair put/get --- Cargo.lock | 7 + examples/ipfs_node/Cargo.toml | 1 + examples/ipfs_node/Config.toml | 2 +- examples/ipfs_node/src/imports.rs | 130 +++++++++++------- examples/ipfs_node/src/lib.rs | 1 + examples/ipfs_node/src/main.rs | 3 +- examples/ipfs_node/src/node.rs | 24 ++-- .../ipfs_node/src/node_public_interface.rs | 6 +- examples/ipfs_node/wasm/ipfs_node/src/main.rs | 16 ++- examples/ipfs_node/wasm/ipfs_node/wit | 6 +- examples/ipfs_node/wasm/ipfs_rpc/src/main.rs | 23 ++-- examples/ipfs_node/wasm/ipfs_rpc/wit | 8 +- fce/src/vm/module/fce_module.rs | 22 ++- fce/src/vm/module/wit_function.rs | 19 +-- 14 files changed, 167 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d00fe227..8a8685d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cmd_lib" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475bd7aa7680b4ed8f6bb59745e882bcbaeb39326532bb79ffb1716480d9a274" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -514,6 +520,7 @@ dependencies = [ name = "ipfs_node" version = "0.1.0" dependencies = [ + "cmd_lib", "fce", "serde", "serde_derive", diff --git a/examples/ipfs_node/Cargo.toml b/examples/ipfs_node/Cargo.toml index c3c657f2..e7715903 100644 --- a/examples/ipfs_node/Cargo.toml +++ b/examples/ipfs_node/Cargo.toml @@ -15,3 +15,4 @@ toml = "0.5.6" serde = { version = "1.0.111", features = ["derive"] } serde_json = "1.0.53" serde_derive = "1.0.111" +cmd_lib = "0.7.8" diff --git a/examples/ipfs_node/Config.toml b/examples/ipfs_node/Config.toml index 286b683e..bc55ba70 100644 --- a/examples/ipfs_node/Config.toml +++ b/examples/ipfs_node/Config.toml @@ -19,4 +19,4 @@ [rpc_module.wasi] envs = ["asdsad=sdaasd"] preopened_files = ["/Users/mike/dev/work/fluence/wasm/tmp"] - mapped_dirs = { "/tmp/" = "/Users/mike/dev/work/fluence/wasm/tmp" } + mapped_dirs = { "/tmp" = "/Users/mike/dev/work/fluence/wasm/tmp" } diff --git a/examples/ipfs_node/src/imports.rs b/examples/ipfs_node/src/imports.rs index 9a8a7807..dda98ee3 100644 --- a/examples/ipfs_node/src/imports.rs +++ b/examples/ipfs_node/src/imports.rs @@ -26,7 +26,12 @@ use wasmer_core::backend::SigRegistry; use wasmer_runtime::types::LocalOrImport; use wasmer_core::module::ExportIndex; -const ALLOCATE_FUNC_NAME: &'static str = "allocate"; +use std::collections::HashMap; +use cmd_lib::run_fun; + +const ALLOCATE_FUNC_NAME: &str = "allocate"; +const SET_PTR_FUNC_NAME: &str = "set_result_ptr"; +const SET_SIZE_FUNC_NAME: &str = "set_result_size"; pub(super) fn log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { use wasmer_core::memory::ptr::{Array, WasmPtr}; @@ -38,7 +43,7 @@ pub(super) fn log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { } } -// rewrited from Wasmer: https://github.com/wasmerio/wasmer/blob/081f6250e69b98b9f95a8f62ad6d8386534f3279/lib/runtime-core/src/instance.rs#L863 +// based on Wasmer: https://github.com/wasmerio/wasmer/blob/081f6250e69b98b9f95a8f62ad6d8386534f3279/lib/runtime-core/src/instance.rs#L863 unsafe fn get_export_func_by_name<'a, Args, Rets>( ctx: &'a mut Ctx, name: &str, @@ -108,68 +113,99 @@ where Ok(typed_func) } -pub(super) fn create_host_import_func(host_cmd: String) -> DynamicFunc<'static> { - let allocate_func: Option> = None; - let set_result_ptr: Option> = None; - let set_result_size: Option> = None; +#[allow(dead_code)] +fn to_full_path(cmd: S, mapped_dirs: &HashMap) -> String +where + S: Into, +{ + use std::str::pattern::Pattern; + + fn find_start_at<'a, P: Pattern<'a>>(slice: &'a str, at: usize, pat: P) -> Option { + slice[at..].find(pat).map(|i| at + i) + } + + let cmd = cmd.into(); + + if cmd.is_empty() || mapped_dirs.is_empty() { + return cmd; + } + + // assume that string is started with / + let from_dir = if let Some(found_pos) = find_start_at(&cmd, 1, '/') { + // it is safe because we are splitting on the found position + cmd.split_at(found_pos) + } else { + (cmd.as_str(), "") + }; + + match mapped_dirs.get(from_dir.0) { + Some(to_dir) => { + let ret = format!("{}/{}", to_dir, from_dir.1); + println!("ret is {}", ret); + ret + } + None => cmd, + } +} + +fn write_to_mem(context: &mut Ctx, address: usize, value: &[u8]) { + let memory = context.memory(0); + + for (byte_id, cell) in memory.view::()[address as usize..(address + value.len())] + .iter() + .enumerate() + { + cell.set(value[byte_id]); + } +} + +pub(super) fn create_host_import_func(host_cmd: S) -> DynamicFunc<'static> +where + S: Into, +{ + /* + let mut allocate_func: Option> = None; + let mut set_result_ptr: Option> = None; + let mut set_result_size: Option> = None; + */ + + let host_cmd = host_cmd.into(); let func = move |ctx: &mut Ctx, inputs: &[Value]| -> Vec { use wasmer_core::memory::ptr::{Array, WasmPtr}; - println!("inputs size is {}", inputs.len()); - - // TODO: refactor this let array_ptr = inputs[0].to_u128() as i32; let array_size = inputs[1].to_u128() as i32; - println!("ptr is {}, size is {}", array_ptr, array_size); let wasm_ptr = WasmPtr::::new(array_ptr as _); let result = match wasm_ptr.get_utf8_string(ctx.memory(0), array_size as _) { Some(arg_value) => { - let output = std::process::Command::new(host_cmd.clone()) - .arg(arg_value) - .output() - .unwrap(); - output.stdout + // let arg_value = " add -Q /Users/mike/dev/work/fluence/wasm/tmp/ipfs_rpc_file"; + let output = run_fun!("{} {}", host_cmd, arg_value).unwrap(); + output } - None => b"host callback: incorrect UTF8 string's been supplied to import".to_vec(), + None => return vec![Value::I32(1)], }; - println!("from host import function: result is {:?}", result); - unsafe { - if let mut allocate_func = None { - let func = match get_export_func_by_name::(ctx, ALLOCATE_FUNC_NAME) { - Ok(func) => func, - Err(_) => return vec![Value::I32(0)], - }; - allocate_func = Some(func); - } + let mem_address = match get_export_func_by_name::(ctx, ALLOCATE_FUNC_NAME) { + Ok(func) => func.call(result.len() as i32).unwrap(), + Err(_) => return vec![Value::I32(2)], + }; - if let mut set_result_ptr = None { - let func = match get_export_func_by_name::(ctx, ALLOCATE_FUNC_NAME) { - Ok(func) => func, - Err(_) => return vec![Value::I32(0)], - }; - set_result_ptr = Some(func); - } + write_to_mem(ctx, mem_address as usize, result.as_bytes()); - if let mut set_result_size = None { - let func = match get_export_func_by_name::(ctx, ALLOCATE_FUNC_NAME) { - Ok(func) => func, - Err(_) => return vec![Value::I32(0)], - }; - set_result_size = Some(func); - } - let mem_address = allocate_func - .clone() - .unwrap() - .call(result.len() as i32) - .unwrap(); - let _ = set_result_ptr.clone().unwrap().call(mem_address as i32); - let _ = set_result_size.clone().unwrap().call(result.len() as i32); + match get_export_func_by_name::(ctx, SET_PTR_FUNC_NAME) { + Ok(func) => func.call(mem_address as i32).unwrap(), + Err(_) => return vec![Value::I32(3)], + }; - vec![Value::I32(1)] + match get_export_func_by_name::(ctx, SET_SIZE_FUNC_NAME) { + Ok(func) => func.call(result.len() as i32).unwrap(), + Err(_) => return vec![Value::I32(4)], + }; + + vec![Value::I32(0)] } }; diff --git a/examples/ipfs_node/src/lib.rs b/examples/ipfs_node/src/lib.rs index f951f12b..d8b2357d 100644 --- a/examples/ipfs_node/src/lib.rs +++ b/examples/ipfs_node/src/lib.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#![feature(pattern)] mod node; mod errors; diff --git a/examples/ipfs_node/src/main.rs b/examples/ipfs_node/src/main.rs index bd2db8e4..55e799c5 100644 --- a/examples/ipfs_node/src/main.rs +++ b/examples/ipfs_node/src/main.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#![feature(pattern)] mod node; mod errors; @@ -44,7 +45,7 @@ fn main() { println!("ipfs node interface is\n{}", ipfs_node.get_interface()); let result = ipfs_node - .rpc_call(&ipfs_rpc, "put", &[IValue::String("asdsad".to_string())]) + .rpc_call(&ipfs_rpc, "put", &[IValue::String("QmdHsYnAvbrvXg3iwr6bLaqooVT31E8CMpZRWc9wX2Fbt8".to_string())]) .unwrap(); println!("execution result {:?}", result); diff --git a/examples/ipfs_node/src/node.rs b/examples/ipfs_node/src/node.rs index 3b435141..01d01775 100644 --- a/examples/ipfs_node/src/node.rs +++ b/examples/ipfs_node/src/node.rs @@ -26,9 +26,11 @@ use fce::WasmProcess; use fce::IValue; use fce::FCEModuleConfig; +use wasmer_wasi::generate_import_object_for_version; + +use std::collections::HashMap; use std::fs; use std::path::PathBuf; -use wasmer_wasi::generate_import_object_for_version; pub struct IpfsNode { process: FCE, @@ -137,13 +139,6 @@ impl IpfsNode { } } - if let Some(imports) = module_config.imports { - for (import_name, host_cmd) in imports { - let host_import = create_host_import_func(host_cmd); - namespace.insert(import_name, host_import); - } - } - let mut import_object = if let Some(wasi) = module_config.wasi { if let Some(envs) = wasi.envs { wasm_module_config.wasi_envs = envs; @@ -174,6 +169,19 @@ impl IpfsNode { ImportObject::new() }; + let _mapped_dirs = wasm_module_config + .wasi_mapped_dirs + .iter() + .map(|(from, to)| (from.clone(), to.as_path().to_str().unwrap().to_string())) + .collect::>(); + + if let Some(imports) = module_config.imports { + for (import_name, host_cmd) in imports { + let host_import = create_host_import_func(host_cmd); + namespace.insert(import_name, host_import); + } + } + import_object.register("host", namespace); wasm_module_config.imports = import_object; diff --git a/examples/ipfs_node/src/node_public_interface.rs b/examples/ipfs_node/src/node_public_interface.rs index 010422d1..418cf232 100644 --- a/examples/ipfs_node/src/node_public_interface.rs +++ b/examples/ipfs_node/src/node_public_interface.rs @@ -39,12 +39,12 @@ impl<'a> fmt::Display for NodePublicInterface<'a> { impl<'a> fmt::Display for NodeModulePublicInterface<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}\n", self.name)?; + writeln!(f, "{}", self.name)?; for function in self.functions.iter() { - write!( + writeln!( f, - " pub fn {}({:?}) -> {:?}\n", + " pub fn {}({:?}) -> {:?}", function.name, function.inputs, function.outputs )?; } diff --git a/examples/ipfs_node/wasm/ipfs_node/src/main.rs b/examples/ipfs_node/wasm/ipfs_node/src/main.rs index 554a998c..d21b0d07 100644 --- a/examples/ipfs_node/wasm/ipfs_node/src/main.rs +++ b/examples/ipfs_node/wasm/ipfs_node/src/main.rs @@ -21,7 +21,7 @@ mod result; use crate::result::{RESULT_PTR, RESULT_SIZE}; -const RESULT_PATH: &str = "/tmp/ipfs_rpc_file"; +const RESULT_PATH: &str = "/Users/mike/dev/work/fluence/wasm/tmp/ipfs_rpc_file"; pub fn main() { println!("ipfs_node.main: WASI initialization finished"); @@ -31,12 +31,13 @@ pub fn main() { pub unsafe fn put(file_path_ptr: *mut u8, file_path_size: usize) { let file_path = String::from_raw_parts(file_path_ptr, file_path_size, file_path_size); - println!("ipfs_node.put: file path is {}\n", file_path); + let msg = format!("ipfs_node.put: file path is {}\n", file_path); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); let cmd = format!("add -Q {}", file_path); let result = ipfs(cmd.as_ptr() as _, cmd.len() as _); - let hash = if result == 1 { + let hash = if result == 0 { String::from_raw_parts( *RESULT_PTR.get_mut() as _, *RESULT_SIZE.get_mut(), @@ -46,7 +47,8 @@ pub unsafe fn put(file_path_ptr: *mut u8, file_path_size: usize) { "host ipfs call failed".to_string() }; - println!("ipfs_node.put: file add wtih hash is {} \n", hash); + let msg = format!("ipfs_node.put: file add wtih hash is {} \n", hash); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); *RESULT_PTR.get_mut() = hash.as_ptr() as _; *RESULT_SIZE.get_mut() = hash.len(); @@ -57,7 +59,8 @@ pub unsafe fn put(file_path_ptr: *mut u8, file_path_size: usize) { pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { let hash = String::from_raw_parts(hash_ptr, hash_size, hash_size); - println!("ipfs_node.get: file hash is {}\n", hash); + let msg = format!("ipfs_node.get: file hash is {}\n", hash); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); let cmd = format!("get -o {} {}", RESULT_PATH, hash); let _result = ipfs(cmd.as_ptr() as _, cmd.len() as _); @@ -71,7 +74,8 @@ pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { // TODO: check output let file_path = RESULT_PATH.to_string(); - println!("ipfs_node.get: file path is {}", file_path); + let msg = format!("ipfs_node.get: file path is {}", file_path); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); *RESULT_PTR.get_mut() = file_path.as_ptr() as _; *RESULT_SIZE.get_mut() = file_path.len(); diff --git a/examples/ipfs_node/wasm/ipfs_node/wit b/examples/ipfs_node/wasm/ipfs_node/wit index 7622d095..e90c6b4b 100644 --- a/examples/ipfs_node/wasm/ipfs_node/wit +++ b/examples/ipfs_node/wasm/ipfs_node/wit @@ -35,10 +35,11 @@ (@interface export "put" (func 5)) ;; 6 (@interface export "get" (func 6)) ;; 7 +;; adapter for export function put (@interface func (type 7) arg.get 0 string.size - call-core 0 ;; call allocate + call-core 0 ;; call allocate arg.get 0 string.lower_memory call-core 6 ;; call self.put @@ -50,10 +51,11 @@ call-core 1 ;; call deallocate ) +;; adapter for export function get (@interface func (type 8) arg.get 0 string.size - call-core 0 ;; call allocate + call-core 0 ;; call allocate arg.get 0 string.lower_memory call-core 7 ;; call self.get diff --git a/examples/ipfs_node/wasm/ipfs_rpc/src/main.rs b/examples/ipfs_node/wasm/ipfs_rpc/src/main.rs index 0e55c83f..c708703a 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/src/main.rs +++ b/examples/ipfs_node/wasm/ipfs_rpc/src/main.rs @@ -22,7 +22,7 @@ use crate::result::{RESULT_PTR, RESULT_SIZE}; use std::fs; use std::path::PathBuf; -const RPC_TMP_FILEPATH: &str = "/tmp/ipfs_rpc_file"; +const RPC_TMP_FILEPATH: &str = "/Users/mike/dev/work/fluence/wasm/tmp/ipfs_rpc_file"; pub fn main() { println!("ipfs_rpc.main: WASI initialization finished"); @@ -30,9 +30,11 @@ pub fn main() { #[no_mangle] pub unsafe fn invoke(_ptr: *mut u8, _size: usize) { - println!("ipfs_rpc.invoke: invoke called"); + let msg = "ipfs_rpc.invoke: invoke called\n"; + log_utf8_string(msg.as_ptr() as _, msg.len() as _); + + let result = "IFPFS_RPC wasm example, it allows to:\ninvoke\nput\nget".to_string(); - let result = "IPFS_RPC wasm example, it allow:\nput\nget".to_string(); *RESULT_PTR.get_mut() = result.as_ptr() as _; *RESULT_SIZE.get_mut() = result.len(); std::mem::forget(result); @@ -43,13 +45,15 @@ pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) { let file_content = String::from_raw_parts(file_content_ptr, file_content_size, file_content_size); - println!("ipfs_rpc.put: file_content is {}\n", file_content); + let msg = format!("ipfs_rpc.put: file_content is {}\n", file_content); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); let rpc_tmp_filepath = RPC_TMP_FILEPATH.to_string(); let r = fs::write(PathBuf::from(rpc_tmp_filepath.clone()), file_content); if let Err(e) = r { - println!("{}", e); + let msg: String = e.to_string(); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); } ipfs_put(rpc_tmp_filepath.as_ptr() as _, rpc_tmp_filepath.len() as _); @@ -61,7 +65,8 @@ pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) { *RESULT_SIZE.get_mut(), ); - println!("ipfs_rpc.put: file add with hash {}\n", hash); + let msg = format!("ipfs_rpc.put: file add with hash {}\n", hash); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); *RESULT_PTR.get_mut() = hash.as_ptr() as _; *RESULT_SIZE.get_mut() = hash.len(); @@ -72,7 +77,8 @@ pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) { pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { let hash = String::from_raw_parts(hash_ptr, hash_size, hash_size); - println!("ipfs_rpc.get: getting file with hash {}\n", hash); + let msg = format!("ipfs_rpc.get: getting file with hash {}\n", hash); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); ipfs_get(hash.as_ptr() as _, hash.len() as _); @@ -82,7 +88,8 @@ pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { *RESULT_SIZE.get_mut(), ); - println!("ipfs_rpc.get: reading file from {}\n", file_path); + let msg = format!("ipfs_rpc.get: reading file from {}\n", file_path); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); let file_content = fs::read(file_path).unwrap_or_else(|_| b"error while reading file".to_vec()); diff --git a/examples/ipfs_node/wasm/ipfs_rpc/wit b/examples/ipfs_node/wasm/ipfs_rpc/wit index 8026c16f..eefe2d53 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/wit +++ b/examples/ipfs_node/wasm/ipfs_rpc/wit @@ -50,8 +50,8 @@ (@interface import "ipfs_node.wasm" "get" (func (type 5))) (@interface import "ipfs_node.wasm" "put" (func (type 6))) -(@interface import "ipfs_node.wasm" "get" (func (type 7))) ;; 7 -(@interface import "ipfs_node.wasm" "put" (func (type 8))) ;; 8 +(@interface import "ipfs_node.wasm" "get" (func (type 7))) ;; 9 +(@interface import "ipfs_node.wasm" "put" (func (type 8))) ;; 10 ;; adapter for export invoke function (@interface func (type 2) @@ -106,7 +106,7 @@ arg.get 0 arg.get 1 string.lift_memory - call-core 7 ;; call ipfs_node.get that returns string + call-core 9 ;; call ipfs_node.get that returns string dup string.size call-core 0 ;; call allocate @@ -121,7 +121,7 @@ arg.get 0 arg.get 1 string.lift_memory - call-core 8 ;; call ipfs_node.put that returns string + call-core 10 ;; call ipfs_node.put that returns string dup string.size call-core 0 ;; call allocate diff --git a/fce/src/vm/module/fce_module.rs b/fce/src/vm/module/fce_module.rs index 7261e12a..ba6ddc46 100644 --- a/fce/src/vm/module/fce_module.rs +++ b/fce/src/vm/module/fce_module.rs @@ -225,20 +225,31 @@ impl FCEModule { fn create_raw_import( wit_instance: Arc>, interpreter: WITInterpreter, + import_namespace: String, + import_name: String, ) -> impl Fn(&mut Ctx, &[WValue]) -> Vec + 'static { move |_: &mut Ctx, inputs: &[WValue]| -> Vec { use super::type_converters::wval_to_ival; + println!( + "raw import for {}.{} called with {:?}\n", + import_namespace, import_name, inputs + ); + // copy here because otherwise wit_instance will be consumed by the closure let wit_instance_callable = wit_instance.clone(); - let converted_inputs = inputs.iter().map(wval_to_ival).collect::>(); + let wit_inputs = inputs.iter().map(wval_to_ival).collect::>(); unsafe { // error here will be propagated by the special error instruction let _ = interpreter.run( - &converted_inputs, + &wit_inputs, Arc::make_mut(&mut wit_instance_callable.assume_init()), ); } + println!( + "\nraw import for {}.{} finished", + import_namespace, import_name + ); // wit import functions should only change the stack state - // the result will be returned by an export function @@ -269,7 +280,12 @@ impl FCEModule { WITAstType::Function { inputs, .. } => { let interpreter: WITInterpreter = adapter_instructions.try_into()?; - let raw_import = create_raw_import(wit_instance.clone(), interpreter); + let raw_import = create_raw_import( + wit_instance.clone(), + interpreter, + import_namespace.to_string(), + import_name.to_string(), + ); let wit_import = dyn_func_from_raw_import(inputs.clone(), raw_import); Ok((import_namespace.to_string(), (*import_name, wit_import))) diff --git a/fce/src/vm/module/wit_function.rs b/fce/src/vm/module/wit_function.rs index 4c229f9b..36983339 100644 --- a/fce/src/vm/module/wit_function.rs +++ b/fce/src/vm/module/wit_function.rs @@ -43,24 +43,6 @@ pub(super) struct WITFunction { inner: WITFunctionInner, } -/* -impl Drop for WITFunction { - fn drop(&mut self) { - match &self.inner { - WITFunctionInner::Export { func, .. } => { - println!("WITFunction export dropped: {:?}", func.signature()); - } - WITFunctionInner::Import { callable } => { - println!( - "WITFunction import dropped: {:?}", - callable.wit_module_func.inputs - ); - } - } - } -} - */ - impl WITFunction { /// Creates functions from a "usual" (not WIT) module export. pub(super) fn from_export(dyn_func: DynFunc<'static>) -> Result { @@ -131,6 +113,7 @@ impl wasm::structures::LocalImport for WITFunction { fn call(&self, arguments: &[IValue]) -> Result, ()> { use super::type_converters::{ival_to_wval, wval_to_ival}; + // println!("wit_function called with {:?}", arguments); match &self.inner { WITFunctionInner::Export { func, .. } => func