JVM的任何编译器是否使用“wide”的goto指令?

15 浏览
0 Comments

JVM的任何编译器是否使用“wide”的goto指令?

我猜你们大多数人都知道goto是Java语言中的保留关键字,但实际上并没有使用。你们可能也知道goto是Java虚拟机(JVM)的操作码。我认为Java、Scala和Kotlin的所有复杂控制流结构在JVM级别上都是使用gotoifeqifleiflt等的组合来实现的。

查看JVM规范https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.goto_w我发现还有一个goto_w操作码。而goto使用2字节的分支偏移量,goto_w使用4字节的分支偏移量。规范说明:

尽管goto_w指令使用4字节的分支偏移量,但其他因素限制了方法的大小为65535字节(§4.11)。这个限制在未来的Java虚拟机版本中可能会提高。

在我看来,goto_w是为了未来做好准备,就像其他*_w操作码一样。但我也想到,也许可以将goto_w与两个更重要的字节清零,并将两个较不重要的字节与goto一样,根据需要进行调整。

例如,给定以下Java Switch-Case(或Scala Match-Case):

     12: lookupswitch  {
                112785: 48 // case "red"
               3027034: 76 // case "green"
              98619139: 62 // case "blue"
               default: 87
          }
      48: aload_2
      49: ldc           #17                 // String red
      51: invokevirtual #18
            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      54: ifeq          87
      57: iconst_0
      58: istore_3
      59: goto          87
      62: aload_2
      63: ldc           #19                 // String green
      65: invokevirtual #18
            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      68: ifeq          87
      71: iconst_1
      72: istore_3
      73: goto          87
      76: aload_2
      77: ldc           #20                 // String blue
      79: invokevirtual #18 
      // etc.

我们可以将其重写为:

     12: lookupswitch  { 
                112785: 48
               3027034: 78
              98619139: 64
               default: 91
          }
      48: aload_2
      49: ldc           #17                 // String red
      51: invokevirtual #18
            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      54: ifeq          91 // 00 5B
      57: iconst_0
      58: istore_3
      59: goto_w        91 // 00 00 00 5B
      64: aload_2
      65: ldc           #19                 // String green
      67: invokevirtual #18
            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      70: ifeq          91
      73: iconst_1
      74: istore_3
      75: goto_w          91
      79: aload_2
      81: ldc           #20                 // String blue
      83: invokevirtual #18 
      // etc.

我实际上还没有尝试过这个,因为我可能在更改“行号”以适应goto_w时犯了错误。但既然规范中有这个说明,那么应该是可以做到的。

我的问题是,除了展示它可以做到之外,编译器或其他字节码生成器是否有其他原因使用goto_w与当前的65535限制呢?

0