aio*_*obe 58 java jvm bytecode
鉴于此计划:
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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
使用以下异常表:
Exception table:
from to target type
0 8 8 Class NullPointerException
0 17 28 any
28 29 28 any
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么它包含异常表中的最后一个条目?!
据我了解,它基本上说" 如果astore_2抛出异常,抓住它,并重试相同的指令 ".
即使使用空的try/catch/finally子句,也会产生这样的条目
try {} catch (NullPointerException npe) {} finally {}
Run Code Online (Sandbox Code Playgroud)
一些观察
astore指令.VirtualMachineError任何指令都是合法的.我猜这个特殊的条目可以防止任何这样的错误从该指令传播出去.只有两种可能的解释:编译器包含一个错误,或者由于不明原因而放置了一种水印.
该条目肯定是假的,因为finally块本身抛出的任何异常必须将执行流发送到外部异常处理程序或最后阻塞,但永远不会"再次"运行相同的finally块.
此外,一个很好的证据表明它是一个错误/水印,事实上Eclipse(可能还有其他Java编译器)没有生成这样的条目,即便如此,Eclipse生成的类在Sun的JVM上运行良好.
也就是说,这篇文章很有意思,因为它似乎是有效的并且验证了类文件.如果我是JVM实现者,我会忽略该条目并填写Sun/Oracle的错误!
看看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的不断复杂,我敢肯定,太阳/ Oracle有我们在OpenJDK中没有看到的其他闭源测试.OpenJDK 7020373更改用于LinkageError验证/使测试结果无效.