Pourquoi la valeur de typeof null change-t-elle dans une boucle?

109

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 imprimera falsepour un certain nombre d'itérations, puis truepour le reste.

entrez la description de l'image ici

Pourquoi cela arrive-t-il? Est-ce juste un bug?

Agos
la source
4
Il revient 1000 fois vrai pour moi ...
Hoàng Long
2
Je pense que c'est un bug, j'ai 262 faux / 738 vrai
Jax Teller
1
c'est quelque chose de bizarre avec la console de chrome: si vous poussez vers un tableau et enregistrez le tableau, c'est tout false. tel quel, le nombre de trues fluctue en chrome.
dandavis
1
@ HoàngLong comme je l'ai dit dans la question, cela n'arrive que sur certaines machines. Il est également possible que cela se produit uniquement sur certaines versions de Chrome
Agos
2
@ HoàngLong assurez-vous de l'exécuter dans Chrome
Nobita

Réponses:

37

C'est en fait un bogue du moteur JavaScript V8 ( Wiki ).

Ce moteur est utilisé dans Chromium, Maxthron, Android OS, Node.js etc.

Description de bogue relativement simple que vous pouvez trouver dans cette rubrique Reddit :

Les moteurs JavaScript modernes compilent le code JS en code machine optimisé lorsqu'il est exécuté (compilation Just In Time) pour le rendre plus rapide. Cependant, l'étape d'optimisation a un certain coût de performance initial en échange d'une accélération à long terme, de sorte que le moteur décide 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é, tandis que le chemin non optimisé fonctionne correctement. Donc, au début, la méthode fonctionne comme prévu, mais si elle est appelée dans une boucle assez souvent à un moment donné, le moteur décidera de l'optimiser et de la remplacer par la version boguée.

Ce bogue semble avoir été corrigé dans V8 lui-même ( commit ), ainsi que dans Chromium ( rapport de bogue ) et NodeJS ( commit ).

Sergey Novikov
la source
J'ai confirmé que le bogue est toujours dans Node.js 6.2.2 ce qui m'inquiète.
Michael Shopsdu
Il a été corrigé dans le moteur V8 aujourd'hui (21.06), je crois que les logiciels associés seront bientôt mis à jour.
Sergey Novikov
Le rétroportage du correctif v8 vers Node.js 6.2.x est déjà en cours en tant que numéro 7348 appartenant à TheAlphaNerd .
Michael Shopsdu
18

Pour répondre à la question directe de savoir pourquoi il 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 est écrit, mais plus vous l'exécutez, plus il y a de chances que les avantages de l'optimisation l'emportent sur les coûts d'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 fait une hypothèse incorrecte et la version optimisée ne produit pas réellement le résultat correct.

Plus précisément, l' utilisateur de Reddit RainHappens suggère qu'il s'agit d'une erreur de propagation de type :

Il effectue également une certaine propagation de type (comme dans quels types une variable, etc. peut être). Il existe un type spécial "indétectable" lorsqu'une variable est indéfinie ou nulle. Dans ce cas, l'optimiseur indique "null est indétectable, il peut donc être remplacé par la chaîne" non définie "pour la comparaison.

C'est l'un des problèmes difficiles avec l'optimisation du code: comment garantir que le code qui a été réorganisé pour les performances aura toujours le même effet que l'original.

IMSoP
la source