wasmer/wasm_c_api/externals/
function.rs1use 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#[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 = 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 = 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#[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 = 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 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 if Arc::strong_count(&self.env_finalizer) == 1 {
131 if let Some(env_finalizer) = guard.take() {
132 unsafe { (env_finalizer)(self.env.as_ptr()) };
133 }
134 }
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 = 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#[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#[no_mangle]
194pub unsafe extern "C" fn wasm_func_delete(_func: Option<Box<wasm_func_t>>) {}
195
196#[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 = 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, ¶ms) {
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#[no_mangle]
231pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize {
232 func.extern_
233 .function()
234 .ty(&func.extern_.store.store())
235 .params()
236 .len()
237}
238
239#[no_mangle]
240pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize {
241 func.extern_
242 .function()
243 .ty(&func.extern_.store.store())
244 .results()
245 .len()
246}
247
248#[no_mangle]
249pub unsafe extern "C" fn wasm_func_type(
250 func: Option<&wasm_func_t>,
251) -> Option<Box<wasm_functype_t>> {
252 let func = func?;
253 Some(Box::new(wasm_functype_t::new(
254 func.extern_.function().ty(&func.extern_.store.store()),
255 )))
256}