summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/CodeFolding.cpp29
1 files changed, 22 insertions, 7 deletions
diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp
index 70a357bbf..10255a670 100644
--- a/src/passes/CodeFolding.cpp
+++ b/src/passes/CodeFolding.cpp
@@ -304,13 +304,28 @@ private:
// anything exiting that is in all targets is something bad
return false;
}
- // Currently pop instructions are only used for exnref.pop, which is a
- // pseudo instruction following a catch. We check if the current
- // expression has a pop child. This can be overly conservative, because
- // this can also exclude whole try-catches that contain a pop within them.
- if (getModule()->features.hasExceptionHandling() &&
- !FindAll<Pop>(item).list.empty()) {
- return false;
+ if (getModule()->features.hasExceptionHandling()) {
+ // Currently pop instructions are only used for exnref.pop, which is a
+ // pseudo instruction following a catch. We check if the current
+ // expression has a pop child. This can be overly conservative, because
+ // this can also exclude whole try-catches that contain a pop within
+ // them.
+ if (!FindAll<Pop>(item).list.empty()) {
+ return false;
+ }
+ // When an expression can throw and it is within a try scope, taking it
+ // out of the try scope changes the program's behavior, because the
+ // expression that would otherwise have been caught by the try now
+ // throws up to the next try scope or even up to the caller. We restrict
+ // the move if 'outOf' contains a 'try' anywhere in it. This is a
+ // conservative approximation because there can be cases that 'try' is
+ // within the expression that may throw so it is safe to take the
+ // expression out.
+ if (EffectAnalyzer(getPassOptions(), getModule()->features, item)
+ .throws &&
+ !FindAll<Try>(outOf).list.empty()) {
+ return false;
+ }
}
}
return true;