虚方法调用接口成员的CLR实现 [英] CLR implementation of virtual method calls to interface members

查看:35
本文介绍了虚方法调用接口成员的CLR实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于好奇:CLR 如何将虚方法调用分派到接口成员到正确的实现?

我知道 CLR 为每个类型维护的 VTable 以及每个方法的方法槽,以及事实上,对于每个接口,它都有一个指向相关接口方法实现的方法槽的附加列表.但我不明白以下内容:CLR 如何有效地确定从类型的 VTable 中选择哪个接口方法槽列表?

I know about the VTable that the CLR maintains for each type with method slots for each method, and the fact that for each interface it has an additional list of method slots that point to the associated interface method implementations. But I don't understand the following: how does the CLR efficiently determine which interface method slot list to pick from the type's VTable?

文章深入研究 .NET Framework 内部结构以了解 CLR 如何创建运行时对象 来自 MSDN 杂志 2005 年 5 月期的讨论讨论了按接口 ID 索引的进程级映射表 IVMap.这是否意味着同一进程中的所有类型都具有指向同一个 IVMap 的相同指针?

The article Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects from the May 2005 issue of the MSDN Magazine talks about a process-level mapping table IVMap indexed by interface ID. Does this mean that all types in the same process have the same pointer to the same IVMap?

它还指出:

如果 MyInterface1 由两个类实现,则会有两个IVMap 表中的条目.入口将指向开始嵌入在 MyClass 方法表中的子表.

If MyInterface1 is implemented by two classes, there will be two entries in the IVMap table. The entry will point back to the beginning of the sub-table embedded within the MyClass method table.

CLR 如何知道选择哪个条目?它是否进行线性搜索以查找与当前类型匹配的条目?还是二分查找?或者某种直接索引并有一个可能包含许多空条目的地图?

How does the CLR know which entry to pick? Does it do a linear search to find the entry that matches the current type? Or a binary search? Or some kind of direct indexing and have a map with possibly many empty entries in it?

我还通过 C# 3rd edition 阅读了 CLR 中的接口一章,但它没有讨论这个.因此,这个其他问题的答案并没有回答我的问题.

I've also read the chapter on Interfaces in CLR via C# 3rd edition but it does not talk about this. Therefore, the answers to this other question do not answer my question.

推荐答案

如果您查看链接站点上的图表,可能会更容易理解.

If you take a look at diagram that was on the linked site, it may make it easier to understand.

这是否意味着同一进程中的所有类型都具有指向同一个IVMap的相同指针?

Does this mean that all types in the same process have the same pointer to the same IVMap?

是的,因为它是在域级别,这意味着该 AppDomain 中的所有内容都具有相同的 IVMap.

Yes, since it is at the domain level, it means everything in that AppDomain has the same IVMap.

CLR 如何知道选择哪个条目?它是否进行线性搜索以查找与当前类型匹配的条目?还是二分查找?或者某种直接索引并有一个可能包含许多空条目的地图?

How does the CLR know which entry to pick? Does it do a linear search to find the entry that matches the current type? Or a binary search? Or some kind of direct indexing and have a map with possibly many empty entries in it?

这些类是用偏移量布置的,所以所有东西都有一个相对固定的区域.这使寻找方法时的事情变得更容易.它将搜索 IVMap 表并从接口中找到该方法.从那里,它转到 MethodSlotTable 并使用该类的接口实现.类的接口映射包含元数据,但是,实现的处理方式与任何其他方法一样.

The classes are laid out with offsets, so everything has a relatively set area on where it would be. That makes things easier when looking for methods. It would search the IVMap table and find that method from the interface. From there, it goes to the MethodSlotTable and uses that class' implementation of the interface. The inteface map for the class holds the metadata, however, the implementation is treated just like any other method.

再次来自您链接的网站:

Again from the site you linked:

每个接口实现在 IVMap 中都会有一个条目.如果 MyInterface1 由两个类实现,则 IVMap 表中将有两个条目.该条目将指向嵌入在 MyClass 方法表中的子表的开头

Each interface implementation will have an entry in IVMap. If MyInterface1 is implemented by two classes, there will be two entries in the IVMap table. The entry will point back to the beginning of the sub-table embedded within the MyClass method table

这意味着每次实现接口时,它在 IVMap 中都有一个唯一记录,指向 MethodSlotTable,而 MethodSlotTable 又指向实现.因此,它知道根据调用它的类选择哪个实现,因为该 IVMap 记录指向调用该方法的类中的 MethodSlotTable.所以我想这只是通过 IVMap 进行线性搜索以找到正确的实例,然后它们就会关闭并运行.

This means that each time an interface is implemented it has a unique record in the IVMap which points to the MethodSlotTable which in turn points to the implementation. So it knows which implementation to pick based on the class that is calling it as that IVMap record points to the MethodSlotTable in the class calling the method. So I imagine it is just a linear search through the IVMap to find the correct instance and then they are off and running.

提供有关 IVMap 的更多信息.

To provide more info on the IVMap.

同样,来自 OP 中的链接:

Again, from the link in the OP:

第一个InterfaceInfo 条目的前4 个字节指向MyInterface1 的TypeHandle(见图9 和图10).下一个 WORD(2 个字节)被 Flags 占用(其中 0 继承自 parent,1 在当前类中实现).Flags 后面的 WORD 是 Start Slot,类加载器使用它来布置接口实现子表.

The first 4 bytes of the first InterfaceInfo entry points to the TypeHandle of MyInterface1 (see Figure 9 and Figure 10). The next WORD (2 bytes) is taken up by Flags (where 0 is inherited from parent, and 1 is implemented in the current class). The WORD right after Flags is Start Slot, which is used by the class loader to lay out the interface implementation sub-table.

所以这里我们有一个表,其中的数字是字节的偏移量.这只是 IVMap 中的一条记录:

So here we have a table where the number is the offset of bytes. This is just one record in the IVMap:

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

假设这个 AppDomain 中有 100 条接口记录,我们需要找到每一条的实现.我们只是比较第 5 个字节,看看它是否与我们当前的类匹配,如果匹配,我们跳转到第 6 个字节中的代码.由于每条记录的长度为 8 个字节,因此我们需要执行以下操作:(伪代码)

Suppose there are 100 interface records in this AppDomain and we need to find the implementation for each one. We just compare the 5th byte to see if it matches our current class and if it does, we jump to the code in the 6th byte. Since, each record is 8 bytes long, we would need to do something like this: (Psuedocode)

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

虽然它仍然是线性搜索,但实际上,只要迭代的数据量不大,它就不会花那么长时间.我希望这会有所帮助.

While it is still a linear search, in reality, it isn't going to take that long as the size of data being iterated isn't huge. I hope that helps.

因此,在查看图表并想知道为什么图表中的类的 IVMap 中没有插槽 1 后,我重新阅读了该部分并发现了这一点:

So after looking at the diagram and wondering why there is no Slot 1 in the IVMap for the class in the diagram I re-read the section and found this:

IVMap 是根据方法表中嵌入的接口映射信息创建的.Interface Map 是在 MethodTable 布局过程中根据类的元数据创建的.类型加载完成后,方法分派只使用IVMap.

IVMap is created based on the Interface Map information embedded within the method table. Interface Map is created based on the metadata of the class during the MethodTable layout process. Once typeloading is complete, only IVMap is used in method dispatching.

所以类的IVMap只加载了特定类继承的接口.它看起来像是从域 IVMap 复制的,但只保留指向的接口.这就引出了另一个问题,如何?它可能与 C++ 执行 vtables 的方式等效,其中每个条目都有一个偏移量,并且接口映射提供了要包含在 IVMap 中的偏移量列表.

So the IVMap for a class is only loaded with the interfaces that the specific class inherits. It looks like it copies from the Domain IVMap but only keeps the interfaces that are pointed to. This brings up another question, how? Chances are it is the equivalent of how C++ does vtables where each entry has an offset and the Interface Map provides a list of the offsets to include in the IVMap.

如果我们查看可能适用于整个域的 IVMap:

If we look at the IVMap that could be for this entire domain:

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

假设该域中只有 4 个接口映射实现.每个插槽都有一个偏移量(类似于我之前发布的 IVMap 记录),此类的 IVMap 将使用这些偏移量访问 IVMap 中的记录.

Assume there are only 4 implementations of Interface Map in this domain. Each slot would have an offset (similar to the IVMap record I posted earlier) and the IVMap for this class would use those offsets to access the record in the IVMap.

假设每个插槽是 8 个字节,插槽 1 从 0 开始,所以如果我们想要获得插槽 2 和 3,我们会做这样的事情:

Assume each slot is 8 bytes with slot 1 starting at 0 so if we wanted to get slot 2 and 3 we would do something like this:

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,因为我不太熟悉它,但我试图复制链接到的文章中的内容.

Please excuse my x86 as I'm not that familiar with it but I tried to copy what they have in the article that was linked to.

这篇关于虚方法调用接口成员的CLR实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