私はC#で小さなコンパイラを構築していますので、必然的に動的アセンブリと発光コードに干渉しなければならなくなりました。今、奇妙なことは、私のEmit()呼び出しが、生成されたモジュールに追加のnopオペコードを作成することです。パフォーマンスは本当に重要なものではないので、私の場合はそれほど重要ではありませんが、正直なところ、なぜこのようなことが起こっているのかは分かりません。地元の人や議論に読み込んだり、保管したりした後に起こっているようです。私がチェックできるものを私に指摘する可能性のあるC#/ダイナミックアセンブリの専門家はいますか?私は、生成されたコードのサンプルを添付しました。それ以上の情報が必要な場合は教えてください。ありがとう。ILGenerator.Emit()は、nopオペコードを動的アセンブリに挿入するのはなぜですか?
IL_0000: ldc.i4 0x0
IL_0005: stloc c
IL_0009: nop
IL_000a: nop
IL_000b: ldloc c
IL_000f: nop
IL_0010: nop
IL_0011: stloc i
IL_0015: nop
IL_0016: nop
IL_0017: ldarg s
IL_001b: nop
IL_001c: nop
IL_001d: ldloc i
IL_0021: nop
IL_0022: nop
IL_0023: add
IL_0024: stloc $0
IL_0028: nop
IL_0029: nop
IL_002a: ldloc $0
IL_002e: nop
IL_002f: nop
IL_0030: ldind.i1
IL_0031: ldc.i4 0x0
IL_0036: bne.un IL_0040
IL_003b: br IL_008e
IL_0040: ldloc c
IL_0044: nop
IL_0045: nop
IL_0046: stloc $1
ここでは、私のコードの外観を要約しています。いくつか欠けているものがあり、コードが別々の モジュールに分割されているため、これらは実行される順序で最も関連性の高い部分です。 (3番地コードで飾られた)私の抽象構文木の各ノードに対して
string programName = "myprogram";
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName(programName), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module = n.AssemblyBuilder.DefineDynamicModule(programName, string.Format("{0}.exe", programName), true);
string contextName = string.Format("{0}.{1}", programName, "context");
MethodAttributes attributes = MethodAttributes.Private | MethodAttributes.Static;
MethodBuilder methodBuilder = typeBuilder.DefineMethod(method, attributes, returnType, paramTypes);
foreach (string name in paramNames)
methodBuilder.DefineParameter(i++, ParameterAttributes.None, name);
ILGenerator Cil = methodBuilder.GetILGenerator();
...
foreach (var g in qLocals)
{
LocalBuilder localBuilder = Cil.DeclareLocal(type);
localBuilder.SetLocalSymInfo(g.Name);
}
foreach (var s in strings)
{
LocalBuilder localBuilder = Cil.DeclareLocal(typeIndexed.DotNetElementType. MakePointerType());
localBuilder.SetLocalSymInfo(string.Format("_{0}", index));
}
IEnumerable<Quad> jumpTargets =
(from q in n.Tac
select q.Addrs.OfType<AddrQuad>()).
SelectMany(x => x).Select(a => a.Quad).Distinct();
foreach (Quad q in jumpTargets)
q.DefineLabel(Cil);
}
、私は単純に実行します。
public override void DefaultPost(NodeBase n)
{
foreach (Quad q in n.Tac)
q.Emit(Cil);
}
これは、この関数が生成する呼び出しのシーケンスです:
cil.Emit(OpCodes.Ldloc, Index);
cil.Emit(OpCodes.Stloc, Index);
cil.Emit(OpCodes.Ldc_I4, (int)this.i);
cil.Emit(OpCodes.Stloc, Index);
cil.Emit(OpCodes.Ldloc, Index);
cil.Emit(OpCodes.Ldc_I4, (int)this.i);
cil.Emit(OpCodes.Br, res.Quad.Label.Value);
cil.Emit(OpCodes.Ldloc, Index);
cil.Emit(OpCodes.Ldc_I4, (int)this.i);
cil.Emit(OpCodes.Stloc, Index);
cil.Emit(OpCodes.Ldloc, Index);
cil.Emit(OpCodes.Stloc, Index);
cil.Emit(OpCodes.Ldloc, Index);
cil.Emit(OpCodes.Ldc_I4, (int)this.i);
cil.Emit(OpCodes.Bge, quad.Label.Value);
cil.Emit(OpCodes.Br, res.Quad.Label.Value);
...
これが役立つかどうか分かりません。完全なプロジェクトをチェックアウトしたい場合は、
http://github.com/yannikab/grc
ターゲットコードの生成に関連するすべてのものは、Cil名前空間の下にあります。コード生成のためにすべてをまとめるクラスは、CilVisitorという名前です。
[this](https://stackoverflow.com/questions/1498162/c-sharp-ilgenerator-nop)を参照してください。おそらく間違ったエンコーディングです。 – Mat
メソッドの発行方法のサンプルコードが参考になります。 – IllidanS4
私の質問を更新しました – user1171946