-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Fix GC hole with STOREIND of LCL_VAR_ADDR/LCL_FLD_ADDR #45818
Conversation
See #45557 for more detailed IL + code analysis. Additional work:
|
cc @dotnet/jit-contrib |
/azp run runtime-coreclr outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
It seems like the same change should be made in |
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.
Should we assert over in UpdateLifeVar
if we see addresses?
Will be interesting to determine whether this is a long-standing issue that somehow just surfaced now. From what I can tell the emitter/codegen parts haven't changed in a few years.
This code in
so an assert wouldn't have helped in this case; not sure it would help in any other case.
Yes, these lines of code have been there a long time. My guess is that we never saw STOREIND with ref types until recently (maybe some of the struct work?), as they would have been block ops or STORE_OBJ instead. |
How unfortunate. Seems like we have a fairly fragile contract here... |
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.
LGTM, thanks for the detailed analysis.
We were updating the GC liveness of the ADDR node, but `genUpdateLife()` expects to get the parent node, so no liveness was ever updated. There were 4 SPMI GC info diffs in the libraries, all related to uses of `System.Collections.Immutable.ImmutableArray` where we struct promote fields who are themselves single-element gc ref structs that are kept on the stack and not in registers. In all cases, the liveness of the stack local was not reflected in codegen's GC sets, but it was reflected in the emitter's GC sets, so it was marked as a GC lifetime. However, that lifetime would get cut short if we hit a call site before the last use, as calls (sometimes) carry the full set of live variables across the call. So, variables not in this set (including the "accidental" emitter-created GC lifetimes here) would get killed, leaving a hole between the intermediate call and actual stack local last use. Fixes dotnet#45557
62a69cf
to
0147e21
Compare
Backport of (part of) dotnet#45818 to release/5.0 Fixes: dotnet#45557 Reported by Roslyn. Bad GC info can lead to an unexplained crash that can't easily be found or worked around. Manual, new unit test, CLR outerloop, SuperPMI asm diffs. Low
Did you determine if this was a regression in 5.0? |
Yes, this looks like a regression in 5.0, apparently due to keeping struct types around instead of "unwrapping" or bashing the type to the single-element struct ref type. |
We were updating the GC liveness of the ADDR node, but
genUpdateLife()
expects to get the parent node, so noliveness was ever updated.
There were 4 SPMI GC info diffs in the libraries, all
related to uses of
System.Collections.Immutable.ImmutableArray
where we struct promote fields who are themselves single-element
gc ref structs that are kept on the stack and not in registers.
In all cases, the liveness of the stack local was not reflected
in codegen's GC sets, but it was reflected in the emitter's GC
sets, so it was marked as a GC lifetime. However, that lifetime
would get cut short if we hit a call site before the last use,
as calls (sometimes) carry the full set of live variables across
the call. So, variables not in this set (including the
"accidental" emitter-created GC lifetimes here) would get killed,
leaving a hole between the intermediate call and actual stack
local last use.
Fixes #45557