web-dev-qa-db-ja.com

typeof nullの値がループ内で変化するのはなぜですか?

Chromeコンソールでこのスニペットを実行する:

function foo() {
    return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());

1000回falseを印刷する必要がありますが、一部のマシンでは、多数の反復でfalseを印刷し、残りの場合はtrueを印刷します。

enter image description here

なぜこうなった?単なるバグですか?

109
Agos

これには、クロムのバグがあります。

問題604033-メソッドの動作を保持しないJITコンパイラー

はい、それは単なるバグです!

74
Slumber86

実際には V8 JavaScriptエンジン( Wiki )バグです。

このエンジンはChromium、Maxthron、Android OS、Node.jsなどで使用されます。

比較的単純 バグの説明 この中にあります Redditトピック

最新のJavaScriptエンジンは、実行時にJSコ​​ードを最適化されたマシンコードにコンパイルし(Just In Timeコンパイル)、より高速に実行します。ただし、最適化ステップでは、長期的な高速化と引き換えに初期パフォーマンスコストが発生するため、エンジンは、使用頻度に応じてメソッドが価値があるかどうかを動的に決定します。

この場合、最適化されたパスにのみバグがあるように見えますが、最適化されていないパスは正常に機能します。そのため、最初はメソッドは意図したとおりに機能しますが、ある時点でループ内で頻繁に呼び出されると、エンジンは最適化を決定し、バグのあるバージョンに置き換えます。

このバグはV8自体( commit )、およびChromium( bug report )およびNodeJS( commit )で修正されているようです。

37
Sergey Novikov

なぜ変更されるのかという直接的な質問に答えるために、バグはChromeで使用されるV8 JSエンジンの「JIT」最適化ルーチンにあります。最初は、記述されたとおりにコードが実行されますが、実行するほど、最適化の利点が分析のコストを上回る可能性が高くなります。

この場合、ループ内で繰り返し実行された後、JITコンパイラーは関数を分析し、最適化されたバージョンに置き換えます。残念ながら、分析では誤った仮定が行われ、最適化されたバージョンでは実際には正しい結果が得られません。

具体的には、 RedditユーザーRainHappensが示唆している型伝播のエラーであること

また、いくつかの型の伝播も行います(変数などがどの型になる可能性があるかなど)。変数が未定義またはnullの場合には、特別な「検出不能」タイプがあります。この場合、オプティマイザーは「nullは検出できないため、比較のために「undefined」文字列に置き換えることができます。

これは、コードの最適化に関する困難な問題の1つです。パフォーマンスのために再配置されたコードが元のコードと同じ効果を持つことを保証する方法。

18
IMSoP
1
user835611