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