DynamicMethods, expression trees and DLR

I have some questions about the interactions and relationships between DynamicMethods, expression trees, and DLR.

  • I know that LambdaExpression.Compile uses ILGenerator to create a delegate. However, there are some fundamental differences between the compiled LambdaExpression and DynamicMethod. For instance,

    a. DynamicMethods call faster

    b. Compiled LambdaExpressions can embed closures (ConstantExpressions, which are not primitive values)

    b. Compiled LambdaExpression expressions do not have DeclaringType.

    Questions:

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

    b. What is special about compiled LambdaExpressions that allow closing? Does the expression tree really generate a closure class when I use a non-constant expression? And if so, where does this generated class come from?

    with. Where do the compiled LambdaExpressions go (at runtime)? Where their support is supported. It may not be just Reflection.Emit, right?

  • I know that the dynamic keyword is just a compiler trick for emitting CallSites, CSharp bindings, etc. Internally, as I understand it, they generate expression trees, and also use an abridged version of the C # compiler.

  • / p>

    Questions

    a. Are expression trees a function of CallSiteBinders as a whole or of a specific implementation and use of them in Microsoft.CSharp dll?

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

    with. Where and why does the stripped down version of the C # compiler come into play? Why and how is this different from regular LambdaExpression.Compile or DynamicMethods calls or any kind of IL generation? I can understand how CallSiteBinders can be used to create expression trees, but why do I need a C # compiler after this conversion? And the fact that C # is associated with it in general when it occurs in the form of an expression tree (this is just an API).

+4
source share
2 answers

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

Why are DynamicMethods faster to call than compiled LambdaExpressions?

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

What is special about compiled LambdaExpressions that allow closing? Does the expression tree really generate a closure class when I use a non-constant expression? And if so, where does this generated class come from?

This is easy to verify. Just look at the Target and Method delegate generated by compiling the expression tree. You will notice that Target (and the first Method parameter) is System.Runtime.CompilerServices.Closure . A class containing the object[] Constants field, where non-primitive values ​​from ConstantExpression are stored.

Where do the compiled LambdaExpressions go (at runtime)? Where their support is supported. It may not be just Reflection.Emit, right?

As I said, Expression.Compile() internally uses DynamicMethod . So yes, this is just Reflection.Emit.

+3
source

Well, I can’t answer all your questions, but I can answer some of them, and I think that can answer most of your questions. Perhaps, at a minimum, this will give you enough information to continue your research.

Why are DynamicMethods faster to call than compiled LambdaExpressions?

I don’t think they are, maybe you were wrong, and that’s the difference JIT'ing

What is special about compiled LambdaExpressions that allow closing? Does the expression tree really generate a closure class when I use a non-constant expression? And if so, where does this generated class come from?

I'm not sure about that. I would suggest that Expression.Constant can contain reference types, then this is not a problem, but if it really can only have value types, then I would assume that the compiler will simply generate an expression in which variables captured in the closure are simply passed to as parameters.

Where do the compiled LambdaExpressions go (at runtime)? Where their support is supported. It may not be just Reflection.Emit, right?

System.Linq.Expressions is actually just a friendly API on top of Reflection.Emit, ergo, they are just stored in memory, like Reflection.Emit by default (although with Reflection.Emit you can save the emitted code, I think)

Are expression trees a function of CallSiteBinders in general or of a specific implementation and use of them in Microsoft.CSharp dll?

I did a little System.Dynamic work, so I can not answer this, but I understand that CallSiteBinder simply caches and calls the expression, but passes the actual generation to another (i.e. DynamicObject). But then again, you probably know more here than me.

Are these expression trees made up of DynamicExpression nodes? Or something different? If something else, why?

No, the dynamics are still bound by the same rules as everything else in .net. Dynamic simply says: "At runtime, when I do x, and try to build the code that I would normally write and execute it for me." Things like DynamicObject are going to build a simple tree of old expressions, a dynamic object just provides you some metadata so you can actually build this tree (e.g. return type, access type, name, etc.).

Where and why does the stripped down version of the C # compiler come into play? Why and how is this different from regular LambdaExpression.Compile or DynamicMethods calls or any kind of IL generation? I can understand how CallSiteBinders can be used to create expression trees, but why do I need a C # compiler after this conversion? And the fact that C # is associated with it in general, as soon as it is in the form of an expression tree (this is just an API).

I'm not sure what you mean by the remote compiler or what the runtime actually does to generate the IL code (which I think is what you are here for), so I don't think I can answer this question .

I will say, however, as I said: the System.Linq.Expression stuff is really just a friendly API on top of Reflection.Emit. An expression tree is just the information it needs to go to reflection.emit, generate a dynamic method and return it back to you.

+2
source

Source: https://habr.com/ru/post/1492864/


All Articles