1111use anyhow:: { bail, Context , Result } ;
1212use std:: collections:: { HashMap , HashSet } ;
1313use std:: fmt:: { self , Write } ;
14+ use std:: marker;
1415use std:: mem;
1516use std:: path:: Path ;
1617use wasmparser:: * ;
@@ -54,6 +55,7 @@ pub struct Printer {
5455 line : usize ,
5556 group_lines : Vec < usize > ,
5657 code_section_hints : Vec < ( u32 , Vec < ( usize , BranchHint ) > ) > ,
58+ name_unnamed : bool ,
5759}
5860
5961#[ derive( Default ) ]
@@ -66,18 +68,41 @@ struct CoreState {
6668 tables : u32 ,
6769 modules : u32 ,
6870 instances : u32 ,
69- func_names : HashMap < u32 , Naming > ,
70- local_names : HashMap < ( u32 , u32 ) , Naming > ,
71- label_names : HashMap < ( u32 , u32 ) , Naming > ,
72- type_names : HashMap < u32 , Naming > ,
73- tag_names : HashMap < u32 , Naming > ,
74- table_names : HashMap < u32 , Naming > ,
75- memory_names : HashMap < u32 , Naming > ,
76- global_names : HashMap < u32 , Naming > ,
77- element_names : HashMap < u32 , Naming > ,
78- data_names : HashMap < u32 , Naming > ,
79- module_names : HashMap < u32 , Naming > ,
80- instance_names : HashMap < u32 , Naming > ,
71+ func_names : NamingMap < u32 , NameFunc > ,
72+ local_names : NamingMap < ( u32 , u32 ) , NameLocal > ,
73+ label_names : NamingMap < ( u32 , u32 ) , NameLabel > ,
74+ type_names : NamingMap < u32 , NameType > ,
75+ tag_names : NamingMap < u32 , NameTag > ,
76+ table_names : NamingMap < u32 , NameTable > ,
77+ memory_names : NamingMap < u32 , NameMemory > ,
78+ global_names : NamingMap < u32 , NameGlobal > ,
79+ element_names : NamingMap < u32 , NameElem > ,
80+ data_names : NamingMap < u32 , NameData > ,
81+ module_names : NamingMap < u32 , NameModule > ,
82+ instance_names : NamingMap < u32 , NameInstance > ,
83+ }
84+
85+ /// A map of index-to-name for tracking what are the contents of the name
86+ /// section.
87+ ///
88+ /// The type parameter `T` is either `u32` for most index-based maps or a `(u32,
89+ /// u32)` for label/local maps where there are two levels of indices.
90+ ///
91+ /// The type parameter `K` is a static description/namespace for what kind of
92+ /// item is contained within this map. That's used by some helper methods to
93+ /// synthesize reasonable names automatically.
94+ struct NamingMap < T , K > {
95+ index_to_name : HashMap < T , Naming > ,
96+ _marker : marker:: PhantomData < K > ,
97+ }
98+
99+ impl < T , K > Default for NamingMap < T , K > {
100+ fn default ( ) -> NamingMap < T , K > {
101+ NamingMap {
102+ index_to_name : HashMap :: new ( ) ,
103+ _marker : marker:: PhantomData ,
104+ }
105+ }
81106}
82107
83108#[ derive( Default ) ]
@@ -87,11 +112,11 @@ struct ComponentState {
87112 instances : u32 ,
88113 components : u32 ,
89114 values : u32 ,
90- type_names : HashMap < u32 , Naming > ,
91- func_names : HashMap < u32 , Naming > ,
92- component_names : HashMap < u32 , Naming > ,
93- instance_names : HashMap < u32 , Naming > ,
94- value_names : HashMap < u32 , Naming > ,
115+ type_names : NamingMap < u32 , NameType > ,
116+ func_names : NamingMap < u32 , NameFunc > ,
117+ component_names : NamingMap < u32 , NameComponent > ,
118+ instance_names : NamingMap < u32 , NameInstance > ,
119+ value_names : NamingMap < u32 , NameValue > ,
95120}
96121
97122struct State {
@@ -136,6 +161,20 @@ impl Printer {
136161 self . print_skeleton = print;
137162 }
138163
164+ /// Assign names to all unnamed items.
165+ ///
166+ /// If enabled then any previously unnamed item will have a name synthesized
167+ /// that looks like `$#func10` for example. The leading `#` indicates that
168+ /// it's `wasmprinter`-generated. The `func` is the namespace of the name
169+ /// and provides extra context about the item when referenced. The 10 is the
170+ /// local index of the item.
171+ ///
172+ /// Note that if the resulting text output is converted back to binary the
173+ /// resulting `name` custom section will not be the same as before.
174+ pub fn name_unnamed ( & mut self , enable : bool ) {
175+ self . name_unnamed = enable;
176+ }
177+
139178 /// Registers a custom `printer` function to get invoked whenever a custom
140179 /// section of name `section` is seen.
141180 ///
@@ -552,8 +591,8 @@ impl Printer {
552591 }
553592
554593 fn register_names ( & mut self , state : & mut State , names : NameSectionReader < ' _ > ) -> Result < ( ) > {
555- fn indirect_name_map (
556- into : & mut HashMap < ( u32 , u32 ) , Naming > ,
594+ fn indirect_name_map < K > (
595+ into : & mut NamingMap < ( u32 , u32 ) , K > ,
557596 names : IndirectNameMap < ' _ > ,
558597 name : & str ,
559598 ) -> Result < ( ) > {
@@ -567,7 +606,7 @@ impl Printer {
567606 } ;
568607 for naming in indirect. names {
569608 let naming = naming?;
570- into. insert (
609+ into. index_to_name . insert (
571610 ( indirect. index , naming. index ) ,
572611 Naming :: new ( naming. name , naming. index , name, used. as_mut ( ) ) ,
573612 ) ;
@@ -811,8 +850,7 @@ impl Printer {
811850 // we need to be careful to terminate previous param blocks and open
812851 // a new one if that's the case with a named parameter.
813852 for ( i, param) in ty. params ( ) . iter ( ) . enumerate ( ) {
814- let name = names_for. and_then ( |n| state. core . local_names . get ( & ( n, i as u32 ) ) ) ;
815- params. start_local ( name, & mut self . result ) ;
853+ params. start_local ( names_for. unwrap_or ( u32:: MAX ) , i as u32 , self , state) ;
816854 self . print_valtype ( * param) ?;
817855 params. end_local ( & mut self . result ) ;
818856 }
@@ -1171,8 +1209,7 @@ impl Printer {
11711209 self . newline ( offset) ;
11721210 first = false ;
11731211 }
1174- let name = state. core . local_names . get ( & ( func_idx, params + local_idx) ) ;
1175- locals. start_local ( name, & mut self . result ) ;
1212+ locals. start_local ( func_idx, params + local_idx, self , state) ;
11761213 self . print_valtype ( ty) ?;
11771214 locals. end_local ( & mut self . result ) ;
11781215 local_idx += 1 ;
@@ -1345,28 +1382,55 @@ impl Printer {
13451382 Ok ( ( ) )
13461383 }
13471384
1348- fn print_idx ( & mut self , names : & HashMap < u32 , Naming > , idx : u32 ) -> Result < ( ) > {
1385+ fn print_idx < K > ( & mut self , names : & NamingMap < u32 , K > , idx : u32 ) -> Result < ( ) >
1386+ where
1387+ K : NamingNamespace ,
1388+ {
1389+ self . _print_idx ( & names. index_to_name , idx, K :: desc ( ) )
1390+ }
1391+
1392+ fn _print_idx ( & mut self , names : & HashMap < u32 , Naming > , idx : u32 , desc : & str ) -> Result < ( ) > {
13491393 match names. get ( & idx) {
13501394 Some ( name) => write ! ( self . result, "${}" , name. identifier( ) ) ?,
1351- None => write ! ( self . result, "{}" , idx) ?,
1395+ None if self . name_unnamed => write ! ( self . result, "$#{desc}{idx}" ) ?,
1396+ None => write ! ( self . result, "{idx}" ) ?,
13521397 }
13531398 Ok ( ( ) )
13541399 }
13551400
13561401 fn print_local_idx ( & mut self , state : & State , func : u32 , idx : u32 ) -> Result < ( ) > {
1357- match state. core . local_names . get ( & ( func, idx) ) {
1402+ match state. core . local_names . index_to_name . get ( & ( func, idx) ) {
13581403 Some ( name) => write ! ( self . result, "${}" , name. identifier( ) ) ?,
1404+ None if self . name_unnamed => write ! ( self . result, "$#local{idx}" ) ?,
13591405 None => write ! ( self . result, "{}" , idx) ?,
13601406 }
13611407 Ok ( ( ) )
13621408 }
13631409
1364- fn print_name ( & mut self , names : & HashMap < u32 , Naming > , cur_idx : u32 ) -> Result < ( ) > {
1365- if let Some ( name) = names. get ( & cur_idx) {
1366- name. write ( & mut self . result ) ;
1367- self . result . push ( ' ' ) ;
1410+ fn print_name < K > ( & mut self , names : & NamingMap < u32 , K > , cur_idx : u32 ) -> Result < ( ) >
1411+ where
1412+ K : NamingNamespace ,
1413+ {
1414+ self . _print_name ( & names. index_to_name , cur_idx, K :: desc ( ) )
1415+ }
1416+
1417+ fn _print_name (
1418+ & mut self ,
1419+ names : & HashMap < u32 , Naming > ,
1420+ cur_idx : u32 ,
1421+ desc : & str ,
1422+ ) -> Result < ( ) > {
1423+ match names. get ( & cur_idx) {
1424+ Some ( name) => {
1425+ name. write ( & mut self . result ) ;
1426+ self . result . push ( ' ' ) ;
1427+ }
1428+ None if self . name_unnamed => {
1429+ write ! ( self . result, "$#{desc}{cur_idx} " ) ?;
1430+ }
1431+ None => { }
13681432 }
1369- write ! ( self . result, "(;{};)" , cur_idx ) ?;
1433+ write ! ( self . result, "(;{cur_idx };)" ) ?;
13701434 Ok ( ( ) )
13711435 }
13721436
@@ -2764,35 +2828,46 @@ impl NamedLocalPrinter {
27642828 }
27652829 }
27662830
2767- fn start_local ( & mut self , name : Option < & Naming > , dst : & mut String ) {
2831+ fn start_local ( & mut self , func : u32 , local : u32 , dst : & mut Printer , state : & State ) {
2832+ let name = state. core . local_names . index_to_name . get ( & ( func, local) ) ;
2833+
27682834 // Named locals must be in their own group, so if we have a name we need
27692835 // to terminate the previous group.
27702836 if name. is_some ( ) && self . in_group {
2771- dst. push ( ')' ) ;
2837+ dst. result . push ( ')' ) ;
27722838 self . in_group = false ;
27732839 }
27742840
27752841 if self . first {
27762842 self . first = false ;
27772843 } else {
2778- dst. push ( ' ' ) ;
2844+ dst. result . push ( ' ' ) ;
27792845 }
27802846
27812847 // Next we either need a separator if we're already in a group or we
27822848 // need to open a group for our new local.
27832849 if !self . in_group {
2784- dst. push ( '(' ) ;
2785- dst. push_str ( self . group_name ) ;
2786- dst. push ( ' ' ) ;
2850+ dst. result . push ( '(' ) ;
2851+ dst. result . push_str ( self . group_name ) ;
2852+ dst. result . push ( ' ' ) ;
27872853 self . in_group = true ;
27882854 }
27892855
27902856 // Print the optional name if given...
2791- if let Some ( name) = name {
2792- name. write ( dst) ;
2793- dst. push ( ' ' ) ;
2857+ match name {
2858+ Some ( name) => {
2859+ name. write ( & mut dst. result ) ;
2860+ dst. result . push ( ' ' ) ;
2861+ self . end_group_after_local = true ;
2862+ }
2863+ None if dst. name_unnamed => {
2864+ dst. result . push_str ( & format ! ( "$#local{local} " ) ) ;
2865+ self . end_group_after_local = true ;
2866+ }
2867+ None => {
2868+ self . end_group_after_local = false ;
2869+ }
27942870 }
2795- self . end_group_after_local = name. is_some ( ) ;
27962871 }
27972872
27982873 fn end_local ( & mut self , dst : & mut String ) {
@@ -3019,11 +3094,43 @@ impl Naming {
30193094 }
30203095}
30213096
3022- fn name_map ( into : & mut HashMap < u32 , Naming > , names : NameMap < ' _ > , name : & str ) -> Result < ( ) > {
3097+ /// Helper trait for the `NamingMap` type's `K` type parameter.
3098+ trait NamingNamespace {
3099+ fn desc ( ) -> & ' static str ;
3100+ }
3101+
3102+ macro_rules! naming_namespaces {
3103+ ( $( struct $name: ident => $desc: tt) * ) => ( $(
3104+ struct $name;
3105+
3106+ impl NamingNamespace for $name {
3107+ fn desc( ) -> & ' static str { $desc }
3108+ }
3109+ ) * )
3110+ }
3111+
3112+ naming_namespaces ! {
3113+ struct NameFunc => "func"
3114+ struct NameModule => "module"
3115+ struct NameInstance => "instance"
3116+ struct NameGlobal => "global"
3117+ struct NameMemory => "memory"
3118+ struct NameLocal => "local"
3119+ struct NameLabel => "label"
3120+ struct NameTable => "table"
3121+ struct NameValue => "value"
3122+ struct NameType => "type"
3123+ struct NameData => "data"
3124+ struct NameElem => "elem"
3125+ struct NameComponent => "component"
3126+ struct NameTag => "tag"
3127+ }
3128+
3129+ fn name_map < K > ( into : & mut NamingMap < u32 , K > , names : NameMap < ' _ > , name : & str ) -> Result < ( ) > {
30233130 let mut used = HashSet :: new ( ) ;
30243131 for naming in names {
30253132 let naming = naming?;
3026- into. insert (
3133+ into. index_to_name . insert (
30273134 naming. index ,
30283135 Naming :: new ( naming. name , naming. index , name, Some ( & mut used) ) ,
30293136 ) ;
0 commit comments