diff options
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 26 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs-eh.wast | 34 |
2 files changed, 50 insertions, 10 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index c166d3c07..c2370aca6 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -464,12 +464,13 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // later down, see visitLocalSet. } - // A stack of try_tables that are parents of the current expression. - std::vector<TryTable*> tryTables; + // A stack of catching expressions that are parents of the current expression, + // that is, Try and TryTable. + std::vector<Expression*> catchers; - static void popTryTable(RemoveUnusedBrs* self, Expression** currp) { - assert(!self->tryTables.empty() && self->tryTables.back() == *currp); - self->tryTables.pop_back(); + static void popCatcher(RemoveUnusedBrs* self, Expression** currp) { + assert(!self->catchers.empty() && self->catchers.back() == *currp); + self->catchers.pop_back(); } void visitThrow(Throw* curr) { @@ -481,8 +482,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // To do so, look at the closest try and see if it will catch us, and // proceed outwards if not. auto thrownTag = curr->tag; - for (int i = tryTables.size() - 1; i >= 0; i--) { - auto* tryy = tryTables[i]; + for (int i = catchers.size() - 1; i >= 0; i--) { + auto* tryy = catchers[i]->dynCast<TryTable>(); + if (!tryy) { + // We do not handle mixtures of Try and TryTable. + return; + } for (Index j = 0; j < tryy->catchTags.size(); j++) { auto tag = tryy->catchTags[j]; // The tag must match, or be a catch_all. @@ -544,12 +549,13 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { self->pushTask(scan, &iff->condition); return; } - if (auto* tryy = (*currp)->dynCast<TryTable>()) { + if ((*currp)->is<TryTable>() || (*currp)->is<Try>()) { // Push the try we are reaching, and add a task to pop it, after all the // tasks that Super::scan will push for its children. - self->tryTables.push_back(tryy); - self->pushTask(popTryTable, currp); + self->catchers.push_back(*currp); + self->pushTask(popCatcher, currp); } + Super::scan(self, currp); } diff --git a/test/lit/passes/remove-unused-brs-eh.wast b/test/lit/passes/remove-unused-brs-eh.wast index 544ff81b0..b3b89df63 100644 --- a/test/lit/passes/remove-unused-brs-eh.wast +++ b/test/lit/passes/remove-unused-brs-eh.wast @@ -245,6 +245,40 @@ ) ) + ;; CHECK: (func $throw-mixed (type $0) + ;; CHECK-NEXT: (block $catch + ;; CHECK-NEXT: (try_table (catch_all $catch) + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $throw-mixed + ;; When we see mixed Trys and TryTables, we do not optimize (we would need + ;; to analyze if the Trys catch the exceptions and not the TryTables, but + ;; we don't bother to handle this odd case of mixing the old and new + ;; styles of code). + (block $catch + (try_table (catch_all $catch) + (try + (do + ;; This throw is caught by the Try, not the TryTable. + (throw $e) + ) + (catch_all + (unreachable) + ) + ) + ) + ) + ) + ;; CHECK: (func $threading (type $0) ;; CHECK-NEXT: (block $outer ;; CHECK-NEXT: (block $middle |