Pages

Thursday, November 4, 2010

IL In depth look

IL In depth Look

This is next in the series of IL programming, facts, and cool stuff thats happening there, that's totally useless if you are doing a day to day job and probably some website, but it's good to know how things work on the byte code level to get a grater understanding of the platform and write better code and do some IL level optimalisations when needed.

Lets Start.

Right so normally when you have such a simple code like this:

class Program
    {
        static void Main(string[] args)
        {
            Console.Write("I was called from " + 
                MethodInfo.GetCurrentMethod().Name);
            Console.ReadKey();
        }

        static void Test(string[] args)
        {
            Console.Write("I was called from " + 
                MethodInfo.GetCurrentMethod().Name);
            Console.ReadKey();
        }
    }

the entry point is always main, normally you can change it in visual studio or by compiling the code with csc.exe, but how is this possible to change entry points exactly? If you look at the IL of the code you will see something like this.

.class private auto ansi beforefieldinit ConsoleApplication.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
   
    // Code size       34 (0x22)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "I was called from"
    IL_0006:  call       class [mscorlib]System.Reflection.MethodBase
                             [mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
    IL_000b:  callvirt   instance string [mscorlib]System.Reflection.MemberInfo::get_Name()
    IL_0010:  call       string [mscorlib]System.String::Concat(string,
                                                                string)
    IL_0015:  call       void [mscorlib]System.Console::Write(string)
    IL_001a:  nop
    IL_001b:  call       valuetype [mscorlib]System.ConsoleKeyInfo 
                             [mscorlib]System.Console::ReadKey()
    IL_0020:  pop
    IL_0021:  ret
  } // end of method Program::Main

  .method private hidebysig static void  Test(string[] args) cil managed
  {
    .entrypoint
    // Code size       34 (0x22)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "I was called from"
    IL_0006:  call       class [mscorlib]System.Reflection.MethodBase 
                            [mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
    IL_000b:  callvirt   instance string [mscorlib]System.Reflection.MemberInfo::get_Name()
    IL_0010:  call       string [mscorlib]System.String::Concat(string,
                                                                string)
    IL_0015:  call       void [mscorlib]System.Console::Write(string)
    IL_001a:  nop
    IL_001b:  call       valuetype [mscorlib]System.ConsoleKeyInfo 
                             [mscorlib]System.Console::ReadKey()
    IL_0020:  pop
    IL_0021:  ret
  } // end of method Program::Test

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class ConsoleApplication.Program

In this code the ".entrypoint" is responsible for setting the startup method on the code, in this case I changed it to Test, so the app will start from that place.

This simple piece of IL code has lot's of interesting properties besides the application's entrypoint, that are worth to look like:

.maxstack that informs JIT what is the maximum size of the stack for the method, but as far as I know this is just informal and it's not used in the standard implemenatation of the VM.

specialname that is an informal field and informs about static methods/fields, marshaling and some internal operations in the framework.

.hidebysig  that hides by name and signature, that basically means that you can call the base method form the derived class that has the same method name with different parameters, because the derived method does't hide the base one, so just by deleting this parameter different behavior can be enforced.

This concludes this part of my post, I will be writing more on the IL topic when I find something cool and do some research on it, this is not an easy topic but that makes it exciting and interesting :-)

No comments:

 
ranktrackr.net