C#/CIL/Reflection.Emit 質問:
関数ポインターを持つ型を定義し、その型をインスタンス化し、別の型で静的メソッドを作成しようとしています (「単なる関数」を作成する他の方法がわからないため)、この静的メソッドへのポインターを与えるインスタンスに、後でそのポインタを使用して関数を呼び出します。
私はほとんど成功していません。:-(
タイプは次のとおりです。
Thunk = modb.DefineType("Thunk");
Thunk.DefineField("Env" , Env.AsType(), FieldAttributes.Public);
Thunk.DefineField("Expr", typeof(int), FieldAttributes.Public); // int is the correct type according to http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldftn.aspx
Thunk.CreateType();
ここまでは順調です(と思います)。次に、これらのいずれかを作成し、関数ポインターを割り当てます。
var methodBuilder = MainType.DefineMethod("my_other_little_function", MethodAttributes.Static, typeof(Int64), new[] {Env.AsType()});
{
var il2 = methodBuilder.GetILGenerator();
il2.Emit(OpCodes.Ldarg_0);
il2.Emit(OpCodes.Stloc_0);
binding.Expr.Compile(il2);
il2.Emit(OpCodes.Ret);
}
il.Emit(OpCodes.Newobj, ThunkCtor);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stfld, Thunk.GetField("Env"));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldftn, methodBuilder);
il.Emit(OpCodes.Stfld, Thunk.GetField("Expr"));
私が知る限り、この部分は問題なく機能しています。私がそれを呼び出そうとすると、問題は別の場所にあります:
var func = il.DeclareLocal(typeof(int));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldfld, Thunk.GetField("Expr"));
il.Emit(OpCodes.Stloc, func);
il.Emit(OpCodes.Ldfld, Thunk.GetField("Env"));
il.Emit(OpCodes.Ldloc, func);
il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(Int64), new[] { Env.AsType() }, null);
これによって作成されたプログラムを実行しようとすると、バイトコードが実行される前にエラーが発生します (または、少なくともそのように表示されます)。
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
代わりに、EmitCalli() を単純に関数ポインターと引数をポップして数値をプッシュするコードに置き換えると、プログラムの残りの部分は正常に動作します。では、この関数をどのように呼び出す必要がありますか?
本当にありがとう。:-)