You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This looks like JIT stress issue. JIT stress converted delegate call to tailcall. This conversion is not valid when the delegate points to virtual interface method.
This looks like JIT stress issue. JIT stress converted delegate call to tailcall. This conversion is not valid when the delegate points to virtual interface method.
What exactly do you mean by virtual interface method here? Do you mean any call that may go through VSD?
Here is what is happening based on the crash dump:
// This delegate points to shuffle thunk that in turn points to VSD stub
// The VSD stub expects the callsite to be VSD DelegateCallSite.
var d = typeof(IFace).GetMethod("Method").CreateDelegate<Action<IFace>>();
var c = new ClassA();
// JIT stress converted this to tailcall. The callsite is not identified as
// DelegateCallSite anymore and that's why we get the assert.
d(c);
public class ClassA : IFace
{
public virtual void Method() { Console.WriteLine("Method"); }
}
public interface IFace
{
public void Method();
}
it is curious that this seemingly used to work.
These delegates pointing to VSD stubs are very rare. It is quite possible that it was broken for a long time and we just got lucky that the JIT stress did not hit it before.
These delegates pointing to VSD stubs are very rare. It is quite possible that it was broken for a long time and we just got lucky that the JIT stress did not hit it before.
I see, thanks for the example. In practice does this mean that tail prefixed delegate calls cannot be done through the old mechanism?
The other half of why we may not have seen this before is that isCallRelativeIndirect inside StubCallSite::StubCallSite needs to pass, i.e. the tailcaller's caller need to be on the form call [rel32]. If that check does not pass the VSD resolver properly sees the call as a delegate call.
Activity
jkotas commentedon Jun 5, 2022
This looks like JIT stress issue. JIT stress converted delegate call to tailcall. This conversion is not valid when the delegate points to virtual interface method.
BruceForstall commentedon Jun 5, 2022
@jakobbotsch Related to #69941? #70033?
jakobbotsch commentedon Jun 5, 2022
Probably #70033, though it is curious that this seemingly used to work. Maybe something rotted in the period that the JIT helper was not being used.
jakobbotsch commentedon Jun 5, 2022
@jkotas
What exactly do you mean by virtual interface method here? Do you mean any call that may go through VSD?
jkotas commentedon Jun 5, 2022
Here is what is happening based on the crash dump:
These delegates pointing to VSD stubs are very rare. It is quite possible that it was broken for a long time and we just got lucky that the JIT stress did not hit it before.
jakobbotsch commentedon Jun 5, 2022
I see, thanks for the example. In practice does this mean that tail prefixed delegate calls cannot be done through the old mechanism?
jkotas commentedon Jun 5, 2022
Right.
It may be possible to fix up the x86
JIT_TailCallhelper to handle this case, but I do not think that it is worth it.jakobbotsch commentedon Jun 5, 2022
The other half of why we may not have seen this before is that
isCallRelativeIndirectinsideStubCallSite::StubCallSiteneeds to pass, i.e. the tailcaller's caller need to be on the formcall [rel32]. If that check does not pass the VSD resolver properly sees the call as a delegate call.Always use portable tailcalling mechanism for delegate tailcalls
Always use portable tailcalling mechanism for delegate tailcalls (#70269