diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs new file mode 100644 index 000000000..bf31d852c --- /dev/null +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -0,0 +1,169 @@ +use super::super::{ + wasm_functype_t, wasm_store_t, wasm_trap_t, wasm_val_inner, wasm_val_t, wasm_valkind_enum, +}; +use std::convert::TryInto; +use std::ffi::c_void; +use std::ptr::NonNull; +use std::sync::Arc; +use wasmer::{Function, Instance, RuntimeError, Store, Val}; + +#[repr(C)] +pub struct wasm_func_t { + pub(crate) inner: Function, + // this is how we ensure the instance stays alive + pub(crate) instance: Option>, +} + +#[allow(non_camel_case_types)] +pub type wasm_func_callback_t = + unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t; + +#[allow(non_camel_case_types)] +pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( + *mut c_void, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> *mut wasm_trap_t; + +#[allow(non_camel_case_types)] +pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void); + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_new( + store: Option>, + ft: &wasm_functype_t, + callback: wasm_func_callback_t, +) -> Option> { + // TODO: handle null pointers? + let store_ptr = store?.cast::(); + let store = store_ptr.as_ref(); + let func_sig = ft.sig(); + let num_rets = func_sig.results().len(); + let inner_callback = move |args: &[Val]| -> Result, RuntimeError> { + let processed_args = args + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + .expect("Argument conversion failed"); + + let mut results = vec![ + wasm_val_t { + kind: wasm_valkind_enum::WASM_I64 as _, + of: wasm_val_inner { int64_t: 0 }, + }; + num_rets + ]; + + let _traps = callback(processed_args.as_ptr(), results.as_mut_ptr()); + // TODO: do something with `traps` + + let processed_results = results + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + .expect("Result conversion failed"); + Ok(processed_results) + }; + let f = Function::new(store, &func_sig, inner_callback); + Some(Box::new(wasm_func_t { + instance: None, + inner: f, + })) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_new_with_env( + store: Option>, + ft: &wasm_functype_t, + callback: wasm_func_callback_with_env_t, + env: *mut c_void, + finalizer: wasm_env_finalizer_t, +) -> Option> { + // TODO: handle null pointers? + let store_ptr = store?.cast::(); + let store = store_ptr.as_ref(); + let func_sig = ft.sig(); + let num_rets = func_sig.results().len(); + let inner_callback = + move |env: &mut *mut c_void, args: &[Val]| -> Result, RuntimeError> { + let processed_args = args + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + .expect("Argument conversion failed"); + + let mut results = vec![ + wasm_val_t { + kind: wasm_valkind_enum::WASM_I64 as _, + of: wasm_val_inner { int64_t: 0 }, + }; + num_rets + ]; + + let _traps = callback(*env, processed_args.as_ptr(), results.as_mut_ptr()); + // TODO: do something with `traps` + + let processed_results = results + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + .expect("Result conversion failed"); + Ok(processed_results) + }; + let f = Function::new_with_env(store, &func_sig, env, inner_callback); + Some(Box::new(wasm_func_t { + instance: None, + inner: f, + })) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_delete(_func: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_call( + func: &wasm_func_t, + args: *const wasm_val_t, + results: *mut wasm_val_t, +) -> Option> { + let num_params = func.inner.ty().params().len(); + let params: Vec = (0..num_params) + .map(|i| (&(*args.add(i))).try_into()) + .collect::>() + .ok()?; + + match func.inner.call(¶ms) { + Ok(wasm_results) => { + for (i, actual_result) in wasm_results.iter().enumerate() { + let result_loc = &mut (*results.add(i)); + *result_loc = (&*actual_result).try_into().ok()?; + } + None + } + Err(e) => Some(NonNull::new_unchecked(Box::into_raw(Box::new(e)) as _)), + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize { + func.inner.ty().params().len() +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize { + func.inner.ty().results().len() +} + +macro_rules! wasm_declare_own { + ($name:ident) => { + paste::item! { + #[repr(C)] + pub struct [] {} + + #[no_mangle] + pub extern "C" fn [](_arg: *mut []) { + todo!("in generated delete") + } + } + }; +} diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index f81e700af..6f39bfe81 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -1,3 +1,4 @@ +pub mod function; pub mod global; pub mod memory; pub mod table; diff --git a/lib/c-api/src/wasm_c_api/mod.rs b/lib/c-api/src/wasm_c_api/mod.rs index 8bb3a450a..1ac143845 100644 --- a/lib/c-api/src/wasm_c_api/mod.rs +++ b/lib/c-api/src/wasm_c_api/mod.rs @@ -11,6 +11,7 @@ pub mod wasi; // https://github.com/rust-lang/rust/issues/57966 use crate::c_try; use crate::ordered_resolver::OrderedResolver; +use externals::function::wasm_func_t; use externals::global::wasm_global_t; use externals::memory::wasm_memory_t; use externals::table::wasm_table_t; @@ -23,8 +24,8 @@ use std::sync::Arc; use store::wasm_store_t; use thiserror::Error; use wasmer::{ - ExportType, Extern, ExternType, Function, FunctionType, GlobalType, ImportType, Instance, - MemoryType, Module, Mutability, Pages, RuntimeError, Store, TableType, Val, ValType, + ExportType, Extern, ExternType, FunctionType, GlobalType, ImportType, Instance, MemoryType, + Module, Mutability, Pages, RuntimeError, Store, TableType, Val, ValType, }; #[cfg(feature = "jit")] use wasmer_engine_jit::JIT; @@ -579,167 +580,9 @@ impl TryFrom<&Val> for wasm_val_t { } } -#[allow(non_camel_case_types)] -pub type wasm_func_callback_t = - unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t; - -#[allow(non_camel_case_types)] -pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( - *mut c_void, - args: *const wasm_val_t, - results: *mut wasm_val_t, -) -> *mut wasm_trap_t; - #[allow(non_camel_case_types)] pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void); -#[repr(C)] -pub struct wasm_func_t { - inner: Function, - // this is how we ensure the instance stays alive - instance: Option>, -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_new( - store: Option>, - ft: &wasm_functype_t, - callback: wasm_func_callback_t, -) -> Option> { - // TODO: handle null pointers? - let store_ptr = store?.cast::(); - let store = store_ptr.as_ref(); - let func_sig = ft.sig(); - let num_rets = func_sig.results().len(); - let inner_callback = move |args: &[Val]| -> Result, RuntimeError> { - let processed_args = args - .into_iter() - .map(TryInto::try_into) - .collect::, _>>() - .expect("Argument conversion failed"); - - let mut results = vec![ - wasm_val_t { - kind: wasm_valkind_enum::WASM_I64 as _, - of: wasm_val_inner { int64_t: 0 }, - }; - num_rets - ]; - - let _traps = callback(processed_args.as_ptr(), results.as_mut_ptr()); - // TODO: do something with `traps` - - let processed_results = results - .into_iter() - .map(TryInto::try_into) - .collect::, _>>() - .expect("Result conversion failed"); - Ok(processed_results) - }; - let f = Function::new(store, &func_sig, inner_callback); - Some(Box::new(wasm_func_t { - instance: None, - inner: f, - })) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_new_with_env( - store: Option>, - ft: &wasm_functype_t, - callback: wasm_func_callback_with_env_t, - env: *mut c_void, - finalizer: wasm_env_finalizer_t, -) -> Option> { - // TODO: handle null pointers? - let store_ptr = store?.cast::(); - let store = store_ptr.as_ref(); - let func_sig = ft.sig(); - let num_rets = func_sig.results().len(); - let inner_callback = - move |env: &mut *mut c_void, args: &[Val]| -> Result, RuntimeError> { - let processed_args = args - .into_iter() - .map(TryInto::try_into) - .collect::, _>>() - .expect("Argument conversion failed"); - - let mut results = vec![ - wasm_val_t { - kind: wasm_valkind_enum::WASM_I64 as _, - of: wasm_val_inner { int64_t: 0 }, - }; - num_rets - ]; - - let _traps = callback(*env, processed_args.as_ptr(), results.as_mut_ptr()); - // TODO: do something with `traps` - - let processed_results = results - .into_iter() - .map(TryInto::try_into) - .collect::, _>>() - .expect("Result conversion failed"); - Ok(processed_results) - }; - let f = Function::new_with_env(store, &func_sig, env, inner_callback); - Some(Box::new(wasm_func_t { - instance: None, - inner: f, - })) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_delete(_func: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_call( - func: &wasm_func_t, - args: *const wasm_val_t, - results: *mut wasm_val_t, -) -> Option> { - let num_params = func.inner.ty().params().len(); - let params: Vec = (0..num_params) - .map(|i| (&(*args.add(i))).try_into()) - .collect::>() - .ok()?; - - match func.inner.call(¶ms) { - Ok(wasm_results) => { - for (i, actual_result) in wasm_results.iter().enumerate() { - let result_loc = &mut (*results.add(i)); - *result_loc = (&*actual_result).try_into().ok()?; - } - None - } - Err(e) => Some(NonNull::new_unchecked(Box::into_raw(Box::new(e)) as _)), - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize { - func.inner.ty().params().len() -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize { - func.inner.ty().results().len() -} - -macro_rules! wasm_declare_own { - ($name:ident) => { - paste::item! { - #[repr(C)] - pub struct [] {} - - #[no_mangle] - pub extern "C" fn [](_arg: *mut []) { - todo!("in generated delete") - } - } - }; -} - macro_rules! wasm_declare_vec_inner { ($name:ident) => { paste::item! {