没错,事情是这样的。在阅读周志明大大的《深入理解jvm 第三版》的字节码指令一节的时候,讲到iload_<n style="margin: 0px; padding: 0px; font-size: inherit; color: inherit; line-height: inherit;">指令中,n只能取0~3。有点不解,遂du了一下。</n>
然后!然后!然后!果然没让我失望,那个对jvm有着深厚造诣的蓝人--R大!!在b乎回答了这个问题。膜拜R大,这个蓝人tql。
直接上链接好了。
java字节码指令iload_<n style="margin: 0px; padding: 0px; font-size: inherit; color: inherit; line-height: inherit;">为什么只有0到3?- RednaxelaFX的回答 - 知乎
https://www.zhihu.com/question/54390587/answer/139423116</n>
总结一下:
这是Java字节码上针对字节码大小的一个早期优化。Java字节码指令集里,大部分操作局部变量的指令(例如iload、istore)都有完整版:
iload n
例如iload 5,以及针对前4个局部变量/参数的缩写版
iload_<n>
例如iload_0,这样两个版本。其中缩写版只有0~3的范围。
二者的区别是,完整版有显式的“操作数”(operand),缩写版把操作数融合到了操作码(opcode)中。分别用两种指令举个例子:
iload的指令格式是:
iload index
image
index是一个unsigned byte,用来指定局部变量的下标。另外看Notes里标注,还有wide版,如果在iload前面带有wide前缀的话,则格式为:
wide iload index1 index2
其中wide、iload、index1、index2各自为一个字节,(index1<<8)| index2 构成指令局部变量下标的操作数。
iload_<n>的指令格式是:
iload_<n>
image
其中iload_<n>自身就是opcode,它可能的取值为:
iload_0 = 26 (0x1a)
iload_1 = 27 (0x1b)
iload_2 = 28 (0x1c)
iload_3 = 29 (0x1d)
这样的话,针对前4个局部变量,iload_<n>就可以只用一个字节的opcode来表达整条指令,比使用完整版的iload要少一个字节。使用缩写版指令不但可以让字节码的大小减少,还可以让解释器的性能提升。原因如下图所示:摘自R大的知乎回答。
当使用缩写版指令时,decode_operands()就不需要做任何额外的内存读,因为operand已经隐藏在opcode里了,于是就会比完整版指令要快一些。
至于选择03的范围来做的原因,R大猜测大概只是正好发现,如果用03的话基本可以把opcode范围用满(因为字节码是1字节,最多256个),而如果用04的话就把编码空间超了,02的话则用不满,仅此而已。
《!-- 毁灭吧,赶紧的,累了 --》
网友评论