Skip to content

Commit 00cc81c

Browse files
authored
Bring back legacy exception handling opcodes (#1661)
* Bring back legacy exception handling opcodes under flag * Bring back legacy exception handling opcodes under flag (prepare place for tests) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes)
1 parent a63834a commit 00cc81c

File tree

7 files changed

+145
-22
lines changed

7 files changed

+145
-22
lines changed

crates/wasmparser/src/features.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ define_wasm_features! {
148148
pub component_model_nested_names: COMPONENT_MODEL_NESTED_NAMES(1 << 22) = false;
149149
/// Support for more than 32 flags per-type in the component model.
150150
pub component_model_more_flags: COMPONENT_MODEL_MORE_FLAGS(1 << 23) = false;
151+
/// The WebAssembly legacy exception handling proposal (phase 1)
152+
///
153+
/// # Note
154+
///
155+
/// Support this feature as long as all leading browsers also support it
156+
/// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md
157+
pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 24) = false;
151158
}
152159
}
153160

crates/wasmparser/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ macro_rules! for_each_operator {
158158
@exceptions Throw { tag_index: u32 } => visit_throw
159159
@exceptions ThrowRef => visit_throw_ref
160160
// Deprecated old instructions from the exceptions proposal
161-
@exceptions Try { blockty: $crate::BlockType } => visit_try
162-
@exceptions Catch { tag_index: u32 } => visit_catch
163-
@exceptions Rethrow { relative_depth: u32 } => visit_rethrow
164-
@exceptions Delegate { relative_depth: u32 } => visit_delegate
165-
@exceptions CatchAll => visit_catch_all
161+
@legacy_exceptions Try { blockty: $crate::BlockType } => visit_try
162+
@legacy_exceptions Catch { tag_index: u32 } => visit_catch
163+
@legacy_exceptions Rethrow { relative_depth: u32 } => visit_rethrow
164+
@legacy_exceptions Delegate { relative_depth: u32 } => visit_delegate
165+
@legacy_exceptions CatchAll => visit_catch_all
166166
@mvp End => visit_end
167167
@mvp Br { relative_depth: u32 } => visit_br
168168
@mvp BrIf { relative_depth: u32 } => visit_br_if

crates/wasmparser/src/validator/operators.rs

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,24 @@ pub enum FrameKind {
121121
///
122122
/// This belongs to the Wasm exception handling proposal.
123123
TryTable,
124+
/// A Wasm legacy `try` control block.
125+
///
126+
/// # Note
127+
///
128+
/// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs`
129+
LegacyTry,
130+
/// A Wasm legacy `catch` control block.
131+
///
132+
/// # Note
133+
///
134+
/// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs`
135+
LegacyCatch,
136+
/// A Wasm legacy `catch_all` control block.
137+
///
138+
/// # Note
139+
///
140+
/// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs`
141+
LegacyCatchAll,
124142
}
125143

126144
struct OperatorValidatorTemp<'validator, 'resources, T> {
@@ -1322,6 +1340,7 @@ macro_rules! validate_proposal {
13221340
(desc function_references) => ("function references");
13231341
(desc memory_control) => ("memory control");
13241342
(desc gc) => ("gc");
1343+
(desc legacy_exceptions) => ("legacy exceptions");
13251344
}
13261345

13271346
impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T>
@@ -1486,21 +1505,6 @@ where
14861505
self.unreachable()?;
14871506
Ok(())
14881507
}
1489-
fn visit_try(&mut self, _: BlockType) -> Self::Output {
1490-
bail!(self.offset, "unimplemented validation of deprecated opcode")
1491-
}
1492-
fn visit_catch(&mut self, _: u32) -> Self::Output {
1493-
bail!(self.offset, "unimplemented validation of deprecated opcode")
1494-
}
1495-
fn visit_rethrow(&mut self, _: u32) -> Self::Output {
1496-
bail!(self.offset, "unimplemented validation of deprecated opcode")
1497-
}
1498-
fn visit_delegate(&mut self, _: u32) -> Self::Output {
1499-
bail!(self.offset, "unimplemented validation of deprecated opcode")
1500-
}
1501-
fn visit_catch_all(&mut self) -> Self::Output {
1502-
bail!(self.offset, "unimplemented validation of deprecated opcode")
1503-
}
15041508
fn visit_end(&mut self) -> Self::Output {
15051509
let mut frame = self.pop_ctrl()?;
15061510

@@ -4124,6 +4128,80 @@ where
41244128
self.pop_operand(Some(ValType::Ref(RefType::I31REF)))?;
41254129
self.push_operand(ValType::I32)
41264130
}
4131+
fn visit_try(&mut self, mut ty: BlockType) -> Self::Output {
4132+
self.check_block_type(&mut ty)?;
4133+
for ty in self.params(ty)?.rev() {
4134+
self.pop_operand(Some(ty))?;
4135+
}
4136+
self.push_ctrl(FrameKind::LegacyTry, ty)?;
4137+
Ok(())
4138+
}
4139+
fn visit_catch(&mut self, index: u32) -> Self::Output {
4140+
let frame = self.pop_ctrl()?;
4141+
if frame.kind != FrameKind::LegacyTry && frame.kind != FrameKind::LegacyCatch {
4142+
bail!(self.offset, "catch found outside of an `try` block");
4143+
}
4144+
// Start a new frame and push `exnref` value.
4145+
let height = self.operands.len();
4146+
let init_height = self.inits.len();
4147+
self.control.push(Frame {
4148+
kind: FrameKind::LegacyCatch,
4149+
block_type: frame.block_type,
4150+
height,
4151+
unreachable: false,
4152+
init_height,
4153+
});
4154+
// Push exception argument types.
4155+
let ty = self.tag_at(index)?;
4156+
for ty in ty.params() {
4157+
self.push_operand(*ty)?;
4158+
}
4159+
Ok(())
4160+
}
4161+
fn visit_rethrow(&mut self, relative_depth: u32) -> Self::Output {
4162+
// This is not a jump, but we need to check that the `rethrow`
4163+
// targets an actual `catch` to get the exception.
4164+
let (_, kind) = self.jump(relative_depth)?;
4165+
if kind != FrameKind::LegacyCatch && kind != FrameKind::LegacyCatchAll {
4166+
bail!(
4167+
self.offset,
4168+
"invalid rethrow label: target was not a `catch` block"
4169+
);
4170+
}
4171+
self.unreachable()?;
4172+
Ok(())
4173+
}
4174+
fn visit_delegate(&mut self, relative_depth: u32) -> Self::Output {
4175+
let frame = self.pop_ctrl()?;
4176+
if frame.kind != FrameKind::LegacyTry {
4177+
bail!(self.offset, "delegate found outside of an `try` block");
4178+
}
4179+
// This operation is not a jump, but we need to check the
4180+
// depth for validity
4181+
let _ = self.jump(relative_depth)?;
4182+
for ty in self.results(frame.block_type)? {
4183+
self.push_operand(ty)?;
4184+
}
4185+
Ok(())
4186+
}
4187+
fn visit_catch_all(&mut self) -> Self::Output {
4188+
let frame = self.pop_ctrl()?;
4189+
if frame.kind == FrameKind::LegacyCatchAll {
4190+
bail!(self.offset, "only one catch_all allowed per `try` block");
4191+
} else if frame.kind != FrameKind::LegacyTry && frame.kind != FrameKind::LegacyCatch {
4192+
bail!(self.offset, "catch_all found outside of a `try` block");
4193+
}
4194+
let height = self.operands.len();
4195+
let init_height = self.inits.len();
4196+
self.control.push(Frame {
4197+
kind: FrameKind::LegacyCatchAll,
4198+
block_type: frame.block_type,
4199+
height,
4200+
unreachable: false,
4201+
init_height,
4202+
});
4203+
Ok(())
4204+
}
41274205
}
41284206

