Странная запись в таблице исключений, созданная javac от Sun - PullRequest
58 голосов
/ 17 июня 2011

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

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's 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 для любой инструкции. Я предполагаю, что специфическая запись предотвращает распространение таких ошибок из этой инструкции.

Ответы [ 3 ]

9 голосов
/ 19 июня 2011

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

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

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

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

7 голосов
/ 29 сентября 2011

Глядя на исходный код 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 для проверки / аннулирования результатов теста.

1 голос
/ 21 июня 2011

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

...