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


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

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");
        }
    }
}

солнечное 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 не документирует никаких исключений времени выполнения для the astore - инструкции.
  • я знаю, что это законно для JVM, чтобы бросить VirtualMachineError для любой инструкции. Я угадайте, что специфическая запись предотвращает распространение таких ошибок из этой инструкции.
3 57

3 ответа:

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

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

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

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

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

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

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

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