23 方法调用的流程(invokestatic为例)
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23 方法调用的流程(invokestatic为例)相关的知识,希望对你有一定的参考价值。
前言
之前看到一篇文章, java 反射调用 private 相关
里面 大佬大致截图 截了一下 为什么运行时生成的 GeneratedMethodAccessor 可以访问所有的方法
呵呵 说实话 这个问题 之前还没有考虑到
但是 大佬的截图 说是话 还是有些抽象, 没有和具体的 运行时的来龙去脉 连接在一起
但是 在排查整个流程之前, 我们需要知道 方法调用 指令处理了那些事情
呵呵 这个就是 本文的重点了
本文 主要是以 invokestatic 为例来走一下 大致的流程
有一些基础知识 可以参考一下文章, 以及一下文章的参考文章(recurse)
以下代码, 截图 基于 jdk9
测试用例
package com.hx.test05;
/**
* InvokeStatic
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2020-05-01 15:03
*/
public class Test18InvokeStatic
// Test18InvokeStatic
public static void main(String[] args)
foo();
// foo
public static void foo()
呵呵 我们主要走的是 invokestatic 的整个流程, 因此 这个测试用例 很简单
对应的字节码信息如下, 下面参照可能需要使用到
master:classes jerry$ javap -c -v com/hx/test05/Test18InvokeStatic.class
Classfile /Users/jerry/IdeaProjects/HelloWorld/target/classes/com/hx/test05/Test18InvokeStatic.class
Last modified May 1, 2020; size 487 bytes
MD5 checksum d8cf4aca9a312dae396d364dff4e4e53
Compiled from "Test18InvokeStatic.java"
public class com.hx.test05.Test18InvokeStatic
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#19 // java/lang/Object."<init>":()V
#2 = Methodref #3.#20 // com/hx/test05/Test18InvokeStatic.foo:()V
#3 = Class #21 // com/hx/test05/Test18InvokeStatic
#4 = Class #22 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 LocalVariableTable
#10 = Utf8 this
#11 = Utf8 Lcom/hx/test05/Test18InvokeStatic;
#12 = Utf8 main
#13 = Utf8 ([Ljava/lang/String;)V
#14 = Utf8 args
#15 = Utf8 [Ljava/lang/String;
#16 = Utf8 foo
#17 = Utf8 SourceFile
#18 = Utf8 Test18InvokeStatic.java
#19 = NameAndType #5:#6 // "<init>":()V
#20 = NameAndType #16:#6 // foo:()V
#21 = Utf8 com/hx/test05/Test18InvokeStatic
#22 = Utf8 java/lang/Object
public com.hx.test05.Test18InvokeStatic();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/hx/test05/Test18InvokeStatic;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method foo:()V
3: return
LineNumberTable:
line 15: 0
line 17: 3
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 args [Ljava/lang/String;
public static void foo();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=0, args_size=0
0: return
LineNumberTable:
line 22: 0
SourceFile: "Test18InvokeStatic.java"
基于 lldb 的调试
还是同参考的一系列文章差不多, 我们这里 先来进行 lldb 的调试, 然后 之后再来分析 相关的代码
(lldb) p _active_table._table[9][184]
(address) $1 = 0x000000010584c8bf "L\\x89m?A\\x0f?U\\x01H\\x8bM??\\U0000008b\\\\???\\x10\\x81??
(lldb) b 0x000000010584c8bf
Breakpoint 3: address = 0x000000010584c8bf
(lldb) c
Process 3885 resuming
Process 3885 stopped
* thread #5, stop reason = breakpoint 3.1
frame #0: 0x000000010584c8bf
-> 0x10584c8bf: movq %r13, -0x40(%rbp)
0x10584c8c3: movzwl 0x1(%r13), %edx
0x10584c8c8: movq -0x30(%rbp), %rcx
0x10584c8cc: shll $0x2, %edx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x00007000063a3650
rbx = 0x00000000000000b8
rcx = 0x0000000000000008
rdx = 0x0000000000000000
rdi = 0x0000000101807000
rsi = 0x0000000000000008
rbp = 0x00007000063a3698
rsp = 0x00007000063a3650
r8 = 0x0000000000002901
r9 = 0x0000000101807000
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x000000011d369e70
r14 = 0x00007000063a36a8
r15 = 0x0000000101807000
rip = 0x000000010584c8bf
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) x 0x000000011d369e70
0x11d369e70: b8 01 00 b1 ff 00 1e 1a 00 00 00 00 04 00 0e 00 ?..??...........
0x11d369e80: 0f 00 00 00 00 00 01 00 40 6f 23 04 01 00 00 00 ........@o#.....
(lldb) x 0x00007000063a3650 -c 0x100
0x7000063a3650: 50 36 3a 06 00 70 00 00 70 9e 36 1d 01 00 00 00 P6:..p..p.6.....
0x7000063a3660: a8 36 3a 06 00 70 00 00 78 9f 36 1d 01 00 00 00 ?6:..p..x.6.....
0x7000063a3670: 00 00 00 00 00 00 00 00 58 7f bb 47 07 00 00 00 ........X.?G....
0x7000063a3680: 88 9e 36 1d 01 00 00 00 00 00 00 00 00 00 00 00 ..6.............
0x7000063a3690: a8 36 3a 06 00 70 00 00 10 37 3a 06 00 70 00 00 ?6:..p...7:..p..
0x7000063a36a0: f1 09 80 05 01 00 00 00 a0 83 bb 47 07 00 00 00 ?.......?.?G....
0x7000063a36b0: a0 1f 00 00 03 00 00 00 00 00 00 00 00 00 00 00 ?...............
0x7000063a36c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7000063a36d0: 00 00 00 00 00 00 00 00 00 40 3a 06 00 70 00 00 .........@:..p..
0x7000063a36e0: 20 38 3a 06 00 70 00 00 50 3d 3a 06 00 70 00 00 8:..p..P=:..p..
0x7000063a36f0: 0a 00 00 00 00 70 00 00 88 9e 36 1d 01 00 00 00 .....p....6.....
0x7000063a3700: 00 a7 82 05 01 00 00 00 a0 3a 3a 06 00 70 00 00 .?......?::..p..
0x7000063a3710: e0 38 3a 06 00 70 00 00 1d bb 8e 03 01 00 00 00 ?8:..p...?......
0x7000063a3720: 01 00 00 00 00 70 00 00 00 70 80 01 01 00 00 00 .....p...p......
0x7000063a3730: 50 37 3a 06 00 70 00 00 15 95 28 03 01 00 00 00 P7:..p....(.....
0x7000063a3740: 70 37 3a 06 00 70 00 00 00 70 80 01 01 00 00 00 p7:..p...p......
(lldb) p ((Method*)0x0747bb7f58)
(Method *) $2 = 0x0000000747bb7f58
(lldb) p ((Method*)0x011d369e88)->print()
method
- this oop: 0x000000011d369e88
- method holder: 'com/hx/test05/Test18InvokeStatic'
- constants: 0x000000011d369c50 constant pool [23] 0x000000011d369c50 for 'com/hx/test05/Test18InvokeStatic' cache=0x000000011d369f78
- access: 0x9 public static
- name: 'main'
- signature: '([Ljava/lang/String;)V'
- max stack: 1
- max locals: 1
- size of params: 1
- method size: 11
- vtable index: -2
- i2i entry: 0x000000010582a700
- adapters: AHE@0x00000001010292e0: 0xb0000000 i2c: 0x00000001059a4460 c2i: 0x00000001059a459a c2iUV: 0x00000001059a456d
- compiled entry 0x00000001059a459a
- code size: 4
- code start: 0x000000011d369e70
- code end (excl): 0x000000011d369e74
- checked ex length: 0
- linenumber start: 0x000000011d369e74
- localvar length: 1
- localvar start: 0x000000011d369e7a
(lldb) dis
-> 0x10584c8bf: movq %r13, -0x40(%rbp)
0x10584c8c3: movzwl 0x1(%r13), %edx
0x10584c8c8: movq -0x30(%rbp), %rcx
0x10584c8cc: shll $0x2, %edx
0x10584c8cf: movl 0x10(%rcx,%rdx,8), %ebx
0x10584c8d3: shrl $0x10, %ebx
0x10584c8d6: andl $0xff, %ebx
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8c3
-> 0x10584c8c3: movzwl 0x1(%r13), %edx
0x10584c8c8: movq -0x30(%rbp), %rcx
0x10584c8cc: shll $0x2, %edx
0x10584c8cf: movl 0x10(%rcx,%rdx,8), %ebx
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8c8
-> 0x10584c8c8: movq -0x30(%rbp), %rcx
0x10584c8cc: shll $0x2, %edx
0x10584c8cf: movl 0x10(%rcx,%rdx,8), %ebx
0x10584c8d3: shrl $0x10, %ebx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x00007000063a3650
rbx = 0x00000000000000b8
rcx = 0x0000000000000008
rdx = 0x0000000000000001
rdi = 0x0000000101807000
rsi = 0x0000000000000008
rbp = 0x00007000063a3698
rsp = 0x00007000063a3650
r8 = 0x0000000000002901
r9 = 0x0000000101807000
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x000000011d369e70
r14 = 0x00007000063a36a8
r15 = 0x0000000101807000
rip = 0x000000010584c8c8
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8cc
-> 0x10584c8cc: shll $0x2, %edx
0x10584c8cf: movl 0x10(%rcx,%rdx,8), %ebx
0x10584c8d3: shrl $0x10, %ebx
0x10584c8d6: andl $0xff, %ebx
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8cf
-> 0x10584c8cf: movl 0x10(%rcx,%rdx,8), %ebx
0x10584c8d3: shrl $0x10, %ebx
0x10584c8d6: andl $0xff, %ebx
0x10584c8dc: cmpl $0xb8, %ebx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x00007000063a3650
rbx = 0x00000000000000b8
rcx = 0x000000011d369f78
rdx = 0x0000000000000004
rdi = 0x0000000101807000
rsi = 0x0000000000000008
rbp = 0x00007000063a3698
rsp = 0x00007000063a3650
r8 = 0x0000000000002901
r9 = 0x0000000101807000
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x000000011d369e70
r14 = 0x00007000063a36a8
r15 = 0x0000000101807000
rip = 0x000000010584c8cf
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8d3
-> 0x10584c8d3: shrl $0x10, %ebx
0x10584c8d6: andl $0xff, %ebx
0x10584c8dc: cmpl $0xb8, %ebx
0x10584c8e2: je 0x10584cb5c
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8d6
-> 0x10584c8d6: andl $0xff, %ebx
0x10584c8dc: cmpl $0xb8, %ebx
0x10584c8e2: je 0x10584cb5c
0x10584c8e8: movl $0xb8, %ebx
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8dc
-> 0x10584c8dc: cmpl $0xb8, %ebx
0x10584c8e2: je 0x10584cb5c
0x10584c8e8: movl $0xb8, %ebx
0x10584c8ed: callq 0x10584c8f7
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8e2
-> 0x10584c8e2: je 0x10584cb5c
0x10584c8e8: movl $0xb8, %ebx
0x10584c8ed: callq 0x10584c8f7
0x10584c8f2: jmp 0x10584cb50
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584c8e8
-> 0x10584c8e8: movl $0xb8, %ebx
0x10584c8ed: callq 0x10584c8f7
0x10584c8f2: jmp 0x10584cb50
0x10584c8f7: movq %rbx, %rsi
Target 0: (java) stopped.
(lldb) b 0x10584cb5c
Breakpoint 4: address = 0x000000010584cb5c
(lldb) c
Process 3885 resuming
Process 3885 stopped
* thread #5, stop reason = breakpoint 4.1
frame #0: 0x000000010584cb5c
-> 0x10584cb5c: movq 0x18(%rcx,%rdx,8), %rbx
0x10584cb61: movl 0x28(%rcx,%rdx,8), %edx
0x10584cb65: shrl $0x1c, %edx
0x10584cb68: movabsq $0x10430c240, %r10 ; imm = 0x10430C240
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584cb61
-> 0x10584cb61: movl 0x28(%rcx,%rdx,8), %edx
0x10584cb65: shrl $0x1c, %edx
0x10584cb68: movabsq $0x10430c240, %r10 ; imm = 0x10430C240
0x10584cb72: movq (%r10,%rdx,8), %rdx
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584cb65
-> 0x10584cb65: shrl $0x1c, %edx
0x10584cb68: movabsq $0x10430c240, %r10 ; imm = 0x10430C240
0x10584cb72: movq (%r10,%rdx,8), %rdx
0x10584cb76: pushq %rdx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0x000000011d369f20
rcx = 0x000000011d369f78
rdx = 0x0000000090000000
rdi = 0x0000000101807000
rsi = 0x0000000000000008
rbp = 0x00007000063a3698
rsp = 0x00007000063a3650
r8 = 0x0000000000000000
r9 = 0x0000000114b01290
r10 = 0x0000000000000000
r11 = 0x0000000114b0128c
r12 = 0x0000000000000000
r13 = 0x000000011d369e70
r14 = 0x00007000063a36a8
r15 = 0x0000000101807000
rip = 0x000000010584cb65
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
Target 0: (java) stopped.
(lldb) p ((Method*)0x000000011d369f20)->print()
method
- this oop: 0x000000011d369f20
- method holder: 'com/hx/test05/Test18InvokeStatic'
- constants: 0x000000011d369c50 constant pool [23] 0x000000011d369c50 for 'com/hx/test05/Test18InvokeStatic' cache=0x000000011d369f78
- access: 0x9 public static
- name: 'foo'
- signature: '()V'
- max stack: 1
- max locals: 0
- size of params: 0
- method size: 11
- vtable index: -2
- i2i entry: 0x000000010582a700
- adapters: AHE@0x0000000101029760: 0x i2c: 0x00000001059d4ae0 c2i: 0x00000001059d4c16 c2iUV: 0x00000001059d4be9
- compiled entry 0x00000001059d4c16
- code size: 1
- code start: 0x000000011d369f18
- code end (excl): 0x000000011d369f19
- checked ex length: 0
- linenumber start: 0x000000011d369f19
- localvar length: 0
(lldb) b 0x10584ccd2
Breakpoint 5: address = 0x000000010584ccd2
(lldb) c
Process 3885 resuming
Process 3885 stopped
* thread #5, stop reason = breakpoint 5.1
frame #0: 0x000000010584ccd2
-> 0x10584ccd2: leaq 0x8(%rsp), %r13
0x10584ccd7: movq %r13, -0x10(%rbp)
0x10584ccdb: jmpq *0x50(%rbx)
0x10584ccde: movq %rsp, -0x28(%rsp)
Target 0: (java) stopped.
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584ccd7
-> 0x10584ccd7: movq %r13, -0x10(%rbp)
0x10584ccdb: jmpq *0x50(%rbx)
0x10584ccde: movq %rsp, -0x28(%rsp)
0x10584cce3: subq $0x80, %rsp
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0x000000011d369f20
rcx = 0x000000011d369f78
rdx = 0x000000010580b4a3
rdi = 0x0000000101807000
rsi = 0x0000000000000008
rbp = 0x00007000063a3698
rsp = 0x00007000063a3648
r8 = 0x0000000000000000
r9 = 0x0000000114b01290
r10 = 0x000000010430c240 libjvm.dylib`TemplateInterpreter::_invoke_return_entry
r11 = 0x0000000114b0128c
r12 = 0x0000000000000000
r13 = 0x00007000063a3650
r14 = 0x00007000063a36a8
r15 = 0x0000000101807000
rip = 0x000000010584ccd7
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010584ccdb
-> 0x10584ccdb: jmpq *0x50(%rbx)
0x10584ccde: movq %rsp, -0x28(%rsp)
0x10584cce3: subq $0x80, %rsp
0x10584ccea: movq %rax, 0x78(%rsp)
Target 0: (java) stopped.
(lldb) x 0x00007000063a3648 -c 0x100
0x7000063a3648: a3 b4 80 05 01 00 00 00 50 36 3a 06 00 70 00 00 ??......P6:..p..
0x7000063a3658: 70 9e 36 1d 01 00 00 00 a8 36 3a 06 00 70 00 00 p.6.....?6:..p..
0x7000063a3668: 78 9f 36 1d 01 00 00 00 00 00 00 00 00 00 00 00 x.6.............
0x7000063a3678: 58 7f bb 47 07 00 00 00 88 9e 36 1d 01 00 00 00 X.?G......6.....
0x7000063a3688: 50 36 3a 06 00 70 00 00 a8 36 3a 06 00 70 00 00 P6:..p..?6:..p..
0x7000063a3698: 10 37 3a 06 00 70 00 00 f1 09 80 05 01 00 00 00 .7:..p..?.......
0x7000063a36a8: a0 83 bb 47 07 00 00 00 a0 1f 00 00 03 00 00 00 ?.?G....?.......
0x7000063a36b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7000063a36c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7000063a36d8: 00 40 3a 06 00 70 00 00 20 38 3a 06 00 70 00 00 .@:..p.. 8:..p..
0x7000063a36e8: 50 3d 3a 06 00 70 00 00 0a 00 00 00 00 70 00 00 P=:..p.......p..
0x7000063a36f8: 88 9e 36 1d 01 00 00 00 00 a7 82 05 01 00 00 00 ..6......?......
0x7000063a3708: a0 3a 3a 06 00 70 00 00 e0 38 3a 06 00 70 00 00 ?::..p..?8:..p..
0x7000063a3718: 1d bb 8e 03 01 00 00 00 01 00 00 00 00 70 00 00 .?...........p..
0x7000063a3728: 00 70 80 01 01 00 00 00 50 37 3a 06 00 70 00 00 .p......P7:..p..
0x7000063a3738: 15 95 28 03 01 00 00 00 70 37 3a 06 00 70 00 00 ..(.....p7:..p..
(lldb) nexti
Process 3885 stopped
* thread #5, stop reason = instruction step over
frame #0: 0x000000010582a700
-> 0x10582a700: movq 0x10(%rbx), %rdx
0x10582a704: movzwl 0x34(%rdx), %ecx
0x10582a708: movzwl 0x32(%rdx), %edx
0x10582a70c: subl %ecx, %edx
Target 0: (java) stopped.
(lldb)
判断了一下 方法是否已经解析完成, 如果没有解析 则调用 InterpreterRuntime::resolve_from_cache 触发解析
然后 之后更新 rbx 为方法的 解析的目标地址, 然后 跳到给定的方法的 entry_point
entry_point 部分的调用代码 可以参考 15 main方法的栈帧信息
当然 其中还有一些 处理标志, 处理返回地址, profiling 方法的调用信息 等等
invokestatic 的汇编?
invokestatic 的汇编入口主要来自于 templateTable_x86.cpp invokestatic
templateTable_x86.cpp invokestatic
void TemplateTable::invokestatic(int byte_no)
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rbx); // get f1 Method*
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rbcp, false);
__ jump_from_interpreted(rbx, rax);
templateTable_x86.cpp prepare_invoke
void TemplateTable::prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index, // itable index, MethodType, etc.
Register recv, // if caller wants to see it
Register flags // if caller wants to test it
)
// determine flags
const Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokehandle = code == Bytecodes::_invokehandle;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
const bool load_receiver = (recv != noreg);
const bool save_flags = (flags != noreg);
assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal");
assert(flags == noreg || flags == rdx, "");
assert(recv == noreg || recv == rcx, "");
// setup registers & access constant pool cache
if (recv == noreg) recv = rcx;
if (flags == noreg) flags = rdx;
assert_different_registers(method, index, recv, flags);
// save 'interpreter return address'
__ save_bcp();
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
// maybe push appendix to arguments (just before return address)
if (is_invokedynamic || is_invokehandle)
Label L_no_push;
__ testl(flags, (1 << ConstantPoolCacheEntry::has_appendix_shift));
__ jcc(Assembler::zero, L_no_push);
// Push the appendix as a trailing parameter.
// This must be done before we get the receiver,
// since the parameter_size includes it.
__ push(rbx);
__ mov(rbx, index);
assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0");
__ load_resolved_reference_at_index(index, rbx);
__ pop(rbx);
__ push(index); // push appendix (MethodType, CallSite, etc.)
__ bind(L_no_push);
// load receiver if needed (after appendix is pushed so parameter size is correct)
// Note: no return address pushed yet
if (load_receiver)
__ movl(recv, flags);
__ andl(recv, ConstantPoolCacheEntry::parameter_size_mask);
const int no_return_pc_pushed_yet = -1; // argument slot correction before we push return address
const int receiver_is_at_end = -1; // back off one slot to get receiver
Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end);
__ movptr(recv, recv_addr);
__ verify_oop(recv);
if (save_flags)
__ movl(rbcp, flags);
// compute return type
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
// Make sure we don't need to mask flags after the above shift
ConstantPoolCacheEntry::verify_tos_state_shift();
// load return address
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
ExternalAddress table(table_addr);
LP64_ONLY(__ lea(rscratch1, table));
LP64_ONLY(__ movptr(flags, Address(rscratch1, flags, Address::times_ptr)));
NOT_LP64(__ movptr(flags, ArrayAddress(table, Address(noreg, flags, Address::times_ptr))));
// push return address
__ push(flags);
// Restore flags value from the constant pool cache, and restore rsi
// for later null checks. r13 is the bytecode pointer
if (save_flags)
__ movl(flags, rbcp);
__ restore_bcp();
templateTable_x86.cpp load_invoke_cp_cache_entry
void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
Register method,
Register itable_index,
Register flags,
bool is_invokevirtual,
bool is_invokevfinal, /*unused*/
bool is_invokedynamic)
// setup registers
const Register cache = rcx;
const Register index = rdx;
assert_different_registers(method, flags);
assert_different_registers(method, cache, index);
assert_different_registers(itable_index, flags);
assert_different_registers(itable_index, cache, index);
// determine constant pool cache field offsets
assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
const int method_offset = in_bytes(
ConstantPoolCache::base_offset() +
((byte_no == f2_byte)
? ConstantPoolCacheEntry::f2_offset()
: ConstantPoolCacheEntry::f1_offset()));
const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::flags_offset());
// access constant pool cache fields
const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset());
size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
resolve_cache_and_index(byte_no, cache, index, index_size);
__ movptr(method, Address(cache, index, Address::times_ptr, method_offset));
if (itable_index != noreg)
// pick up itable or appendix index from f2 also:
__ movptr(itable_index, Address(cache, index, Address::times_ptr, index_offset));
__ movl(flags, Address(cache, index, Address::times_ptr, flags_offset));
templateTable_x86.cpp resolve_cache_and_index
void TemplateTable::resolve_cache_and_index(int byte_no,
Register Rcache,
Register index,
size_t index_size)
const Register temp = rbx;
assert_different_registers(Rcache, index, temp);
Label resolved;
Bytecodes::Code code = bytecode();
switch (code)
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
__ cmpl(temp, code); // have we resolved this bytecode?
__ jcc(Assembler::equal, resolved);
// resolve first time through
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
__ movl(temp, code);
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
__ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
__ bind(resolved);
对于 invokestatic 生成出来的汇编如下
(lldb) dis -s 0x000000011f4178a0 -c 0x100
// set_vtos_entry_points 的前置处理
0x11f4178a0: pushq %rax
0x11f4178a1: jmp 0x11f4178df
0x11f4178a6: subq $0x8, %rsp
0x11f4178aa: vmovss %xmm0, (%rsp)
0x11f4178af: jmp 0x11f4178df
0x11f4178b4: subq $0x10, %rsp
0x11f4178b8: vmovsd %xmm0, (%rsp)
0x11f4178bd: jmp 0x11f4178df
0x11f4178c2: subq $0x10, %rsp
0x11f4178c6: movq %rax, (%rsp)
0x11f4178ca: movabsq $0x0, %r10
0x11f4178d4: movq %r10, 0x8(%rsp)
0x11f4178d9: jmp 0x11f4178df
0x11f4178de: pushq %rax
// save_bcp
0x11f4178df: movq %r13, -0x40(%rbp)
// get_cache_and_index_and_bytecode_at_bcp
// get_cache_and_index_at_bcp
// constantsPoolCache = -0x30(%rbp)
// index = 0x1(%r13) << 2 // 基于 constantsPoolCache.base() 的偏移
0x11f4178e3: movzwl 0x1(%r13), %edx
0x11f4178e8: movq -0x30(%rbp), %rcx
0x11f4178ec: shll $0x2, %edx
// if(cache_entry(thread).is_resolved(invokestatic)) goto 0x11f417b7c
// +0x10, 跳过 constantsPoolCache 头部 16byte
0x11f4178ef: movl 0x10(%rcx,%rdx,8), %ebx
0x11f4178f3: shrl $0x10, %ebx
0x11f4178f6: andl $0xff, %ebx
// have we resolved this bytecode?
0x11f4178fc: cmpl $0xb8, %ebx
0x11f417902: je 0x11f417b7c
// InterpreterRuntime::resolve_from_cache
0x11f417908: movl $0xb8, %ebx
0x11f41790d: callq 0x11f417917
0x11f417912: jmp 0x11f417b70
0x11f417917: movq %rbx, %rsi
0x11f41791a: leaq 0x8(%rsp), %rax
0x11f41791f: movq %r13, -0x40(%rbp)
0x11f417923: cmpq $0x0, -0x10(%rbp)
0x11f41792b: je 0x11f4179a8
0x11f417931: movq %rsp, -0x28(%rsp)
0x11f417936: subq $0x80, %rsp
0x11f41793d: movq %rax, 0x78(%rsp)
0x11f417942: movq %rcx, 0x70(%rsp)
0x11f417947: movq %rdx, 0x68(%rsp)
0x11f41794c: movq %rbx, 0x60(%rsp)
0x11f417951: movq %rbp, 0x50(%rsp)
0x11f417956: movq %rsi, 0x48(%rsp)
0x11f41795b: movq %rdi, 0x40(%rsp)
0x11f417960: movq %r8, 0x38(%rsp)
0x11f417965: movq %r9, 0x30(%rsp)
0x11f41796a: movq %r10, 0x28(%rsp)
0x11f41796f: movq %r11, 0x20(%rsp)
0x11f417974: movq %r12, 0x18(%rsp)
0x11f417979: movq %r13, 0x10(%rsp)
0x11f41797e: movq %r14, 0x8(%rsp)
0x11f417983: movq %r15, (%rsp)
0x11f417987: movabsq $0x1116984ed, %rdi ; imm = 0x1116984ED
0x11f417991: movabsq $0x11f417931, %rsi ; imm = 0x11F417931
0x11f41799b: movq %rsp, %rdx
0x11f41799e: andq $-0x10, %rsp
0x11f4179a2: callq 0x11116af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
0x11f4179a7: hlt
0x11f4179a8: pushq %r10
0x11f4179aa: cmpq -0xdb013c1(%rip), %r12 ; Universe::_narrow_ptrs_base
0x11f4179b1: je 0x11f417a2e
0x11f4179b7: movq %rsp, -0x28(%rsp)
0x11f4179bc: subq $0x80, %rsp
0x11f4179c3: movq %rax, 0x78(%rsp)
0x11f4179c8: movq %rcx, 0x70(%rsp)
0x11f4179cd: movq %rdx, 0x68(%rsp)
0x11f4179d2: movq %rbx, 0x60(%rsp)
0x11f4179d7: movq %rbp, 0x50(%rsp)
0x11f4179dc: movq %rsi, 0x48(%rsp)
0x11f4179e1: movq %rdi, 0x40(%rsp)
0x11f4179e6: movq %r8, 0x38(%rsp)
0x11f4179eb: movq %r9, 0x30(%rsp)
0x11f4179f0: movq %r10, 0x28(%rsp)
0x11f4179f5: movq %r11, 0x20(%rsp)
0x11f4179fa: movq %r12, 0x18(%rsp)
0x11f4179ff: movq %r13, 0x10(%rsp)
0x11f417a04: movq %r14, 0x8(%rsp)
0x11f417a09: movq %r15, (%rsp)
0x11f417a0d: movabsq $0x1116d4efc, %rdi ; imm = 0x1116D4EFC
0x11f417a17: movabsq $0x11f4179b7, %rsi ; imm = 0x11F4179B7
0x11f417a21: movq %rsp, %rdx
0x11f417a24: andq $-0x10, %rsp
0x11f417a28: callq 0x11116af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
0x11f417a2d: hlt
0x11f417a2e: popq %r10
0x11f417a30: movq %r15, %rdi
0x11f417a33: movq %rbp, 0x218(%r15)
0x11f417a3a: movq %rax, 0x208(%r15)
0x11f417a41: testl $0xf, %esp
0x11f417a47: je 0x11f417a5f
0x11f417a4d: subq $0x8, %rsp
0x11f417a51: callq 0x110ed41a0 ; InterpreterRuntime::resolve_from_cache at interpreterRuntime.cpp:868
0x11f417a56: addq $0x8, %rsp
0x11f417a5a: jmp 0x11f417a64
0x11f417a5f: callq 0x110ed41a0 ; InterpreterRuntime::resolve_from_cache at interpreterRuntime.cpp:868
0x11f417a64: pushq %rax
0x11f417a65: pushq %rdi
0x11f417a66: pushq %rsi
0x11f417a67: pushq %rdx
0x11f417a68: pushq %rcx
0x11f417a69: pushq %r8
0x11f417a6b: pushq %r9
0x11f417a6d: pushq %r10
0x11f417a6f: pushq %r11
0x11f417a71: testl $0xf, %esp
0x11f417a77: je 0x11f417a8f
0x11f417a7d: subq $0x8, %rsp
0x11f417a81: callq 0x110603ae0 ; Thread::current at thread.hpp:660
0x11f417a86: addq $0x8, %rsp
0x11f417a8a: jmp 0x11f417a94
0x11f417a8f: callq 0x110603ae0 ; Thread::current at thread.hpp:660
0x11f417a94: popq %r11
0x11f417a96: popq %r10
0x11f417a98: popq %r9
0x11f417a9a: popq %r8
0x11f417a9c: popq %rcx
0x11f417a9d: popq %rdx
0x11f417a9e: popq %rsi
0x11f417a9f: popq %rdi
0x11f417aa0: cmpq %rax, %r15
0x11f417aa3: je 0x11f417b20
0x11f417aa9: movq %rsp, -0x28(%rsp)
0x11f417aae: subq $0x80, %rsp
0x11f417ab5: movq %rax, 0x78(%rsp)
0x11f417aba: movq %rcx, 0x70(%rsp)
0x11f417abf: movq %rdx, 0x68(%rsp)
0x11f417ac4: movq %rbx, 0x60(%rsp)
0x11f417ac9: movq %rbp, 0x50(%rsp)
0x11f417ace: movq %rsi, 0x48(%rsp)
0x11f417ad3: movq %rdi, 0x40(%rsp)
0x11f417ad8: movq %r8, 0x38(%rsp)
0x11f417add: movq %r9, 0x30(%rsp)
0x11f417ae2: movq %r10, 0x28(%rsp)
0x11f417ae7: movq %r11, 0x20(%rsp)
0x11f417aec: movq %r12, 0x18(%rsp)
0x11f417af1: movq %r13, 0x10(%rsp)
0x11f417af6: movq %r14, 0x8(%rsp)
0x11f417afb: movq %r15, (%rsp)
0x11f417aff: movabsq $0x1116d5043, %rdi ; imm = 0x1116D5043
0x11f417b09: movabsq $0x11f417aa9, %rsi ; imm = 0x11F417AA9
0x11f417b13: movq %rsp, %rdx
0x11f417b16: andq $-0x10, %rsp
0x11f417b1a: callq 0x11116af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
0x11f417b1f: hlt
0x11f417b20: popq %rax
0x11f417b21: movabsq $0x0, %r10
0x11f417b2b: movq %r10, 0x208(%r15)
0x11f417b32: movabsq $0x0, %r10
0x11f417b3c: movq %r10, 0x218(%r15)
0x11f417b43: movabsq $0x0, %r10
0x11f417b4d: movq %r10, 0x210(%r15)
0x11f417b54: cmpq $0x0, 0x8(%r15)
0x11f417b5c: je 0x11f417b67
0x11f417b62: jmp 0x11f3d77a0
0x11f417b67: movq -0x40(%rbp), %r13
0x11f417b6b: movq -0x38(%rbp), %r14
0x11f417b6f: retq
// get_cache_and_index_at_bcp
0x11f417b70: movzwl 0x1(%r13), %edx
0x11f417b75: movq -0x30(%rbp), %rcx
0x11f417b79: shll $0x2, %edx
// rbx = method, rdx = flags
0x11f417b7c: movq 0x18(%rcx,%rdx,8), %rbx
0x11f417b81: movl 0x28(%rcx,%rdx,8), %edx
// compute return type
0x11f417b85: shrl $0x1c, %edx
// load return address
0x11f417b88: movabsq $0x11190c240, %r10 ; imm = 0x11190C240
0x11f417b92: movq (%r10,%rdx,8), %rdx
// push return address
0x11f417b96: pushq %rdx
// profile_call
0x11f417b97: movq -0x28(%rbp), %rax
0x11f417b9b: testq %rax, %rax
0x11f417b9e: je 0x11f417bb6
0x11f417ba4: addq $0x1, 0x8(%rax)
0x11f417ba9: sbbq $0x0, 0x8(%rax)
0x11f417bae: addq $0x10, %rax
0x11f417bb2: movq %rax, -0x28(%rbp)
// profile_arguments_type
0x11f417bb6: movq -0x28(%rbp), %rax
0x11f417bba: testq %rax, %rax
0x11f417bbd: je 0x11f417cf2
0x11f417bc3: cmpb $0xa, -0x10(%rax)
0x11f417bc7: jne 0x11f417cf2
0x11f417bcd: addq $0x8, %rax
0x11f417bd1: movq -0x8(%rax), %r13
0x11f417bd5: subl $0x0, %r13d
0x11f417bd9: cmpl $0x2, %r13d
0x11f417bdd: jl 0x11f417ce7
0x11f417be3: movq 0x10(%rbx), %r13
0x11f417be7: movzwl 0x34(%r13), %r13d
0x11f417bec: subq (%rax), %r13
0x11f417bef: subl $0x1, %r13d
0x11f417bf3: movq 0x8(%rsp,%r13,8), %r13
0x11f417bf8: testq %r13, %r13
0x11f417bfb: jne 0x11f417c07
0x11f417bfd: orq $0x1, 0x8(%rax)
0x11f417c05: jmp 0x11f417c54
0x11f417c07: movl 0x8(%r13), %r13d
0x11f417c0b: shlq $0x3, %r13
0x11f417c0f: xorq 0x8(%rax), %r13
0x11f417c13: testq $-0x4, %r13
0x11f417c1a: je 0x11f417c54
0x11f417c1c: testq $0x2, %r13
0x11f417c23: jne 0x11f417c54
0x11f417c25: cmpq $0x0, 0x8(%rax)
0x11f417c2d: je 0x11f417c50
0x11f417c2f: cmpq $0x1, 0x8(%rax)
0x11f417c37: je 0x11f417c50
0x11f417c39: xorq 0x8(%rax), %r13
0x11f417c3d: testq $-0x4, %r13
0x11f417c44: je 0x11f417c54
0x11f417c46: orq $0x2, 0x8(%rax)
0x11f417c4e: jmp 0x11f417c54
0x11f417c50: movq %r13, 0x8(%rax)
0x11f417c54: addq $0x10, %rax
0x11f417c58: movq -0x18(%rax), %r13
0x11f417c5c: subl $0x2, %r13d
0x11f417c60: cmpl $0x2, %r13d
0x11f417c64: jl 0x11f417ce7
0x11f417c6a: movq 0x10(%rbx), %r13
0x11f417c6e: movzwl 0x34(%r13), %r13d
0x11f417c73: subq (%rax), %r13
0x11f417c76: subl $0x1, %r13d
0x11f417c7a: movq 0x8(%rsp,%r13,8), %r13
0x11f417c7f: testq %r13, %r13
0x11f417c82: jne 0x11f417c8e
0x11f417c84: orq $0x1, 0x8(%rax)
0x11f417c8c: jmp 0x11f417cdb
0x11f417c8e: movl 0x8(%r13), %r13d
0x11f417c92: shlq $0x3, %r13
0x11f417c96: xorq 0x8(%rax), %r13
0x11f417c9a: testq $-0x4, %r13
0x11f417ca1: je 0x11f417cdb
0x11f417ca3: testq $0x2, %r13
0x11f417caa: jne 0x11f417cdb
0x11f417cac: cmpq $0x0, 0x8(%rax)
0x11f417cb4: je 0x11f417cd7
0x11f417cb6: cmpq $0x1, 0x8(%rax)
0x11f417cbe: je 0x11f417cd7
0x11f417cc0: xorq 0x8(%rax), %r13
0x11f417cc4: testq $-0x4, %r13
0x11f417ccb: je 0x11f417cdb
0x11f417ccd: orq $0x2, 0x8(%rax)
0x11f417cd5: jmp 0x11f417cdb
0x11f417cd7: movq %r13, 0x8(%rax)
0x11f417cdb: addq $0x10, %rax
0x11f417cdf: movq -0x28(%rax), %r13
0x11f417ce3: subl $0x4, %r13d
0x11f417ce7: shll $0x3, %r13d
0x11f417ceb: addq %r13, %rax
0x11f417cee: movq %rax, -0x28(%rbp)
// jump_from_interpreted
0x11f417cf2: leaq 0x8(%rsp), %r13
0x11f417cf7: movq %r13, -0x10(%rbp)
0x11f417cfb: jmpq *0x50(%rbx)
0x11f417cfe: int3
0x11f417cff: int3
0x11f417d00: int3
0x11f417d01: int3
0x11f417d02: int3
0x11f417d03: int3
0x11f417d04: int3
0x11f417d05: int3
0x11f417d06: int3
0x11f417d07: int3
0x11f417d08: int3
InterpreterRuntime::resolve_from_cache 的处理
这里面主要是 类, 方法 的相关 符号引用 替换为 直接引用, 以及 相关标记
加载方法的时候 会做一系列的校验处理
这部分的内容 暂时就到这里吧
添加于2020.07.04 - bytecodeInterpreter.cpp 中的逻辑代码
bytecodeInterpreter.cpp 中可读性更好的代码
CASE(_invokevirtual):
CASE(_invokespecial):
CASE(_invokestatic):
u2 index = Bytes::get_native_u2(pc+1);
ConstantPoolCacheEntry* cache = cp->entry_at(index);
// QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases
// out so c++ compiler has a chance for constant prop to fold everything possible away.
if (!cache->is_resolved((Bytecodes::Code)opcode))
CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
handle_exception);
cache = cp->entry_at(index);
istate->set_msg(call_method);
Method* callee;
// 省略部分 invokevirtual, invokespecial 的处理
istate->set_callee(callee);
istate->set_callee_entry_point(callee->from_interpreted_entry());
#ifdef VM_JVMTI
if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode())
istate->set_callee_entry_point(callee->interpreter_entry());
#endif /* VM_JVMTI */
istate->set_bcp_advance(3);
UPDATE_PC_AND_RETURN(0); // I'll be back...
完
参考
以上是关于23 方法调用的流程(invokestatic为例)的主要内容,如果未能解决你的问题,请参考以下文章