0

I want to create some dynamic method whcih has 2 cycles: in first some N values are pushed onto evaluation stack, in second - these N values are popped from stack. But CreateMethod throws InvalidProgramException. How I can realize what I want? My code is:

public static Action MakeSimpleAction()
{
    var dm = new DynamicMethod("evil", typeof(void), new Type[] {  }, true);
    var il = dm.GetILGenerator(); Label startCycle;
    il.DeclareLocal(typeof(int));   //i = 0

    //Method 1: All is OK!
    //il.Emit(OpCodes.Ldc_I4_0);  //Push 0 onto evaluation stack
    //il.Emit(OpCodes.Pop);  //Pop value from evaluation stack
    //il.Emit(OpCodes.Ret);

    //Method 2: In cycles - throws an exception!

    //First cycle: for (int i = 0; i < 5; i ++) Push(0);
    il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0);    //i = 0
    il.MarkLabel(startCycle = il.DefineLabel());
    il.Emit(OpCodes.Ldc_I4_0);  //Push 0 onto evaluation stack
    
    il.Emit(OpCodes.Ldloc_0);   //i ++
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Stloc_0);
    //if i < 5 goto startCycle
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldc_I4_5);
    il.Emit(OpCodes.Clt);   //if i < 5
    il.Emit(OpCodes.Brtrue_S, startCycle);

    //Second cycle: for (int i = 0; i < 5; i ++) Pop();
    il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0);    //i = 0
    il.MarkLabel(startCycle = il.DefineLabel());
    il.Emit(OpCodes.Pop);  //Pop value from evaluation stack

    il.Emit(OpCodes.Ldloc_0);   //i ++
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Stloc_0);
    //if i < 5 goto startCycle
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldc_I4_5);
    il.Emit(OpCodes.Clt);   //if i < 5
    il.Emit(OpCodes.Brtrue_S, startCycle);

    il.Emit(OpCodes.Ret);

    //throw System.InvalidProgramException: 'Common Language Runtime detected an invalid program.'
    return (Action)dm.CreateDelegate(typeof(Action));
}
Tadeusz
  • 6,453
  • 9
  • 40
  • 58
  • What if you write the c# code on [SharpLab](https://sharplab.io/) and compare the generated IL to your source. – Jeroen van Langen Mar 16 '22 at 13:11
  • If you're going to be using Reflection.Emit, you need to know how to use [PEVerify.exe](https://learn.microsoft.com/en-us/dotnet/framework/tools/peverify-exe-peverify-tool) which will scan your assembly and give you diagnostic feedback on why your program is invalid. In order to use it, you'll have to (temporarily) [save your generated assembly](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.assemblybuilder.save?view=netframework-4.8) to disk. – Kirk Woll Mar 16 '22 at 13:16
  • There is no C# code for what I want to do :(( – Tadeusz Mar 16 '22 at 13:17
  • @Tadeusz you can also use sharplab to write IL directly, it has a faster develop cycle. – Jeroen van Langen Mar 16 '22 at 13:40

0 Answers0