为什么基于寄存器的虚拟机比基于堆栈的虚拟机更好?

发布于 2024-12-23 10:35:52 字数 344 浏览 0 评论 0原文

为什么基于寄存器的虚拟机比基于堆栈的虚拟机更好?

具体来说,在Parrot VM 的文档中,设计者解释了注册机的好处:

[...]许多高级语言程序由嵌套函数和方法调用组成,有时还使用词法变量来保存中间结果。在非 JIT 设置下,基于堆栈的 VM 会多次弹出并压入相同的操作数,而基于寄存器的 VM 只会分配适量的寄存器并对其进行操作,这可以显着减少操作量和 CPU 时间。

但为什么相同的操作数会被推送多次呢?

Why are register-based virtual machines better than stack-based ones?

Specifically, in the Parrot VM's document, the designer explains the benefits of register machines:

[...] many programs in high-level languages consist of nested function and method calls, sometimes with lexical variables to hold intermediate results. Under non-JIT settings, a stack-based VM will be popping and then pushing the same operands many times, while a register-based VM will simply allocate the right amount of registers and operate on them, which can significantly reduce the amount of operations and CPU time.

but why are the same operands pushed many times?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

活泼老夫 2024-12-30 10:35:52

他们似乎描述了一个虚拟机,该虚拟机按照语言设计中的描述执行代码,逐个字节码,无需编译或优化。在这种情况下,这是真的。例如,考虑一下执行类似操作的代码:

x = first(a,b,c)
y = second(a,b,c)
third(y,x)

使用基于寄存器的系统,您可以简单地将参数放在所需的任何位置(如果寄存器可用于传递参数)。如果所有寄存器都是“全局”的,而不是每个函数的(或者至少在弹出调用堆栈时恢复),您可能不需要在调用 firstsecond.

如果您有一个基于堆栈的虚拟机,您最终会得到类似的结果(希望您确实有交换):

push a
push b
push c
call first
push a # pushing same arguments again
push b
push c
call second
swap
call third

此外,如果您计算重用相同变量的数学表达式,您可能需要这样做像这样的东西:

push a
push b
add
push a
push c
add
add

而不是(假设有寄存器a,b,c,并且您可以销毁b和c的内容):

add b, a
add c, a
add b, c # result in b

这避免了恢复a,这需要在单独的推入中完成第一个案例。

再说一遍,我只是猜测这些例子,也许它们意味着其他一些情况......

It seems like they describe a VM which executes the code as described in the language design, bytecode-by-bytecode without compiling or optimisation. In that case it is true. Think about code doing something like this for example:

x = first(a,b,c)
y = second(a,b,c)
third(y,x)

With a register based system, you might be able to simply put the arguments in whatever position they're expected (if registers can be used to pass arguments). If all registers are "global", not per-function (or at least restored when poping the call-stack) you might not need to do anything between the call to first and second.

If you have a stack-based VM, you'd end up with something like (hopefully you do have swap):

push a
push b
push c
call first
push a # pushing same arguments again
push b
push c
call second
swap
call third

Also if you calculate a math expression which reuses the same variables, you might need to do something like this:

push a
push b
add
push a
push c
add
add

instead of (assuming there are registers a,b,c and you can destroy the contents of b and c):

add b, a
add c, a
add b, c # result in b

this avoids restoring a, which needed to be done in a separate push in the first case.

Then again, I'm just guessing the examples, maybe they meant some other case...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文