Skip to content

Commit 230ce7f

Browse files
authored
Canonicalize types earlier in validation (#1299)
* Canonicalize types earlier in validation This commit refactors the internals of validation to centralize canonicalization in one location. This means that stages such as operator validation no longer need to perform canonicalization. Additionally types are always stored in their canonical forms. The refactoring here is done when a `RecGroup` is inserted into a `TypeList`. The rec-group-local offsets are used to intern the group but when actually adding to a `TypeList` all rec-group-local offsets are updated to an ID-based form. This is then plumbed in many other locations as well by changing many `t: ValType` validators to `t: &mut ValType` to internally canonicalize. This is originally motivated by trying to update Wasmtime to the latest `wasmparser` but many APIs which previously returned `&FuncType` for example returned `FuncType` instead due to the canonicalization-on-the-fly. This change means that the old `&FuncType`-style APIs can return because types are always canonicalized at-rest. This change additionally changes the behavior of one test. It was previously considered valid and is now considered valid. I've confirmed that `wasm-opt` considers the test invalid, so I've updated the test to `assert_invalid` instead. * Fix test compile * Remove unused arguments * Review comments
1 parent acee342 commit 230ce7f

File tree

14 files changed

+429
-585
lines changed

14 files changed

+429
-585
lines changed

Cargo.lock

Lines changed: 0 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/wasmparser/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ edition.workspace = true
1313
exclude = ["benches/*.wasm"]
1414

1515
[dependencies]
16-
hashbrown = { version = "0.14.2", default-features = false, features = ["ahash"] }
1716
indexmap = { workspace = true }
1817
semver = { workspace = true }
1918

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

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
* limitations under the License.
1414
*/
1515

16-
use std::fmt::{self, Debug, Write};
17-
1816
use crate::limits::{
1917
MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, MAX_WASM_STRUCT_FIELDS,
2018
MAX_WASM_SUPERTYPES, MAX_WASM_TYPES,
2119
};
2220
use crate::types::CoreTypeId;
2321
use crate::{BinaryReader, BinaryReaderError, FromReader, Result, SectionLimited};
22+
use std::fmt::{self, Debug, Write};
23+
use std::hash::{Hash, Hasher};
2424

2525
mod matches;
2626
pub(crate) use self::matches::{Matches, WithRecGroup};
@@ -384,6 +384,20 @@ impl RecGroup {
384384
}
385385
}
386386

387+
impl Hash for RecGroup {
388+
fn hash<H: Hasher>(&self, hasher: &mut H) {
389+
self.types().hash(hasher)
390+
}
391+
}
392+
393+
impl PartialEq for RecGroup {
394+
fn eq(&self, other: &RecGroup) -> bool {
395+
self.types() == other.types()
396+
}
397+
}
398+
399+
impl Eq for RecGroup {}
400+
387401
/// Represents a subtype of possible other types in a WebAssembly module.
388402
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
389403
pub struct SubType {
@@ -416,6 +430,35 @@ impl SubType {
416430
pub fn unwrap_struct(&self) -> &StructType {
417431
self.composite_type.unwrap_struct()
418432
}
433+
434+
/// Maps any `UnpackedIndex` via the specified closure.
435+
pub(crate) fn remap_indices(
436+
&mut self,
437+
f: &mut dyn FnMut(&mut PackedIndex) -> Result<()>,
438+
) -> Result<()> {
439+
if let Some(idx) = &mut self.supertype_idx {
440+
f(idx)?;
441+
}
442+
match &mut self.composite_type {
443+
CompositeType::Func(ty) => {
444+
for ty in ty.params_mut() {
445+
ty.remap_indices(f)?;
446+
}
447+
for ty in ty.results_mut() {
448+
ty.remap_indices(f)?;
449+
}
450+
}
451+
CompositeType::Array(ty) => {
452+
ty.0.remap_indices(f)?;
453+
}
454+
CompositeType::Struct(ty) => {
455+
for field in ty.fields.iter_mut() {
456+
field.remap_indices(f)?;
457+
}
458+
}
459+
}
460+
Ok(())
461+
}
419462
}
420463

421464
/// Represents a composite type in a WebAssembly module.
@@ -562,6 +605,19 @@ pub struct FieldType {
562605
pub mutable: bool,
563606
}
564607

608+
impl FieldType {
609+
/// Maps any `UnpackedIndex` via the specified closure.
610+
pub(crate) fn remap_indices(
611+
&mut self,
612+
f: &mut dyn FnMut(&mut PackedIndex) -> Result<()>,
613+
) -> Result<()> {
614+
match &mut self.element_type {
615+
StorageType::I8 | StorageType::I16 => Ok(()),
616+
StorageType::Val(ty) => ty.remap_indices(f),
617+
}
618+
}
619+
}
620+
565621
/// Represents storage types introduced in the GC spec for array and struct fields.
566622
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
567623
pub enum StorageType {
@@ -640,6 +696,23 @@ impl ValType {
640696
Self::Ref(rt) => rt.is_nullable(),
641697
}
642698
}
699+
700+
/// Maps any `UnpackedIndex` via the specified closure.
701+
pub(crate) fn remap_indices(
702+
&mut self,
703+
map: &mut dyn FnMut(&mut PackedIndex) -> Result<()>,
704+
) -> Result<()> {
705+
match self {
706+
ValType::Ref(r) => {
707+
if let Some(mut idx) = r.type_index() {
708+
map(&mut idx)?;
709+
*r = RefType::concrete(r.is_nullable(), idx);
710+
}
711+
}
712+
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
713+
}
714+
Ok(())
715+
}
643716
}
644717

645718
/// A reference type.

0 commit comments

Comments
 (0)