Skip to content

Commit

Permalink
wast: Add exnref, try_table, and throw_ref
Browse files Browse the repository at this point in the history
These types and instructions are part of the exception handling rework tracked
in (WebAssembly/exception-handling#281).
  • Loading branch information
eqrion committed Sep 28, 2023
1 parent 009ce61 commit 53f978f
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 1 deletion.
Binary file added .DS_Store
Binary file not shown.
Binary file added crates/.DS_Store
Binary file not shown.
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
32 changes: 32 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,32 @@ 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);
if let Some(catch_all) = &self.catch_all {
(1 as u8).encode(dst);
catch_all.encode(dst);
} else {
(0 as u8).encode(dst);
}
}
}

impl<'a> Encode for TryTableCatch<'a> {
fn encode(&self, dst: &mut Vec<u8>) {
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
58 changes: 58 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,60 @@ 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>()? {
catches.push(parser.parens(|p| {
p.parse::<kw::catch>()?;
Ok(TryTableCatch {
tag: p.parse()?,
label: p.parse()?,
})
})?);
}

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

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

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

#[derive(Debug)]
#[allow(missing_docs)]
pub struct TryTableCatchAll<'a> {
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
2 changes: 2 additions & 0 deletions crates/wast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,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
11 changes: 11 additions & 0 deletions test-eh.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(module
(func
try
unreachable
catch_all
rethrow 0
end
(block
)
)
)
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
)
)
53 changes: 53 additions & 0 deletions tests/local/exnref/try_table.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
(module
(tag $a (param i32))

(func
try_table
end

try_table (result i32)
i32.const 0
end
drop

try_table (catch $a 0)
end

try_table (catch $a 0) (catch $a 0)
end

try_table (catch_all 0)
end

try_table (catch $a 0) (catch_all 0)
end

try_table (catch $a 0) (catch $a 0) (catch_all 0)
end

try_table (result i32) (catch $a 0)
i32.const 0
end
drop

try_table (result i32) (catch $a 0) (catch $a 0)
i32.const 0
end
drop

try_table (result i32) (catch_all 0)
i32.const 0
end
drop

try_table (result i32) (catch $a 0) (catch_all 0)
i32.const 0
end
drop

try_table (result i32) (catch $a 0) (catch $a 0) (catch_all 0)
i32.const 0
end
drop
)
)
3 changes: 3 additions & 0 deletions tests/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ fn skip_validation(test: &Path) -> bool {
"/proposals/gc/type-equivalence.wast",
"/proposals/gc/type-rec.wast",
"/proposals/gc/type-subtyping.wast",
"/exnref/exnref.wast",
"/exnref/throw_ref.wast",
"/exnref/try_table.wast",
];
let test_path = test.to_str().unwrap().replace("\\", "/"); // for windows paths
if broken.iter().any(|x| test_path.contains(x)) {
Expand Down

0 comments on commit 53f978f

Please sign in to comment.