Skip to content

Commit

Permalink
dump: Better printing of rec groups and sub types (#1379)
Browse files Browse the repository at this point in the history
* dump: Better printing of rec groups and sub types

Still not perfect, but good enough for now. Follow up improvements always
welcome.

Fixes #1359

* review feedback
  • Loading branch information
fitzgen authored Jan 18, 2024
1 parent aaf941d commit 2210c57
Show file tree
Hide file tree
Showing 16 changed files with 172 additions and 54 deletions.
2 changes: 1 addition & 1 deletion crates/wasmparser/src/binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1809,7 +1809,7 @@ impl<'a> VisitOperator<'a> for OperatorFactory<'a> {
/// Iterator returned from [`BinaryReader::read_iter`].
pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> {
remaining: usize,
reader: &'me mut BinaryReader<'a>,
pub(crate) reader: &'me mut BinaryReader<'a>,
_marker: marker::PhantomData<T>,
}

Expand Down
67 changes: 45 additions & 22 deletions crates/wasmparser/src/readers/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,65 +306,73 @@ pub struct RecGroup {

#[derive(Debug, Clone)]
enum RecGroupInner {
Implicit(SubType),
Explicit(Vec<SubType>),
Implicit((usize, SubType)),
Explicit(Vec<(usize, SubType)>),
}

impl RecGroup {
/// Create an explicit `RecGroup` for the given types.
pub(crate) fn explicit(types: Vec<SubType>) -> Self {
pub(crate) fn explicit(types: Vec<(usize, SubType)>) -> Self {
RecGroup {
inner: RecGroupInner::Explicit(types),
}
}

/// Create an implicit `RecGroup` for a type that was not contained
/// in a `(rec ...)`.
pub(crate) fn implicit(ty: SubType) -> Self {
pub(crate) fn implicit(offset: usize, ty: SubType) -> Self {
RecGroup {
inner: RecGroupInner::Implicit(ty),
inner: RecGroupInner::Implicit((offset, ty)),
}
}

/// Is this an explicit recursion group?
pub fn is_explicit_rec_group(&self) -> bool {
matches!(self.inner, RecGroupInner::Explicit(_))
matches!(self.inner, RecGroupInner::Explicit(..))
}

/// Returns the list of subtypes in the recursive type group.
pub fn types(&self) -> &[SubType] {
match &self.inner {
pub fn types(&self) -> impl ExactSizeIterator<Item = &SubType> + '_ {
let types = match &self.inner {
RecGroupInner::Implicit(ty) => std::slice::from_ref(ty),
RecGroupInner::Explicit(types) => types,
}
};
types.iter().map(|(_, ty)| ty)
}

/// Return a mutable borrow of the list of subtypes in this
/// recursive type group.
pub(crate) fn types_mut(&mut self) -> &mut [SubType] {
match &mut self.inner {
pub(crate) fn types_mut(&mut self) -> impl ExactSizeIterator<Item = &mut SubType> + '_ {
let types = match &mut self.inner {
RecGroupInner::Implicit(ty) => std::slice::from_mut(ty),
RecGroupInner::Explicit(types) => types,
}
};
types.iter_mut().map(|(_, ty)| ty)
}

/// Returns an owning iterator of all subtypes in this recursion
/// group.
pub fn into_types(self) -> impl ExactSizeIterator<Item = SubType> {
self.into_types_and_offsets().map(|(_, ty)| ty)
}

/// Returns an owning iterator of all subtypes in this recursion
/// group, along with their offset.
pub fn into_types_and_offsets(self) -> impl ExactSizeIterator<Item = (usize, SubType)> {
return match self.inner {
RecGroupInner::Implicit(ty) => Iter::Implicit(Some(ty)),
RecGroupInner::Implicit(tup) => Iter::Implicit(Some(tup)),
RecGroupInner::Explicit(types) => Iter::Explicit(types.into_iter()),
};

enum Iter {
Implicit(Option<SubType>),
Explicit(std::vec::IntoIter<SubType>),
Implicit(Option<(usize, SubType)>),
Explicit(std::vec::IntoIter<(usize, SubType)>),
}

impl Iterator for Iter {
type Item = SubType;
type Item = (usize, SubType);

fn next(&mut self) -> Option<SubType> {
fn next(&mut self) -> Option<(usize, SubType)> {
match self {
Self::Implicit(ty) => ty.take(),
Self::Explicit(types) => types.next(),
Expand All @@ -386,13 +394,19 @@ impl RecGroup {

impl Hash for RecGroup {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.types().hash(hasher)
let types = self.types();
types.len().hash(hasher);
for ty in types {
ty.hash(hasher);
}
}
}

impl PartialEq for RecGroup {
fn eq(&self, other: &RecGroup) -> bool {
self.types() == other.types()
let self_tys = self.types();
let other_tys = other.types();
self_tys.len() == other_tys.len() && self_tys.zip(other_tys).all(|(a, b)| a == b)
}
}

Expand Down Expand Up @@ -1533,10 +1547,19 @@ impl<'a> FromReader<'a> for RecGroup {
match reader.peek()? {
0x4e => {
reader.read_u8()?;
let types = reader.read_iter(MAX_WASM_TYPES, "rec group types")?;
Ok(RecGroup::explicit(types.collect::<Result<_>>()?))
let mut iter = reader.read_iter(MAX_WASM_TYPES, "rec group types")?;
let mut types = Vec::with_capacity(iter.size_hint().0);
let mut offset = iter.reader.original_position();
while let Some(ty) = iter.next() {
types.push((offset, ty?));
offset = iter.reader.original_position();
}
Ok(RecGroup::explicit(types))
}
_ => Ok(RecGroup::implicit(reader.read()?)),
_ => Ok(RecGroup::implicit(
reader.original_position(),
reader.read()?,
)),
}
}
}
Expand Down
23 changes: 17 additions & 6 deletions crates/wasmparser/src/validator/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ impl ComponentState {
) -> Result<()> {
let id = match ty {
crate::CoreType::Sub(sub) => {
let (_is_new, group_id) = types.intern_canonical_rec_group(RecGroup::implicit(sub));
let (_is_new, group_id) =
types.intern_canonical_rec_group(RecGroup::implicit(offset, sub));
let id = types[group_id].start;
ComponentCoreTypeId::Sub(id)
}
Expand Down Expand Up @@ -1010,7 +1011,8 @@ impl ComponentState {
composite_type: CompositeType::Func(info.into_func_type()),
};

let (_is_new, group_id) = types.intern_canonical_rec_group(RecGroup::implicit(lowered_ty));
let (_is_new, group_id) =
types.intern_canonical_rec_group(RecGroup::implicit(offset, lowered_ty));
let id = types[group_id].start;
self.core_funcs.push(id);

Expand All @@ -1029,7 +1031,8 @@ impl ComponentState {
supertype_idx: None,
composite_type: CompositeType::Func(FuncType::new([rep], [ValType::I32])),
};
let (_is_new, group_id) = types.intern_canonical_rec_group(RecGroup::implicit(core_ty));
let (_is_new, group_id) =
types.intern_canonical_rec_group(RecGroup::implicit(offset, core_ty));
let id = types[group_id].start;
self.core_funcs.push(id);
Ok(())
Expand All @@ -1047,7 +1050,8 @@ impl ComponentState {
supertype_idx: None,
composite_type: CompositeType::Func(FuncType::new([ValType::I32], [])),
};
let (_is_new, group_id) = types.intern_canonical_rec_group(RecGroup::implicit(core_ty));
let (_is_new, group_id) =
types.intern_canonical_rec_group(RecGroup::implicit(offset, core_ty));
let id = types[group_id].start;
self.core_funcs.push(id);
Ok(())
Expand All @@ -1065,7 +1069,8 @@ impl ComponentState {
supertype_idx: None,
composite_type: CompositeType::Func(FuncType::new([ValType::I32], [rep])),
};
let (_is_new, group_id) = types.intern_canonical_rec_group(RecGroup::implicit(core_ty));
let (_is_new, group_id) =
types.intern_canonical_rec_group(RecGroup::implicit(offset, core_ty));
let id = types[group_id].start;
self.core_funcs.push(id);
Ok(())
Expand Down Expand Up @@ -1485,7 +1490,13 @@ impl ComponentState {
for decl in decls {
match decl {
crate::ModuleTypeDeclaration::Type(ty) => {
state.add_types(RecGroup::implicit(ty), features, types, offset, true)?;
state.add_types(
RecGroup::implicit(offset, ty),
features,
types,
offset,
true,
)?;
}
crate::ModuleTypeDeclaration::Export { name, mut ty } => {
let ty = state.check_type_ref(&mut ty, features, types, offset)?;
Expand Down
6 changes: 3 additions & 3 deletions crates/wasmparser/src/validator/core/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ impl<'a> TypeCanonicalizer<'a> {
self.rec_group_start = u32::try_from(self.module.types.len()).unwrap();
self.rec_group_len = u32::try_from(rec_group.types().len()).unwrap();

for (rec_group_index, ty) in rec_group.types_mut().iter_mut().enumerate() {
let rec_group_index = u32::try_from(rec_group_index).unwrap();
let type_index = self.rec_group_start + rec_group_index;
for (rec_group_local_index, ty) in rec_group.types_mut().enumerate() {
let rec_group_local_index = u32::try_from(rec_group_local_index).unwrap();
let type_index = self.rec_group_start + rec_group_local_index;

if let Some(sup) = ty.supertype_idx.as_mut() {
if sup.as_module_index().map_or(false, |i| i >= type_index) {
Expand Down
14 changes: 12 additions & 2 deletions src/bin/wasm-tools/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct Indices {
core_tags: u32,
core_modules: u32,
core_instances: u32,
rec_groups: u32,

// Component indexes
types: u32,
Expand Down Expand Up @@ -101,8 +102,17 @@ impl<'a> Dump<'a> {
write!(self.state, "version {} ({:?})", num, encoding)?;
self.color_print(range.end)?;
}
Payload::TypeSection(s) => self.section(s, "type", |me, end, t| {
write!(me.state, "[type {}] {:?}", inc(&mut i.core_types), t)?;
Payload::TypeSection(s) => self.section(s, "type", |me, end, rec_group| {
let rec_group_index = inc(&mut i.rec_groups);
let explicit = rec_group.is_explicit_rec_group();
let kind = if explicit { "explicit" } else { "implicit" };
writeln!(me.dst, "--- rec group {rec_group_index} ({kind}) ---")?;
for (offset, ty) in rec_group.into_types_and_offsets() {
if explicit {
me.print(offset)?;
}
write!(me.state, "[type {}] {ty:?}", inc(&mut i.core_types))?;
}
me.print(end)
})?,
Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| {
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/dump/alias.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
| 01 00 00 00
0x57 | 01 04 | type section
0x59 | 01 | 1 count
0x5a | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x5a | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x5d | 03 02 | func section
0x5f | 01 | 1 count
0x60 | 00 | [func 0] type 0
Expand Down
6 changes: 4 additions & 2 deletions tests/cli/dump/alias2.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@
| 01 00 00 00
0x158 | 01 04 | type section
0x15a | 01 | 1 count
0x15b | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x15b | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x15e | 03 02 | func section
0x160 | 01 | 1 count
0x161 | 00 | [func 0] type 0
Expand Down Expand Up @@ -162,7 +163,8 @@
| 01 00 00 00
0x1a2 | 01 04 | type section
0x1a4 | 01 | 1 count
0x1a5 | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x1a5 | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x1a8 | 02 19 | import section
0x1aa | 04 | 4 count
0x1ab | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) }
Expand Down
15 changes: 10 additions & 5 deletions tests/cli/dump/blockty.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
| 01 00 00 00
0x8 | 01 17 | type section
0xa | 05 | 5 count
0xb | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
0xe | 60 00 01 7f | [type 1] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [I32] }) }) }
0x12 | 60 01 7f 00 | [type 2] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [] }) }) }
0x16 | 60 01 7f 01 | [type 3] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [I32] }) }) }
--- rec group 0 (implicit) ---
0xb | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
--- rec group 1 (implicit) ---
0xe | 60 00 01 7f | [type 1] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [I32] }) }
--- rec group 2 (implicit) ---
0x12 | 60 01 7f 00 | [type 2] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [] }) }
--- rec group 3 (implicit) ---
0x16 | 60 01 7f 01 | [type 3] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [I32] }) }
| 7f
0x1b | 60 01 7f 02 | [type 4] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [I32, I32] }) }) }
--- rec group 4 (implicit) ---
0x1b | 60 01 7f 02 | [type 4] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [I32, I32] }) }
| 7f 7f
0x21 | 03 02 | func section
0x23 | 01 | 1 count
Expand Down
15 changes: 10 additions & 5 deletions tests/cli/dump/bundled.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
| 01 00 00 00
0x54 | 01 09 | type section
0x56 | 01 | 1 count
0x57 | 60 04 7f 7f | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32, I32, I32], results: [I32] }) }) }
--- rec group 0 (implicit) ---
0x57 | 60 04 7f 7f | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32, I32, I32], results: [I32] }) }
| 7f 7f 01 7f
0x5f | 03 02 | func section
0x61 | 01 | 1 count
Expand Down Expand Up @@ -61,9 +62,11 @@
| 01 00 00 00
0xa0 | 01 09 | type section
0xa2 | 02 | 2 count
0xa3 | 60 02 7f 7f | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32], results: [] }) }) }
--- rec group 0 (implicit) ---
0xa3 | 60 02 7f 7f | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32], results: [] }) }
| 00
0xa8 | 60 00 00 | [type 1] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 1 (implicit) ---
0xa8 | 60 00 00 | [type 1] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0xab | 02 12 | import section
0xad | 01 | 1 count
0xae | 09 77 61 73 | import [func 0] Import { module: "wasi-file", name: "read", ty: Func(0) }
Expand Down Expand Up @@ -103,9 +106,11 @@
| 01 00 00 00
0x101 | 01 0c | type section
0x103 | 02 | 2 count
0x104 | 60 02 7f 7f | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32], results: [] }) }) }
--- rec group 0 (implicit) ---
0x104 | 60 02 7f 7f | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32], results: [] }) }
| 00
0x109 | 60 03 7f 7f | [type 1] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32, I32], results: [] }) }) }
--- rec group 1 (implicit) ---
0x109 | 60 03 7f 7f | [type 1] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32, I32, I32], results: [] }) }
| 7f 00
0x10f | 02 12 | import section
0x111 | 01 | 1 count
Expand Down
6 changes: 4 additions & 2 deletions tests/cli/dump/component-expand-bundle.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
| 01 00 00 00
0x12 | 01 04 | type section
0x14 | 01 | 1 count
0x15 | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x15 | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x18 | 03 02 | func section
0x1a | 01 | 1 count
0x1b | 00 | [func 0] type 0
Expand All @@ -28,7 +29,8 @@
| 01 00 00 00
0x3d | 01 04 | type section
0x3f | 01 | 1 count
0x40 | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x40 | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x43 | 02 06 | import section
0x45 | 01 | 1 count
0x46 | 00 01 61 00 | import [func 0] Import { module: "", name: "a", ty: Func(0) }
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/dump/import-modules.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
| 01 00 00 00
0x2a | 01 04 | type section
0x2c | 01 | 1 count
0x2d | 60 00 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }) }
--- rec group 0 (implicit) ---
0x2d | 60 00 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [], results: [] }) }
0x30 | 03 02 | func section
0x32 | 01 | 1 count
0x33 | 00 | [func 0] type 0
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/dump/names.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
| 01 00 00 00
0x8 | 01 05 | type section
0xa | 01 | 1 count
0xb | 60 01 7f 00 | [type 0] RecGroup { inner: Implicit(SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [] }) }) }
--- rec group 0 (implicit) ---
0xb | 60 01 7f 00 | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: Func(FuncType { params: [I32], results: [] }) }
0xf | 03 02 | func section
0x11 | 01 | 1 count
0x12 | 00 | [func 0] type 0
Expand Down
Loading

0 comments on commit 2210c57

Please sign in to comment.