简体   繁体   English

发射MSIL发出MSIL遇到JIT限制

[英]Emiting MSIL to emit MSIL runs into JIT Limitation

So I wanted to answer https://codegolf.stackexchange.com/q/22921/12097 and decided to emit MSIL code to do the integer addition. 所以我想回答https://codegolf.stackexchange.com/q/22921/12097,并决定发出MSIL代码来进行整数加法。 Since this was successful, I then decided to emit MSIL code, which emits my first code. 既然成功了,我便决定发出MSIL代码,该代码也发出了我的第一个代码。 So calling the code constructs a method, which constructs a method that calls int.op_Addition . 因此,调用代码构造一个方法,该方法构造一个调用int.op_Addition的方法。 This fails miserably with the JIT complaining that I have gone too far! JIT抱怨我走得太远了,这不幸地失败了! Duh! h!

The exception is System.SystemException: {"JIT Compiler encountered an internal limitation."} on the last line when the dynamic method is called. 例外是System.SystemException: {"JIT Compiler encountered an internal limitation."}调用动态方法时,在最后一行上有System.SystemException: {"JIT Compiler encountered an internal limitation."}

My question is, I am correct in assuming that emitting code to emit code is somehow disallowed by the JIT. 我的问题是,我假设JIT禁止以某种方式发出代码来发出代码是正确的。 The alternative is that I made a misake, which is likely, but I checked my code against MSIL code generated by Reflector . 另一种选择是我犯了一个错误,这很可能,但是我对照Reflector生成的MSIL代码检查了我的代码。

Here is the code, for your amusement: 这是代码,供您娱乐:

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);
    }
}

I expect Add2 to generate code that looks like this, which works 100% correctly: 我希望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);
    }

I'm quite certain that the JIT is able to compile code that uses Reflection. 我非常确定JIT能够编译使用Reflection的代码。 If not, you wouldn't be able to use Reflection.Emit , ever. 如果没有,您将永远无法使用Reflection.Emit The MSIL you generate goes through the same JIT process as MSIL generated by the C# compiler. 您生成的MSIL与C#编译器生成的MSIL经历相同的JIT流程。

There is a bit of a difference when it comes to CAS checks, but I see nothing to suggest that you're operating in a partial trust scenario to begin with. 在进行CAS检查时,有一些区别,但是我看不出有任何迹象表明您是在部分信任的情况下开始工作的。

I see this line: 我看到这一行:

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

which locates the DynamicMethod(string, Type, Type[]) constructor that creates an anonymously-hosted method. 它找到了创建匿名托管方法的DynamicMethod(string, Type, Type[])构造函数。 But in Add1 , you have 但是在Add1 ,您有

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

which calls the four-argument DynamicMethod constructor, that adds a method to the type Program . 它将调用四个参数的DynamicMethod构造函数,该构造函数将一个方法添加到Program类型中。

As a result, there's a complete mismatch of the types on the operand stack when you use newobj . 结果,当您使用newobj时,操作数堆栈上的类型完全不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM