Reflection and LCG

Anyone who has played with .NET long enough will tell you that
Reflection is a really cool feature.  Essentially, reflection
enables the developer to query the type system (CLT – Common Language
Type system), dynamically invoke methods, and dynamically create types
at runtime, using meta-data stored in the .NET assemblies. The reflection
API is built into the framework.  The only snag with using
reflection is paying the performance cost.

This post is not about dodging the performance pitfalls with
performance – Joel Pobar, a program manager on the CLR (Common Language
Runtime) team at Microsoft, has written a great article,
which is
extensive and covers the topic of reflection performance.  
Instead, I would like to take this opportunity to mention Lightweight
Code Generation (LCG) in version 2.0 of the .NET Framework.

What is LCG?

LCG is all about generating code on the fly at runtime, which can be
executed.  A good use for LCG is avoiding the performance bloat
associated with method invocation in reflection.  How many times
have you seen the following code?

Type t = typeof(Console);
t.InvokeMember(“WriteLine”, BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, new object[] { “Hello World” });

The above example code gets a Type object (t) for the Console class,
and then invokes the WriteLine method, using the InvokeMember
method.  Of course, this example is not a good representation of a
real world scenario, because it is unlikely that a developer would call
the static WriteLine method of the console class in this way. 
However, imagine that the type (t) was obtained dynamically via
reflection, perhaps as a result of querying custom attributes of a
property or class (GetCustomAttributes).  The developer may intend
a method call on the type (t) during runtime without knowing the class
type at compile time.  Regardless of how a Type object (t) is
obtained, calling InvokeMember is bad for performance (see Joel’s
article for reasons why).

A better approach to the above example would be to obtain a MethodInfo
instance for the dynamically called WriteLine method and then call the
MethodInfo.Invoke method.  This approach is faster than using
Type.InvokeMember, but still not that fast.

Type t = typeof(Console);
MethodInfo method = typeof(Console).GetMethod(
“WriteLine”, BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static, null,
new Type[] { typeof(string) }, null);
method.Invoke(null, new object[] { “Hello World” });

Version 2.0 of the Framework introduces LCGs, which is a half way
compromise between early bound invocation (invocation determined at
compile time) and late bound invocation (invocation determined at
runtime).  LCGs are about creating IL (Intermediate Language)
code, similar to what the compiler would generate as early bound
invocation, at runtime, and then calling the generated IL code from
your application infrastructure.  Joel touches on LCGs in his
article, and explains them further on his blog, the MSDN is also a good
resource for knowledge on this subject.

Below is a helper class (written with the help of examples from Joel on
CodeProject), which contains two public methods.  The Create
method is a replacement for MethodInfo.Invoke, which dynamically
invokes a method on a class (static) or object (non-static) using an
LCG.  The second method – CreateInstance – will create an instance
object from a Type class by using emitted IL in an LCG.  Both of
these helper methods are faster performing than the aforementioned
Type.InvokeMember and MemberInfo.Invoke API methods (perhaps I’ll post
evidence of this later).

