Reputation: 11
I am trying to lower down reflection method call time by creating a DynamicMethod, emitting IL code with its IL generator, and then creating a delegate using its CreateDelegate method. So far the call times are reduced significantly even though the new method call still uses (object callObject, object[] params) as parameters. The problem occurs in the generated IL code when the return type is anything other than void. I have no knowledge of MSIL and did quite a bit of research but found nothing. Here is the code that works:
private void Start()
{
var a = new A();
var method = typeof(A).GetMethod("Add");
Type[] paramsTypes = { typeof(object[]) };
Type[] allTypes = { typeof(object), typeof(object[]) };
Type returnType = typeof(void);
var dm = new DynamicMethod("Hi", returnType, allTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, method, paramsTypes);
il.Emit(OpCodes.Ret);
var del4 = (Action<object, object[]>)dm.CreateDelegate(
typeof(Action<object, object[]>));
var time = DateTime.Now;
for (int i = 0; i < 20000000; i++)
{
//a.Add(); 132 ms
//method.Invoke(a, null);// 25 sec
del4(a, null); // 200 ms
}
var ts = DateTime.Now - time;
Debug.Log($"{ts.Seconds}:{ts.Milliseconds}");
}
public class A
{
public int a = 0;
public void Add() => a++;
}
The resulting time (only the call time is measured) is so much faster compared to normal MethodInfo.Invoke. However, with the following tweaks, the IL generator throws error:
private void Start()
{
var a = new A();
var method = typeof(A).GetMethod("Add");
Type[] paramsTypes = { typeof(object[]) };
Type[] allTypes = { typeof(object), typeof(object[]) };
Type returnType = typeof(object);
var dm = new DynamicMethod("Hi", returnType, allTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, method, paramsTypes);
il.Emit(OpCodes.Ret);
var del4 = (Func<object, object[], object>)dm.CreateDelegate(
typeof(Func<object, object[], object>));
var time = DateTime.Now;
for (int i = 0; i < 20000000; i++)
{
//a.Add(); 132 ms
//method.Invoke(a, null);// 25 sec
del4(a, null); // 200 ms
}
var ts = DateTime.Now - time;
Debug.Log($"{ts.Seconds}:{ts.Milliseconds}");
}
public class A
{
public int a = 0;
public int Add() => a++;
}
When the return type expected is something other than void, the following exception is thrown:
InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:Hi (object,object[]): IL_0006: ret
Does anyone know how to solve this issue?
Edit: Added boxing before return opcode:
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, method, paramsTypes);
il.Emit(OpCodes.Box);
il.Emit(OpCodes.Ret);
Then the following is thrown:
VerificationException: Error in System.Object:(wrapper dynamic-method) object:Hi (object,object[]) Invalid instruction 8c
Upvotes: 1
Views: 649