ART世界探险(10) - 异常处理

对于编译Java的话,有一个问题不能不考虑,就是异常处理的问题。异常处理是基于Java的语句块的,翻译成本地代码的话,需要针对这些指令的地址进行一下重排。
我们来看下ART是如何实现异常处理的。

Java异常处理

首先复习一下Java。
Java有两种Exception,一种是普通Exception,另一种是RuntimeException。非RuntimeException,如果没有处理,就是没有用try...catch块包围或者是throws声明的话,会编译不过。
而RuntimeException就没有这个限制,不处理,就等运行时crash再说吧。

Java源代码

我们先写两个小函数试验一下:

    public void withException(){throw new IllegalStateException();}public void dealWtihException() throws IOException{try{withException();}catch(Exception e){if(e instanceof RuntimeException) throw new IOException();}}

Class字节码

从字节码上我们可以看到,dealWithException中,0到4行是记录在Exception table中的,如果出了Exception,则会跳转到7开始的语句。
而withException方法,因为抛出的是RuntimeException,也没有try...catch,所以没有Exception table.

  public void withException();Code:0: new           #11                 // class java/lang/IllegalStateException3: dup4: invokespecial #12                 // Method java/lang/IllegalStateException."<init>":()V7: athrowpublic void dealWtihException() throws java.io.IOException;Code:0: aload_01: invokevirtual #13                 // Method withException:()V4: goto          237: astore_18: aload_19: instanceof    #15                 // class java/lang/RuntimeException12: ifeq          2315: new           #16                 // class java/io/IOException18: dup19: invokespecial #17                 // Method java/io/IOException."<init>":()V22: athrow23: returnException table:from    to  target type0     4     7   Class java/lang/Exception

Dalvik指令和OAT指令

我们先看只抛个Exception的withException

  7: void com.yunos.xulun.testcppjni2.SampleClass.withException() (dex_method_idx=16784)DEX CODE:0x0000: 2200 3908                    | new-instance v0, java.lang.IllegalStateException // type@21050x0002: 7010 0642 0000               | invoke-direct {v0}, void java.lang.IllegalStateException.<init>() // method@169020x0005: 2700                         | throw v0OatMethodOffsets (offset=0x002778f4)code_offset: 0x00663bdc gc_map: (offset=0x002848e8)OatQuickMethodHeader (offset=0x00663bc0)mapping_table: (offset=0x002deece)vmap_table: (offset=0x0030e0fa)v65535/r30QuickMethodFrameInfoframe_size_in_bytes: 32core_spill_mask: 0x40000000 (r30)fp_spill_mask: 0x00000000 vr_stack_locations:locals: v0[sp + #16]ins: v1[sp + #40]method*: v2[sp + #0]outs: v0[sp + #8]CODE: (code_offset=0x00663bdc size_offset=0x00663bd8 size=116)...0x00663bdc: d1400bf0    sub x16, sp, #0x2000 (8192)0x00663be0: b940021f    ldr wzr, [x16]suspend point dex PC: 0x0000GC map objects:  v1 ([sp + #40])0x00663be4: f81e0fe0    str x0, [sp, #-32]!0x00663be8: f9000ffe    str lr, [sp, #24]0x00663bec: b9002be1    str w1, [sp, #40]0x00663bf0: 79400250    ldrh w16, [tr](state_and_flags)0x00663bf4: 35000290    cbnz w16, #+0x50 (addr 0x663c44)

前面还是保存现场,检查有没有被suspend.
然后调用pAllocObject去new一个IllegalStateException对象。
v0是sp+16

      0x00663bf8: f94003e1    ldr x1, [sp]0x00663bfc: 52810720    mov w0, #0x8390x00663c00: f940d65e    ldr lr, [tr, #424](pAllocObject)0x00663c04: d63f03c0    blr lrsuspend point dex PC: 0x0000GC map objects:  v1 ([sp + #40])0x00663c08: b90013e0    str w0, [sp, #16]0x00663c0c: b94013e0    ldr w0, [sp, #16]0x00663c10: b940001f    ldr wzr, [x0]suspend point dex PC: 0x0002GC map objects:  v0 ([sp + #16]), v1 ([sp + #40])

