[inside hotspot] java方法调用的StubCode (2)

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjgfg.html