diff options
author | Heejin Ahn <aheejin@gmail.com> | 2024-04-24 00:59:36 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-24 00:59:36 +0900 |
commit | 3b9dc42525553653d7477874e854584e957887b2 (patch) | |
tree | a53c1467e4f44eb0352afacbd8333c0baf03cde1 /src/passes/TranslateEH.cpp | |
parent | 4bbae113dc144f80ff4880c74c7068a9f7b14295 (diff) | |
download | binaryen-3b9dc42525553653d7477874e854584e957887b2.tar.gz binaryen-3b9dc42525553653d7477874e854584e957887b2.tar.bz2 binaryen-3b9dc42525553653d7477874e854584e957887b2.zip |
[EH] Fix missing outer block for catchless try (#6519)
When translating a `try` expression, we may need an 'outer' block that
wraps the newly generated `try_table` so we can jump out of the
expression when an exception does not occur. (The condition we use is
when the `try` has any catches or if the `try` is a target of any
inner `try-delegate`s:
https://github.com/WebAssembly/binaryen/blob/219e668e87b012c0634043ed702534b8be31231f/src/passes/TranslateEH.cpp#L677)
In case the `try` has either of `catch` or `delegate`, when we have the
'outer' block, we add the newly created `try_table` in the 'outer' block
and replace the whole expression with the block:
https://github.com/WebAssembly/binaryen/blob/219e668e87b012c0634043ed702534b8be31231f/src/passes/TranslateEH.cpp#L670
https://github.com/WebAssembly/binaryen/blob/219e668e87b012c0634043ed702534b8be31231f/src/passes/TranslateEH.cpp#L332-L340
But in case of a catchless `try`, we forgot to do that:
https://github.com/WebAssembly/binaryen/blob/219e668e87b012c0634043ed702534b8be31231f/src/passes/TranslateEH.cpp#L388
So this PR fixes it.
Diffstat (limited to 'src/passes/TranslateEH.cpp')
-rw-r--r-- | src/passes/TranslateEH.cpp | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/src/passes/TranslateEH.cpp b/src/passes/TranslateEH.cpp index 33fa4689d..f8e059624 100644 --- a/src/passes/TranslateEH.cpp +++ b/src/passes/TranslateEH.cpp @@ -215,7 +215,9 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { // current 'try' into 'try_table' yet; it only adds block, br, and throw_ref // instructions to complete the conversions of inner try~delegates that target // the current try. - void processDelegateTarget(Try* curr, Block* outerBlock) { + void processDelegateTarget(Try* curr, + Block* outerBlock, + bool& outerBlockUsedSoFar) { Builder builder(*getModule()); // Convert @@ -291,10 +293,12 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { Name delegateBrTarget = delegateTargetToBrTarget[curr->name]; Expression* innerBody = nullptr; if (curr->type.isConcrete()) { + outerBlockUsedSoFar = true; auto* brToOuter = builder.makeBreak(outerBlock->name, curr->body); innerBody = builder.blockifyWithName( brToOuter, delegateBrTarget, nullptr, Type(HeapType::exn, Nullable)); } else { + outerBlockUsedSoFar = curr->body->type != Type::unreachable; auto* brToOuter = curr->body->type == Type::unreachable ? nullptr : builder.makeBreak(outerBlock->name); @@ -304,7 +308,7 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { curr->body = builder.makeThrowRef(innerBody); } - void processDelegate(Try* curr, Block* outerBlock) { + void processDelegate(Try* curr, Block* outerBlock, bool outerBlockUsedSoFar) { Builder builder(*getModule()); // Convert // (try @@ -332,7 +336,7 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { // If we need an outer block for other reasons (if this is a target of a // delegate), we insert the new try_table into it. If not we just replace // the current try with the new try_table. - if (outerBlock) { + if (outerBlock && outerBlockUsedSoFar) { outerBlock->list.push_back(tryTable); replaceCurrent(outerBlock); } else { @@ -340,7 +344,7 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { } } - void processCatches(Try* curr, Block* outerBlock) { + void processCatches(Try* curr, Block* outerBlock, bool outerBlockUsedSoFar) { Module* wasm = getModule(); Builder builder(*wasm); @@ -385,7 +389,15 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { // If we don't have any catches, we don't need to do more. if (curr->catchBodies.empty()) { // catch-less try - replaceCurrent(tryTable); + // If we need an outer block for other reasons (if this is a target of a + // delegate), we insert the new try_table into it. If not we just replace + // the current try with the new try_table. + if (outerBlock && outerBlockUsedSoFar) { + outerBlock->list.push_back(tryTable); + replaceCurrent(outerBlock); + } else { + replaceCurrent(tryTable); + } return; } @@ -679,13 +691,14 @@ struct TranslateToNewEH : public WalkerPass<PostWalker<TranslateToNewEH>> { builder.makeBlock(labels->getUnique("outer"), {}, curr->type); } + bool outerBlockUsedSoFar = false; if (it != delegateTargetToBrTarget.end()) { - processDelegateTarget(curr, outerBlock); + processDelegateTarget(curr, outerBlock, outerBlockUsedSoFar); } if (curr->isDelegate()) { - processDelegate(curr, outerBlock); + processDelegate(curr, outerBlock, outerBlockUsedSoFar); } else { // try-catch or catch-less try - processCatches(curr, outerBlock); + processCatches(curr, outerBlock, outerBlockUsedSoFar); } } |