java - 为什么只为 *const_n JVM 指令定义了这样的常量范围?
问题描述
根据 JVM规范,有几条指令针对使用一组特定的常量进行了优化。谁能解释为什么只定义了这个常数范围?
- iconst_n:压入整数常量 n,0 ≤ n ≤ 5
- lconst_n:推长常量n,0≤n≤1
- fconst_n:推送浮点常量 n,0 ≤ n ≤ 2
- dconst_n:push double 常数 n,0 ≤ n ≤ 1
我认为这是由于使用这些常数的频率,但我找不到我的想法或任何其他有关它的信息的确认。
解决方案
意图已被明确提及,例如在JVMS, §3.2 中。常量、局部变量和控制结构的使用:
Java 虚拟机经常利用某些操作数的可能性(
int
常量-1、0、1、2、3、4和5在iconst_<i>指令的情况下)通过使这些操作数隐含在操作码中。因为iconst_0指令知道它将推送一个int
0
,所以 iconst_0不需要存储操作数来告诉它要推送什么值,也不需要获取或解码操作数。将0的 push 编译为bipush 0是正确的,但会使编译后的代码为spin
¹ 长一个字节。一个简单的虚拟机在每次循环中都会花费额外的时间来获取和解码显式操作数。隐式操作数的使用使编译后的代码更加紧凑和高效。
¹这是正在讨论的示例代码,即从零到一百的 for 循环
它不是这种类型的唯一优化,例如,有一些特殊指令用于访问堆栈帧中的局部变量的第一个。
这些操作在指令集中也有特殊的支持。在
spin
中,使用istore_1和iload_1指令将值传入和传出局部变量,每个指令都隐式地对局部变量1进行操作。
还要注意方便的指令iinc的存在,它是唯一直接对局部变量进行操作的指令。因此,计数循环,通常从零或一开始,并将计数器增加一个像 1 这样的小值,是这些优化指令的主要用例。
小变量索引的优化是合理的,因为这些索引按升序分配this
(如果不是static
),然后是参数,然后是第一个局部变量。原则上,编译器可以通过对变量重新排序以在优化索引处具有最常用的变量来进一步优化这一点,但实际上,这不会发生。
对于像 HotSpot 这样的优化 JVM,使用这些指令肯定没有性能优势,但它们仍然使字节码更短。
推荐阅读
- reactjs - 如何访问 React 双列表框中选项的单击事件?
- mysql - 如何获取状态全为 1 的记录数
- javascript - 将 div 拆分为每个 div 的最大高度的 div
- webpack - 如何导入全局 less mixin 以便可以在任何组件中使用?
- opencart - 如何在 Opencart 中更新主题
- bazel - 预编译静态库 /MT 和 /MTd 错误
- javascript - 如何在绘图图中打破长轴标签
- r - 在使用此列中的数据时排除 `dplyr` `mutate_at` 中的列
- postgresql - 我想忽略的更新覆盖字段的 Gorm 模型
- asp.net - 在另一个虚拟目录中运行一个项目以进行调试