call_helper又可以分为两步,第一步判断一下方法是否为空,是否可以JIT编译,是否还有栈空间可以等,第二步StubRoutines::call_stub()实际调用os+cpu限定的方法。
这个StubRoutines::call_stub()返回的是一个函数指针,指向的是平台特定的方法,所以这段代码:
StubRoutines::call_stub()(
(address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
result_val_address,
// see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);
call_stub()返回一个函数指针,指向依赖于操作系统和cpu架构的特定的方法,原因很简单,要执行native代码,得看看是什么cpu架构以便确定寄存器,看看什么os以便确定ABI。
然后传递8个参数到这个方法里面并执行这个方法。那么这个方法是什么呢?进入stubRoutines.cpp便知是StubRoutines::_call_stub_entry。
2. windows+x86_64的stubGenerator
以x64为例,hotspot\src\cpu\x86\vm\stubGenerator_x86_64.cpp的generate_call_stub()会负责初始化StubRoutines::_call_stub_entry函数,使用参数命令
-XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode可以输出generate_call_stub方法生成的汇编,对照着看非常舒服:
address generate_call_stub(address& return_address) {
assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 &&
(int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off,
"adjust this code");
StubCodeMark mark(this, "StubRoutines", "call_stub");
address start = __ pc();
// same as in generate_catch_exception()!
const Address rsp_after_call(rbp, rsp_after_call_off * wordSize);
const Address call_wrapper (rbp, call_wrapper_off * wordSize);
const Address result
(rbp, result_off
* wordSize);
const Address result_type (rbp, result_type_off * wordSize);
const Address method
(rbp, method_off
* wordSize);
const Address entry_point (rbp, entry_point_off * wordSize);
const Address parameters (rbp, parameters_off
* wordSize);
const Address parameter_size(rbp, parameter_size_off * wordSize);
// same as in generate_catch_exception()!
const Address thread
(rbp, thread_off
* wordSize);
const Address r15_save(rbp, r15_off * wordSize);
const Address r14_save(rbp, r14_off * wordSize);
const Address r13_save(rbp, r13_off * wordSize);
const Address r12_save(rbp, r12_off * wordSize);
const Address rbx_save(rbp, rbx_off * wordSize);
// stub code
__ enter();
__ subptr(rsp, -rsp_after_call_off * wordSize);
StubRoutines::call_stub [0x0000026b0a5d09d7, 0x0000026b0a5d0b44[ (365 bytes)
0x0000026b0a5d09d7: push %rbp
0x0000026b0a5d09d8: mov %rsp,%rbp
0x0000026b0a5d09db: sub $0x1d8,%rsp
// save register parameters
#ifndef _WIN64
__ movptr(parameters, c_rarg5); // parameters
__ movptr(entry_point, c_rarg4); // entry_point
#endif
__ movptr(method,
c_rarg3); // method
__ movl(result_type, c_rarg2); // result type
__ movptr(result,
c_rarg1); // result
__ movptr(call_wrapper, c_rarg0); // call wrapper
// r9方法,r8d返回值类型,rdx,返回值,rcx即JavaCallsWrapper
0x0000026b0a5d09e2: mov %r9,0x28(%rbp)
0x0000026b0a5d09e6: mov %r8d,0x20(%rbp)
0x0000026b0a5d09ea: mov %rdx,0x18(%rbp)
0x0000026b0a5d09ee: mov %rcx,0x10(%rbp)
// save regs belonging to calling function
__ movptr(rbx_save, rbx);
__ movptr(r12_save, r12);
__ movptr(r13_save, r13);
__ movptr(r14_save, r14);
__ movptr(r15_save, r15);
if (UseAVX > 2) {
__ movl(rbx, 0xffff);
__ kmovwl(k1, rbx);
}
#ifdef _WIN64
int last_reg = 15;
if (UseAVX > 2) {
last_reg = 31;
}
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vextractf32x4(xmm_save(i), as_XMMRegister(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(xmm_save(i), as_XMMRegister(i));
}
}
// caller-save 寄存器
0x0000026b0a5d09f2: mov %rbx,-0x8(%rbp)
0x0000026b0a5d09f6: mov %r12,-0x20(%rbp)
0x0000026b0a5d09fa: mov %r13,-0x28(%rbp)
0x0000026b0a5d09fe: mov %r14,-0x30(%rbp)
0x0000026b0a5d0a02: mov %r15,-0x38(%rbp)
0x0000026b0a5d0a06: vmovdqu %xmm6,-0x48(%rbp)
0x0000026b0a5d0a0b: vmovdqu %xmm7,-0x58(%rbp)
0x0000026b0a5d0a10: vmovdqu %xmm8,-0x68(%rbp)
0x0000026b0a5d0a15: vmovdqu %xmm9,-0x78(%rbp)
0x0000026b0a5d0a1a: vmovdqu %xmm10,-0x88(%rbp)
0x0000026b0a5d0a22: vmovdqu %xmm11,-0x98(%rbp)
0x0000026b0a5d0a2a: vmovdqu %xmm12,-0xa8(%rbp)
0x0000026b0a5d0a32: vmovdqu %xmm13,-0xb8(%rbp)
0x0000026b0a5d0a3a: vmovdqu %xmm14,-0xc8(%rbp)
0x0000026b0a5d0a42: vmovdqu %xmm15,-0xd8(%rbp)
const Address rdi_save(rbp, rdi_off * wordSize);
const Address rsi_save(rbp, rsi_off * wordSize);
__ movptr(rsi_save, rsi);
__ movptr(rdi_save, rdi);
// rsi rdi
0x0000026b0a5d0a4a: mov %rsi,-0x10(%rbp)
0x0000026b0a5d0a4e: mov %rdi,-0x18(%rbp)
// Load up thread register
__ movptr(r15_thread, thread);
__ reinit_heapbase();
// 线程寄存器
0x0000026b0a5d0a52: mov 0x48(%rbp),%r15
0x0000026b0a5d0a56: movabs $0x7ffe4c5b2be8,%r10
0x0000026b0a5d0a60: mov (%r10),%r12
// pass parameters if any
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
__ movl(c_rarg3, parameter_size);
__ testl(c_rarg3, c_rarg3);
__ jcc(Assembler::zero, parameters_done);
Label loop;
__ movptr(c_rarg2, parameters);
// parameter pointer
__ movl(c_rarg1, c_rarg3);
// parameter counter is in c_rarg1
__ BIND(loop);
__ movptr(rax, Address(c_rarg2, 0));// get parameter
__ addptr(c_rarg2, wordSize);
// advance to next parameter
__ decrementl(c_rarg1);
// decrement counter
__ push(rax);
// pass parameter
__ jcc(Assembler::notZero, loop);
// 这里是个循环,用于传递参数,相当于
// while(r9d){
// rax = *arg
// push_arg(rax)
// arg++; // ptr++
// r9d--; // counter--
// }
0x0000026b0a5d0a63: mov 0x40(%rbp),%r9d
0x0000026b0a5d0a67: test %r9d,%r9d
0x0000026b0a5d0a6a: je
0x0000026b0a5d0a83
0x0000026b0a5d0a70: mov 0x38(%rbp),%r8
0x0000026b0a5d0a74: mov %r9d,%edx
0x0000026b0a5d0a77: mov (%r8),%rax
0x0000026b0a5d0a7a: add $0x8,%r8
0x0000026b0a5d0a7e: dec %edx
0x0000026b0a5d0a80: push %rax
0x0000026b0a5d0a81: jne 0x0000026b0a5d0a77
// call Java function
__ BIND(parameters_done);
__ movptr(rbx, method);
// get Method*
__ movptr(c_rarg1, entry_point); // get entry_point
__ mov(r13, rsp);
// set sender sp
BLOCK_COMMENT("call Java function");
__ call(c_rarg1);
// [!!]调用java方法
0x0000026b0a5d0a83: mov 0x28(%rbp),%rbx
0x0000026b0a5d0a87: mov 0x30(%rbp),%rdx
0x0000026b0a5d0a8b: mov %rsp,%r13
0x0000026b0a5d0a8e: callq *%rdx
BLOCK_COMMENT("call_stub_return_address:");
return_address = __ pc();
// store result depending on type (everything that is not
// T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
__ movptr(c_rarg0, result);
Label is_long, is_float, is_double, exit;
__ movl(c_rarg1, result_type);
__ cmpl(c_rarg1, T_OBJECT);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_LONG);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_FLOAT);
__ jcc(Assembler::equal, is_float);
__ cmpl(c_rarg1, T_DOUBLE);
__ jcc(Assembler::equal, is_double);
// handle T_INT case
__ movl(Address(c_rarg0, 0), rax);
__ BIND(exit);
// pop parameters
__ lea(rsp, rsp_after_call);
// 储存java方法返回值并弹出参数,这里弹出操作即移动一下rsp指针
0x0000026b0a5d0a90: mov 0x18(%rbp),%rcx
0x0000026b0a5d0a94: mov 0x20(%rbp),%edx
0x0000026b0a5d0a97: cmp $0xc,%edx
0x0000026b0a5d0a9a: je
0x0000026b0a5d0b30
0x0000026b0a5d0aa0: cmp $0xb,%edx
0x0000026b0a5d0aa3: je
0x0000026b0a5d0b30
0x0000026b0a5d0aa9: cmp $0x6,%edx
0x0000026b0a5d0aac: je
0x0000026b0a5d0b35
0x0000026b0a5d0ab2: cmp $0x7,%edx
0x0000026b0a5d0ab5: je
0x0000026b0a5d0b3b
0x0000026b0a5d0abb: mov %eax,(%rcx)
0x0000026b0a5d0abd: lea -0x1d8(%rbp),%rsp
// restore regs belonging to calling function
#ifdef _WIN64
// emit the restores for xmm regs
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vinsertf32x4(as_XMMRegister(i), as_XMMRegister(i), xmm_save(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(as_XMMRegister(i), xmm_save(i));
}
}
#endif
__ movptr(r15, r15_save);
__ movptr(r14, r14_save);
__ movptr(r13, r13_save);
__ movptr(r12, r12_save);
__ movptr(rbx, rbx_save);
__ movptr(rdi, rdi_save);
__ movptr(rsi, rsi_save);
// 恢复之前保存的caller-save寄存器
0x0000026b0a5d0ac4: vmovdqu -0x48(%rbp),%xmm6
0x0000026b0a5d0ac9: vmovdqu -0x58(%rbp),%xmm7
0x0000026b0a5d0ace: vmovdqu -0x68(%rbp),%xmm8
0x0000026b0a5d0ad3: vmovdqu -0x78(%rbp),%xmm9
0x0000026b0a5d0ad8: vmovdqu -0x88(%rbp),%xmm10
0x0000026b0a5d0ae0: vmovdqu -0x98(%rbp),%xmm11
0x0000026b0a5d0ae8: vmovdqu -0xa8(%rbp),%xmm12
0x0000026b0a5d0af0: vmovdqu -0xb8(%rbp),%xmm13
0x0000026b0a5d0af8: vmovdqu -0xc8(%rbp),%xmm14
0x0000026b0a5d0b00: vmovdqu -0xd8(%rbp),%xmm15
0x0000026b0a5d0b08: mov -0x38(%rbp),%r15
0x0000026b0a5d0b0c: mov -0x30(%rbp),%r14
0x0000026b0a5d0b10: mov -0x28(%rbp),%r13
0x0000026b0a5d0b14: mov -0x20(%rbp),%r12
0x0000026b0a5d0b18: mov -0x8(%rbp),%rbx
0x0000026b0a5d0b1c: mov -0x18(%rbp),%rdi
0x0000026b0a5d0b20: mov -0x10(%rbp),%rsi
// restore rsp
__ addptr(rsp, -rsp_after_call_off * wordSize);
// return
__ pop(rbp);
__ ret(0);
// 结束__call_stub_entry这个函数
0x0000026b0a5d0b24: add $0x1d8,%rsp
0x0000026b0a5d0b2b: vzeroupper
0x0000026b0a5d0b2e: pop %rbp
0x0000026b0a5d0b2f: retq