41294207
#[derive(Clone, Debug)]

src/bin/wasm-tools/validate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ fn parse_features(arg: &str) -> Result<WasmFeatures> {
201201
("mutable-global", WasmFeatures::MUTABLE_GLOBAL),
202202
("relaxed-simd", WasmFeatures::RELAXED_SIMD),
203203
("gc", WasmFeatures::GC),
204+
("legacy-exceptions", WasmFeatures::LEGACY_EXCEPTIONS),
204205
];
205206

206207
for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) {

tests/local/legacy-exceptions.wat

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
;; --enable-legacy-exceptions
2+
(module
3+
(type (;0;) (func))
4+
(func (;0;) (type 0)
5+
try ;; label = @1
6+
try ;; label = @2
7+
try ;; label = @3
8+
throw 0
9+
catch_all
10+
rethrow 0 (;@3;)
11+
end
12+
delegate 0 (;@2;)
13+
catch 0
14+
end
15+
)
16+
(tag (;0;) (type 0))
17+
)

tests/roundtrip.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,8 @@ impl TestState {
579579
& !WasmFeatures::SHARED_EVERYTHING_THREADS
580580
& !WasmFeatures::COMPONENT_MODEL
581581
& !WasmFeatures::COMPONENT_MODEL_NESTED_NAMES
582-
& !WasmFeatures::COMPONENT_MODEL_MORE_FLAGS;
582+
& !WasmFeatures::COMPONENT_MODEL_MORE_FLAGS
583+
& !WasmFeatures::LEGACY_EXCEPTIONS;
583584
for part in test.iter().filter_map(|t| t.to_str()) {
584585
match part {
585586
"testsuite" => {
@@ -604,6 +605,7 @@ impl TestState {
604605
}
605606
"simd" => features.insert(WasmFeatures::SIMD),
606607
"exception-handling" => features.insert(WasmFeatures::EXCEPTIONS),
608+
"legacy-exceptions.wat" => features.insert(WasmFeatures::LEGACY_EXCEPTIONS),
607609
"tail-call" => features.insert(WasmFeatures::TAIL_CALL),
608610
"memory64" => features.insert(WasmFeatures::MEMORY64),
609611
"component-model" => features.insert(WasmFeatures::COMPONENT_MODEL),
@@ -655,11 +657,13 @@ fn error_matches(error: &str, message: &str) -> bool {
655657
|| message == "alignment must be a power of two"
656658
|| message == "i32 constant out of range"
657659
|| message == "constant expression required"
660+
|| message == "legacy exceptions support is not enabled"
658661
{
659662
return error.contains("expected ")
660663
|| error.contains("constant out of range")
661664
|| error.contains("extra tokens remaining")
662-
|| error.contains("unimplemented validation of deprecated opcode");
665+
|| error.contains("unimplemented validation of deprecated opcode")
666+
|| error.contains("legacy exceptions support is not enabled");
663667
}
664668

665669
if message == "illegal character" {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(module
2+
(type (;0;) (func))
3+
(func (;0;) (type 0)
4+
try ;; label = @1
5+
try ;; label = @2
6+
try ;; label = @3
7+
throw 0
8+
catch_all
9+
rethrow 0 (;@3;)
10+
end
11+
delegate 0 (;@1;)
12+
catch 0
13+
end
14+
)
15+
(tag (;0;) (type 0))
16+
)

0 commit comments

Comments
 (0)