发出MSIL以发出MSIL会进入JIT限制

时间:2014-03-07 05:59:45

标签: c# cil reflection.emit

所以我想回答https://codegolf.stackexchange.com/q/22921/12097并决定发出MSIL代码来进行整数加法。由于这是成功的,我然后决定发出MSIL代码,它发出我的第一个代码。因此,调用代码构造一个方法,该方法构造一个调用int.op_Addition的方法。 JIT抱怨说我走得太远了!杜!

调用动态方法时,最后一行的异常为System.SystemException: {"JIT Compiler encountered an internal limitation."}

我的问题是,我认为JIT不允许以某种方式禁止发出代码来发出代码。另一种方法是我做了一个可能的错误,但是我根据Reflector生成的MSIL代码检查了我的代码。

这是代码,为了您的娱乐:

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 个答案:

答案 0 :(得分:2)

我非常确定JIT能够编译使用Reflection的代码。如果没有,您将永远无法使用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时,操作数堆栈上的类型完全不匹配。