Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wast: Add exnref, try_table, and throw_ref #1225

Merged
merged 3 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,9 @@ impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
match r {
core::HeapType::Func => Self::Func,
core::HeapType::Extern => Self::Extern,
core::HeapType::Exn => {
todo!("encoding of exceptions proposal types not yet implemented")
}
core::HeapType::Index(Index::Num(i, _)) => Self::Indexed(i),
core::HeapType::Index(_) => panic!("unresolved index"),
core::HeapType::Any
Expand Down
1 change: 1 addition & 0 deletions crates/wast/src/component/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ impl<'a> Resolver<'a> {
ValType::Ref(r) => match &mut r.heap {
core::HeapType::Func
| core::HeapType::Extern
| core::HeapType::Exn
| core::HeapType::Any
| core::HeapType::Eq
| core::HeapType::Array
Expand Down
47 changes: 47 additions & 0 deletions crates/wast/src/core/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl<'a> Encode for HeapType<'a> {
match self {
HeapType::Func => e.push(0x70),
HeapType::Extern => e.push(0x6f),
HeapType::Exn => e.push(0x69),
HeapType::Any => e.push(0x6e),
HeapType::Eq => e.push(0x6d),
HeapType::Struct => e.push(0x6b),
Expand Down Expand Up @@ -277,6 +278,11 @@ impl<'a> Encode for RefType<'a> {
nullable: true,
heap: HeapType::Extern,
} => e.push(0x6f),
// The 'exnref' binary abbreviation
RefType {
nullable: true,
heap: HeapType::Exn,
} => e.push(0x69),
// The 'eqref' binary abbreviation
RefType {
nullable: true,
Expand Down Expand Up @@ -1028,6 +1034,47 @@ impl Encode for Id<'_> {
}
}

impl<'a> Encode for TryTable<'a> {
fn encode(&self, dst: &mut Vec<u8>) {
self.block.encode(dst);
self.catches.encode(dst);

let catch_all_flag_byte: u8 = match self.catch_all {
None => 0,
Some(TryTableCatchAll {
kind: TryTableCatchKind::Drop,
..
}) => 1,
Some(TryTableCatchAll {
kind: TryTableCatchKind::Ref,
..
}) => 2,
};
catch_all_flag_byte.encode(dst);
if let Some(catch_all) = &self.catch_all {
catch_all.encode(dst);
}
}
}

impl<'a> Encode for TryTableCatch<'a> {
fn encode(&self, dst: &mut Vec<u8>) {
let catch_flag_byte: u8 = match self.kind {
TryTableCatchKind::Drop => 0,
TryTableCatchKind::Ref => 1,
};
catch_flag_byte.encode(dst);
self.tag.encode(dst);
self.label.encode(dst);
}
}

impl<'a> Encode for TryTableCatchAll<'a> {
fn encode(&self, dst: &mut Vec<u8>) {
self.label.encode(dst);
}
}

impl Encode for V128Const {
fn encode(&self, dst: &mut Vec<u8>) {
dst.extend_from_slice(&self.to_le_bytes());
Expand Down
83 changes: 83 additions & 0 deletions crates/wast/src/core/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,10 @@ instructions! {
Delegate(Index<'a>) : [0x18] : "delegate",
CatchAll : [0x19] : "catch_all",

// Exception handling proposal extension for 'exnref'
ThrowRef : [0x0a] : "throw_ref",
TryTable(TryTable<'a>) : [0x1f] : "try_table",

// Relaxed SIMD proposal
I8x16RelaxedSwizzle : [0xfd, 0x100]: "i8x16.relaxed_swizzle",
I32x4RelaxedTruncF32x4S : [0xfd, 0x101]: "i32x4.relaxed_trunc_f32x4_s",
Expand Down Expand Up @@ -1219,6 +1223,85 @@ impl<'a> Parse<'a> for BlockType<'a> {
}
}

#[derive(Debug)]
#[allow(missing_docs)]
pub struct TryTable<'a> {
pub block: Box<BlockType<'a>>,
pub catches: Vec<TryTableCatch<'a>>,
pub catch_all: Option<TryTableCatchAll<'a>>,
}

impl<'a> Parse<'a> for TryTable<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let block = parser.parse()?;

let mut catches = Vec::new();
while parser.peek2::<kw::catch>()? || parser.peek2::<kw::catch_ref>()? {
catches.push(parser.parens(|p| {
let kind = if parser.peek::<kw::catch_ref>()? {
p.parse::<kw::catch_ref>()?;
TryTableCatchKind::Ref
} else {
p.parse::<kw::catch>()?;
TryTableCatchKind::Drop
};
Ok(TryTableCatch {
kind,
tag: p.parse()?,
label: p.parse()?,
})
})?);
}

let mut catch_all = None;
if parser.peek2::<kw::catch_all>()? || parser.peek2::<kw::catch_all_ref>()? {
catch_all = Some(parser.parens(|p| {
let kind = if parser.peek::<kw::catch_all_ref>()? {
p.parse::<kw::catch_all_ref>()?;
TryTableCatchKind::Ref
} else {
p.parse::<kw::catch_all>()?;
TryTableCatchKind::Drop
};
Ok(TryTableCatchAll {
kind,
label: p.parse()?,
})
})?);
}

Ok(TryTable {
block,
catches,
catch_all,
})
}
}

#[derive(Debug)]
#[allow(missing_docs)]
pub enum TryTableCatchKind {
// Capture the exnref for the try
Ref,
// Drop the exnref for the try
Drop,
}

#[derive(Debug)]
#[allow(missing_docs)]
pub struct TryTableCatch<'a> {
pub kind: TryTableCatchKind,
pub tag: Index<'a>,
pub label: Index<'a>,
}

#[derive(Debug)]
#[allow(missing_docs)]
pub struct TryTableCatchAll<'a> {
pub kind: TryTableCatchKind,
pub label: Index<'a>,
}

/// Extra information associated with the func.bind instruction.
#[derive(Debug)]
#[allow(missing_docs)]
Expand Down
14 changes: 14 additions & 0 deletions crates/wast/src/core/resolve/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,20 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
});
self.resolve_block_type(bt)?;
}
TryTable(try_table) => {
self.blocks.push(ExprBlock {
label: try_table.block.label,
pushed_scope: false,
});
self.resolve_block_type(&mut try_table.block)?;
for catch in &mut try_table.catches {
self.resolver.resolve(&mut catch.tag, Ns::Tag)?;
self.resolve_label(&mut catch.label)?;
}
if let Some(catch_all) = &mut try_table.catch_all {
self.resolve_label(&mut catch_all.label)?;
}
}

