From C# to CLR Jitted Code - Call Delegate

How expensive is a delegate call vs a direct function call? The delegate call is actually pretty fast. The delegate typically stores the function and the calling target. When we invoke the delegate, the JIT will retrieve the function pointer and the target and complete the call. You can see from below example.

Here is the C# code

public class CallDelegate

{

[MethodImpl(MethodImplOptions.NoInlining)]

public static void Run()

{

Foo();

RetVoid f1 = new RetVoid(Foo);

f1(); /// Delegate invoke

}

[MethodImpl(MethodImplOptions.NoInlining)]

public static void Foo()

{

Console.WriteLine("foo");

}

}

L_0000: nop

L_0001: call void JitBlog.CallDelegate::Foo()

L_0006: nop

L_0007: ldnull

L_0008: ldftn void JitBlog.CallDelegate::Foo()

L_000e: newobj instance void JitBlog.RetVoid::.ctor(object, native int) // Build the delegate objiect

L_0013: stloc.0

L_0014: ldloc.0

L_0015: callvirt instance void JitBlog.RetVoid::Invoke() // Delegate invoke

L_001a: nop

L_001b: ret

Here is the disassmbly

call [CallDelegate.Foo()]

nop

mov ECX, 0x1f336c8 //Type of delegate

call CORINFO_HELP_NEWSFAST_CHKRESTORE

mov ESI, EAX

mov EAX, 0x1f3c090

push EAX

push 0x4220f8 // Delegate stub

mov ECX, ESI

xor EDX, EDX

call MulticastDelegate.CtorOpened(ref,int,int)

nop

mov EDI, ESI

mov ECX, EDI

mov EAX, dword ptr [ECX+12] // Retrieve the function pointer from the Delegate

mov ECX, gword ptr [ECX+4] // Retrieve the target object address from the target

call EAX // complete the call