34

好奇心から: CLR はインターフェイス メンバーへの仮想メソッド呼び出しを正しい実装にどのようにディスパッチするのでしょうか?

CLR が各メソッドのメソッド スロットを持つ型ごとに維持する VTable と、関連付けられたインターフェイス メソッドの実装を指すメソッド スロットの追加リストがインターフェイスごとにあることを知っています。しかし、私は次のことを理解していません: CLR はどのインターフェイス メソッド スロット リストを型の VTable から選択するかを効率的に決定する方法を教えてください。

MSDN Magazine の 2005 年 5 月号の記事「Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects」では、インターフェイス ID によってインデックス付けされたプロセス レベルのマッピング テーブル IVMap について説明しています。これは、同じプロセス内のすべてのタイプが同じ IVMap への同じポインターを持っているということですか?

また、次のようにも述べています。

が 2 つのクラスで実装されている場合MyInterface1、IVMap テーブルには 2 つのエントリがあります。MyClassエントリは、メソッド テーブル内に埋め込まれたサブテーブルの先頭を指します。

CLR はどのエントリを選択するかをどのように判断しますか? 現在のタイプに一致するエントリを見つけるために線形検索を行いますか? それとも二分探索?または、ある種の直接索引付けで、おそらく多くの空のエントリが含まれるマップがありますか?

C# 第 3 版による CLR のインターフェイスに関する章も読みましたが、これについては触れていません。したがって、この他の質問への回答は私の質問には答えません。

4

3 に答える 3

24

.NET スタック

リンク先にあった図を見ていただくと分かりやすいかもしれません。

これは、同じプロセス内のすべてのタイプが同じ IVMap への同じポインターを持っているということですか?

はい、ドメイン レベルであるため、その AppDomain 内のすべてが同じ IVMap を持つことを意味します。

CLR はどのエントリを選択するかをどのように判断しますか? 現在のタイプに一致するエントリを見つけるために線形検索を行いますか? それとも二分探索?または、ある種の直接索引付けで、おそらく多くの空のエントリが含まれるマップがありますか?

クラスはオフセットでレイアウトされているため、すべてのクラスが相対的に設定された場所に設定されています。これにより、メソッドを探すときの作業が容易になります。IVMap テーブルを検索し、インターフェイスからそのメソッドを見つけます。そこから MethodSlotTable に移動し、そのクラスのインターフェイスの実装を使用します。クラスのインターフェイス マップはメタデータを保持しますが、実装は他のメソッドと同様に扱われます。

リンクしたサイトからもう一度:

各インターフェイスの実装には、IVMap のエントリがあります。MyInterface1 が 2 つのクラスによって実装されている場合、IVMap テーブルには 2 つのエントリがあります。エントリは、MyClass メソッド テーブル内に埋め込まれたサブテーブルの先頭を指します。

これは、インターフェースが実装されるたびに、IVMap に固有のレコードがあり、これが MethodSlotTable をポイントし、それが実装をポイントすることを意味します。そのため、その IVMap レコードがメソッドを呼び出しているクラスの MethodSlotTable を指しているため、それを呼び出しているクラスに基づいて選択する実装を認識します。したがって、正しいインスタンスを見つけるために IVMap を線形検索するだけで、それらはオフになって実行されていると思います。


編集: IVMap に関する詳細情報を提供します。

繰り返しますが、OP のリンクから:

最初の InterfaceInfo エントリの最初の 4 バイトは、MyInterface1 の TypeHandle を指しています (図 9 および図 10 を参照)。次の WORD (2 バイト) はフラグによって使用されます (0 は親から継承され、1 は現在のクラスで実装されます)。Flags の直後の WORD は Start Slot で、クラス ローダーがインターフェイス実装サブテーブルを配置するために使用します。

ここに、数値がバイトのオフセットであるテーブルがあります。これは、IVMap 内の 1 つのレコードにすぎません。

