preface
I saw an article before java reflection calls private related
A screenshot of the boss inside shows why the generated method accessor generated at runtime can access all methods
Hehe, to tell you the truth, this problem has not been considered before
However, the screenshot of the boss is still a little abstract and is not connected with the context of the specific runtime
But before checking the whole process, we need to know what the method call instruction handles
Hehe, this is the focus of this article
This article mainly takes invokestatic as an example to walk through the general process
For some basic knowledge, you can refer to the article and the reference article of the article
14 debugging of compilation and execution of HelloWorld bytecode
15 stack frame information of main method
07 rewrite of runtime constant pool index
The following code, screenshot based on jdk9
test case
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() { } }
Hehe, we mainly follow the whole process of invokestatic, so this test case is very simple
The corresponding bytecode information is as follows, which may need to be used for reference below
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"
Debugging based on lldb
It's similar to the reference series of articles. Let's debug lldb first, and then analyze the relevant code
(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)
Judge whether the method has been parsed. If not, call interpreter Runtime:: resolve_ from_ Cache trigger resolution
Then update rbx to the resolved target address of the method, and then jump to the entry of the given method_ point
entry_ The calling code of the point part can be referred to 15 stack frame information of main method
Of course, there are also some processing flags, processing return addresses, calling information of profiling methods, and so on
invokestatic assembly?
The assembly entry of invokestatic mainly comes from 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); }
For invokestatic, the generated assembly is as follows
(lldb) dis -s 0x000000011f4178a0 -c 0x100 // set_ vtos_ entry_ Preprocessing of 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 / / based on constantspoolcache Offset of 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, skip constantsPoolCache header 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 processing
This is mainly the replacement of relevant symbolic references of classes and methods with direct references, as well as relevant tags
When loading methods, a series of verification processing will be done
That's all for now
Added on July 4, 2020 - bytecodeinterpreter Logic code in CPP
bytecodeInterpreter. Better readable code in 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; // Omit the processing of some invokevirtual and 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... } }
Finish
reference resources
java reflection calls private related
14 debugging of compilation and execution of HelloWorld bytecode