summaryrefslogtreecommitdiff
path: root/src/wasm-traversal.h
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2019-08-13 00:29:26 +0900
committerGitHub <noreply@github.com>2019-08-13 00:29:26 +0900
commite2f49d8227f2b71e4dede5cf4074bb9f65e3d77f (patch)
tree30b132b02824839d1d7718ed32c6b90cc0828151 /src/wasm-traversal.h
parent69ad1e8a8d2e1d395e30230433742f4f5668563b (diff)
downloadbinaryen-e2f49d8227f2b71e4dede5cf4074bb9f65e3d77f.tar.gz
binaryen-e2f49d8227f2b71e4dede5cf4074bb9f65e3d77f.tar.bz2
binaryen-e2f49d8227f2b71e4dede5cf4074bb9f65e3d77f.zip
Add basic exception handling support (#2282)
This adds basic support for exception handling instructions, according to the spec: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md This PR includes support for: - Binary reading/writing - Wast reading/writing - Stack IR - Validation - binaryen.js + C API - Few IR routines: branch-utils, type-updating, etc - Few passes: just enough to make `wasm-opt -O` pass - Tests This PR does not include support for many optimization passes, fuzzer, or interpreter. They will be follow-up PRs. Try-catch construct is modeled in Binaryen IR in a similar manner to that of if-else: each of try body and catch body will contain a block, which can be omitted if there is only a single instruction. This block will not be emitted in wast or binary, as in if-else. As in if-else, `class Try` contains two expressions each for try body and catch body, and `catch` is not modeled as an instruction. `exnref` value pushed by `catch` is get by `pop` instruction. `br_on_exn` is special: it returns different types of values when taken and not taken. We make `exnref`, the type `br_on_exn` pushes if not taken, as `br_on_exn`'s type.
Diffstat (limited to 'src/wasm-traversal.h')
-rw-r--r--src/wasm-traversal.h102
1 files changed, 101 insertions, 1 deletions
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 04ab5f04a..5e9925b63 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -70,6 +70,10 @@ template<typename SubType, typename ReturnType = void> struct Visitor {
ReturnType visitDrop(Drop* curr) { return ReturnType(); }
ReturnType visitReturn(Return* curr) { return ReturnType(); }
ReturnType visitHost(Host* curr) { return ReturnType(); }
+ ReturnType visitTry(Try* curr) { return ReturnType(); }
+ ReturnType visitThrow(Throw* curr) { return ReturnType(); }
+ ReturnType visitRethrow(Rethrow* curr) { return ReturnType(); }
+ ReturnType visitBrOnExn(BrOnExn* curr) { return ReturnType(); }
ReturnType visitNop(Nop* curr) { return ReturnType(); }
ReturnType visitUnreachable(Unreachable* curr) { return ReturnType(); }
ReturnType visitPush(Push* curr) { return ReturnType(); }
@@ -158,6 +162,14 @@ template<typename SubType, typename ReturnType = void> struct Visitor {
DELEGATE(Return);
case Expression::Id::HostId:
DELEGATE(Host);
+ case Expression::Id::TryId:
+ DELEGATE(Try);
+ case Expression::Id::ThrowId:
+ DELEGATE(Throw);
+ case Expression::Id::RethrowId:
+ DELEGATE(Rethrow);
+ case Expression::Id::BrOnExnId:
+ DELEGATE(BrOnExn);
case Expression::Id::NopId:
DELEGATE(Nop);
case Expression::Id::UnreachableId:
@@ -222,6 +234,10 @@ struct OverriddenVisitor {
UNIMPLEMENTED(Drop);
UNIMPLEMENTED(Return);
UNIMPLEMENTED(Host);
+ UNIMPLEMENTED(Try);
+ UNIMPLEMENTED(Throw);
+ UNIMPLEMENTED(Rethrow);
+ UNIMPLEMENTED(BrOnExn);
UNIMPLEMENTED(Nop);
UNIMPLEMENTED(Unreachable);
UNIMPLEMENTED(Push);
@@ -311,6 +327,14 @@ struct OverriddenVisitor {
DELEGATE(Return);
case Expression::Id::HostId:
DELEGATE(Host);
+ case Expression::Id::TryId:
+ DELEGATE(Try);
+ case Expression::Id::ThrowId:
+ DELEGATE(Throw);
+ case Expression::Id::RethrowId:
+ DELEGATE(Rethrow);
+ case Expression::Id::BrOnExnId:
+ DELEGATE(BrOnExn);
case Expression::Id::NopId:
DELEGATE(Nop);
case Expression::Id::UnreachableId:
@@ -436,6 +460,18 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> {
ReturnType visitHost(Host* curr) {
return static_cast<SubType*>(this)->visitExpression(curr);
}
+ ReturnType visitTry(Try* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitThrow(Throw* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitRethrow(Rethrow* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
+ ReturnType visitBrOnExn(BrOnExn* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
ReturnType visitNop(Nop* curr) {
return static_cast<SubType*>(this)->visitExpression(curr);
}
@@ -723,6 +759,18 @@ struct Walker : public VisitorType {
static void doVisitHost(SubType* self, Expression** currp) {
self->visitHost((*currp)->cast<Host>());
}
+ static void doVisitTry(SubType* self, Expression** currp) {
+ self->visitTry((*currp)->cast<Try>());
+ }
+ static void doVisitThrow(SubType* self, Expression** currp) {
+ self->visitThrow((*currp)->cast<Throw>());
+ }
+ static void doVisitRethrow(SubType* self, Expression** currp) {
+ self->visitRethrow((*currp)->cast<Rethrow>());
+ }
+ static void doVisitBrOnExn(SubType* self, Expression** currp) {
+ self->visitBrOnExn((*currp)->cast<BrOnExn>());
+ }
static void doVisitNop(SubType* self, Expression** currp) {
self->visitNop((*currp)->cast<Nop>());
}
@@ -755,7 +803,6 @@ template<typename SubType, typename VisitorType = Visitor<SubType>>
struct PostWalker : public Walker<SubType, VisitorType> {
static void scan(SubType* self, Expression** currp) {
-
Expression* curr = *currp;
switch (curr->_id) {
case Expression::Id::InvalidId:
@@ -961,6 +1008,30 @@ struct PostWalker : public Walker<SubType, VisitorType> {
}
break;
}
+ case Expression::Id::TryId: {
+ self->pushTask(SubType::doVisitTry, currp);
+ self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody);
+ self->pushTask(SubType::scan, &curr->cast<Try>()->body);
+ break;
+ }
+ case Expression::Id::ThrowId: {
+ self->pushTask(SubType::doVisitThrow, currp);
+ auto& list = curr->cast<Throw>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::RethrowId: {
+ self->pushTask(SubType::doVisitRethrow, currp);
+ self->pushTask(SubType::scan, &curr->cast<Rethrow>()->exnref);
+ break;
+ }
+ case Expression::Id::BrOnExnId: {
+ self->pushTask(SubType::doVisitBrOnExn, currp);
+ self->pushTask(SubType::scan, &curr->cast<BrOnExn>()->exnref);
+ break;
+ }
case Expression::Id::NopId: {
self->pushTask(SubType::doVisitNop, currp);
break;
@@ -1196,6 +1267,35 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
self->maybePushTask(SubType::scan, &curr->cast<Return>()->value);
break;
}
+ case Expression::Id::TryId: {
+ self->pushTask(SubType::doVisitTry, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<Try>()->body);
+ break;
+ }
+ case Expression::Id::ThrowId: {
+ self->pushTask(SubType::doVisitThrow, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ auto& list = curr->cast<Throw>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::RethrowId: {
+ self->pushTask(SubType::doVisitRethrow, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<Rethrow>()->exnref);
+ break;
+ }
+ case Expression::Id::BrOnExnId: {
+ self->pushTask(SubType::doVisitBrOnExn, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<BrOnExn>()->exnref);
+ break;
+ }
case Expression::Id::UnreachableId: {
self->pushTask(SubType::doVisitUnreachable, currp);
self->pushTask(SubType::doNoteNonLinear, currp);