diff options
author | Heejin Ahn <aheejin@gmail.com> | 2020-05-06 16:38:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-06 16:38:37 -0700 |
commit | 5585d3a46f2b1daf74d4a7cf7b1d9a17b102b05c (patch) | |
tree | 19718aa2c531542e67165b5062aa97ddcf2e9037 /src/wasm-interpreter.h | |
parent | 33ee4ccd4985ab134bf48dac4088131105290fee (diff) | |
download | binaryen-5585d3a46f2b1daf74d4a7cf7b1d9a17b102b05c.tar.gz binaryen-5585d3a46f2b1daf74d4a7cf7b1d9a17b102b05c.tar.bz2 binaryen-5585d3a46f2b1daf74d4a7cf7b1d9a17b102b05c.zip |
Add interpreter support for EH (#2780)
This adds interpreter support for EH instructions. This adds
`ExceptionPackage` struct, which contains info of a thrown exception (an
event tag and thrown values), and the union in `Literal` can take a
`unique_ptr` to `ExceptionPackage`. We need a destructor, a copy
constructor, and an assignment operator for `Literal`, because the union
in `Literal` now has a member that cannot be trivially copied or
deleted.
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r-- | src/wasm-interpreter.h | 61 |
1 files changed, 44 insertions, 17 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 0124055ad..2841dc432 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -40,6 +40,11 @@ namespace wasm { +struct WasmException { + WasmException(Literal exn) : exn(exn) {} + Literal exn; +}; + using namespace cashew; // Utilities @@ -81,7 +86,7 @@ public: } } - friend std::ostream& operator<<(std::ostream& o, Flow& flow) { + friend std::ostream& operator<<(std::ostream& o, const Flow& flow) { o << "(flow " << (flow.breakTo.is() ? flow.breakTo.str : "-") << " : {"; for (size_t i = 0; i < flow.values.size(); ++i) { if (i > 0) { @@ -1228,11 +1233,7 @@ public: NOTE_NAME(curr->func); return Literal::makeFuncref(curr->func); } - Flow visitTry(Try* curr) { - NOTE_ENTER("Try"); - // FIXME This currently only executes 'try' part. Correctly implement this. - return visit(curr->body); - } + Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); } Flow visitThrow(Throw* curr) { NOTE_ENTER("Throw"); LiteralList arguments; @@ -1241,8 +1242,12 @@ public: return flow; } NOTE_EVAL1(curr->event); - // FIXME This currently traps. Correctly implement throw. - trap("throw"); + auto exn = std::make_unique<ExceptionPackage>(); + exn->event = curr->event; + for (auto item : arguments) { + exn->values.push_back(item); + } + throwException(Literal(std::move(exn))); WASM_UNREACHABLE("throw"); } Flow visitRethrow(Rethrow* curr) { @@ -1254,13 +1259,14 @@ public: if (flow.getType() == Type::nullref) { trap("rethrow: argument is null"); } - // FIXME This currently traps. Correctly implement rethrow. - trap("rethrow"); + throwException(flow.getSingleValue()); WASM_UNREACHABLE("rethrow"); } Flow visitBrOnExn(BrOnExn* curr) { WASM_UNREACHABLE("unimp"); } virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); } + + virtual void throwException(Literal exn) { WASM_UNREACHABLE("unimp"); } }; // Execute a suspected constant expression (precompute and C-API). @@ -1496,12 +1502,20 @@ public: NOTE_ENTER("Pop"); return Flow(NONCONSTANT_FLOW); } + Flow visitTry(Try* curr) { + NOTE_ENTER("Try"); + return Flow(NONCONSTANT_FLOW); + } Flow visitBrOnExn(BrOnExn* curr) { NOTE_ENTER("BrOnExn"); return Flow(NONCONSTANT_FLOW); } void trap(const char* why) override { throw NonconstantException(); } + + virtual void throwException(Literal exn) override { + throw NonconstantException(); + } }; // Execute an initializer expression of a global, data or element segment. @@ -1548,6 +1562,7 @@ public: SubType& instance) = 0; virtual void growMemory(Address oldSize, Address newSize) = 0; virtual void trap(const char* why) = 0; + virtual void throwException(Literal exnref) = 0; // the default impls for load and store switch on the sizes. you can either // customize load/store, or the sub-functions which they call @@ -2378,6 +2393,15 @@ private: } return {}; } + Flow visitTry(Try* curr) { + NOTE_ENTER("Try"); + try { + return this->visit(curr->body); + } catch (const WasmException& e) { + instance.multiValues.push_back(e.exn); + return this->visit(curr->catchBody); + } + } Flow visitBrOnExn(BrOnExn* curr) { NOTE_ENTER("BrOnExn"); Flow flow = this->visit(curr->exnref); @@ -2387,13 +2411,12 @@ private: if (flow.getType() == Type::nullref) { trap("br_on_exn: argument is null"); } - // Currently we don't have a way to tell if the given expression matches - // the given event tag. Assume any exnref matches for now and always - // extracts a zero or null value of the given event type. - // FIXME Correctly implement event matching and extraction. - Type eventType = instance.wasm.getEvent(curr->event)->sig.params; - flow.values = - eventType == Type::none ? Literals() : Literal::makeZero(eventType); + const ExceptionPackage& ex = flow.getSingleValue().getExceptionPackage(); + if (curr->event != ex.event) { // Not taken + return flow; + } + // Taken + flow.values = ex.values; flow.breakTo = curr->name; return flow; } @@ -2418,6 +2441,10 @@ private: instance.externalInterface->trap(why); } + void throwException(Literal exn) override { + instance.externalInterface->throwException(exn); + } + // Given a value, wrap it to a smaller given number of bytes. Literal wrapToSmallerSize(Literal value, Index bytes) { if (value.type == Type::i32) { |