Skip to content
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

Avoid reusing temps whose refs might be captured #76009

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Nov 21, 2024

Fixes #67435.

The idea is to have a "heuristic" to detect whether a method might capture the references passed to it. If such method call is detected, and a temporary reference is being emitted, we avoid freeing the temp so it lives during the whole method instead of just the expression.

The heuristic is implemented by CodeGenerator.MightEscapeTemporaryRefs. It runs on the lowered nodes (because it's the emit layer which decides to emit a temporary). It might have false positives (some calls like M(rvalue, out _) might be marked by the heuristic as dangerous but they are not), but it shouldn't have false negatives.

Without a heuristic, we would need to avoid reusing many more temps, which would be a regression (at least in IL size). But perhaps that's negligible and it would be better to avoid this complexity? I'm not sure.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Nov 21, 2024
@jjonescz jjonescz marked this pull request as ready for review November 21, 2024 18:32
@jjonescz jjonescz requested a review from a team as a code owner November 21, 2024 18:32
expanded: false);
}

private static bool MightEscapeTemporaryRefs(
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 22, 2024

Choose a reason for hiding this comment

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

MightEscapeTemporaryRefs

I will let Ref-Safety experts to make a call on completeness/correctness of the code in this method. However, it would be good to add comments about explaining the logic. #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

Agree having a strategy comment would help. Not intuitive at a glance why we're using the approach of counting refs 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.

The ref counters have comments and then they are used to compute the return value, also commented in the shouldReturnTrue local function. But I will add another higher-level comment.

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 1), tests are not looked at.

@jaredpar jaredpar removed the untriaged Issues and PRs which have not yet been triaged by a lead label Nov 26, 2024
@jjonescz jjonescz marked this pull request as draft November 27, 2024 11:03
@jjonescz jjonescz marked this pull request as ready for review November 28, 2024 09:19
@jjonescz jjonescz requested a review from AlekseyTs December 4, 2024 20:25
@AlekseyTs
Copy link
Contributor

Done with review pass (commit 6)

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 9). However, this should not be considered as a sign-off on MightEscapeTemporaryRefs method. I think we should get a sign-off for its logic from two "ref safety" experts, at least.

{
if (localDef != null)
{
_addressedLocals?.Add(localDef);
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 10, 2024

Choose a reason for hiding this comment

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

_addressedLocals?.Add(localDef);

Should user defined locals be a subject for this treatment? Presumably ref safety for them was verified during binding. Let's add a unit test with a scenario affecting a user local.

Copy link
Member

Choose a reason for hiding this comment

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

my intuition was that this should impact temps only so share the concern about user defined locals.

Copy link
Member Author

@jjonescz jjonescz Dec 11, 2024

Choose a reason for hiding this comment

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

This does not have any effect on user-defined locals - they are ignored by CodeGenerator.FreeLocal, i.e., they are never reused anyway, regardless of whether we add them to the _addressedLocals and _nonReusableLocals lists. But I could filter them here as well, i.e., avoid adding them to those lists in the first place if you think that would be better.

Let's add a unit test with a scenario affecting a user local.

Not sure which exact scenario you are looking for. There is for example RefEscapingTests.RefTemp_NoTemp added as part of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

But I could filter them here as well, i.e., avoid adding them to those lists in the first place if you think that would be better.

Yes, I think it would be better to be explicit about handling of user-defined locals.

@jjonescz
Copy link
Member Author

@dotnet/roslyn-compiler for a second review, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants