c# - 调用接口(interface)成员的虚方法的CLR实现

标签 c# interface clr dispatch method-call

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

我知道 CLR 为每个类型维护的 VTable 以及每个方法的方法槽,并且对于每个接口(interface)它都有一个额外的方法槽列表,这些方法槽指向关联的接口(interface)方法实现。但我不明白以下内容:CLR 如何有效地确定从类型的 VTable 中选择哪个接口(interface)方法槽列表?

文章Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects来自 MSDN 杂志 2005 年 5 月号的文章讨论了由接口(interface) ID 索引的进程级映射表 IVMap。这是否意味着同一进程中的所有类型都具有指向同一 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.

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

我还通过 C# 3rd edition 阅读了 CLR 中的接口(interface)一章,但它没有讨论这个。因此,this other question 的答案不要回答我的问题。

最佳答案

那篇文章已有 10 多年历史,很多从那以后发生了变化。

IVMaps 现已被 Virtual Stub Dispatch 取代.

Virtual stub dispatching (VSD) is the technique of using stubs for virtual method invocations instead of the traditional virtual method table. In the past, interface dispatch required that interfaces had process-unique identifiers, and that every loaded interface was added to a global interface virtual table map.

去读那篇文章,它有更多你需要知道的细节。它来自 Book of the Runtime ,这是最初由 CLR 开发人员为 CLR 开发人员编写的文档,但现在已发布给所有人。它基本上描述了运行时的核心内容。

我没有必要在这里重复这篇文章,但我只会陈述要点及其含义:

  • 当 JIT 发现对接口(interface)成员的调用时,它会将其编译成一个查找 stub 。这是一段将调用通用解析器的代码。
  • generic resolver 是一个函数,它将找出要调用的方法。这是调用此类方法的最通用因此也是最慢的方法。当第一次从一个查找 stub 调用时,它会将该 stub (在运行时重写它的代码)修补成一个调度 stub 。它还会生成一个解析 stub 供以后使用。 查找 stub 此时消失。
  • dispatch stub 是调用接口(interface)成员的最快方法,但有一个问题:它对调用单态持乐观态度,这意味着它针对接口(interface)调用总是解析为相同具体类型的情况。它将对象的方法表(即具体类型)与之前看到的方法表(硬编码到 stub 中)进行比较,如果比较成功,则调用缓存的方法(其地址也是硬编码的)。如果失败,它会回退到解析 stub
  • resolve stub 处理多态调用(一般情况)。它使用缓存来查找要调用的方法。如果该方法不在缓存中,它会调用通用解析器(它也会写入此缓存)。

这里有一个重要的考虑因素,直接来自文章:

When a dispatch stub fails frequently enough, the call site is deemed to be polymorphic and the resolve stub will back patch the call site to point directly to the resolve stub to avoid the overhead of a consistently failing dispatch stub. At sync points (currently the end of a GC), polymorphic sites will be randomly promoted back to monomorphic call sites under the assumption that the polymorphic attribute of a call site is usually temporary. If this assumption is incorrect for any particular call site, it will quickly trigger a backpatch to demote it to polymorphic again.

运行时对单态调用站点非常乐观,这在实际代码中很有意义,并且会尽量避免解析 stub .

关于c# - 调用接口(interface)成员的虚方法的CLR实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9808982/

相关文章:

c# - 如何编写返回动态对象的扩展方法?

c# - 使用 SQLDataReader 的可空 DateTime

c# - 在 C# 中实现一个使用并返回相同接口(interface)的接口(interface)

c# - F# 和 C# 的 CLR 相同那么为什么 F# 比 C# 快

c# - Lua 语言上下文/作用域实现

c# - 字符串比较等价物

c# winForm 向文本框中的数字添加值

java - OO 设计 - 将结果的责任委托(delegate)给不同的类

Java:使用符合我的接口(interface)的外部类

c# - 使用 OpenXML SDK 将 RTF 文件的内容嵌入到 DOCX 文件中