linera_wasmer/sys/
typed_function.rs

1use crate::{FromToNativeWasmType, RuntimeError, TypedFunction, WasmTypeList};
2use wasmer_types::RawValue;
3
4use crate::native_type::NativeWasmTypeInto;
5use crate::store::{AsStoreMut, AsStoreRef};
6use crate::sys::engine::NativeEngineExt;
7
8macro_rules! impl_native_traits {
9    (  $( $x:ident ),* ) => {
10        #[allow(unused_parens, non_snake_case)]
11        impl<$( $x , )* Rets> TypedFunction<( $( $x ),* ), Rets>
12        where
13            $( $x: FromToNativeWasmType, )*
14            Rets: WasmTypeList,
15        {
16            /// Call the typed func and return results.
17            #[allow(unused_mut)]
18            #[allow(clippy::too_many_arguments)]
19            pub fn call(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
20                let anyfunc = unsafe {
21                    *self.func.0
22                        .handle
23                        .get(store.as_store_ref().objects())
24                        .anyfunc
25                        .as_ptr()
26                        .as_ref()
27                };
28                // Ensure all parameters come from the same context.
29                if $(!FromToNativeWasmType::is_from_store(&$x, store) ||)* false {
30                    return Err(RuntimeError::new(
31                        "cross-`Store` values are not supported",
32                    ));
33                }
34                // TODO: when `const fn` related features mature more, we can declare a single array
35                // of the correct size here.
36                let mut params_list = [ $( $x.to_native().into_raw(store) ),* ];
37                let mut rets_list_array = Rets::empty_array();
38                let rets_list: &mut [RawValue] = rets_list_array.as_mut();
39                let using_rets_array;
40                let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
41                    using_rets_array = false;
42                    params_list.as_mut()
43                } else {
44                    using_rets_array = true;
45                    for (i, &arg) in params_list.iter().enumerate() {
46                        rets_list[i] = arg;
47                    }
48                    rets_list.as_mut()
49                };
50
51                let mut r;
52                loop {
53                    let storeref = store.as_store_ref();
54                    let config = storeref.engine().tunables().vmconfig();
55                    r = unsafe {
56                        wasmer_vm::wasmer_call_trampoline(
57                            store.as_store_ref().signal_handler(),
58                            config,
59                            anyfunc.vmctx,
60                            anyfunc.call_trampoline,
61                            anyfunc.func_ptr,
62                            args_rets.as_mut_ptr() as *mut u8,
63                        )
64                    };
65                    let store_mut = store.as_store_mut();
66                    if let Some(callback) = store_mut.inner.on_called.take() {
67                        match callback(store_mut) {
68                            Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
69                            Ok(wasmer_types::OnCalledAction::Finish) => { break; }
70                            Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
71                            Err(trap) => { return Err(RuntimeError::user(trap)) },
72                        }
73                    }
74                    break;
75                }
76                r?;
77
78                let num_rets = rets_list.len();
79                if !using_rets_array && num_rets > 0 {
80                    let src_pointer = params_list.as_ptr();
81                    let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
82                    unsafe {
83                        // TODO: we can probably remove this copy by doing some clever `transmute`s.
84                        // we know it's not overlapping because `using_rets_array` is false
85                        std::ptr::copy_nonoverlapping(src_pointer,
86                                                        rets_list,
87                                                        num_rets);
88                    }
89                }
90                Ok(unsafe { Rets::from_array(store, rets_list_array) })
91                // TODO: When the Host ABI and Wasm ABI are the same, we could do this instead:
92                // but we can't currently detect whether that's safe.
93                //
94                // let results = unsafe {
95                //     wasmer_vm::catch_traps_with_result(self.vmctx, || {
96                //         let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address());
97                //         // We always pass the vmctx
98                //         f( self.vmctx, $( $x, )* )
99                //     }).map_err(RuntimeError::from_trap)?
100                // };
101                // Ok(Rets::from_c_struct(results))
102            }
103
104            #[doc(hidden)]
105            #[allow(missing_docs)]
106            #[allow(unused_mut)]
107            #[allow(clippy::too_many_arguments)]
108            pub fn call_raw(&self, store: &mut impl AsStoreMut, mut params_list: Vec<RawValue> ) -> Result<Rets, RuntimeError> {
109                let anyfunc = unsafe {
110                    *self.func.0
111                        .handle
112                        .get(store.as_store_ref().objects())
113                        .anyfunc
114                        .as_ptr()
115                        .as_ref()
116                };
117                // TODO: when `const fn` related features mature more, we can declare a single array
118                // of the correct size here.
119                let mut rets_list_array = Rets::empty_array();
120                let rets_list: &mut [RawValue] = rets_list_array.as_mut();
121                let using_rets_array;
122                let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
123                    using_rets_array = false;
124                    params_list.as_mut()
125                } else {
126                    using_rets_array = true;
127                    for (i, &arg) in params_list.iter().enumerate() {
128                        rets_list[i] = arg;
129                    }
130                    rets_list.as_mut()
131                };
132
133                let mut r;
134                loop {
135                    let storeref = store.as_store_ref();
136                    let config = storeref.engine().tunables().vmconfig();
137                    r = unsafe {
138                        wasmer_vm::wasmer_call_trampoline(
139                            store.as_store_ref().signal_handler(),
140                            config,
141                            anyfunc.vmctx,
142                            anyfunc.call_trampoline,
143                            anyfunc.func_ptr,
144                            args_rets.as_mut_ptr() as *mut u8,
145                        )
146                    };
147                    let store_mut = store.as_store_mut();
148                    if let Some(callback) = store_mut.inner.on_called.take() {
149                        // TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451
150                        match callback(store_mut) {
151                            Ok(wasmer_types::OnCalledAction::InvokeAgain) => { continue; }
152                            Ok(wasmer_types::OnCalledAction::Finish) => { break; }
153                            Ok(wasmer_types::OnCalledAction::Trap(trap)) => { return Err(RuntimeError::user(trap)) },
154                            Err(trap) => { return Err(RuntimeError::user(trap)) },
155                        }
156                    }
157                    break;
158                }
159                r?;
160
161                let num_rets = rets_list.len();
162                if !using_rets_array && num_rets > 0 {
163                    let src_pointer = params_list.as_ptr();
164                    let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
165                    unsafe {
166                        // TODO: we can probably remove this copy by doing some clever `transmute`s.
167                        // we know it's not overlapping because `using_rets_array` is false
168                        std::ptr::copy_nonoverlapping(src_pointer,
169                                                        rets_list,
170                                                        num_rets);
171                    }
172                }
173                Ok(unsafe { Rets::from_array(store, rets_list_array) })
174                // TODO: When the Host ABI and Wasm ABI are the same, we could do this instead:
175                // but we can't currently detect whether that's safe.
176                //
177                // let results = unsafe {
178                //     wasmer_vm::catch_traps_with_result(self.vmctx, || {
179                //         let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address());
180                //         // We always pass the vmctx
181                //         f( self.vmctx, $( $x, )* )
182                //     }).map_err(RuntimeError::from_trap)?
183                // };
184                // Ok(Rets::from_c_struct(results))
185            }
186        }
187    };
188}
189
190impl_native_traits!();
191impl_native_traits!(A1);
192impl_native_traits!(A1, A2);
193impl_native_traits!(A1, A2, A3);
194impl_native_traits!(A1, A2, A3, A4);
195impl_native_traits!(A1, A2, A3, A4, A5);
196impl_native_traits!(A1, A2, A3, A4, A5, A6);
197impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
198impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
199impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
200impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
201impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
202impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
203impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
204impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
205impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
206impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
207impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
208impl_native_traits!(
209    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
210);
211impl_native_traits!(
212    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
213);
214impl_native_traits!(
215    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
216);