IL Generated by the “dynamic” keyword

The "dynamic" keyword

The dynamic keyword is a fantastic addition to C#. It is faster than (standard) reflection and also simpler to use if you are willing to give up type safety. However what IL is generated when you drop "dynamic" into your code.

An Example

Well let's start with an empty assembly. That's 3,584 bytes. To that we add this code.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public static class NamePrinter
{
    public static void PrintName(Person person)
    {
        Trace.WriteLine(person.FirstName + " " + person.LastName);
    }
}

And we end up with 4,096 bytes in our assembly. So that's 512 bytes we added. Let's say for some reason we need to use "dynamic" and we end up with this code

public static class NamePrinter
{
    public static void PrintName(dynamic person)
    {
        Trace.WriteLine(person.FirstName + " " + person.LastName);
    }
}

The resultant assembly is 5,632 bytes. We just added 1536 more bytes. So what happened? That is effectively a 300% increase in the size of the real code in our assembly. Well it turns out the answer is in the IL

The resultant IL

The IL for the strong typed approach is

.method public hidebysig static void PrintName(class Person person) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: callvirt instance string Person::get_FirstName()
    L_0006: ldstr " "
    L_000b: ldarg.0 
    L_000c: callvirt instance string Person::get_LastName()
    L_0011: call string [mscorlib]System.String::Concat(string, string, string)
    L_0016: call void [System]System.Diagnostics.Trace::WriteLine(string)
    L_001b: ret 
}

While the IL for the dynamic version is

.method public hidebysig static void PrintName(object person) cil managed
{
    .param [1]
    .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor()
    .maxstack 14
    .locals init (
        [0] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000,
        [1] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0001,
        [2] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0002,
        [3] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0003,
        [4] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0004)
    L_0000: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> NamePrinter/o__SiteContainer0::<>p__Site1
    L_0005: brtrue.s L_0048
    L_0007: ldc.i4 0x100
    L_000c: ldstr "WriteLine"
    L_0011: ldnull 
    L_0012: ldtoken NamePrinter
    L_0017: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_001c: ldc.i4.2 
    L_001d: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0022: stloc.0 
    L_0023: ldloc.0 
    L_0024: ldc.i4.0 
    L_0025: ldc.i4.s 0x21
    L_0027: ldnull 
    L_0028: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_002d: stelem.ref 
    L_002e: ldloc.0 
    L_002f: ldc.i4.1 
    L_0030: ldc.i4.0 
    L_0031: ldnull 
    L_0032: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0037: stelem.ref 
    L_0038: ldloc.0 
    L_0039: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1)
    L_003e: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!--0--> [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0043: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site1
    L_0048: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site1
    L_004d: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Target
    L_0052: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site1
    L_0057: ldtoken [System]System.Diagnostics.Trace
    L_005c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0061: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site2
    L_0066: brtrue.s L_009f
    L_0068: ldc.i4.0 
    L_0069: ldc.i4.0 
    L_006a: ldtoken NamePrinter
    L_006f: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0074: ldc.i4.2 
    L_0075: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_007a: stloc.1 
    L_007b: ldloc.1 
    L_007c: ldc.i4.0 
    L_007d: ldc.i4.0 
    L_007e: ldnull 
    L_007f: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0084: stelem.ref 
    L_0085: ldloc.1 
    L_0086: ldc.i4.1 
    L_0087: ldc.i4.0 
    L_0088: ldnull 
    L_0089: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_008e: stelem.ref 
    L_008f: ldloc.1 
    L_0090: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::BinaryOperation(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, valuetype [System.Core]System.Linq.Expressions.ExpressionType, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1)
    L_0095: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!--0--> [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_009a: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site2
    L_009f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site2
    L_00a4: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Target
    L_00a9: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site2
    L_00ae: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site3
    L_00b3: brtrue.s L_00ec
    L_00b5: ldc.i4.0 
    L_00b6: ldc.i4.0 
    L_00b7: ldtoken NamePrinter
    L_00bc: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_00c1: ldc.i4.2 
    L_00c2: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_00c7: stloc.2 
    L_00c8: ldloc.2 
    L_00c9: ldc.i4.0 
    L_00ca: ldc.i4.0 
    L_00cb: ldnull 
    L_00cc: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_00d1: stelem.ref 
    L_00d2: ldloc.2 
    L_00d3: ldc.i4.1 
    L_00d4: ldc.i4.3 
    L_00d5: ldnull 
    L_00d6: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_00db: stelem.ref 
    L_00dc: ldloc.2 
    L_00dd: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::BinaryOperation(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, valuetype [System.Core]System.Linq.Expressions.ExpressionType, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1)
    L_00e2: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!--0--> [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_00e7: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site3
    L_00ec: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site3
    L_00f1: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Target
    L_00f6: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site3
    L_00fb: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site4
    L_0100: brtrue.s L_0133
    L_0102: ldc.i4.0 
    L_0103: ldstr "FirstName"
    L_0108: ldtoken NamePrinter
    L_010d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0112: ldc.i4.1 
    L_0113: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0118: stloc.3 
    L_0119: ldloc.3 
    L_011a: ldc.i4.0 
    L_011b: ldc.i4.0 
    L_011c: ldnull 
    L_011d: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0122: stelem.ref 
    L_0123: ldloc.3 
    L_0124: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1)
    L_0129: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!--0--> [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_012e: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site4
    L_0133: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site4
    L_0138: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Target
    L_013d: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site4
    L_0142: ldarg.0 
    L_0143: callvirt instance !2 [mscorlib]System.Func`3::Invoke(!0, !1)
    L_0148: ldstr " "
    L_014d: callvirt instance !3 [mscorlib]System.Func`4::Invoke(!0, !1, !2)
    L_0152: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site5
    L_0157: brtrue.s L_018d
    L_0159: ldc.i4.0 
    L_015a: ldstr "LastName"
    L_015f: ldtoken NamePrinter
    L_0164: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0169: ldc.i4.1 
    L_016a: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_016f: stloc.s CS$0$0004
    L_0171: ldloc.s CS$0$0004
    L_0173: ldc.i4.0 
    L_0174: ldc.i4.0 
    L_0175: ldnull 
    L_0176: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_017b: stelem.ref 
    L_017c: ldloc.s CS$0$0004
    L_017e: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1)
    L_0183: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!--0--> [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0188: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site5
    L_018d: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site5
    L_0192: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1&gt;::Target
    L_0197: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1&gt; NamePrinter/o__SiteContainer0::&lt;&gt;p__Site5
    L_019c: ldarg.0 
    L_019d: callvirt instance !2 [mscorlib]System.Func`3::Invoke(!0, !1)
    L_01a2: callvirt instance !3 [mscorlib]System.Func`4::Invoke(!0, !1, !2)
    L_01a7: callvirt instance void [mscorlib]System.Action`3::Invoke(!0, !1, !2)
    L_01ac: ret 
}

In Summary

Ok, I am not even going to try and work out what is going on there. So what is the takeaway from this? Well I think it is "All features have a cost". One of the costs of "dynamic" seems to be the bloat that occurs in the resultant assembly.

Posted by: Simon Cropp
Last revised: 20 Dec, 2011 07:39 PM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.