Why can't the jit inline the generated code?
Assuming the functions and types are known in advance, no virtuals etc: given something like `Main` calling `DoSomething` calling `GetPropertyValue` which is
public int GetPropertyValue(MyObject myObject) { return myObject.PropertyValue; }
When RyuJit compiles your application, it can see these methods and how they're called. `PropertyValue` can be inlined into a field access, `GetPropertyValue` can be inlined into `DoSomething` which in turn can be inlined into `Main`.When you do something like the article:
Func<TestClass, string> getDelegate =
(Func<TestClass, string>)Delegate.CreateDelegate(
typeof(Func<TestClass, string>),
property.GetGetMethod(nonPublic: true));
[Benchmark]
public string GetViaDelegate()
{
return getDelegate(testClass);
}
RyuJit can't see that `getDelegate` is the equivalent of `return myObject.PropertyValue`. It's a reference to some function. RyuJit has to compile calling an arbitrary method vs. calling `GetPropertyValue`.I don't know if they've ever implemented this for delegates, though.
class Program {
interface IFunc<T1, T2, TResult> {
TResult Invoke(T1 x1, T2 x2);
}
struct AddInt32 : IFunc<int, int, int> {
public int Invoke(int x, int y) {
return x + y;
}
}
static T FoldLeft<T, F>(T[] xs, F f) where F : IFunc<T, T, T> {
var res = xs[0];
for (int i = 1; i < xs.Length; ++i) {
res = f.Invoke(res, xs[i]);
}
return res;
}
static void Main() {
Console.ReadKey();
int[] xs = { 1, 2, 3, 5, 8 };
int res = FoldLeft(xs, new AddInt32());
Console.WriteLine(res);
}
}
I compiled and ran it with 3.5 SP1 x86 (the old 64-bit JIT wasn't good, and won't inline in this case). It didn't inline FoldLeft, but it did inline AddInt32 into the loop - this is from VS debugger disassembly: for (int i = 1; i < xs.Length; ++i) {
017B0106 mov edx,1
017B010B mov edi,dword ptr [ecx+4]
017B010E cmp edi,1
017B0111 jle 017B011E
res = f.Invoke(res, xs[i]);
017B0113 mov eax,dword ptr [ecx+edx*4+8]
017B0117 add esi,eax
for (int i = 1; i < xs.Length; ++i) {
017B0119 inc edx
017B011A cmp edi,edx
017B011C jg 017B0113
}My question is what is special about the code that is written into memory by code generation that distinguishes it by code written into memory at program startup. I can't think of anything off the top of my head that would make inlining dynamically generated code impossible, short of possibly not wanting to toss away already jitted code