为什么基于堆栈的 VM?为什么不基于队列的虚拟机?
Why stack-based VM? Why not queue-based VM?
根据我的调查,有两种主要的方法来实现进程 VM:
- 基于堆栈,例如 JVM、CLR 等
- 或者基于寄存器的,比如Lua、Dalvik等
基于寄存器的方法模仿了物理处理器的体系结构。
但是对于基于栈的方法,还有很多其他的数据结构。
我认为选择哪种方式主要取决于我们要如何store/fetch操作数。那么为什么选择栈呢?基于队列的虚拟机怎么样?或其他选项,如链表?
Whosebug 真的不适合基于意见的调查;很有可能关门了。
但是,重要的是要认识到特定于处理器的体系结构通常使用寄存器,因为这与处理器的工作方式相对应。每个指令集都有一组固定的可用寄存器,不同的架构会有不同的数量。此外,某些寄存器根据平台或 ABI 具有特定含义。
通用程序集文件很难在平台之间移植;或者,如果可以的话,您最终会得到尽可能少的结果,因此会错过可能适用于更广泛指令的优化。 64 位处理器的优势之一与其说是额外的宽度,不如说是增加了 ISA 中可用的寄存器数量。
有两种方法可以解决这个问题;假设一个无限寄存器集,然后在为特定体系结构翻译时提供寄存器映射(例如,LLVM 在其 ISA 中使用一个无限寄存器集,然后映射到真实 ISA 上的特定寄存器)或使用堆栈。使用堆栈的一个优点是,当您 运行 out 时,您不需要处理溢出寄存器的特定情况(例如,您有一个函数,您希望有 10 个寄存器,但您的 ISA 只有有 5).堆栈非常擅长表示无限条目(当然是对可用内存量取模。)
就是说,(真实的)堆栈速度较慢 - 实际上您在使用它时忽略了真实的寄存器。所以通常寄存器用于速度,而堆栈用于寄存器中不适合的东西。
无论如何 - VM 代码使用堆栈,因为像 push
和 pop
这样的指令只处理单个值,而基于寄存器的指令通常在操作码编码中使用位标志来指示 N注册使用。因此,定义一个基于堆栈的 ISA 为您提供了一组完全灵活的无限数据点,然后 interpreter/JIT 可以根据需要将它们转换为特定的寄存器——实际上,就像 LLVM 在编译时对 运行 所做的那样-时间优化。这允许 64 位系统上的 Java 程序 运行ning 自动能够在更大的寄存器集上获取,而无需从 32 位系统上的 运行ning 重新编译 - 你可以获得更宽的寄存器集自动。
这里的'stack'是一个逻辑概念,而不是一个特定的数据结构。使用不连续的非增长数据结构真的没有意义。并且堆栈被专门使用,因为通常调用一个新的 subroutine/function/method 会生成一个新的 'stack' space,所以你总是 return 来自那个子程序,然后你来自封闭的 return方法,因此您只能 pop/push 一端(例如,此处与队列无关)。除其他事项外,这就是为什么您会收到 Whosebug 异常以及为什么该站点称为 Whosebug 而不是 QueueOverflow 的原因。
根据我的调查,有两种主要的方法来实现进程 VM:
- 基于堆栈,例如 JVM、CLR 等
- 或者基于寄存器的,比如Lua、Dalvik等
基于寄存器的方法模仿了物理处理器的体系结构。 但是对于基于栈的方法,还有很多其他的数据结构。
我认为选择哪种方式主要取决于我们要如何store/fetch操作数。那么为什么选择栈呢?基于队列的虚拟机怎么样?或其他选项,如链表?
Whosebug 真的不适合基于意见的调查;很有可能关门了。
但是,重要的是要认识到特定于处理器的体系结构通常使用寄存器,因为这与处理器的工作方式相对应。每个指令集都有一组固定的可用寄存器,不同的架构会有不同的数量。此外,某些寄存器根据平台或 ABI 具有特定含义。
通用程序集文件很难在平台之间移植;或者,如果可以的话,您最终会得到尽可能少的结果,因此会错过可能适用于更广泛指令的优化。 64 位处理器的优势之一与其说是额外的宽度,不如说是增加了 ISA 中可用的寄存器数量。
有两种方法可以解决这个问题;假设一个无限寄存器集,然后在为特定体系结构翻译时提供寄存器映射(例如,LLVM 在其 ISA 中使用一个无限寄存器集,然后映射到真实 ISA 上的特定寄存器)或使用堆栈。使用堆栈的一个优点是,当您 运行 out 时,您不需要处理溢出寄存器的特定情况(例如,您有一个函数,您希望有 10 个寄存器,但您的 ISA 只有有 5).堆栈非常擅长表示无限条目(当然是对可用内存量取模。)
就是说,(真实的)堆栈速度较慢 - 实际上您在使用它时忽略了真实的寄存器。所以通常寄存器用于速度,而堆栈用于寄存器中不适合的东西。
无论如何 - VM 代码使用堆栈,因为像 push
和 pop
这样的指令只处理单个值,而基于寄存器的指令通常在操作码编码中使用位标志来指示 N注册使用。因此,定义一个基于堆栈的 ISA 为您提供了一组完全灵活的无限数据点,然后 interpreter/JIT 可以根据需要将它们转换为特定的寄存器——实际上,就像 LLVM 在编译时对 运行 所做的那样-时间优化。这允许 64 位系统上的 Java 程序 运行ning 自动能够在更大的寄存器集上获取,而无需从 32 位系统上的 运行ning 重新编译 - 你可以获得更宽的寄存器集自动。
这里的'stack'是一个逻辑概念,而不是一个特定的数据结构。使用不连续的非增长数据结构真的没有意义。并且堆栈被专门使用,因为通常调用一个新的 subroutine/function/method 会生成一个新的 'stack' space,所以你总是 return 来自那个子程序,然后你来自封闭的 return方法,因此您只能 pop/push 一端(例如,此处与队列无关)。除其他事项外,这就是为什么您会收到 Whosebug 异常以及为什么该站点称为 Whosebug 而不是 QueueOverflow 的原因。