wasmer_c_api/wasm_c_api/externals/
function.rs1use super::super::store::{StoreRef, wasm_store_t};
2use super::super::trap::wasm_trap_t;
3use super::super::types::{wasm_functype_t, wasm_ref_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::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
45fn callback_args_to_wasm(args: &[Value], store: &StoreRef) -> Result<wasm_val_vec_t, RuntimeError> {
48 let vals = args
49 .iter()
50 .map(|v| wasm_val_t::from_value(v, store))
51 .collect::<Result<Vec<wasm_val_t>, &'static str>>()
52 .map_err(RuntimeError::new)?;
53 Ok(vals.into())
54}
55
56fn callback_results_to_values(results: Vec<wasm_val_t>) -> Result<Vec<Value>, RuntimeError> {
58 results
59 .into_iter()
60 .map(Value::try_from)
61 .collect::<Result<Vec<Value>, &'static str>>()
62 .map_err(RuntimeError::new)
63}
64
65#[unsafe(no_mangle)]
66pub unsafe extern "C" fn wasm_func_new(
67 store: Option<&mut wasm_store_t>,
68 function_type: Option<&wasm_functype_t>,
69 callback: Option<wasm_func_callback_t>,
70) -> Option<Box<wasm_func_t>> {
71 let function_type = function_type?;
72 let callback = callback?;
73 let store = store?;
74 let store_weak = store.inner.downgrade();
77 let mut store_mut = unsafe { store.inner.store_mut() };
78
79 let func_sig = &function_type.inner().function_type;
80 let num_rets = func_sig.results().len();
81 let inner_callback = move |mut _env: FunctionEnvMut<'_, FunctionCEnv>,
82 args: &[Value]|
83 -> Result<Vec<Value>, RuntimeError> {
84 let store = store_weak
85 .upgrade()
86 .ok_or_else(|| RuntimeError::new("store was dropped"))?;
87 let processed_args = callback_args_to_wasm(args, &store)?;
88
89 let mut results: wasm_val_vec_t = vec![
90 wasm_val_t {
91 kind: wasm_valkind_enum::WASM_I64 as _,
92 of: wasm_val_inner { int64_t: 0 },
93 };
94 num_rets
95 ]
96 .into();
97
98 let trap = unsafe { callback(&processed_args, &mut results) };
99
100 if let Some(trap) = trap {
101 return Err(trap.inner);
102 }
103
104 callback_results_to_values(results.take())
105 };
106 let env = FunctionEnv::new(&mut store_mut, FunctionCEnv::default());
107 let function = Function::new_with_env(&mut store_mut, &env, func_sig, inner_callback);
108 Some(Box::new(wasm_func_t {
109 extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
110 }))
111}
112
113#[unsafe(no_mangle)]
114pub unsafe extern "C" fn wasm_func_new_with_env(
115 store: Option<&mut wasm_store_t>,
116 function_type: Option<&wasm_functype_t>,
117 callback: Option<wasm_func_callback_with_env_t>,
118 env: *mut c_void,
119 env_finalizer: Option<wasm_env_finalizer_t>,
120) -> Option<Box<wasm_func_t>> {
121 let function_type = function_type?;
122 let callback = callback?;
123 let store = store?;
124 let store_weak = store.inner.downgrade();
125 let mut store_mut = unsafe { store.inner.store_mut() };
126
127 let func_sig = &function_type.inner().function_type;
128 let num_rets = func_sig.results().len();
129
130 #[derive(Clone)]
131 #[repr(C)]
132 struct WrapperEnv {
133 env: FunctionCEnv,
134 env_finalizer: Arc<Mutex<Option<wasm_env_finalizer_t>>>,
135 }
136
137 unsafe impl Send for WrapperEnv {}
140 unsafe impl Sync for WrapperEnv {}
141
142 impl Drop for WrapperEnv {
143 fn drop(&mut self) {
144 if let Ok(mut guard) = self.env_finalizer.lock()
145 && Arc::strong_count(&self.env_finalizer) == 1
146 && let Some(env_finalizer) = guard.take()
147 {
148 unsafe { (env_finalizer)(self.env.as_ptr()) };
149 }
150 }
151 }
152 let inner_callback = move |env: FunctionEnvMut<'_, WrapperEnv>,
153 args: &[Value]|
154 -> Result<Vec<Value>, RuntimeError> {
155 let store = store_weak
156 .upgrade()
157 .ok_or_else(|| RuntimeError::new("store was dropped"))?;
158 let processed_args = callback_args_to_wasm(args, &store)?;
159
160 let mut results: wasm_val_vec_t = vec![
161 wasm_val_t {
162 kind: wasm_valkind_enum::WASM_I64 as _,
163 of: wasm_val_inner { int64_t: 0 },
164 };
165 num_rets
166 ]
167 .into();
168
169 let trap = unsafe { callback(env.data().env.as_ptr(), &processed_args, &mut results) };
170
171 if let Some(trap) = trap {
172 return Err(trap.inner);
173 }
174
175 callback_results_to_values(results.take())
176 };
177 let env = FunctionEnv::new(
178 &mut store_mut,
179 WrapperEnv {
180 env: FunctionCEnv::new(c_try!(
181 std::ptr::NonNull::new(env),
182 "Function environment cannot be a null pointer."
183 )),
184 env_finalizer: Arc::new(Mutex::new(env_finalizer)),
185 },
186 );
187 let function = Function::new_with_env(&mut store_mut, &env, func_sig, inner_callback);
188 Some(Box::new(wasm_func_t {
189 extern_: wasm_extern_t::new(store.inner.clone(), function.into()),
190 }))
191}
192
193#[unsafe(no_mangle)]
194pub extern "C" fn wasm_func_copy(func: &wasm_func_t) -> Box<wasm_func_t> {
195 Box::new(func.clone())
196}
197
198#[unsafe(no_mangle)]
199pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
200
201#[unsafe(no_mangle)]
212pub unsafe extern "C" fn wasm_func_as_ref(
213 func: Option<&mut wasm_func_t>,
214) -> Option<Box<wasm_ref_t>> {
215 let func = func?;
216 wasm_ref_t::new(
217 func.extern_.store.clone(),
218 Value::FuncRef(Some(func.extern_.function())),
219 )
220}
221
222#[unsafe(no_mangle)]
223pub unsafe extern "C" fn wasm_func_as_ref_const(
224 func: Option<&wasm_func_t>,
225) -> Option<Box<wasm_ref_t>> {
226 let func = func?;
227 wasm_ref_t::new(
228 func.extern_.store.clone(),
229 Value::FuncRef(Some(func.extern_.function())),
230 )
231}
232
233#[unsafe(no_mangle)]
234pub unsafe extern "C" fn wasm_ref_as_func(
235 ref_: Option<&mut wasm_ref_t>,
236) -> Option<Box<wasm_func_t>> {
237 let ref_ = ref_?;
238 let func = match &ref_.inner {
239 Value::FuncRef(Some(f)) => f.clone(),
240 _ => return None,
241 };
242 let store = ref_.store.upgrade()?;
243 Some(Box::new(wasm_func_t {
244 extern_: wasm_extern_t::new(store, func.into()),
245 }))
246}
247
248#[unsafe(no_mangle)]
249pub unsafe extern "C" fn wasm_ref_as_func_const(
250 ref_: Option<&wasm_ref_t>,
251) -> Option<Box<wasm_func_t>> {
252 let ref_ = ref_?;
253 let func = match &ref_.inner {
254 Value::FuncRef(Some(f)) => f.clone(),
255 _ => return None,
256 };
257 let store = ref_.store.upgrade()?;
258 Some(Box::new(wasm_func_t {
259 extern_: wasm_extern_t::new(store, func.into()),
260 }))
261}
262
263#[unsafe(no_mangle)]
264pub unsafe extern "C" fn wasm_func_call(
265 func: Option<&mut wasm_func_t>,
266 args: Option<&wasm_val_vec_t>,
267 results: &mut wasm_val_vec_t,
268) -> Option<Box<wasm_trap_t>> {
269 let func = func?;
270 let args = args?;
271 let store_ref = func.extern_.store.clone();
272 let mut store = func.extern_.store.clone();
273 let mut store_mut = unsafe { store.store_mut() };
274 let params = c_try!(
277 args.as_slice()
278 .iter()
279 .map(Value::try_from)
280 .collect::<Result<Vec<Value>, _>>()
281 );
282
283 match func.extern_.function().call(&mut store_mut, ¶ms) {
284 Ok(wasm_results) => {
285 for (slot, val) in results
286 .as_uninit_slice()
287 .iter_mut()
288 .zip(wasm_results.iter())
289 {
290 let converted = c_try!(wasm_val_t::from_value(val, &store_ref));
291 *slot = MaybeUninit::new(converted);
292 }
293
294 None
295 }
296 Err(e) => Some(Box::new(e.into())),
297 }
298}
299
300#[unsafe(no_mangle)]
301pub unsafe extern "C" fn wasm_func_param_arity(func: Option<&wasm_func_t>) -> usize {
302 let Some(func) = func else {
303 update_last_error("func pointer is null");
304 return 0;
305 };
306 let store_ref = unsafe { func.extern_.store.store() };
307 func.extern_.function().ty(&store_ref).params().len()
308}
309
310#[unsafe(no_mangle)]
311pub unsafe extern "C" fn wasm_func_result_arity(func: Option<&wasm_func_t>) -> usize {
312 let Some(func) = func else {
313 update_last_error("func pointer is null");
314 return 0;
315 };
316 let store_ref = unsafe { func.extern_.store.store() };
317 func.extern_.function().ty(&store_ref).results().len()
318}
319
320#[unsafe(no_mangle)]
321pub unsafe extern "C" fn wasm_func_type(
322 func: Option<&wasm_func_t>,
323) -> Option<Box<wasm_functype_t>> {
324 let func = func?;
325 let store_ref = unsafe { func.extern_.store.store() };
326 Some(Box::new(wasm_functype_t::new(
327 func.extern_.function().ty(&store_ref),
328 )))
329}