Eu acho que a maioria de vocês sabe que goto
é uma palavra-chave reservada na linguagem Java, mas na verdade não é usada. E você provavelmente também sabe que esse goto
é um código de operação da Java Virtual Machine (JVM). Eu conto todas as estruturas de controle de fluxo sofisticados de Java, Scala e Kotlin são, ao nível JVM, implementado usando uma combinação de goto
e ifeq
, ifle
, iflt
, etc.
Observando as especificações da JVM https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.goto_w , vejo também que há um goto_w
código de operação. Considerando que goto
leva um deslocamento de ramificação de 2 bytes, goto_w
leva um deslocamento de ramificação de 4 bytes. A especificação afirma que
Embora a instrução goto_w use um deslocamento de ramificação de 4 bytes, outros fatores limitam o tamanho de um método a 65535 bytes (§4.11). Esse limite pode ser aumentado em uma versão futura da Java Virtual Machine.
Parece-me goto_w
à prova de futuro, como alguns dos outros *_w
opcodes. Mas também me ocorre que talvez goto_w
possa ser usado com os dois bytes mais significativos zerados e os dois bytes menos significativos iguais, como goto
com os ajustes necessários.
Por exemplo, dado este Java Switch-Case (ou 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.
poderíamos reescrevê-lo 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.
Na verdade, eu não tentei isso, pois provavelmente cometi um erro ao alterar os "números de linha" para acomodar os goto_w
s. Mas como está na especificação, deve ser possível fazê-lo.
Minha pergunta é se existe uma razão pela qual um compilador ou outro gerador de bytecode pode usar goto_w
com o atual limite 65535 diferente de mostrar que isso pode ser feito?
// ... repeat 10K times ...
Isso compila? Eu sei que há um limite para o tamanho de uma única classe de origem ... mas não sei exatamente o que é (a geração de código é a única vez que eu vejo algo realmente acontecer).