我想你们大多数人都知道goto
是Java语言中的保留关键字,但实际上并未使用。您可能还知道goto
是Java虚拟机(JVM)操作码。我认为在JVM级别上,Java,Scala和Kotlin的所有复杂控制流结构都是使用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切换案例(或Scala匹配案例):
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限制,而不是表明可以这样做?
我想你们大多数人都知道goto是Java语言中的保留关键字,但实际上并未使用。您可能还知道goto是Java虚拟机(JVM)操作码。我认为所有的...
方法代码的大小可以最大为65K。
[short goto
的分支偏移是一个有符号的16位整数:从-32768到32767。
当分支适合goto_w
时,没有理由使用goto
。但是您似乎错过了分支是relative