;; prepare entry: : mov 0x28(%rbp),%rbx 0x0000000002400611: mov 0x30(%rbp),%rdx 0x0000000002400615: mov %rsp,%r13 //保存栈顶指针 ;; jump to run Java method: 0x0000000002400618: callq *%rdx
6.准备保存返回结果,这里需要先根据不同的返回类型取出返回结果,然后保存到返回结果指针所指向的位置
;; prepare to save result: : mov 0x18(%rbp),%rcx 0x000000000240061e: mov 0x20(%rbp),%edx ;; handle result accord to different result_type: 0x0000000002400621: cmp $0xc,%edx 0x0000000002400624: je 0x00000000024006b7 0x000000000240062a: cmp $0xb,%edx 0x000000000240062d: je 0x00000000024006b7 0x0000000002400633: cmp $0x6,%edx 0x0000000002400636: je 0x00000000024006bc 0x000000000240063c: cmp $0x7,%edx 0x000000000240063f: je 0x00000000024006c2 ;; save result for the other result_type: 0x0000000002400645: mov %eax,(%rcx)
下面分别为返回结果类型为long、float、double的情况
;; long 类型返回结果保存: 0x00000000024006b7: mov %rax,(%rcx) 0x00000000024006ba: jmp 0x0000000002400647 ;; float 类型返回结果保存: 0x00000000024006bc: vmovss %xmm0,(%rcx) 0x00000000024006c0: jmp 0x0000000002400647 ;; double 类型返回结果保存: 0x00000000024006c2: vmovsd %xmm0,(%rcx) 0x00000000024006c6: jmpq 0x0000000002400647
7.被调用者保存寄存器的恢复,以及栈指针的复位
;; restore registers: 0x0000000002400647: lea -0xd8(%rbp),%rsp 0x000000000240064e: vmovdqu -0xd8(%rbp),%xmm15 0x0000000002400656: vmovdqu -0xc8(%rbp),%xmm14 0x000000000240065e: vmovdqu -0xb8(%rbp),%xmm13 0x0000000002400666: vmovdqu -0xa8(%rbp),%xmm12 0x000000000240066e: vmovdqu -0x98(%rbp),%xmm11 0x0000000002400676: vmovdqu -0x88(%rbp),%xmm10 0x000000000240067e: vmovdqu -0x78(%rbp),%xmm9 0x0000000002400683: vmovdqu -0x68(%rbp),%xmm8 0x0000000002400688: vmovdqu -0x58(%rbp),%xmm7 0x000000000240068d: vmovdqu -0x48(%rbp),%xmm6 0x0000000002400692: mov -0x38(%rbp),%r15 0x0000000002400696: mov -0x30(%rbp),%r14 0x000000000240069a: mov -0x28(%rbp),%r13 0x000000000240069e: mov -0x20(%rbp),%r12 0x00000000024006a2: mov -0x8(%rbp),%rbx 0x00000000024006a6: mov -0x18(%rbp),%rdi 0x00000000024006aa: mov -0x10(%rbp),%rsi ;; back to old(caller) stack frame: : pop %rbp : retq
归纳出call_stub栈结构如下:
8.对于不同的Java方法,虚拟机在初始化时会生成不同的方法入口例程
(method entry point)来准备栈帧,这里以较常被使用的zerolocals方法入口为例,分析Java方法的栈帧结构与调用过程,入口例程目标代码的产生在InterpreterGenerator::generate_normal_entry()中:
(1).根据之前的分析,初始的栈结构如下:
获取传入参数数量到rcx中: