1 use arbitrary::Arbitrary; 2 use std::mem::MaybeUninit; 3 use wasmtime::component::__internal::{ 4 CanonicalAbiInfo, InstanceType, InterfaceType, LiftContext, LowerContext, 5 }; 6 use wasmtime::component::{ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, Val}; 7 use wasmtime::{AsContextMut, Config, Engine}; 8 use wasmtime_environ::error::Result; 9 10 pub trait TypedFuncExt<P, R> { 11 fn call_and_post_return(&self, store: impl AsContextMut<Data: Send>, params: P) -> Result<R>; 12 } 13 14 impl<P, R> TypedFuncExt<P, R> for TypedFunc<P, R> 15 where 16 P: ComponentNamedList + Lower, 17 R: ComponentNamedList + Lift + Send + Sync + 'static, 18 { 19 fn call_and_post_return( 20 &self, 21 mut store: impl AsContextMut<Data: Send>, 22 params: P, 23 ) -> Result<R> { 24 let result = self.call(&mut store, params)?; 25 self.post_return(&mut store)?; 26 Ok(result) 27 } 28 } 29 30 pub trait FuncExt { 31 fn call_and_post_return( 32 &self, 33 store: impl AsContextMut<Data: Send>, 34 params: &[Val], 35 results: &mut [Val], 36 ) -> Result<()>; 37 } 38 39 impl FuncExt for Func { 40 fn call_and_post_return( 41 &self, 42 mut store: impl AsContextMut<Data: Send>, 43 params: &[Val], 44 results: &mut [Val], 45 ) -> Result<()> { 46 self.call(&mut store, params, results)?; 47 self.post_return(&mut store)?; 48 Ok(()) 49 } 50 } 51 52 pub fn config() -> Config { 53 drop(env_logger::try_init()); 54 55 let mut config = Config::new(); 56 config.wasm_component_model(true); 57 58 // When `WASMTIME_TEST_NO_HOG_MEMORY` is set it means we're in qemu. The 59 // component model tests create a disproportionate number of instances so 60 // try to cut down on virtual memory usage by avoiding 4G reservations. 61 if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() { 62 config.memory_reservation(0); 63 config.memory_guard_size(0); 64 } 65 config 66 } 67 68 pub fn engine() -> Engine { 69 Engine::new(&config()).unwrap() 70 } 71 72 pub fn async_engine() -> Engine { 73 let mut config = config(); 74 config.async_support(true); 75 Engine::new(&config).unwrap() 76 } 77 78 /// Newtype wrapper for `f32` whose `PartialEq` impl considers NaNs equal to each other. 79 #[derive(Copy, Clone, Debug, Arbitrary)] 80 pub struct Float32(pub f32); 81 82 /// Newtype wrapper for `f64` whose `PartialEq` impl considers NaNs equal to each other. 83 #[derive(Copy, Clone, Debug, Arbitrary)] 84 pub struct Float64(pub f64); 85 86 macro_rules! forward_impls { 87 ($($a:ty => $b:ty,)*) => ($( 88 unsafe impl ComponentType for $a { 89 type Lower = <$b as ComponentType>::Lower; 90 91 const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI; 92 93 #[inline] 94 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> { 95 <$b as ComponentType>::typecheck(ty, types) 96 } 97 } 98 99 unsafe impl Lower for $a { 100 fn linear_lower_to_flat<U>( 101 &self, 102 cx: &mut LowerContext<'_, U>, 103 ty: InterfaceType, 104 dst: &mut MaybeUninit<Self::Lower>, 105 ) -> Result<()> { 106 <$b as Lower>::linear_lower_to_flat(&self.0, cx, ty, dst) 107 } 108 109 fn linear_lower_to_memory<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType, offset: usize) -> Result<()> { 110 <$b as Lower>::linear_lower_to_memory(&self.0, cx, ty, offset) 111 } 112 } 113 114 unsafe impl Lift for $a { 115 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> { 116 Ok(Self(<$b as Lift>::linear_lift_from_flat(cx, ty, src)?)) 117 } 118 119 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> { 120 Ok(Self(<$b as Lift>::linear_lift_from_memory(cx, ty, bytes)?)) 121 } 122 } 123 124 impl PartialEq for $a { 125 fn eq(&self, other: &Self) -> bool { 126 self.0 == other.0 || (self.0.is_nan() && other.0.is_nan()) 127 } 128 } 129 )*) 130 } 131 132 forward_impls! { 133 Float32 => f32, 134 Float64 => f64, 135 } 136