Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DynamicMethods, Expression Trees and the DLR

I have some questions about the interactions and relationships between DynamicMethods, Expression Trees and the DLR.

  1. I know that LambdaExpression.Compile uses an ILGenerator internally to create a Delegate. However, there are some fundamental differences between a compiled LambdaExpression and a DynamicMethod. For instance

    a. DynamicMethods invoke faster

    b. Compiled LambdaExpressions can embed closures (ConstantExpressions that are non primitive values)

    b. Compiled LambdaExpressions have no DeclaringType.

    Questions:

    a. Why are DynamicMethods faster to invoke than compiled LambdaExpressions?

    b. What's special about compiled LambdaExpressions that allows for closures? Does the Expression Tree actually generate a closure class when I use a non ConstantExpression? And if so, where does this generated class go?

    c. Where do compiled LambdaExpressions go (at runtime)? Where is the support for them implemented. It can't just be Reflection.Emit, can it?

  2. I know that the dynamic keyword is really just a compiler trick for emitting CSharp CallSites, Binders, etc. Internally, as I understand, these generate Expression Trees and also use a stripped down version of the C# compiler.

    Questions

    a. Are the expression trees being generated a function of CallSiteBinders in general or the specific implementation and usage of them in the Microsoft.CSharp dll?

    b. Are these expression trees composed of DynamicExpression nodes? Or something else? If something else, why?

    c. Where and why does the stripped down version of the C# compiler come into play? Why and how is it different than regular calls to LambdaExpression.Compile or DynamicMethods or any kind of IL generation? I can understand how CallSiteBinders could be used to build Expression Trees, but why is the C# compiler needed after that transformation occurs? And what does C# have to do with it at all once it's in the form of an Expression Tree (which is just an API).

like image 805
Jeff Avatar asked Jul 23 '13 04:07

Jeff


1 Answers

I don't know much about dynamic, so I'm going to answer only the first part of your question.

Why are DynamicMethods faster to invoke than compiled LambdaExpressions?

I would be very surprised if they were, since Expression.Compile() internally uses DynamicMethod.

What's special about compiled LambdaExpressions that allows for closures? Does the Expression Tree actually generate a closure class when I use a non ConstantExpression? And if so, where does this generated class go?

That's easy to verify. Just look at Target and Method of a delegate generated from compiling an expression tree. You will notice that the Target (and first parameter of Method) is System.Runtime.CompilerServices.Closure. That's a class that contains a field object[] Constants, which is where non-primitive values from ConstantExpressions are stored.

Where do compiled LambdaExpressions go (at runtime)? Where is the support for them implemented. It can't just be Reflection.Emit, can it?

Like I said before, Expression.Compile() internally uses DynamicMethod. So, yeah, it is just Reflection.Emit.

like image 104
svick Avatar answered Sep 23 '22 23:09

svick