Comment fonctionne l’instruction callvirt .NET pour les interfaces?

Expliquer la répartition virtuelle à une personne est simple: chaque object a un pointeur vers une table dans le cadre de ses données. Il y a N méthodes virtuelles sur la classe. Chaque appel à une méthode particulière indexe l’object lorsqu’il arrive et appelle la méthode ith dans la table. Chaque classe qui implémente la méthode X () aura le code de la méthode X () dans le même index ith.

Mais alors nous obtenons des interfaces. Et les interfaces requièrent une sorte de contorsion car deux classes non héritées qui implémentent la même interface auront les fonctions virtuelles dans différents index de la table.

J’ai cherché sur Internet, et je peux trouver de nombreuses discussions sur la manière dont la répartition des interfaces peut être mise en œuvre. Il existe deux grandes catégories: a) une sorte de table de hachage recherche l’object pour trouver la bonne table de dissortingbution vtable.

Mais malgré de nombreuses informations sur son fonctionnement, je ne trouve rien sur la manière dont le moteur d’exécution .NET l’implémente réellement.

Est-ce que quelqu’un connaît un document qui décrit l’arithmétique de pointeur réelle qui se produit à une instruction callvirt lorsque le type d’object est une interface?

La répartition des interfaces dans le CLR est la magie noire.

Comme vous le remarquez correctement, la répartition des méthodes virtuelles est conceptuellement facile à expliquer. Et en fait je le fais dans cette série d’articles, où je décris comment vous pouvez implémenter des méthodes virtuelles dans un langage de type C # qui leur manquait:

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

Les mécanismes que je décris sont assez similaires aux mécanismes réellement utilisés.

La répartition des interfaces est beaucoup plus difficile à décrire et la façon dont le CLR l’implémente n’est pas du tout évidente. Les mécanismes CLR pour la répartition des interfaces ont été soigneusement ajustés pour fournir des performances élevées dans les situations les plus courantes, et les détails de ces mécanismes sont donc susceptibles de changer à mesure que l’équipe CLR développe ses connaissances sur les schémas d’utilisation réels.

Fondamentalement, la façon dont cela fonctionne en arrière-plan est que chaque site d’appel – c’est-à-dire chaque point du code où une méthode d’interface est appelée – contient un petit cache qui dit: .. ici”. La grande majorité du temps, cette cache est correcte; Vous appelez très rarement la même méthode d’interface un million de fois avec un million d’implémentations différentes. C’est généralement la même implémentation encore et encore, plusieurs fois de suite.

Si le cache s’avère être un échec, il revient à une table de hachage qui est maintenue, pour effectuer une recherche légèrement plus lente.

Si cela s’avère être un échec, alors les métadonnées de l’object sont analysées pour déterminer quelle méthode correspond à l’emplacement d’interface.

L’effet net est que sur un site d’appel donné, si vous invoquez toujours une méthode d’interface qui correspond à une méthode de classe particulière, il est très rapide. Si vous invoquez toujours l’une des nombreuses méthodes de classe pour une méthode d’interface donnée, les performances sont plutôt bonnes. La pire chose à faire est de ne jamais appeler la même méthode de classe deux fois avec la même méthode d’interface sur le même site; cela prend le chemin le plus lent à chaque fois.

Si vous voulez savoir comment les tables pour la recherche lente sont conservées en mémoire, consultez le lien dans la réponse de Matthew Watson.

Comme le compilateur doit toujours avoir un object réel sur lequel appeler la méthode (au moment de l’exécution), il sait toujours à l’exécution le type concret qu’il traite.

Le code qui appelle une méthode virtuelle détermine d’abord le type de l’object utilisé. Il consulte ensuite la table de méthodes du type pour rechercher la méthode appelée. Le code appelle ensuite simplement cette méthode, transmettant la référence de l’object comme ceci avec tous les autres parameters.

Je soupçonne que le bit crucial qui vous intéresse est la façon dont le code recherche l’adresse de la méthode dans la table de méthodes du type.

Vous trouverez plus de détails sur le tableau des méthodes dans l’article «JIT and Run» de l’édition de mai 2005 du magazine MSDN (qui, au moment de la rédaction, peut être téléchargé sous forme de fichier «.chm» à partir de cette page) . aux propriétés du fichier pour le déverrouiller avant qu’il ne s’affiche correctement, en raison de ressortingctions de sécurité.)

La façon dont la recherche est faite est un peu hésitante, mais elle donne beaucoup d’autres détails.