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