Exécution de cet extrait dans la console Chrome:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
devrait imprimer 1000 fois false
, mais sur certaines machines, false
sera imprimé plusieurs fois, puis true
pour le reste.
Pourquoi cela arrive-t-il? Est-ce juste un bug?
Il y a un bug de chrome ouvert pour cela:
Problème 604033 - Le compilateur JIT ne conserve pas le comportement de la méthode
Alors oui, c'est juste un bug!
C’est en fait un bug V8 du moteur JavaScript ( Wiki ).
Ce moteur est utilisé dans Chrome, Maxthron, Android OS, Node.js etc.
Relativement simple description du bogue vous pouvez trouver dans ce sujet Reddit :
Les moteurs JavaScript modernes compilent le code JS en un code machine optimisé lors de son exécution (compilation Just In Time) pour accélérer son exécution. Cependant, l’optimisation a un coût de performance initial en contrepartie d’une accélération à long terme. Le moteur décide donc dynamiquement si une méthode en vaut la peine, en fonction de la fréquence à laquelle elle est utilisée.
Dans ce cas, il semble y avoir un bogue uniquement dans le chemin optimisé, alors que le chemin non optimisé fonctionne correctement. Ainsi, au début, la méthode fonctionne comme prévu, mais si elle est appelée dans une boucle assez souvent, le moteur décide de l'optimiser et de la remplacer par la version buggy.
Ce bogue semble avoir été corrigé dans la V8 ( commit ), ainsi que dans Chromium ( rapport de bogue ) et NodeJS ( commit ).
Pour répondre à la question directe de savoir pourquoi cela change, le bogue se trouve dans la routine d'optimisation "JIT" du moteur V8 JS utilisé par Chrome. Au début, le code est exécuté exactement comme il a été écrit, mais plus vous l'exécutez, plus les avantages de l'optimisation l'emportent sur les coûts de l'analyse.
Dans ce cas, après une exécution répétée dans la boucle, le compilateur JIT analyse la fonction et la remplace par une version optimisée. Malheureusement, l'analyse émet une hypothèse incorrecte et la version optimisée ne produit pas le résultat correct.
Plus précisément, RainHappens suggère par Reddit qu'il s'agit d'une erreur dans la propagation du type :
Il effectue également une propagation de type (comme dans quels types une variable, etc., peut être). Il existe un type spécial "indétectable" pour les variables indéfinies ou nulles. Dans ce cas, l'optimiseur indique que "null est indétectable, il peut donc être remplacé par la chaîne" indéfinie "pour la comparaison.
C’est l’un des problèmes majeurs de l’optimisation du code: comment garantir que le code qui a été réorganisé pour obtenir des performances aura toujours le même effet que le code original.
Cela a été corrigé il y a deux mois et arrivera dans Chrome bientôt (déjà dans Canary).
V8 Issue 1912553002 - Correction de la canonisation de 'typeof null' dans le vilebrequin
Numéro de chrome 604033 - Le compilateur JIT ne conserve pas le comportement de la méthode