IL Call Vs. Callvirt Instruction 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 null check reason.
But with this sense when this is not in use or when this can’t be null there is no need to check for nullfor 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# compilerjit 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 reflector or 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 callvirt and cmp has 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 cmp has used.

Advertisements
This entry was posted in .NET and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s