代码之家  ›  专栏  ›  技术社区  ›  Logan McNichols

有没有一个内置程序可以处理V8 Ignition的字节码指令的完整序列?

  •  0
  • Logan McNichols  · 技术社区  · 2 年前

    V8的点火开关是如何执行我的代码的,这让我很困惑。根据我在网上读到的所有内容,点火创建字节码,然后由Turbofan创建的汇编存根处理各个字节码指令。所以我希望看到一些Ignition调用这些存根函数的循环。但似乎所有内容都是在单个程序块中计算的,代码在此处输入: 中的src/execution/execution.cc Invoke

          value = Tagged<Object>(
              stub_entry.Call(isolate->isolate_data()->isolate_root(), orig_func,
                              func, recv, JSParameterCount(params.argc), argv));
    

    这调用了一个函数指针,我认为它指向了一些预编译的二进制文件,因为我无法进入它。这似乎可以处理下面更复杂的脚本的整个执行过程。

    我也试过在Ignition生成字节码数组后对其进行调整。这在汇编黑匣子中的某个地方引发了一个错误。所以字节码指令的处理似乎都是在一个内置程序中处理的?

    如果有人能帮助澄清点火的工作原理,我将不胜感激!

    我正在运行带有D8外壳的V8。我使用的是V8 12.1版本,并编译为out/x64调试。无论是简单的测试脚本,我上面描述的行为都是一样的:

    const x = 2;
    console.log(x);
    

    或者一个稍微复杂一点的脚本:

    const x = [1,2,3];
    const y = [4,5,6];
    const z = [];
    for (let i=0; i<x.length; i++) {
      z.push(x[i] + y[i]);
    }
    console.log(z[0], z[1], z[2]);
    
    0 回复  |  直到 2 年前
        1
  •  1
  •   jmrk    2 年前

    (此处为V8开发人员。)

    点火创建字节码,然后单独的字节码指令由Turbofan创建的汇编存根处理。

    对值得注意的是,这些“汇编存根”(我们称之为“字节码处理程序”)是在V8构建时生成的(由 mksnapshot 二进制)并编译成最终的V8二进制。你 可以 在它们内部中断,但要弄清楚断点放在哪里有点麻烦,您将得到的只是一个汇编视图。如果您愿意重新编译V8,一种更简单的方法是添加 DebugBreak(); 到您感兴趣的处理程序,该处理程序会发出 int3 你当然可以 只有 在调试器中运行该二进制文件,因为未调试的执行将在该点以陷阱终止;你仍然只能得到一个装配视图。

    我希望看到Ignition调用这些存根函数的一些循环

    Ignition是一个“间接线程”解释器:每个字节码处理程序以 the instruction sequence 它加载下一个字节码并跳转到相应的处理程序。
    这种设计背后的思想是,指令序列可能不是随机的:例如,字节码A后面可能有很大的机会跟着字节码B。间接线程设计使CPU的分支预测器很容易了解这种情况,因为(在本例中)A结尾的间接跳动(几乎)总是跳到B,而其他处理程序结尾的间接跳跃可以学习自己最可能的跳跃目标。
    理论上,现代CPU也可以合理地处理更直观的交换机上的环路解释器设计(这要归功于在其分支预测中考虑了大量的历史),但这肯定会使CPU的寿命更加困难,即可能会有更多的调度开销 至少 在较弱的CPU设计上,甚至可能无处不在。

    有没有一个内置程序可以处理V8 Ignition的字节码指令的完整序列?

    没有(见上文),但也没有一个大的C++循环:字节码处理程序正在相互尾部调用。

    有关更多背景信息,请参阅 v8.dev .