代码之家  ›  专栏  ›  技术社区  ›  John Alexiou

发出MSIL以发出MSIL运行到JIT限制

  •  -1
  • John Alexiou  · 技术社区  · 10 年前

    所以我想回答 https://codegolf.stackexchange.com/q/22921/12097 并决定发出MSIL代码来进行整数加法。由于这是成功的,所以我决定发出MSIL代码,这将发出我的第一个代码。因此,调用代码构造一个方法,该方法构造一个调用 int.op_Addition 。由于JIT抱怨我做得太过分,这失败得很惨!啊!

    例外情况是 System.SystemException: {"JIT Compiler encountered an internal limitation."} 在调用动态方法的最后一行。

    我的问题是,我假设JIT不允许发出代码来发出代码是正确的。另一种选择是我犯了一个错误,这很可能,但我根据生成的MSIL代码检查了我的代码 Reflector .

    这是代码,供您消遣:

    class Program
    {
        static void Main(string[] args)
        {
            int z2=Add2(1, 2);
            // z2 = "JIT Compiler encountered an internal limitation."
        }
    
        // Emit MSIL to emit MSIL
        public static int Add2(int x, int y)
        {
            Type delegate_type=typeof(Func<int, int, int>);
            DynamicMethod method=new DynamicMethod(typeof(Program).ToString()+".GenAdd",
                typeof(int),
                new Type[] { typeof(int), typeof(int) }, typeof(Program));
            ILGenerator generator=method.GetILGenerator();
    
            LocalBuilder method1=generator.DeclareLocal(typeof(DynamicMethod));
            LocalBuilder generator1=generator.DeclareLocal(typeof(ILGenerator));
            LocalBuilder add1=generator.DeclareLocal(typeof(Func<int, int, int>));
            LocalBuilder args1=generator.DeclareLocal(typeof(Type[]));
            generator.Emit(OpCodes.Ldtoken, typeof(int));            
    
            generator.Emit(OpCodes.Call, 
                typeof(Type).GetMethod("GetTypeFromHandle", 
                    System.Reflection.BindingFlags.Public | 
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(object).GetMethod("ToString", 
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Instance));
            generator.Emit(OpCodes.Ldstr, ".op_Addition");                        
            generator.Emit(OpCodes.Call,                
                typeof(string).GetMethod("Concat",
                    new Type[] { typeof(string), typeof(string) } ));
            generator.Emit(OpCodes.Ldtoken, typeof(int));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Ldc_I4, 2);
            generator.Emit(OpCodes.Newarr, typeof(Type));
            generator.Emit(OpCodes.Stloc_3);
            generator.Emit(OpCodes.Ldloc_3);
            generator.Emit(OpCodes.Ldc_I4, 0);
            generator.Emit(OpCodes.Ldtoken, typeof(int));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Stelem_Ref);
            generator.Emit(OpCodes.Ldloc_3);
            generator.Emit(OpCodes.Ldc_I4, 1);
            generator.Emit(OpCodes.Ldtoken, typeof(int));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Stelem_Ref);
            generator.Emit(OpCodes.Ldloc_3);
            generator.Emit(OpCodes.Ldtoken, typeof(Program));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
    
            generator.Emit(OpCodes.Newobj,
                typeof(DynamicMethod).GetConstructor(
                    new Type[] { typeof(string), typeof(Type), typeof(Type[]) }));
    
            generator.Emit(OpCodes.Stloc_0);
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Callvirt,
                typeof(DynamicMethod).GetMethod("GetILGenerator",
                    Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc_1);
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldtoken, typeof(int));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("DeclareLocal",
                    new Type[] { typeof(Type) }));
            generator.Emit(OpCodes.Pop);
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Ldarg_0",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Ldarg_1",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Add",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Stloc_0",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Ldloc_0",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldsfld,
                typeof(OpCodes).GetField("Ret",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode) }));
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldtoken, typeof(Func<int, int, int>));
            generator.Emit(OpCodes.Call,
                typeof(Type).GetMethod("GetTypeFromHandle",
                    System.Reflection.BindingFlags.Public|
                    System.Reflection.BindingFlags.Static));
            generator.Emit(OpCodes.Callvirt,
                typeof(DynamicMethod).GetMethod("CreateDelegate",
                    new Type[] { typeof(Type)} ));
            generator.Emit(OpCodes.Isinst, typeof(Func<int, int, int>));
            generator.Emit(OpCodes.Stloc_2);
            generator.Emit(OpCodes.Ldloc_2);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Callvirt,
                typeof(Func<int, int, int>).GetMethod("Invoke",
                    System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance));
            generator.Emit(OpCodes.Ret);
    
            Func<int, int, int> add2=method.CreateDelegate(typeof(Func<int, int, int>)) as Func<int, int, int>;
    
            return add2(x, y);
        }
    }
    

    我想 Add2 生成如下代码,该代码100%正确工作:

        // Emit MSIL directly
        public static int Add1(int x, int y)
        {
            Type delegate_type=typeof(Func<int, int, int>);
            DynamicMethod method = new DynamicMethod(typeof(int).ToString()+".op_Addition",
                typeof(int),
                new Type[] { typeof(int), typeof(int) }, typeof(Program));
    
            ILGenerator generator=method.GetILGenerator();
            LocalBuilder result=generator.DeclareLocal(typeof(int));
    
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Add);
            generator.Emit(OpCodes.Stloc_0);
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ret);
    
            Func<int, int, int> add=method.CreateDelegate(typeof(Func<int, int, int>)) as Func<int, int, int>;
    
            return add(x, y);
        }
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Ben Voigt    10 年前

    我很确定JIT能够编译使用反射的代码。如果没有,您将无法使用 Reflection.Emit 曾经您生成的MSIL与C#编译器生成的MSIL经历相同的JIT过程。

    当涉及到CAS检查时,会有一点不同,但我看不出有任何迹象表明您在开始时是在部分信任场景中操作的。

    我看到这行:

    generator.Emit(OpCodes.Newobj,
    typeof(DynamicMethod).GetConstructor(
        new Type[] { typeof(string), typeof(Type), typeof(Type[]) }));
    

    它定位 DynamicMethod(string, Type, Type[]) 创建匿名托管方法的构造函数。但在 Add1 ,你有

    DynamicMethod method = new DynamicMethod(typeof(int).ToString()+".op_Addition",
                                             typeof(int),
                                             new Type[] { typeof(int), typeof(int) }, 
                                             typeof(Program));
    

    它调用四个参数 DynamicMethod 构造函数,将方法添加到类型 Program .

    因此,当您使用 newobj .