23 process of method invocation (invokestatic as an example)

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

15 stack frame information of main method

07 rewrite of runtime constant pool index

Keywords: Java static

Added by vboctor on Sat, 05 Feb 2022 14:17:07 +0200