ART世界探险(10) - 异常处理
来源:互联网 发布:古筝校音器软件 编辑:程序博客网 时间:2024/04/30 01:31
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/IllegalStateException 3: dup 4: invokespecial #12 // Method java/lang/IllegalStateException."<init>":()V 7: athrow public void dealWtihException() throws java.io.IOException; Code: 0: aload_0 1: invokevirtual #13 // Method withException:()V 4: goto 23 7: astore_1 8: aload_1 9: instanceof #15 // class java/lang/RuntimeException 12: ifeq 23 15: new #16 // class java/io/IOException 18: dup 19: invokespecial #17 // Method java/io/IOException."<init>":()V 22: athrow 23: return Exception table: from to target type 0 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@2105 0x0002: 7010 0642 0000 | invoke-direct {v0}, void java.lang.IllegalStateException.<init>() // method@16902 0x0005: 2700 | throw v0 OatMethodOffsets (offset=0x002778f4) code_offset: 0x00663bdc gc_map: (offset=0x002848e8) OatQuickMethodHeader (offset=0x00663bc0) mapping_table: (offset=0x002deece) vmap_table: (offset=0x0030e0fa) v65535/r30 QuickMethodFrameInfo frame_size_in_bytes: 32 core_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: 0x0000 GC 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, #0x839 0x00663c00: f940d65e ldr lr, [tr, #424] (pAllocObject) 0x00663c04: d63f03c0 blr lr suspend point dex PC: 0x0000 GC 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: 0x0002 GC 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, #0x1040 0x00663c28: f2a00050 movk x16, #0x2, lsl #16 0x00663c2c: f8706800 ldr x0, [x0, x16] 0x00663c30: f940181e ldr lr, [x0, #48] 0x00663c34: d63f03c0 blr lr suspend point dex PC: 0x0002 GC 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 lr suspend point dex PC: 0x0005 GC map objects: v0 ([sp + #16]), v1 ([sp + #40]) 0x00663c44: f9421e5e ldr lr, [tr, #1080] (pTestSuspend) 0x00663c48: d63f03c0 blr lr suspend point dex PC: 0x0000 GC 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@16784 0x0003: 0e00 | return-void 0x0004: 0d00 | move-exception v0 0x0005: 2001 4908 | instance-of v1, v0, java.lang.RuntimeException // type@2121 0x0007: 3801 fcff | if-eqz v1, -4 0x0009: 2201 2008 | new-instance v1, java.io.IOException // type@2080 0x000b: 7010 ca41 0100 | invoke-direct {v1}, void java.io.IOException.<init>() // method@16842 0x000e: 2701 | throw v1 OatMethodOffsets (offset=0x002778dc) code_offset: 0x0066341c gc_map: (offset=0x002ce33a) OatQuickMethodHeader (offset=0x00663400) mapping_table: (offset=0x00308696) vmap_table: (offset=0x0030e0fa) v65535/r30 QuickMethodFrameInfo frame_size_in_bytes: 48 core_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: 0x0000 GC 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: 0x0000 GC 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 lr suspend point dex PC: 0x0000 GC map objects: v2 ([sp + #56])
返回值也用不到,所以直接返回了。
0x00663458: f94017fe ldr lr, [sp, #40] 0x0066345c: 9100c3ff add sp, sp, #0x30 (48) 0x00663460: d65f03c0 ret catch 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, #0x0 0x00663490: 340000a0 cbz w0, #+0x14 (addr 0x6634a4)
对象已经初始化过了,就去调pInstanceofNonTrivial去做instanceof检查。
0x00663494: b9400002 ldr w2, [x0] 0x00663498: 6b01005f cmp w2, w1 0x0066349c: 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, eq 0x006634b4: 2a0103e0 mov w0, w1 0x006634b8: 35fffd00 cbnz w0, #-0x60 (addr 0x663458)
这里调用pAllocObject去new IOException的对象。
0x006634bc: f94003e1 ldr x1, [sp] 0x006634c0: 52810400 mov w0, #0x820 0x006634c4: f940d65e ldr lr, [tr, #424] (pAllocObject) 0x006634c8: d63f03c0 blr lr suspend point dex PC: 0x0009 GC 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: 0x000b GC 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, #0xe60 0x006634ec: f2a00050 movk x16, #0x2, lsl #16 0x006634f0: f8706800 ldr x0, [x0, x16] 0x006634f4: f940181e ldr lr, [x0, #48] 0x006634f8: d63f03c0 blr lr suspend point dex PC: 0x000b GC 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 lr suspend point dex PC: 0x000e GC map objects: v0 ([sp + #28]), v1 ([sp + #32]), v2 ([sp + #56]) 0x00663508: f9421e5e ldr lr, [tr, #1080] (pTestSuspend) 0x0066350c: d63f03c0 blr lr suspend point dex PC: 0x0000 GC map objects: v2 ([sp + #56]) 0x00663510: 17ffffca b #-0xd8 (addr 0x663438)
pInitializeType是检查类型是否已经初始化过了。
0x00663514: 52810920 mov w0, #0x849 0x00663518: f9410a5e ldr lr, [tr, #528] (pInitializeType) 0x0066351c: d63f03c0 blr lr suspend point dex PC: 0x0005 GC map objects: v0 ([sp + #28]), v2 ([sp + #56]) 0x00663520: 17ffffd8 b #-0xa0 (addr 0x663480)
最后是instanceof的实现,pInstanceofNonTrivial
0x00663524: aa0103e0 mov x0, x1 0x00663528: aa0203e1 mov x1, x2 0x0066352c: f940fa5e ldr lr, [tr, #496] (pInstanceofNonTrivial) 0x00663530: d63f03c0 blr lr suspend point dex PC: 0x0005 GC map objects: v0 ([sp + #28]), v2 ([sp + #56]) 0x00663534: 2a0003e2 mov w2, w0 0x00663538: 17ffffdb b #-0x94 (addr 0x6634a4)
异常处理相关指令总结
- ART世界探险(10) - 异常处理
- ART世界探险(7) - 数组
- ART世界探险(18) InlineMethod
- ART探险(1) - oatdump看到的世界
- ART世界探险(5) - 计算指令
- ART世界探险(6) - 流程控制指令
- ART世界探险(8) - 面向对象编程
- ART世界探险(9) - 同步锁
- ART世界探险(11) - OAT文件格式分析
- ART世界探险(13) - 初入dex2oat
- ART世界探险(2) - 从java byte code说起
- ART世界探险(14) - 快速编译器和优化编译器
- ART世界探险(15) - CompilerDriver,ClassLinker,Runtime三大组件
- ART世界探险(16) - 快速编译器下的方法编译
- ART世界探险(17) - 中层中间代码MIR
- ART世界探险(19) - 优化编译器的编译流程
- ART世界探险(20) - Android N上的编译流程
- ART异常处理机制(1)
- Java_集合_Collection
- hdu 3068最长回文 Manacher算法
- Andorid命令行签名
- bzoj 1208: [HNOI2004]宠物收养所 splay
- 金额正则表达式
- ART世界探险(10) - 异常处理
- 二维码生成和解析
- 黑客攻防入门(二)shellcode构造
- 移动web开发之——viewport
- 轻松把玩HttpClient之封装HttpClient工具类(五),携带Cookie的请求
- LeetCode#371 Sum of Two Integers
- Web恶意代码检测方法
- HDU5762 Teacher Bo 带处理的暴力
- 容器学习总结