6

我知道 JVM 和 CLR 被设计为基于堆栈的虚拟机。当 JIT 将字节码编译为本机代码时,它是否还将堆栈原语(加载/存储)转换为 X86 平台上的寄存器?

如果是的话,看起来字节码是基于堆栈还是基于寄存器并不重要。JIT 很重要。

4

3 回答 3

7

我认为您混淆了两个不同的概念。

至少对于 Java,JVM 充当虚拟机——它是一个理想化的计算机,具有相对高级的汇编语言(字节码),它基于带有堆栈帧的调用堆栈。在将 Java 编译为字节码时,Java 程序(本质上)变成了用于控制这台机器的汇编程序。

在给定系统上实际运行 Java 时,JVM 实现的工作是使用实际可用的任何硬件忠实地模拟这个基于堆栈的机器的执行。这通常意味着大量的堆栈操作将在可能的情况下使用寄存器来实现,并且可能使用 Java 虚拟机描述中不存在的其他专用硬件。如何做到这一点的实际细节是特定于实现的——一些实现可能会将其编译为几乎所有在寄存器中完成的机器代码,而更简单的实现可能只是编译为内存中的操作。我在 JVM 的 JavaScript 实现上工作了几个月,在这种情况下,我们将代码“编译”为 JS 函数,

这种区别的原因是Java被设计成易于下载和嵌入(想想applet)。在这种情况下,安全性和可移植性是重要的考虑因素。字节码必须有某种方法可以自动检查以排除某些类型的恶意代码(例如缓冲区溢出)。同样,无论使用何种格式,都必须足够高级,以便可以在各种不同的平台(手持设备、超级计算机、PC 等)上运行。选择基于堆栈的 JVM 使这两个问题成为可能同时满足。它足够高级,可以检查字节码以排除许多类型错误或未初始化内存的读/写,同时足够低级,JVM 可以使用诸如使用寄存器编译代码之类的技巧。

如果您好奇您的特定JVM 将对特定代码段做什么,您应该查看文档。大多数 JVM 都有某种方式可以为您提供有关它们如何执行代码的信息。如果您的问题是“为什么不让字节码进行基于寄存器的操作”,原因有两个:

  1. 字节码中有一个类似的寄存器 - 每个堆栈帧都有一些额外的专用空间用于存储临时值,并且
  2. 对寄存器的支持不如 x86 或 MIPS 中的强大,因为 JVM 代码必须易于在多个硬件上执行,并且在多个寄存器中硬编码可能会使事情复杂化。

希望这可以帮助!

于 2012-06-18T23:34:46.540 回答
2

在 x86 内核上不使用寄存器是不可能的。处理器没有添加两个局部变量的指令。其中一个必须加载到寄存器中。然后您可以将寄存器中的值添加到变量中的值。并将结果存储回堆栈变量。

从这个序列中可以明显看出优化机会。就像将其存储回来,而是将结果保存在寄存器中并稍后使用它,同时保存存储和加载。那是优化器的工作,它寻找方法来充分利用可用的寄存器。

于 2012-06-19T01:01:33.457 回答
0

唯一确定的方法是检查 JIT 编译的输出,但可以肯定地说,使用寄存器是 JIT 编译器最蹩脚的优化之一。我相信大多数程序员很难写出比 JIT 编译器更快的代码。

JIT 编译器有很多功能,并且可能会尽可能多地使用寄存器。方法内联之类的东西鼓励使用寄存器,并且许多命令式程序代码可以在基于寄存器的架构上更简单地表达,因此只有 JIT 编译器使用寄存器才有意义。

于 2012-06-18T23:29:28.267 回答