-
Notifications
You must be signed in to change notification settings - Fork 5.1k
[mono][interp] Link try bblock with leave targets from catch block #116298
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes the control flow issue in the interpreter by linking try basic blocks with corresponding leave targets from catch blocks to ensure correct SSA dominance and phi node management.
- Introduces a new flag "linked_try_bblocks" in the TransformData structure.
- Adds DFS logic to connect try blocks to leave targets when processing exception handling edges in the CFG.
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
src/mono/mono/mini/interp/transform.h | Added a flag to track linking of try blocks. |
src/mono/mono/mini/interp/transform-opt.c | Implemented DFS linking for try blocks and updated DFS visitation to invoke linking. |
Tagging subscribers to this area: @BrzVlad, @kotlarmilos |
Otherwise SSA dominance algorithms may fail to detect certain code flow and incorrectly manage phi nodes. public bool M() { bool ret = true; try { // throw NULL } catch (NullReferenceException) { goto Label; } ret = false; Label: return ret; } Without this fix, given the SSA cfg doesn't include EH bblocks, we would see the return opcode always reachable through the fallthrough from `ret = false`.
6f83e31
to
1153e64
Compare
I'm curious – I thought Mono handled variable uses reachable from EH conservatively (from our discussion in #96315 (comment)). Is it not the case? |
Yes, that is how it works. If |
Ok -- so it's only for variables used directly in EH clauses, not for variable uses reachable from EH clauses. |
gboolean *marked = (gboolean*)g_malloc0 (sizeof (gboolean) * num_eh_bblocks); | ||
for (int i = td->bblocks_count_no_eh; i < td->bblocks_count_eh; i++) { | ||
if (td->bblocks [i]->try_bblock && td->bblocks [i]->try_bblock->dfs_index < td->bblocks_count_no_eh) | ||
dfs_link_try_bblock (td, td->bblocks [i], stack, marked); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the marked
array should be reset between DFS runs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wasn't necessary because we would never scan overlapping regions of code. However, this made me realize that if we have the same pattern inside a catch handler, then once again this fix is not enough. Having those nested catch blocks scanned also seems to be getting a bit too complex for what it's worth. I think I'll just end up disabling SSA optimizations for methods where a leave in a catch goes to a bblock that is not already a successor for the try bblock.
Otherwise SSA dominance algorithms may fail to detect certain code flow and incorrectly manage phi nodes.
Without this fix, given the SSA cfg doesn't include EH bblocks, we would see the return opcode always reachable through the fallthrough from
ret = false
.