Skip to content

Commit 727c91a

Browse files
authored
Dummy interpreter support for EH (#2774)
This adds dummy interpreter support for EH instructions, mainly for fuzzing. The plan is to make the interpreter support for EH instructions correctly using Asyncify in the future. Also to support the correct behavior we will need a `Literal` of `exnref` type too, which will be added later too. Currently what this dummy implementation does is: - `try`-`catch`-`end`: only runs `try` body and ignores `catch` body - `throw`: traps - `retyrow`: - Traps on nullref argument (correct behavior based on the spec) - Traps otherwise too (dummy implementation for now) - `br_on_exn`: - Traps on nullref (correct behavior) - Otherwise we assume the current expression matches the current event and extracts a 0 literal based on the current type. This also adds some interpreter tests, which tests the basic dummy behaviors for now. (Deleted tests are the ones that weren't tested before.)
1 parent c916225 commit 727c91a

File tree

2 files changed

+76
-21
lines changed

2 files changed

+76
-21
lines changed

src/wasm-interpreter.h

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,13 +1215,39 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
12151215
NOTE_NAME(curr->func);
12161216
return Literal::makeFuncref(curr->func);
12171217
}
1218-
// TODO Implement EH instructions
1219-
Flow visitTry(Try*) { WASM_UNREACHABLE("unimp"); }
1220-
Flow visitThrow(Throw*) { WASM_UNREACHABLE("unimp"); }
1221-
Flow visitRethrow(Rethrow*) { WASM_UNREACHABLE("unimp"); }
1222-
Flow visitBrOnExn(BrOnExn*) { WASM_UNREACHABLE("unimp"); }
1218+
Flow visitTry(Try* curr) {
1219+
NOTE_ENTER("Try");
1220+
// FIXME This currently only executes 'try' part. Correctly implement this.
1221+
return visit(curr->body);
1222+
}
1223+
Flow visitThrow(Throw* curr) {
1224+
NOTE_ENTER("Throw");
1225+
LiteralList arguments;
1226+
Flow flow = generateArguments(curr->operands, arguments);
1227+
if (flow.breaking()) {
1228+
return flow;
1229+
}
1230+
NOTE_EVAL1(curr->event);
1231+
// FIXME This currently traps. Correctly implement throw.
1232+
trap("throw");
1233+
WASM_UNREACHABLE("throw");
1234+
}
1235+
Flow visitRethrow(Rethrow* curr) {
1236+
NOTE_ENTER("Rethrow");
1237+
Flow flow = visit(curr->exnref);
1238+
if (flow.breaking()) {
1239+
return flow;
1240+
}
1241+
if (flow.getType() == Type::nullref) {
1242+
trap("rethrow: argument is null");
1243+
}
1244+
// FIXME This currently traps. Correctly implement rethrow.
1245+
trap("rethrow");
1246+
WASM_UNREACHABLE("rethrow");
1247+
}
1248+
Flow visitBrOnExn(BrOnExn* curr) { WASM_UNREACHABLE("unimp"); }
12231249

1224-
virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
1250+
virtual void trap(const char* why) { WASM_UNREACHABLE(why); }
12251251
};
12261252

12271253
// Execute an constant expression in a global init or memory offset.
@@ -2097,6 +2123,25 @@ template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
20972123
}
20982124
return {};
20992125
}
2126+
Flow visitBrOnExn(BrOnExn* curr) {
2127+
NOTE_ENTER("BrOnExn");
2128+
Flow flow = this->visit(curr->exnref);
2129+
if (flow.breaking()) {
2130+
return flow;
2131+
}
2132+
if (flow.getType() == Type::nullref) {
2133+
trap("br_on_exn: argument is null");
2134+
}
2135+
// Currently we don't have a way to tell if the given expression matches
2136+
// the given event tag. Assume any exnref matches for now and always
2137+
// extracts a zero or null value of the given event type.
2138+
// FIXME Correctly implement event matching and extraction.
2139+
Type eventType = instance.wasm.getEvent(curr->event)->sig.params;
2140+
flow.values =
2141+
eventType == Type::none ? Literals() : Literal::makeZero(eventType);
2142+
flow.breakTo = curr->name;
2143+
return flow;
2144+
}
21002145
Flow visitPush(Push* curr) {
21012146
NOTE_ENTER("Push");
21022147
Flow value = this->visit(curr->value);

test/spec/exception-handling.wast

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,39 @@
22
(event $e0 (attr 0) (param i32))
33
(event $e1 (attr 0) (param i32 f32))
44

5-
(func $exnref_test (param $0 exnref) (result exnref)
6-
(local.get $0)
5+
(func (export "throw_test")
6+
(throw $e0 (i32.const 0))
77
)
88

9-
(func $eh_test (local $exn exnref)
10-
(try
11-
(throw $e0 (i32.const 0))
9+
(func (export "rethrow_test")
10+
(rethrow (ref.null))
11+
)
12+
13+
(func (export "try_test") (result i32)
14+
(try (result i32)
15+
(i32.const 3)
1216
(catch
13-
;; Multi-value is not available yet, so block can't take a value from
14-
;; stack. So this uses locals for now.
15-
(local.set $exn (exnref.pop))
16-
(drop
17-
(block $l0 (result i32)
18-
(rethrow
19-
(br_on_exn $l0 $e0 (local.get $exn))
20-
)
21-
)
22-
)
17+
(drop (exnref.pop))
18+
(i32.const 3)
2319
)
2420
)
2521
)
22+
23+
(func (export "br_on_exn_test") (result i32)
24+
(block $l0 (result i32)
25+
(drop
26+
(br_on_exn $l0 $e0 (ref.null))
27+
)
28+
(i32.const 0)
29+
)
30+
)
2631
)
2732

33+
(assert_trap (invoke "throw_test"))
34+
(assert_trap (invoke "rethrow_test"))
35+
(assert_return (invoke "try_test") (i32.const 3))
36+
(assert_trap (invoke "br_on_exn_test"))
37+
2838
(assert_invalid
2939
(module
3040
(func $f0

0 commit comments

Comments
 (0)