Skip to content

Commit 7e9cf05

Browse files
authored
[stack-switching] Support the resume_throw_ref instruction (#2423)
This patch adds support for the `resume_throw_ref` instruction, which is similar to the `resume_throw` instruction, but rather than injecting a fresh exception into the continuation, the `resume_throw_ref` instruction injects an exception reference into the continuation. Note: the new instruction is, at the time of writing, assigned the opcode `0xE5` conflicting with the `switch` instruction, which has been assigned `0xE6` as its opcode instead (c.f. [the work-in-progress specification](https://github.com/WebAssembly/stack-switching/blob/main/proposals/stack-switching/Explainer.md#binary-format)).
1 parent 445db15 commit 7e9cf05

23 files changed

Lines changed: 866 additions & 3 deletions

File tree

crates/wasm-encoder/src/core/code.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,10 @@ pub enum Instruction<'a> {
13081308
tag_index: u32,
13091309
resume_table: Cow<'a, [Handle]>,
13101310
},
1311+
ResumeThrowRef {
1312+
cont_type_index: u32,
1313+
resume_table: Cow<'a, [Handle]>,
1314+
},
13111315
Switch {
13121316
cont_type_index: u32,
13131317
tag_index: u32,
@@ -2156,6 +2160,10 @@ impl Encode for Instruction<'_> {
21562160
tag_index,
21572161
ref resume_table,
21582162
} => sink.resume_throw(cont_type_index, tag_index, resume_table.iter().cloned()),
2163+
Instruction::ResumeThrowRef {
2164+
cont_type_index,
2165+
ref resume_table,
2166+
} => sink.resume_throw_ref(cont_type_index, resume_table.iter().cloned()),
21592167
Instruction::Switch {
21602168
cont_type_index,
21612169
tag_index,

crates/wasm-encoder/src/core/instructions.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4588,9 +4588,24 @@ impl<'a> InstructionSink<'a> {
45884588
self
45894589
}
45904590

4591+
/// Encode [`Instruction::ResumeThrowRef`].
4592+
pub fn resume_throw_ref<V: IntoIterator<Item = Handle>>(
4593+
&mut self,
4594+
cont_type_index: u32,
4595+
resume_table: V,
4596+
) -> &mut Self
4597+
where
4598+
V::IntoIter: ExactSizeIterator,
4599+
{
4600+
self.sink.push(0xE5);
4601+
cont_type_index.encode(self.sink);
4602+
encode_vec(resume_table, self.sink);
4603+
self
4604+
}
4605+
45914606
/// Encode [`Instruction::Switch`].
45924607
pub fn switch(&mut self, cont_type_index: u32, tag_index: u32) -> &mut Self {
4593-
self.sink.push(0xE5);
4608+
self.sink.push(0xE6);
45944609
cont_type_index.encode(self.sink);
45954610
tag_index.encode(self.sink);
45964611
self

crates/wasmparser/src/arity.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,16 @@ fn visit_resume_throw(
285285
Some((params + 1, results))
286286
}
287287

288+
fn visit_resume_throw_ref(
289+
module: &dyn ModuleArity,
290+
cont: u32,
291+
_table: ResumeTable,
292+
) -> Option<(u32, u32)> {
293+
let (_, results) = module.sub_type_arity(module.sub_type_at(cont)?)?;
294+
// in: [exnref, cont], out: [result(cont)]
295+
Some((2, results))
296+
}
297+
288298
fn visit_switch(module: &dyn ModuleArity, cont: u32, _tag: u32) -> Option<(u32, u32)> {
289299
let (params, _) = module.sub_type_arity(module.sub_type_at(cont)?)?;
290300
let st = &module.sub_type_at(cont)?.composite_type.inner;

crates/wasmparser/src/binary_reader.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,8 @@ impl<'a> BinaryReader<'a> {
11871187
0xe4 => {
11881188
visitor.visit_resume_throw(self.read_var_u32()?, self.read_var_u32()?, self.read()?)
11891189
}
1190-
0xe5 => visitor.visit_switch(self.read_var_u32()?, self.read_var_u32()?),
1190+
0xe5 => visitor.visit_resume_throw_ref(self.read_var_u32()?, self.read()?),
1191+
0xe6 => visitor.visit_switch(self.read_var_u32()?, self.read_var_u32()?),
11911192

11921193
0xfb => self.visit_0xfb_operator(pos, visitor)?,
11931194
0xfc => self.visit_0xfc_operator(pos, visitor)?,

crates/wasmparser/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ macro_rules! _for_each_operator_group {
788788
Suspend { tag_index: u32 } => visit_suspend (arity custom)
789789
Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity custom)
790790
ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity custom)
791+
ResumeThrowRef { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw_ref (arity custom)
791792
Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity custom)
792793
}
793794

crates/wasmparser/src/validator/operators.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4368,6 +4368,16 @@ where
43684368
}
43694369
Ok(())
43704370
}
4371+
fn visit_resume_throw_ref(&mut self, type_index: u32, table: ResumeTable) -> Self::Output {
4372+
let ft = self.check_resume_table(table, type_index)?;
4373+
self.pop_concrete_ref(true, type_index)?;
4374+
self.pop_operand(Some(ValType::EXNREF))?;
4375+
4376+
for &ty in ft.results() {
4377+
self.push_operand(ty)?
4378+
}
4379+
Ok(())
4380+
}
43714381
fn visit_switch(&mut self, type_index: u32, tag_index: u32) -> Self::Output {
43724382
// [t1* (ref null $ct2)] -> [te1*]
43734383
let cont_ty = self.cont_type_at(type_index)?;

crates/wasmprinter/src/operator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,7 @@ macro_rules! define_visit {
14021402
(name Suspend) => ("suspend");
14031403
(name Resume) => ("resume");
14041404
(name ResumeThrow) => ("resume_throw");
1405+
(name ResumeThrowRef) => ("resume_throw_ref");
14051406
(name Switch) => ("switch");
14061407
(name I64Add128) => ("i64.add128");
14071408
(name I64Sub128) => ("i64.sub128");

crates/wast/src/core/binary.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,13 @@ impl<'a> Encode for ResumeThrow<'a> {
13341334
}
13351335
}
13361336

1337+
impl<'a> Encode for ResumeThrowRef<'a> {
1338+
fn encode(&self, dst: &mut Vec<u8>) {
1339+
self.type_index.encode(dst);
1340+
self.table.encode(dst);
1341+
}
1342+
}
1343+
13371344
impl<'a> Encode for ResumeTable<'a> {
13381345
fn encode(&self, dst: &mut Vec<u8>) {
13391346
self.handlers.encode(dst);

crates/wast/src/core/expr.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,8 @@ instructions! {
11951195
Suspend(Index<'a>) : [0xe2] : "suspend",
11961196
Resume(Resume<'a>) : [0xe3] : "resume",
11971197
ResumeThrow(ResumeThrow<'a>) : [0xe4] : "resume_throw",
1198-
Switch(Switch<'a>) : [0xe5] : "switch",
1198+
ResumeThrowRef(ResumeThrowRef<'a>) : [0xe5] : "resume_throw_ref",
1199+
Switch(Switch<'a>) : [0xe6] : "switch",
11991200

12001201
// Wide arithmetic proposal
12011202
I64Add128 : [0xfc, 19] : "i64.add128",
@@ -1313,6 +1314,23 @@ impl<'a> Parse<'a> for ResumeThrow<'a> {
13131314
}
13141315
}
13151316

1317+
/// Extra information associated with the resume_throw_ref instruction
1318+
#[derive(Debug, Clone)]
1319+
#[allow(missing_docs)]
1320+
pub struct ResumeThrowRef<'a> {
1321+
pub type_index: Index<'a>,
1322+
pub table: ResumeTable<'a>,
1323+
}
1324+
1325+
impl<'a> Parse<'a> for ResumeThrowRef<'a> {
1326+
fn parse(parser: Parser<'a>) -> Result<Self> {
1327+
Ok(ResumeThrowRef {
1328+
type_index: parser.parse()?,
1329+
table: parser.parse()?,
1330+
})
1331+
}
1332+
}
1333+
13161334
/// Extra information associated with the switch instruction
13171335
#[derive(Debug, Clone)]
13181336
#[allow(missing_docs)]

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,10 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
677677
self.resolver.resolve(&mut rt.tag_index, Ns::Tag)?;
678678
self.resolve_resume_table(&mut rt.table)?;
679679
}
680+
ResumeThrowRef(rt) => {
681+
self.resolver.resolve(&mut rt.type_index, Ns::Type)?;
682+
self.resolve_resume_table(&mut rt.table)?;
683+
}
680684
Switch(s) => {
681685
self.resolver.resolve(&mut s.type_index, Ns::Type)?;
682686
self.resolver.resolve(&mut s.tag_index, Ns::Tag)?;

0 commit comments

Comments
 (0)