为什么 JVM 有 iconst_2 - iconst_5 操作码?

Why does the JVM have the iconst_2 - iconst_5 opcodes?

在阅读 JVM 规范时(正如我所做的那样),当我遇到 7 个 iconst_<i> 操作码时,我感到非常惊讶。毕竟只有一个字节可以玩

我很少在代码中写 2、3、4 或 5 的文字。我能理解为什么 -1、0 和 1 可能会被特殊对待,但令我惊讶的是,设计师竟然想在恰好很小的数字上使用 4 个宝贵的操作码。

有谁知道这是否有充分的理由?我是否低估了这些的好处?

我认为,您的假设是正确的:只是为了让字节码更小,Java 解释器稍微快一点(那时候没有 JIT 编译器)。请注意,这些字节码的使用频率可能比您预期的要高得多。例如,考虑以下代码:

int[] a = {10, 20, 30, 40};

实际上它被编译成类似这样的东西:

int[] a = new int[4];
a[0] = 10;
a[1] = 20;
a[2] = 30;
a[3] = 40;

所以这里使用了iconst_0iconst_4,即使你在源代码中没有这样的常量。

希望这可以澄清你的问题为什么要浪费 4 个操作码..

查看这段代码的字节码

public static void main(String[] args) {
        int b = 20;
        int c = 5;
        int d= 6;
    }

部分字节码

0: bipush        20
 2: istore_1
 3: iconst_5
 4: istore_2
 5: bipush        6
 7: istore_3

如您所见,对于大于 5 的数字,它开始使用 bipush,这通常比等效的 iconst_<n> 效率低,并且还会在 class 文件中占用更多字节。

bipush byte1 expands byte1 to an int and then pushes it onto the stack, because every slot on the Java stack is 32 bits wide (JVM is Stack Based Virtual Machines)

然后看看bipush是否占用更多byte..

查看以下两个代码的 class 文件大小。(这个大小在我的 64 位机器上。它可能在你的机器上有所不同,但差异是相同的)

public class Test2 {

    public static void main(String[] args) {
        int b = 5;

    }

}

size 406 bytes

现在如果我替换 b =6 ; 同一个 class 文件的大小变为 407 bytes,即使 b=127 也使用 bipush,它仍然保持不变。这种 Size 的差异是由于 bipush 有 2 个字节,一个字节的操作码,第二个字节立即数 constat 值

bipush格式:

bipush
byte

从字节码中的行 5: bipush 6 可以看出,而 iconst_<n> 仅使用 1 个字节。

So such bytecodes are defined for some commonly pushed numbers, to increase the efficiency of bytecode execution and reduce the size of bytecode streams.

正如 Tagir 所说,这些数字的使用频率将超出您的想象