Me imagino que la mayoría de ustedes saben que goto
es una palabra clave reservada en el lenguaje Java pero que en realidad no se usa. Y probablemente también sepa que goto
es un código de operación de Java Virtual Machine (JVM). Creo que todas las estructuras de flujo de control sofisticados de Java, Scala y Kotlin son, a nivel JVM, implementado usando una combinación de goto
y ifeq
, ifle
, iflt
, etc.
Mirando la especificación JVM https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.goto_w veo que también hay un goto_w
código de operación. Mientras que goto
toma un desplazamiento de rama de 2 bytes, goto_w
toma un desplazamiento de rama de 4 bytes. La especificación establece que
Aunque la instrucción goto_w toma un desplazamiento de rama de 4 bytes, otros factores limitan el tamaño de un método a 65535 bytes (§4.11). Este límite puede aumentarse en una versión futura de Java Virtual Machine.
Me parece que goto_w
es a prueba de futuro, como algunos de los otros *_w
códigos de operación. Pero también se me ocurre que tal vez goto_w
podría usarse con los dos bytes más significativos puestos a cero y los dos bytes menos significativos de la misma manera goto
, con los ajustes necesarios.
Por ejemplo, dado este caso de conmutador de Java (o caso de coincidencia de 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.
podríamos reescribirlo como
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.
Realmente no he intentado esto, ya que probablemente he cometido un error al cambiar los "números de línea" para acomodar el goto_w
s. Pero como está en la especificación, debería ser posible hacerlo.
Mi pregunta es si hay una razón por la que un compilador u otro generador de bytecode podría usar goto_w
el límite actual de 65535 además de mostrar que se puede hacer.
// ... repeat 10K times ...
Eso compila? Sé que hay un límite para el tamaño de una sola clase de origen ... pero no sé cuál es precisamente (la generación de código es la única vez que he visto algo realmente golpearlo).