// On `End` instructions we pop a label from the stack, and for both
// `End` and `Else` instructions if they have labels listed we
Expand Down
3 changes: 2 additions & 1 deletion crates/wast/src/core/resolve/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ impl<'a> Expander<'a> {
| Instruction::If(bt)
| Instruction::Loop(bt)
| Instruction::Let(LetType { block: bt, .. })
| Instruction::Try(bt) => {
| Instruction::Try(bt)
| Instruction::TryTable(TryTable { block: bt, .. }) => {
// No expansion necessary, a type reference is already here.
// We'll verify that it's the same as the inline type, if any,
// later.
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 @@ -66,6 +66,8 @@ pub enum HeapType<'a> {
/// A reference to any host value: externref. This is part of the reference
/// types proposal.
Extern,
/// A reference to a wasm exception. This is part of the exceptions proposal.
Exn,
/// A reference to any reference value: anyref. This is part of the GC
/// proposal.
Any,
Expand Down Expand Up @@ -98,6 +100,9 @@ impl<'a> Parse<'a> for HeapType<'a> {
} else if l.peek::<kw::r#extern>()? {
parser.parse::<kw::r#extern>()?;
Ok(HeapType::Extern)
} else if l.peek::<kw::exn>()? {
parser.parse::<kw::exn>()?;
Ok(HeapType::Exn)
} else if l.peek::<kw::r#any>()? {
parser.parse::<kw::r#any>()?;
Ok(HeapType::Any)
Expand Down Expand Up @@ -134,6 +139,7 @@ impl<'a> Peek for HeapType<'a> {
fn peek(cursor: Cursor<'_>) -> Result<bool> {
Ok(kw::func::peek(cursor)?
|| kw::r#extern::peek(cursor)?
|| kw::exn::peek(cursor)?
|| kw::any::peek(cursor)?
|| kw::eq::peek(cursor)?
|| kw::r#struct::peek(cursor)?
Expand Down Expand Up @@ -174,6 +180,14 @@ impl<'a> RefType<'a> {
}
}

/// An `exnrefr` as an abbreviation for `(ref null exn)`.
pub fn exn() -> Self {
RefType {
nullable: true,
heap: HeapType::Exn,
}
}

/// An `anyref` as an abbreviation for `(ref null any)`.
pub fn any() -> Self {
RefType {
Expand Down Expand Up @@ -251,6 +265,9 @@ impl<'a> Parse<'a> for RefType<'a> {
} else if l.peek::<kw::externref>()? {
parser.parse::<kw::externref>()?;
Ok(RefType::r#extern())
} else if l.peek::<kw::exnref>()? {
parser.parse::<kw::exnref>()?;
Ok(RefType::exn())
} else if l.peek::<kw::anyref>()? {
parser.parse::<kw::anyref>()?;
Ok(RefType::any())
Expand Down Expand Up @@ -306,6 +323,7 @@ impl<'a> Peek for RefType<'a> {
Ok(kw::funcref::peek(cursor)?
|| /* legacy */ kw::anyfunc::peek(cursor)?
|| kw::externref::peek(cursor)?
|| kw::exnref::peek(cursor)?
|| kw::anyref::peek(cursor)?
|| kw::eqref::peek(cursor)?
|| kw::structref::peek(cursor)?
Expand Down
4 changes: 4 additions & 0 deletions crates/wast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,9 @@ pub mod kw {
custom_keyword!(block);
custom_keyword!(borrow);
custom_keyword!(catch);
custom_keyword!(catch_ref);
custom_keyword!(catch_all);
custom_keyword!(catch_all_ref);
custom_keyword!(code);
custom_keyword!(component);
custom_keyword!(data);
Expand All @@ -404,6 +406,8 @@ pub mod kw {
custom_keyword!(elem);
custom_keyword!(end);
custom_keyword!(tag);
custom_keyword!(exn);
custom_keyword!(exnref);
custom_keyword!(export);
custom_keyword!(r#extern = "extern");
custom_keyword!(externref);
Expand Down
5 changes: 5 additions & 0 deletions tests/local/exnref/exnref.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(module
(func (param exnref))
(func (param (ref null exn)))
(func (param (ref exn)))
)
6 changes: 6 additions & 0 deletions tests/local/exnref/throw_ref.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(module
(func (param exnref)
local.get 0
throw_ref
)
)
Loading