///
/// Factory class to invoke a method on a type using Dynamic Methods in C# 2.0
///
public class DynamicMethodFactory
{
///
/// Factory returns a delegate instance for the invoked method.
///
/// Target object (null if invoking the constructor).
/// Arguments.
/// Return type of some sort.
public delegate object DynamicMethodDelegate(object target, object[] args);

///
/// Create a delegate for a dynamically invoked method that will create an instance of a type.
///
/// Constructor info for the type to create.
/// Delegate for the dynamic method.
public static DynamicMethodDelegate CreateInstance(ConstructorInfo ctor)
{
// Get the parameter details.
ParameterInfo[] parameters = ctor.GetParameters();
// Create the dynamic method, parameter is just an array of objects.
Type[] parameterTypes = { typeof(object), typeof(object[]) };
DynamicMethod dMethod = new DynamicMethod(String.Empty, typeof(object), parameterTypes, typeof(DynamicMethodFactory), false);
// Create the IL for the method (the meat in the sandwich) we just created.
ILGenerator il = dMethod.GetILGenerator();
// Check the parameters.
CompareArgsIL(il, parameters);
// Emit IL for the parameters before creating a new instance.
EmitArgsIL(il, parameters);
il.Emit(OpCodes.Newobj, ctor);
// Return object.
il.Emit(OpCodes.Ret);
// Return the delegate.
return (DynamicMethodDelegate)dMethod.CreateDelegate(typeof(DynamicMethodDelegate));
}

///
/// Create a delegate for a dynamically invoked method.
///
/// Method info.
/// Delegate.
public static DynamicMethodDelegate Create(MethodInfo method)
{
// Get the parameter details.
ParameterInfo[] parameters = method.GetParameters();
// Create the dynamic method.
Type[] parameterTypes = { typeof(object), typeof(object[]) };
DynamicMethod dMethod = new DynamicMethod(String.Empty, typeof(object), parameterTypes, typeof(DynamicMethodFactory), false);
// Create the IL for the method (the meat in the sandwich) we just created.
ILGenerator il = dMethod.GetILGenerator();
// Check the parameters.
CompareArgsIL(il, parameters);
// Push the target object on the stack if not static.
if (!method.IsStatic)
{
// Argument of our dynamic method is the target instance.
il.Emit(OpCodes.Ldarg_0);
}
// Emit IL for the parameters before our method call.
EmitArgsIL(il, parameters);
// Call the method, process return value and return from call site.
// If method is not final then we need to call it as a virtual method call.
if (method.IsFinal)
{
il.Emit(OpCodes.Call, method);
}
else
{
il.Emit(OpCodes.Callvirt, method);
}
// Check for return type.
// if return type is non-void reference type then use the last parameter on the eval stack from
// the last call statement.
if (typeof(void) != method.ReturnType)
{
// Box returned value types.
if (method.ReturnType.IsValueType)
{
il.Emit(OpCodes.Box, method.ReturnType);
}
}
else
{
il.Emit(OpCodes.Ldnull);
}
// Return object.
il.Emit(OpCodes.Ret);

// Return the delegate.
return (DynamicMethodDelegate)dMethod.CreateDelegate(typeof(DynamicMethodDelegate));
}

///
/// Emit IL code to check parameters.
///
/// IL generator.
/// Parameters defined for a dynamic method.
private static void CompareArgsIL(ILGenerator il, ParameterInfo[] parameters)
{
// Check the number of arguments in the array with this accepted by the method being invoked.
// Define a label for successful arg count checking.
Label argsGood = il.DefineLabel();
// Check input arg count.
il.Emit(OpCodes.Ldarg_1); // Loads argument at index 1 onto evaluation stack.
il.Emit(OpCodes.Ldlen); // Pushes number of elements of a zero based, one-dimentional array on the stack.
il.Emit(OpCodes.Ldc_I4, parameters.Length); // Push Int32 on evaluation stack.
il.Emit(OpCodes.Beq, argsGood); // Transfer to target if both arguments are equal.
// Argument is wrong, thrown an exception.
il.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Throw);
// Mark label into IL, which is the skip point if args are good.
il.MarkLabel(argsGood);
}

///
/// Emit parameter IL for a method call.
///
/// IL generator.
/// Parameters defined for a dynamic method.
private static void EmitArgsIL(ILGenerator il, ParameterInfo[] parameters)
{
// Add args. Since all args are objects, value types are unboxed. Refs to value types are to be
// converted to values themselves.
for (int i = 0; i < parameters.Length; i++)
{
// Push args array reference on the stack , followed by the index.
// Ldelem will resolve them to args[i].
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
// If param is a value type then we need to unbox it.
Type paramType = parameters[i].ParameterType;
if (paramType.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, paramType);
}
}
}
}

The above helper methods can be called using the example code below:

// Late bound instance creation using LCG.
Type t = typeof(ArrayList);
ConstructorInfo cInfo = t.GetConstructor(Type.EmptyTypes);
DynamicMethodFactory.DynamicMethodDelegate del = DynamicMethodFactory.CreateInstance(cInfo);
object listRef = del.Invoke(null, new object[] { }) as ArrayList;

// Late bound invocation using LCG.
MethodInfo mInfo = t.GetMethod(
“Add”, BindingFlags.Instance |BindingFlags.ExactBinding | BindingFlags.Public, null, new Type[] { typeof(object) }, null);
del = DynamicMethodFactory.Create(mInfo);
del.Invoke(listRef, new object[] { “a string” });
mInfo = t.GetMethod(“Count”, Type.EmptyTypes);

7 thoughts on “Reflection and LCG

  1. Bruno Baia

    Hi Rob,
    <br>
    <br>I got some MethodAccessException with the current DynamicMethodFactory.Create method, so i changed the owner of the dynamic method from &quot;typeof(DynamicMethodFactory)&quot; to &quot;method.DeclaringType&quot; (line 50).
    <br>Maybe same thing for DynamicMethodFactory.CreateInstance method ?
    <br>
    <br>
    <br>Nice code btw.
    <br>
    <br>Cheers,
    <br>Bruno

  2. dave dolan

    Wow. See I had done this ‘by hand’ for a bunch of different scenarios and I was looking around to see if anyone had generalized it. Lo and behold I tried a search for DynamicMethodFactory, and here you are! Very nice!

Comments are closed.