IL call vs. callvirt, part two
In the first part I wrote about what is call and callvirt, what the differences and why should I care. We saw that even non-virtual methods called via callvirt instruction because the nullcheck reason. But with this sense when this is not in use or when thiscan’t be null there is no need to check for *null.*for example: static class. And indeed for those cases the compiler emit call instruction.
Here is the cases that call instruction will emit:
static class methods
struct methods
new MyClass().SampleMethod();
The C# compiler / jit compiler know that it can’t be null so it generating a call instruction
What do you think happening here?
var c = new MyClass();
c.MyMethod();
Is this same as
new MyClass().MyMethod();
Check it yourself with reflectoror with Ildasm :-)
For who that want to know how all of those seem in ‘real life’ (it’s also answering on the above question), given the following code:
C#:
static void Main(string[] args)
{
var a = new myclass();
a.mymethod(args.Length);
}
IL: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 17 (0x11) .maxstack 2 .locals init ([0] class sealedvsnon.myclass a) IL_0000: newobj instance void sealedvsnon.myclass::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.0 IL_0008: ldlen IL_0009: conv.i4 IL_000a: callvirt instance int32 sealedvsnon.myclass::mymethod(int32) IL_000f: pop IL_0010: ret } // end of method Program::Main
Disassembly:00CD0099 cmp dword ptr [ecx],ecx 00CD009B call dword ptr ds:[0BE380Ch]
As you can see callvirtand cmphas used.
And with the following code: C#:
static void Main(string[] args)
{
new myclass().mymethod(args.Length);
}
IL:.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 15 (0xf) .maxstack 8 IL_0000: newobj instance void sealedvsnon.myclass::.ctor() IL_0005: ldarg.0 IL_0006: ldlen IL_0007: conv.i4 IL_0008: call instance int32 sealedvsnon.myclass::mymethod(int32) IL_000d: pop IL_000e: ret } // end of method Program::Main
Disassembly:01220088 mov ecx,dword ptr [ebp-0Ch] 0122008B call dword ptr ds:[11C380Ch]
And here you can see that non callvirt or cmphas used.