As some of you (probably very few) know, the C# port of StringTemplate
builds and caches dynamic accessors for fields and methods to improve
performance. Today I made an update that I should have made in the past.
Instead of manually building the IL for the accessors, I use the LINQ
expression trees to handle the work behind the scenes. Behind the scenes
work includes selecting the proper opcode for the call (direct vs.
indirect dispatch), optimizations for static methods, and only boxing
results when necessary. The front-end work (actually relevant to the
task at hand) is now a clean expression of the desired behavior.

 

Later I'll be updating the experimental ST compiler (only available via
the depot source for the C# port, and disabled by default) to use
expression trees instead of building IL and re-benchmarking it.

 

The result looks like this:

 

Before:

 

private static Func<object, object> BuildAccessor( MethodInfo method )

{

    System.Reflection.Emit.DynamicMethod dm = new
System.Reflection.Emit.DynamicMethod(method.DeclaringType.Name +
method.Name + "MethodAccessor", typeof(object), new Type[] {
typeof(object) }, method.DeclaringType);

    var gen = dm.GetILGenerator();

 

    if (!method.IsStatic)

    {

        gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);

        gen.Emit(System.Reflection.Emit.OpCodes.Castclass,
method.DeclaringType);

    }

 

    if (method.IsVirtual && !method.IsFinal)

        gen.EmitCall(System.Reflection.Emit.OpCodes.Callvirt, method,
null);

    else

        gen.EmitCall(System.Reflection.Emit.OpCodes.Call, method, null);

 

    if (method.ReturnType.IsValueType)

        gen.Emit(System.Reflection.Emit.OpCodes.Box, method.ReturnType);

 

    gen.Emit(System.Reflection.Emit.OpCodes.Ret);

    return (Func<object, object>)dm.CreateDelegate(typeof(Func<object,
object>));

}

 

private static Func<object, object> BuildAccessor( FieldInfo field )

{

    System.Reflection.Emit.DynamicMethod dm = new
System.Reflection.Emit.DynamicMethod(field.DeclaringType.Name +
field.Name + "FieldAccessor", typeof(object), new Type[] {
typeof(object) }, field.DeclaringType);

 

    var gen = dm.GetILGenerator();

    if (field.IsStatic)

    {

        gen.Emit(System.Reflection.Emit.OpCodes.Ldsfld, field);

    }

    else

    {

        gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);

        gen.Emit(System.Reflection.Emit.OpCodes.Castclass,
field.DeclaringType);

        gen.Emit(System.Reflection.Emit.OpCodes.Ldfld, field);

    }

 

    if (field.FieldType.IsValueType)

        gen.Emit(System.Reflection.Emit.OpCodes.Box, field.FieldType);

 

    gen.Emit(System.Reflection.Emit.OpCodes.Ret);

    return (Func<object, object>)dm.CreateDelegate(typeof(Func<object,
object>));

}

 

After:

 

private static Func<object, object> BuildAccessor(MethodInfo method)

{

    ParameterExpression obj = Expression.Parameter(typeof(object),
"obj");

    Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(

        Expression.Convert(

            Expression.Call(

                Expression.Convert(obj, method.DeclaringType),

                method),

            typeof(object)),

        obj);

 

    return expr.Compile();

}

 

private static Func<object, object> BuildAccessor(FieldInfo field)

{

    ParameterExpression obj = Expression.Parameter(typeof(object),
"obj");

    Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(

        Expression.Convert(

            Expression.Field(

                Expression.Convert(obj, field.DeclaringType),

                field),

            typeof(object)),

        obj);

 

    return expr.Compile();

}

 

_______________________________________________
antlr-dev mailing list
[email protected]
http://www.antlr.org/mailman/listinfo/antlr-dev

Reply via email to