1use crate::backend::sys::engine::NativeEngineExt;
2use crate::{
3 FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, StoreContext, TypedFunction,
4 Value, WasmTypeList,
5 store::{AsStoreMut, AsStoreRef},
6};
7#[cfg(feature = "experimental-async")]
8use crate::{StoreAsync, store::AsStoreAsync};
9use std::future::Future;
10use wasmer_types::{FunctionType, RawValue, Type};
11
12macro_rules! impl_native_traits {
13 ( $( $x:ident ),* ) => {
14 #[allow(unused_parens, non_snake_case)]
15 impl<$( $x , )* Rets> TypedFunction<( $( $x ),* ), Rets>
16 where
17 $( $x: FromToNativeWasmType, )*
18 Rets: WasmTypeList,
19 {
20 #[allow(unused_mut)]
22 #[allow(clippy::too_many_arguments)]
23 pub fn call_sys(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
24 let anyfunc = unsafe {
25 *self.func.as_sys()
26 .handle
27 .get(store.as_store_ref().objects().as_sys())
28 .anyfunc
29 .as_ptr()
30 .as_ref()
31 };
32 if $(!FromToNativeWasmType::is_from_store(&$x, store) ||)* false {
34 return Err(RuntimeError::new(
35 "cross-`Store` values are not supported",
36 ));
37 }
38 let mut params_list = [ $( $x.to_native().into_raw(store) ),* ];
41 let mut rets_list_array = Rets::empty_array();
42 let rets_list: &mut [RawValue] = rets_list_array.as_mut();
43 let using_rets_array;
44 let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
45 using_rets_array = false;
46 params_list.as_mut()
47 } else {
48 using_rets_array = true;
49 for (i, &arg) in params_list.iter().enumerate() {
50 rets_list[i] = arg;
51 }
52 rets_list.as_mut()
53 };
54
55 let store_id = store.objects_mut().id();
56 let store_install_guard = unsafe {
58 StoreContext::ensure_installed(store.as_store_mut().inner as *mut _)
59 };
60
61 let mut r;
62 loop {
63 let storeref = store.as_store_ref();
64 let config = storeref.engine().tunables().vmconfig();
65 r = unsafe {
66 let pause_guard = StoreContext::pause(store_id);
69 wasmer_vm::wasmer_call_trampoline(
70 store.as_store_ref().signal_handler(),
71 config,
72 anyfunc.vmctx,
73 anyfunc.call_trampoline,
74 anyfunc.func_ptr,
75 args_rets.as_mut_ptr() as *mut u8,
76 )
77 };
78 let store_mut = store.as_store_mut();
79 if let Some(callback) = store_mut.inner.on_called.take() {
80 match callback(store_mut) {
81 Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
82 Ok(wasmer_types::OnCalledAction::Finish) => { break; }
83 Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
84 Err(trap) => { return Err(RuntimeError::user(trap)) },
85 }
86 }
87 break;
88 }
89
90 drop(store_install_guard);
91
92 r?;
93
94 let num_rets = rets_list.len();
95 if !using_rets_array && num_rets > 0 {
96 let src_pointer = params_list.as_ptr();
97 let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
98 unsafe {
99 std::ptr::copy_nonoverlapping(src_pointer,
102 rets_list,
103 num_rets);
104 }
105 }
106 Ok(unsafe { Rets::from_array(store, rets_list_array) })
107 }
119
120 #[allow(unused_mut)]
122 #[allow(clippy::too_many_arguments)]
123 #[cfg(feature = "experimental-async")]
124 pub(crate) fn call_async_sys(
125 func: Function,
126 store: StoreAsync,
127 $( $x: $x, )*
128 ) -> impl Future<Output = Result<Rets, RuntimeError>> + 'static
129 where
130 $( $x: FromToNativeWasmType + 'static, )*
131 {
132 async move {
133 let mut write = store.write_lock().await;
134 let func_ty = func.ty(&mut write);
135 let mut params_raw = [ $( $x.to_native().into_raw(&mut write) ),* ];
136 let mut params_values = Vec::with_capacity(params_raw.len());
137 {
138 for (raw, ty) in params_raw.iter().zip(func_ty.params()) {
139 unsafe {
140 params_values.push(Value::from_raw(&mut write, *ty, *raw));
141 }
142 }
143 }
144 drop(write);
145
146 let results = func.call_async(&store, params_values).await?;
147 let mut write = store.write_lock().await;
148 convert_results::<Rets>(&mut write, func_ty, &results)
149 }
150 }
151
152 #[doc(hidden)]
153 #[allow(missing_docs)]
154 #[allow(unused_mut)]
155 #[allow(clippy::too_many_arguments)]
156 pub fn call_raw_sys(&self, store: &mut impl AsStoreMut, mut params_list: Vec<RawValue> ) -> Result<Rets, RuntimeError> {
157 let anyfunc = unsafe {
158 *self.func.as_sys()
159 .handle
160 .get(store.as_store_ref().objects().as_sys())
161 .anyfunc
162 .as_ptr()
163 .as_ref()
164 };
165 let mut rets_list_array = Rets::empty_array();
168 let rets_list: &mut [RawValue] = rets_list_array.as_mut();
169 let using_rets_array;
170 let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
171 using_rets_array = false;
172 params_list.as_mut()
173 } else {
174 using_rets_array = true;
175 for (i, &arg) in params_list.iter().enumerate() {
176 rets_list[i] = arg;
177 }
178 rets_list.as_mut()
179 };
180
181 let store_id = store.objects_mut().id();
182 let store_install_guard = unsafe {
184 StoreContext::ensure_installed(store.as_store_mut().inner as *mut _)
185 };
186
187 let mut r;
188 loop {
189 let storeref = store.as_store_ref();
190 let config = storeref.engine().tunables().vmconfig();
191 r = unsafe {
192 let pause_guard = StoreContext::pause(store_id);
195 wasmer_vm::wasmer_call_trampoline(
196 store.as_store_ref().signal_handler(),
197 config,
198 anyfunc.vmctx,
199 anyfunc.call_trampoline,
200 anyfunc.func_ptr,
201 args_rets.as_mut_ptr() as *mut u8,
202 )
203 };
204 let store_mut = store.as_store_mut();
205 if let Some(callback) = store_mut.inner.on_called.take() {
206 match callback(store_mut) {
208 Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
209 Ok(wasmer_types::OnCalledAction::Finish) => { break; }
210 Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
211 Err(trap) => { return Err(RuntimeError::user(trap)) },
212 }
213 }
214 break;
215 }
216
217 drop(store_install_guard);
218
219 r?;
220
221 let num_rets = rets_list.len();
222 if !using_rets_array && num_rets > 0 {
223 let src_pointer = params_list.as_ptr();
224 let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
225 unsafe {
226 std::ptr::copy_nonoverlapping(src_pointer,
229 rets_list,
230 num_rets);
231 }
232 }
233 Ok(unsafe { Rets::from_array(store, rets_list_array) })
234 }
246 }
247 };
248}
249
250impl_native_traits!();
251impl_native_traits!(A1);
252impl_native_traits!(A1, A2);
253impl_native_traits!(A1, A2, A3);
254impl_native_traits!(A1, A2, A3, A4);
255impl_native_traits!(A1, A2, A3, A4, A5);
256impl_native_traits!(A1, A2, A3, A4, A5, A6);
257impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
258impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
259impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
260impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
261impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
262impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
263impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
264impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
265impl_native_traits!(
266 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
267);
268impl_native_traits!(
269 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
270);
271impl_native_traits!(
272 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
273);
274impl_native_traits!(
275 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
276);
277impl_native_traits!(
278 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
279);
280impl_native_traits!(
281 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
282);
283
284fn convert_results<Rets>(
285 store: &mut impl AsStoreMut,
286 ty: FunctionType,
287 results: &[Value],
288) -> Result<Rets, RuntimeError>
289where
290 Rets: WasmTypeList,
291{
292 if results.len() != ty.results().len() {
293 return Err(RuntimeError::new("result arity mismatch"));
294 }
295 let mut raw_array = Rets::empty_array();
296 for ((slot, value_ty), value) in raw_array
297 .as_mut()
298 .iter_mut()
299 .zip(ty.results().iter())
300 .zip(results.iter())
301 {
302 debug_assert_eq!(value.ty(), *value_ty);
303 *slot = value.as_raw(store);
304 }
305 unsafe { Ok(Rets::from_array(store, raw_array)) }
306}