public static unsafe InvokeFunc CreateInvokeDelegate(MethodBase method)
{
Debug.Assert(!method.ContainsGenericParameters);
bool emitNew = method is RuntimeConstructorInfo;
bool hasThis = !(emitNew || method.IsStatic);
// The first parameter is unused but supports treating the DynamicMethod as an instance method which is slightly faster than a static.
Type[] delegateParameters = new Type[3] {
typeof(object), typeof(object), typeof(IntPtr *)
};
string declaringTypeName = method.DeclaringType != null ? method.DeclaringType.Name + "." : string.Empty;
var dm = new DynamicMethod(
InvokeStubPrefix + declaringTypeName + method.Name,
returnType: typeof(object),
delegateParameters,
restrictedSkipVisibility: true);
ILGenerator il = dm.GetILGenerator();
// Handle instance methods.
if (hasThis)
{
il.Emit(OpCodes.Ldarg_1);
if (method.DeclaringType !.IsValueType)
{
il.Emit(OpCodes.Unbox, method.DeclaringType);
}
}
// Push the arguments.
ParameterInfo[] parameters = method.GetParametersNoCopy();
for (int i = 0; i < parameters.Length; i++)
{
il.Emit(OpCodes.Ldarg_2);
if (i != 0)
{
il.Emit(OpCodes.Ldc_I4, i * IntPtr.Size);
il.Emit(OpCodes.Add);
}
il.Emit(OpCodes.Call, Methods.ByReferenceOfByte_Value()); // This can be replaced by ldfld once byref fields are available in C#
RuntimeType parameterType = (RuntimeType)parameters[i].ParameterType;
if (!parameterType.IsByRef)
{
il.Emit(OpCodes.Ldobj, parameterType.IsPointer ? typeof(IntPtr) : parameterType);
}
}
// Invoke the method.
if (emitNew)
{
il.Emit(OpCodes.Newobj, (ConstructorInfo)method);
}
else if (method.IsStatic || method.DeclaringType !.IsValueType)
{
il.Emit(OpCodes.Call, (MethodInfo)method);
}