Странное исключение запись в таблице производится компилятором 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
чтобы проверить или сделать недействительными результаты испытаний.