2014-03-07 63 views
-1

所以我想回答https://codegolf.stackexchange.com/q/22921/12097並決定發射MSIL代碼做整數加法。由於這是成功的,我決定發出MSIL代碼,它發出我的第一個代碼。所以調用代碼構造一個方法,構造一個調用int.op_Addition的方法。 JIT抱怨說我太過分了!咄!發射MSIL發射MSIL運行到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); 
    } 
+0

如果代碼有問題,它會產生一個'System.SystemException:{「Common Language Runtime檢測到一個無效的程序。」}' – ja72

+0

感謝Ben的代碼現在可以工作,並且沒有問題畢竟是「JIT」。 FYI - 這裏是代碼大賽帖子:http://codegolf.stackexchange.com/a/23305/12097 – ja72

回答

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[])構造函數創建一個匿名託管方法。但在​​,你有

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

它調用四個參數DynamicMethod構造,增加了一個方法的類型Program

因此,當您使用newobj時,操作數堆棧中的類型會有完全不匹配。

+0

我要爲這個構造函數'public DynamicMethod(string name,Type returnType,Type [] parameterTypes,Type owner); '。你是對的。它現在有效。 – ja72