diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/CodeFolding.cpp | 29 |
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; |