1use 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
20pub trait Kind {}
24
25pub 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
33pub 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#[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 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
71pub struct Host(());
74
75impl Kind for Host {}
76
77pub trait WasmTypeList {
79 type CStruct;
81
82 type RetArray: AsMut<[u64]>;
84
85 fn from_ret_array(array: Self::RetArray) -> Self;
87
88 fn empty_ret_array() -> Self::RetArray;
91
92 fn from_c_struct(c_struct: Self::CStruct) -> Self;
94
95 fn into_c_struct(self) -> Self::CStruct;
97
98 fn types() -> &'static [Type];
100
101 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#[doc(hidden)]
122pub trait HostFunctionKind {}
123
124#[doc(hidden)]
133pub struct ExplicitVmCtx {}
134
135impl HostFunctionKind for ExplicitVmCtx {}
136
137pub struct ImplicitVmCtx {}
146
147impl HostFunctionKind for ImplicitVmCtx {}
148
149pub trait HostFunction<Kind, Args, Rets>
152where
153 Kind: HostFunctionKind,
154 Args: WasmTypeList,
155 Rets: WasmTypeList,
156{
157 fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>);
159}
160
161pub trait TrapEarly<Rets>
163where
164 Rets: WasmTypeList,
165{
166 type Error: Send + 'static;
168 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
193pub struct DynamicFunc<'a> {
195 _inner: Box<dyn Kind>,
196
197 func: NonNull<vm::Func>,
199
200 func_env: Option<NonNull<vm::FuncEnv>>,
202
203 vmctx: *mut vm::Ctx,
205
206 signature: Arc<FuncSig>,
212
213 _phantom: PhantomData<&'a ()>,
214}
215
216unsafe impl<'a> Send for DynamicFunc<'a> {}
217
218#[derive(Clone)]
220pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
221 inner: Inner,
222
223 func: NonNull<vm::Func>,
225
226 func_env: Option<NonNull<vm::FuncEnv>>,
228
229 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 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 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 #[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; 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 drop(args); (&*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]; 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 pub fn params(&self) -> &'static [Type] {
471 Args::types()
472 }
473
474 pub fn returns(&self) -> &'static [Type] {
476 Rets::types()
477 }
478
479 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 #[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 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 let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func;
629
630 let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions };
632
633 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 let vmctx = unsafe { func_ctx.vmctx.as_mut() };
649
650 let func_env = func_ctx.func_env;
652
653 let func: &FN = match func_env {
654 Some(func_env) => unsafe {
659 let func: NonNull<FN> = func_env.cast();
660
661 &*func.as_ptr()
662 },
663
664 None => unreachable!()
666 };
667
668 let err = match panic::catch_unwind(
670 panic::AssertUnwindSafe(
671 || {
672 func(vmctx $( , WasmExternType::from_native($x) )* ).report()
673 }
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 Err(err) => RuntimeError::User(err),
686 };
687
688 unsafe {
691 (&*vmctx.module).runnable_module.do_early_trap(err)
692 }
693 }
694
695 let func_env: Option<NonNull<vm::FuncEnv>> =
698 if mem::size_of::<Self>() == 0 {
701 NonNull::new(&self as *const _ as *mut vm::FuncEnv)
702 }
703 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 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 let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func;
745
746 let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions };
748
749 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 let vmctx = unsafe { func_ctx.vmctx.as_mut() };
765
766 let func_env = func_ctx.func_env;
768
769 let func: &FN = match func_env {
770 Some(func_env) => unsafe {
775 let func: NonNull<FN> = func_env.cast();
776
777 &*func.as_ptr()
778 },
779
780 None => unreachable!()
782 };
783
784 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 Err(err) => RuntimeError::User(err),
799 };
800
801 unsafe {
804 (&*vmctx.module).runnable_module.do_early_trap(err)
805 }
806 }
807
808 let func_env: Option<NonNull<vm::FuncEnv>> =
811 if mem::size_of::<Self>() == 0 {
814 NonNull::new(&self as *const _ as *mut vm::FuncEnv)
815 }
816 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 #[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
926pub(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 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}