ILCode compiling with error - C#

0

/Please skip to Update,

Using Net Framework 3.5 (Mono) with C# 7.0

I'm trying to create Dynamic method what take its parameters, box them to object array and call it on simple method.

Then in runtime I replace method via unsafe context. (Doing it for better API)

I created code how I imagine it and I posted that code in LINQPad 5.

void TestCall(string a, int b) {
    NetworkInvoke(a, b);
}

void NetworkInvoke(params object[] parameters) {

}

In LINQPad I've got IL Code:

g__TestCall0_0:
IL_0000:  nop         
IL_0001:  ldc.i4.2    
IL_0002:  newarr      System.Object
IL_0007:  dup         
IL_0008:  ldc.i4.0    
IL_0009:  ldarg.0     
IL_000A:  stelem.ref  
IL_000B:  dup         
IL_000C:  ldc.i4.1    
IL_000D:  ldarg.1     
IL_000E:  box         System.Int32
IL_0013:  stelem.ref  
IL_0014:  call        g__NetworkInvoke0_1
IL_0019:  nop         
IL_001A:  ret   

Now lets recreate this in ILGenerator. (I have already code for supporting all paramaters but it don't works too. Then I created this simple static code what don't work too)

private MethodInfo CreateMethodFrom(MethodInfo method) {
    var name = method.Name;
    var attributes = method.Attributes;
    var callConv = method.CallingConvention;
    var returnType = method.ReturnType;
    var parameters = new Type[method.GetParameters().Length];
    for (int i = 0; i < parameters.Length; i++)
        parameters[i] = method.GetParameters()[i].ParameterType;

    Debug.Log("Creating dynamic method!");

    var dynMethod = new DynamicMethod(name, attributes, callConv, returnType, parameters, GetType().BaseType, false);
    for (int i = 0; i < parameters.Length; i++) {
        dynMethod.DefineParameter(i, method.GetParameters()[i].Attributes, method.GetParameters()[i].Name);
    }

    var networkInvoker = GetType().BaseType.GetMethod("NetworkInvoke", BindingFlags.Instance | BindingFlags.NonPublic);

    Debug.Log("Creating ILGenerator!");

    ILGenerator il = dynMethod.GetILGenerator();

    //ILCode(il, parameters, networkInvoker);

    il.Emit(OpCodes.Nop);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldc_I4_2);
    il.Emit(OpCodes.Newarr, typeof(System.Object));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stelem_Ref);
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Ldarg_2);
    il.Emit(OpCodes.Box, typeof(System.Int32));
    il.Emit(OpCodes.Stelem_Ref);
    il.Emit(OpCodes.Call, networkInvoker);
    il.Emit(OpCodes.Nop);
    il.Emit(OpCodes.Ret);

    return dynMethod;
}

Lets invoke our dynamic method:

forEach { //Iterating over methods
    MethodInfo ourCorrectMethodToBeReplaced = it; //This method is for a debug, its signature is: (string testString, int testInt)
    var replacedMethod = CreateMethodFrom(ourCorrectMethodToBeReplaced);

    string test = "test1";
    int test2 = 69;

    replacedMethod.Invoke(methodInstance, new object[] {test, test2});
} 

When I call it, I receive InvalidProgramException

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) SioFramework.Script:TestCall (string,int): IL_000b: stelem.ref

I tried to remove reference - (Stelem_Ref) Then I've got

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) SioFramework.Script:TestCall (string,int): IL_000d: ldarg.2

Any ideas What I'm doing wrong? Thanks for any tip.

Update, well, it looks like I posted wrong code here. (I tried to solve this problem almost full day of yesterday)

When I rewrited the ILCode to the correct (sorry, my mistake)

il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Box, typeof(System.Int32));
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Call, networkInvoker);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);

I've got

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) SioFramework.Script:TestCall (string,int): IL_0014: call
0x00000005

This is the correct error.

Update 2 I created Debug, when comparing both methods they are looks same.

private void DebugM(MethodInfo method) {
    var builder = new StringBuilder();
    builder.Append("Name: ").Append(method.Name);
    builder.Append("\nParameters(").Append(method.GetParameters().Length).Append("): ");

    foreach (var parameter in method.GetParameters()) {
        builder.Append("(").Append(parameter.ParameterType.FullName).Append(")");
    }
    builder.Append("\nReturnType: ").Append(method.ReturnType.FullName);
    builder.Append("\nMemberType: ").Append(method.MemberType);
    builder.Append("\nCC: ").Append(method.CallingConvention);
    builder.Append("\nModule: ").Append(method.Module.Name);
    Debug.Log(builder.ToString());
}

Name: TestCall Parameters(2): (System.String)(System.Int32) ReturnType: System.Void MemberType: Method CC: Standard, HasThis Module: Assembly-CSharp.dll

I created exactly same method what is being recreated: To detect if it isn't due to parameters count Method what is being recreated:

public void TestCall(string testString, int testInt) {
    Debug.Log("Called TestCAll with params: " + testInt + ", " + testInt);
}

Method to call:

internal void TestMethod(string a, int b) {
    Debug.Log("Called TestMethod!!");
}

I tried to invoke it with delegate:

public delegate void TestDelegate(String a, int b);

//In end of CreateMethodFrom
var delTest = (TestDelegate) dynMethod.CreateDelegate(typeof(TestDelegate));
delTest("TESTA", 31321321);

Result is same:

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) SioFramework.Script:TestCall (string,int): IL_0014: call
0x00000005

Stacktrace

System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Delegate.cs:268)
System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Delegate.cs:291)
System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Delegate.cs:295)
System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs:179)
SioFramework.Script.CreateMethodFrom (System.Reflection.MethodInfo method) (at Assets/SioFramework/Script.cs:167)

167:

var delTest = (TestDelegate) dynMethod.CreateDelegate(typeof(TestDelegate));
c#
asked on Stack Overflow Jun 29, 2017 by siOnzee • edited Jun 30, 2017 by siOnzee

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0