Mad about .NET A blog from Jose Fco Bonnin


One of the features we have in .NET is the ability to execute IL code generated dynamically, in fact there is a complete namespace to generate code at runtime called System.Reflection.Emit

Prior to .NET Framework 2.0 if we wanted to execute the IL code generated we needed to deal with a dynamic assembly making use of classes like the AssemblyBuilder, ModuleBuilder, etc. together with the IL code we can also emit symbolic information making possible to debug the dynamic code even within Visual Studio.

The main downside of this way of generating the IL code is (by design) that the generated code can not be garbage collected and therefore the memory is not released until the AppDomain is unload. This created some controversy about if this was a memory leak or not, which in any case is avoidable by loading everything in a separated AppDomain that can be unloaded when it's not used anymore.

With .NET Framework 2.0 we got the LCG (Lightweight Code Generation), which allows generating code at run time, without having to define the dynamic assembly nor type to contain the methods we create. In addition, the IL and the data structures related to the code generation are allocated on the managed, meaning that they can be garbage collected when there are no more references to the DynamicMethod class that is the main class of LCG.

Below you can see some simple code that dynamically emits the IL for a method "Talk" that concatenates two strings.

   1: class Demo
   2: {
   3:     public void RunDynamicCode()
   4:     {
   5:         MethodInfo concatMethodInfo = typeof(string).GetMethod("Concat", 
   6:             new Type[] { typeof(string), typeof(string) });
   7:  
   8:         DynamicMethod dm = new DynamicMethod("Talk", typeof(string), 
   9:             new Type[] { typeof(string) }, this.GetType(), true);
  10:  
  11:         ILGenerator generator = dm.GetILGenerator();
  12:         generator.Emit(OpCodes.Ldstr, "Hello ");
  13:         generator.Emit(OpCodes.Ldarg_0);
  14:         generator.EmitCall(OpCodes.Call, concatMethodInfo, null);
  15:         generator.Emit(OpCodes.Ret);
  16:  
  17:         Func<string,string> talkDelegate =
  18:             (Func<string, string>)dm.CreateDelegate(typeof(Func<string, string>));
  19:  
  20:         string result = talkDelegate("Jose Bonnin");
  21:  
  22:         Console.Write(result);
  23:         Console.ReadKey();
  24:     }
  25: }

Line 8 instantiates the DynamicMethod and specifies the name, the return type, an array with the parameters received and the type owner. The C# signature would be similar to "string Talk(string);"

Lines from 11 to 15 is where we write the IL code making use of the ILGenerator class. Note that in the line 16 we are emitting a call to the MethodInfo for the method String.Concat we obtained in the line 5.

Finally, in line 17 we do the coolest, we obtain a delegate for the method we have just generated that is callable from our C# code.

The main problem we experience with DynamicMethod is that we do not have the ability to generate debugging info for LCG, since the debugging API is based on metadata that the LCG does not have. In any case, not all is lost since we can continue debugging with WinDBG.

If we attach WinDBG to the code above we can effectively check that we have created a dynamic method and see the IL generated. To do it we just need to obtain a pointer to the DynamicMethod which can be obtained in different ways, an easy one for demo purposes is to the do a !DumpHeap -stat to obtain a list of the different objects grouped by type, then we just need to locate in the list the MT address of the type System.Reflection.Emit.DynamicMethod and run the command !DumpHeap -mt [address] over it. Which will show something similar to this:

0:003> !DumpHeap -mt 6fbf026c
Address      MT         Size
01d0e028   6fbf026c    56
total 1 objects
Statistics:
MT         Count   TotalSize    Class Name
6fbf041c        1            56     System.Reflection.Emit.DynamicMethod
Total 1 objects

Now that we have obtained the address (01d0e028) we can run the command DumpIL to see the dynamic IL generated.

0:003> !DumpIL 01d0e028
This is dynamic IL. Exception info is not reported at this time.
If a token is unresolved, run "!do " on the addr given
in parenthesis. You can also look at the token table yourself, by
running "!DumpArray 01d0e62c".

IL_0000: ldstr 70000002 "Hello "
IL_0005: ldarg.0
IL_0006: call a000003 (01d0e560)
IL_000b: ret

In this post we have seen how we do not need to look to "new" technologies like WPF, Silverlight or WCF to find cool things within .NET




Comments

December 29 2009

Virginia Payday Loans

Do you have any more info on this?

Virginia Payday Loans

February 11 2010

Variable Annuities

I like .NET because of its cool addons features. Thank you.

Variable Annuities

Add comment


(Will show your Gravatar icon)

  Country flag

Captcha Image biuquote
  • Comment
  • Preview
Loading