Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Lightweight Code Generation (LCG) dead?

In the .NET 2.0-3.5 frameworks, LCG (aka the DynamicMethod class) was a decent way to emit lightweight methods at runtime when no class structure was needed to support them.

In .NET 4.0, expression trees now support statements and blocks, and as such appear to provide sufficient functionality to build just about any functionality you could require from such a method, and can be constructed in a much easier and safer way than directly emitting CIL op-codes. (This statement is borne from today's experimentation of converting some of our most complex LCG code to use expression tree building and compilation instead.)

So is there any reason why one would use LCG in any new code? Is there anything it can do that expression trees cannot? Or is it now a 'dead' piece of functionality?

like image 633
Greg Beech Avatar asked Jun 08 '10 23:06

Greg Beech


3 Answers

There is no point in constructing CIL directly without any intermediate steps. But it is perfectly fine to use your own intermediate languages that are targeting IL at the end. Expression trees, etc., are not sufficient - it is only one language, whereas while implementing DSLs you'd need many different semantics.

You can emit easily unsafe code (with lots of ldftns and alike), you can emit tail calls (not sure if it is possible with expressions), nonvirtual calls to virtual methods, you can efficiently construct large state automatons with labels and jumps, etc. Expressions trees are so limiting that I simply cannot understand how can they be compared to a raw CIL.

like image 118
SK-logic Avatar answered Oct 04 '22 01:10

SK-logic


Well, this question's pretty old now, and I'm waiting for a tf get to complete... so I'll answer it myself.

Yes, LCG is dead in most cases.

We used to make quite a bit of use of LCG and it has now all been converted to use expression trees instead. They are much easier to build, the code is significantly easier to maintain and debug, and the error messages are generally more informative than 'Operation could destabilize the runtime' when you get things wrong during development.

But, perhaps most importantly, expression trees are composable in a way that Reflection.Emit is not. This means the architecture of the components used for runtime code generation can be more modular and even allow plugins to extend the code generation framework.

The one thing I've found that is supported by Reflection.Emit that isn't directly supported in expression trees is setting .initonly fields. This, however, can be achieved by using a little helper class and invoking it in the expression tree, for example the one I used is below:

internal static class FieldHelper
{
    public static TTarget AssignInitOnlyField<TTarget, TField>(
        TTarget target, string fieldName, TField value)
    {
        var field = target.GetType().GetField(
            fieldName, 
            BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
        var boxed = (object)target; // required for value type support
        field.SetValue(boxed, value);
        return (TTarget)boxed;
    }
}

It's worth mentioning the one down-side of using expression trees rather than LCG is that the construction and compilation of the expression trees is definitely slower than emitting the raw op-codes directly. Assuming you're caching the compiled methods this is unlikely to be a significant problem, but it's the one reason that could still compel you to use LCG.

like image 43
Greg Beech Avatar answered Oct 04 '22 01:10

Greg Beech


Expression trees are certainly a way to go for the most of the run-time generated code. However you should clearly realize that it is limited and does not provide you with an access to the whole power of MSIL language. So LGC and ILGenerator are certainly to stay for the more demanding tasks.

like image 40
Alex Petrov Avatar answered Oct 04 '22 01:10

Alex Petrov