Skip to content

Commit

Permalink
dump: Better printing of rec groups and sub types
Browse files Browse the repository at this point in the history
Still not perfect, but good enough for now. Follow up improvements always
welcome.

Fixes bytecodealliance#1359
  • Loading branch information
fitzgen committed Jan 18, 2024
1 parent eced912 commit c11da2b
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 51 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
90 changes: 71 additions & 19 deletions crates/wasmparser/src/readers/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,65 +306,102 @@ 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> {
return match self.inner {
RecGroupInner::Implicit(ty) => Iter::Implicit(Some(ty)),
RecGroupInner::Implicit((_, ty)) => Iter::Implicit(Some(ty)),
RecGroupInner::Explicit(types) => Iter::Explicit(types.into_iter()),
};

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

impl Iterator for Iter {
type Item = SubType;

fn next(&mut self) -> Option<SubType> {
match self {
Self::Implicit(ty) => ty.take(),
Self::Explicit(types) => types.next().map(|(_, ty)| ty),
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::Implicit(None) => (0, Some(0)),
Self::Implicit(Some(_)) => (1, Some(1)),
Self::Explicit(types) => types.size_hint(),
}
}
}

impl ExactSizeIterator for Iter {}
}

/// 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(tup) => Iter::Implicit(Some(tup)),
RecGroupInner::Explicit(types) => Iter::Explicit(types.into_iter()),
};

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

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

fn next(&mut self) -> Option<(usize, SubType)> {
match self {
Self::Implicit(ty) => ty.take(),
Self::Explicit(types) => types.next(),
Expand All @@ -386,13 +423,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 +1576,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
12 changes: 11 additions & 1 deletion tests/cli/dump/alias.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@
| 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
24 changes: 22 additions & 2 deletions tests/cli/dump/alias2.wat.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,17 @@
| 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 +172,17 @@
| 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
Loading

0 comments on commit c11da2b

Please sign in to comment.