-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Not inlining trivial default interface method on known struct #39419
Comments
The type of Default interface methods are better to be avoided in high performance code. |
It manages to inline it when using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
interface IM
{
bool UseDefaultM { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; }
ValueTask M(int instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false");
static ValueTask DefaultM(int instance) {
Console.WriteLine("Default Behaviour");
return default;
}
}
struct M : IM {}
public static class Program
{
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
static void Main()
{
var m = new M();
if (((IM)m).UseDefaultM)
{
IM.DefaultM(42);
}
else
{
((IM)m).M(42);
}
}
} |
#9588 is probably the main reason then. |
A decent workaround is: using System;
using System.Threading.Tasks;
interface IM
{
bool UseDefaultM { get => true; }
}
interface IM<T> : IM
{
ValueTask M(T instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false");
static ValueTask DefaultM(T instance) {
Console.WriteLine("Default Behaviour");
return default;
}
}
struct M : IM<int> {}
public static class Program
{
static void Main()
{
var m = new M();
if (((IM<int>)m).UseDefaultM)
{
IM<int>.DefaultM(42);
}
else
{
((IM<int>)m).M(42);
}
}
} |
Right, devirtualization is failing in I should plumb through failure reason reporting and pass the reason back to the jit, so it's more obvious on the jit side what is happening. Currently we just see a generic failure:
Going to mark this as future and relabel as a VM issue. |
The VM side is tracked in #9588 so we can just call this a dup and close. |
Consider the following code:
I was hoping to use this pattern to avoid boxing m, since I would have expected
UseDefaultM
to be inlined, therefore avoiding boxingm
when it's a struct, since either the staticDefaultM
method will be called, or the instance ofIM
overrides the DIM forM
in which case it doesn't require boxing. However when I look at the jit asm on sharplab, it appears this isn't happening.EDIT
Note that this does work when IM is non-generic:
The jit works out that
IM.DefaultM
is always called and removes bothUseDefaultM
and((IM)m).M(42)
from the generated asm:The text was updated successfully, but these errors were encountered: