VerifyError: Неинициализированный объект существует в обратной ветви / JVM Spec 4.10.2.4

JVM Spec 4.10.2.4 версия 7, последний абзацговорит

У действительной последовательности команд не должно быть неинициализированного объекта в стеке операндов или в локальной переменной в целевом объекте обратной ветви, если специальный тип неинициализированного объекта объединяется со специальным типом, отличным от самого себя

Вот пример, отклоненный верификатором - я подозреваю, что он должен быть принят:

public scala.Tuple2<scala.runtime.Null$, scala.runtime.Null
public 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 ]

Сообщение об ошибке жалуется на обратный переходifne 5

java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
  Location:
    C.apply(Z)Lscala/Tuple2; @6: ifne

Действительно, в стеке у цели перехода действительно неинициализированный объект; однако мне кажется, что «особый тип неинициализированного объекта» объединяется с самим собой, как того требует спецификация.

Я думаю, что есть только один фрейм карты стека, поэтому его нельзя объединить ни с чем другим.

Интересно, что ограничение на обратные ветви было снято вJVM Spec версия 8.

Однако Verifier в Java 8 VM по-прежнему отклоняет пример.

Я неправильно прочитал спецификацию JVM, или пример действительно не прошел проверку? Я пробовал версии1.7.0_60-b19 а также1.8.0_05-b13.

Общие исследования

Проблема появляется в Scala (сообщение об ошибке). Для воспроизведения возьмите scala 2.11.1, убедитесь, что вы используете JVM> = 1.7, и выполните следующее (не забудьте передать-target:jvm-1.7 Скала):

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

Как уже упоминалось выше -Отчет об ошибке JDK здесьЯ надеюсь получить ответ там.

Ошибка JDK была исправлена ​​вJDK 8u25

Ответы на вопрос(0)

Ваш ответ на вопрос