11
11
use anyhow:: { bail, Context , Result } ;
12
12
use std:: collections:: { HashMap , HashSet } ;
13
13
use std:: fmt:: { self , Write } ;
14
+ use std:: marker;
14
15
use std:: mem;
15
16
use std:: path:: Path ;
16
17
use wasmparser:: * ;
@@ -54,6 +55,7 @@ pub struct Printer {
54
55
line : usize ,
55
56
group_lines : Vec < usize > ,
56
57
code_section_hints : Vec < ( u32 , Vec < ( usize , BranchHint ) > ) > ,
58
+ name_unnamed : bool ,
57
59
}
58
60
59
61
#[ derive( Default ) ]
@@ -66,18 +68,41 @@ struct CoreState {
66
68
tables : u32 ,
67
69
modules : u32 ,
68
70
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
+ }
81
106
}
82
107
83
108
#[ derive( Default ) ]
@@ -87,11 +112,11 @@ struct ComponentState {
87
112
instances : u32 ,
88
113
components : u32 ,
89
114
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 > ,
95
120
}
96
121
97
122
struct State {
@@ -136,6 +161,20 @@ impl Printer {
136
161
self . print_skeleton = print;
137
162
}
138
163
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
+
139
178
/// Registers a custom `printer` function to get invoked whenever a custom
140
179
/// section of name `section` is seen.
141
180
///
@@ -552,8 +591,8 @@ impl Printer {
552
591
}
553
592
554
593
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 > ,
557
596
names : IndirectNameMap < ' _ > ,
558
597
name : & str ,
559
598
) -> Result < ( ) > {
@@ -567,7 +606,7 @@ impl Printer {
567
606
} ;
568
607
for naming in indirect. names {
569
608
let naming = naming?;
570
- into. insert (
609
+ into. index_to_name . insert (
571
610
( indirect. index , naming. index ) ,
572
611
Naming :: new ( naming. name , naming. index , name, used. as_mut ( ) ) ,
573
612
) ;
@@ -811,8 +850,7 @@ impl Printer {
811
850
// we need to be careful to terminate previous param blocks and open
812
851
// a new one if that's the case with a named parameter.
813
852
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) ;
816
854
self . print_valtype ( * param) ?;
817
855
params. end_local ( & mut self . result ) ;
818
856
}
@@ -1171,8 +1209,7 @@ impl Printer {
1171
1209
self . newline ( offset) ;
1172
1210
first = false ;
1173
1211
}
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) ;
1176
1213
self . print_valtype ( ty) ?;
1177
1214
locals. end_local ( & mut self . result ) ;
1178
1215
local_idx += 1 ;
@@ -1345,28 +1382,55 @@ impl Printer {
1345
1382
Ok ( ( ) )
1346
1383
}
1347
1384
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 < ( ) > {
1349
1393
match names. get ( & idx) {
1350
1394
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}" ) ?,
1352
1397
}
1353
1398
Ok ( ( ) )
1354
1399
}
1355
1400
1356
1401
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) ) {
1358
1403
Some ( name) => write ! ( self . result, "${}" , name. identifier( ) ) ?,
1404
+ None if self . name_unnamed => write ! ( self . result, "$#local{idx}" ) ?,
1359
1405
None => write ! ( self . result, "{}" , idx) ?,
1360
1406
}
1361
1407
Ok ( ( ) )
1362
1408
}
1363
1409
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 => { }
1368
1432
}
1369
- write ! ( self . result, "(;{};)" , cur_idx ) ?;
1433
+ write ! ( self . result, "(;{cur_idx };)" ) ?;
1370
1434
Ok ( ( ) )
1371
1435
}
1372
1436
@@ -2764,35 +2828,46 @@ impl NamedLocalPrinter {
2764
2828
}
2765
2829
}
2766
2830
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
+
2768
2834
// Named locals must be in their own group, so if we have a name we need
2769
2835
// to terminate the previous group.
2770
2836
if name. is_some ( ) && self . in_group {
2771
- dst. push ( ')' ) ;
2837
+ dst. result . push ( ')' ) ;
2772
2838
self . in_group = false ;
2773
2839
}
2774
2840
2775
2841
if self . first {
2776
2842
self . first = false ;
2777
2843
} else {
2778
- dst. push ( ' ' ) ;
2844
+ dst. result . push ( ' ' ) ;
2779
2845
}
2780
2846
2781
2847
// Next we either need a separator if we're already in a group or we
2782
2848
// need to open a group for our new local.
2783
2849
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 ( ' ' ) ;
2787
2853
self . in_group = true ;
2788
2854
}
2789
2855
2790
2856
// 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
+ }
2794
2870
}
2795
- self . end_group_after_local = name. is_some ( ) ;
2796
2871
}
2797
2872
2798
2873
fn end_local ( & mut self , dst : & mut String ) {
@@ -3019,11 +3094,43 @@ impl Naming {
3019
3094
}
3020
3095
}
3021
3096
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 < ( ) > {
3023
3130
let mut used = HashSet :: new ( ) ;
3024
3131
for naming in names {
3025
3132
let naming = naming?;
3026
- into. insert (
3133
+ into. index_to_name . insert (
3027
3134
naming. index ,
3028
3135
Naming :: new ( naming. name , naming. index , name, Some ( & mut used) ) ,
3029
3136
) ;
0 commit comments