Skip to content

Commit

Permalink
Add nullexnref and noexn types to exception-handling (bytecodeall…
Browse files Browse the repository at this point in the history
  • Loading branch information
eqrion authored Apr 3, 2024
1 parent 3710141 commit c85632b
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 21 deletions.
7 changes: 6 additions & 1 deletion crates/wasm-encoder/src/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,12 @@ pub enum HeapType {
/// The unboxed `i31` heap type.
I31,

/// The abstract` exception` heap type.
/// The abstract `exception` heap type.
Exn,

/// The abstract `noexn` heap type.
NoExn,

/// A concrete Wasm-defined type at the given index.
Concrete(u32),
}
Expand All @@ -471,6 +474,7 @@ impl Encode for HeapType {
HeapType::Array => sink.push(0x6A),
HeapType::I31 => sink.push(0x6C),
HeapType::Exn => sink.push(0x69),
HeapType::NoExn => sink.push(0x74),
// Note that this is encoded as a signed type rather than unsigned
// as it's decoded as an s33
HeapType::Concrete(i) => i64::from(*i).encode(sink),
Expand All @@ -496,6 +500,7 @@ impl TryFrom<wasmparser::HeapType> for HeapType {
wasmparser::HeapType::Array => HeapType::Array,
wasmparser::HeapType::I31 => HeapType::I31,
wasmparser::HeapType::Exn => HeapType::Exn,
wasmparser::HeapType::NoExn => HeapType::NoExn,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/wasm-mutate/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub fn map_ref_type(ref_ty: wasmparser::RefType) -> Result<RefType> {
wasmparser::HeapType::Array => HeapType::Array,
wasmparser::HeapType::I31 => HeapType::I31,
wasmparser::HeapType::Exn => HeapType::Exn,
wasmparser::HeapType::NoExn => HeapType::NoExn,
wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().unwrap()),
},
})
Expand Down
1 change: 1 addition & 0 deletions crates/wasm-mutate/src/mutators/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ pub fn heapty(t: &mut dyn Translator, ty: &wasmparser::HeapType) -> Result<HeapT
wasmparser::HeapType::Array => Ok(HeapType::Array),
wasmparser::HeapType::I31 => Ok(HeapType::I31),
wasmparser::HeapType::Exn => Ok(HeapType::Exn),
wasmparser::HeapType::NoExn => Ok(HeapType::NoExn),
wasmparser::HeapType::Concrete(i) => Ok(HeapType::Concrete(
t.remap(Item::Type, i.as_module_index().unwrap())?,
)),
Expand Down
16 changes: 10 additions & 6 deletions crates/wasm-smith/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ impl Module {
matches!(self.ty(b).composite_type, CompositeType::Func(_))
}

(HT::NoExn, HT::Exn) => true,

// Nothing else matches. (Avoid full wildcard matches so that
// adding/modifying variants is easier in the future.)
(HT::Concrete(_), _)
Expand All @@ -508,11 +510,9 @@ impl Module {
| (HT::Eq, _)
| (HT::Struct, _)
| (HT::Array, _)
| (HT::I31, _) => false,

// TODO: `exn` probably will be its own type hierarchy and will
// probably get `noexn` as well.
(HT::Exn, _) => false,
| (HT::I31, _)
| (HT::Exn, _)
| (HT::NoExn, _) => false,
}
}

Expand Down Expand Up @@ -781,7 +781,7 @@ impl Module {
HT::Extern => {
choices.push(HT::NoExtern);
}
HT::Exn | HT::None | HT::NoExtern | HT::NoFunc => {}
HT::Exn | HT::NoExn | HT::None | HT::NoExtern | HT::NoFunc => {}
}
Ok(*u.choose(&choices)?)
}
Expand Down Expand Up @@ -860,6 +860,9 @@ impl Module {
choices.extend(self.func_types.iter().copied().map(HT::Concrete));
choices.push(HT::Func);
}
HT::NoExn => {
choices.push(HT::Exn);
}
HT::Concrete(mut idx) => {
match &self
.types
Expand Down Expand Up @@ -1648,6 +1651,7 @@ impl Module {
wasmparser::HeapType::Array => HeapType::Array,
wasmparser::HeapType::I31 => HeapType::I31,
wasmparser::HeapType::Exn => HeapType::Exn,
wasmparser::HeapType::NoExn => HeapType::NoExn,
}
}

