如何在低(汇编)级别捕获和处理异常?

时间:2014-07-29 02:37:03

标签: java code-generation jit

我有这段代码 -

try {
     doSomething();
} catch (Exception e) {
   e.printStackTrace();
}

编译器实际如何实现。实际放在汇编代码中的异常检查在哪里?

更新
我知道上面的代码是如何转换为字节码的。字节码仅将try-catch转换为相应的try-handler块。我感兴趣的是它将如何转换为汇编/并由jvm处理。

4 个答案:

答案 0 :(得分:12)

如果我理解你的问题,请使用以下代码

public class Example {
    public static void main(String[] args) {
        try {
            otherMethod();
        }
        catch (Exception e) {}
        try {
            otherMethod();
            someMethod();
        }
        catch (SQLException e) {}
        catch (IOException e) {}
    }

    public static void someMethod() throws IOException {throw new IOException();}
    public static void otherMethod() throws SQLException, IOException {}
}

生成以下(人类可读版本的字节代码摘录)。

//  main method
     0: invokestatic  #2                  // Method otherMethod:()V
     3: goto          7
     6: astore_1      
     7: invokestatic  #2                  // Method otherMethod:()V
    10: invokestatic  #4                  // Method someMethod:()V
    13: goto          21
    16: astore_1      
    17: goto          21
    20: astore_1      
    21: return        
  Exception table:
     from    to  target type
         0     3     6   Class java/lang/Exception
         7    13    16   Class java/sql/SQLException
         7    13    20   Class java/io/IOException

你会注意到Exception table。此构造指示VM,如果在typefrom的指令之间发生类型to的异常,则它必须goto指令(偏移)target 。它还指示它在堆栈上推送Exception引用,以便可以复制其值并将其绑定到catch块中的参数。

您还有与上述throw声明相关的这篇文章。

// someMethod method
     0: new           #6                  // class java/io/IOException
     3: dup           
     4: invokespecial #7                  // Method java/io/IOException."<init>":()V
     7: athrow        

The instruction athrow does the following

  

抛出错误或异常(注意堆栈的其余部分是   清除,只留下对Throwable的引用)

The JVM explains what happens

  

objectref必须是类型引用,并且必须引用一个对象   这是Throwable类的实例或Throwable的子类的实例。   它从操作数堆栈中弹出。然后抛出objectref   在当前方法(第2.6节)中搜索第一个异常处理程序   匹配objectref的类,由算法中给出   §2.10。

     

如果找到与objectref匹配的异常处理程序,则它包含   用于处理此异常的代码的位置。电脑   寄存器重置到该位置,即当前的操作数堆栈   帧被清除,objectref被推回到操作数堆栈上,并且   继续执行。

     

如果在当前帧中找不到匹配的异常处理程序,那么   弹出框架。如果当前框架代表a的调用   同步方法,监视器在调用时输入或重新输入   退出该方法就好像通过执行monitorexit指令一样   (§monitorexit)。 最后,恢复其调用者的框架,如果   存在这样的帧,并且重新抛出objectref。如果没有这样的帧   存在,当前线程退出。

因此,堆栈帧会一直弹出,直到找到一个可以处理抛出异常的帧。

  

编译器实际如何实现。哪里是   检查实际放入汇编代码生成的异常?

编译器生成上面的字节码。没有检查异常,只有字节代码指令。 athrow将指示VM执行我们称之为抛出异常的任务,这将导致弹出堆栈,搜索当前堆栈帧中的异常表等。

答案 1 :(得分:8)

try-catch块的成本

粗略地说try块不会向结果程序集添加任何异常检查代码。只要没有抛出异常,它基本上是一个无操作。所有缓慢的工作都是通过异常抛出代码来完成的。

try-catch进行JIT编译时,会从代码中添加旁边的异常表。它将可能发生处理的异常的地址范围映射到相应的异常处理程序的地址。 注意:这些不是字节码索引,而是实际内存地址。

如何在HotSpot中抛出异常?

  1. 隐含异常:在信号处理程序中检测到NullPointerExceptionStackOverflowError以响应分段错误。
  2. 明确检查
  3. ArrayIndexOutOfBoundsExceptionClassCastException等。相应的检查将内联到已完成数组访问的已编译代码中。
  4. 只要执行线程状态转换(vm-&gt; java或native-&gt; java),就会明确检查
  5. OutOfMemoryError以及从本机代码抛出的所有其他异常。
  6. athrow字节码引发的所有用户异常。在快速路径中(当同一帧中存在catch处理程序时),JIT将athrow编译为简单的跳转。否则,将进行去优化,并在VM运行时内完成异常处理。
  7. 那么,'如何在汇编级别捕获异常?'

    绝不 我的意思是,异常通常不会在汇编级别捕获 - 所有繁重的东西(堆栈遍历,处理程序查找,去优化,监视器解锁等)都是在VM运行时完成的,即在C代码中完成。

答案 2 :(得分:3)

我没有为您提供明确的答案,但我会为您提供获取程序集的步骤,您可以根据用例进行剖析。

  • 确保您感兴趣的方法已编译为程序集
    • 我通常使用2 for loops 来破坏转义分析并确保我的代码没有标记为NOP
  • 确保您正在运行调试JVM构建或构建了HotSpot反汇编程序 - instructions to build on a Mac
  • 使用 java -XX运行程序:+ UnlockDiagnosticVMOptions -XX:+ PrintAssembly

还有一个用于分析和可视化JIT编译器日志文件的GUI工具,它被称为JITWatch

这是我用它来测试它的类,可能有点冗长,但是将myMethod和doSomething都编译成汇编。

public class Question {
  public static void main(String[] args) {
    long result = 0;
    for (int i = 0; i < 100; i++) {
      for (int j = 0; j < 100; j++) {
        result += myMethod();
      }
    }
    System.out.println(result);
  }

  private static long myMethod() {
    try {
      return doSomething();
    }
    catch (Exception e) {
      return 100;
    }
  }

  private static long doSomething() {
    if (System.currentTimeMillis() % 2 == 0)
      return System.currentTimeMillis();
    else
      throw new RuntimeException();
  }
}

答案 3 :(得分:-1)

我会推荐你 an answer to a stack overflow question

对于在这些机器上运行的程序,java字节代码是机器语言。没有“汇编语言”。