Sun的javac产生了奇怪的exception表条目

鉴于这个计划:

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的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表格:

  Exception table: from to target type 0 8 8 Class NullPointerException 0 17 28 any 28 29 28 any 

我的问题是: 为什么它包括exception表中的最后一项?

据我所知,它基本上说“ 如果astore_2抛出一个exception,抓住它, astore_2试相同的指令 ”。

这样的入口甚至是空的try / catch / finally子句,如

 try {} catch (NullPointerException npe) {} finally {} 

一些观察

  • Eclipse编译器不会产生任何这样的exception表项
  • JVM规范不loggingastore指令的任何运行时exception。
  • 我知道JVM抛出VirtualMachineError是合法的。 我想这个特殊的入口可以防止这样的错误从这条指令中传播出去。

只有两种可能的解释:编译器包含一个错误,或者由于模糊原因放置了一种水印。

这个入口肯定是假的,因为finally块本身抛出的任何exception都必须将执行stream发送到外部exception处理程序,或者最终阻塞,但永远不会再次运行相同的finally块。

另外,一个很好的证据表明它是一个错误/水印,事实上Eclipse(也可能是其他的Java编译器)不会生成这样的条目,即使如此,Eclipse生成的类也可以在Sun的JVM上正常工作。

这就是说,这个post很有趣,因为它似乎是类文件有效和validation。 如果我是一个JVM实现者,我会忽略那个条目,并填写Sun / Oracle的一个错误!

看一下OpenJDK 7的源代码,我会冒险猜测最后28 29 28 anyexception表项的原因,因为处理astore字节码的代码 (请参阅第1871行开始的代码 )可以抛出一个java.lang.LinkageError如果从操作数堆栈中popup的值不是returnAddressreferencetypes(请参阅“Java虚拟机规范”),并且希望在堆栈跟踪中显示此错误条件, 则会发生exception。

如果操作数堆栈中的操作数types错误,JVM将清除操作数堆栈(摆脱坏操作数),在操作堆栈上放置LinkageError ,并再次执行astore字节码,这次成功执行astore字节码使用JVM提供的LinkageError对象引用。 请参阅athrow文档以获取更多信息。

我非常怀疑引起链接错误的根本原因是由于JSR / RET子例程在字节码validation中引入了复杂性 (OpenJDK的变化6878713,69232496和7020373是JSR持续复杂性的最新证据;我相信Sun / Oracle有OpenJDK中没有看到的其他闭源testing)。 OpenJDK 7020373更改使用LinkageError来validation/无效testing结果。

我的理解是,第二个exception表条目是编译器添加的隐含的catch everything子句,以覆盖抛出的主体或catch处理程序中的任何exception/错误,第三个条目是隐式catch的guard,强制通过最后执行。