wasmer/backend/sys/entities/function/
mod.rs

1//! Data types, functions and traits for `sys` runtime's `Function` implementation.
2
3pub(crate) mod env;
4pub(crate) mod typed;
5
6use crate::{
7    BackendFunction, FunctionEnv, FunctionEnvMut, FunctionType, HostFunction, RuntimeError,
8    StoreInner, Value, WithEnv, WithoutEnv,
9    backend::sys::{engine::NativeEngineExt, vm::VMFunctionCallback},
10    entities::store::{AsStoreMut, AsStoreRef, StoreMut},
11    utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList},
12    vm::{VMExtern, VMExternFunction},
13};
14use std::panic::{self, AssertUnwindSafe};
15use std::{cell::UnsafeCell, cmp::max, error::Error, ffi::c_void};
16use wasmer_types::{NativeWasmType, RawValue};
17use wasmer_vm::{
18    MaybeInstanceOwned, StoreHandle, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext,
19    VMFuncRef, VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind, VMTrampoline,
20    on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline,
21};
22
23#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
24#[derive(Debug, Clone, PartialEq, Eq)]
25/// A WebAssembly `function` instance, in the `sys` runtime.
26pub struct Function {
27    pub(crate) handle: StoreHandle<VMFunction>,
28}
29
30impl From<StoreHandle<VMFunction>> for Function {
31    fn from(handle: StoreHandle<VMFunction>) -> Self {
32        Self { handle }
33    }
34}
35
36impl Function {
37    pub(crate) fn new_with_env<FT, F, T: Send + 'static>(
38        store: &mut impl AsStoreMut,
39        env: &FunctionEnv<T>,
40        ty: FT,
41        func: F,
42    ) -> Self
43    where
44        FT: Into<FunctionType>,
45        F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
46            + 'static
47            + Send
48            + Sync,
49    {
50        let function_type = ty.into();
51        let func_ty = function_type.clone();
52        let func_env = env.clone().into_sys();
53        let raw_store = store.as_store_mut().as_raw() as *mut u8;
54        let wrapper = move |values_vec: *mut RawValue| -> Result<(), RuntimeError> {
55            unsafe {
56                let mut store = StoreMut::from_raw(raw_store as *mut StoreInner);
57                let mut args = Vec::with_capacity(func_ty.params().len());
58
59                for (i, ty) in func_ty.params().iter().enumerate() {
60                    args.push(Value::from_raw(
61                        &mut store,
62                        *ty,
63                        values_vec.add(i).read_unaligned(),
64                    ));
65                }
66                let store_mut = StoreMut::from_raw(raw_store as *mut StoreInner);
67                let env = env::FunctionEnvMut {
68                    store_mut,
69                    func_env: func_env.clone(),
70                }
71                .into();
72                let returns = func(env, &args)?;
73
74                // We need to dynamically check that the returns
75                // match the expected types, as well as expected length.
76                let return_types = returns.iter().map(|ret| ret.ty());
77                if return_types.ne(func_ty.results().iter().copied()) {
78                    return Err(RuntimeError::new(format!(
79                        "Dynamic function returned wrong signature. Expected {:?} but got {:?}",
80                        func_ty.results(),
81                        returns.iter().map(|ret| ret.ty())
82                    )));
83                }
84                for (i, ret) in returns.iter().enumerate() {
85                    values_vec.add(i).write_unaligned(ret.as_raw(&store));
86                }
87            }
88            Ok(())
89        };
90        let mut host_data = Box::new(VMDynamicFunctionContext {
91            address: std::ptr::null(),
92            ctx: DynamicFunction {
93                func: wrapper,
94                raw_store,
95            },
96        });
97        host_data.address = host_data.ctx.func_body_ptr();
98
99        // We don't yet have the address with the Wasm ABI signature.
100        // The engine linker will replace the address with one pointing to a
101        // generated dynamic trampoline.
102        let func_ptr = std::ptr::null() as VMFunctionCallback;
103        let type_index = store
104            .as_store_mut()
105            .engine()
106            .as_sys()
107            .register_signature(&function_type);
108        let vmctx = VMFunctionContext {
109            host_env: host_data.as_ref() as *const _ as *mut c_void,
110        };
111        let call_trampoline = host_data.ctx.call_trampoline_address();
112        let anyfunc = VMCallerCheckedAnyfunc {
113            func_ptr,
114            type_index,
115            vmctx,
116            call_trampoline,
117        };
118
119        let vm_function = VMFunction {
120            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
121            kind: VMFunctionKind::Dynamic,
122            signature: function_type,
123            host_data,
124        };
125        Self {
126            handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function),
127        }
128    }
129
130    /// Creates a new host `Function` from a native function.
131    pub(crate) fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
132    where
133        F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
134        Args: WasmTypeList,
135        Rets: WasmTypeList,
136    {
137        let env = FunctionEnv::new(store, ());
138        let func_ptr = func.function_callback_sys().into_sys();
139        let host_data = Box::new(StaticFunction {
140            raw_store: store.as_store_mut().as_raw() as *mut u8,
141            env,
142            func,
143        });
144        let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
145
146        let type_index = store
147            .as_store_mut()
148            .engine()
149            .as_sys()
150            .register_signature(&function_type);
151        let vmctx = VMFunctionContext {
152            host_env: host_data.as_ref() as *const _ as *mut c_void,
153        };
154        let call_trampoline =
155            <F as HostFunction<(), Args, Rets, WithoutEnv>>::call_trampoline_address().into_sys();
156        let anyfunc = VMCallerCheckedAnyfunc {
157            func_ptr,
158            type_index,
159            vmctx,
160            call_trampoline,
161        };
162
163        let vm_function = VMFunction {
164            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
165            kind: VMFunctionKind::Static,
166            signature: function_type,
167            host_data,
168        };
169        Self {
170            handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function),
171        }
172    }
173
174    pub(crate) fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
175        store: &mut impl AsStoreMut,
176        env: &FunctionEnv<T>,
177        func: F,
178    ) -> Self
179    where
180        F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
181        Args: WasmTypeList,
182        Rets: WasmTypeList,
183    {
184        let func_ptr = func.function_callback_sys().into_sys();
185        let host_data = Box::new(StaticFunction {
186            raw_store: store.as_store_mut().as_raw() as *mut u8,
187            env: env.as_sys().clone().into(),
188            func,
189        });
190        let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
191
192        let type_index = store
193            .as_store_mut()
194            .engine()
195            .as_sys()
196            .register_signature(&function_type);
197        let vmctx = VMFunctionContext {
198            host_env: host_data.as_ref() as *const _ as *mut c_void,
199        };
200        let call_trampoline =
201            <F as HostFunction<T, Args, Rets, WithEnv>>::call_trampoline_address().into_sys();
202        let anyfunc = VMCallerCheckedAnyfunc {
203            func_ptr,
204            type_index,
205            vmctx,
206            call_trampoline,
207        };
208
209        let vm_function = VMFunction {
210            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
211            kind: VMFunctionKind::Static,
212            signature: function_type,
213            host_data,
214        };
215        Self {
216            handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function),
217        }
218    }
219
220    pub(crate) fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
221        self.handle
222            .get(store.as_store_ref().objects().as_sys())
223            .signature
224            .clone()
225    }
226
227    fn call_wasm(
228        &self,
229        store: &mut impl AsStoreMut,
230        trampoline: VMTrampoline,
231        params: &[Value],
232        results: &mut [Value],
233    ) -> Result<(), RuntimeError> {
234        let format_types_for_error_message = |items: &[Value]| {
235            items
236                .iter()
237                .map(|param| param.ty().to_string())
238                .collect::<Vec<String>>()
239                .join(", ")
240        };
241        // TODO: Avoid cloning the signature here, it's expensive.
242        let signature = self.ty(store);
243        if signature.params().len() != params.len() {
244            return Err(RuntimeError::new(format!(
245                "Parameters of type [{}] did not match signature {}",
246                format_types_for_error_message(params),
247                &signature
248            )));
249        }
250        if signature.results().len() != results.len() {
251            return Err(RuntimeError::new(format!(
252                "Results of type [{}] did not match signature {}",
253                format_types_for_error_message(results),
254                &signature,
255            )));
256        }
257
258        let mut values_vec = vec![RawValue { i32: 0 }; max(params.len(), results.len())];
259
260        // Store the argument values into `values_vec`.
261        let param_tys = signature.params().iter();
262        for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
263            if arg.ty() != *ty {
264                let param_types = format_types_for_error_message(params);
265                return Err(RuntimeError::new(format!(
266                    "Parameters of type [{}] did not match signature {}",
267                    param_types, &signature,
268                )));
269            }
270            if !arg.is_from_store(store) {
271                return Err(RuntimeError::new("cross-`Store` values are not supported"));
272            }
273            *slot = arg.as_raw(store);
274        }
275
276        // Invoke the call
277        self.call_wasm_raw(store, trampoline, values_vec, results)?;
278        Ok(())
279    }
280
281    fn call_wasm_raw(
282        &self,
283        store: &mut impl AsStoreMut,
284        trampoline: VMTrampoline,
285        mut params: Vec<RawValue>,
286        results: &mut [Value],
287    ) -> Result<(), RuntimeError> {
288        // Call the trampoline.
289        let result = {
290            let mut r;
291            // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451
292            loop {
293                let storeref = store.as_store_ref();
294                let vm_function = self.handle.get(storeref.objects().as_sys());
295                let config = storeref.engine().tunables().vmconfig();
296                r = unsafe {
297                    wasmer_call_trampoline(
298                        store.as_store_ref().signal_handler(),
299                        config,
300                        vm_function.anyfunc.as_ptr().as_ref().vmctx,
301                        trampoline,
302                        vm_function.anyfunc.as_ptr().as_ref().func_ptr,
303                        params.as_mut_ptr() as *mut u8,
304                    )
305                };
306                let store_mut = store.as_store_mut();
307                if let Some(callback) = store_mut.inner.on_called.take() {
308                    match callback(store_mut) {
309                        Ok(wasmer_types::OnCalledAction::InvokeAgain) => {
310                            continue;
311                        }
312                        Ok(wasmer_types::OnCalledAction::Finish) => {
313                            break;
314                        }
315                        Ok(wasmer_types::OnCalledAction::Trap(trap)) => {
316                            return Err(RuntimeError::user(trap));
317                        }
318                        Err(trap) => return Err(RuntimeError::user(trap)),
319                    }
320                }
321                break;
322            }
323            r
324        };
325        if let Err(error) = result {
326            return Err(error.into());
327        }
328
329        // Load the return values out of `values_vec`.
330        let signature = self.ty(store);
331        for (index, &value_type) in signature.results().iter().enumerate() {
332            unsafe {
333                results[index] = Value::from_raw(store, value_type, params[index]);
334            }
335        }
336
337        Ok(())
338    }
339
340    pub(crate) fn result_arity(&self, store: &impl AsStoreRef) -> usize {
341        self.ty(store).results().len()
342    }
343
344    pub(crate) fn call(
345        &self,
346        store: &mut impl AsStoreMut,
347        params: &[Value],
348    ) -> Result<Box<[Value]>, RuntimeError> {
349        let trampoline = unsafe {
350            self.handle
351                .get(store.as_store_ref().objects().as_sys())
352                .anyfunc
353                .as_ptr()
354                .as_ref()
355                .call_trampoline
356        };
357        let mut results = vec![Value::null(); self.result_arity(store)];
358        self.call_wasm(store, trampoline, params, &mut results)?;
359        Ok(results.into_boxed_slice())
360    }
361
362    #[doc(hidden)]
363    #[allow(missing_docs)]
364    pub(crate) fn call_raw(
365        &self,
366        store: &mut impl AsStoreMut,
367        params: Vec<RawValue>,
368    ) -> Result<Box<[Value]>, RuntimeError> {
369        let trampoline = unsafe {
370            self.handle
371                .get(store.as_store_ref().objects().as_sys())
372                .anyfunc
373                .as_ptr()
374                .as_ref()
375                .call_trampoline
376        };
377        let mut results = vec![Value::null(); self.result_arity(store)];
378        self.call_wasm_raw(store, trampoline, params, &mut results)?;
379        Ok(results.into_boxed_slice())
380    }
381
382    pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
383        let vm_function = self.handle.get(store.as_store_ref().objects().as_sys());
384        if vm_function.kind == VMFunctionKind::Dynamic {
385            panic!("dynamic functions cannot be used in tables or as funcrefs");
386        }
387        VMFuncRef(vm_function.anyfunc.as_ptr())
388    }
389
390    pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
391        let signature = {
392            let anyfunc = unsafe { funcref.0.as_ref() };
393            store
394                .as_store_ref()
395                .engine()
396                .as_sys()
397                .lookup_signature(anyfunc.type_index)
398                .expect("Signature not found in store")
399        };
400        let vm_function = VMFunction {
401            anyfunc: MaybeInstanceOwned::Instance(funcref.0),
402            signature,
403            // All functions in tables are already Static (as dynamic functions
404            // are converted to use the trampolines with static signatures).
405            kind: wasmer_vm::VMFunctionKind::Static,
406            host_data: Box::new(()),
407        };
408        Self {
409            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
410        }
411    }
412
413    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
414        Self {
415            handle: unsafe {
416                StoreHandle::from_internal(
417                    store.as_store_ref().objects().id(),
418                    vm_extern.into_sys(),
419                )
420            },
421        }
422    }
423
424    /// Checks whether this `Function` can be used with the given store.
425    pub(crate) fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
426        self.handle.store_id() == store.as_store_ref().objects().id()
427    }
428
429    pub(crate) fn to_vm_extern(&self) -> VMExtern {
430        VMExtern::Sys(wasmer_vm::VMExtern::Function(self.handle.internal_handle()))
431    }
432}
433
434// We want to keep as much logic as possible on the host stack,
435// since the WASM stack may be out of memory. In that scenario,
436// throwing exceptions won't work since libunwind requires
437// considerable stack space to do its magic, but everything else
438// should work.
439enum InvocationResult<T, E> {
440    Success(T),
441    Exception(crate::Exception),
442    Trap(Box<E>),
443}
444
445fn to_invocation_result<T, E>(result: Result<T, E>) -> InvocationResult<T, E>
446where
447    E: Error + 'static,
448{
449    match result {
450        Ok(value) => InvocationResult::Success(value),
451        Err(trap) => {
452            let dyn_err_ref = &trap as &dyn Error;
453            if let Some(runtime_error) = dyn_err_ref.downcast_ref::<RuntimeError>()
454                && let Some(exception) = runtime_error.to_exception()
455            {
456                return InvocationResult::Exception(exception);
457            }
458            InvocationResult::Trap(Box::new(trap))
459        }
460    }
461}
462
463/// Host state for a dynamic function.
464pub(crate) struct DynamicFunction<F> {
465    func: F,
466    raw_store: *mut u8,
467}
468
469impl<F> DynamicFunction<F>
470where
471    F: Fn(*mut RawValue) -> Result<(), RuntimeError> + 'static,
472{
473    // This function wraps our func, to make it compatible with the
474    // reverse trampoline signature
475    unsafe extern "C-unwind" fn func_wrapper(
476        this: &mut VMDynamicFunctionContext<Self>,
477        values_vec: *mut RawValue,
478    ) {
479        let result = on_host_stack(|| {
480            panic::catch_unwind(AssertUnwindSafe(|| {
481                to_invocation_result((this.ctx.func)(values_vec))
482            }))
483        });
484
485        // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
486        // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
487        // See: https://github.com/wasmerio/wasmer/pull/5700
488        match result {
489            Ok(InvocationResult::Success(())) => {}
490            Ok(InvocationResult::Exception(exception)) => unsafe {
491                let store = StoreMut::from_raw(this.ctx.raw_store as *mut _);
492                wasmer_vm::libcalls::throw(
493                    store.as_store_ref().objects().as_sys(),
494                    exception.vm_exceptionref().as_sys().to_u32_exnref(),
495                )
496            },
497            Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
498            Err(panic) => unsafe { resume_panic(panic) },
499        }
500    }
501
502    fn func_body_ptr(&self) -> VMFunctionCallback {
503        Self::func_wrapper as VMFunctionCallback
504    }
505
506    fn call_trampoline_address(&self) -> VMTrampoline {
507        Self::call_trampoline
508    }
509
510    unsafe extern "C" fn call_trampoline(
511        vmctx: *mut VMContext,
512        _body: VMFunctionCallback,
513        args: *mut RawValue,
514    ) {
515        // The VMFunctionCallback is null here: it is only filled in later
516        // by the engine linker.
517        unsafe {
518            let dynamic_function = &mut *(vmctx as *mut VMDynamicFunctionContext<Self>);
519            Self::func_wrapper(dynamic_function, args);
520        }
521    }
522}
523
524/// Represents a low-level Wasm static host function. See
525/// [`crate::Function::new_typed`] and
526/// [`crate::Function::new_typed_with_env`] to learn more.
527pub(crate) struct StaticFunction<F, T> {
528    pub(crate) raw_store: *mut u8,
529    pub(crate) env: FunctionEnv<T>,
530    pub(crate) func: F,
531}
532
533impl crate::Function {
534    /// Consume [`self`] into [`crate::backend::sys::function::Function`].
535    pub fn into_sys(self) -> crate::backend::sys::function::Function {
536        match self.0 {
537            BackendFunction::Sys(s) => s,
538            _ => panic!("Not a `sys` function!"),
539        }
540    }
541
542    /// Convert a reference to [`self`] into a reference to [`crate::backend::sys::function::Function`].
543    pub fn as_sys(&self) -> &crate::backend::sys::function::Function {
544        match self.0 {
545            BackendFunction::Sys(ref s) => s,
546            _ => panic!("Not a `sys` function!"),
547        }
548    }
549
550    /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::function::Function`].
551    pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::function::Function {
552        match self.0 {
553            BackendFunction::Sys(ref mut s) => s,
554            _ => panic!("Not a `sys` function!"),
555        }
556    }
557}
558
559macro_rules! impl_host_function {
560    ([$c_struct_representation:ident] $c_struct_name:ident, $( $x:ident ),* ) => {
561        paste::paste! {
562        #[allow(non_snake_case)]
563        pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower _no_env>]
564            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, Func: Fn($( $x , )*) -> RetsAsResult + 'static>
565            (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
566            /// This is a function that wraps the real host
567            /// function. Its address will be used inside the
568            /// runtime.
569            unsafe extern "C-unwind" fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, ()>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
570            where
571                $( $x: FromToNativeWasmType, )*
572                Rets: WasmTypeList,
573                RetsAsResult: IntoResult<Rets>,
574                Func: Fn($( $x , )*) -> RetsAsResult + 'static,
575            {
576                let mut store = unsafe { StoreMut::from_raw(env.raw_store as *mut _) };
577                let result = on_host_stack(|| {
578                    panic::catch_unwind(AssertUnwindSafe(|| {
579                        $(
580                            let $x = unsafe {
581                                FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
582                            };
583                        )*
584                        to_invocation_result((env.func)($($x),* ).into_result())
585                    }))
586                });
587
588                // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
589                // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
590                // See: https://github.com/wasmerio/wasmer/pull/5700
591                match result {
592                    Ok(InvocationResult::Success(result)) => {
593                        unsafe {
594                            return result.into_c_struct(&mut store);
595                        }
596                    },
597                    Ok(InvocationResult::Exception(exception)) => unsafe {
598                        wasmer_vm::libcalls::throw(
599                            store.as_store_ref().objects().as_sys(),
600                            exception.vm_exceptionref().as_sys().to_u32_exnref()
601                        )
602                    }
603                    Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
604                    Err(panic) => unsafe { resume_panic(panic) },
605                }
606            }
607
608            func_wrapper::< $( $x, )* Rets, RetsAsResult, Func > as _
609
610        }
611
612        #[allow(non_snake_case)]
613        pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower _no_env>]
614            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
615            () -> crate::backend::sys::vm::VMTrampoline {
616
617            unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
618            (
619                vmctx: *mut crate::backend::sys::vm::VMContext,
620                body: crate::backend::sys::vm::VMFunctionCallback,
621                args: *mut RawValue,
622            ) {
623                let mut _n = 0;
624
625                unsafe {
626                    let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body);
627                    $(
628                        let $x = *args.add(_n).cast();
629                        _n += 1;
630                    )*
631                    let results = body(vmctx, $( $x ),*);
632                    Rets::write_c_struct_to_ptr(results, args);
633                }
634            }
635
636            call_trampoline::<$( $x, )* Rets> as _
637
638        }
639
640        #[allow(non_snake_case)]
641        pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower>]
642            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, T: Send + 'static,  Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static>
643            (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
644            /// This is a function that wraps the real host
645            /// function. Its address will be used inside the
646            /// runtime.
647            unsafe extern "C-unwind" fn func_wrapper<T: Send + 'static, $( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, T>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
648                where
649                $( $x: FromToNativeWasmType, )*
650                Rets: WasmTypeList,
651                RetsAsResult: IntoResult<Rets>,
652                Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
653            {
654
655                let mut store = unsafe { StoreMut::from_raw(env.raw_store as *mut _) };
656                let result = wasmer_vm::on_host_stack(|| {
657                    panic::catch_unwind(AssertUnwindSafe(|| {
658                        $(
659                            let $x = unsafe {
660                                FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
661                            };
662                        )*
663                        let store_mut = unsafe { StoreMut::from_raw(env.raw_store as *mut _) };
664                        let f_env = crate::backend::sys::function::env::FunctionEnvMut {
665                            store_mut,
666                            func_env: env.env.as_sys().clone(),
667                        }.into();
668                        to_invocation_result((env.func)(f_env, $($x),* ).into_result())
669                    }))
670                });
671
672                // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
673                // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
674                // See: https://github.com/wasmerio/wasmer/pull/5700
675                match result {
676                    Ok(InvocationResult::Success(result)) => {
677                        unsafe {
678                            return result.into_c_struct(&mut store);
679                        }
680                    },
681                    Ok(InvocationResult::Exception(exception)) => unsafe {
682                        wasmer_vm::libcalls::throw(
683                            store.as_store_ref().objects().as_sys(),
684                            exception.vm_exceptionref().as_sys().to_u32_exnref()
685                        )
686                    }
687                    Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
688                    Err(panic) => unsafe { resume_panic(panic) },
689                }
690            }
691            func_wrapper::< T, $( $x, )* Rets, RetsAsResult, Func > as _
692        }
693
694        #[allow(non_snake_case)]
695        pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower>]
696            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
697            () -> crate::backend::sys::vm::VMTrampoline {
698
699            unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>(
700                  vmctx: *mut crate::backend::sys::vm::VMContext,
701                  body: crate::backend::sys::vm::VMFunctionCallback,
702                  args: *mut RawValue,
703            ) {
704                unsafe {
705                    let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body);
706                    let mut _n = 0;
707                    $(
708                    let $x = *args.add(_n).cast();
709                    _n += 1;
710                    )*
711
712                    let results = body(vmctx, $( $x ),*);
713
714                    Rets::write_c_struct_to_ptr(results, args);
715                }
716            }
717
718            call_trampoline::<$( $x, )* Rets> as _
719        }
720    }};
721}
722
723// Here we go! Let's generate all the C struct, `WasmTypeList`
724// implementations and `HostFunction` implementations.
725impl_host_function!([C] S0,);
726impl_host_function!([transparent] S1, A1);
727impl_host_function!([C] S2, A1, A2);
728impl_host_function!([C] S3, A1, A2, A3);
729impl_host_function!([C] S4, A1, A2, A3, A4);
730impl_host_function!([C] S5, A1, A2, A3, A4, A5);
731impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6);
732impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7);
733impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
734impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
735impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
736impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
737impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
738impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
739impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
740impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
741impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
742impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
743impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
744impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
745impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
746impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
747impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
748impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
749impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
750impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
751impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);