Skip to content

Commit

Permalink
WIP type canonicalization
Browse files Browse the repository at this point in the history
  • Loading branch information
fitzgen committed Oct 30, 2023
1 parent 706f755 commit 7ce725d
Show file tree
Hide file tree
Showing 12 changed files with 1,168 additions and 287 deletions.
10 changes: 7 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/wasmparser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition.workspace = true
exclude = ["benches/*.wasm"]

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

Expand Down
66 changes: 47 additions & 19 deletions crates/wasmparser/src/define_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
//
// * It must implement `Into<u32>` and `From<u32>`
//
// * `$index_type::from(u32::from(index))` must be the identity function.
// * `$index_from_u32($u32_from_index(index))` must be the identity function.
//
// * `u32::from($index_type::from(x))` must also be the identity function.
// * `u32_from_index($index_from_u32(x))` must also be the identity function.
//
// * Its `u32` representation must fit within 20 bits, that is
// * Its `u32` representation must fit within 22 bits, that is
//
// index.into() <= (1 << 20) - 1
// index.into() <= (1 << 22) - 1
//
// must hold true for all indices.
macro_rules! define_core_wasm_types {
($index_type:ty) => {
($index_type:ty, $index_from_u32:expr, $u32_from_index:expr) => {
/// Represents a recursive type group in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct RecGroup {
Expand Down Expand Up @@ -58,6 +58,15 @@ macro_rules! define_core_wasm_types {
}
}

/// 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 {
RecGroupInner::Implicit(ty) => std::slice::from_mut(ty),
RecGroupInner::Explicit(types) => types,
}
}

/// Returns an owning iterator of all subtypes in this recursion
/// group.
pub fn into_types(self) -> impl ExactSizeIterator<Item = SubType> {
Expand Down Expand Up @@ -95,7 +104,7 @@ macro_rules! define_core_wasm_types {
}

/// Represents a subtype of possible other types in a WebAssembly module.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct SubType {
/// Is the subtype final.
pub is_final: bool,
Expand Down Expand Up @@ -129,7 +138,7 @@ macro_rules! define_core_wasm_types {
}

/// Represents a composite type in a WebAssembly module.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum CompositeType {
/// The type is for a function.
Func(FuncType),
Expand Down Expand Up @@ -221,12 +230,26 @@ macro_rules! define_core_wasm_types {
&self.params_results[..self.len_params]
}

/// Returns an exclusive slice to the parameter types of the
/// [`FuncType`].
#[inline]
pub(crate) fn params_mut(&mut self) -> &mut [ValType] {
&mut self.params_results[..self.len_params]
}

/// Returns a shared slice to the result types of the [`FuncType`].
#[inline]
pub fn results(&self) -> &[ValType] {
&self.params_results[self.len_params..]
}

/// Returns an exclusive slice to the result types of the
/// [`FuncType`].
#[inline]
pub(crate) fn results_mut(&mut self) -> &mut [ValType] {
&mut self.params_results[self.len_params..]
}

pub(crate) fn desc(&self) -> String {
let mut s = String::new();
s.push_str("[");
Expand All @@ -249,11 +272,11 @@ macro_rules! define_core_wasm_types {
}

/// Represents a type of an array in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ArrayType(pub FieldType);

/// Represents a field type of an array or a struct.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct FieldType {
/// Array element type.
pub element_type: StorageType,
Expand Down Expand Up @@ -359,7 +382,7 @@ macro_rules! define_core_wasm_types {
// It has the following internal structure:
//
// ```
// [nullable:u1 concrete==1:u1 unused:u2 index:u20]
// [nullable:u1 concrete==1:u1 index:u22]
// [nullable:u1 concrete==0:u1 abstype:u4 (unused):u18]
// ```
//
Expand Down Expand Up @@ -434,7 +457,7 @@ macro_rules! define_core_wasm_types {
fn can_fit_max_wasm_types_in_ref_type() {
fn can_roundtrip_index(index: u32) -> bool {
assert!(RefType::can_represent_type_index(index));
let rt = match RefType::concrete(true, index) {
let rt = match RefType::concrete(true, $index_from_u32(index)) {
Some(rt) => rt,
None => panic!(),
};
Expand All @@ -443,7 +466,7 @@ macro_rules! define_core_wasm_types {
Some(i) => i,
None => panic!(),
};
actual_index == index
$u32_from_index(actual_index) == index
}

assert!(can_roundtrip_index(crate::limits::MAX_WASM_TYPES as u32));
Expand All @@ -454,10 +477,12 @@ macro_rules! define_core_wasm_types {
}

impl RefType {
const NULLABLE_BIT: u32 = 1 << 23; // bit #23
const CONCRETE_BIT: u32 = 1 << 22; // bit #22
// These bits are valid for all `RefType`s.
const NULLABLE_BIT: u32 = 1 << 23;
const CONCRETE_BIT: u32 = 1 << 22;

const ABSTYPE_MASK: u32 = 0b1111 << 18; // 4 bits #21-#18 (if `concrete == 0`)
// The `abstype` field is valid only when `concrete == 0`.
const ABSTYPE_MASK: u32 = 0b1111 << 18;
const ANY_ABSTYPE: u32 = 0b1111 << 18;
const EQ_ABSTYPE: u32 = 0b1101 << 18;
const I31_ABSTYPE: u32 = 0b1000 << 18;
Expand All @@ -469,7 +494,8 @@ macro_rules! define_core_wasm_types {
const NOEXTERN_ABSTYPE: u32 = 0b0010 << 18;
const NONE_ABSTYPE: u32 = 0b0000 << 18;

const INDEX_MASK: u32 = (1 << 20) - 1; // 20 bits #19-#0 (if `concrete == 1`)
// The `index` is valid only when `concrete == 1`.
const INDEX_MASK: u32 = (1 << 22) - 1;

/// A nullable untyped function reference aka `(ref null func)` aka
/// `funcref` aka `anyfunc`.
Expand Down Expand Up @@ -560,7 +586,7 @@ macro_rules! define_core_wasm_types {
/// Returns `None` when the type index is beyond this crate's
/// implementation limits and therefore is not representable.
pub fn concrete(nullable: bool, index: $index_type) -> Option<Self> {
let index: u32 = index.into();
let index: u32 = $u32_from_index(index);
if Self::can_represent_type_index(index) {
let nullable32 = Self::NULLABLE_BIT * nullable as u32;
Some(RefType::from_u32(nullable32 | Self::CONCRETE_BIT | index))
Expand Down Expand Up @@ -596,17 +622,19 @@ macro_rules! define_core_wasm_types {
self.as_u32() & Self::CONCRETE_BIT != 0
}

/// If this is a reference to a typed function, get its type index.
/// If this is a reference to a concrete Wasm-defined type, get its
/// type index.
pub fn type_index(&self) -> Option<$index_type> {
if self.is_concrete_type_ref() {
let index = self.as_u32() & Self::INDEX_MASK;
Some(<$index_type>::from(index))
Some($index_from_u32(index))
} else {
None
}
}

const fn abstype(&self) -> u32 {
debug_assert!(!self.is_concrete_type_ref());
self.as_u32() & Self::ABSTYPE_MASK
}

Expand Down
Loading

0 comments on commit 7ce725d

Please sign in to comment.