Expand Down
33 changes: 30 additions & 3 deletions crates/wasmparser/src/readers/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,8 @@ impl std::fmt::Debug for RefType {
(false, HeapType::Func) => write!(f, "(ref func)"),
(true, HeapType::Exn) => write!(f, "exnref"),
(false, HeapType::Exn) => write!(f, "(ref exn)"),
(true, HeapType::NoExn) => write!(f, "nullexnref"),
(false, HeapType::NoExn) => write!(f, "(ref noexn)"),
(true, HeapType::Concrete(idx)) => write!(f, "(ref null {idx})"),
(false, HeapType::Concrete(idx)) => write!(f, "(ref {idx})"),
}
Expand Down Expand Up @@ -928,6 +930,7 @@ impl RefType {
const EXTERN_ABSTYPE: u32 = 0b0011 << 18;
const NOEXTERN_ABSTYPE: u32 = 0b0010 << 18;
const EXN_ABSTYPE: u32 = 0b0001 << 18;
const NOEXN_ABSTYPE: u32 = 0b1110 << 18;
const NONE_ABSTYPE: u32 = 0b0000 << 18;

// The `index` is valid only when `concrete == 1`.
Expand Down Expand Up @@ -972,6 +975,10 @@ impl RefType {
/// `exnref`.
pub const EXNREF: Self = RefType::EXN.nullable();

/// A nullable reference to a noexn object aka `(ref null noexn)` aka
/// `nullexnref`.
pub const NULLEXNREF: Self = RefType::NOEXN.nullable();

/// A non-nullable untyped function reference aka `(ref func)`.
pub const FUNC: Self = RefType::from_u32(Self::FUNC_ABSTYPE);

Expand Down Expand Up @@ -1005,6 +1012,9 @@ impl RefType {
/// A non-nullable reference to an exn object aka `(ref exn)`.
pub const EXN: Self = RefType::from_u32(Self::EXN_ABSTYPE);

/// A non-nullable reference to a noexn object aka `(ref noexn)`.
pub const NOEXN: Self = RefType::from_u32(Self::NOEXN_ABSTYPE);

const fn can_represent_type_index(index: u32) -> bool {
index & Self::INDEX_MASK == index
}
Expand Down Expand Up @@ -1045,6 +1055,7 @@ impl RefType {
| Self::NOEXTERN_ABSTYPE
| Self::NONE_ABSTYPE
| Self::EXN_ABSTYPE
| Self::NOEXN_ABSTYPE
)
);

Expand Down Expand Up @@ -1083,6 +1094,7 @@ impl RefType {
HeapType::Array => Some(Self::from_u32(nullable32 | Self::ARRAY_ABSTYPE)),
HeapType::I31 => Some(Self::from_u32(nullable32 | Self::I31_ABSTYPE)),
HeapType::Exn => Some(Self::from_u32(nullable32 | Self::EXN_ABSTYPE)),
HeapType::NoExn => Some(Self::from_u32(nullable32 | Self::NOEXN_ABSTYPE)),
}
}

Expand Down Expand Up @@ -1179,6 +1191,7 @@ impl RefType {
Self::ARRAY_ABSTYPE => HeapType::Array,
Self::I31_ABSTYPE => HeapType::I31,
Self::EXN_ABSTYPE => HeapType::Exn,
Self::NOEXN_ABSTYPE => HeapType::NoExn,
_ => unreachable!(),
}
}
Expand All @@ -1200,6 +1213,7 @@ impl RefType {
(true, HeapType::Array) => "arrayref",
(true, HeapType::I31) => "i31ref",
(true, HeapType::Exn) => "exnref",
(true, HeapType::NoExn) => "nullexnref",
(false, HeapType::Func) => "(ref func)",
(false, HeapType::Extern) => "(ref extern)",
(false, HeapType::Concrete(_)) => "(ref $type)",
Expand All @@ -1212,6 +1226,7 @@ impl RefType {
(false, HeapType::Array) => "(ref array)",
(false, HeapType::I31) => "(ref i31)",
(false, HeapType::Exn) => "(ref exn)",
(false, HeapType::NoExn) => "(ref noexn)",
}
}
}
Expand Down Expand Up @@ -1297,13 +1312,20 @@ pub enum HeapType {
///
/// Introduced in the exception-handling proposal.
Exn,

/// The abstract `noexn` heap type.
///
/// The common subtype (a.k.a. bottom) of all exception types.
///
/// Introduced in the exception-handling proposal.
NoExn,
}

