Skip to content

Add fixup function for nested pops in catch #4348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 22, 2021

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Nov 19, 2021

This adds EHUtils::handleBlockNestedPops, which can be called at the
end of passes that has a possibility to put pops inside blocks. This
method assumes there exists a pop in a first-descendant line, even
though it can be nested within a block. This allows a pop to be nested
within a block or a try, but not a loop, since that means the
pop can run multile times. In case of if, pop can exist only in
its condition; if a pop is in its true or false body, that's not in
the first-descendant line.

This can be useful when optimization passes create blocks to do
transformations. Wrapping expressions wiith a block does not change
semantics most of the time, but if pops happen to be inside a block
generated by those passes, they can result in invalid binaries.

To test this, this adds passes/test_passes.cpp, which is intended to
contain multiple test passes that test a single (or more) utility
functions separately. Without this kind of pass, it is hard to test
various cases in which nested pops can be generated in existing
passes. This PR also adds PassRegistry::registerTestPass, which
registers a pass that's intended only for internal testing and does not
show up in wasm-opt --help.

Fixes #4237.

@aheejin aheejin requested review from kripken and tlively November 19, 2021 22:24
This adds `EHUtils::handleBlockNestedPops`, which can be called at the
end of passes that has a possibility to put `pop`s inside `block`s. This
method assumes there exists a `pop` in a first-descendant line, even
though it can be nested within a block. This allows a `pop` to be nested
within a `block` or a `try`, but not a `loop`, since that means the
`pop` can run multile times. In case of `if`, `pop` can exist only in
its condition; if a `pop` is in its true or false body, that's not in
the first-descendant line.

To test this, this adds `passes/test_passes.cpp`, which is intended to
contain multiple test passes that test a single (or more) utility
functions separately. Without this kind of pass, it is hard to test
various cases in which nested `pop`s can be generated in existing
passes. This PR also adds `PassRegistry::registerTestPass`, which
registers a pass that's intended only for internal testing and does not
show up in `wasm-opt --help`.

Fixes WebAssembly#4237.
Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, generally lgtm % comments (some of which I'm not sure about).

@@ -20,6 +20,8 @@
namespace wasm {

class Expression;
class Function;
class Module;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I noticed this before, but looks like it avoids including wasm.h by adding these forward declarations? Given there are 3 of them I think a single line that includes "wasm.h" would be shorter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I tried to avoid includes if possible (just as general recommendations), but in this case that might not matter much anyway...

try_->catchBodies[i] =
builder.makeSequence(builder.makeLocalSet(newLocal, pop), catchBody);
*popPtr = builder.makeLocalGet(newLocal, pop->type);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should call handleNondefaultableLocals as well for the non-nullable local case, as I assume it's possible to pop a non-nullable type?

(All these corner cases stack up, sadly...)

Copy link
Member Author

@aheejin aheejin Nov 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, thanks. I added $pop-non-defaultable-type-within-block to test this case too.

src/pass.h Outdated
std::unique_ptr<Pass> createPass(std::string name);
std::vector<std::string> getRegisteredNames();
std::vector<std::string> getRegisteredNames(bool includeHidden = false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about an enum for Hidden/Visible? Can be used on line 58 too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the hidden property to option, so this code is gone now.. PTAL at the new code and let me know if that looks fine.

@aheejin
Copy link
Member Author

aheejin commented Nov 20, 2021

Hmm, the hidden property should be also in Option I think after all...

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm % comments

}
if (firstChild->is<Try>()) {
isPopNested = true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about switching the sequence of ifs to a chain of if-else, and then add WASM_UNREACHABLE at the end? Then if we add a new control flow instruction in the future it would error here, which could help avoid some future debugging.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -1,12 +1,18 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --no-validation --catch-pop-fixup -all -S -o - | filecheck %s
;; RUN: wasm-opt %s --catch-pop-fixup --no-validation -all -S -o - | filecheck %s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment about why no-validation is used here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@aheejin aheejin merged commit 3c1c8ae into WebAssembly:main Nov 22, 2021
@aheejin aheejin deleted the catch_fixup branch November 22, 2021 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pop in catch emitted inside a block ("not enough arguments on the stack" from VM)
2 participants