VerifyError: existe um objeto não inicializado na ramificação reversa / JVM Spec 4.10.2.4
oJVM Spec 4.10.2.4 versão 7, último parágrafodiz
Uma sequência de instruções válida não deve ter um objeto não inicializado na pilha de operandos ou em uma variável local no destino de uma ramificação reversa se o tipo especial do objeto não inicializado for mesclado com um tipo especial que não seja ele próprio
Aqui está um exemplo rejeitado pelo verificador - suspeito que deve ser aceito:
public scala.Tuple2<scala.runtime.Null$, scala.runtime.Nullpublic scala.Tuple2<scala.runtime.Null$, scala.runtime.Null$> apply(boolean);
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: new #12 // class scala/Tuple2
3: dup
4: aconst_null
5: iload_1
6: ifne 5
9: aconst_null
10: invokespecial #16 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
13: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LC;
0 14 1 x Z
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 5
locals = [ class C, int ]
stack = [ uninitialized 0, uninitialized 0, null ]
gt; apply(boolean);
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: new #12 // class scala/Tuple2
3: dup
4: aconst_null
5: iload_1
6: ifne 5
9: aconst_null
10: invokespecial #16 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
13: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LC;
0 14 1 x Z
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 5
locals = [ class C, int ]
stack = [ uninitialized 0, uninitialized 0, null ]
A mensagem de erro reclama sobre o salto para trásifne 5
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
Location:
C.apply(Z)Lscala/Tuple2; @6: ifne
De fato, há um objeto não inicializado na pilha no alvo do salto; no entanto, parece-me que o "tipo especial do objeto não inicializado" é mesclado consigo mesmo, conforme exigido pelas especificações.
Eu acho que existe apenas um quadro de mapa de pilha, então ele não pode ser mesclado com mais nada.
Curiosamente, a restrição de ramificações anteriores foi removida noJVM Spec versão 8.
No entanto, o Verificador na Java 8 VM ainda rejeita o exemplo.
Eu interpretei errado a especificação da JVM ou o exemplo realmente deve falhar na verificação? Eu tentei versões1.7.0_60-b19
e1.8.0_05-b13
.
A questão aparece em Scala (relatório de erro) Para reproduzir, use o scala 2.11.1, verifique se você está em uma JVM> = 1.7 e execute o seguinte (certifique-se de passar-target:jvm-1.7
para scala):
localhost:sandbox luc$ scala -target:jvm-1.7
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class C {
| def apply(x: Boolean) = new Tuple2(null, {
| while (x) { }
| null
| })
| }
defined class C
scala> new C
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
Location:
C.apply(Z)Lscala/Tuple2; @6: ifne
Reason:
Error exists in the bytecode
Bytecode:
0000000: bb00 0959 011b 9aff ff01 b700 0db0
Stackmap Table:
full_frame(@5,{Object[#2],Integer},{Uninitialized[#0],Uninitialized[#0],Null})
... 32 elided
Como acima mencionado -Relatório de erros do JDK aqui, Espero obter uma resposta lá.
O bug do JDK foi corrigido noJDK 8u25