impl ValType {
pub(crate) fn is_valtype_byte(byte: u8) -> bool {
match byte {
0x7F | 0x7E | 0x7D | 0x7C | 0x7B | 0x70 | 0x6F | 0x64 | 0x63 | 0x6E | 0x71 | 0x72
| 0x73 | 0x6D | 0x6B | 0x6A | 0x6C | 0x69 => true,
| 0x74 | 0x73 | 0x6D | 0x6B | 0x6A | 0x6C | 0x69 => true,
_ => false,
}
}
Expand Down Expand Up @@ -1348,8 +1370,8 @@ impl<'a> FromReader<'a> for ValType {
reader.position += 1;
Ok(ValType::V128)
}
0x70 | 0x6F | 0x64 | 0x63 | 0x6E | 0x71 | 0x72 | 0x73 | 0x6D | 0x6B | 0x6A | 0x6C
| 0x69 => Ok(ValType::Ref(reader.read()?)),
0x70 | 0x6F | 0x64 | 0x63 | 0x6E | 0x71 | 0x72 | 0x73 | 0x74 | 0x6D | 0x6B | 0x6A
| 0x6C | 0x69 => Ok(ValType::Ref(reader.read()?)),
_ => bail!(reader.original_position(), "invalid value type"),
}
}
Expand All @@ -1369,6 +1391,7 @@ impl<'a> FromReader<'a> for RefType {
0x6A => Ok(RefType::ARRAY.nullable()),
0x6C => Ok(RefType::I31.nullable()),
0x69 => Ok(RefType::EXN.nullable()),
0x74 => Ok(RefType::NOEXN.nullable()),
byte @ (0x63 | 0x64) => {
let nullable = byte == 0x63;
let pos = reader.original_position();
Expand Down Expand Up @@ -1427,6 +1450,10 @@ impl<'a> FromReader<'a> for HeapType {
reader.position += 1;
Ok(HeapType::Exn)
}
0x74 => {
reader.position += 1;
Ok(HeapType::NoExn)
}
_ => {
let idx = match u32::try_from(reader.read_var_s33()?) {
Ok(idx) => idx,
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmparser/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ impl WasmFeatures {
}

// These types were added in the exception-handling proposal.
(HeapType::Exn, _) => {
(HeapType::Exn | HeapType::NoExn, _) => {
if self.exceptions {
Ok(())
} else {
Expand Down
3 changes: 2 additions & 1 deletion crates/wasmparser/src/validator/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,8 @@ impl Module {
| HeapType::Struct
| HeapType::Array
| HeapType::I31
| HeapType::Exn => return Ok(()),
| HeapType::Exn
| HeapType::NoExn => return Ok(()),
HeapType::Concrete(type_index) => type_index,
};
match type_index {
Expand Down
12 changes: 6 additions & 6 deletions crates/wasmparser/src/validator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,8 @@ impl TypeList {
matches!(subtype(b_group, b).composite_type, CompositeType::Func(_))
}

(HT::NoExn, HT::Exn) => true,

// Nothing else matches. (Avoid full wildcard matches so that
// adding/modifying variants is easier in the future.)
(HT::Concrete(_), _)
Expand All @@ -2707,11 +2709,9 @@ impl TypeList {
| (HT::Eq, _)
| (HT::Struct, _)
| (HT::Array, _)
| (HT::I31, _) => false,

// TODO: this probably isn't right, this is probably related to some
// gc type.
(HT::Exn, _) => false,
| (HT::I31, _)
| (HT::Exn, _)
| (HT::NoExn, _) => false,
}
}

Expand Down Expand Up @@ -2749,7 +2749,7 @@ impl TypeList {
| HeapType::Array
| HeapType::I31
| HeapType::None => HeapType::Any,
HeapType::Exn => HeapType::Exn,
HeapType::Exn | HeapType::NoExn => HeapType::Exn,
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/wasmprinter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ impl Printer {
RefType::STRUCT => self.result.push_str("structref"),
RefType::ARRAY => self.result.push_str("arrayref"),
RefType::EXN => self.result.push_str("exnref"),
RefType::NOEXN => self.result.push_str("nullexnref"),
_ => {
self.result.push_str("(ref null ");
self.print_heaptype(state, ty.heap_type())?;
Expand Down Expand Up @@ -996,6 +997,7 @@ impl Printer {
HeapType::Array => self.result.push_str("array"),
HeapType::I31 => self.result.push_str("i31"),
HeapType::Exn => self.result.push_str("exn"),
HeapType::NoExn => self.result.push_str("noexn"),
HeapType::Concrete(i) => {
self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
match r {
core::HeapType::Func => Self::Func,
core::HeapType::Extern => Self::Extern,
core::HeapType::Exn => {
core::HeapType::Exn | core::HeapType::NoExn => {
todo!("encoding of exceptions proposal types not yet implemented")
}
core::HeapType::Concrete(Index::Num(i, _)) => Self::Concrete(i),
Expand Down
3 changes: 2 additions & 1 deletion crates/wast/src/component/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,8 @@ impl<'a> Resolver<'a> {
| core::HeapType::Struct
| core::HeapType::None
| core::HeapType::NoFunc
| core::HeapType::NoExtern => {}
| core::HeapType::NoExtern
| core::HeapType::NoExn => {}
core::HeapType::Concrete(id) => {
self.resolve_ns(id, Ns::Type)?;
}
Expand Down
6 changes: 6 additions & 0 deletions crates/wast/src/core/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ impl<'a> Encode for HeapType<'a> {
HeapType::I31 => e.push(0x6c),
HeapType::NoFunc => e.push(0x73),
HeapType::NoExtern => e.push(0x72),
HeapType::NoExn => e.push(0x74),
HeapType::None => e.push(0x71),
// Note that this is encoded as a signed leb128 so be sure to cast
// to an i64 first
Expand Down Expand Up @@ -349,6 +350,11 @@ impl<'a> Encode for RefType<'a> {
nullable: true,
heap: HeapType::NoExtern,
} => e.push(0x72),
// The 'nullexnref' binary abbreviation
RefType {
nullable: true,
heap: HeapType::NoExn,
} => e.push(0x74),
// The 'nullref' binary abbreviation
RefType {
nullable: true,
Expand Down
18 changes: 18 additions & 0 deletions crates/wast/src/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ pub enum HeapType<'a> {
NoExtern,
/// The bottom type of the anyref hierarchy. Part of the GC proposal.
None,
/// The bottom type of the exnref hierarchy. Part of the exceptions proposal.
NoExn,
/// A reference to a concrete function, struct, or array type defined by
/// Wasm: `ref T`. This is part of the function references and GC proposals.
Concrete(Index<'a>),
Expand Down Expand Up @@ -124,6 +126,9 @@ impl<'a> Parse<'a> for HeapType<'a> {
} else if l.peek::<kw::noextern>()? {
parser.parse::<kw::noextern>()?;
Ok(HeapType::NoExtern)
} else if l.peek::<kw::noexn>()? {
parser.parse::<kw::noexn>()?;
Ok(HeapType::NoExn)
} else if l.peek::<kw::none>()? {
parser.parse::<kw::none>()?;
Ok(HeapType::None)
Expand All @@ -147,6 +152,7 @@ impl<'a> Peek for HeapType<'a> {
|| kw::i31::peek(cursor)?
|| kw::nofunc::peek(cursor)?
|| kw::noextern::peek(cursor)?
|| kw::noexn::peek(cursor)?
|| kw::none::peek(cursor)?
|| (LParen::peek(cursor)? && kw::r#type::peek2(cursor)?))
}
Expand Down Expand Up @@ -251,6 +257,14 @@ impl<'a> RefType<'a> {
heap: HeapType::None,
}
}

/// A `nullexnref` as an abbreviation for `(ref null noexn)`.
pub fn nullexnref() -> Self {
RefType {
nullable: true,
heap: HeapType::NoExn,
}
}
}

impl<'a> Parse<'a> for RefType<'a> {
Expand Down Expand Up @@ -286,6 +300,9 @@ impl<'a> Parse<'a> for RefType<'a> {
} else if l.peek::<kw::nullexternref>()? {
parser.parse::<kw::nullexternref>()?;
Ok(RefType::nullexternref())
} else if l.peek::<kw::nullexnref>()? {
parser.parse::<kw::nullexnref>()?;
Ok(RefType::nullexnref())
} else if l.peek::<kw::nullref>()? {
parser.parse::<kw::nullref>()?;
Ok(RefType::nullref())
Expand Down Expand Up @@ -327,6 +344,7 @@ impl<'a> Peek for RefType<'a> {
|| kw::i31ref::peek(cursor)?
|| kw::nullfuncref::peek(cursor)?
|| kw::nullexternref::peek(cursor)?
|| kw::nullexnref::peek(cursor)?
|| kw::nullref::peek(cursor)?
|| (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?))
}
Expand Down
Loading

0 comments on commit c85632b

Please sign in to comment.