Skip to content

[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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

BrzVlad
Copy link
Member

@BrzVlad BrzVlad commented Jun 4, 2025

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.

@Copilot Copilot AI review requested due to automatic review settings June 4, 2025 10:41
Copy link
Contributor

@Copilot Copilot AI left a 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.

Copy link
Contributor

Tagging subscribers to this area: @BrzVlad, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

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`.
@BrzVlad BrzVlad force-pushed the fix-interp-ssa-catch-goto branch from 6f83e31 to 1153e64 Compare June 4, 2025 10:47
@jakobbotsch
Copy link
Member

I'm curious – I thought Mono handled variable uses reachable from EH conservatively (from our discussion in #96315 (comment)). Is it not the case?

@BrzVlad
Copy link
Member Author

BrzVlad commented Jun 4, 2025

Yes, that is how it works. If ret was used in the catch handler everything would work ok. However, in our case, ret is not such a variable since it is not used in exception handlers. So the problem is not really with variables used in EH handlers, but rather the control flow for the rest of the code, when jumping from catch handler. Before this change, the optimizations were not aware that there is a possible try -> catch -> Label flow, so code would have been optimized to always return false.

@jakobbotsch
Copy link
Member

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);
Copy link
Member

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.

Copy link
Member Author

@BrzVlad BrzVlad Jun 5, 2025

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.

@BrzVlad BrzVlad added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Codegen-Interpreter-mono NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants