6

我一直很好奇为什么 JVM 和 CLR 有一个基于堆栈的架构?他们为什么不使用基于寄存器的方法?与基于寄存器的方法相比,它有什么好处?

4

2 回答 2

9

我曾经思考寄存器和堆栈机器之间的差异并比较指令序列,并运行基准测试......

然后我花了几年时间在 Parrot VM 上工作,同时实现了这两种类型的机器,它是一台注册机器。我们天真地从一个固定的寄存器集开始,结合数据和寄存器堆栈,但最终得出结论,这是人为的限制,所以我们改为无限寄存器集和分配器。在某些时候,Parrot 快速核心(GCC 计算 goto)优于 Mono 和 JVM 解释器核心(非 JIT),但差异归结于 JIT。Parrot 的 JIT 从未与其他人的质量相提并论。JITter 的质量造就了最终的机器,而这通常是人们关心的。如果所有虚拟机都按照相同的规则运行(即它们有一个限制,可以在没有 JIT 的解释模式下运行),然后我的证据表明寄存器机器在等效堆栈机器上具有性能优势。更大的指令,但更少的指令 == 更高的吞吐量 (IPC),以及更好的缓存引用局部性。Dalvik JVM 实际上支持了我的发现,Dalvik 有几年没有 JIT,并与它的解释器核心竞争。

很少有主流虚拟机专门以解释模式运行(AFAIK),它们是 JIT 编译的,这就是我们的基准测试。解释器核心的重点是在平台上建立存在,进行字节码验证,并在没有 JIT 的情况下提供故障安全执行核心。当然,这不是规则。有数十亿台设备在没有 JIT 的情况下运行 ARM 加速 JVM,但在没有内存或 CPU 限制的情况下,这适用。

我不断地调整核心、测试和调优,最终发现我们真的想要一个快速的 JIT。我得出的结论是,如果您最终要使用 JIT,那么无论您是实现堆栈还是注册机器来启动,做自己喜欢的事情都无关紧要;但是使用堆栈机器可以更快地“推向市场”。通过虚拟机内核对字节码解释进行大量伪寄存器机虚拟优化部分是浪费努力,因为它不是真正的本机优化。软核不像真正的处理器那样进行分支预测、寄存器重命名、指令重新排序、并行执行或预取。我的感觉是,一旦我们对本地二进制文件进行了高质量的 JIT,我们就会到达同一个目的地。

出于这些原因,我在技术上支持基于堆栈的机器:

  1. 简单 - 更少的代码需要维护 = 更少的错误
  2. 实施时间

但在视觉上和情感上,我更喜欢注册机:

  1. 视觉概念模型更接近机器和我的大脑
  2. 灵活性——编译器可以使用 SSA 以不同的顺序评估他们的表达式树。

请注意,我并没有说编译器可以更“轻松”地生成代码。这似乎是主要使用堆栈机器的人喜欢争论的问题。我不相信,也没有发现这是真的。我在 Parrot 和 CLR 上看到了很多爱好编译器,虽然我承认 CLR 上的编译器质量更高,但这主要是生态系统和可用工具的质量之一。我自己在这两个平台上编写了编译器,发现有一些权衡,但还不足以让我失眠。

这是一个有根据的猜测,因为我的实际经验不包括编写完整的 JITter,所以我没有第一手经验来比较 JITting 各种形式的操作码的优缺点,但我的意见是,如果你打算包括一个 JIT,然后创建一个极其复杂的虚拟机操作码核心相当于过早优化。你的时间最好花在别处。

于 2014-06-19T04:44:21.557 回答
3

通常只链接到一篇文章是不合适的,但这次我会例外:Eric Lippert 的这篇文章回答了这个问题。

于 2012-10-28T22:50:29.220 回答