Comment le type est-il vérifié dans un interpréteur / compilateur de langage dynamique, tel que JavaScript?

11

Dans les langages dynamiques, tels que JavaScript ou Python, le type d'une variable est déterminé lors de l'exécution. C'est une des raisons pour lesquelles ils sont plus lents que les langages typés tels que Java.

Comment s'effectue la vérification de type? Quelle est la raison essentielle pour laquelle ce processus est lent?


la source
Ils ne sont pas plus lents car ils sont dynamiques, ils sont plus lents car il est plus difficile de les rendre plus rapides. JavaScript est en fait le plus optimisé et est assez rapide.
Derek Litz

Réponses:

5

Il y a de la confusion dans la question.

On suppose que la vérification de type est lente, ce qui n'est pas nécessairement le cas.

La question semble également confondre le processus d' envoi de type avec la vérification de type , et ce sont deux choses différentes. L'un est un processus qui se fait au moment de l'exécution, l'autre un processus au moment de la compilation. Je soupçonne que la question pose vraiment sur la répartition des types.

C'est la répartition de type qui peut introduire une surcharge lors de l'exécution, car le calcul passe du temps avec des instructions qui décident, dynamiquement, de l'action à entreprendre, en fonction des types de valeurs qu'il voit au moment de l'exécution. Par exemple, dans un langage dynamique, si j'applique "+" sur deux choses, je pourrais signifier l'addition numérique ou la concaténation de chaînes, donc je dois passer du temps à regarder ce qui est à portée de main pour décider quoi faire. Il existe des stratégies d'évaluation qui peuvent réduire le coût de la répartition dynamique. (par exemple, traçage des JIT)

En ce qui concerne la vérification de type en JavaScript, voir: http://www.cs.brown.edu/~sk/Publications/Papers/Published/gsk-flow-typing-theory/ . Pour un aperçu plus général du fonctionnement des vérificateurs de type, un manuel de langage de programmation standard couvrira les algorithmes. Par exemple, http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/

dyoo
la source
J'ai également écrit une petite enquête sur le traçage des JIT et des langages dynamiques dans hashcollision.org/comprehensive/tracing.pdf
L'interpréteur Javascript porte des bits de balise avec chaque valeur pour la répartition de type. Pourriez-vous nous en dire un peu plus à ce sujet? Par exemple, à quoi servent les bits de balise? Un bit correspond-il à un type?
Le concept de type n'est pas toujours lié à la représentation. Nous pourrions avoir un concept de type «mile» par rapport à un type «kilomètre», par exemple, et il est raisonnable d'avoir un langage qui peut détecter statiquement, au moment de la compilation, si les calculs appliquent incorrectement des opérations sur des valeurs qui gâchent les types . Vous pourriez imaginer qu'ils auraient la même représentation, et si le compilateur peut, au moment de la compilation, garantir qu'ils ne sont jamais mélangés, alors il n'y a aucune raison pour que les valeurs nécessitent l'étiquetage supplémentaire dans la représentation.
1
Continue: mais souvent, en particulier dans les langages dynamiques, vous souhaitez représenter des valeurs de différents types. Il existe plusieurs façons de faire cette discrimination. Les balises de type sont courantes, mais il existe d'autres techniques. Par exemple, vous pouvez placer certains types dans des régions de mémoire bloquées. Voir «Représentation des informations de type dans des langages typés dynamiquement». lambda-the-ultimate.org/node/3912 pour une étude complète des techniques de représentation.
7

Fondamentalement, dans les langages non typés, chaque référence pointe vers un objet qui contient à la fois le type et la valeur. Par exemple var a = 3pointe vers une instance qui contient la valeur 3 et le type int, si vous faites a = "bla", la référence est mise à jour vers une instance qui contient la chaîne "bla" et la chaîne de type, l'ancien objet est supprimé, etc ...

Ceci est lent car chaque fois qu'une opération (par exemple a + b) doit être effectuée sur ces types de base, le runtime doit d'abord déréférencer les objets, vérifier que leur type est compatible, effectuer l'opération, créer un nouvel objet.

En revanche, a + ben C ++ ou Java vérifie au moment de la compilation que les types sont valides et compatibles, puis a et b sont stockés en tant que valeurs immédiates (pas de références), et l'addition est une opération de processeur simple sur ces valeurs.

Bien sûr, tout cela est très théorique. En pratique, beaucoup d'optimisation peut être effectuée sur ce processus pour éviter la plupart des frais généraux, et les langages typés dynamiquement peuvent devenir assez rapides.

solendil
la source
1
Des astuces comme les caches polymorphes en ligne peuvent améliorer considérablement les performances. Les écrits de David Ungar (Self) et d'Eliot Miranda (Squeak, Visual Works Smalltalk virtual machines) sont les plus informatifs en ce qui concerne les performances du langage dynamique.
Frank Shearar
0

Chaque valeur est stockée avec son type, que l'on doit d'abord inspecter. Les conversions indiquent également que la chaîne de caractères passe par l'inspection, à la volée.

Joop Eggen
la source
Oui, c'est ça, c'est juste une vérification de l'exécution, rien d'extraordinaire.
Anon