wasmer_runtime_core_fl/
typed_func.rs

1//! The typed func module implements a way of representing a wasm function
2//! with the correct types from rust. Function calls using a typed func have a low overhead.
3use crate::{
4    error::{InvokeError, RuntimeError},
5    export::{Context, Export, FuncPointer},
6    import::IsExport,
7    types::{FuncSig, NativeWasmType, Type, WasmExternType},
8    vm,
9};
10use std::{
11    any::Any,
12    convert::Infallible,
13    ffi::c_void,
14    marker::PhantomData,
15    mem, panic,
16    ptr::{self, NonNull},
17    sync::Arc,
18};
19
20/// This is just an empty trait to constrict that types that
21/// can be put into the third/fourth (depending if you include lifetimes)
22/// of the `Func` struct.
23pub trait Kind {}
24
25/// Aliases to an extern "C" type used as a trampoline to a function.
26pub type Trampoline = unsafe extern "C" fn(
27    vmctx: *mut vm::Ctx,
28    func: NonNull<vm::Func>,
29    args: *const u64,
30    rets: *mut u64,
31);
32
33/// Aliases to an extern "C" type used to invoke a function.
34pub type Invoke = unsafe extern "C" fn(
35    trampoline: Trampoline,
36    vmctx: *mut vm::Ctx,
37    func: NonNull<vm::Func>,
38    args: *const u64,
39    rets: *mut u64,
40    error_out: *mut Option<RuntimeError>,
41    extra: Option<NonNull<c_void>>,
42) -> bool;
43
44/// TODO(lachlan): Naming TBD.
45/// This contains the trampoline and invoke functions for a specific signature,
46/// as well as the environment that the invoke function may or may not require.
47#[derive(Copy, Clone)]
48pub struct Wasm {
49    pub(crate) trampoline: Trampoline,
50    pub(crate) invoke: Invoke,
51    pub(crate) invoke_env: Option<NonNull<c_void>>,
52}
53
54impl Kind for Wasm {}
55
56impl Wasm {
57    /// Create new `Wasm` from given parts.
58    pub unsafe fn from_raw_parts(
59        trampoline: Trampoline,
60        invoke: Invoke,
61        invoke_env: Option<NonNull<c_void>>,
62    ) -> Self {
63        Self {
64            trampoline,
65            invoke,
66            invoke_env,
67        }
68    }
69}
70
71/// This type, as part of the `Func` type signature, represents a function that is created
72/// by the host.
73pub struct Host(());
74
75impl Kind for Host {}
76
77/// Represents a list of WebAssembly values.
78pub trait WasmTypeList {
79    /// CStruct type.
80    type CStruct;
81
82    /// Array of return values.
83    type RetArray: AsMut<[u64]>;
84
85    /// Construct `Self` based on an array of returned values.
86    fn from_ret_array(array: Self::RetArray) -> Self;
87
88    /// Generates an empty array that will hold the returned values of
89    /// the WebAssembly function.
90    fn empty_ret_array() -> Self::RetArray;
91
92    /// Transforms C values into Rust values.
93    fn from_c_struct(c_struct: Self::CStruct) -> Self;
94
95    /// Transforms Rust values into C values.
96    fn into_c_struct(self) -> Self::CStruct;
97
98    /// Get types of the current values.
99    fn types() -> &'static [Type];
100
101    /// This method is used to distribute the values onto a function,
102    /// e.g. `(1, 2).call(func, …)`. This form is unlikely to be used
103    /// directly in the code, see the `Func::call` implementation.
104    unsafe fn call<Rets>(
105        self,
106        f: NonNull<vm::Func>,
107        wasm: Wasm,
108        ctx: *mut vm::Ctx,
109    ) -> Result<Rets, RuntimeError>
110    where
111        Rets: WasmTypeList;
112}
113
114/// Empty trait to specify the kind of `HostFunction`: With or
115/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the
116/// `ImplicitVmCtx` structures.
117///
118/// This trait is never aimed to be used by a user. It is used by the
119/// trait system to automatically generate an appropriate `wrap`
120/// function.
121#[doc(hidden)]
122pub trait HostFunctionKind {}
123
124/// This empty structure indicates that an external function must
125/// contain an explicit `vm::Ctx` argument (at first position).
126///
127/// ```rs,ignore
128/// fn add_one(_: mut &vm::Ctx, x: i32) -> i32 {
129///     x + 1
130/// }
131/// ```
132#[doc(hidden)]
133pub struct ExplicitVmCtx {}
134
135impl HostFunctionKind for ExplicitVmCtx {}
136
137/// This empty structure indicates that an external function has no
138/// `vm::Ctx` argument (at first position). Its signature is:
139///
140/// ```rs,ignore
141/// fn add_one(x: i32) -> i32 {
142///     x + 1
143/// }
144/// ```
145pub struct ImplicitVmCtx {}
146
147impl HostFunctionKind for ImplicitVmCtx {}
148
149/// Represents a function that can be converted to a `vm::Func`
150/// (function pointer) that can be called within WebAssembly.
151pub trait HostFunction<Kind, Args, Rets>
152where
153    Kind: HostFunctionKind,
154    Args: WasmTypeList,
155    Rets: WasmTypeList,
156{
157    /// Convert to function pointer.
158    fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>);
159}
160
161/// Represents a TrapEarly type.
162pub trait TrapEarly<Rets>
163where
164    Rets: WasmTypeList,
165{
166    /// The error type for this trait.
167    type Error: Send + 'static;
168    /// Get returns or error result.
169    fn report(self) -> Result<Rets, Self::Error>;
170}
171
172impl<Rets> TrapEarly<Rets> for Rets
173where
174    Rets: WasmTypeList,
175{
176    type Error = Infallible;
177    fn report(self) -> Result<Rets, Infallible> {
178        Ok(self)
179    }
180}
181
182impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
183where
184    Rets: WasmTypeList,
185    E: Send + 'static,
186{
187    type Error = E;
188    fn report(self) -> Result<Rets, E> {
189        self
190    }
191}
192
193/// Represents a type-erased function provided by either the host or the WebAssembly program.
194pub struct DynamicFunc<'a> {
195    _inner: Box<dyn Kind>,
196
197    /// The function pointer.
198    func: NonNull<vm::Func>,
199
200    /// The function environment.
201    func_env: Option<NonNull<vm::FuncEnv>>,
202
203    /// The famous `vm::Ctx`.
204    vmctx: *mut vm::Ctx,
205
206    /// The runtime signature of this function.
207    ///
208    /// When converted from a `Func`, this is determined by the static `Args` and `Rets` type parameters.
209    /// otherwise the signature is dynamically assigned during `DynamicFunc` creation, usually when creating
210    /// a polymorphic host function.
211    signature: Arc<FuncSig>,
212
213    _phantom: PhantomData<&'a ()>,
214}
215
216unsafe impl<'a> Send for DynamicFunc<'a> {}
217
218/// Represents a function that can be used by WebAssembly.
219#[derive(Clone)]
220pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
221    inner: Inner,
222
223    /// The function pointer.
224    func: NonNull<vm::Func>,
225
226    /// The function environment.
227    func_env: Option<NonNull<vm::FuncEnv>>,
228
229    /// The famous `vm::Ctx`.
230    vmctx: *mut vm::Ctx,
231
232    _phantom: PhantomData<(&'a (), Args, Rets)>,
233}
234
235unsafe impl<'a, Args, Rets> Send for Func<'a, Args, Rets, Wasm> {}
236unsafe impl<'a, Args, Rets> Send for Func<'a, Args, Rets, Host> {}
237
238impl<'a, Args, Rets, Inner> From<Func<'a, Args, Rets, Inner>> for DynamicFunc<'a>
239where
240    Args: WasmTypeList,
241    Rets: WasmTypeList,
242    Inner: Kind + 'static,
243{
244    fn from(that: Func<'a, Args, Rets, Inner>) -> DynamicFunc<'a> {
245        DynamicFunc {
246            _inner: Box::new(that.inner),
247            func: that.func,
248            func_env: that.func_env,
249            vmctx: that.vmctx,
250            signature: Arc::new(FuncSig::new(Args::types(), Rets::types())),
251            _phantom: PhantomData,
252        }
253    }
254}
255
256impl<'a, Args, Rets> Func<'a, Args, Rets, Wasm>
257where
258    Args: WasmTypeList,
259    Rets: WasmTypeList,
260{
261    // TODO: document the invariants `unsafe` requires here
262    /// Create Func from raw pointers.
263    pub unsafe fn from_raw_parts(
264        inner: Wasm,
265        func: NonNull<vm::Func>,
266        func_env: Option<NonNull<vm::FuncEnv>>,
267        vmctx: *mut vm::Ctx,
268    ) -> Func<'a, Args, Rets, Wasm> {
269        Func {
270            inner,
271            func,
272            func_env,
273            vmctx,
274            _phantom: PhantomData,
275        }
276    }
277}
278
279impl<'a, Args, Rets> Func<'a, Args, Rets, Host>
280where
281    Args: WasmTypeList,
282    Rets: WasmTypeList,
283{
284    /// Creates a new `Func`.
285    pub fn new<F, Kind>(func: F) -> Self
286    where
287        Kind: HostFunctionKind,
288        F: HostFunction<Kind, Args, Rets>,
289    {
290        let (func, func_env) = func.to_raw();
291
292        Func {
293            inner: Host(()),
294            func,
295            func_env,
296            vmctx: ptr::null_mut(),
297            _phantom: PhantomData,
298        }
299    }
300}
301
302impl<'a> DynamicFunc<'a> {
303    /// Creates a dynamic function that is polymorphic over its argument and return types.
304    #[allow(unused_variables)]
305    #[cfg(all(unix, target_arch = "x86_64"))]
306    pub fn new<F>(signature: Arc<FuncSig>, func: F) -> Self
307    where
308        F: Fn(&mut vm::Ctx, &[crate::types::Value]) -> Vec<crate::types::Value> + 'static,
309    {
310        use crate::trampoline_x64::{CallContext, TrampolineBufferBuilder};
311        use crate::types::Value;
312
313        struct PolymorphicContext {
314            arg_types: Vec<Type>,
315            func: Box<dyn Fn(&mut vm::Ctx, &[Value]) -> Vec<Value>>,
316        }
317        unsafe fn do_enter_host_polymorphic(
318            ctx: *const CallContext,
319            args: *const u64,
320        ) -> Vec<Value> {
321            let ctx = &*(ctx as *const PolymorphicContext);
322            let vmctx = &mut *(*args.offset(0) as *mut vm::Ctx);
323            let args: Vec<Value> = ctx
324                .arg_types
325                .iter()
326                .enumerate()
327                .map(|(i, t)| {
328                    let i = i + 1; // skip vmctx
329                    match *t {
330                        Type::I32 => Value::I32(*args.offset(i as _) as i32),
331                        Type::I64 => Value::I64(*args.offset(i as _) as i64),
332                        Type::F32 => Value::F32(f32::from_bits(*args.offset(i as _) as u32)),
333                        Type::F64 => Value::F64(f64::from_bits(*args.offset(i as _) as u64)),
334                        Type::V128 => {
335                            todo!("enter_host_polymorphic: 128-bit types are not supported")
336                        }
337                    }
338                })
339                .collect();
340            match panic::catch_unwind(panic::AssertUnwindSafe(|| (ctx.func)(vmctx, &args))) {
341                Ok(x) => x,
342                Err(e) => {
343                    // At this point, there is an error that needs to be trapped.
344                    drop(args); // Release the Vec which will leak otherwise.
345                    (&*vmctx.module)
346                        .runnable_module
347                        .do_early_trap(RuntimeError::User(e))
348                }
349            }
350        }
351
352        #[cfg(not(all(unix, target_arch = "x86_64")))]
353        pub fn new<F>(_signature: Arc<FuncSig>, _func: F) -> Self
354        where
355            F: Fn(&mut vm::Ctx, &[crate::types::Value]) -> Vec<crate::types::Value> + 'static,
356        {
357            unimplemented!("The DynamicFunc::new is not yet implemented in your architecture.");
358        }
359
360        unsafe extern "C" fn enter_host_polymorphic_i(
361            ctx: *const CallContext,
362            args: *const u64,
363        ) -> u64 {
364            let rets = do_enter_host_polymorphic(ctx, args);
365            if rets.len() == 0 {
366                0
367            } else if rets.len() == 1 {
368                match rets[0] {
369                    Value::I32(x) => x as u64,
370                    Value::I64(x) => x as u64,
371                    _ => panic!("enter_host_polymorphic_i: invalid return type"),
372                }
373            } else {
374                panic!(
375                    "multiple return values from polymorphic host functions is not yet supported"
376                );
377            }
378        }
379        unsafe extern "C" fn enter_host_polymorphic_f(
380            ctx: *const CallContext,
381            args: *const u64,
382        ) -> f64 {
383            let rets = do_enter_host_polymorphic(ctx, args);
384            if rets.len() == 0 {
385                0.0
386            } else if rets.len() == 1 {
387                match rets[0] {
388                    Value::F32(x) => f64::from_bits(x.to_bits() as u64),
389                    Value::F64(x) => x,
390                    _ => panic!("enter_host_polymorphic_f: invalid return type"),
391                }
392            } else {
393                panic!(
394                    "multiple return values from polymorphic host functions is not yet supported"
395                );
396            }
397        }
398
399        if cfg!(not(feature = "dynamicfunc-fat-closures")) && mem::size_of::<F>() != 0 {
400            unimplemented!("DynamicFunc with captured environment is disabled");
401        }
402
403        let mut builder = TrampolineBufferBuilder::new();
404        let ctx: Box<PolymorphicContext> = Box::new(PolymorphicContext {
405            arg_types: signature.params().to_vec(),
406            func: Box::new(func),
407        });
408        let ctx = Box::into_raw(ctx);
409
410        let mut native_param_types = vec![Type::I64]; // vm::Ctx is the first parameter.
411        native_param_types.extend_from_slice(signature.params());
412
413        match signature.returns() {
414            [x] if *x == Type::F32 || *x == Type::F64 => {
415                builder.add_callinfo_trampoline(
416                    unsafe { std::mem::transmute(enter_host_polymorphic_f as usize) },
417                    ctx as *const _,
418                    &native_param_types,
419                    signature.returns(),
420                );
421            }
422            _ => {
423                builder.add_callinfo_trampoline(
424                    enter_host_polymorphic_i,
425                    ctx as *const _,
426                    &native_param_types,
427                    signature.returns(),
428                );
429            }
430        }
431
432        let ptr = builder
433            .insert_global()
434            .expect("cannot bump-allocate global trampoline memory");
435
436        struct AutoRelease {
437            ptr: NonNull<u8>,
438            ctx: *mut PolymorphicContext,
439        }
440
441        impl Drop for AutoRelease {
442            fn drop(&mut self) {
443                unsafe {
444                    TrampolineBufferBuilder::remove_global(self.ptr);
445                    Box::from_raw(self.ctx);
446                }
447            }
448        }
449
450        impl Kind for AutoRelease {}
451
452        DynamicFunc {
453            _inner: Box::new(AutoRelease { ptr, ctx }),
454            func: ptr.cast::<vm::Func>(),
455            func_env: None,
456            vmctx: ptr::null_mut(),
457            signature,
458            _phantom: PhantomData,
459        }
460    }
461}
462
463impl<'a, Args, Rets, Inner> Func<'a, Args, Rets, Inner>
464where
465    Args: WasmTypeList,
466    Rets: WasmTypeList,
467    Inner: Kind,
468{
469    /// Returns the types of the function inputs.
470    pub fn params(&self) -> &'static [Type] {
471        Args::types()
472    }
473
474    /// Returns the types of the function outputs.
475    pub fn returns(&self) -> &'static [Type] {
476        Rets::types()
477    }
478
479    /// Get the underlying func pointer.
480    pub fn get_vm_func(&self) -> NonNull<vm::Func> {
481        self.func
482    }
483}
484
485impl WasmTypeList for Infallible {
486    type CStruct = Infallible;
487    type RetArray = [u64; 0];
488
489    fn from_ret_array(_: Self::RetArray) -> Self {
490        unreachable!()
491    }
492
493    fn empty_ret_array() -> Self::RetArray {
494        unreachable!()
495    }
496
497    fn from_c_struct(_: Self::CStruct) -> Self {
498        unreachable!()
499    }
500
501    fn into_c_struct(self) -> Self::CStruct {
502        unreachable!()
503    }
504
505    fn types() -> &'static [Type] {
506        &[]
507    }
508
509    #[allow(non_snake_case)]
510    unsafe fn call<Rets>(
511        self,
512        _: NonNull<vm::Func>,
513        _: Wasm,
514        _: *mut vm::Ctx,
515    ) -> Result<Rets, RuntimeError>
516    where
517        Rets: WasmTypeList,
518    {
519        unreachable!()
520    }
521}
522
523macro_rules! impl_traits {
524    ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => {
525        /// Struct for typed funcs.
526        #[repr($repr)]
527        pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* )
528        where
529            $( $x: WasmExternType ),*;
530
531        #[allow(unused_parens)]
532        impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
533        where
534            $( $x: WasmExternType ),*
535        {
536            type CStruct = $struct_name<$( $x ),*>;
537
538            type RetArray = [u64; count_idents!( $( $x ),* )];
539
540            fn from_ret_array(array: Self::RetArray) -> Self {
541                #[allow(non_snake_case)]
542                let [ $( $x ),* ] = array;
543
544                ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
545            }
546
547            fn empty_ret_array() -> Self::RetArray {
548                [0; count_idents!( $( $x ),* )]
549            }
550
551            fn from_c_struct(c_struct: Self::CStruct) -> Self {
552                #[allow(non_snake_case)]
553                let $struct_name ( $( $x ),* ) = c_struct;
554
555                ( $( WasmExternType::from_native($x) ),* )
556            }
557
558            #[allow(unused_parens, non_snake_case)]
559            fn into_c_struct(self) -> Self::CStruct {
560                let ( $( $x ),* ) = self;
561
562                $struct_name ( $( WasmExternType::to_native($x) ),* )
563            }
564
565            fn types() -> &'static [Type] {
566                &[$( $x::Native::TYPE ),*]
567            }
568
569            #[allow(unused_parens, non_snake_case)]
570            unsafe fn call<Rets>(
571                self,
572                f: NonNull<vm::Func>,
573                wasm: Wasm,
574                ctx: *mut vm::Ctx,
575            ) -> Result<Rets, RuntimeError>
576            where
577                Rets: WasmTypeList
578            {
579                let ( $( $x ),* ) = self;
580                let args = [ $( $x.to_native().to_binary()),* ];
581                let mut rets = Rets::empty_ret_array();
582                let mut error_out = None;
583
584                if (wasm.invoke)(
585                    wasm.trampoline,
586                    ctx,
587                    f,
588                    args.as_ptr(),
589                    rets.as_mut().as_mut_ptr(),
590                    &mut error_out,
591                    wasm.invoke_env
592                ) {
593                    Ok(Rets::from_ret_array(rets))
594                } else {
595                    Err(error_out.map_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError), Into::into))
596                }
597            }
598        }
599
600        #[allow(unused_parens)]
601        impl< $( $x, )* Rets, Trap, FN > HostFunction<ExplicitVmCtx, ( $( $x ),* ), Rets> for FN
602        where
603            $( $x: WasmExternType, )*
604            Rets: WasmTypeList,
605            Trap: TrapEarly<Rets>,
606            FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap + 'static + Send,
607        {
608            #[allow(non_snake_case)]
609            fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>) {
610                // The `wrap` function is a wrapper around the
611                // imported function. It manages the argument passed
612                // to the imported function (in this case, the
613                // `vmctx` along with the regular WebAssembly
614                // arguments), and it manages the trapping.
615                //
616                // It is also required for the LLVM backend to be
617                // able to unwind through this function.
618                extern fn wrap<$( $x, )* Rets, Trap, FN>(
619                    vmctx: &vm::Ctx $( , $x: <$x as WasmExternType>::Native )*
620                ) -> Rets::CStruct
621                where
622                    $( $x: WasmExternType, )*
623                    Rets: WasmTypeList,
624                    Trap: TrapEarly<Rets>,
625                    FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap,
626                {
627                    // Get the pointer to this `wrap` function.
628                    let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func;
629
630                    // Get the collection of imported functions.
631                    let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions };
632
633                    // Retrieve the `vm::FuncCtx`.
634                    let mut func_ctx: NonNull<vm::FuncCtx> = vm_imported_functions
635                        .iter()
636                        .find_map(|(_, imported_func)| {
637                            if imported_func.func == self_pointer {
638                                Some(imported_func.func_ctx)
639                            } else {
640                                None
641                            }
642                        })
643                        .expect("Import backing is not well-formed, cannot find `func_ctx`.");
644                    let func_ctx = unsafe { func_ctx.as_mut() };
645
646                    // Extract `vm::Ctx` from `vm::FuncCtx`. The
647                    // pointer is always non-null.
648                    let vmctx = unsafe { func_ctx.vmctx.as_mut() };
649
650                    // Extract `vm::FuncEnv` from `vm::FuncCtx`.
651                    let func_env = func_ctx.func_env;
652
653                    let func: &FN = match func_env {
654                        // The imported function is a regular
655                        // function, a closure without a captured
656                        // environment, or a closure with a captured
657                        // environment.
658                        Some(func_env) => unsafe {
659                            let func: NonNull<FN> = func_env.cast();
660
661                            &*func.as_ptr()
662                        },
663
664                        // This branch is supposed to be unreachable.
665                        None => unreachable!()
666                    };
667
668                    // Catch unwind in case of errors.
669                    let err = match panic::catch_unwind(
670                        panic::AssertUnwindSafe(
671                            || {
672                                func(vmctx $( , WasmExternType::from_native($x) )* ).report()
673                                //   ^^^^^ The imported function
674                                //         expects `vm::Ctx` as first
675                                //         argument; provide it.
676                            }
677                        )
678                    ) {
679                        Ok(Ok(returns)) => return returns.into_c_struct(),
680                        Ok(Err(err)) => {
681                            let b: Box<_> = err.into();
682                            RuntimeError::User(b as Box<dyn Any + Send>)
683                        },
684                        // TODO(blocking): this line is wrong!
685                        Err(err) => RuntimeError::User(err),
686                    };
687
688                    // At this point, there is an error that needs to
689                    // be trapped.
690                    unsafe {
691                        (&*vmctx.module).runnable_module.do_early_trap(err)
692                    }
693                }
694
695                // Extract the captured environment of the imported
696                // function if any.
697                let func_env: Option<NonNull<vm::FuncEnv>> =
698                    // `FN` is a function pointer, or a closure
699                    // _without_ a captured environment.
700                    if mem::size_of::<Self>() == 0 {
701                        NonNull::new(&self as *const _ as *mut vm::FuncEnv)
702                    }
703                    // `FN` is a closure _with_ a captured
704                    // environment.
705                    else {
706                        NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast)
707                    };
708
709                (
710                    NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(),
711                    func_env
712                )
713            }
714        }
715
716        #[allow(unused_parens)]
717        impl< $( $x, )* Rets, Trap, FN > HostFunction<ImplicitVmCtx, ( $( $x ),* ), Rets> for FN
718        where
719            $( $x: WasmExternType, )*
720            Rets: WasmTypeList,
721            Trap: TrapEarly<Rets>,
722            FN: Fn($( $x, )*) -> Trap + 'static + Send,
723        {
724            #[allow(non_snake_case)]
725            fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>) {
726                // The `wrap` function is a wrapper around the
727                // imported function. It manages the argument passed
728                // to the imported function (in this case, only the
729                // regular WebAssembly arguments), and it manages the
730                // trapping.
731                //
732                // It is also required for the LLVM backend to be
733                // able to unwind through this function.
734                extern fn wrap<$( $x, )* Rets, Trap, FN>(
735                    vmctx: &vm::Ctx $( , $x: <$x as WasmExternType>::Native )*
736                ) -> Rets::CStruct
737                where
738                    $( $x: WasmExternType, )*
739                    Rets: WasmTypeList,
740                    Trap: TrapEarly<Rets>,
741                    FN: Fn($( $x, )*) -> Trap,
742                {
743                    // Get the pointer to this `wrap` function.
744                    let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func;
745
746                    // Get the collection of imported functions.
747                    let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions };
748
749                    // Retrieve the `vm::FuncCtx`.
750                    let mut func_ctx: NonNull<vm::FuncCtx> = vm_imported_functions
751                        .iter()
752                        .find_map(|(_, imported_func)| {
753                            if imported_func.func == self_pointer {
754                                Some(imported_func.func_ctx)
755                            } else {
756                                None
757                            }
758                        })
759                        .expect("Import backing is not well-formed, cannot find `func_ctx`.");
760                    let func_ctx = unsafe { func_ctx.as_mut() };
761
762                    // Extract `vm::Ctx` from `vm::FuncCtx`. The
763                    // pointer is always non-null.
764                    let vmctx = unsafe { func_ctx.vmctx.as_mut() };
765
766                    // Extract `vm::FuncEnv` from `vm::FuncCtx`.
767                    let func_env = func_ctx.func_env;
768
769                    let func: &FN = match func_env {
770                        // The imported function is a regular
771                        // function, a closure without a captured
772                        // environment, or a closure with a captured
773                        // environment.
774                        Some(func_env) => unsafe {
775                            let func: NonNull<FN> = func_env.cast();
776
777                            &*func.as_ptr()
778                        },
779
780                        // This branch is supposed to be unreachable.
781                        None => unreachable!()
782                    };
783
784                    // Catch unwind in case of errors.
785                    let err = match panic::catch_unwind(
786                        panic::AssertUnwindSafe(
787                            || {
788                                func($( WasmExternType::from_native($x), )* ).report()
789                            }
790                        )
791                    ) {
792                        Ok(Ok(returns)) => return returns.into_c_struct(),
793                        Ok(Err(err)) => {
794                            let b: Box<_> = err.into();
795                            RuntimeError::User(b as Box<dyn Any + Send>)
796                        },
797                        // TODO(blocking): this line is wrong!
798                        Err(err) => RuntimeError::User(err),
799                    };
800
801                    // At this point, there is an error that needs to
802                    // be trapped.
803                    unsafe {
804                        (&*vmctx.module).runnable_module.do_early_trap(err)
805                    }
806                }
807
808                // Extract the captured environment of the imported
809                // function if any.
810                let func_env: Option<NonNull<vm::FuncEnv>> =
811                    // `FN` is a function pointer, or a closure
812                    // _without_ a captured environment.
813                    if mem::size_of::<Self>() == 0 {
814                        NonNull::new(&self as *const _ as *mut vm::FuncEnv)
815                    }
816                    // `FN` is a closure _with_ a captured
817                    // environment.
818                    else {
819                        NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast)
820                    };
821
822                (
823                    NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(),
824                    func_env
825                )
826            }
827        }
828
829        #[allow(unused_parens)]
830        impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm>
831        where
832            $( $x: WasmExternType, )*
833            Rets: WasmTypeList,
834        {
835            /// Call the typed func and return results.
836            #[allow(non_snake_case, clippy::too_many_arguments)]
837            pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
838                #[allow(unused_parens)]
839                unsafe {
840                    <( $( $x ),* ) as WasmTypeList>::call(
841                        ( $( $x ),* ),
842                        self.func,
843                        self.inner,
844                        self.vmctx
845                    )
846                }
847            }
848        }
849    };
850}
851
852macro_rules! count_idents {
853    ( $($idents:ident),* ) => {{
854        #[allow(dead_code, non_camel_case_types)]
855        enum Idents { $($idents,)* __CountIdentsLast }
856        const COUNT: usize = Idents::__CountIdentsLast as usize;
857        COUNT
858    }};
859}
860
861impl_traits!([C] S0,);
862impl_traits!([transparent] S1, A);
863impl_traits!([C] S2, A, B);
864impl_traits!([C] S3, A, B, C);
865impl_traits!([C] S4, A, B, C, D);
866impl_traits!([C] S5, A, B, C, D, E);
867impl_traits!([C] S6, A, B, C, D, E, F);
868impl_traits!([C] S7, A, B, C, D, E, F, G);
869impl_traits!([C] S8, A, B, C, D, E, F, G, H);
870impl_traits!([C] S9, A, B, C, D, E, F, G, H, I);
871impl_traits!([C] S10, A, B, C, D, E, F, G, H, I, J);
872impl_traits!([C] S11, A, B, C, D, E, F, G, H, I, J, K);
873impl_traits!([C] S12, A, B, C, D, E, F, G, H, I, J, K, L);
874impl_traits!([C] S13, A, B, C, D, E, F, G, H, I, J, K, L, M);
875impl_traits!([C] S14, A, B, C, D, E, F, G, H, I, J, K, L, M, N);
876impl_traits!([C] S15, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
877impl_traits!([C] S16, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
878impl_traits!([C] S17, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
879impl_traits!([C] S18, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
880impl_traits!([C] S19, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
881impl_traits!([C] S20, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
882impl_traits!([C] S21, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
883impl_traits!([C] S22, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
884impl_traits!([C] S23, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
885impl_traits!([C] S24, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
886impl_traits!([C] S25, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
887impl_traits!([C] S26, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
888
889impl<'a> IsExport for DynamicFunc<'a> {
890    fn to_export(&self) -> Export {
891        let func = unsafe { FuncPointer::new(self.func.as_ptr()) };
892        let ctx = match self.func_env {
893            func_env @ Some(_) => Context::ExternalWithEnv(self.vmctx, func_env),
894            None => Context::Internal,
895        };
896
897        Export::Function {
898            func,
899            ctx,
900            signature: self.signature.clone(),
901        }
902    }
903}
904
905impl<'a, Args, Rets, Inner> IsExport for Func<'a, Args, Rets, Inner>
906where
907    Args: WasmTypeList,
908    Rets: WasmTypeList,
909    Inner: Kind,
910{
911    fn to_export(&self) -> Export {
912        let func = unsafe { FuncPointer::new(self.func.as_ptr()) };
913        let ctx = match self.func_env {
914            func_env @ Some(_) => Context::ExternalWithEnv(self.vmctx, func_env),
915            None => Context::Internal,
916        };
917
918        Export::Function {
919            func,
920            ctx,
921            signature: Arc::new(FuncSig::new(Args::types(), Rets::types())),
922        }
923    }
924}
925
926/// Function that always fails. It can be used as a placeholder when a
927/// host function is missing for instance.
928pub(crate) fn always_trap() -> Result<(), &'static str> {
929    Err("not implemented")
930}
931
932#[cfg(test)]
933mod tests {
934    use super::*;
935
936    macro_rules! test_func_arity_n {
937        ($test_name:ident, $($x:ident),*) => {
938            #[test]
939            fn $test_name() {
940                use crate::vm;
941
942                fn with_vmctx(_: &mut vm::Ctx, $($x: i32),*) -> i32 {
943                    vec![$($x),*].iter().sum()
944                }
945
946                fn without_vmctx($($x: i32),*) -> i32 {
947                    vec![$($x),*].iter().sum()
948                }
949
950                let _ = Func::new(with_vmctx);
951                let _ = Func::new(without_vmctx);
952                let _ = Func::new(|_: &mut vm::Ctx, $($x: i32),*| -> i32 {
953                    vec![$($x),*].iter().sum()
954                });
955                let _ = Func::new(|$($x: i32),*| -> i32 {
956                    vec![$($x),*].iter().sum()
957                });
958            }
959        }
960    }
961
962    #[test]
963    fn test_func_arity_0() {
964        fn foo(_: &mut vm::Ctx) -> i32 {
965            0
966        }
967
968        fn bar() -> i32 {
969            0
970        }
971
972        let _ = Func::new(foo);
973        let _ = Func::new(bar);
974        let _ = Func::new(|_: &mut vm::Ctx| -> i32 { 0 });
975        let _ = Func::new(|| -> i32 { 0 });
976    }
977
978    test_func_arity_n!(test_func_arity_1, a);
979    test_func_arity_n!(test_func_arity_2, a, b);
980    test_func_arity_n!(test_func_arity_3, a, b, c);
981    test_func_arity_n!(test_func_arity_4, a, b, c, d);
982    test_func_arity_n!(test_func_arity_5, a, b, c, d, e);
983    test_func_arity_n!(test_func_arity_6, a, b, c, d, e, f);
984    test_func_arity_n!(test_func_arity_7, a, b, c, d, e, f, g);
985    test_func_arity_n!(test_func_arity_8, a, b, c, d, e, f, g, h);
986    test_func_arity_n!(test_func_arity_9, a, b, c, d, e, f, g, h, i);
987    test_func_arity_n!(test_func_arity_10, a, b, c, d, e, f, g, h, i, j);
988    test_func_arity_n!(test_func_arity_11, a, b, c, d, e, f, g, h, i, j, k);
989    test_func_arity_n!(test_func_arity_12, a, b, c, d, e, f, g, h, i, j, k, l);
990    test_func_arity_n!(test_func_arity_13, a, b, c, d, e, f, g, h, i, j, k, l, m);
991    test_func_arity_n!(test_func_arity_14, a, b, c, d, e, f, g, h, i, j, k, l, m, n);
992    #[rustfmt::skip] test_func_arity_n!(test_func_arity_15, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
993    #[rustfmt::skip] test_func_arity_n!(test_func_arity_16, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p);
994    #[rustfmt::skip] test_func_arity_n!(test_func_arity_17, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q);
995    #[rustfmt::skip] test_func_arity_n!(test_func_arity_18, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r);
996    #[rustfmt::skip] test_func_arity_n!(test_func_arity_19, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s);
997    #[rustfmt::skip] test_func_arity_n!(test_func_arity_20, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t);
998    #[rustfmt::skip] test_func_arity_n!(test_func_arity_21, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u);
999    #[rustfmt::skip] test_func_arity_n!(test_func_arity_22, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v);
1000    #[rustfmt::skip] test_func_arity_n!(test_func_arity_23, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w);
1001    #[rustfmt::skip] test_func_arity_n!(test_func_arity_24, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x);
1002    #[rustfmt::skip] test_func_arity_n!(test_func_arity_25, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y);
1003    #[rustfmt::skip] test_func_arity_n!(test_func_arity_26, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
1004
1005    #[test]
1006    fn test_call() {
1007        fn foo(_ctx: &mut vm::Ctx, a: i32, b: i32) -> (i32, i32) {
1008            (a, b)
1009        }
1010
1011        let _f = Func::new(foo);
1012    }
1013
1014    #[test]
1015    fn test_imports() {
1016        use crate::{func, imports};
1017
1018        fn foo(_ctx: &mut vm::Ctx, a: i32) -> i32 {
1019            a
1020        }
1021
1022        let _import_object = imports! {
1023            "env" => {
1024                "foo" => func!(foo),
1025            },
1026        };
1027    }
1028
1029    #[cfg(all(unix, target_arch = "x86_64"))]
1030    #[test]
1031    fn test_many_new_dynamics() {
1032        use crate::types::{FuncSig, Type};
1033
1034        // Check that generating a lot (1M) of polymorphic functions doesn't use up the executable buffer.
1035        for _ in 0..1000000 {
1036            let arglist = vec![Type::I32; 100];
1037            DynamicFunc::new(
1038                Arc::new(FuncSig::new(arglist, vec![Type::I32])),
1039                |_, _| unreachable!(),
1040            );
1041        }
1042    }
1043}