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
6#[cfg(feature = "experimental-async")]
7use crate::{
8    AsStoreAsync, AsyncFunctionEnvMut, BackendAsyncFunctionEnvMut, StoreAsync,
9    entities::function::async_host::{AsyncFunctionEnv, AsyncHostFunction},
10    sys::{
11        async_runtime::{AsyncRuntimeError, block_on_host_future, call_function_async},
12        function::env::AsyncFunctionEnvMutStore,
13    },
14};
15use crate::{
16    BackendFunction, FunctionEnv, FunctionEnvMut, FunctionType, HostFunction, RuntimeError,
17    StoreContext, StoreInner, Value, WithEnv, WithoutEnv,
18    backend::sys::{engine::NativeEngineExt, vm::VMFunctionCallback},
19    entities::store::{AsStoreMut, AsStoreRef, StoreMut},
20    utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList},
21    vm::{VMExtern, VMExternFunction},
22};
23use std::panic::{self, AssertUnwindSafe};
24use std::{
25    cell::UnsafeCell, cmp::max, error::Error, ffi::c_void, future::Future, marker::PhantomData,
26    pin::Pin, sync::Arc,
27};
28use wasmer_types::{NativeWasmType, RawValue, StoreId};
29#[cfg(feature = "experimental-host-interrupt")]
30use wasmer_vm::interrupt_registry;
31use wasmer_vm::{
32    MaybeInstanceOwned, StoreHandle, Trap, TrapCode, VMCallerCheckedAnyfunc, VMContext,
33    VMDynamicFunctionContext, VMExceptionRef, VMFuncRef, VMFunction, VMFunctionBody,
34    VMFunctionContext, VMFunctionKind, VMTrampoline, on_host_stack, raise_lib_trap,
35    raise_user_trap, resume_panic, wasmer_call_trampoline,
36};
37
38#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
39#[derive(Debug, Clone, PartialEq, Eq)]
40/// A WebAssembly `function` instance, in the `sys` runtime.
41pub struct Function {
42    pub(crate) handle: StoreHandle<VMFunction>,
43}
44
45impl From<StoreHandle<VMFunction>> for Function {
46    fn from(handle: StoreHandle<VMFunction>) -> Self {
47        Self { handle }
48    }
49}
50
51impl Function {
52    pub(crate) fn new_with_env<FT, F, T: Send + 'static>(
53        store: &mut impl AsStoreMut,
54        env: &FunctionEnv<T>,
55        ty: FT,
56        func: F,
57    ) -> Self
58    where
59        FT: Into<FunctionType>,
60        F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
61            + 'static
62            + Send
63            + Sync,
64    {
65        let function_type = ty.into();
66        let func_ty = function_type.clone();
67        let func_env = env.clone().into_sys();
68        let store_id = store.objects_mut().id();
69        let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome {
70            unsafe {
71                let mut store_wrapper = unsafe { StoreContext::get_current(store_id) };
72                let mut store_mut = store_wrapper.as_mut();
73                let mut args = Vec::with_capacity(func_ty.params().len());
74
75                for (i, ty) in func_ty.params().iter().enumerate() {
76                    args.push(Value::from_raw(
77                        &mut store_mut,
78                        *ty,
79                        values_vec.add(i).read_unaligned(),
80                    ));
81                }
82                let env = env::FunctionEnvMut {
83                    store_mut,
84                    func_env: func_env.clone(),
85                }
86                .into();
87                let sig = func_ty.clone();
88                let result = func(env, &args);
89                HostCallOutcome::Ready {
90                    func_ty: sig,
91                    result,
92                }
93            }
94        };
95        let mut host_data = Box::new(VMDynamicFunctionContext {
96            address: std::ptr::null(),
97            ctx: DynamicFunction {
98                func: wrapper,
99                store_id,
100            },
101        });
102        host_data.address = host_data.ctx.func_body_ptr();
103
104        // We don't yet have the address with the Wasm ABI signature.
105        // The engine linker will replace the address with one pointing to a
106        // generated dynamic trampoline.
107        let func_ptr = std::ptr::null() as VMFunctionCallback;
108        let type_signature_hash = store
109            .as_store_ref()
110            .engine()
111            .as_sys()
112            .register_signature(&function_type);
113        let vmctx = VMFunctionContext {
114            host_env: host_data.as_ref() as *const _ as *mut c_void,
115        };
116        let call_trampoline = host_data.ctx.call_trampoline_address();
117        let anyfunc = VMCallerCheckedAnyfunc {
118            func_ptr,
119            type_signature_hash,
120            vmctx,
121            call_trampoline,
122        };
123
124        let vm_function = VMFunction {
125            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
126            kind: VMFunctionKind::Dynamic,
127            signature: function_type,
128            host_data,
129        };
130        Self {
131            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
132        }
133    }
134
135    #[cfg(feature = "experimental-async")]
136    pub(crate) fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
137    where
138        FT: Into<FunctionType>,
139        F: Fn(&[Value]) -> Fut + 'static,
140        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
141    {
142        let env = FunctionEnv::new(store, ());
143        let wrapped = move |_env: AsyncFunctionEnvMut<()>, values: &[Value]| func(values);
144        Self::new_with_env_async(store, &env, ty, wrapped)
145    }
146
147    #[cfg(feature = "experimental-async")]
148    pub(crate) fn new_with_env_async<FT, F, Fut, T: 'static>(
149        store: &mut impl AsStoreMut,
150        env: &FunctionEnv<T>,
151        ty: FT,
152        func: F,
153    ) -> Self
154    where
155        FT: Into<FunctionType>,
156        F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
157        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
158    {
159        let function_type = ty.into();
160        let func_ty = function_type.clone();
161        let func_env = env.clone().into_sys();
162        let store_id = store.objects_mut().id();
163        let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome {
164            unsafe {
165                let mut context = StoreContext::try_get_current_async(store_id);
166                let mut store_mut = match &mut context {
167                    crate::GetStoreAsyncGuardResult::Ok(wrapper) => StoreMut {
168                        inner: wrapper.guard.as_mut().unwrap(),
169                    },
170                    crate::GetStoreAsyncGuardResult::NotAsync(ptr) => ptr.as_mut(),
171                    crate::GetStoreAsyncGuardResult::NotInstalled => {
172                        panic!("No store context installed on this thread")
173                    }
174                };
175                let id = store_mut.as_store_ref().objects().id();
176                let mut args = Vec::with_capacity(func_ty.params().len());
177
178                for (i, ty) in func_ty.params().iter().enumerate() {
179                    args.push(Value::from_raw(
180                        &mut store_mut,
181                        *ty,
182                        values_vec.add(i).read_unaligned(),
183                    ));
184                }
185                let store_async = match context {
186                    crate::GetStoreAsyncGuardResult::Ok(wrapper) => {
187                        AsyncFunctionEnvMutStore::Async(StoreAsync {
188                            id,
189                            inner: crate::LocalRwLockWriteGuard::lock_handle(
190                                wrapper.guard.as_mut().unwrap(),
191                            ),
192                        })
193                    }
194                    crate::GetStoreAsyncGuardResult::NotAsync(ptr) => {
195                        AsyncFunctionEnvMutStore::Sync(ptr)
196                    }
197                    crate::GetStoreAsyncGuardResult::NotInstalled => unreachable!(),
198                };
199                let env = crate::AsyncFunctionEnvMut(crate::BackendAsyncFunctionEnvMut::Sys(
200                    env::AsyncFunctionEnvMut {
201                        store: store_async,
202                        func_env: func_env.clone(),
203                    },
204                ));
205                let sig = func_ty.clone();
206                let future = func(env, &args);
207                HostCallOutcome::Future {
208                    func_ty: sig,
209                    future: Box::pin(future),
210                }
211            }
212        };
213        let mut host_data = Box::new(VMDynamicFunctionContext {
214            address: std::ptr::null(),
215            ctx: DynamicFunction {
216                func: wrapper,
217                store_id,
218            },
219        });
220        host_data.address = host_data.ctx.func_body_ptr();
221
222        let func_ptr = std::ptr::null() as VMFunctionCallback;
223        let type_signature_hash = store
224            .as_store_ref()
225            .engine()
226            .as_sys()
227            .register_signature(&function_type);
228        let vmctx = VMFunctionContext {
229            host_env: host_data.as_ref() as *const _ as *mut c_void,
230        };
231        let call_trampoline = host_data.ctx.call_trampoline_address();
232        let anyfunc = VMCallerCheckedAnyfunc {
233            func_ptr,
234            type_signature_hash,
235            vmctx,
236            call_trampoline,
237        };
238
239        let vm_function = VMFunction {
240            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
241            kind: VMFunctionKind::Dynamic,
242            signature: function_type,
243            host_data,
244        };
245        Self {
246            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
247        }
248    }
249
250    /// Creates a new host `Function` from a native function.
251    pub(crate) fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
252    where
253        F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
254        Args: WasmTypeList,
255        Rets: WasmTypeList,
256    {
257        let env = FunctionEnv::new(store, ());
258        let func_ptr = func.function_callback_sys().unwrap_sys();
259        let host_data = Box::new(StaticFunction {
260            store_id: store.objects_mut().id(),
261            env,
262            func,
263        });
264        let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
265
266        let type_signature_hash = store
267            .as_store_ref()
268            .engine()
269            .as_sys()
270            .register_signature(&function_type);
271        let vmctx = VMFunctionContext {
272            host_env: host_data.as_ref() as *const _ as *mut c_void,
273        };
274        let call_trampoline =
275            <F as HostFunction<(), Args, Rets, WithoutEnv>>::call_trampoline_address().unwrap_sys();
276        let anyfunc = VMCallerCheckedAnyfunc {
277            func_ptr,
278            type_signature_hash,
279            vmctx,
280            call_trampoline,
281        };
282
283        let vm_function = VMFunction {
284            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
285            kind: VMFunctionKind::Static,
286            signature: function_type,
287            host_data,
288        };
289        Self {
290            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
291        }
292    }
293
294    #[cfg(feature = "experimental-async")]
295    pub(crate) fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
296    where
297        Args: WasmTypeList + 'static,
298        Rets: WasmTypeList + 'static,
299        F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
300    {
301        let env = FunctionEnv::new(store, ());
302        let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
303        let args_sig = Arc::new(signature.clone());
304        let results_sig = Arc::new(signature.clone());
305        let func = Arc::new(func);
306        Self::new_with_env_async(
307            store,
308            &env,
309            signature,
310            move |mut env_mut,
311                  values|
312                  -> Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>> {
313                let sys_env = match env_mut.0 {
314                    BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env,
315                    _ => panic!("Not a sys backend"),
316                };
317                let mut store_mut_wrapper =
318                    unsafe { StoreContext::get_current(sys_env.store_id()) };
319                let mut store_mut = store_mut_wrapper.as_mut();
320                let args_sig = args_sig.clone();
321                let results_sig = results_sig.clone();
322                let func = func.clone();
323                let args =
324                    match typed_args_from_values::<Args>(&mut store_mut, args_sig.as_ref(), values)
325                    {
326                        Ok(args) => args,
327                        Err(err) => return Box::pin(async { Err(err) }),
328                    };
329                drop(store_mut_wrapper);
330                let future = func.as_ref().call_async(AsyncFunctionEnv::new(), args);
331                Box::pin(async move {
332                    let typed_result = future.await?;
333                    let mut store_mut = env_mut.write().await;
334                    typed_results_to_values::<Rets>(
335                        &mut store_mut.as_store_mut(),
336                        results_sig.as_ref(),
337                        typed_result,
338                    )
339                })
340            },
341        )
342    }
343
344    #[cfg(feature = "experimental-async")]
345    pub(crate) fn new_typed_with_env_async<T, F, Args, Rets>(
346        store: &mut impl AsStoreMut,
347        env: &FunctionEnv<T>,
348        func: F,
349    ) -> Self
350    where
351        T: 'static,
352        F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
353        Args: WasmTypeList + 'static,
354        Rets: WasmTypeList + 'static,
355    {
356        let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
357        let args_sig = Arc::new(signature.clone());
358        let results_sig = Arc::new(signature.clone());
359        let func = Arc::new(func);
360        Self::new_with_env_async(
361            store,
362            env,
363            signature,
364            move |mut env_mut,
365                  values|
366                  -> Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>> {
367                let sys_env = match env_mut.0 {
368                    BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env,
369                    _ => panic!("Not a sys backend"),
370                };
371                let mut store_mut_wrapper =
372                    unsafe { StoreContext::get_current(sys_env.store_id()) };
373                let mut store_mut = store_mut_wrapper.as_mut();
374                let args_sig = args_sig.clone();
375                let results_sig = results_sig.clone();
376                let func = func.clone();
377                let args =
378                    match typed_args_from_values::<Args>(&mut store_mut, args_sig.as_ref(), values)
379                    {
380                        Ok(args) => args,
381                        Err(err) => return Box::pin(async { Err(err) }),
382                    };
383                drop(store_mut_wrapper);
384                let env_mut_clone = env_mut.as_mut();
385                let future = func
386                    .as_ref()
387                    .call_async(AsyncFunctionEnv::with_env(env_mut), args);
388                Box::pin(async move {
389                    let typed_result = future.await?;
390                    let mut store_mut = env_mut_clone.write().await;
391                    typed_results_to_values::<Rets>(
392                        &mut store_mut.as_store_mut(),
393                        results_sig.as_ref(),
394                        typed_result,
395                    )
396                })
397            },
398        )
399    }
400
401    pub(crate) fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
402        store: &mut impl AsStoreMut,
403        env: &FunctionEnv<T>,
404        func: F,
405    ) -> Self
406    where
407        F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
408        Args: WasmTypeList,
409        Rets: WasmTypeList,
410    {
411        let func_ptr = func.function_callback_sys().unwrap_sys();
412        let host_data = Box::new(StaticFunction {
413            store_id: store.objects_mut().id(),
414            env: env.as_sys().clone().into(),
415            func,
416        });
417        let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
418
419        let type_signature_hash = store
420            .as_store_ref()
421            .engine()
422            .as_sys()
423            .register_signature(&function_type);
424        let vmctx = VMFunctionContext {
425            host_env: host_data.as_ref() as *const _ as *mut c_void,
426        };
427        let call_trampoline =
428            <F as HostFunction<T, Args, Rets, WithEnv>>::call_trampoline_address().unwrap_sys();
429        let anyfunc = VMCallerCheckedAnyfunc {
430            func_ptr,
431            type_signature_hash,
432            vmctx,
433            call_trampoline,
434        };
435
436        let vm_function = VMFunction {
437            anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
438            kind: VMFunctionKind::Static,
439            signature: function_type,
440            host_data,
441        };
442        Self {
443            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
444        }
445    }
446
447    pub(crate) fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
448        self.handle
449            .get(store.as_store_ref().objects().as_sys())
450            .signature
451            .clone()
452    }
453
454    fn call_wasm(
455        &self,
456        store: &mut impl AsStoreMut,
457        trampoline: VMTrampoline,
458        params: &[Value],
459        results: &mut [Value],
460    ) -> Result<(), RuntimeError> {
461        let format_types_for_error_message = |items: &[Value]| {
462            items
463                .iter()
464                .map(|param| param.ty().to_string())
465                .collect::<Vec<String>>()
466                .join(", ")
467        };
468        // TODO: Avoid cloning the signature here, it's expensive.
469        let signature = self.ty(store);
470        if signature.params().len() != params.len() {
471            return Err(RuntimeError::new(format!(
472                "Parameters of type [{}] did not match signature {}",
473                format_types_for_error_message(params),
474                signature
475            )));
476        }
477        if signature.results().len() != results.len() {
478            return Err(RuntimeError::new(format!(
479                "Results of type [{}] did not match signature {}",
480                format_types_for_error_message(results),
481                signature,
482            )));
483        }
484
485        let mut values_vec = vec![RawValue { i32: 0 }; max(params.len(), results.len())];
486
487        // Store the argument values into `values_vec`.
488        let param_tys = signature.params().iter();
489        for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
490            if arg.ty() != *ty {
491                let param_types = format_types_for_error_message(params);
492                return Err(RuntimeError::new(format!(
493                    "Parameters of type [{param_types}] did not match signature {signature}",
494                )));
495            }
496            if !arg.is_from_store(store) {
497                return Err(RuntimeError::new("cross-`Store` values are not supported"));
498            }
499            *slot = arg.as_raw(store);
500        }
501
502        // Invoke the call
503        self.call_wasm_raw(store, trampoline, values_vec, results)?;
504        Ok(())
505    }
506
507    fn call_wasm_raw(
508        &self,
509        store: &mut impl AsStoreMut,
510        trampoline: VMTrampoline,
511        mut params: Vec<RawValue>,
512        results: &mut [Value],
513    ) -> Result<(), RuntimeError> {
514        // Call the trampoline.
515        let result = {
516            let store_id = store.objects_mut().id();
517
518            #[cfg(feature = "experimental-host-interrupt")]
519            let interrupt_guard = match interrupt_registry::install(store_id) {
520                Ok(x) => x,
521                Err(interrupt_registry::InstallError::AlreadyInterrupted) => {
522                    return Err(Trap::lib(TrapCode::HostInterrupt).into());
523                }
524            };
525
526            // Safety: the store context is uninstalled before we return, and the
527            // store mut is valid for the duration of the call.
528            let store_install_guard =
529                unsafe { StoreContext::ensure_installed(store.as_store_mut().inner as *mut _) };
530
531            let mut r;
532            // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451
533            loop {
534                let storeref = store.as_store_ref();
535                let vm_function = self.handle.get(storeref.objects().as_sys());
536                let config = storeref.engine().tunables().vmconfig();
537                let signal_handler = storeref.signal_handler();
538                r = unsafe {
539                    // Safety: This is the intended use-case for StoreContext::pause, as
540                    // documented in the function's doc comments.
541                    let pause_guard = StoreContext::pause(store_id);
542                    wasmer_call_trampoline(
543                        signal_handler,
544                        config,
545                        vm_function.anyfunc.as_ptr().as_ref().vmctx,
546                        trampoline,
547                        vm_function.anyfunc.as_ptr().as_ref().func_ptr,
548                        params.as_mut_ptr() as *mut u8,
549                    )
550                };
551                let store_mut = store.as_store_mut();
552                if let Some(callback) = store_mut.inner.on_called.take() {
553                    match callback(store_mut) {
554                        Ok(wasmer_types::OnCalledAction::InvokeAgain) => {
555                            continue;
556                        }
557                        Ok(wasmer_types::OnCalledAction::Finish) => {
558                            break;
559                        }
560                        Ok(wasmer_types::OnCalledAction::Trap(trap)) => {
561                            return Err(RuntimeError::user(trap));
562                        }
563                        Err(trap) => return Err(RuntimeError::user(trap)),
564                    }
565                }
566                break;
567            }
568
569            drop(store_install_guard);
570            #[cfg(feature = "experimental-host-interrupt")]
571            drop(interrupt_guard);
572
573            r
574        };
575
576        if let Err(error) = result {
577            return Err(error.into());
578        }
579
580        // Load the return values out of `values_vec`.
581        let signature = self.ty(store);
582        for (index, &value_type) in signature.results().iter().enumerate() {
583            unsafe {
584                results[index] = Value::from_raw(store, value_type, params[index]);
585            }
586        }
587
588        Ok(())
589    }
590
591    pub(crate) fn result_arity(&self, store: &impl AsStoreRef) -> usize {
592        self.ty(store).results().len()
593    }
594
595    pub(crate) fn call(
596        &self,
597        store: &mut impl AsStoreMut,
598        params: &[Value],
599    ) -> Result<Box<[Value]>, RuntimeError> {
600        let trampoline = unsafe {
601            self.handle
602                .get(store.objects_mut().as_sys())
603                .anyfunc
604                .as_ptr()
605                .as_ref()
606                .call_trampoline
607        };
608        let mut results = vec![Value::null(); self.result_arity(store)];
609        self.call_wasm(store, trampoline, params, &mut results)?;
610        Ok(results.into_boxed_slice())
611    }
612
613    #[cfg(feature = "experimental-async")]
614    #[allow(clippy::type_complexity)]
615    pub(crate) fn call_async(
616        &self,
617        store: &impl AsStoreAsync,
618        params: Vec<Value>,
619    ) -> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static>> {
620        let function = self.clone();
621        let store = store.store();
622        Box::pin(call_function_async(function, store, params))
623    }
624
625    #[doc(hidden)]
626    #[allow(missing_docs)]
627    pub(crate) fn call_raw(
628        &self,
629        store: &mut impl AsStoreMut,
630        params: Vec<RawValue>,
631    ) -> Result<Box<[Value]>, RuntimeError> {
632        let trampoline = unsafe {
633            self.handle
634                .get(store.objects_mut().as_sys())
635                .anyfunc
636                .as_ptr()
637                .as_ref()
638                .call_trampoline
639        };
640        let mut results = vec![Value::null(); self.result_arity(store)];
641        self.call_wasm_raw(store, trampoline, params, &mut results)?;
642        Ok(results.into_boxed_slice())
643    }
644
645    pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
646        let vm_function = self.handle.get(store.as_store_ref().objects().as_sys());
647        if vm_function.kind == VMFunctionKind::Dynamic {
648            panic!("dynamic functions cannot be used in tables or as funcrefs");
649        }
650        VMFuncRef(vm_function.anyfunc.as_ptr())
651    }
652
653    pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
654        let signature = {
655            let anyfunc = unsafe { funcref.0.as_ref() };
656            store
657                .as_store_mut()
658                .engine()
659                .as_sys()
660                .lookup_signature(anyfunc.type_signature_hash)
661                .expect("Signature not found in store")
662        };
663        let vm_function = VMFunction {
664            anyfunc: MaybeInstanceOwned::Instance(funcref.0),
665            signature,
666            // All functions in tables are already Static (as dynamic functions
667            // are converted to use the trampolines with static signatures).
668            kind: wasmer_vm::VMFunctionKind::Static,
669            host_data: Box::new(()),
670        };
671        Self {
672            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
673        }
674    }
675
676    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
677        Self {
678            handle: unsafe {
679                StoreHandle::from_internal(store.objects_mut().id(), vm_extern.unwrap_sys())
680            },
681        }
682    }
683
684    /// Checks whether this `Function` can be used with the given store.
685    pub(crate) fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
686        self.handle.store_id() == store.as_store_ref().objects().id()
687    }
688
689    pub(crate) fn to_vm_extern(&self) -> VMExtern {
690        VMExtern::Sys(wasmer_vm::VMExtern::Function(self.handle.internal_handle()))
691    }
692}
693
694// We want to keep as much logic as possible on the host stack,
695// since the WASM stack may be out of memory. In that scenario,
696// throwing exceptions won't work since libunwind requires
697// considerable stack space to do its magic, but everything else
698// should work.
699enum InvocationResult<T, E> {
700    Success(T),
701    Exception(crate::Exception),
702    Trap(Box<E>),
703    YieldOutsideAsyncContext,
704}
705
706fn to_invocation_result<T, E>(result: Result<T, E>) -> InvocationResult<T, E>
707where
708    E: Error + 'static,
709{
710    match result {
711        Ok(value) => InvocationResult::Success(value),
712        Err(trap) => {
713            let dyn_err_ref = &trap as &dyn Error;
714            if let Some(runtime_error) = dyn_err_ref.downcast_ref::<RuntimeError>()
715                && let Some(exception) = runtime_error.to_exception()
716            {
717                return InvocationResult::Exception(exception);
718            }
719            InvocationResult::Trap(Box::new(trap))
720        }
721    }
722}
723
724fn write_dynamic_results(
725    store_id: StoreId,
726    func_ty: &FunctionType,
727    returns: Vec<Value>,
728    values_vec: *mut RawValue,
729) -> Result<(), RuntimeError> {
730    let mut store_wrapper = unsafe { StoreContext::get_current(store_id) };
731    let mut store = store_wrapper.as_mut();
732    let return_types = returns.iter().map(|ret| ret.ty());
733    if return_types.ne(func_ty.results().iter().copied()) {
734        return Err(RuntimeError::new(format!(
735            "Dynamic function returned wrong signature. Expected {:?} but got {:?}",
736            func_ty.results(),
737            returns.iter().map(|ret| ret.ty())
738        )));
739    }
740    for (i, ret) in returns.iter().enumerate() {
741        unsafe {
742            values_vec.add(i).write_unaligned(ret.as_raw(&store));
743        }
744    }
745    Ok(())
746}
747
748fn finalize_dynamic_call(
749    store_id: StoreId,
750    func_ty: FunctionType,
751    values_vec: *mut RawValue,
752    result: Result<Vec<Value>, RuntimeError>,
753) -> Result<(), RuntimeError> {
754    match result {
755        Ok(values) => write_dynamic_results(store_id, &func_ty, values, values_vec),
756        Err(err) => Err(err),
757    }
758}
759
760fn typed_args_from_values<Args>(
761    store: &mut StoreMut,
762    func_ty: &FunctionType,
763    values: &[Value],
764) -> Result<Args, RuntimeError>
765where
766    Args: WasmTypeList,
767{
768    if values.len() != func_ty.params().len() {
769        return Err(RuntimeError::new(
770            "typed host function received wrong number of parameters",
771        ));
772    }
773    let mut raw_array = Args::empty_array();
774    for ((slot, value), expected_ty) in raw_array
775        .as_mut()
776        .iter_mut()
777        .zip(values.iter())
778        .zip(func_ty.params().iter())
779    {
780        debug_assert_eq!(
781            value.ty(),
782            *expected_ty,
783            "wasm should only call host functions with matching signatures"
784        );
785        *slot = value.as_raw(store);
786    }
787    unsafe { Ok(Args::from_array(store, raw_array)) }
788}
789
790fn typed_results_to_values<Rets>(
791    store: &mut StoreMut,
792    func_ty: &FunctionType,
793    rets: Rets,
794) -> Result<Vec<Value>, RuntimeError>
795where
796    Rets: WasmTypeList,
797{
798    let mut raw_array = unsafe { rets.into_array(store) };
799    let mut values = Vec::with_capacity(func_ty.results().len());
800    for (raw, ty) in raw_array.as_mut().iter().zip(func_ty.results().iter()) {
801        unsafe {
802            values.push(Value::from_raw(store, *ty, *raw));
803        }
804    }
805    Ok(values)
806}
807
808pub(crate) enum HostCallOutcome {
809    Ready {
810        func_ty: FunctionType,
811        result: Result<Vec<Value>, RuntimeError>,
812    },
813    #[cfg(feature = "experimental-async")]
814    Future {
815        func_ty: FunctionType,
816        future: Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>>,
817    },
818}
819
820/// Host state for a dynamic function.
821pub(crate) struct DynamicFunction<F> {
822    func: F,
823    store_id: StoreId,
824}
825
826impl<F> DynamicFunction<F>
827where
828    F: Fn(*mut RawValue) -> HostCallOutcome + 'static,
829{
830    // This function wraps our func, to make it compatible with the
831    // reverse trampoline signature
832    unsafe extern "C-unwind" fn func_wrapper(
833        this: &mut VMDynamicFunctionContext<Self>,
834        values_vec: *mut RawValue,
835    ) {
836        let result = on_host_stack(|| {
837            panic::catch_unwind(AssertUnwindSafe(|| match (this.ctx.func)(values_vec) {
838                HostCallOutcome::Ready { func_ty, result } => to_invocation_result(
839                    finalize_dynamic_call(this.ctx.store_id, func_ty, values_vec, result),
840                ),
841                #[cfg(feature = "experimental-async")]
842                HostCallOutcome::Future { func_ty, future } => {
843                    let awaited = block_on_host_future(future);
844                    let result = match awaited {
845                        Ok(value) => Ok(value),
846                        Err(AsyncRuntimeError::RuntimeError(e)) => Err(e),
847                        Err(AsyncRuntimeError::YieldOutsideAsyncContext) => {
848                            return InvocationResult::YieldOutsideAsyncContext;
849                        }
850                    };
851                    to_invocation_result(finalize_dynamic_call(
852                        this.ctx.store_id,
853                        func_ty,
854                        values_vec,
855                        result,
856                    ))
857                }
858            }))
859        });
860
861        // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
862        // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
863        // See: https://github.com/wasmerio/wasmer/pull/5700
864        match result {
865            Ok(InvocationResult::Success(())) => unsafe {
866                // Note: can't acquire a proper ref-counted context ref here, since we can switch
867                // away from the WASM stack at any time.
868                // Safety: The pointer is only used for the duration of the call to
869                // `get_current_transient`.
870                let mut store_wrapper = StoreContext::get_current_transient(this.ctx.store_id);
871                let mut store = store_wrapper.as_mut().unwrap();
872                #[cfg(feature = "experimental-host-interrupt")]
873                if interrupt_registry::is_interrupted(store.objects.id()) {
874                    raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
875                }
876            },
877            Ok(InvocationResult::Exception(exception)) => unsafe {
878                // Note: can't acquire a proper ref-counted context ref here, since we can switch
879                // away from the WASM stack at any time.
880                // Safety: The pointer is only used for the duration of the call to `throw` and
881                // `is_interrupted`.
882                let mut store_wrapper = StoreContext::get_current_transient(this.ctx.store_id);
883                let mut store = store_wrapper.as_mut().unwrap();
884                #[cfg(feature = "experimental-host-interrupt")]
885                if interrupt_registry::is_interrupted(store.objects.id()) {
886                    raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
887                }
888                wasmer_vm::libcalls::throw(
889                    store.objects.as_sys(),
890                    exception.vm_exceptionref().unwrap_sys_ref().to_u32_exnref(),
891                )
892            },
893            Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
894            Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
895                raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
896            },
897            Err(panic) => unsafe { resume_panic(panic) },
898        }
899    }
900
901    fn func_body_ptr(&self) -> VMFunctionCallback {
902        Self::func_wrapper as VMFunctionCallback
903    }
904
905    fn call_trampoline_address(&self) -> VMTrampoline {
906        Self::call_trampoline
907    }
908
909    unsafe extern "C" fn call_trampoline(
910        vmctx: *mut VMContext,
911        _body: VMFunctionCallback,
912        args: *mut RawValue,
913    ) {
914        // The VMFunctionCallback is null here: it is only filled in later
915        // by the engine linker.
916        unsafe {
917            let dynamic_function = &mut *(vmctx as *mut VMDynamicFunctionContext<Self>);
918            Self::func_wrapper(dynamic_function, args);
919        }
920    }
921}
922
923/// Represents a low-level Wasm static host function. See
924/// [`crate::Function::new_typed`] and
925/// [`crate::Function::new_typed_with_env`] to learn more.
926pub(crate) struct StaticFunction<F, T> {
927    pub(crate) store_id: StoreId,
928    pub(crate) env: FunctionEnv<T>,
929    pub(crate) func: F,
930}
931
932impl crate::Function {
933    /// Consume [`self`] into [`crate::backend::sys::function::Function`].
934    pub fn into_sys(self) -> crate::backend::sys::function::Function {
935        match self.0 {
936            BackendFunction::Sys(s) => s,
937            _ => panic!("Not a `sys` function!"),
938        }
939    }
940
941    /// Convert a reference to [`self`] into a reference to [`crate::backend::sys::function::Function`].
942    pub fn as_sys(&self) -> &crate::backend::sys::function::Function {
943        match self.0 {
944            BackendFunction::Sys(ref s) => s,
945            _ => panic!("Not a `sys` function!"),
946        }
947    }
948
949    /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::function::Function`].
950    pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::function::Function {
951        match self.0 {
952            BackendFunction::Sys(ref mut s) => s,
953            _ => panic!("Not a `sys` function!"),
954        }
955    }
956}
957
958macro_rules! impl_host_function {
959    ([$c_struct_representation:ident] $c_struct_name:ident, $( $x:ident ),* ) => {
960        paste::paste! {
961        #[allow(non_snake_case)]
962        pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower _no_env>]
963            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, Func: Fn($( $x , )*) -> RetsAsResult + 'static>
964            (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
965            /// This is a function that wraps the real host
966            /// function. Its address will be used inside the
967            /// runtime.
968            unsafe extern "C-unwind" fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, ()>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
969            where
970                $( $x: FromToNativeWasmType, )*
971                Rets: WasmTypeList,
972                RetsAsResult: IntoResult<Rets>,
973                Func: Fn($( $x , )*) -> RetsAsResult + 'static,
974            {
975                let result = on_host_stack(|| {
976                    panic::catch_unwind(AssertUnwindSafe(|| {
977                        let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) };
978                        let mut store = store_wrapper.as_mut();
979                        $(
980                            let $x = unsafe {
981                                FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
982                            };
983                        )*
984                        to_invocation_result((env.func)($($x),* ).into_result())
985                    }))
986                });
987
988                // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
989                // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
990                // See: https://github.com/wasmerio/wasmer/pull/5700
991                match result {
992                    Ok(InvocationResult::Success(result)) => unsafe {
993                        // Note: can't acquire a proper ref-counted context ref here, since we can switch
994                        // away from the WASM stack at any time.
995                        // Safety: The pointer is only used for the duration of the call to
996                        // `into_c_struct` and `get_current_transient`.
997                        let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
998                        let mut store = store_wrapper.as_mut().unwrap();
999                        #[cfg(feature = "experimental-host-interrupt")]
1000                        if interrupt_registry::is_interrupted(store.objects.id()) {
1001                            raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
1002                        }
1003                        return result.into_c_struct(store);
1004                    },
1005                    Ok(InvocationResult::Exception(exception)) => unsafe {
1006                        // Note: can't acquire a proper ref-counted context ref here, since we can switch
1007                        // away from the WASM stack at any time.
1008                        // Safety: The pointer is only used for the duration of the call to `throw` and
1009                        // `is_interrupted`.
1010                        let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
1011                        let mut store = store_wrapper.as_mut().unwrap();
1012                        #[cfg(feature = "experimental-host-interrupt")]
1013                        if interrupt_registry::is_interrupted(store.objects.id()) {
1014                            raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
1015                        }
1016                        wasmer_vm::libcalls::throw(
1017                            store.objects.as_sys(),
1018                            exception.vm_exceptionref().unwrap_sys_ref().to_u32_exnref(),
1019                        )
1020                    }
1021                    Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
1022                    Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
1023                        raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
1024                    },
1025                    Err(panic) => unsafe { resume_panic(panic) },
1026                }
1027            }
1028
1029            func_wrapper::< $( $x, )* Rets, RetsAsResult, Func > as _
1030
1031        }
1032
1033        #[allow(non_snake_case)]
1034        pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower _no_env>]
1035            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
1036            () -> crate::backend::sys::vm::VMTrampoline {
1037
1038            unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
1039            (
1040                vmctx: *mut crate::backend::sys::vm::VMContext,
1041                body: crate::backend::sys::vm::VMFunctionCallback,
1042                args: *mut RawValue,
1043            ) {
1044                let mut _n = 0;
1045
1046                unsafe {
1047                    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);
1048                    $(
1049                        let $x = *args.add(_n).cast();
1050                        _n += 1;
1051                    )*
1052                    let results = body(vmctx, $( $x ),*);
1053                    Rets::write_c_struct_to_ptr(results, args);
1054                }
1055            }
1056
1057            call_trampoline::<$( $x, )* Rets> as _
1058
1059        }
1060
1061        #[allow(non_snake_case)]
1062        pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower>]
1063            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, T: Send + 'static,  Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static>
1064            (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
1065            /// This is a function that wraps the real host
1066            /// function. Its address will be used inside the
1067            /// runtime.
1068            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
1069                where
1070                $( $x: FromToNativeWasmType, )*
1071                Rets: WasmTypeList,
1072                RetsAsResult: IntoResult<Rets>,
1073                Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
1074            {
1075                let result = wasmer_vm::on_host_stack(|| {
1076                    panic::catch_unwind(AssertUnwindSafe(|| {
1077                        let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) };
1078                        let mut store = store_wrapper.as_mut();
1079                        $(
1080                            let $x = unsafe {
1081                                FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
1082                            };
1083                        )*
1084                        let f_env = crate::backend::sys::function::env::FunctionEnvMut {
1085                            store_mut: store,
1086                            func_env: env.env.as_sys().clone(),
1087                        }.into();
1088                        to_invocation_result((env.func)(f_env, $($x),* ).into_result())
1089                    }))
1090                });
1091
1092                // IMPORTANT: DO NOT ALLOCATE ON THE STACK,
1093                // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE.
1094                // See: https://github.com/wasmerio/wasmer/pull/5700
1095                match result {
1096                    Ok(InvocationResult::Success(result)) => unsafe {
1097                        // Note: can't acquire a proper ref-counted context ref here, since we can switch
1098                        // away from the WASM stack at any time.
1099                        // Safety: The pointer is only used for the duration of the call to
1100                        // `into_c_struct` and `get_current_transient`.
1101                        let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
1102                        let mut store = store_wrapper.as_mut().unwrap();
1103                        #[cfg(feature = "experimental-host-interrupt")]
1104                        if interrupt_registry::is_interrupted(store.objects.id()) {
1105                            raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
1106                        }
1107                        return result.into_c_struct(store);
1108                    },
1109                    Ok(InvocationResult::Exception(exception)) => unsafe {
1110                        // Note: can't acquire a proper ref-counted context ref here, since we can switch
1111                        // away from the WASM stack at any time.
1112                        // Safety: The pointer is only used for the duration of the call to `throw` and
1113                        // `is_interrupted`.
1114                        let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
1115                        let mut store = store_wrapper.as_mut().unwrap();
1116                        #[cfg(feature = "experimental-host-interrupt")]
1117                        if interrupt_registry::is_interrupted(store.objects.id()) {
1118                            raise_lib_trap(Trap::lib(TrapCode::HostInterrupt))
1119                        }
1120                        wasmer_vm::libcalls::throw(
1121                            store.objects.as_sys(),
1122                            exception.vm_exceptionref().unwrap_sys_ref().to_u32_exnref(),
1123                        )
1124                    }
1125                    Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
1126                    Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
1127                        raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
1128                    },
1129                    Err(panic) => unsafe { resume_panic(panic) },
1130                }
1131            }
1132            func_wrapper::< T, $( $x, )* Rets, RetsAsResult, Func > as _
1133        }
1134
1135        #[allow(non_snake_case)]
1136        pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower>]
1137            <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
1138            () -> crate::backend::sys::vm::VMTrampoline {
1139
1140            unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>(
1141                  vmctx: *mut crate::backend::sys::vm::VMContext,
1142                  body: crate::backend::sys::vm::VMFunctionCallback,
1143                  args: *mut RawValue,
1144            ) {
1145                unsafe {
1146                    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);
1147                    let mut _n = 0;
1148                    $(
1149                    let $x = *args.add(_n).cast();
1150                    _n += 1;
1151                    )*
1152
1153                    let results = body(vmctx, $( $x ),*);
1154
1155                    Rets::write_c_struct_to_ptr(results, args);
1156                }
1157            }
1158
1159            call_trampoline::<$( $x, )* Rets> as _
1160        }
1161    }};
1162}
1163
1164// Here we go! Let's generate all the C struct, `WasmTypeList`
1165// implementations and `HostFunction` implementations.
1166impl_host_function!([C] S0,);
1167impl_host_function!([transparent] S1, A1);
1168impl_host_function!([C] S2, A1, A2);
1169impl_host_function!([C] S3, A1, A2, A3);
1170impl_host_function!([C] S4, A1, A2, A3, A4);
1171impl_host_function!([C] S5, A1, A2, A3, A4, A5);
1172impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6);
1173impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7);
1174impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
1175impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
1176impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
1177impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
1178impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
1179impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
1180impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
1181impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
1182impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
1183impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
1184impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
1185impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
1186impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
1187impl_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);
1188impl_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);
1189impl_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);
1190impl_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);
1191impl_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);
1192impl_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);