-
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
Insert a breakpoint instruction after throwing calls #101037
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
A fairly trivial change - mostly moving insertion of BRK from one place to another which should result in covering a few places that older approach missed. Somehow it causes crossgen2 to assert and then hang when building clr subset:
If crossgen is disabled, product builds and tests run. |
The failures are indeed around places where we could pick a few cases not covered before.
[SupportedOSPlatform("windows")]
public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) =>
OpenExistingWorker(name, out result!) == OpenExistingResult.Success; and private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle? result)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
} Since the throwing call is an argument to a comparison, it is very possible that it had some dead code after the call and was not seen by the previous approach, since the call is not at the end of the block. But weird thing is that this does not impact normal execution of tests and seems to only impact crossgen. |
@@ -394,7 +394,7 @@ | |||
Test="true" Category="tools"/> | |||
</ItemGroup> | |||
|
|||
<ItemGroup Condition="$(_subset.Contains('+clr.nativecorelib+'))"> | |||
<ItemGroup Condition="$(_subset.Contains('+clr.nativecorelib+')) and '$(TargetArchitecture)' != 'arm'"> |
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.
A temporary workaround for the crossgen assert/hang.
Maybe there is a better solution...
Did you look into breaking trees with no return calls and discarding anything that comes later? Would be nice if there weren't special cases like this. |
From the discussion #100900 (comment) it seemed that there are cases where this situation cannot be easily fixed and adding a breakpoint after calls is a more robust strategy. |
I agree that removing dead code is a good thing on its own though. Dead code could be a nuisance, since it may not conform with general invariants and in the end is not needed, so removing it is often better than figuring how to deal with situations that arise. I have seen code that tries to remove everything in a block after a throwing call, but it looks like it does not always work. Perhaps some cases materialize too late. |
Morph does this, but at statement level granularity, so if the throwing call is a subtree it may leave stuff up above sometimes. It may be painful to clean up in tree form. Once we get to linear form it should be simpler to get rid of whatever comes after the call. |
That sounds like just stop emitting the block (and perhaps wiping the rest) after seeing a no-return call. Is that the idea? |
More or less, yes. There may be a bit more to it than that, if the throwing call's use has other uses you may need to mark them as unused or something. |
Would be an interesting thing to try. But we will still insert BRK in One reason for this could be that Even if we insert BRK in codegen, |
Actually that is not very important. The extra instructions could be redundant, but if the breakpoint comes after, it is still ok. |
Interesting failure. We morph binary operators that are statically overflowing into runtime/src/coreclr/jit/gentree.cpp Line 16327 in b35b67d
It looks like 0 literals can consume temps, so if I just drop the rest of the block, I get
Is there a way to manufacture a value that would not use any kind of temp? Alternatively - maybe we can tell that this instance of CORINFO_HELP_OVERFLOW actually returns nonvoid type and use it as-is, not wrap it in a comma. Also the problem with temps could be more general than just this case. I am not sure yet. |
Can you share a jitdump? It sounds to me like the call node has a user if it is ending up with a temp, and that the 0 there is unrelated. How are you removing the nodes after the call? It should be simple to do that at the end of |
I think this is obsolete now. We do the same as a result of interruptibility change which inserts breakpoints in these locations. |
A follow up for #100900
See discussion at: #100900 (comment)
Instead of inserting a breakpoint at the end of
BBJ_THROW
blocks that end on a throwing call, we insert a breakpoint after throwing calls.The change should end up with roughly the same number of added breakpoint instructions, since a BBJ_THROW nearly always ends with a throwing call anyways. However, this approach would be more robust in rare situations when a throwing call is followed by some extra code, which may potentially be removed at later phases.