只要是对象,就要调用构造方法,下面就是计算和调用构造方法。

      0x00663c14: b9000fe0    str w0, [sp, #12]0x00663c18: b9400fe1    ldr w1, [sp, #12]0x00663c1c: f94003e0    ldr x0, [sp]0x00663c20: b9400400    ldr w0, [x0, #4]0x00663c24: d2820810    mov x16, #0x10400x00663c28: f2a00050    movk x16, #0x2, lsl #160x00663c2c: f8706800    ldr x0, [x0, x16]0x00663c30: f940181e    ldr lr, [x0, #48]0x00663c34: d63f03c0    blr lrsuspend point dex PC: 0x0002GC map objects:  v0 ([sp + #16]), v1 ([sp + #40])

从v0(sp+16)把异常对象的引用读回来,然后调用pDeliverException将其抛出去。

      0x00663c38: b94013e0    ldr w0, [sp, #16]0x00663c3c: f942225e    ldr lr, [tr, #1088](pDeliverException)0x00663c40: d63f03c0    blr lrsuspend point dex PC: 0x0005GC map objects:  v0 ([sp + #16]), v1 ([sp + #40])0x00663c44: f9421e5e    ldr lr, [tr, #1080](pTestSuspend)0x00663c48: d63f03c0    blr lrsuspend point dex PC: 0x0000GC map objects:  v1 ([sp + #40])0x00663c4c: 17ffffeb    b #-0x54 (addr 0x663bf8)

下面再看dealWtihException的:

  1: void com.yunos.xulun.testcppjni2.SampleClass.dealWtihException() (dex_method_idx=16778)DEX CODE:0x0000: 6e10 9041 0200               | invoke-virtual {v2}, void com.yunos.xulun.testcppjni2.SampleClass.withException() // method@167840x0003: 0e00                         | return-void0x0004: 0d00                         | move-exception v00x0005: 2001 4908                    | instance-of v1, v0, java.lang.RuntimeException // type@21210x0007: 3801 fcff                    | if-eqz v1, -40x0009: 2201 2008                    | new-instance v1, java.io.IOException // type@20800x000b: 7010 ca41 0100               | invoke-direct {v1}, void java.io.IOException.<init>() // method@168420x000e: 2701                         | throw v1OatMethodOffsets (offset=0x002778dc)code_offset: 0x0066341c gc_map: (offset=0x002ce33a)OatQuickMethodHeader (offset=0x00663400)mapping_table: (offset=0x00308696)vmap_table: (offset=0x0030e0fa)v65535/r30QuickMethodFrameInfoframe_size_in_bytes: 48core_spill_mask: 0x40000000 (r30)fp_spill_mask: 0x00000000 vr_stack_locations:locals: v0[sp + #28] v1[sp + #32]ins: v2[sp + #56]method*: v3[sp + #0]outs: v0[sp + #8]CODE: (code_offset=0x0066341c size_offset=0x00663418 size=288)...0x0066341c: d1400bf0    sub x16, sp, #0x2000 (8192)0x00663420: b940021f    ldr wzr, [x16]suspend point dex PC: 0x0000GC map objects:  v2 ([sp + #56])0x00663424: f81d0fe0    str x0, [sp, #-48]!0x00663428: f90017fe    str lr, [sp, #40]0x0066342c: b9003be1    str w1, [sp, #56]0x00663430: 79400250    ldrh w16, [tr](state_and_flags)0x00663434: 350006b0    cbnz w16, #+0xd4 (addr 0x663508)

本地变量:
v0是sp+28
v1是sp+32

开始先将sp+56(v2)清0.
然后调用我们自己写的withException方法。

      0x00663438: b9403be0    ldr w0, [sp, #56]0x0066343c: b940001f    ldr wzr, [x0]suspend point dex PC: 0x0000GC map objects:  v2 ([sp + #56])0x00663440: b9001be0    str w0, [sp, #24]0x00663444: b9401be1    ldr w1, [sp, #24]0x00663448: b9400020    ldr w0, [x1]0x0066344c: f9418c00    ldr x0, [x0, #792]0x00663450: f940181e    ldr lr, [x0, #48]0x00663454: d63f03c0    blr lrsuspend point dex PC: 0x0000GC map objects:  v2 ([sp + #56])

返回值也用不到,所以直接返回了。

      0x00663458: f94017fe    ldr lr, [sp, #40]0x0066345c: 9100c3ff    add sp, sp, #0x30 (48)0x00663460: d65f03c0    retcatch entry dex PC: 0x0004

下面是处理Exception的部分:

Exception的类型放到w0中,然后去判断类型是否已经初始化过了。

      0x00663464: b9408a40    ldr w0, [tr, #136](exception)0x00663468: b9008a5f    str wzr, [tr, #136](exception)0x0066346c: b9001fe0    str w0, [sp, #28]0x00663470: f94003e0    ldr x0, [sp]0x00663474: b9400800    ldr w0, [x0, #8]0x00663478: b9613000    ldr w0, [x0, #8496]0x0066347c: 340004c0    cbz w0, #+0x98 (addr 0x663514)

如果没有初始化,那就真接跳0x663490,返回

      0x00663480: b9001be0    str w0, [sp, #24]0x00663484: b9401fe0    ldr w0, [sp, #28]0x00663488: b9401be1    ldr w1, [sp, #24]0x0066348c: 52800002    mov w2, #0x00x00663490: 340000a0    cbz w0, #+0x14 (addr 0x6634a4)

对象已经初始化过了,就去调pInstanceofNonTrivial去做instanceof检查。

      0x00663494: b9400002    ldr w2, [x0]0x00663498: 6b01005f    cmp w2, w10x0066349c: 54000441    b.ne #+0x88 (addr 0x663524)0x006634a0: 52800022    mov w2, #0x1

下面这段是判断不是RuntimeException的子类,所以跳回,结束的情况。0x00663458是上面的返回部分的代码。

      0x006634a4: b90023e2    str w2, [sp, #32]0x006634a8: b94023e0    ldr w0, [sp, #32]0x006634ac: 7100001f    cmp w0, #0x0 (0)0x006634b0: 1a9f17e1    cset w1, eq0x006634b4: 2a0103e0    mov w0, w10x006634b8: 35fffd00    cbnz w0, #-0x60 (addr 0x663458)

这里调用pAllocObject去new IOException的对象。

      0x006634bc: f94003e1    ldr x1, [sp]0x006634c0: 52810400    mov w0, #0x8200x006634c4: f940d65e    ldr lr, [tr, #424](pAllocObject)0x006634c8: d63f03c0    blr lrsuspend point dex PC: 0x0009GC map objects:  v0 ([sp + #28]), v2 ([sp + #56])0x006634cc: b90023e0    str w0, [sp, #32]0x006634d0: b94023e0    ldr w0, [sp, #32]0x006634d4: b940001f    ldr wzr, [x0]suspend point dex PC: 0x000bGC map objects:  v0 ([sp + #28]), v1 ([sp + #32]), v2 ([sp + #56])

下面当然是调IOException的构造方法了:

      0x006634d8: b9001be0    str w0, [sp, #24]0x006634dc: b9401be1    ldr w1, [sp, #24]0x006634e0: f94003e0    ldr x0, [sp]0x006634e4: b9400400    ldr w0, [x0, #4]0x006634e8: d281cc10    mov x16, #0xe600x006634ec: f2a00050    movk x16, #0x2, lsl #160x006634f0: f8706800    ldr x0, [x0, x16]0x006634f4: f940181e    ldr lr, [x0, #48]0x006634f8: d63f03c0    blr lrsuspend point dex PC: 0x000bGC map objects:  v0 ([sp + #28]), v1 ([sp + #32]), v2 ([sp + #56])

最后调用pDeliveryException抛出去。

      0x006634fc: b94023e0    ldr w0, [sp, #32]0x00663500: f942225e    ldr lr, [tr, #1088](pDeliverException)0x00663504: d63f03c0    blr lrsuspend point dex PC: 0x000eGC map objects:  v0 ([sp + #28]), v1 ([sp + #32]), v2 ([sp + #56])0x00663508: f9421e5e    ldr lr, [tr, #1080](pTestSuspend)0x0066350c: d63f03c0    blr lrsuspend point dex PC: 0x0000GC map objects:  v2 ([sp + #56])0x00663510: 17ffffca    b #-0xd8 (addr 0x663438)

pInitializeType是检查类型是否已经初始化过了。

      0x00663514: 52810920    mov w0, #0x8490x00663518: f9410a5e    ldr lr, [tr, #528](pInitializeType)0x0066351c: d63f03c0    blr lrsuspend point dex PC: 0x0005GC map objects:  v0 ([sp + #28]), v2 ([sp + #56])0x00663520: 17ffffd8    b #-0xa0 (addr 0x663480)

最后是instanceof的实现,pInstanceofNonTrivial

      0x00663524: aa0103e0    mov x0, x10x00663528: aa0203e1    mov x1, x20x0066352c: f940fa5e    ldr lr, [tr, #496](pInstanceofNonTrivial)0x00663530: d63f03c0    blr lrsuspend point dex PC: 0x0005GC map objects:  v0 ([sp + #28]), v2 ([sp + #56])0x00663534: 2a0003e2    mov w2, w00x00663538: 17ffffdb    b #-0x94 (addr 0x6634a4)

异常处理相关指令总结

Java字节码 Dalvik指令 OAT过程
athrow throw v0 pDeliverException

ART世界探险(10) - 异常处理相关推荐

  1. ART世界探险(6) - 流程控制指令

    ART世界探险(6) - 流程控制指令 分支结构 Java分支结构 我们先来个最简单的,比较大小吧. public static long bigger(long a, long b){if(a> ...

  2. ART世界探险(17) - 中层中间代码MIR

    ART世界探险(17) - 中层中间代码MIR Dalvik字节码的指令格式 指令格式分类 Dalvik指令,根据需要的寄存器数目的不同,长度也有所不同. 如下面的结构所示,有下面的这些情况: enu ...

  3. ART世界探险(5) - 计算指令

    ART世界探险(5) - 计算指令 整数运算 Java的整型运算 我们先看看JVM是如何处理这些基本整数运算的吧. public static long add(long a, long b){ret ...

  4. ART世界探险(12) - OAT文件分析(2) - ELF文件头分析(中)

    ART世界探险(12) - OAT文件分析(2) - ELF文件头分析(中) 段(section)的概念 一块内存分配给应用程序之后,从代码的组织上,我们就有将它们分段的需求. 比如,可以分为代码段, ...

  5. ART世界探险(4) - 数据传送指令和桶型移位器

    ART世界探险(4) - 数据传送指令和桶型移位器 数据传送指令 将数在寄存器之间传递,或者将立即数传给寄存器.所谓的立即数,就是直接写在指令里的数,比如MOV X0,100,这个100就是立即数.立 ...

  6. ART世界探险(18) InlineMethod

    ART世界探险(18) InlineMethod 好,我们还是先复习一下上上节学到的图: 在开始InlineMethod之前,我们再继续补充一点BasicBlock的知识. BasicBlock中针对 ...

  7. 2021年泰晤士世界大学学科排名公布!清北均有学科位居世界前10

    来源:青塔 10月28日北京时间下午5点,2021年度泰晤士高等教育学科排名公布. 泰晤士世界大学学科排名(THE World University Rankings by Subject)涵盖工程技 ...

  8. 【巨人的肩膀上制造世界】——10——Unity3D实用插件之Vectrosity,轻松便捷的实现2D/3D画线功能

    [巨人的肩膀上制造世界]--10--Unity3D实用插件之Vectrosity,轻松便捷的实现2D/3D画线功能 目录 1.博客介绍 2.内容 (1)编辑器预制线条 (2)编辑器修改线条 (3)线条 ...

  9. 轰动世界的10大营销理念

    轰动世界的10大营销理念 知识营销 知识营销指的是向大众传播新的科学技术以及它们对人们生活的影响,通过科普宣传,让消费者不仅知其然,而且知其所以然,重新建立新的产品概念,进而使消费者萌发对新产品的需要 ...

最新文章

  1. 小米语音首席科学家Daniel Povey:下一代Kaldi将走向何方?
  2. SSRS配置2:加密管理
  3. xftp Initialize Flexnet Service failed / Error code: 50003
  4. ORACLE将表中的数据恢复到某一个时间点
  5. 系统云服务器,系统云服务器
  6. mysql java 获取周_Java中获取Mysql中datetime类型的数据
  7. bootstrap 点击按钮刷新_Spring Cloud 中的 Bootstrap 上下文
  8. Win-MASM64汇编语言-MUL/DIV
  9. Linux 防火墙 开放 端口 iptables
  10. 拓端tecdat|Python、R对小说进行文本挖掘和层次聚类可视化分析案例
  11. delphi 算术溢出解决方法_文言文代码算什么?跟着九章算术学Python编程才厉害...
  12. 浅谈《原神》中的图形渲染技术
  13. Excel自定义格式日期计算问题
  14. CentOS 7 出现 a problem has occured and the system can‘t recover 解决办法:组合键进入命令行进行修复
  15. 进制转换简单实现代码
  16. python俄罗斯方块小游戏实验报告_python实现俄罗斯方块游戏
  17. wx.createVideoContext 全屏播放
  18. android加载大量图片内存优化,Android图片加载内存优化
  19. 计算机音乐专业考研,武汉音乐学院2021年硕士研究生招生考试《计算机音乐作曲》考试大纲...
  20. 光纤激光器仿真:(2)孤子分子及其转换动力学

热门文章

  1. Postfix实现代理Exchange邮件传输方案
  2. VulnHub靶机系列:Os-ByteSec
  3. linux 查找某目录下包含关键字内容的文件(文件内容、grep)
  4. Linux查找字符串包含在某目录所有文件中
  5. Python中MRO
  6. 2022年轻人潮流爱好报告:被朋友圈高赞的神秘爱好,不烧钱还能脱单
  7. 你的“不着急”,最后都是“来不及”
  8. STM32之外部中断原理
  9. vrp 节约算法 c++_数据结构和算法(Golang实现)(8.1)基础知识-前言
  10. 华为开发者被批评在 Linux 内核刷 KPI