JVM的任何编译器是否使用“wide”的goto指令?
JVM的任何编译器是否使用“wide”的goto指令?
我猜你们大多数人都知道goto
是Java语言中的保留关键字,但实际上并没有使用。你们可能也知道goto
是Java虚拟机(JVM)的操作码。我认为Java、Scala和Kotlin的所有复杂控制流结构在JVM级别上都是使用goto
和ifeq
、ifle
、iflt
等的组合来实现的。
查看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限制呢?