Sellec
Sellec

Reputation: 64

emit code works bad

I'm trying to create a call to a proxy method in generated class with opcodes and I get ExecutionEngineException. This method must receive return type as first argument and array of arguments from calling method.

var methodILGen = methodBuilder.GetILGenerator();
if (methodInfo.ReturnType != typeof(void))
{
 var method = typeBuilder.BaseType.GetMethod("proxyCaller");
 var args = methodInfo.GetParameters();
 var lb = methodILGen.DeclareLocal(methodInfo.ReturnType);  

 LocalBuilder _args = methodILGen.DeclareLocal(typeof(object[]));

 methodILGen.Emit(OpCodes.Ldc_I4_S, args.Length);
 methodILGen.Emit(OpCodes.Newarr, typeof(object));
 methodILGen.Emit(OpCodes.Stloc, _args);

 methodILGen.Emit(OpCodes.Ldloc, _args);
 for (int i = 0; i < args.Length; i++)
 {
  methodILGen.Emit(OpCodes.Ldc_I4_S, i);      
  methodILGen.Emit(OpCodes.Ldarg_S, i + 1);
  methodILGen.Emit(OpCodes.Stelem_Ref);
  methodILGen.Emit(OpCodes.Ldloc, _args);
 }
 methodILGen.Emit(OpCodes.Stloc, _args);

 methodILGen.Emit(OpCodes.Ldarg_0); // instance pointer
 methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType); //return type
 methodILGen.Emit(OpCodes.Ldloc, _args); //args list

 methodILGen.Emit(OpCodes.Call, method);//, new Type[0]);

 if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum) methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
}
methodILGen.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);

And the second problem is that i receive firstly an array of args and then return type.

Upvotes: 1

Views: 459

Answers (1)

Jury Soldatenkov
Jury Soldatenkov

Reputation: 417

  1. Save your dynamic assembly, and use PEVerify.exe to check it.
  2. OpCodes.ldtoken does not put Type on stack. It puts RuntimeTypeHandle. To get type you should do something like that:

    var getTypeMethod = typeof (Type).GetMethod("GetTypeFromHandle");  
    methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);  
    methodILGen.Emit(OpCodes.Call, getTypeMethod);  
    methodILGen.Emit(OpCodes.Ldloc, _args);
    

Upvotes: 4

Related Questions