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