@@ -19,53 +19,63 @@ const TEST_MAX_SUSPENSIONS: u32 = 1000;
1919
2020#[ derive( Default ) ]
2121struct ModuleRegistry {
22- modules : HashMap < String , ModuleInstance > ,
23- named_modules : HashMap < String , ModuleInstance > ,
24- last_module : Option < ModuleInstance > ,
22+ definitions : HashMap < String , Module > ,
23+ instances : HashMap < String , ModuleInstance > ,
24+ registered : HashMap < String , ModuleInstance > ,
25+ last_definition : Option < Module > ,
26+ last_instance : Option < ModuleInstance > ,
2527}
2628
2729impl ModuleRegistry {
28- fn modules ( & self ) -> & HashMap < String , ModuleInstance > {
29- & self . modules
30+ fn registered ( & self ) -> & HashMap < String , ModuleInstance > {
31+ & self . registered
3032 }
3133
32- fn update_last_module ( & mut self , module : ModuleInstance , name : Option < String > ) {
33- self . last_module = Some ( module. clone ( ) ) ;
34+ fn define ( & mut self , module : Module , name : Option < String > ) {
35+ self . last_definition = Some ( module. clone ( ) ) ;
3436 if let Some ( name) = name {
35- self . named_modules . insert ( name, module) ;
37+ self . definitions . insert ( name, module) ;
3638 }
3739 }
3840
39- fn register ( & mut self , name : String , module : ModuleInstance ) {
41+ fn definition ( & self , id : Option < wast:: token:: Id < ' _ > > ) -> Option < Module > {
42+ match id {
43+ Some ( id) => self . definitions . get ( id. name ( ) ) . cloned ( ) ,
44+ None => self . last_definition . clone ( ) ,
45+ }
46+ }
47+
48+ fn update_last_instance ( & mut self , instance : ModuleInstance , name : Option < String > ) {
49+ self . last_instance = Some ( instance. clone ( ) ) ;
50+ if let Some ( name) = name {
51+ self . instances . insert ( name, instance) ;
52+ }
53+ }
54+
55+ fn register ( & mut self , name : String , id : Option < wast:: token:: Id < ' _ > > ) -> bool {
56+ let Some ( instance) = self . get ( id) else { return false } ;
4057 debug ! ( "registering module: {name}" ) ;
41- self . modules . insert ( name. clone ( ) , module. clone ( ) ) ;
42- self . last_module = Some ( module. clone ( ) ) ;
43- self . named_modules . insert ( name, module) ;
58+ self . registered . insert ( name, instance) ;
59+ true
4460 }
4561
4662 fn get_idx ( & self , module_id : Option < wast:: token:: Id < ' _ > > ) -> Option < u32 > {
4763 match module_id {
48- Some ( module) => self
49- . modules
50- . get ( module. name ( ) )
51- . or_else ( || self . named_modules . get ( module. name ( ) ) )
52- . map ( ModuleInstance :: id) ,
53- None => self . last_module . as_ref ( ) . map ( ModuleInstance :: id) ,
64+ Some ( module) => {
65+ self . registered . get ( module. name ( ) ) . or_else ( || self . instances . get ( module. name ( ) ) ) . map ( ModuleInstance :: id)
66+ }
67+ None => self . last_instance . as_ref ( ) . map ( ModuleInstance :: id) ,
5468 }
5569 }
5670
5771 fn get ( & self , module_id : Option < wast:: token:: Id < ' _ > > ) -> Option < ModuleInstance > {
5872 match module_id {
5973 Some ( module_id) => {
60- self . modules . get ( module_id. name ( ) ) . or_else ( || self . named_modules . get ( module_id. name ( ) ) ) . cloned ( )
74+ self . registered . get ( module_id. name ( ) ) . or_else ( || self . instances . get ( module_id. name ( ) ) ) . cloned ( )
6175 }
62- None => self . last_module . clone ( ) ,
76+ None => self . last_instance . clone ( ) ,
6377 }
6478 }
65-
66- fn last ( & self ) -> Option < ModuleInstance > {
67- self . last_module . clone ( )
68- }
6979}
7080
7181#[ derive( Default ) ]
@@ -200,6 +210,11 @@ impl WastRunner {
200210 Ok ( imports)
201211 }
202212
213+ fn instantiate_module ( store : & mut Store , registry : & ModuleRegistry , module : & Module ) -> Result < ModuleInstance > {
214+ let imports = Self :: imports ( store, registry. registered ( ) ) ?;
215+ Ok ( ModuleInstance :: instantiate ( store, module, Some ( & imports) ) ?)
216+ }
217+
203218 pub fn run_file ( & mut self , file : TestFile < ' _ > ) -> Result < ( ) > {
204219 let test_group = self . test_group ( file. name ( ) , file. parent ( ) ) ;
205220 let wast_raw = file. raw ( ) ;
@@ -213,51 +228,72 @@ impl WastRunner {
213228 for ( i, directive) in directives. into_iter ( ) . enumerate ( ) {
214229 let span = directive. span ( ) ;
215230 use wast:: WastDirective :: {
216- AssertExhaustion , AssertInvalid , AssertMalformed , AssertReturn , AssertTrap , AssertUnlinkable , Invoke ,
217- Module as Wat , ModuleDefinition , Register ,
231+ AssertException , AssertExhaustion , AssertInvalid , AssertMalformed , AssertReturn , AssertTrap ,
232+ AssertUnlinkable , Invoke , Module as Wat , ModuleDefinition , ModuleInstance as Instance , Register ,
218233 } ;
219234
220235 match directive {
221- Register { span, name, .. } => {
222- let Some ( last ) = module_registry. last ( ) else {
236+ Register { span, name, module } => {
237+ if ! module_registry. register ( name . to_string ( ) , module ) {
223238 test_group. add_result (
224239 & format ! ( "Register({i})" ) ,
225240 span. linecol_in ( wast_raw) ,
226- Err ( eyre ! ( "no module to register" ) ) ,
241+ Err ( eyre ! ( "module instance to register was not found " ) ) ,
227242 ) ;
228243 continue ;
229- } ;
230- module_registry. register ( name. to_string ( ) , last) ;
244+ }
231245 test_group. add_result ( & format ! ( "Register({i})" ) , span. linecol_in ( wast_raw) , Ok ( ( ) ) ) ;
232246 }
233247 Wat ( module) => {
234248 let result = catch_unwind_silent ( || {
235- let ( name, bytes) = encode_quote_wat ( module) ;
236- let module = parse_module_bytes ( & bytes) . expect ( "failed to parse module bytes" ) ;
237- let imports = Self :: imports ( & mut store, module_registry. modules ( ) ) . unwrap ( ) ;
238- let module_instance = ModuleInstance :: instantiate ( & mut store, & module, Some ( & imports) )
249+ let ( name, module) = parse_quote_module ( module) . expect ( "failed to parse module bytes" ) ;
250+ let instance = Self :: instantiate_module ( & mut store, & module_registry, & module)
239251 . expect ( "failed to instantiate module" ) ;
240- ( name, module_instance )
252+ ( name, instance )
241253 } )
242254 . map_err ( |e| eyre ! ( "failed to parse wat module: {}" , try_downcast_panic( e) ) ) ;
243255
244256 match & result {
245257 Err ( err) => debug ! ( "failed to parse module: {err:?}" ) ,
246- Ok ( ( name, module ) ) => module_registry. update_last_module ( module . clone ( ) , name. clone ( ) ) ,
258+ Ok ( ( name, instance ) ) => module_registry. update_last_instance ( instance . clone ( ) , name. clone ( ) ) ,
247259 } ;
248260
249261 test_group. add_result ( & format ! ( "Wat({i})" ) , span. linecol_in ( wast_raw) , result. map ( |_| ( ) ) ) ;
250262 }
251263 ModuleDefinition ( module) => {
264+ let result =
265+ catch_unwind_silent ( || parse_quote_module ( module) . expect ( "failed to parse module definition" ) )
266+ . map_err ( |err| eyre ! ( "failed to parse module definition: {}" , try_downcast_panic( err) ) ) ;
267+
268+ if let Ok ( ( name, module) ) = & result {
269+ module_registry. define ( module. clone ( ) , name. clone ( ) ) ;
270+ }
271+
272+ test_group. add_result (
273+ & format ! ( "ModuleDefinition({i})" ) ,
274+ span. linecol_in ( wast_raw) ,
275+ result. map ( |_| ( ) ) ,
276+ ) ;
277+ }
278+ Instance { span, instance, module } => {
279+ let name = instance. map ( |id| id. name ( ) . to_string ( ) ) ;
252280 let result = catch_unwind_silent ( || {
253- let ( _, bytes) = encode_quote_wat ( module) ;
254- parse_module_bytes ( & bytes)
281+ let module = module_registry
282+ . definition ( module)
283+ . ok_or_else ( || eyre ! ( "module definition was not found" ) ) ?;
284+ Self :: instantiate_module ( & mut store, & module_registry, & module)
255285 } )
256- . map_err ( |err| eyre ! ( "failed to parse module definition: {}" , try_downcast_panic( err) ) )
257- . and_then ( |result| result)
258- . map ( |_| ( ) ) ;
286+ . map_err ( |err| eyre ! ( "failed to instantiate module definition: {}" , try_downcast_panic( err) ) )
287+ . and_then ( |result| result) ;
259288
260- test_group. add_result ( & format ! ( "ModuleDefinition({i})" ) , span. linecol_in ( wast_raw) , result) ;
289+ if let Ok ( instance) = & result {
290+ module_registry. update_last_instance ( instance. clone ( ) , name) ;
291+ }
292+ test_group. add_result (
293+ & format ! ( "ModuleInstance({i})" ) ,
294+ span. linecol_in ( wast_raw) ,
295+ result. map ( |_| ( ) ) ,
296+ ) ;
261297 }
262298 AssertMalformed { span, mut module, message } => {
263299 let Ok ( encoded) = module. encode ( ) else {
@@ -330,7 +366,7 @@ impl WastRunner {
330366 wast:: WastExecute :: Wat ( mut wat) => {
331367 let module = parse_module_bytes ( & wat. encode ( ) . expect ( "failed to encode module" ) )
332368 . expect ( "failed to parse module" ) ;
333- let imports = Self :: imports ( & mut store, module_registry. modules ( ) ) . unwrap ( ) ;
369+ let imports = Self :: imports ( & mut store, module_registry. registered ( ) ) . unwrap ( ) ;
334370 ModuleInstance :: instantiate ( & mut store, & module, Some ( & imports) ) ?;
335371 return Ok ( ( ) ) ;
336372 }
@@ -371,11 +407,37 @@ impl WastRunner {
371407 ) ,
372408 }
373409 }
410+ AssertException { exec, span } => {
411+ let res: Result < tinywasm:: Result < ( ) > , _ > = catch_unwind_silent ( || {
412+ let invoke = match exec {
413+ wast:: WastExecute :: Wat ( mut wat) => {
414+ let module = parse_module_bytes ( & wat. encode ( ) . expect ( "failed to encode module" ) )
415+ . expect ( "failed to parse module" ) ;
416+ let imports = Self :: imports ( & mut store, module_registry. registered ( ) ) . unwrap ( ) ;
417+ ModuleInstance :: instantiate ( & mut store, & module, Some ( & imports) ) ?;
418+ return Ok ( ( ) ) ;
419+ }
420+ wast:: WastExecute :: Get { .. } => panic ! ( "get not supported" ) ,
421+ wast:: WastExecute :: Invoke ( invoke) => invoke,
422+ } ;
423+ let module = module_registry. get_idx ( invoke. module ) ;
424+ let args =
425+ convert_wastargs ( invoke. args ) . map_err ( |err| tinywasm:: Error :: Other ( err. to_string ( ) ) ) ?;
426+ exec_fn_instance ( module, & mut store, invoke. name , & args) . map ( |_| ( ) )
427+ } ) ;
428+ let result = match res {
429+ Err ( err) => Err ( eyre ! ( "test panicked: {}" , try_downcast_panic( err) ) ) ,
430+ Ok ( Err ( tinywasm:: Error :: Exception ( _) ) ) => Ok ( ( ) ) ,
431+ Ok ( Err ( err) ) => Err ( eyre ! ( "expected exception, got: {err:?}" ) ) ,
432+ Ok ( Ok ( ( ) ) ) => Err ( eyre ! ( "expected exception, got Ok" ) ) ,
433+ } ;
434+ test_group. add_result ( & format ! ( "AssertException({i})" ) , span. linecol_in ( wast_raw) , result) ;
435+ }
374436 AssertUnlinkable { mut module, span, message } => {
375437 let res = catch_unwind_silent ( || {
376438 let module = parse_module_bytes ( & module. encode ( ) . expect ( "failed to encode module" ) )
377439 . expect ( "failed to parse module" ) ;
378- let imports = Self :: imports ( & mut store, module_registry. modules ( ) ) . unwrap ( ) ;
440+ let imports = Self :: imports ( & mut store, module_registry. registered ( ) ) . unwrap ( ) ;
379441 ModuleInstance :: instantiate ( & mut store, & module, Some ( & imports) )
380442 } ) ;
381443 match res {
@@ -729,6 +791,11 @@ fn parse_module_bytes(bytes: &[u8]) -> Result<Module> {
729791 Ok ( tinywasm:: parse_bytes ( bytes) ?)
730792}
731793
794+ fn parse_quote_module ( module : QuoteWat ) -> Result < ( Option < String > , Module ) > {
795+ let ( name, bytes) = encode_quote_wat ( module) ;
796+ Ok ( ( name, parse_module_bytes ( & bytes) ?) )
797+ }
798+
732799fn convert_wastargs ( args : Vec < wast:: WastArg > ) -> Result < Vec < WasmValue > > {
733800 args. into_iter ( ) . map ( wastarg2tinywasmvalue) . collect ( )
734801}
@@ -947,4 +1014,26 @@ mod tests {
9471014 let mut runner = WastRunner :: new ( ) ;
9481015 runner. run_paths ( & [ path] ) . unwrap ( ) ;
9491016 }
1017+
1018+ #[ test]
1019+ fn runs_module_definition_and_instance_directives ( ) {
1020+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
1021+ let path = dir. path ( ) . join ( "instance.wast" ) ;
1022+ std:: fs:: write (
1023+ & path,
1024+ r#"
1025+ (module definition $M (global (export "g") i32 (i32.const 42)))
1026+ (module instance $I $M)
1027+ (register "I" $I)
1028+ (module
1029+ (import "I" "g" (global $g i32))
1030+ (func (export "get") (result i32) global.get $g))
1031+ (assert_return (invoke "get") (i32.const 42))
1032+ "# ,
1033+ )
1034+ . unwrap ( ) ;
1035+
1036+ let mut runner = WastRunner :: new ( ) ;
1037+ runner. run_paths ( & [ path] ) . unwrap ( ) ;
1038+ }
9501039}
0 commit comments