diff options
author | Heejin Ahn <aheejin@gmail.com> | 2019-08-13 00:29:26 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-13 00:29:26 +0900 |
commit | e2f49d8227f2b71e4dede5cf4074bb9f65e3d77f (patch) | |
tree | 30b132b02824839d1d7718ed32c6b90cc0828151 /src/wasm-traversal.h | |
parent | 69ad1e8a8d2e1d395e30230433742f4f5668563b (diff) | |
download | binaryen-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.h | 102 |
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); |