1#[cfg(feature = "experimental-host-interrupt")]
2use crate::backend::sys::vm::interrupt_registry;
3use crate::backend::sys::{
4 engine::NativeEngineExt,
5 vm::{Trap, TrapCode},
6};
7use crate::{
8 FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, StoreContext, TypedFunction,
9 Value, WasmTypeList,
10 store::{AsStoreMut, AsStoreRef},
11};
12#[cfg(feature = "experimental-async")]
13use crate::{StoreAsync, store::AsStoreAsync};
14use std::future::Future;
15use wasmer_types::{FunctionType, RawValue, Type};
16
17macro_rules! impl_native_traits {
18 ( $( $x:ident ),* ) => {
19 #[allow(unused_parens, non_snake_case)]
20 impl<$( $x , )* Rets> TypedFunction<( $( $x ),* ), Rets>
21 where
22 $( $x: FromToNativeWasmType, )*
23 Rets: WasmTypeList,
24 {
25 #[allow(unused_mut)]
27 #[allow(clippy::too_many_arguments)]
28 pub fn call_sys(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
29 let anyfunc = unsafe {
30 *self.func.as_sys()
31 .handle
32 .get(store.as_store_ref().objects().as_sys())
33 .anyfunc
34 .as_ptr()
35 .as_ref()
36 };
37 if $(!FromToNativeWasmType::is_from_store(&$x, store) ||)* false {
39 return Err(RuntimeError::new(
40 "cross-`Store` values are not supported",
41 ));
42 }
43 let mut params_list = [ $( $x.to_native().into_raw(store) ),* ];
46 let mut rets_list_array = Rets::empty_array();
47 let rets_list: &mut [RawValue] = rets_list_array.as_mut();
48 let using_rets_array;
49 let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
50 using_rets_array = false;
51 params_list.as_mut()
52 } else {
53 using_rets_array = true;
54 for (i, &arg) in params_list.iter().enumerate() {
55 rets_list[i] = arg;
56 }
57 rets_list.as_mut()
58 };
59
60 let store_id = store.objects_mut().id();
61
62 #[cfg(feature = "experimental-host-interrupt")]
63 let interrupt_guard = match interrupt_registry::install(store_id) {
64 Ok(x) => x,
65 Err(interrupt_registry::InstallError::AlreadyInterrupted) => {
66 return Err(Trap::lib(TrapCode::HostInterrupt).into());
67 }
68 };
69
70 let store_install_guard = unsafe {
72 StoreContext::install(store.as_store_mut().inner as *mut _)
73 };
74
75 let mut r;
76 loop {
77 let storeref = store.as_store_ref();
78 let config = storeref.engine().tunables().vmconfig();
79 r = unsafe {
80 let pause_guard = StoreContext::pause(store_id);
83 wasmer_vm::wasmer_call_trampoline(
84 store.as_store_ref().signal_handler(),
85 config,
86 anyfunc.vmctx,
87 anyfunc.call_trampoline,
88 anyfunc.func_ptr,
89 args_rets.as_mut_ptr() as *mut u8,
90 )
91 };
92 let store_mut = store.as_store_mut();
93 if let Some(callback) = store_mut.inner.on_called.take() {
94 match callback(store_mut) {
95 Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
96 Ok(wasmer_types::OnCalledAction::Finish) => { break; }
97 Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
98 Err(trap) => { return Err(RuntimeError::user(trap)) },
99 }
100 }
101 break;
102 }
103
104 drop(store_install_guard);
105 #[cfg(feature = "experimental-host-interrupt")]
106 drop(interrupt_guard);
107
108 r?;
109
110 let num_rets = rets_list.len();
111 if !using_rets_array && num_rets > 0 {
112 let src_pointer = params_list.as_ptr();
113 let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
114 unsafe {
115 std::ptr::copy_nonoverlapping(src_pointer,
118 rets_list,
119 num_rets);
120 }
121 }
122 Ok(unsafe { Rets::from_array(store, rets_list_array) })
123 }
135
136 #[allow(unused_mut)]
138 #[allow(clippy::too_many_arguments)]
139 #[cfg(feature = "experimental-async")]
140 pub(crate) fn call_async_sys(
141 func: Function,
142 store: StoreAsync,
143 $( $x: $x, )*
144 ) -> impl Future<Output = Result<Rets, RuntimeError>> + 'static
145 where
146 $( $x: FromToNativeWasmType + 'static, )*
147 {
148 async move {
149 let mut write = store.write_lock().await;
150 let func_ty = func.ty(&mut write);
151 let mut params_raw = [ $( $x.to_native().into_raw(&mut write) ),* ];
152 let mut params_values = Vec::with_capacity(params_raw.len());
153 {
154 for (raw, ty) in params_raw.iter().zip(func_ty.params()) {
155 unsafe {
156 params_values.push(Value::from_raw(&mut write, *ty, *raw));
157 }
158 }
159 }
160 drop(write);
161
162 let results = func.call_async(&store, params_values).await?;
163 let mut write = store.write_lock().await;
164 convert_results::<Rets>(&mut write, func_ty, &results)
165 }
166 }
167
168 #[doc(hidden)]
169 #[allow(missing_docs)]
170 #[allow(unused_mut)]
171 #[allow(clippy::too_many_arguments)]
172 pub fn call_raw_sys(&self, store: &mut impl AsStoreMut, mut params_list: Vec<RawValue> ) -> Result<Rets, RuntimeError> {
173 let anyfunc = unsafe {
174 *self.func.as_sys()
175 .handle
176 .get(store.as_store_ref().objects().as_sys())
177 .anyfunc
178 .as_ptr()
179 .as_ref()
180 };
181 let mut rets_list_array = Rets::empty_array();
184 let rets_list: &mut [RawValue] = rets_list_array.as_mut();
185 let using_rets_array;
186 let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
187 using_rets_array = false;
188 params_list.as_mut()
189 } else {
190 using_rets_array = true;
191 for (i, &arg) in params_list.iter().enumerate() {
192 rets_list[i] = arg;
193 }
194 rets_list.as_mut()
195 };
196
197 let store_id = store.objects_mut().id();
198
199 #[cfg(feature = "experimental-host-interrupt")]
200 let interrupt_guard = match interrupt_registry::install(store_id) {
201 Ok(x) => x,
202 Err(interrupt_registry::InstallError::AlreadyInterrupted) => {
203 return Err(Trap::lib(TrapCode::HostInterrupt).into());
204 }
205 };
206
207 let store_install_guard = unsafe {
209 StoreContext::install(store.as_store_mut().inner as *mut _)
210 };
211
212 let mut r;
213 loop {
214 let storeref = store.as_store_ref();
215 let config = storeref.engine().tunables().vmconfig();
216 r = unsafe {
217 let pause_guard = StoreContext::pause(store_id);
220 wasmer_vm::wasmer_call_trampoline(
221 store.as_store_ref().signal_handler(),
222 config,
223 anyfunc.vmctx,
224 anyfunc.call_trampoline,
225 anyfunc.func_ptr,
226 args_rets.as_mut_ptr() as *mut u8,
227 )
228 };
229 let store_mut = store.as_store_mut();
230 if let Some(callback) = store_mut.inner.on_called.take() {
231 match callback(store_mut) {
233 Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
234 Ok(wasmer_types::OnCalledAction::Finish) => { break; }
235 Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
236 Err(trap) => { return Err(RuntimeError::user(trap)) },
237 }
238 }
239 break;
240 }
241
242 drop(store_install_guard);
243 #[cfg(feature = "experimental-host-interrupt")]
244 drop(interrupt_guard);
245
246 r?;
247
248 let num_rets = rets_list.len();
249 if !using_rets_array && num_rets > 0 {
250 let src_pointer = params_list.as_ptr();
251 let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
252 unsafe {
253 std::ptr::copy_nonoverlapping(src_pointer,
256 rets_list,
257 num_rets);
258 }
259 }
260 Ok(unsafe { Rets::from_array(store, rets_list_array) })
261 }
273 }
274 };
275}
276
277impl_native_traits!();
278impl_native_traits!(A1);
279impl_native_traits!(A1, A2);
280impl_native_traits!(A1, A2, A3);
281impl_native_traits!(A1, A2, A3, A4);
282impl_native_traits!(A1, A2, A3, A4, A5);
283impl_native_traits!(A1, A2, A3, A4, A5, A6);
284impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
285impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
286impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
287impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
288impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
289impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
290impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
291impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
292impl_native_traits!(
293 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
294);
295impl_native_traits!(
296 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
297);
298impl_native_traits!(
299 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
300);
301impl_native_traits!(
302 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
303);
304impl_native_traits!(
305 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
306);
307impl_native_traits!(
308 A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
309);
310
311fn convert_results<Rets>(
312 store: &mut impl AsStoreMut,
313 ty: FunctionType,
314 results: &[Value],
315) -> Result<Rets, RuntimeError>
316where
317 Rets: WasmTypeList,
318{
319 if results.len() != ty.results().len() {
320 return Err(RuntimeError::new("result arity mismatch"));
321 }
322 let mut raw_array = Rets::empty_array();
323 for ((slot, value_ty), value) in raw_array
324 .as_mut()
325 .iter_mut()
326 .zip(ty.results().iter())
327 .zip(results.iter())
328 {
329 debug_assert_eq!(value.ty(), *value_ty);
330 *slot = value.as_raw(store);
331 }
332 unsafe { Ok(Rets::from_array(store, raw_array)) }
333}