From fe716cd078fa68decb9439b557a2e9c4522f1003 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 7 Jun 2020 12:33:26 +0300 Subject: [PATCH] allow several host imports --- .../src/fce_wit_interfaces.rs | 34 +++++---- examples/ipfs_node/Cargo.toml | 2 +- examples/ipfs_node/src/config.rs | 2 + examples/ipfs_node/src/imports.rs | 14 ++-- examples/ipfs_node/src/node.rs | 5 +- examples/ipfs_node/wasm/ipfs_node/src/lib.rs | 16 ++-- examples/ipfs_node/wasm/ipfs_node/wit | 25 ++++++- examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs | 9 +-- examples/ipfs_node/wasm/ipfs_rpc/wit | 31 ++++++-- fce/src/vm/fce.rs | 6 ++ fce/src/vm/module/fce_module.rs | 73 ++++++++++++++----- fce/src/vm/module/wit_function.rs | 13 ++++ fce/src/vm/module/wit_instance.rs | 30 ++++---- 13 files changed, 182 insertions(+), 78 deletions(-) diff --git a/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs index b325dab1..4f47df18 100644 --- a/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs +++ b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs @@ -35,13 +35,15 @@ pub struct FCEWITInterfaces<'a> { types: Vec, /// All the imported functions. - imports: MultiMap, ImportNamespace<'a>)>, + imports: Vec>, + core_type_to_imports: MultiMap, ImportNamespace<'a>)>, /// All the adapters. adapters: HashMap>, /// All the exported functions. - exports: MultiMap>, + exports: Vec>, + core_type_to_exports: MultiMap>, /// All the implementations. adapter_type_to_core: MultiMap, @@ -50,9 +52,9 @@ pub struct FCEWITInterfaces<'a> { impl<'a> FCEWITInterfaces<'a> { pub fn new(interfaces: Interfaces<'a>) -> Self { - let imports = interfaces + let core_type_to_imports = interfaces .imports - .into_iter() + .iter() .map(|import| (import.function_type, (import.namespace, import.name))) .collect::>(); @@ -62,9 +64,9 @@ impl<'a> FCEWITInterfaces<'a> { .map(|adapter| (adapter.function_type, adapter.instructions)) .collect::>(); - let exports = interfaces + let core_type_to_exports = interfaces .exports - .into_iter() + .iter() .map(|export| (export.function_type, export.name)) .collect::>(); @@ -92,9 +94,11 @@ impl<'a> FCEWITInterfaces<'a> { Self { types: interfaces.types, - imports, + imports: interfaces.imports, + core_type_to_imports, adapters, - exports, + exports: interfaces.exports, + core_type_to_exports, adapter_type_to_core, core_type_to_adapter, } @@ -114,9 +118,7 @@ impl<'a> FCEWITInterfaces<'a> { .ok_or_else(|| FCEWITInterfacesError::NoSuchType(idx)) } - pub fn imports( - &self, - ) -> impl Iterator, ImportNamespace<'a>))> { + pub fn imports(&self) -> impl Iterator> { self.imports.iter() } @@ -124,14 +126,14 @@ impl<'a> FCEWITInterfaces<'a> { &self, import_type: CoreFunctionType, ) -> Option<&Vec<(ImportName<'a>, ImportNamespace<'a>)>> { - self.imports.get_vec(&import_type) + self.core_type_to_imports.get_vec(&import_type) } pub fn imports_by_type_r( &self, import_type: CoreFunctionType, ) -> Result<&Vec<(ImportName<'a>, ImportNamespace<'a>)>, FCEWITInterfacesError> { - self.imports + self.core_type_to_imports .get_vec(&import_type) .ok_or_else(|| FCEWITInterfacesError::NoSuchImport(import_type)) } @@ -153,19 +155,19 @@ impl<'a> FCEWITInterfaces<'a> { .ok_or_else(|| FCEWITInterfacesError::NoSuchAdapter(adapter_type)) } - pub fn exports(&self) -> impl Iterator)> { + pub fn exports(&self) -> impl Iterator> { self.exports.iter() } pub fn exports_by_type(&self, export_type: u32) -> Option<&Vec>> { - self.exports.get_vec(&export_type) + self.core_type_to_exports.get_vec(&export_type) } pub fn exports_by_type_r( &self, export_type: CoreFunctionType, ) -> Result<&Vec>, FCEWITInterfacesError> { - self.exports + self.core_type_to_exports .get_vec(&export_type) .ok_or_else(|| FCEWITInterfacesError::NoSuchImport(export_type)) } diff --git a/examples/ipfs_node/Cargo.toml b/examples/ipfs_node/Cargo.toml index 18b7c289..28bb3488 100644 --- a/examples/ipfs_node/Cargo.toml +++ b/examples/ipfs_node/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] fce = { path = "../../fce" } -wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0" } +wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] } wasmer-runtime = "0.17.0" toml = "0.5.6" diff --git a/examples/ipfs_node/src/config.rs b/examples/ipfs_node/src/config.rs index 27bcc4be..5456eec3 100644 --- a/examples/ipfs_node/src/config.rs +++ b/examples/ipfs_node/src/config.rs @@ -163,10 +163,12 @@ pub(crate) fn parse_config_from_file( } }); + /* println!( "parsed modules config:\n{:?}\nparsed rpc config:\n{:?}", modules_config, rpc_module_config ); + */ Ok(NodeConfig { modules_config, diff --git a/examples/ipfs_node/src/imports.rs b/examples/ipfs_node/src/imports.rs index 046da9f9..ba22f626 100644 --- a/examples/ipfs_node/src/imports.rs +++ b/examples/ipfs_node/src/imports.rs @@ -23,7 +23,7 @@ pub(super) fn log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { let wasm_ptr = WasmPtr::::new(offset as _); match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) { Some(msg) => print!("{}", msg), - None => print!("ipfs node logger: incorrect UTF8 string's been supplied to logger"), + None => print!("ipfs node logger: incorrect UTF8 string's been supplied to logger\n"), } } @@ -32,12 +32,14 @@ pub(super) fn create_host_import_func(host_cmd: String) -> DynamicFunc<'static> use wasmer_core::types::Type; use wasmer_core::types::FuncSig; - let func = Box::new(move |ctx: &mut Ctx, inputs: &[Value]| -> Vec { + 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; + let array_ptr = inputs[1].to_u128() as i32; + let array_size = inputs[0].to_u128() as i32; + println!("ptr is {}, size is {}", array_ptr, array_size); let wasm_ptr = WasmPtr::::new(array_ptr as _); match wasm_ptr.get_utf8_string(ctx.memory(0), array_size as _) { @@ -45,10 +47,10 @@ pub(super) fn create_host_import_func(host_cmd: String) -> DynamicFunc<'static> None => print!("ipfs node logger: incorrect UTF8 string's been supplied to logger"), } vec![] - }); + }; DynamicFunc::new( - std::sync::Arc::new(FuncSig::new(vec![Type::I32, Type::I32], vec![])), + std::sync::Arc::new(FuncSig::new(vec![Type::I32, Type::I32], vec![Type::I32])), func, ) } diff --git a/examples/ipfs_node/src/node.rs b/examples/ipfs_node/src/node.rs index 0102cf66..bfa43524 100644 --- a/examples/ipfs_node/src/node.rs +++ b/examples/ipfs_node/src/node.rs @@ -17,7 +17,7 @@ use super::errors::NodeError; use wasmer_core::import::ImportObject; -use wasmer_runtime::{imports, func}; +use wasmer_runtime::func; use fce::FCE; use fce::WasmProcess; use fce::NodeFunction; @@ -131,6 +131,7 @@ impl IpfsNode { if let Some(imports) = module_config.imports { for (import_name, host_cmd) in imports { + println!("{} - {}", import_name, host_cmd); let host_import = create_host_import_func(host_cmd); namespace.insert(import_name, host_import); } @@ -147,7 +148,7 @@ impl IpfsNode { if let Some(preopened_files) = wasi.preopened_files { wasm_module_config.wasi_preopened_files = preopened_files .iter() - .map(|file| PathBuf::from(file)) + .map(PathBuf::from) .collect::>(); } diff --git a/examples/ipfs_node/wasm/ipfs_node/src/lib.rs b/examples/ipfs_node/wasm/ipfs_node/src/lib.rs index 0211b025..3ea6b43d 100644 --- a/examples/ipfs_node/wasm/ipfs_node/src/lib.rs +++ b/examples/ipfs_node/wasm/ipfs_node/src/lib.rs @@ -26,13 +26,19 @@ 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); - let msg = format!("from Wasm node: file content is {}\n", file_content); + let msg = format!( + "from Wasm ipfs_node.get: file content is {}\n", + file_content + ); log_utf8_string(msg.as_ptr() as _, msg.len() as _); let cmd = format!("put {}", file_content); ipfs(cmd.as_ptr() as _, cmd.len() as _); - let result = "Hello from IPFS node, take your hash".to_string(); + let after_ipfs = format!("after ipfs call"); + log_utf8_string(after_ipfs.as_ptr() as _, after_ipfs.len() as _); + + let result = "IPFS node: hash is asdasdsad".to_string(); *RESULT_PTR.get_mut() = result.as_ptr() as _; *RESULT_SIZE.get_mut() = result.len(); @@ -43,13 +49,13 @@ 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); - let msg = format!("from Wasm node: file content is {}\n", hash); + let msg = format!("from Wasm ipfs_node.get: file hash is {}\n", hash); log_utf8_string(msg.as_ptr() as _, msg.len() as _); let cmd = format!("get {}", hash); ipfs(cmd.as_ptr() as _, cmd.len() as _); - let result = "Hello from IPFS node, take your file".to_string(); + let result = "IPFS node: file is hhhhaaa".to_string(); *RESULT_PTR.get_mut() = result.as_ptr() as _; *RESULT_SIZE.get_mut() = result.len(); @@ -62,5 +68,5 @@ extern "C" { fn log_utf8_string(ptr: i32, size: i32); /// Put a file to ipfs, returns ipfs hash of the file. - fn ipfs(ptr: i32, size: i32); + fn ipfs(ptr: i32, size: i32) -> i32; } diff --git a/examples/ipfs_node/wasm/ipfs_node/wit b/examples/ipfs_node/wasm/ipfs_node/wit index 81e4f950..7622d095 100644 --- a/examples/ipfs_node/wasm/ipfs_node/wit +++ b/examples/ipfs_node/wasm/ipfs_node/wit @@ -22,6 +22,9 @@ ;; import ipfs put/get function (@interface type (func (param string) (result string))) ;; 7 +;; import ipfs put/get function +(@interface type (func (param string) (result string))) ;; 8 + (@interface export "allocate" (func 0)) ;; 0 (@interface export "deallocate" (func 1)) ;; 1 (@interface export "get_result_size" (func 3)) ;; 2 @@ -30,9 +33,24 @@ (@interface export "set_result_ptr" (func 4)) ;; 5 (@interface export "put" (func 5)) ;; 6 -(@interface export "get" (func 5)) ;; 7 +(@interface export "get" (func 6)) ;; 7 -(@interface func (type 6) +(@interface func (type 7) + arg.get 0 + string.size + call-core 0 ;; call allocate + arg.get 0 + string.lower_memory + call-core 6 ;; call self.put + call-core 3 ;; call get_result_ptr + call-core 2 ;; call get_result_size + string.lift_memory + call-core 3 ;; call get_result_ptr + call-core 2 ;; call get_result_size + call-core 1 ;; call deallocate +) + +(@interface func (type 8) arg.get 0 string.size call-core 0 ;; call allocate @@ -48,4 +66,5 @@ ) ;; Implementations -(@interface implement (func 5) (func 6)) +(@interface implement (func 5) (func 7)) +(@interface implement (func 6) (func 8)) diff --git a/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs b/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs index 37211b18..f1e19a6b 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs +++ b/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs @@ -18,7 +18,7 @@ mod mem; mod result; -// use crate::result::{RESULT_PTR, RESULT_SIZE}; +use crate::result::{RESULT_PTR, RESULT_SIZE}; #[no_mangle] pub unsafe fn invoke(file_content_ptr: *mut u8, file_content_size: usize) { @@ -26,19 +26,18 @@ pub unsafe fn invoke(file_content_ptr: *mut u8, file_content_size: usize) { String::from_raw_parts(file_content_ptr, file_content_size, file_content_size); let msg = format!("from Wasm rpc: file_content is {}\n", file_content); log_utf8_string(msg.as_ptr() as _, msg.len() as _); + log_utf8_string(msg.as_ptr() as _, msg.len() as _); - put(file_content_ptr as _, file_content_size as _); + put(file_content.as_ptr() as _, file_content.len() as _); - /* let hash = String::from_raw_parts( - *RESULT_PTR.get_mut(), + *RESULT_PTR.get_mut() as _, *RESULT_SIZE.get_mut(), *RESULT_SIZE.get_mut(), ); let msg = format!("from Wasm rpc: hash is {}\n", hash); log_utf8_string(msg.as_ptr() as _, msg.len() as _); - */ } #[link(wasm_import_module = "host")] diff --git a/examples/ipfs_node/wasm/ipfs_rpc/wit b/examples/ipfs_node/wasm/ipfs_rpc/wit index f3dc07c8..5c4f1b20 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/wit +++ b/examples/ipfs_node/wasm/ipfs_rpc/wit @@ -17,13 +17,19 @@ (@interface type (func (param i32 i32))) ;; 5 ;; import ipfs put/get function -(@interface type (func (param string) (result string))) ;; 6 +(@interface type (func (param i32 i32))) ;; 6 ;; import ipfs put/get function (@interface type (func (param string) (result string))) ;; 7 ;; import ipfs put/get function -(@interface type (func (param i64 i32) (result i64 i32))) ;; 8 +(@interface type (func (param string) (result string))) ;; 8 + +;; import ipfs put/get function +(@interface type (func (param i32 i32))) ;; 9 + +;; import ipfs put/get function +(@interface type (func (param i32 i32))) ;; 10 (@interface export "allocate" (func 0)) ;; 0 (@interface export "deallocate" (func 1)) ;; 1 @@ -34,7 +40,7 @@ (@interface export "set_result_ptr" (func 4)) ;; 6 (@interface import "ipfs_node.wasm" "get" (func (type 5))) -(@interface import "ipfs_node.wasm" "put" (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 @@ -54,7 +60,7 @@ call-core 1 ;; call deallocate ) -(@interface func (type 5) +(@interface func (type 9) arg.get 0 arg.get 1 string.lift_memory @@ -68,6 +74,21 @@ call-core 5 ;; call set_result_ptr ) +(@interface func (type 10) + arg.get 0 + arg.get 1 + string.lift_memory + call-core 8 ;; call ipfs_node.put that returns string + dup + string.size + call-core 0 ;; call allocate + swap2 + string.lower_memory + call-core 6 ;; call set_result_size + call-core 5 ;; call set_result_ptr +) + ;; Implementations (@interface implement (func 2) (func 2)) -(@interface implement (func 5) (func 5)) +(@interface implement (func 5) (func 9)) +(@interface implement (func 6) (func 10)) diff --git a/fce/src/vm/fce.rs b/fce/src/vm/fce.rs index 059acd36..d8ddf279 100644 --- a/fce/src/vm/fce.rs +++ b/fce/src/vm/fce.rs @@ -28,6 +28,12 @@ pub struct FCE { modules: HashMap>, } +impl Drop for FCE { + fn drop(&mut self) { + // println!("FCE dropped"); + } +} + impl FCE { pub fn new() -> Self { Self { diff --git a/fce/src/vm/module/fce_module.rs b/fce/src/vm/module/fce_module.rs index cd990e53..de95135f 100644 --- a/fce/src/vm/module/fce_module.rs +++ b/fce/src/vm/module/fce_module.rs @@ -47,6 +47,12 @@ pub struct FCEModule { exports_funcs: HashMap, } +impl Drop for FCEModule { + fn drop(&mut self) { + // println!("FCEModule dropped: {:?}", self.exports_funcs.keys()); + } +} + impl FCEModule { pub fn new( wasm_bytes: &[u8], @@ -183,16 +189,48 @@ impl FCEModule { use wasmer_core::typed_func::DynamicFunc; use wasmer_core::vm::Ctx; + #[derive(Clone)] + struct T {} + + impl Drop for T { + fn drop(&mut self) { + // println!("drop T"); + } + } + // returns function that will be called from imports of Wasmer module fn dyn_func_from_raw_import( inputs: Vec, - func: Box Vec + 'static>, + wit_instance: Arc>, + interpreter: WITInterpreter, ) -> DynamicFunc<'static> { use wasmer_core::types::FuncSig; use super::type_converters::itype_to_wtype; + let t = T {}; let signature = inputs.iter().map(itype_to_wtype).collect::>(); - DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func) + DynamicFunc::new( + Arc::new(FuncSig::new(signature, vec![])), + move |_: &mut Ctx, inputs: &[WValue]| -> Vec { + use super::type_converters::wval_to_ival; + let t_copied = t.clone(); + + // 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::>(); + unsafe { + // error here will be propagated by the special error instruction + let _ = interpreter.run( + &converted_inputs, + Arc::make_mut(&mut wit_instance_callable.assume_init()), + ); + } + + // wit import functions should only change the stack state - + // the result will be returned by an export function + vec![] + }, + ) } // creates a closure that is represent a WIT module import @@ -220,7 +258,7 @@ impl FCEModule { }) } - let namespaces = wit + let wit_import_funcs = wit .implementations() .filter_map(|(adapter_function_type, core_function_type)| { match wit.imports_by_type(*core_function_type) { @@ -242,13 +280,14 @@ impl FCEModule { match wit_type { WITAstType::Function { inputs, .. } => { let interpreter: WITInterpreter = adapter_instructions.try_into()?; - let inner_import = create_raw_import(wit_instance.clone(), interpreter); - let wit_import = dyn_func_from_raw_import(inputs.clone(), inner_import); - let mut namespace = Namespace::new(); - namespace.insert(*import_name, wit_import); + let wit_import = dyn_func_from_raw_import( + inputs.clone(), + wit_instance.clone(), + interpreter, + ); - Ok((import_namespace.to_string(), namespace)) + Ok((import_namespace.to_string(), (*import_name, wit_import))) } _ => Err(FCEError::IncorrectWIT(format!( "type with idx = {} isn't a function type", @@ -256,23 +295,17 @@ impl FCEModule { ))), } }) - .collect::, FCEError>>()?; + .collect::, FCEError>>()?; let mut import_object = ImportObject::new(); // TODO: refactor it - for (namespace_name, namespaces) in namespaces.iter_all() { - let mut result_namespace = Namespace::new(); - for namespace in namespaces { - use wasmer_core::import::LikeNamespace; - - result_namespace.insert( - namespace.get_exports()[0].0.clone(), - namespace.get_exports()[0].1.clone(), - ); + for (namespace_name, funcs) in wit_import_funcs.into_iter() { + let mut namespace = Namespace::new(); + for (import_name, import_func) in funcs.into_iter() { + namespace.insert(import_name.to_string(), import_func); } - - import_object.register(namespace_name, result_namespace); + import_object.register(namespace_name, namespace); } Ok(import_object) diff --git a/fce/src/vm/module/wit_function.rs b/fce/src/vm/module/wit_function.rs index 7a9547af..ffaf0496 100644 --- a/fce/src/vm/module/wit_function.rs +++ b/fce/src/vm/module/wit_function.rs @@ -45,6 +45,19 @@ 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 { func_name, .. } => { + // println!("WITFunction import dropped: {:?}", func_name); + } + } + } +} + impl WITFunction { /// Creates functions from a "usual" (not WIT) module export. pub(super) fn from_export(dyn_func: DynFunc<'static>) -> Result { diff --git a/fce/src/vm/module/wit_instance.rs b/fce/src/vm/module/wit_instance.rs index 5e9a1a5e..a7e640d2 100644 --- a/fce/src/vm/module/wit_instance.rs +++ b/fce/src/vm/module/wit_instance.rs @@ -33,6 +33,12 @@ pub(super) struct WITInstance { memories: Vec, } +impl Drop for WITInstance { + fn drop(&mut self) { + // println!("WITInstance dropped"); + } +} + impl WITInstance { pub(super) fn new( wasmer_instance: &WasmerInstance, @@ -59,8 +65,8 @@ impl WITInstance { wit.exports() .enumerate() - .map(|(export_id, (_, export_name))| { - let export_func = module_exports.get(*export_name)?; + .map(|(export_id, export)| { + let export_func = module_exports.get(export.name)?; unsafe { // TODO: refactor this with new Wasmer API when it is ready // here it is safe because dyn func is never lives WITInstance @@ -79,23 +85,17 @@ impl WITInstance { start_index: usize, ) -> Result, FCEError> { wit.imports() - .filter(|(core_function_type, _)| { + .filter(|import| { // filter out imports that have implementations - matches!(wit.adapter_by_type(**core_function_type), None) + matches!(wit.adapter_by_type(import.function_type), None) }) .enumerate() - .map(|(idx, (_, (import_namespace, import_name)))| { - match modules.get(*import_namespace) { - Some(module) => { - let func = - WITFunction::from_import(module.clone(), import_name.to_string())?; - Ok((start_index + idx as usize, func)) - } - None => { - println!("no such module: {}", import_namespace); - Err(FCEError::NoSuchModule) - } + .map(|(idx, import)| match modules.get(import.namespace) { + Some(module) => { + let func = WITFunction::from_import(module.clone(), import.name.to_string())?; + Ok((start_index + idx as usize, func)) } + None => Err(FCEError::NoSuchModule), }) .collect::, _>>() }