34

C# で公開されていない IL 命令はどれですか?

sizeof や cpblk などの命令について言及しています。これらの命令を実行するクラスやコマンドはありません (C# の sizeof は、実行時の AFAIK ではなく、コンパイル時に計算されます)。

その他?

編集:私がこれを尋ねている理由(そして、これが私の質問をもう少し有効にすることを願っています)は、これらの命令の機能を提供する小さなライブラリに取り組んでいるためです。sizeof と cpblk は既に実装されています。先に進む前に、他に見逃している可能性があるものを知りたかったのです。

EDIT2:エリックの答えを使用して、指示のリストをまとめました:

  • 壊す
  • JMP
  • カリ
  • Cpobj
  • クフィニット
  • プレフィックス[1-7]
  • Prefixref
  • エンドフィルター
  • 非整列
  • テイルコール
  • Cpblk
  • 初期化ブロック

リストに含まれていない他の多くの命令がありましたが、それらは基本的に他の命令のショートカットであるため、分離しています (時間とスペースを節約するために圧縮されています)。

  • Ldarg[0-3]
  • Ldloc[0-3]
  • Stloc[0-3]
  • Ldc_[I4_[M1/S/0-8]/I8/R4/R8]
  • Ldind_[I1/U1/I2/U2/I4/U4/I8/R4/R8]
  • Stind_[I1/I2/I4/I8/R4/R8]
  • Conv_[I1/I2/I4/I8/R4/R8/U4/U8/U2/U1]
  • Conv_Ovf_[I1/I2/I4/I8/U1/U2/U4/U8]
  • Conv_Ovf_[I1/I2/I4/I8/U1/U2/U4/U8]_Un
  • Ldelem_[I1/I2/I4/I8/U1/U2/U4/R4/R8]
  • Stelem_[I1/I2/I4/I8/R4/R8]
4

4 に答える 4

36

sizeofやcpblkなどの命令を参照しています。これらの命令を実行するクラスやコマンドはありません(C#のsizeofは、実行時のAFAIKではなく、コンパイル時に計算されます)。

これは正しくありません。sizeof(int)もちろん、コンパイル時定数4として扱われますunsafeが、コンパイラが構造体のメモリサイズを決定するためにランタイムに依存する状況はたくさんあります(すべてコード内)。たとえば、2つのポインタを含む構造について考えてみます。サイズは32ビットマシンでは8ですが、64ビットマシンでは16になります。そのような状況では、コンパイラはsizeofオペコードを生成します。

その他?

作成していないすべてのオペコードのリストはありません。そのようなリストを作成する必要はありませんでした。ただし、頭のてっぺんから、C#で「間接呼び出し」(calli)命令を生成する方法はないと言えます。特定の相互運用シナリオのパフォーマンスが向上するため、この機能を求められることがあります。

更新:ソースコードを取得して、確実に作成するオペコードのリストを作成ました。彼らです:

追加
add_ovf
add_ovf_un
をし、 引数 リスト BEQ beq_s BGE
bge_s bge_un bge_un_s BGT bgt_s bgt_un bgt_un_s BLE ble_s ble_un ble_un_s BLT blt_s blt_un blt_un_s bne_un bne_un_s ボックス BR br_s brfalse brfalse_s brtrue brtrue_s コール callvirt castclass CEQ CGT cgt_un CLT clt_un 拘束 さ れ た conv_i conv_ovf_i






































conv_ovf_i_un
conv_ovf_u
conv_ovf_u_un
conv_r
conv_r_un
conv_uの
div
div_un DUP
endfinally
initobj
isinst
ldarg
ldarg_
ldarg_s
ldarga
ldarga_s
ldc_i
ldc_r
ldelem
ldelem_i
ldelem_r
ldelem_ref
ldelem_u
ldelema
ldfld ldflda
ldftn
ldind_i
ldind_r
ldind_ref
ldind_u
ldlen
ldloc
ldloc_
ldloc_s
ldloca
ldloca_s
ldnull
ldobj
ldsfld


ldsflda
ldstr
ldtoken
ldvirtftn
Leave_s
localloc
mkrefany mul mul_ovf
mul_ovf_un neg newarr newobj nop not or pop readonly refanytype refanyval rem rem_un ret rethrow shl shr shr_un sizeof starg starg_s stelem stelem_i _ _ _ _ _ _ _ _ _ _


































stsfld
subsub_ovfsub_ovf_un スイッチ
throwunbox_anyvolatile xor
_ _ _ _




それがすべてであることを保証するつもりはありませんが、それは確かにそれらのほとんどです。次に、それをすべてのオペコードのリストと比較して、何が欠落しているかを確認できます。

于 2011-08-18T16:50:19.880 に答える
13

エリックの答えに基づいて、私が見つけたものをいくつか紹介します。理由がわかる場合はそれを示しましたが、そうでない場合は自由に推測します。それらの推測が間違っているかどうかを遠慮なく示してください。

Break

共通言語インフラストラクチャ (CLI) に信号を送って、ブレーク ポイントが作動したことをデバッガーに通知します。

System.Diagnostics.Debugger.Break() を呼び出してこれを行います。これは、その命令を直接使用するのではなく、CLR に組み込まれた BreakInternal() メソッドを使用するように見えます。

CpblkCpobj

指定されたバイト数を送信元アドレスから宛先アドレスにコピーします。オブジェクトのアドレスにある値型 (&、* またはネイティブ int 型) をコピー先オブジェクト (&、* またはネイティブ int 型) のアドレスにコピーします。

これらは C++/CLI (以前の Managed C++) 用に追加されたものだと思いますが、それは私の推測にすぎません。また、特定のシステム コールに存在する場合もありますが、コンパイラによって正常に生成されず、危険な楽しみやゲームにある程度の範囲を提供します。

Endfilter

例外のフィルター句から共通言語インフラストラクチャ (CLI) の例外ハンドラーに制御を戻します。

C# は例外フィルタリングをサポートしていません。ただし、VB コンパイラは間違いなくこれを利用します。

Initblk

特定のアドレスにある指定されたメモリ ブロックを、指定されたサイズと初期値に初期化します。

これが安全でないコードや C++/CLI で役立つ可能性があることをもう一度推測します。

Jmp

現在のメソッドを終了し、指定されたメソッドにジャンプします。

この種のトランポリンは、テール コールを避けたい人に役立つのではないかと推測します。おそらくDLRはそれを利用していますか?

Tailcall

実際の呼び出し命令が実行される前に現在のメソッドのスタック フレームが削除されるように、後置メソッド呼び出し命令を実行します。

他の場所で詳細に説明されていますが、現在、c# コンパイラはこのオペコードを出力しません

Unaligned

現在評価スタックの一番上にあるアドレスが、直後の ldind、stind、ldfld、stfld、ldobj、stobj、initblk、または cpblk 命令の本来のサイズにアラインされていない可能性があることを示します。

C# (および CLR) は、結果として得られるコードとデータの多くの整列された性質に関して、かなりの数の保証を行います。これが出力されないのは当然のことですが、これが含まれる理由はわかります。

Unbox

値型のボックス化された表現をボックス化されていない形式に変換します。

Unbox_AnyC# コンパイラは、この目的のためだけに命令を使用することを好みます。これが 2.0 リリースの命令セットに追加されたことに基づいて、ジェネリックが実現可能になるか、はるかに単純になると思います。その時点で、ジェネリックであろうとなかろうと、すべてのコード全体でそれを使用することは、より安全で、より単純で、より高速でした (またはすべての組み合わせでした)。


脚注:

Prefix1、Prefix2、Prefix3、Prefix4、Prefix5、Prefix6、Prefix7、Prefixref

インフラストラクチャー。これは予約命令です。

これらは命令そのものではありません。一部の IL 命令は他の命令よりも長くなります。これらの可変長のものは、解析を明確にするために、それ自体では決して有効ではないプレフィックスで開始する必要があります。これらのプレフィックス オペコードはそのために予約されているため、他の場所では使用されません。間違いなく、IL シーケンス用の switch ステートメント ベースのパーサーを実装している人は、それらをトラップして状態を維持できるので、これらを高く評価するでしょう。

于 2011-08-18T18:47:33.603 に答える
4

興味深い例の 1 つはtail.call( OpCodes.Tailcall ) で、再帰のテール コールの最適化を可能にします。

于 2011-08-18T17:00:22.427 に答える
1

.overrideILディレクティブ(正しい用語かどうかはわかりませんが、確かに命令ではありません) は C# コンパイラによって生成されますが、明示的なインターフェイスの実装という特殊なケースでのみ生成されます。

VB.NET のように、実装メンバーにエイリアスを設定したり、インターフェイス メンバーとは異なるアクセス修飾子を使用したりできるように、より自由に使用できるようになれば興味深いでしょう。

于 2011-08-18T19:55:13.180 に答える