前言
字节码里面隐藏了多少秘密, 呵呵 我们这里来以一个极简单的例子 来探索一下, 探索一下 基于解释执行的 相关细节
lldb 汇编调试的部分需要感谢朋友 "新加坡买买提", 去年 12 月份的时候花了一下午的时间不佞帮助我, 呵呵 本文的例子也是那个时候 编写的以及调试的, 不过 当时是 clion 里面也能进行 lldb 的调试, 命令行中也可以, 现在 clion 里面的 lldb 不知道为啥不能调试了 ...
测试用例
package com.hx.test02;/*** TemplateInterpreter** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2019-12-08 13:36*/
public class Test23TemplateInterpreter {public static void main(String[] args) {// System.gc();int x = 1;}}
对应的字节码的相关信息如下, 一下可能会用于参照
master:classes jerry$ javap -c com/hx/test02/Test23TemplateInterpreter.class
Compiled from "Test23TemplateInterpreter.java"
public class com.hx.test02.Test23TemplateInterpreter {public com.hx.test02.Test23TemplateInterpreter();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: return
}
基于 lldb 的调试
(lldb) p _active_table._table[9][4]
(address) $1 = 0x0000000105830e1f "?\x01"
(lldb) p _active_table._table[9][60]
(address) $2 = 0x0000000105833aa0 "\x8b\x04$H\x83\U00000088A\x89F?A\x0f?]\x01I??I?p?0\x04\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f
(lldb) b 0x0000000105833aa0
Breakpoint 4: address = 0x0000000105833aa0
// iconst_1
(lldb) c
Process 3086 resuming
Process 3086 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
-> 0x105830e1f: movl $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq %r130x105830e2c: movabsq $0x104308a70, %r10 ; imm = 0x104308A70
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e24
-> 0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq %r130x105830e2c: movabsq $0x104308a70, %r10 ; imm = 0x104308A70 0x105830e36: jmpq *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e29
-> 0x105830e29: incq %r130x105830e2c: movabsq $0x104308a70, %r10 ; imm = 0x104308A70 0x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e2c
-> 0x105830e2c: movabsq $0x104308a70, %r10 ; imm = 0x104308A70 0x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop 0x105830e3b: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e36
-> 0x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop 0x105830e3b: nop 0x105830e3c: nop
Target 0: (java) stopped.// istore_1
(lldb) c
Process 3086 resuming
Process 3086 stopped
* thread #5, stop reason = breakpoint 4.1frame #0: 0x0000000105833aa0
-> 0x105833aa0: movl (%rsp), %eax0x105833aa3: addq $0x8, %rsp0x105833aa7: movl %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000000000000rbx = 0x000000000000003crcx = 0x0000000000006a00rdx = 0x0000000000006a00rdi = 0x0000000105005000rsi = 0x0000000000000008rbp = 0x0000700009d05690rsp = 0x0000700009d05640r8 = 0x0000000000000000r9 = 0x0000000100611890r10 = 0x0000000104306270 libjvm.dylib`TemplateInterpreter::_normal_table + 18432r11 = 0x000000010061188cr12 = 0x0000000000000000r13 = 0x000000011c7ede61r14 = 0x0000700009d056a8r15 = 0x0000000105005000rip = 0x0000000105833aa0rflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa3
-> 0x105833aa3: addq $0x8, %rsp0x105833aa7: movl %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq %r13
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000000000001rbx = 0x000000000000003crcx = 0x0000000000006a00rdx = 0x0000000000006a00rdi = 0x0000000105005000rsi = 0x0000000000000008rbp = 0x0000700009d05690rsp = 0x0000700009d05640r8 = 0x0000000000000000r9 = 0x0000000100611890r10 = 0x0000000104306270 libjvm.dylib`TemplateInterpreter::_normal_table + 18432r11 = 0x000000010061188cr12 = 0x0000000000000000r13 = 0x000000011c7ede61r14 = 0x0000700009d056a8r15 = 0x0000000105005000rip = 0x0000000105833aa3rflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa7
-> 0x105833aa7: movl %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq %r130x105833ab3: movabsq $0x10430b270, %r10 ; imm = 0x10430B270
Target 0: (java) stopped.
(lldb) x 0x0000700009d05640 -c 0x100
0x700009d05640: 01 00 00 00 00 00 00 00 48 56 d0 09 00 70 00 00 ........HV?..p..
0x700009d05650: 61 de 7e 1c 01 00 00 00 a8 56 d0 09 00 70 00 00 a?~.....?V?..p..
0x700009d05660: e0 de 7e 1c 01 00 00 00 00 00 00 00 00 00 00 00 ??~.............
0x700009d05670: d0 7f bb 47 07 00 00 00 88 de 7e 1c 01 00 00 00 ?.?G.....?~.....
0x700009d05680: 00 00 00 00 00 00 00 00 a8 56 d0 09 00 70 00 00 ........?V?..p..
0x700009d05690: 10 57 d0 09 00 70 00 00 f1 09 80 05 01 00 00 00 .W?..p..?.......
0x700009d056a0: 00 00 00 00 00 00 00 00 88 83 bb 47 07 00 00 00 ..........?G....
0x700009d056b0: a0 1f 00 00 03 00 00 00 00 00 00 00 00 00 00 00 ?...............
0x700009d056c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x700009d056d0: 00 00 00 00 00 00 00 00 00 60 d0 09 00 70 00 00 .........`?..p..
0x700009d056e0: 20 58 d0 09 00 70 00 00 50 5d d0 09 00 70 00 00 X?..p..P]?..p..
0x700009d056f0: 0a 00 00 00 00 70 00 00 88 de 7e 1c 01 00 00 00 .....p...?~.....
0x700009d05700: 00 a7 82 05 01 00 00 00 a0 5a d0 09 00 70 00 00 .?......?Z?..p..
0x700009d05710: e0 58 d0 09 00 70 00 00 1d bb 8e 03 01 00 00 00 ?X?..p...?......
0x700009d05720: 01 00 00 00 00 70 00 00 00 50 00 05 01 00 00 00 .....p...P......
0x700009d05730: 50 57 d0 09 00 70 00 00 15 95 28 03 01 00 00 00 PW?..p....(.....
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aab
-> 0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq %r130x105833ab3: movabsq $0x10430b270, %r10 ; imm = 0x10430B270 0x105833abd: jmpq *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) x 0x0000700009d05640 -c 0x100
0x700009d05640: 01 00 00 00 00 00 00 00 48 56 d0 09 00 70 00 00 ........HV?..p..
0x700009d05650: 61 de 7e 1c 01 00 00 00 a8 56 d0 09 00 70 00 00 a?~.....?V?..p..
0x700009d05660: e0 de 7e 1c 01 00 00 00 00 00 00 00 00 00 00 00 ??~.............
0x700009d05670: d0 7f bb 47 07 00 00 00 88 de 7e 1c 01 00 00 00 ?.?G.....?~.....
0x700009d05680: 00 00 00 00 00 00 00 00 a8 56 d0 09 00 70 00 00 ........?V?..p..
0x700009d05690: 10 57 d0 09 00 70 00 00 f1 09 80 05 01 00 00 00 .W?..p..?.......
0x700009d056a0: 01 00 00 00 00 00 00 00 88 83 bb 47 07 00 00 00 ..........?G....
0x700009d056b0: a0 1f 00 00 03 00 00 00 00 00 00 00 00 00 00 00 ?...............
0x700009d056c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x700009d056d0: 00 00 00 00 00 00 00 00 00 60 d0 09 00 70 00 00 .........`?..p..
0x700009d056e0: 20 58 d0 09 00 70 00 00 50 5d d0 09 00 70 00 00 X?..p..P]?..p..
0x700009d056f0: 0a 00 00 00 00 70 00 00 88 de 7e 1c 01 00 00 00 .....p...?~.....
0x700009d05700: 00 a7 82 05 01 00 00 00 a0 5a d0 09 00 70 00 00 .?......?Z?..p..
0x700009d05710: e0 58 d0 09 00 70 00 00 1d bb 8e 03 01 00 00 00 ?X?..p...?......
0x700009d05720: 01 00 00 00 00 70 00 00 00 50 00 05 01 00 00 00 .....p...P......
0x700009d05730: 50 57 d0 09 00 70 00 00 15 95 28 03 01 00 00 00 PW?..p....(.....
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab0
-> 0x105833ab0: incq %r130x105833ab3: movabsq $0x10430b270, %r10 ; imm = 0x10430B270 0x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab3
-> 0x105833ab3: movabsq $0x10430b270, %r10 ; imm = 0x10430B270 0x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop 0x105833ac2: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833abd
-> 0x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop 0x105833ac2: nop 0x105833ac3: nop
Target 0: (java) stopped.
(lldb)
其中 0x700009d056a0 对应的数据对应的是 slot1[变量x]
可以看到这里的 iconst_1, istore_1 的大致的流程, 然后 如何存放到 slot1 里面的
这里有一个问题就是 0x105833aa0 的地方直接使用了 栈顶的数据 放到 rax 然后进行之后的业务操作
但是 在 iconst_1 的相关代码里面么有看到 将 rax 存入 stack 的过程(这个 push rax 在后面)
字节码执行之间中插的代码?
在 iconst_1 和 istore_1 之间, 还执行了如下一段代码, 呵呵 有些地方看的明白, 大部分地方看不明白, 先放在这里吧, 后面 有一定的了解之后再来解惑
(lldb) dis -s 0x105825f24 -c 200// push rax, 将1入表达式栈(这里的场景)0x105825f24: pushq %rax// MacroAssembler::call_VM_helper0x105825f25: callq 0x105825f2f0x105825f2a: jmp 0x1058261850x105825f2f: leaq 0x8(%rsp), %rax// save_bcp0x105825f34: movq %r13, -0x40(%rbp)// cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD)0x105825f38: cmpq $0x0, -0x10(%rbp)0x105825f40: je 0x105825fbd// ignore MacroAssembler::debug64// 擦 这里对应的是哪里 0x105825fbd: pushq %r100x105825fbf: cmpq -0x150f9d6(%rip), %r12 ; Universe::_narrow_ptrs_base0x105825fc6: je 0x105826043// ignore MacroAssembler::debug640x105826043: popq %r10// LP64_ONLY(mov(c_rarg0, r15_thread))0x105826045: movq %r15, %rdi// set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);0x105826048: movq %rbp, 0x218(%r15)0x10582604f: movq %rax, 0x208(%r15)// MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); 0x105826056: testl $0xf, %esp0x10582605c: je 0x1058260740x105826062: subq $0x8, %rsp0x105826066: callq 0x1038d5ac0 ; InterpreterRuntime::at_safepoint at interpreterRuntime.cpp:10500x10582606b: addq $0x8, %rsp0x10582606f: jmp 0x1058260790x105826074: callq 0x1038d5ac0 ; InterpreterRuntime::at_safepoint at interpreterRuntime.cpp:1050// get_thread(java_thread);0x105826079: pushq %rax0x10582607a: pushq %rdi0x10582607b: pushq %rsi0x10582607c: pushq %rdx0x10582607d: pushq %rcx0x10582607e: pushq %r80x105826080: pushq %r90x105826082: pushq %r100x105826084: pushq %r110x105826086: testl $0xf, %esp0x10582608c: je 0x1058260a40x105826092: subq $0x8, %rsp0x105826096: callq 0x103003ae0 ; Thread::current at thread.hpp:6600x10582609b: addq $0x8, %rsp0x10582609f: jmp 0x1058260a90x1058260a4: callq 0x103003ae0 ; Thread::current at thread.hpp:6600x1058260a9: popq %r110x1058260ab: popq %r100x1058260ad: popq %r90x1058260af: popq %r80x1058260b1: popq %rcx0x1058260b2: popq %rdx0x1058260b3: popq %rsi0x1058260b4: popq %rdi0x1058260b5: cmpq %rax, %r150x1058260b8: je 0x105826135// ignore MacroAssembler::debug640x105826135: popq %rax// reset_last_Java_frame(java_thread, true);0x105826136: movabsq $0x0, %r100x105826140: movq %r10, 0x208(%r15)0x105826147: movabsq $0x0, %r100x105826151: movq %r10, 0x218(%r15)0x105826158: movabsq $0x0, %r100x105826162: movq %r10, 0x210(%r15)// check_exceptions0x105826169: cmpq $0x0, 0x8(%r15)0x105826171: je 0x10582617c0x105826177: jmp 0x1058007a0// restore_bcp();0x10582617c: movq -0x40(%rbp), %r13// restore_locals();0x105826180: movq -0x38(%rbp), %r140x105826184: retq// dispatch 下一条指令 0x105826185: movzbl (%r13), %ebx0x10582618a: movabsq $0x104306270, %r10 ; imm = 0x1043062700x105826194: jmpq *(%r10,%rbx,8)
这块代码 主要的目的是调用 InterpreterRuntime::at_safepoint
生成上面这段汇编的核心代码 似乎是来自于这里, 传入的 entry_point 是 InterpreterRuntime::at_safepoint 的 entry_point
呵呵 先留在这里不求甚解吧
另外还有一个现象是, 这断代码 核心调用的是 InterpreterRuntime::at_safepoint 在 lldb 命令行里面调试的时候, 你会清楚的看到 会执行这段代码, 但是 在 clion 里面调试的时候 打上一个断点, 却不会执行, 这个是和 什么时候调试 有一定的关系么 ?
这部分中插代码再记录 add at 2020.06.06
======================= add at 2020.06.06 =======================
今天又重新调试了一下 这个例子, 呵呵 发现了一点 之前调试记录的不同的东西
呵呵, 有些时候 没有去 调用 InterpreterRuntime::at_safepoint
直接按照 字节码模板 的调度过程去进行执行了, 直接以 ax 作为媒介来传递了数据
(lldb) p _active_table._table[9][4]
(address) $1 = 0x0000000105830e1f "?\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f// iconst_1
(lldb) c
Process 3326 resuming
Process 3326 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
-> 0x105830e1f: movl $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq %r130x105830e2c: movabsq $0x103b08a70, %r10 ; imm = 0x103B08A70
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e24
-> 0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq %r130x105830e2c: movabsq $0x103b08a70, %r10 ; imm = 0x103B08A700x105830e36: jmpq *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e29
-> 0x105830e29: incq %r130x105830e2c: movabsq $0x103b08a70, %r10 ; imm = 0x103B08A700x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e2c
-> 0x105830e2c: movabsq $0x103b08a70, %r10 ; imm = 0x103B08A700x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop0x105830e3b: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e36
-> 0x105830e36: jmpq *(%r10,%rbx,8)0x105830e3a: nop0x105830e3b: nop0x105830e3c: nop
Target 0: (java) stopped.// istore_1
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa7
-> 0x105833aa7: movl %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq %r130x105833ab3: movabsq $0x103b0b270, %r10 ; imm = 0x103B0B270
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aab
-> 0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq %r130x105833ab3: movabsq $0x103b0b270, %r10 ; imm = 0x103B0B2700x105833abd: jmpq *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab0
-> 0x105833ab0: incq %r130x105833ab3: movabsq $0x103b0b270, %r10 ; imm = 0x103B0B2700x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab3
-> 0x105833ab3: movabsq $0x103b0b270, %r10 ; imm = 0x103B0B2700x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop0x105833ac2: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833abd
-> 0x105833abd: jmpq *(%r10,%rbx,8)0x105833ac1: nop0x105833ac2: nop0x105833ac3: nop
Target 0: (java) stopped.
呵呵 上面的 字节码执行之间中插的代码 来自于
以上两种情况对应于 active_table 为 normal_table 或者 切换为 safept_table 的情况, 呵呵 但是什么情况下切换, 目前我还不明白
active_table 为 normal_table 的场景
(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010604f980 "XH;"
(lldb) p _active_table._table[0][0]
(address) $1 = 0x0000000106030b9e "PA\x0f\xb6]\x01I??I\xbap\xb2\xb0\x03\x01"
(lldb) p _normal_table._table[0][0]
(address) $2 = 0x0000000106030b9e "PA\x0f\xb6]\x01I??I\xbap\xb2\xb0\x03\x01"
(lldb) p _safept_table._table[0][0]
(address) $3 = 0x00000001060252e0 "P?
(lldb) p _active_table._table[9][4]
(address) $4 = 0x0000000106030e1f "\xb8\x01"
(lldb) b 0x0000000106030e1f
Breakpoint 3: address = 0x0000000106030e1f
(lldb) c
Process 3783 resuming
Process 3783 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000106030e1f
-> 0x106030e1f: movl $0x1, %eax0x106030e24: movzbl 0x1(%r13), %ebx0x106030e29: incq %r130x106030e2c: movabsq $0x103b08a70, %r10 ; imm = 0x103B08A70
Target 0: (java) stopped.
(lldb) p _active_table._table[0][0]
(address) $5 = 0x0000000106030b9e "PA\x0f?]\x01I??I?p??\x03\x01"
active_table 为 safept_table 的场景
(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010584f980 "XH;"
(lldb) p _active_table._table[0][0]
(address) $1 = 0x0000000105830b9e "PA\x0f\xb6]\x01I??I\xbap\xb20\x04\x01"
(lldb) p _normal_table._table[0][0]
(address) $2 = 0x0000000105830b9e "PA\x0f\xb6]\x01I??I\xbap\xb20\x04\x01"
(lldb) p _safept_table._table[0][0]
(address) $3 = 0x00000001058252e0 "P?
(lldb) p _active_table._table[9][4]
(address) $4 = 0x0000000105830e1f "?\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f
(lldb) c
Process 3646 resuming
Process 3646 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
-> 0x105830e1f: movl $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq %r130x105830e2c: movabsq $0x104308a70, %r10 ; imm = 0x104308A70
Target 0: (java) stopped.
(lldb) p _active_table._table[0][0]
(address) $5 = 0x00000001058252e0 "P?
完