+----------------------------------+
| 0 - InterfaceInfo                |
+----------------------------------+
| 4 - Parent                       |
+----------------------------------+
| 5 - Current Class                |
+----------------------------------+
| 6 - Start Slot (2 Bytes)         |
+----------------------------------+

この AppDomain に 100 個のインターフェイス レコードがあり、それぞれの実装を見つける必要があるとします。5 番目のバイトを比較して現在のクラスと一致するかどうかを確認し、一致する場合は 6 バイト目のコードにジャンプします。各レコードの長さは 8 バイトなので、次のようにする必要があります: (疑似コード)

findclass :
   if (!position == class) 
      findclass adjust offset by 8 and try again

これは依然として線形検索ですが、実際には、反復されるデータのサイズがそれほど大きくないため、それほど時間はかかりません。それが役立つことを願っています。


EDIT2:

ダイアグラムを見て、ダイアグラム内のクラスの IVMap にスロット 1 がない理由を疑問に思った後、セクションを読み直したところ、次のことがわかりました。

IVMap は、メソッド テーブル内に埋め込まれた Interface Map 情報に基づいて作成されます。インターフェイス マップは、MethodTable レイアウト プロセス中にクラスのメタデータに基づいて作成されます。タイプロードが完了すると、IVMap のみがメソッドのディスパッチに使用されます。

そのため、クラスの IVMap は、特定のクラスが継承するインターフェースのみでロードされます。Domain IVMap からコピーしているように見えますが、ポイントされているインターフェースのみを保持しています。これは別の質問を引き起こします。おそらく、C++ が各エントリにオフセットを持ち、Interface Map が IVMap に含めるオフセットのリストを提供する vtables を行う方法と同等です。

このドメイン全体の可能性がある IVMap を見ると、次のようになります。

+-------------------------+
| Slot 1 - YourInterface  |
+-------------------------+
| Slot 2 - MyInterface    |
+-------------------------+
| Slot 3 - MyInterface2   |
+-------------------------+
| Slot 4 - YourInterface2 |
+-------------------------+

このドメインには Interface Map の実装が 4 つしかないとします。各スロットにはオフセットがあり (前に投稿した IVMap レコードと同様)、このクラスの IVMap はこれらのオフセットを使用して IVMap 内のレコードにアクセスします。

各スロットが 8 バイトで、スロット 1 が 0 から始まると仮定すると、スロット 2 と 3 を取得したい場合は、次のようにします。

mov ecx,edi
mov eax, dword ptr [ecx]
mov eax, dword ptr [ecx+08h] ; slot 2
; do stuff with slot 2
mov eax, dword ptr [ecx+10h] ; slot 3
; do stuff with slot 3

x86 については詳しくないので、申し訳ありませんが、リンク先の記事にあるものをコピーしようとしました。

于 2012-03-21T19:09:16.577 に答える
0

リンクした最初の記事から:

MyInterface1 が 2 つのクラスによって実装されている場合、IVMap テーブルには 2 つのエントリがあります。図 9 に示すように、エントリは、MyClass メソッド テーブル内に埋め込まれたサブテーブルの先頭を指します。

ClassLoader は、現在のクラス、親クラス、およびインターフェイスのメタデータを調べて、メソッド テーブルを作成します。レイアウト プロセスでは、オーバーライドされた仮想メソッドを置き換え、非表示になっている親クラス メソッドを置き換え、新しいスロットを作成し、必要に応じてスロットを複製します。スロットの複製は、各インターフェイスが独自のミニ vtable を持っているという錯覚を作成するために必要です。ただし、重複したスロットは同じ物理実装を指しています。

これは、インターフェイスの IVMap に、クラスの vtable のサブセクションを指すクラス名 (またはそれに相当するもの) によってキー付けされたエントリが含まれていることを示唆しています。クラス自身の vtable エントリと同じ物理的な実装。

しかし、完全に間違っている可能性があります。

于 2012-03-21T18:54:10.887 に答える