为什么 typeof null 的值会在循环内发生变化?
Why does the value of typeof null change inside a loop?
在 Chrome 控制台中执行此代码段:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
应该打印 1000 次 false
,但在某些机器上会打印 false
多次迭代,然后 true
打印其余部分。
为什么会这样?这只是一个错误吗?
有一个 chrome 漏洞为此打开:
Issue 604033 - JIT compiler not preserving method behavior
是的,这只是一个错误!
这实际上是一个 V8 JavaScript engine (Wiki) 错误。
Chromium、Maxthron、Android、OS、Node.js等都使用了该引擎
比较简单bug description you can find in this Reddit topic:
Modern JavaScript engines compile JS code into optimized machine code
when it is executed (Just In Time compilation) to make it run faster.
However, the optimization step has some initial performance cost in
exchange for a long term speedup, so the engine dynamically decides
whether a method is worth it depending on how commonly it is used.
In this case there appears to be a bug only in the optimized path,
while the unoptimized path works fine. So at first the method works as
intended, but if it's called in a loop often enough at some point the
engine will decide to optimize it and replaces it with the buggy
version.
此错误似乎已在 V8 本身中修复 (commit), aswell as in Chromium (bug report) and NodeJS (commit)。
要直接回答为什么会改变的问题,这个错误在 Chrome 使用的 V8 JS 引擎的 "JIT" 优化例程中。一开始,代码 运行 和写的一模一样,但你 运行 越多,优化的好处就越有可能超过分析的成本。
在这种情况下,在循环中重复执行后,JIT 编译器会分析该函数,并将其替换为优化版本。不幸的是,分析做出了错误的假设,优化后的版本实际上并没有产生正确的结果。
具体来说,Reddit user RainHappens suggests这是类型传播中的一个错误:
It also does some type propagation (as in what types a variable etc can be). There's a special "undetectable" type for when a variable is undefined or null. In this case the optimizer goes "null is undetectable, so it can be replaced with the "undefined" string for the comparison.
这是优化代码的难点之一:如何保证经过性能重排后的代码仍然具有与原始代码相同的效果。
这是两个月前修复的,很快就会在 Chrome 中登陆(已经在 Canary 中)。
V8 Issue 1912553002 - Fix 'typeof null' canonicalization in crankshaft
Chromium Issue 604033 - JIT compiler not preserving method behavior
在 Chrome 控制台中执行此代码段:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
应该打印 1000 次 false
,但在某些机器上会打印 false
多次迭代,然后 true
打印其余部分。
为什么会这样?这只是一个错误吗?
有一个 chrome 漏洞为此打开:
Issue 604033 - JIT compiler not preserving method behavior
是的,这只是一个错误!
这实际上是一个 V8 JavaScript engine (Wiki) 错误。
Chromium、Maxthron、Android、OS、Node.js等都使用了该引擎
比较简单bug description you can find in this Reddit topic:
Modern JavaScript engines compile JS code into optimized machine code when it is executed (Just In Time compilation) to make it run faster. However, the optimization step has some initial performance cost in exchange for a long term speedup, so the engine dynamically decides whether a method is worth it depending on how commonly it is used.
In this case there appears to be a bug only in the optimized path, while the unoptimized path works fine. So at first the method works as intended, but if it's called in a loop often enough at some point the engine will decide to optimize it and replaces it with the buggy version.
此错误似乎已在 V8 本身中修复 (commit), aswell as in Chromium (bug report) and NodeJS (commit)。
要直接回答为什么会改变的问题,这个错误在 Chrome 使用的 V8 JS 引擎的 "JIT" 优化例程中。一开始,代码 运行 和写的一模一样,但你 运行 越多,优化的好处就越有可能超过分析的成本。
在这种情况下,在循环中重复执行后,JIT 编译器会分析该函数,并将其替换为优化版本。不幸的是,分析做出了错误的假设,优化后的版本实际上并没有产生正确的结果。
具体来说,Reddit user RainHappens suggests这是类型传播中的一个错误:
It also does some type propagation (as in what types a variable etc can be). There's a special "undetectable" type for when a variable is undefined or null. In this case the optimizer goes "null is undetectable, so it can be replaced with the "undefined" string for the comparison.
这是优化代码的难点之一:如何保证经过性能重排后的代码仍然具有与原始代码相同的效果。
这是两个月前修复的,很快就会在 Chrome 中登陆(已经在 Canary 中)。
V8 Issue 1912553002 - Fix 'typeof null' canonicalization in crankshaft
Chromium Issue 604033 - JIT compiler not preserving method behavior