Подтвердить что ты не робот

Странная запись таблицы исключений, созданная Sun javac

Учитывая эту программу:

class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();
        } catch (NullPointerException npe) {
            System.out.println("In catch");
        } finally {
            System.out.println("In finally");
        }
    }
}

Sun javac (v 1.6.0_24) создает следующий байт-код:

public static void main(java.lang.String[]);

        // Instantiate / throw NPE
   0:   new     #2;         // class NullPointerException
   3:   dup
   4:   invokespecial   #3; // Method NullPointerException."<init>":()V
   7:   athrow

        // Start of catch clause
   8:   astore_1
   9:   getstatic       #4; // Field System.out
   12:  ldc     #5;         // "In catch"
   14:  invokevirtual   #6; // Method PrintStream.println
   17:  getstatic       #4; // Field System.out

        // Inlined finally block
   20:  ldc     #7;         // String In finally
   22:  invokevirtual   #6; // Method PrintStream.println
   25:  goto    39

        // Finally block
        // store "incomming" exception(?)
   28:  astore_2
   29:  getstatic       #4; // Field System.out
   32:  ldc     #7;         // "In finally"
   34:  invokevirtual   #6; // Method PrintStream.println

        // rethrow "incomming" exception
   37:  aload_2
   38:  athrow

   39:  return

Со следующей таблицей исключений:

  Exception table:
   from   to  target type
     0     8     8   Class NullPointerException
     0    17    28   any
    28    29    28   any


Мой вопрос: Почему он включает эту последнюю запись в таблицу исключений?!

Насколько я понимаю, в основном говорится: "Если astore_2 выдает исключение, ловить его и повторять ту же инструкцию".

Такая запись создается даже с пустыми предложениями try/catch/finally, такими как

try {} catch (NullPointerException npe) {} finally {}

Некоторые наблюдения

  • Компилятор Eclipse не создает такую ​​запись таблицы исключений
  • Спецификация JVM не документирует исключения во время выполнения для инструкции astore.
  • Я знаю, что JVM имеет право бросать VirtualMachineError для любой команды. Я предполагаю, что особенная запись предотвращает распространение таких ошибок из этой инструкции.
4b9b3361

Ответ 1

Есть только два возможных объяснения: компилятор содержит ошибку или помещает своего рода водяной знак для неясных причин.

Эта запись, безусловно, подделана, потому что любое исключение, созданное блоком finally, должно отправлять поток выполнения внешнему обработчику исключений или, наконец, блокировать, но никогда не "запускать" тот же последний блок.

Кроме того, хорошим доказательством того, что это ошибка/водяной знак, является тот факт, что Eclipse (и, возможно, другие компиляторы Java) не генерируют такую ​​запись, и даже поэтому классы, созданные Eclipse, отлично работают на Sun JVM.

Тем не менее, этот пост интересен тем, что кажется, что файл класса действителен и проверен. Если бы я был разработчиком JVM, я бы проигнорировал эту запись и заполнил ошибку для Sun/Oracle!

Ответ 2

Глядя на исходный код OpenJDK 7, я бы рискнул угадать причину что последняя запись таблицы исключений 28 29 28 any - это потому, что код, который обрабатывает байт-код astore (см. код, начиная с строки 1871), может бросить java.lang.LinkageError исключение, если всплывающее значение из стека операндов не является типом returnAddress или reference (см. Спецификация виртуальной машины Java для astore), и они хотят этого условие ошибки для отображения на трассировке стека.

В случае, если в стеке операндов существует неправильный тип операнда, JVM будет очистите стек операнда (избавившись от этого плохого операнда), поставьте LinkageError в стеке операндов и снова выполнить байт-код astore, на этот раз успешно выполнив байт-код astore, используя JVM при условии LinkageError ссылка на объект. Дополнительную информацию см. В документации athrow.

Я бы очень сильно подозревал основную причину бросания LinkageError во время astore обработка происходит из-за сложности подпрограмм JSR/RET вводят в проверку байт-кода (OpenJDK изменения 6878713, 6932496 и 7020373 недавние доказательства JSR непрерывной сложности; Я уверен, что Sun/Oracle имеет другие закрытые исходные тесты, которые мы не видим в OpenJDK). OpenJDK 7020373 изменение использует LinkageError для проверки/недействительности результатов теста.

Ответ 3

Я понимаю, что вторая запись таблицы исключений - это неявное предложение catch all, добавленное компилятором для покрытия любых исключений/ошибок, брошенных в тело или обработчиков catch, а третья запись - это защита от неявного улова, чтобы заставить поток через окончательное выполнение.