How does the callvirt .NET instruction work for interfaces?

前端 未结 2 2006
半阙折子戏
半阙折子戏 2021-01-31 08:29

Explaining virtual dispatching to someone is easy: every object has a pointer to a table as part of its data. There are N virtual methods on the class. Every call to a particula

2条回答
  •  囚心锁ツ
    2021-01-31 09:03

    Interface dispatching in the CLR is black magic.

    As you correctly note, virtual method dispatch is conceptually easy to explain. And in fact I do so in this series of articles, where I describe how you could implement virtual methods in a C#-like language that lacked them:

    http://blogs.msdn.com/b/ericlippert/archive/2011/03/17/implementing-the-virtual-method-pattern-in-c-part-one.aspx

    The mechanisms I describe are quite similar to the mechanisms actually used.

    Interface dispatch is much harder to describe, and the way the CLR implements it is not at all apparent. The CLR mechanisms for interface dispatch have been carefully tuned to provide high performance for the most common situations, and the details of those mechanisms are therefore subject to change based as the CLR team develops more knowledge about real-world patterns of usage.

    Basically the way it works behind the scenes is that each call site -- that is, each point in the code where an interface method is invoked -- there is a little cache that says "I think the method associated with this interface slot is... here". The vast majority of the time, that cache is right; you very seldom call the same interface method a million times with a million different implementations. It's usually the same implementation over and over again, many times in a row.

    If the cache turns out to be a miss then it falls back to a hash table that is maintained, to do a slightly slower lookup.

    If that turns out to be a miss, then the object metadata is analyzed to determine what method corresponds to the interface slot.

    The net effect is that at a given call site, if you always invoke an interface method that maps to a particular class method, it is very fast. If you always invoke one of a handful of class methods for a given interface method, performance is pretty good. The worst thing to do is to never invoke the same class method twice with the same interface method at the same site; that takes the slowest path every time.

    If you want to know how the tables for the slow lookup are maintained in memory, see the link in Matthew Watson's answer.

提交回复
热议问题