36 votes

Pourquoi le compilateur émet-il des instructions pour comparer les instances d'un type de référence?

Voici un type générique simple avec un paramètre générique unique contraint aux types de référence:

 class A<T> where T : class
{
    public bool F(T r1, T r2)
    {
        return r1 == r2;
    }
}
 

Le IL généré par csc.exe est:

 ldarg.1
box        !T
ldarg.2
box        !T
ceq
 

Donc, chaque paramètre est encadré avant de procéder à la comparaison.

Mais si la contrainte indique que "T" ne devrait jamais être un type de valeur, pourquoi le compilateur essaie-t-il d'encadrer r1 et r2 ?

43voto

Mehrdad Afshari Points 204872

Il est nécessaire pour satisfaire la vérifiabilité des contraintes pour l'généré IL. Notez que invérifiables ne veut pas forcément dire incorrecte. Il fonctionne très bien sans l' box d'instructions tant que son contexte de sécurité permet l'exécution de code non vérifiable. La vérification est conservateur et est basé sur un ensemble de règles (comme l'accessibilité). Pour simplifier les choses, ils ont choisi de ne pas se soucier de la présence de génériques type de contraintes dans l'algorithme de vérification.

Common Language Infrastructure Spécification ECMA-335)

La Section 9.11: Contraintes sur les paramètres génériques

... Contraintes sur un paramètre générique seulement de restreindre les types que le paramètre générique peut être instancié avec. De vérification (voir la Partition III) exige qu'un champ, une propriété ou une méthode qui un paramètre générique est connu pour fournir, à travers la rencontre d'une contrainte, ne peut pas accéder directement appelé via le paramètre générique , sauf si elle est d'abord en boîte (voir la Partition III) ou de l' callvirt instruction est préfixé avec l' constrained préfixe d'instruction. ...

Retrait de l' box instructions entraînera la invérifiable code:

.method public hidebysig instance bool 
       F(!T r1,
         !T r2) cil managed
{
   ldarg.1
   ldarg.2
   ceq
   ret
}


c:\Users\Mehrdad\Scratch>peverify sc.dll

Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[IL]: Error: [c:\Users\Mehrdad\Scratch\sc.dll : A`1[T]::F][offset 0x00000002][fo
und (unboxed) 'T'] Non-compatible types on the stack.
1 Error(s) Verifying sc.dll

Mise à JOUR (Réponse aux commentaires): Comme je l'ai mentionné ci-dessus, la vérifiabilité n'est pas équivalent à la justesse (ici je parle de "correct" à partir d'un type de sécurité de point de vue). Vérifiable programmes sont un sous-ensemble strict de corriger des programmes (c'est à dire tous vérifiables programmes sont incontestablement correct, mais il y a des programmes corrects qui ne sont pas vérifiables). Ainsi, la vérifiabilité est un renforcement de la propriété que de justesse. Depuis le C# est un Turing-complet de la langue, de Riz du théorème stipule que prouver que les programmes sont correctes est indécidable dans le cas général.

Revenons-en à mon connectivité de l' analogie, car il est plus facile à expliquer. Supposons que vous ont été la conception de C#. Une chose avoir pensé, c'est lors de l'émission d'un avertissement au sujet de code inaccessible, et pour enlever ce morceau de code tout à fait dans l'optimiseur, mais comment vous allez détecter tous les code inaccessible? De nouveau, le Riz est le théorème dit que vous ne pouvez pas le faire pour tous les programmes. Par exemple:

void Method() {
    while (true) {
    }
    DoSomething();  // unreachable code
}

C'est quelque chose que le compilateur C# prévient effectivement. Mais il n'est pas de les avertir:

bool Condition() {
   return true;
}

void Method() {
   while (Condition()) {
   }
   DoSomething();  // no longer considered unreachable by the C# compiler
}

Un homme peut prouver que le contrôle de flux n'atteint jamais cette ligne dans le dernier cas. On pourrait dire que le compilateur pourrait statiquement prouver DoSomething est inaccessible dans ce cas aussi, mais il ne le fait pas. Pourquoi? Le point est que vous ne pouvez pas le faire pour tous les programmes, de sorte que vous devrait tracer la ligne à un certain point. À ce stade, vous devez définir un decidable de la propriété et de l'appeler "l'accessibilité". Par exemple, pour l'accessibilité, C# bâtons à des expressions constantes et de ne pas regarder le contenu des fonctions à tous. La simplicité de l'analyse et de la cohérence de la conception sont des objectifs importants pour décider de l'endroit où tracer la ligne.

Pour en revenir à notre vérifiabilité concept, c'est un problème similaire. La vérifiabilité, contrairement à l'exactitude, est un decidable de la propriété. Comme le moteur d'exécution de concepteur, vous devez décider comment définir la vérifiabilité, basée sur des considérations de performance, facile de mise en œuvre, la facilité de spécifications, la consistance, le rendant facile pour le compilateur de manière à générer vérifiables code. Comme la plupart des décisions de conception, il implique beaucoup de compromis. En fin de compte, la CLI concepteurs ont décidé qu'ils préfèrent ne pas trop regarder contraintes génériques à tous lors de la vérification de la vérifiabilité.

16voto

Eric Lippert Points 300275

Mehrdad la réponse est assez bonne; je voulais juste ajouter quelques points:

Tout d'abord, oui, dans ce cas, c'est juste pour garder le vérificateur heureux. La gigue doit bien sûr d'optimiser loin de la boxe de l'instruction, car il n'est pas utile de cocher le type d'une référence.

Cependant, il ya des cas où le garder le vérificateur heureux, nous devons introduire la boxe des instructions qui ne sont pas optimisés loin. Par exemple, si vous dites:

class B<T> { public virtual void M<U>(U u) where U : T {...} }
class D : B<int> 
{ 
    public override void M<U>(U u)
    {

Le compilateur C# sait que, dans D. M, U ne peut être de type int. Néanmoins, afin d'être vérifiable, il y a des situations où u doit être mis en boîte à l'objet, et puis "unboxed" int. La gigue n'est pas toujours d'optimiser ces; nous l'avons souligné à la gigue de l'équipe que c'est une optimisation possible, mais la situation est tellement obscur qu'il est peu probable de causer un gain important pour de nombreux clients réels. Il y a plus grand-bang-pour-buck optimisations qu'ils pourraient passer leur temps sur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X