1+ use std:: hash:: Hasher ;
12use std:: panic:: { self , AssertUnwindSafe } ;
23
34use eyre:: { bail, eyre, Result } ;
5+ use tinywasm:: { CoroState , SuspendConditions , SuspendReason } ;
46use tinywasm_types:: { ExternRef , FuncRef , ModuleInstanceAddr , TinyWasmModule , ValType , WasmValue } ;
57use wasm_testsuite:: wast;
68use wasm_testsuite:: wast:: { core:: AbstractHeapType , QuoteWat } ;
@@ -12,6 +14,25 @@ pub fn try_downcast_panic(panic: Box<dyn std::any::Any + Send>) -> String {
1214 info. unwrap_or ( info_str. unwrap_or ( & info_string. unwrap_or ( "unknown panic" . to_owned ( ) ) ) . to_string ( ) )
1315}
1416
17+ // due to imprecision it's not exact
18+ fn make_sometimes_breaking_cb ( probability : f64 ) -> impl FnMut ( & tinywasm:: Store ) -> std:: ops:: ControlFlow < ( ) , ( ) > {
19+ let mut counter = 0 as u64 ;
20+ let mut hasher = std:: hash:: DefaultHasher :: new ( ) ;
21+ let threshhold = ( probability * ( u64:: MAX as f64 ) ) as u64 ; // 2 lossy conversions
22+
23+ move |_| {
24+ hasher. write_u64 ( counter) ;
25+ counter += 1 ;
26+ if hasher. finish ( ) < threshhold {
27+ std:: ops:: ControlFlow :: Break ( ( ) )
28+ } else {
29+ std:: ops:: ControlFlow :: Continue ( ( ) )
30+ }
31+ }
32+ }
33+
34+
35+ #[ cfg( not( feature = "test_async" ) ) ]
1536pub fn exec_fn_instance (
1637 instance : Option < & ModuleInstanceAddr > ,
1738 store : & mut tinywasm:: Store ,
@@ -30,6 +51,51 @@ pub fn exec_fn_instance(
3051 func. call ( store, args)
3152}
3253
54+
55+ #[ cfg( feature = "test_async" ) ]
56+ pub fn exec_fn_instance (
57+ instance : Option < & ModuleInstanceAddr > ,
58+ store : & mut tinywasm:: Store ,
59+ name : & str ,
60+ args : & [ tinywasm_types:: WasmValue ] ,
61+ ) -> Result < Vec < tinywasm_types:: WasmValue > , tinywasm:: Error > {
62+ let Some ( instance) = instance else {
63+ return Err ( tinywasm:: Error :: Other ( "no instance found" . to_string ( ) ) ) ;
64+ } ;
65+
66+ let mut prev_reason = None ;
67+ store. update_suspend_conditions ( |old_cond| {
68+ prev_reason = Some ( old_cond) ;
69+ SuspendConditions { suspend_cb : Some ( Box :: new ( make_sometimes_breaking_cb ( 2.0 / 3.0 ) ) ) , ..Default :: default ( ) }
70+ } ) ;
71+ let res = || -> Result < Vec < tinywasm_types:: WasmValue > , tinywasm:: Error > {
72+ let Some ( instance) = store. get_module_instance ( * instance) else {
73+ return Err ( tinywasm:: Error :: Other ( "no instance found" . to_string ( ) ) ) ;
74+ } ;
75+
76+ let func = instance. exported_func_untyped ( store, name) ?;
77+ let mut state = match func. call_coro ( store, args) ? {
78+ tinywasm:: PotentialCoroCallResult :: Return ( val) => return Ok ( val) ,
79+ tinywasm:: PotentialCoroCallResult :: Suspended ( suspend_reason, state) => {
80+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) ) ;
81+ state
82+ }
83+ } ;
84+ loop {
85+ match state. resume ( store, None ) ? {
86+ tinywasm:: CoroStateResumeResult :: Return ( val) => return Ok ( val) ,
87+ tinywasm:: CoroStateResumeResult :: Suspended ( suspend_reason) => {
88+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) )
89+ }
90+ }
91+ }
92+ } ( ) ;
93+ // restore store suspend conditions before returning error or success
94+ store. set_suspend_conditions ( prev_reason. unwrap ( ) ) ;
95+ res
96+ }
97+
98+ #[ cfg( not( feature = "test_async" ) ) ]
3399pub fn exec_fn (
34100 module : Option < & TinyWasmModule > ,
35101 name : & str ,
@@ -39,13 +105,62 @@ pub fn exec_fn(
39105 let Some ( module) = module else {
40106 return Err ( tinywasm:: Error :: Other ( "no module found" . to_string ( ) ) ) ;
41107 } ;
42-
43108 let mut store = tinywasm:: Store :: new ( ) ;
44109 let module = tinywasm:: Module :: from ( module) ;
45110 let instance = module. instantiate ( & mut store, imports) ?;
46111 instance. exported_func_untyped ( & store, name) ?. call ( & mut store, args)
47112}
48113
114+ #[ cfg( feature = "test_async" ) ]
115+ pub fn exec_fn (
116+ module : Option < & TinyWasmModule > ,
117+ name : & str ,
118+ args : & [ tinywasm_types:: WasmValue ] ,
119+ imports : Option < tinywasm:: Imports > ,
120+ ) -> Result < Vec < tinywasm_types:: WasmValue > , tinywasm:: Error > {
121+ let Some ( module) = module else {
122+ return Err ( tinywasm:: Error :: Other ( "no module found" . to_string ( ) ) ) ;
123+ } ;
124+
125+ let mut store = tinywasm:: Store :: new ( ) ;
126+
127+ store. set_suspend_conditions ( SuspendConditions {
128+ suspend_cb : Some ( Box :: new ( make_sometimes_breaking_cb ( 2.0 / 3.0 ) ) ) ,
129+ ..Default :: default ( )
130+ } ) ;
131+
132+ let module = tinywasm:: Module :: from ( module) ;
133+ let instance = match module. instantiate_coro ( & mut store, imports) ? {
134+ tinywasm:: PotentialCoroCallResult :: Return ( res) => res,
135+ tinywasm:: PotentialCoroCallResult :: Suspended ( suspend_reason, mut state) => loop {
136+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) ) ;
137+ match state. resume ( & mut store, None ) ? {
138+ tinywasm:: CoroStateResumeResult :: Return ( res) => break res,
139+ tinywasm:: CoroStateResumeResult :: Suspended ( suspend_reason) => {
140+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) ) ;
141+ }
142+ }
143+ } ,
144+ } ;
145+
146+ let mut state = match instance. exported_func_untyped ( & store, name) ?. call_coro ( & mut store, args) ? {
147+ tinywasm:: PotentialCoroCallResult :: Return ( r) => return Ok ( r) ,
148+ tinywasm:: PotentialCoroCallResult :: Suspended ( suspend_reason, state) => {
149+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) ) ;
150+ state
151+ }
152+ } ;
153+ loop {
154+ match state. resume ( & mut store, None ) ? {
155+ tinywasm:: CoroStateResumeResult :: Return ( res) => return Ok ( res) ,
156+ tinywasm:: CoroStateResumeResult :: Suspended ( suspend_reason) => {
157+ assert ! ( matches!( suspend_reason, SuspendReason :: SuspendedCallback ) )
158+ }
159+ }
160+ }
161+ }
162+
163+
49164pub fn catch_unwind_silent < R > ( f : impl FnOnce ( ) -> R ) -> std:: thread:: Result < R > {
50165 let prev_hook = panic:: take_hook ( ) ;
51166 panic:: set_hook ( Box :: new ( |_| { } ) ) ;
0 commit comments