由Sun的javac制作的奇怪异常表条目

时间:2011-06-17 13:59:30

标签: 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");
        }
    }
}

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 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 instruction的任何运行时异常。
  • 我知道JVM为任何指令抛出VirtualMachineError是合法的。我猜这个特殊的条目可以防止任何此类错误从该指令传播出来。

3 个答案:

答案 0 :(得分:8)

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

该条目肯定是假的,因为finally块本身抛出的任何异常必须将执行流发送到外部异常处理程序或最后阻塞,但绝不会“再次”运行相同的finally块。

此外,一个很好的证据表明它是一个错误/水印,是Eclipse(可能还有其他Java编译器)没有生成这样的条目,即便如此,Eclipse生成的类在Sun的JVM上运行良好。

也就是说,这篇文章很有意思,因为它似乎是有效的并且验证了类文件。如果我是JVM实现者,我会忽略该条目并填写Sun / Oracle的错误!

答案 1 :(得分:6)

看看OpenJDK 7源代码,我冒昧地猜测原因 最后28 29 28 any异常表条目是因为代码 处理astore字节码(见code从第1871行开始)即可 如果弹出值,则抛出java.lang.LinkageError异常 来自操作数堆栈的不是returnAddressreference类型(参见 astore)的Java虚拟机规范,他们想要这个 错误条件显示在堆栈跟踪上。

如果操作数堆栈上存在错误的操作数类型,JVM将会 清除操作数堆栈(摆脱那个坏操作数),放一个LinkageError 在操作数堆栈上,这次再次执行astore字节码 使用提供的astore JVM成功执行LinkageError字节码 对象参考。有关详细信息,请参阅athrow文档。

我非常怀疑在{期间}投掷LinkageError的根本原因 astore处理归因于complexities JSR/RET subroutines引入字节码验证(OpenJDK更改 687871369324967020373是。{ 最近证据JSR的复杂性持续存在;我确信Sun / Oracle还有其他 我们在OpenJDK中没有看到的闭源测试。 OpenJDK 7020373更改使用LinkageError来验证/使测试结果无效。

答案 2 :(得分:1)

我的理解是第二个异常表条目是编译器添加的隐式catch everything子句,用于覆盖正文或catch处理程序中抛出的任何异常/错误,第三个条目是该隐式catch上的守护强制流经最后的执行。