summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/eh-utils.cpp31
-rw-r--r--src/ir/eh-utils.h20
-rw-r--r--src/wasm/wasm-validator.cpp27
3 files changed, 53 insertions, 25 deletions
diff --git a/src/ir/eh-utils.cpp b/src/ir/eh-utils.cpp
index 3d369573d..fe33b09c2 100644
--- a/src/ir/eh-utils.cpp
+++ b/src/ir/eh-utils.cpp
@@ -162,6 +162,37 @@ void handleBlockNestedPops(Function* func, Module& wasm) {
TypeUpdating::handleNonDefaultableLocals(func, wasm);
}
+Pop* findPop(Expression* expr) {
+ auto pops = findPops(expr);
+ if (pops.size() == 0) {
+ return nullptr;
+ }
+ assert(pops.size() == 1);
+ return pops[0];
+}
+
+SmallVector<Pop*, 1> findPops(Expression* expr) {
+ SmallVector<Pop*, 1> pops;
+ SmallVector<Expression*, 8> work;
+ work.push_back(expr);
+ while (!work.empty()) {
+ auto* curr = work.back();
+ work.pop_back();
+ if (auto* pop = curr->dynCast<Pop>()) {
+ pops.push_back(pop);
+ } else if (auto* try_ = curr->dynCast<Try>()) {
+ // We don't go into inner catch bodies; pops in inner catch bodies
+ // belong to the inner catches
+ work.push_back(try_->body);
+ } else {
+ for (auto* child : ChildIterator(curr)) {
+ work.push_back(child);
+ }
+ }
+ }
+ return pops;
+};
+
} // namespace EHUtils
} // namespace wasm
diff --git a/src/ir/eh-utils.h b/src/ir/eh-utils.h
index 25677a32e..79ccbc507 100644
--- a/src/ir/eh-utils.h
+++ b/src/ir/eh-utils.h
@@ -17,6 +17,7 @@
#ifndef wasm_ir_eh_h
#define wasm_ir_eh_h
+#include "support/small_vector.h"
#include "wasm.h"
namespace wasm {
@@ -40,6 +41,25 @@ void handleBlockNestedPop(Try* try_, Function* func, Module& wasm);
// Calls handleBlockNestedPop for each 'Try's in a given function.
void handleBlockNestedPops(Function* func, Module& wasm);
+// Given a catch body, find the pop corresponding to the catch. There might be
+// pops nested inside a try inside this catch, and we must ignore them, like
+// here:
+//
+// (catch
+// (pop) ;; we want this for the outer catch
+// (try
+// (catch
+// (pop) ;; but we do not want this for the outer catch
+//
+// If there is no pop, which can happen if the tag has no params, then nullptr
+// is returned.
+Pop* findPop(Expression* expr);
+
+// Like findPop(), but it does *not* assume that the module validates. A catch
+// might therefore have any number of pops. This function is primarily useful in
+// the validator - normally you should call findPop(), above.
+SmallVector<Pop*, 1> findPops(Expression* expr);
+
} // namespace EHUtils
} // namespace wasm
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 9845da72c..57b52e182 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2165,29 +2165,6 @@ void FunctionValidator::visitTry(Try* curr) {
curr,
"try cannot have both catch and delegate at the same time");
- // Given a catch body, find pops corresponding to the catch
- auto findPops = [](Expression* expr) {
- SmallVector<Pop*, 1> pops;
- SmallVector<Expression*, 8> work;
- work.push_back(expr);
- while (!work.empty()) {
- auto* curr = work.back();
- work.pop_back();
- if (auto* pop = curr->dynCast<Pop>()) {
- pops.push_back(pop);
- } else if (auto* try_ = curr->dynCast<Try>()) {
- // We don't go into inner catch bodies; pops in inner catch bodies
- // belong to the inner catches
- work.push_back(try_->body);
- } else {
- for (auto* child : ChildIterator(curr)) {
- work.push_back(child);
- }
- }
- }
- return pops;
- };
-
for (Index i = 0; i < curr->catchTags.size(); i++) {
Name tagName = curr->catchTags[i];
auto* tag = getModule()->getTagOrNull(tagName);
@@ -2196,7 +2173,7 @@ void FunctionValidator::visitTry(Try* curr) {
}
auto* catchBody = curr->catchBodies[i];
- SmallVector<Pop*, 1> pops = findPops(catchBody);
+ auto pops = EHUtils::findPops(catchBody);
if (tag->sig.params == Type::none) {
if (!shouldBeTrue(pops.empty(), curr, "")) {
getStream() << "catch's tag (" << tagName
@@ -2225,7 +2202,7 @@ void FunctionValidator::visitTry(Try* curr) {
if (curr->hasCatchAll()) {
auto* catchAllBody = curr->catchBodies.back();
- shouldBeTrue(findPops(catchAllBody).empty(),
+ shouldBeTrue(EHUtils::findPops(catchAllBody).empty(),
curr,
"catch_all's body should not have pops");
}