优化/功能 运行 上的 v8 状态代码会发生什么变化?

What happens to v8 status code on optimization / function run?

我看到了一个关于 的问题,这让我尝试了一下 v8 优化。 我还看到了关于 v8 Optimization killers.

的蓝鸟 post

根据 v8 repo,优化状态代码是 2 的乘积: 1,2,4 ,8 等等(参见 OptimizationStatus 枚举)

然而,下面的代码给了我奇怪的状态代码,比如 17 和 65,而且只在这些特定情况下(见最后几行代码)。 关于为什么会发生这种情况的任何想法?

function adder(a, b) {
    return new Function('a', 'b', 'return b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b')(a, b);
}
function addereval(a, b) {
    return eval('b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b');
}

function printStatus(fn) {
    var status = %GetOptimizationStatus(fn)
    switch (status) {
        case 1: console.log(fn.name, "function is optimized"); break;
        case 2: console.log(fn.name, "function is not optimized"); break;
        case 3: console.log(fn.name, "function is always optimized"); break;
        case 4: console.log(fn.name, "function is never optimized"); break;
        case 6: console.log(fn.name, "function is maybe deoptimized"); break;
        case 7: console.log(fn.name,"Function is optimized by TurboFan"); break;
        default: console.log(fn.name, "Unknown optimization status: ", status); break;
    }
}
printStatus(adder);
printStatus(addereval);


for(let i = 0; i < 263; i++) {
    adder(1, 2);
}
console.log('\n', '==== adder after invocation - result is on node v8.2.1 17 or 65 on node v8.7.0 ===');
printStatus(adder);

addereval(1, 2);
console.log('\n', '==== addereval after invocation - result is 65 ===');
printStatus(addereval);

运行 此代码为:

node --trace_deopt --allow-natives-syntax FILENAME.js

如果觉得舒服可以用my gist

status 是一个 bitwise 标志值,代码应该看起来更像这样:

var status = GetOptimizationStatus(fn);
if ((status & (1 << 0)) {
  console.log(fn.name, "kIsFunction");
}
if ((status & (1 << 1)) {
  console.log(fn.name, "kNeverOptimize");
}
// etc .. can be 'true' for several different combinations;
// most notably, many different status will also include 'kIsFunction'

考虑 17 的 "status code" ~或~ 16 + 1 ~或~ (1 << 4) | (1 << 0) ~这意味着~ "kIsFunction" "kIsOptimized".

请参阅 bit arrays 进行一般操作 - 以及为什么在代码中显示的条件下使用 &

%GetOptimizationStatus 已更新为 return 一组按位标志而不是单个值,文章 Optimization Killers 已过时。可用状态信息也略有更改。

要访问新值,您需要采用 returned 值的二进制表示。现在,例如,如果 65 被 returned,则二进制表示如下:

65₁₀ = 000001000001₂

每个二进制数字作为布尔值,含义如下:

0 0 0 0 0 1 0 0 0 0 0 1
┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │ │ │ │ │ │ └─╸ is function
│ │ │ │ │ │ │ │ │ │ └───╸ is never optimized
│ │ │ │ │ │ │ │ │ └─────╸ is always optimized
│ │ │ │ │ │ │ │ └───────╸ is maybe deoptimized
│ │ │ │ │ │ │ └─────────╸ is optimized
│ │ │ │ │ │ └───────────╸ is optimized by TurboFan
│ │ │ │ │ └─────────────╸ is interpreted
│ │ │ │ └───────────────╸ is marked for optimization
│ │ │ └─────────────────╸ is marked for concurrent optimization
│ │ └───────────────────╸ is optimizing concurrently
│ └─────────────────────╸ is executing
└───────────────────────╸ topmost frame is turbo fanned

因此,65表示该函数是一个函数并被解释(这意味着它在查询其状态时优化)。

要访问 JavaScript 中的这些值,只需使用按位与运算符并查看值是否非零:

var status = %GetOptimizationStatus(fn);

if (status & 1) console.log("function is function");
if (status & 2) console.log("function is never optimized");
if (status & 4) console.log("function is always optimized");
if (status & 8) console.log("function is maybe deoptimized");
if (status & 16) console.log("function is optimized");
if (status & 32) console.log("function is optimized by TurboFan");
if (status & 64) console.log("function is interpreted");
...

等等。这里的关键方面是不止一个这些条件可以评估为真。