wasmer_c_api/wasm_c_api/externals/
function.rs

1use super::super::store::wasm_store_t;
2use super::super::trap::wasm_trap_t;
3use super::super::types::{wasm_functype_t, wasm_valkind_enum};
4use super::super::value::{wasm_val_inner, wasm_val_t, wasm_val_vec_t};
5use super::wasm_extern_t;
6use crate::wasm_c_api::function_env::FunctionCEnv;
7use libc::c_void;
8use std::convert::TryInto;
9use std::mem::MaybeUninit;
10use std::sync::{Arc, Mutex};
11use wasmer_api::{Extern, Function, FunctionEnv, FunctionEnvMut, RuntimeError, Value};
12
13#[derive(Clone)]
14#[allow(non_camel_case_types)]
15#[repr(C)]
16pub struct wasm_func_t {
17    pub(crate) extern_: wasm_extern_t,
18}
19
20impl wasm_func_t {
21    pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_func_t> {
22        match &e.inner {
23            Extern::Function(_) => Some(unsafe { &*(e as *const _ as *const _) }),
24            _ => None,
25        }
26    }
27}
28
29#[allow(non_camel_case_types)]
30pub type wasm_func_callback_t = unsafe extern "C" fn(
31    args: &wasm_val_vec_t,
32    results: &mut wasm_val_vec_t,
33) -> Option<Box<wasm_trap_t>>;
34
35#[allow(non_camel_case_types)]
36pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
37    env: *mut c_void,
38    args: &wasm_val_vec_t,
39    results: &mut wasm_val_vec_t,
40) -> Option<Box<wasm_trap_t>>;
41
42#[allow(non_camel_case_types)]
43pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void);
44
45#[unsafe(no_mangle)]
46pub unsafe extern "C" fn wasm_func_new(
47    store: Option<&mut wasm_store_t>,
48    function_type: Option<&wasm_functype_t>,
49    callback: Option<wasm_func_callback_t>,
50) -> Option<Box<wasm_func_t>> {
51    let function_type = function_type?;
52    let callback = callback?;
53    let store = store?;
54    let mut store_mut = unsafe { store.inner.store_mut() };
55
56    let func_sig = &function_type.inner().function_type;
57    let num_rets = func_sig.results().len();
58    let inner_callback = move |mut _env: FunctionEnvMut<'_, FunctionCEnv>,
59                               args: &[Value]|
60          -> Result<Vec<Value>, RuntimeError> {
61        let processed_args: wasm_val_vec_t = args
62            .iter()
63            .map(TryInto::try_into)
64            .collect::<Result<Vec<wasm_val_t>, _>>()
65            .expect("Argument conversion failed")
66            .into();
67
68        let mut results: wasm_val_vec_t = vec![
69            wasm_val_t {
70                kind: wasm_valkind_enum::WASM_I64 as _,
71                of: wasm_val_inner { int64_t: 0 },
72            };
73            num_rets
74        ]
75        .into();
76
77        let trap = unsafe { callback(&processed_args, &mut results) };
78
79        if let Some(trap) = trap {
80            return Err(trap.inner);
81        }
82
83        let processed_results = results
84            .take()
85            .into_iter()
86            .map(TryInto::try_into)
87            .collect::<Result<Vec<Value>, _>>()
88            .expect("Result conversion failed");
89
90        Ok(processed_results)
91    };
92    let env = FunctionEnv::new(&mut store_mut, FunctionCEnv::default());
93    let function = Function::new_with_env(&mut store_mut, &env, func_sig, inner_callback);
94    Some(Box::new(wasm_func_t {
95        extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
96    }))
97}
98
99#[unsafe(no_mangle)]
100pub unsafe extern "C" fn wasm_func_new_with_env(
101    store: Option<&mut wasm_store_t>,
102    function_type: Option<&wasm_functype_t>,
103    callback: Option<wasm_func_callback_with_env_t>,
104    env: *mut c_void,
105    env_finalizer: Option<wasm_env_finalizer_t>,
106) -> Option<Box<wasm_func_t>> {
107    let function_type = function_type?;
108    let callback = callback?;
109    let store = store?;
110    let mut store_mut = unsafe { store.inner.store_mut() };
111
112    let func_sig = &function_type.inner().function_type;
113    let num_rets = func_sig.results().len();
114
115    #[derive(Clone)]
116    #[repr(C)]
117    struct WrapperEnv {
118        env: FunctionCEnv,
119        env_finalizer: Arc<Mutex<Option<wasm_env_finalizer_t>>>,
120    }
121
122    // Only relevant when using multiple threads in the C API;
123    // Synchronization will be done via the C API / on the C side.
124    unsafe impl Send for WrapperEnv {}
125    unsafe impl Sync for WrapperEnv {}
126
127    impl Drop for WrapperEnv {
128        fn drop(&mut self) {
129            if let Ok(mut guard) = self.env_finalizer.lock()
130                && Arc::strong_count(&self.env_finalizer) == 1
131                && let Some(env_finalizer) = guard.take()
132            {
133                unsafe { (env_finalizer)(self.env.as_ptr()) };
134            }
135        }
136    }
137    let inner_callback = move |env: FunctionEnvMut<'_, WrapperEnv>,
138                               args: &[Value]|
139          -> Result<Vec<Value>, RuntimeError> {
140        let processed_args: wasm_val_vec_t = args
141            .iter()
142            .map(TryInto::try_into)
143            .collect::<Result<Vec<wasm_val_t>, _>>()
144            .expect("Argument conversion failed")
145            .into();
146
147        let mut results: wasm_val_vec_t = vec![
148            wasm_val_t {
149                kind: wasm_valkind_enum::WASM_I64 as _,
150                of: wasm_val_inner { int64_t: 0 },
151            };
152            num_rets
153        ]
154        .into();
155
156        let trap = unsafe { callback(env.data().env.as_ptr(), &processed_args, &mut results) };
157
158        if let Some(trap) = trap {
159            return Err(trap.inner);
160        }
161
162        let processed_results = results
163            .take()
164            .into_iter()
165            .map(TryInto::try_into)
166            .collect::<Result<Vec<Value>, _>>()
167            .expect("Result conversion failed");
168
169        Ok(processed_results)
170    };
171    let env = FunctionEnv::new(
172        &mut store_mut,
173        WrapperEnv {
174            env: FunctionCEnv::new(c_try!(
175                std::ptr::NonNull::new(env),
176                "Function environment cannot be a null pointer."
177            )),
178            env_finalizer: Arc::new(Mutex::new(env_finalizer)),
179        },
180    );
181    let function = Function::new_with_env(&mut store_mut, &env, func_sig, inner_callback);
182    Some(Box::new(wasm_func_t {
183        extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
184    }))
185}
186
187#[unsafe(no_mangle)]
188pub extern "C" fn wasm_func_copy(func: &wasm_func_t) -> Box<wasm_func_t> {
189    Box::new(func.clone())
190}
191
192#[unsafe(no_mangle)]
193pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
194
195#[unsafe(no_mangle)]
196pub unsafe extern "C" fn wasm_func_call(
197    func: Option<&mut wasm_func_t>,
198    args: Option<&wasm_val_vec_t>,
199    results: &mut wasm_val_vec_t,
200) -> Option<Box<wasm_trap_t>> {
201    let func = func?;
202    let args = args?;
203    let mut store = func.extern_.store.clone();
204    let mut store_mut = unsafe { store.store_mut() };
205    let params = args
206        .as_slice()
207        .iter()
208        .cloned()
209        .map(TryInto::try_into)
210        .collect::<Result<Vec<Value>, _>>()
211        .expect("Arguments conversion failed");
212
213    match func.extern_.function().call(&mut store_mut, &params) {
214        Ok(wasm_results) => {
215            for (slot, val) in results
216                .as_uninit_slice()
217                .iter_mut()
218                .zip(wasm_results.iter())
219            {
220                *slot = MaybeUninit::new(val.try_into().expect("Results conversion failed"));
221            }
222
223            None
224        }
225        Err(e) => Some(Box::new(e.into())),
226    }
227}
228
229#[unsafe(no_mangle)]
230pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize {
231    let store_ref = unsafe { func.extern_.store.store() };
232    func.extern_.function().ty(&store_ref).params().len()
233}
234
235#[unsafe(no_mangle)]
236pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
237    let store_ref = unsafe { func.extern_.store.store() };
238    func.extern_.function().ty(&store_ref).results().len()
239}
240
241#[unsafe(no_mangle)]
242pub unsafe extern "C" fn wasm_func_type(
243    func: Option<&wasm_func_t>,
244) -> Option<Box<wasm_functype_t>> {
245    let func = func?;
246    let store_ref = unsafe { func.extern_.store.store() };
247    Some(Box::new(wasm_functype_t::new(
248        func.extern_.function().ty(&store_ref),
249    )))
250}