Skip to content

Commit e8a7c3f

Browse files
committed
wast: Add exnref, try_table, and throw_ref
These types and instructions are part of the exception handling rework tracked in (WebAssembly/exception-handling#281).
1 parent 009ce61 commit e8a7c3f

File tree

9 files changed

+131
-1
lines changed

9 files changed

+131
-1
lines changed

crates/wast/src/component/binary.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
599599
match r {
600600
core::HeapType::Func => Self::Func,
601601
core::HeapType::Extern => Self::Extern,
602+
core::HeapType::Exn => todo!("encoding of exceptions proposal types not yet implemented"),
602603
core::HeapType::Index(Index::Num(i, _)) => Self::Indexed(i),
603604
core::HeapType::Index(_) => panic!("unresolved index"),
604605
core::HeapType::Any

crates/wast/src/component/resolve.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ impl<'a> Resolver<'a> {
523523
ValType::Ref(r) => match &mut r.heap {
524524
core::HeapType::Func
525525
| core::HeapType::Extern
526+
| core::HeapType::Exn
526527
| core::HeapType::Any
527528
| core::HeapType::Eq
528529
| core::HeapType::Array

crates/wast/src/core/binary.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ impl<'a> Encode for HeapType<'a> {
246246
match self {
247247
HeapType::Func => e.push(0x70),
248248
HeapType::Extern => e.push(0x6f),
249+
HeapType::Exn => e.push(0x69),
249250
HeapType::Any => e.push(0x6e),
250251
HeapType::Eq => e.push(0x6d),
251252
HeapType::Struct => e.push(0x6b),
@@ -277,6 +278,11 @@ impl<'a> Encode for RefType<'a> {
277278
nullable: true,
278279
heap: HeapType::Extern,
279280
} => e.push(0x6f),
281+
// The 'exnref' binary abbreviation
282+
RefType {
283+
nullable: true,
284+
heap: HeapType::Exn,
285+
} => e.push(0x69),
280286
// The 'eqref' binary abbreviation
281287
RefType {
282288
nullable: true,
@@ -1028,6 +1034,32 @@ impl Encode for Id<'_> {
10281034
}
10291035
}
10301036

1037+
impl<'a> Encode for TryTable<'a> {
1038+
fn encode(&self, dst: &mut Vec<u8>) {
1039+
self.block.encode(dst);
1040+
self.catches.encode(dst);
1041+
if let Some(catch_all) = &self.catch_all {
1042+
(1 as u8).encode(dst);
1043+
catch_all.encode(dst);
1044+
} else {
1045+
(0 as u8).encode(dst);
1046+
}
1047+
}
1048+
}
1049+
1050+
impl<'a> Encode for TryTableCatch<'a> {
1051+
fn encode(&self, dst: &mut Vec<u8>) {
1052+
self.tag.encode(dst);
1053+
self.label.encode(dst);
1054+
}
1055+
}
1056+
1057+
impl<'a> Encode for TryTableCatchAll<'a> {
1058+
fn encode(&self, dst: &mut Vec<u8>) {
1059+
self.label.encode(dst);
1060+
}
1061+
}
1062+
10311063
impl Encode for V128Const {
10321064
fn encode(&self, dst: &mut Vec<u8>) {
10331065
dst.extend_from_slice(&self.to_le_bytes());

crates/wast/src/core/expr.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,10 @@ instructions! {
11491149
Delegate(Index<'a>) : [0x18] : "delegate",
11501150
CatchAll : [0x19] : "catch_all",
11511151

1152+
// Exception handling proposal extension for 'exnref'
1153+
ThrowRef : [0x16] : "throw_ref",
1154+
TryTable(TryTable<'a>) : [0x17] : "try_table",
1155+
11521156
// Relaxed SIMD proposal
11531157
I8x16RelaxedSwizzle : [0xfd, 0x100]: "i8x16.relaxed_swizzle",
11541158
I32x4RelaxedTruncF32x4S : [0xfd, 0x101]: "i32x4.relaxed_trunc_f32x4_s",
@@ -1219,6 +1223,60 @@ impl<'a> Parse<'a> for BlockType<'a> {
12191223
}
12201224
}
12211225

1226+
#[derive(Debug)]
1227+
#[allow(missing_docs)]
1228+
pub struct TryTable<'a> {
1229+
pub block: Box<BlockType<'a>>,
1230+
pub catches: Vec<TryTableCatch<'a>>,
1231+
pub catch_all: Option<TryTableCatchAll<'a>>,
1232+
}
1233+
1234+
impl<'a> Parse<'a> for TryTable<'a> {
1235+
fn parse(parser: Parser<'a>) -> Result<Self> {
1236+
let block = parser.parse()?;
1237+
1238+
let mut catches = Vec::new();
1239+
while parser.peek2::<kw::catch>()? {
1240+
catches.push(parser.parens(|p| {
1241+
p.parse::<kw::catch>()?;
1242+
Ok(TryTableCatch {
1243+
tag: p.parse()?,
1244+
label: p.parse()?,
1245+
})
1246+
})?);
1247+
}
1248+
1249+
let mut catch_all = None;
1250+
if parser.peek2::<kw::catch_all>()? {
1251+
catch_all = Some(parser.parens(|p| {
1252+
p.parse::<kw::catch_all>()?;
1253+
Ok(TryTableCatchAll {
1254+
label: p.parse()?,
1255+
})
1256+
})?);
1257+
}
1258+
1259+
Ok(TryTable {
1260+
block,
1261+
catches,
1262+
catch_all,
1263+
})
1264+
}
1265+
}
1266+
1267+
#[derive(Debug)]
1268+
#[allow(missing_docs)]
1269+
pub struct TryTableCatch<'a> {
1270+
pub tag: Index<'a>,
1271+
pub label: Index<'a>,
1272+
}
1273+
1274+
#[derive(Debug)]
1275+
#[allow(missing_docs)]
1276+
pub struct TryTableCatchAll<'a> {
1277+
pub label: Index<'a>,
1278+
}
1279+
12221280
/// Extra information associated with the func.bind instruction.
12231281
#[derive(Debug)]
12241282
#[allow(missing_docs)]

crates/wast/src/core/resolve/names.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,20 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
521521
});
522522
self.resolve_block_type(bt)?;
523523
}
524+
TryTable(try_table) => {
525+
self.blocks.push(ExprBlock {
526+
label: try_table.block.label,
527+
pushed_scope: false,
528+
});
529+
self.resolve_block_type(&mut try_table.block)?;
530+
for catch in &mut try_table.catches {
531+
self.resolver.resolve(&mut catch.tag, Ns::Tag)?;
532+
self.resolve_label(&mut catch.label)?;
533+
}
534+
if let Some(catch_all) = &mut try_table.catch_all {
535+
self.resolve_label(&mut catch_all.label)?;
536+
}
537+
}
524538

525539
// On `End` instructions we pop a label from the stack, and for both
526540
// `End` and `Else` instructions if they have labels listed we

crates/wast/src/core/resolve/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ impl<'a> Expander<'a> {
140140
| Instruction::If(bt)
141141
| Instruction::Loop(bt)
142142
| Instruction::Let(LetType { block: bt, .. })
143-
| Instruction::Try(bt) => {
143+
| Instruction::Try(bt)
144+
| Instruction::TryTable(TryTable { block: bt, .. }) => {
144145
// No expansion necessary, a type reference is already here.
145146
// We'll verify that it's the same as the inline type, if any,
146147
// later.

crates/wast/src/core/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ pub enum HeapType<'a> {
6666
/// A reference to any host value: externref. This is part of the reference
6767
/// types proposal.
6868
Extern,
69+
/// A reference to a wasm exception. This is part of the exceptions proposal.
70+
Exn,
6971
/// A reference to any reference value: anyref. This is part of the GC
7072
/// proposal.
7173
Any,
@@ -98,6 +100,9 @@ impl<'a> Parse<'a> for HeapType<'a> {
98100
} else if l.peek::<kw::r#extern>()? {
99101
parser.parse::<kw::r#extern>()?;
100102
Ok(HeapType::Extern)
103+
} else if l.peek::<kw::exn>()? {
104+
parser.parse::<kw::exn>()?;
105+
Ok(HeapType::Exn)
101106
} else if l.peek::<kw::r#any>()? {
102107
parser.parse::<kw::r#any>()?;
103108
Ok(HeapType::Any)
@@ -134,6 +139,7 @@ impl<'a> Peek for HeapType<'a> {
134139
fn peek(cursor: Cursor<'_>) -> Result<bool> {
135140
Ok(kw::func::peek(cursor)?
136141
|| kw::r#extern::peek(cursor)?
142+
|| kw::exn::peek(cursor)?
137143
|| kw::any::peek(cursor)?
138144
|| kw::eq::peek(cursor)?
139145
|| kw::r#struct::peek(cursor)?
@@ -174,6 +180,14 @@ impl<'a> RefType<'a> {
174180
}
175181
}
176182

183+
/// An `exnrefr` as an abbreviation for `(ref null exn)`.
184+
pub fn exn() -> Self {
185+
RefType {
186+
nullable: true,
187+
heap: HeapType::Exn,
188+
}
189+
}
190+
177191
/// An `anyref` as an abbreviation for `(ref null any)`.
178192
pub fn any() -> Self {
179193
RefType {
@@ -251,6 +265,9 @@ impl<'a> Parse<'a> for RefType<'a> {
251265
} else if l.peek::<kw::externref>()? {
252266
parser.parse::<kw::externref>()?;
253267
Ok(RefType::r#extern())
268+
} else if l.peek::<kw::exnref>()? {
269+
parser.parse::<kw::exnref>()?;
270+
Ok(RefType::exn())
254271
} else if l.peek::<kw::anyref>()? {
255272
parser.parse::<kw::anyref>()?;
256273
Ok(RefType::any())
@@ -306,6 +323,7 @@ impl<'a> Peek for RefType<'a> {
306323
Ok(kw::funcref::peek(cursor)?
307324
|| /* legacy */ kw::anyfunc::peek(cursor)?
308325
|| kw::externref::peek(cursor)?
326+
|| kw::exnref::peek(cursor)?
309327
|| kw::anyref::peek(cursor)?
310328
|| kw::eqref::peek(cursor)?
311329
|| kw::structref::peek(cursor)?

crates/wast/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,8 @@ pub mod kw {
404404
custom_keyword!(elem);
405405
custom_keyword!(end);
406406
custom_keyword!(tag);
407+
custom_keyword!(exn);
408+
custom_keyword!(exnref);
407409
custom_keyword!(export);
408410
custom_keyword!(r#extern = "extern");
409411
custom_keyword!(externref);

tests/roundtrip.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ fn skip_validation(test: &Path) -> bool {
193193
"/proposals/gc/type-equivalence.wast",
194194
"/proposals/gc/type-rec.wast",
195195
"/proposals/gc/type-subtyping.wast",
196+
"/exnref/exnref.wast",
197+
"/exnref/throw_ref.wast",
198+
"/exnref/try_table.wast",
196199
];
197200
let test_path = test.to_str().unwrap().replace("\\", "/"); // for windows paths
198201
if broken.iter().any(|x| test_path.contains(x)) {

0 commit comments

Comments
 (0)