为什么在 Java 字节码中跳转而不是 return?

Why jump instead of return in Java bytecode?

背景

我编译的方法如下:

public static final boolean equalTo(final int x, final int y) {
    return x == y;
}

并且使用javap可以看到为它生成了以下字节码:

  public static final boolean equalTo(int, int);                                                                                                                                                                 
    descriptor: (II)Z                                                                                                                                                                                            
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL                                                                                                                                                            
    Code:                                                                                                                                                                                                        
      stack=2, locals=2, args_size=2                                                                                                                                                                             
         0: iload_0                                                                                                                                                                                              
         1: iload_1                                                                                                                                                                                              
         2: if_icmpne     9                                                                                                                                                                                      
         5: iconst_1                                                                                                                                                                                             
         6: goto          10                                                                                                                                                                                     
         9: iconst_0                                                                                                                                                                                             
        10: ireturn                                                                                                                                                                                              
      LineNumberTable:                                                                                                                                                                                           
        line 72: 0                                                                                                                                                                                               
      StackMapTable: number_of_entries = 2                                                                                                                                                                       
        frame_type = 9 /* same */                                                                                                                                                                                
        frame_type = 64 /* same_locals_1_stack_item */                                                                                                                                                           
          stack = [ int ]                                                    

我写了 ASM 来创建相同的字节码,并且还通过将 goto 10 更改为 ireturn 创建了另一个表现相同的版本。它可以忽略不计,但这也减少了 StackMapTable 的大小,因为它消除了跳跃。

问题

我知道“它只是字节码”并不能指示机器将做什么,但是为什么编译器在它可以简单地发出 ireturn 时发出 goto 10

前端编译器使用简单的模式生成代码,它们依靠优化过程来清理代码。在生成 x == y 表达式时,编译器“不知道”接下来是 return 语句。它可能会对此进行检查,但是可以使用某种窥孔优化器同样轻松地处理这个额外的步骤。

窥孔优化器的好处是它可以执行级联优化,也就是说,一个优化的结果可以输入到下一个优化中。生成 x == y 表达式的代码实际上没有任何方法可以在不增加更多复杂性的情况下执行不止一个优化步骤。

java 编译器曾经有一个优化功能,但是为了支持 HotSpot 而放弃了这个功能,它可以执行更强大的优化。在 java 编译器中执行优化会减慢它的速度,并且不会真正改善很多东西。