Description
This probably will end up in the future releases wishlist, but it something that has been looking forward for a long time already.
Lets say that we have this code:
public class Executer<T> where T : ICalls
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute(T instance)
{
instance.Execute();
}
}
And we have the following instances:
private readonly Executer<ClassCalls> _classCalls = new Executer<ClassCalls>();
private readonly Executer<ICalls> _interfaceCalls = new Executer<ICalls>();
private readonly Executer<SealedClassCalls> _sealedCalls = new Executer<SealedClassCalls>();
Now we would expect that the call for _classCalls.Execute(x) would be different than for _interfaceCalls(x). Apparently that is not the case, the JIT stops at the first level even if have the complete information to emit highly optimized code for that call-site.
Now, supposed the implementation is:
public class ClassCalls : ICalls
{
public static int i;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute()
{
i = 0;
i++;
}
}
There is no way that the JIT would inline that code, even if for all purposes it is safe to do so.
The scenario for this pattern is pretty common in high performance code where the calls are very small, in tight loops but must be able to handle more than a single type... An example is a BitVector with variants for MemoryMappedBitVector, UnsafeBitVector, LongBitVector and so on. Operations tend to be very small and executed in very tight loops.
Today we either need a different codepath for each one, or pay the call tax.
category:cq
theme:inlining
skill-level:expert
cost:large