寄存器对堆栈

与使用基于堆栈的虚拟机相比,使用基于寄存器的虚拟机到底有哪些优点和缺点?

在我看来,似乎基于寄存器的机器编程更直接,效率更高。那么为什么 JVM、 CLR 和 Python VM 都是基于堆栈的呢?

33762 次浏览

你需要多少个寄存器?

我可能至少还需要一个。

在硬件实现中,基于寄存器的机器会更有效率,因为对较慢的 RAM 的访问较少。然而,在软件中,即使是基于寄存器的架构也很可能在 RAM 中有“寄存器”。在这种情况下,基于堆栈的机器将同样有效。

此外,基于堆栈的 VM 将使编写编译器变得更加容易。您不必处理寄存器分配策略。实际上,您可以使用无限数量的寄存器。

更新: 我在假设解释 VM 的情况下写了这个答案。对于 JIT 编译的 VM,这可能不成立。我遇到过 这张纸,它似乎表明 JIT 编译的 VM 使用寄存器架构可能更有效率。

构建基于堆栈的 VM 的一个原因是,实际的 VM 操作码可以更小更简单(不需要编码/解码操作数)。这使得生成的代码更小,也使得 VM 代码更简单。

基于堆栈的 VM 更容易生成代码。

基于寄存器的 VM 更容易为其创建快速实现,也更容易为其生成高度优化的代码。

对于您的第一次尝试,我建议从基于堆栈的 VM 开始。

对我来说,“基于寄存器的”虚拟机是“更直接的编程”还是“更有效率”并不明显。也许您认为虚拟寄存器将在 JIT 编译阶段提供一种捷径?这种情况当然不会发生,因为真正的处理器可能比 VM 拥有更多或更少的寄存器,并且这些寄存器可以以不同的方式使用。(例如: 要递减的值最好放在 x86处理器上的 ECX 寄存器中。)如果真正的机器比虚拟机有更多的寄存器,那么你就是在浪费资源,使用“基于寄存器”的编程会使你一无所获。

在某种程度上,Parrot VM 的 FAQ 和相关文档已经回答了这个问题: 鹦鹉综述 该文件的相关内容如下:

Parrot VM 将有一个寄存器架构,而不是堆栈架构。它还将具有非常低级的操作,与中级的 Perl 和 Python 等操作相比,它更类似于 Java 的操作。

这个决定的理由主要是,通过在某种程度上类似于底层硬件,可以将 Parrot 字节码编译成高效的本地机器语言。

此外,许多高级语言中的程序由嵌套函数和方法调用组成,有时使用词法变量来保存中间结果。在非 JIT 设置下,基于堆栈的虚拟机将弹出并多次推送相同的操作数,而基于寄存器的虚拟机将简单地分配适量的寄存器并对其进行操作,这可以大大减少操作量和 CPU 时间。

你可能也想阅读这篇文章: 注册器与解释器设计的堆栈 引用一下:

毫无疑问,为堆栈机器生成代码更容易。大多数大一的编译专业学生都能做到这一点。为寄存器机器生成代码有点困难,除非您将其视为带有累加器的堆栈机器。(这是可行的,尽管从性能的角度来看有些不理想)目标的简单性并不是什么大问题,至少对我来说不是,部分原因是很少有人真正直接瞄准它——我的意思是,拜托,你知道有多少人真正尝试编写一个任何人都会关心的编译器吗?人数很少。另一个问题是,许多具有编译器知识的人已经习惯于瞄准寄存器机器,因为所有常用的硬件 CPU 都是寄存器机器。

基于堆栈的虚拟机更简单,代码更紧凑。作为一个现实世界的例子,一个朋友(大约30年前)在 Cosmac 上用自制的 Forth VM 构建了一个数据记录系统。ForthVM 是机器上的30字节代码,2k ROM 和256字节 RAM。

传统上,虚拟机实现者更喜欢基于堆栈的架构,而不是基于寄存器的架构,因为“简单的 VM 实现”编写编译器后端很容易——大多数虚拟机最初设计为托管单一语言,堆栈架构的代码密度和可执行文件总是小于寄存器架构的可执行文件。简单性和代码密度是性能的代价。

研究表明,基于注册的体系结构比基于堆栈的体系结构平均少执行47% 的 VM 指令,注册代码比相应的堆栈代码大25% ,但是由于代码大小增加了获取更多 VM 指令的成本,每条 VM 指令只需要额外的1.07% 的实际机器负载,这是可以忽略不计的。基于寄存器的 VM 的总体性能是,执行标准基准测试所需的平均时间减少了32.3% 。