Skip to content

Commit 97cad53

Browse files
kritzcreekChristoph Hegemann
andauthored
wasmprinter: prints field names declared in the names section (#1512)
* wasmprinter: prints field names declared in the names section * fixes for testsuite * bit of type juggling * missed this one * names field names in the types section for --name-unnamed * emits names for fields when encoding with wast * adds an extra test case for field names and updates snapshots --------- Co-authored-by: Christoph Hegemann <christoph@deepchannel.com>
1 parent cbd87b7 commit 97cad53

16 files changed

Lines changed: 197 additions & 54 deletions

File tree

crates/wasm-metadata/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ impl<'a> ModuleNames<'a> {
646646
wasmparser::Name::Global(m) => section.globals(&name_map(&m)?),
647647
wasmparser::Name::Element(m) => section.elements(&name_map(&m)?),
648648
wasmparser::Name::Data(m) => section.data(&name_map(&m)?),
649+
wasmparser::Name::Field(m) => section.fields(&indirect_name_map(&m)?),
649650
wasmparser::Name::Tag(m) => section.tags(&name_map(&m)?),
650651
wasmparser::Name::Unknown { .. } => {} // wasm-encoder doesn't support it
651652
}

crates/wasmparser/src/readers/core/names.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ pub enum Name<'a> {
101101
Element(NameMap<'a>),
102102
/// The name is for the data segments.
103103
Data(NameMap<'a>),
104+
/// The name is for fields.
105+
Field(IndirectNameMap<'a>),
104106
/// The name is for tags.
105107
Tag(NameMap<'a>),
106108
/// An unknown [name subsection](https://webassembly.github.io/spec/core/appendix/custom.html#subsections).
@@ -145,6 +147,7 @@ impl<'a> Subsection<'a> for Name<'a> {
145147
7 => Name::Global(NameMap::new(data, offset)?),
146148
8 => Name::Element(NameMap::new(data, offset)?),
147149
9 => Name::Data(NameMap::new(data, offset)?),
150+
10 => Name::Field(IndirectNameMap::new(data, offset)?),
148151
11 => Name::Tag(NameMap::new(data, offset)?),
149152
ty => Name::Unknown {
150153
ty,

crates/wasmprinter/src/lib.rs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct CoreState {
7272
local_names: NamingMap<(u32, u32), NameLocal>,
7373
label_names: NamingMap<(u32, u32), NameLabel>,
7474
type_names: NamingMap<u32, NameType>,
75+
field_names: NamingMap<(u32, u32), NameField>,
7576
tag_names: NamingMap<u32, NameTag>,
7677
table_names: NamingMap<u32, NameTable>,
7778
memory_names: NamingMap<u32, NameMemory>,
@@ -639,7 +640,7 @@ impl Printer {
639640
let mut used = match name {
640641
// labels can be shadowed, so maintaining the used names is not useful.
641642
"label" => None,
642-
"local" => Some(HashSet::new()),
643+
"local" | "field" => Some(HashSet::new()),
643644
_ => unimplemented!("{name} is an unknown type of indirect names"),
644645
};
645646
for naming in indirect.names {
@@ -668,6 +669,7 @@ impl Printer {
668669
Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?,
669670
Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?,
670671
Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?,
672+
Name::Field(n) => indirect_name_map(&mut state.core.field_names, n, "field")?,
671673
Name::Tag(n) => name_map(&mut state.core.tag_names, n, "tag")?,
672674
Name::Unknown { .. } => (),
673675
}
@@ -774,37 +776,33 @@ impl Printer {
774776

775777
fn print_type(&mut self, state: &mut State, ty: SubType) -> Result<()> {
776778
self.start_group("type ");
777-
self.print_name(&state.core.type_names, state.core.types.len() as u32)?;
779+
let ty_idx = state.core.types.len() as u32;
780+
self.print_name(&state.core.type_names, ty_idx)?;
778781
self.result.push(' ');
779-
self.print_sub(state, &ty, None)?;
782+
self.print_sub(state, &ty, ty_idx)?;
780783
self.end_group(); // `type`
781784
state.core.types.push(Some(ty));
782785
Ok(())
783786
}
784787

785-
fn print_sub(&mut self, state: &State, ty: &SubType, names_for: Option<u32>) -> Result<u32> {
788+
fn print_sub(&mut self, state: &State, ty: &SubType, ty_idx: u32) -> Result<u32> {
786789
let r = if !ty.is_final || !ty.supertype_idx.is_none() {
787790
self.start_group("sub");
788791
self.print_sub_type(state, ty)?;
789-
let r = self.print_composite(state, &ty.composite_type, names_for)?;
792+
let r = self.print_composite(state, &ty.composite_type, ty_idx)?;
790793
self.end_group(); // `sub`
791794
r
792795
} else {
793-
self.print_composite(state, &ty.composite_type, names_for)?
796+
self.print_composite(state, &ty.composite_type, ty_idx)?
794797
};
795798
Ok(r)
796799
}
797800

798-
fn print_composite(
799-
&mut self,
800-
state: &State,
801-
ty: &CompositeType,
802-
names_for: Option<u32>,
803-
) -> Result<u32> {
801+
fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
804802
let r = match &ty {
805803
CompositeType::Func(ty) => {
806804
self.start_group("func");
807-
let r = self.print_func_type(state, ty, names_for)?;
805+
let r = self.print_func_type(state, ty, None)?;
808806
self.end_group(); // `func`
809807
r
810808
}
@@ -816,7 +814,7 @@ impl Printer {
816814
}
817815
CompositeType::Struct(ty) => {
818816
self.start_group("struct");
819-
let r = self.print_struct_type(state, ty)?;
817+
let r = self.print_struct_type(state, ty, ty_idx)?;
820818
self.end_group(); // `struct`
821819
r
822820
}
@@ -904,8 +902,20 @@ impl Printer {
904902
Ok(ty.params().len() as u32)
905903
}
906904

907-
fn print_field_type(&mut self, state: &State, ty: &FieldType) -> Result<u32> {
905+
fn print_field_type(
906+
&mut self,
907+
state: &State,
908+
ty: &FieldType,
909+
ty_field_idx: Option<(u32, u32)>,
910+
) -> Result<u32> {
908911
self.result.push(' ');
912+
if let Some(idxs @ (_, field_idx)) = ty_field_idx {
913+
match state.core.field_names.index_to_name.get(&idxs) {
914+
Some(name) => write!(self.result, "${} ", name.identifier())?,
915+
None if self.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
916+
None => {}
917+
}
918+
}
909919
if ty.mutable {
910920
self.result.push_str("(mut ");
911921
}
@@ -917,13 +927,13 @@ impl Printer {
917927
}
918928

919929
fn print_array_type(&mut self, state: &State, ty: &ArrayType) -> Result<u32> {
920-
self.print_field_type(state, &ty.0)
930+
self.print_field_type(state, &ty.0, None)
921931
}
922932

923-
fn print_struct_type(&mut self, state: &State, ty: &StructType) -> Result<u32> {
924-
for field in ty.fields.iter() {
933+
fn print_struct_type(&mut self, state: &State, ty: &StructType, ty_idx: u32) -> Result<u32> {
934+
for (field_index, field) in ty.fields.iter().enumerate() {
925935
self.result.push_str(" (field");
926-
self.print_field_type(state, field)?;
936+
self.print_field_type(state, field, Some((ty_idx, field_index as u32)))?;
927937
self.result.push(')');
928938
}
929939
Ok(0)
@@ -1459,6 +1469,15 @@ impl Printer {
14591469
Ok(())
14601470
}
14611471

1472+
fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1473+
match state.core.field_names.index_to_name.get(&(ty, idx)) {
1474+
Some(name) => write!(self.result, "${}", name.identifier())?,
1475+
None if self.name_unnamed => write!(self.result, "$#field{idx}")?,
1476+
None => write!(self.result, "{}", idx)?,
1477+
}
1478+
Ok(())
1479+
}
1480+
14621481
fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
14631482
where
14641483
K: NamingNamespace,
@@ -3184,6 +3203,7 @@ naming_namespaces! {
31843203
struct NameTable => "table"
31853204
struct NameValue => "value"
31863205
struct NameType => "type"
3206+
struct NameField => "field"
31873207
struct NameData => "data"
31883208
struct NameElem => "elem"
31893209
struct NameComponent => "component"

crates/wasmprinter/src/operator.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,6 @@ impl<'a, 'b> PrintOperator<'a, 'b> {
254254
self.printer.print_idx(&self.state.core.type_names, idx)
255255
}
256256

257-
fn field_index(&mut self, idx: u32) -> Result<()> {
258-
write!(&mut self.printer.result, "{idx}")?;
259-
Ok(())
260-
}
261-
262257
fn from_ref_type(&mut self, ref_ty: RefType) -> Result<()> {
263258
self.printer.print_reftype(self.state, ref_ty)
264259
}
@@ -555,6 +550,30 @@ macro_rules! define_visit {
555550
.ok_or_else(|| anyhow!("implementation limit: type index too large"))?;
556551
$self.printer.print_reftype($self.state, rty)?;
557552
);
553+
(payload $self:ident StructGet $ty:ident $field:ident) => (
554+
$self.push_str(" ");
555+
$self.struct_type_index($ty)?;
556+
$self.push_str(" ");
557+
$self.printer.print_field_idx($self.state, $ty, $field)?;
558+
);
559+
(payload $self:ident StructGetS $ty:ident $field:ident) => (
560+
$self.push_str(" ");
561+
$self.struct_type_index($ty)?;
562+
$self.push_str(" ");
563+
$self.printer.print_field_idx($self.state, $ty, $field)?;
564+
);
565+
(payload $self:ident StructGetU $ty:ident $field:ident) => (
566+
$self.push_str(" ");
567+
$self.struct_type_index($ty)?;
568+
$self.push_str(" ");
569+
$self.printer.print_field_idx($self.state, $ty, $field)?;
570+
);
571+
(payload $self:ident StructSet $ty:ident $field:ident) => (
572+
$self.push_str(" ");
573+
$self.struct_type_index($ty)?;
574+
$self.push_str(" ");
575+
$self.printer.print_field_idx($self.state, $ty, $field)?;
576+
);
558577
(payload $self:ident $op:ident $($arg:ident)*) => (
559578
$(
560579
$self.push_str(" ");

crates/wast/src/core/binary.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ struct Names<'a> {
911911
data_idx: u32,
912912
elems: Vec<(u32, &'a str)>,
913913
elem_idx: u32,
914+
fields: Vec<(u32, Vec<(u32, &'a str)>)>,
914915
}
915916

916917
fn find_names<'a>(
@@ -1045,6 +1046,24 @@ fn find_names<'a>(
10451046
}
10461047
}
10471048

1049+
// Handle struct fields separately from above
1050+
if let ModuleField::Type(ty) = field {
1051+
let mut field_names = vec![];
1052+
match &ty.def {
1053+
TypeDef::Func(_) | TypeDef::Array(_) => {}
1054+
TypeDef::Struct(ty_struct) => {
1055+
for (idx, field) in ty_struct.fields.iter().enumerate() {
1056+
if let Some(name) = get_name(&field.id, &None) {
1057+
field_names.push((idx as u32, name))
1058+
}
1059+
}
1060+
}
1061+
}
1062+
if field_names.len() > 0 {
1063+
ret.fields.push((*idx, field_names))
1064+
}
1065+
}
1066+
10481067
*idx += 1;
10491068
}
10501069

@@ -1061,8 +1080,9 @@ impl Names<'_> {
10611080
&& self.memories.is_empty()
10621081
&& self.tables.is_empty()
10631082
&& self.types.is_empty()
1064-
&& self.data.is_empty()
10651083
&& self.elems.is_empty()
1084+
&& self.data.is_empty()
1085+
&& self.fields.is_empty()
10661086
&& self.tags.is_empty()
10671087
// NB: specifically don't check modules/instances since they're
10681088
// not encoded for now.
@@ -1119,6 +1139,10 @@ impl Encode for Names<'_> {
11191139
self.data.encode(&mut tmp);
11201140
subsec(9, &mut tmp);
11211141
}
1142+
if self.fields.len() > 0 {
1143+
self.fields.encode(&mut tmp);
1144+
subsec(10, &mut tmp);
1145+
}
11221146
if self.tags.len() > 0 {
11231147
self.tags.encode(&mut tmp);
11241148
subsec(11, &mut tmp);

fuzz/src/roundtrip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ fn validate_name_section(wasm: &[u8]) -> wasmparser::Result<()> {
8282
name?;
8383
}
8484
}
85-
Name::Local(n) | Name::Label(n) => {
85+
Name::Local(n) | Name::Label(n) | Name::Field(n) => {
8686
for name in n {
8787
for name in name?.names {
8888
name?;

src/bin/wasm-tools/demangle.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ impl Opts {
7373
Name::Data(names) => new_section.data(&self.name_map(names)?),
7474
Name::Local(names) => new_section.locals(&self.indirect_name_map(names)?),
7575
Name::Label(names) => new_section.labels(&self.indirect_name_map(names)?),
76+
Name::Field(names) => new_section.fields(&self.indirect_name_map(names)?),
7677
Name::Tag(names) => new_section.tags(&self.name_map(names)?),
7778
Name::Unknown { .. } => bail!("unknown name section"),
7879
}

src/bin/wasm-tools/dump.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ impl<'a> Dump<'a> {
566566
Name::Global(n) => self.print_name_map("global", n)?,
567567
Name::Element(n) => self.print_name_map("element", n)?,
568568
Name::Data(n) => self.print_name_map("data", n)?,
569+
Name::Field(n) => self.print_indirect_name_map("type", "field", n)?,
569570
Name::Tag(n) => self.print_name_map("tag", n)?,
570571
Name::Unknown { ty, range, .. } => {
571572
write!(self.state, "unknown names: {}", ty)?;

tests/local/gc/gc-struct-names.wat

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
;; --enable-gc
2+
3+
(module
4+
(type $named (struct (field $x i32) (field $y i32)))
5+
(type $partially_named (struct (field $x i32) (field i32)))
6+
(type $unnamed (struct (field i32) (field i32)))
7+
8+
(func (param (ref $named) (ref $partially_named) (ref $unnamed))
9+
i32.const 1
10+
i32.const 2
11+
struct.new $named
12+
local.tee 0
13+
struct.get $named 0
14+
local.get 0
15+
struct.get $named 1
16+
drop
17+
drop
18+
19+
i32.const 1
20+
i32.const 2
21+
struct.new $partially_named
22+
local.tee 1
23+
struct.get $partially_named 0
24+
local.get 1
25+
struct.get $partially_named 1
26+
drop
27+
drop
28+
29+
i32.const 1
30+
i32.const 2
31+
struct.new $unnamed
32+
local.tee 2
33+
struct.get $unnamed 0
34+
local.get 2
35+
struct.get $unnamed 1
36+
drop
37+
drop
38+
)
39+
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(module
2+
(type $named (;0;) (struct (field $x i32) (field $y i32)))
3+
(type $partially_named (;1;) (struct (field $x i32) (field i32)))
4+
(type $unnamed (;2;) (struct (field i32) (field i32)))
5+
(type (;3;) (func (param (ref $named) (ref $partially_named) (ref $unnamed))))
6+
(func (;0;) (type 3) (param (ref $named) (ref $partially_named) (ref $unnamed))
7+
i32.const 1
8+
i32.const 2
9+
struct.new $named
10+
local.tee 0
11+
struct.get $named $x
12+
local.get 0
13+
struct.get $named $y
14+
drop
15+
drop
16+
i32.const 1
17+
i32.const 2
18+
struct.new $partially_named
19+
local.tee 1
20+
struct.get $partially_named $x
21+
local.get 1
22+
struct.get $partially_named 1
23+
drop
24+
drop
25+
i32.const 1
26+
i32.const 2
27+
struct.new $unnamed
28+
local.tee 2
29+
struct.get $unnamed 0
30+
local.get 2
31+
struct.get $unnamed 1
32+
drop
33+
drop
34+
)
35+
)

0 commit comments

Comments
 (0)