hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
address generate_call_stub(address& return_address) {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
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");
{- -------------------------------------------
(1) (以下, StubCodeMark によるスタブ生成を行う) (See: StubCodeMark)
---------------------------------------- -}
StubCodeMark mark(this, "StubRoutines", "call_stub");
{- -------------------------------------------
(1) (ここからが生成するコードの始まり)
---------------------------------------- -}
address start = __ pc();
{- -------------------------------------------
(1) (変数宣言など)
(call_wrapper から thread までが, スタブコードに渡された引数の待避先)
(r15_save から rbx_save までが, callee save レジスタの待避先)
---------------------------------------- -}
// 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);
{- -------------------------------------------
(1) (以下で, スタブコードを生成する)
---------------------------------------- -}
// stub code
{- -------------------------------------------
(1) コード生成:
「rbp をスタック上に待避し, rbp の値を rsp の値に変更」
---------------------------------------- -}
__ enter();
{- -------------------------------------------
(1) コード生成:
「引数が入っているレジスタや callee save レジスタを待避するスペースが必要なので,
rsp を rsp_after_call_off 分だけずらしておく」
---------------------------------------- -}
__ subptr(rsp, -rsp_after_call_off * wordSize);
{- -------------------------------------------
(1) コード生成:
「レジスタに入っている引数の値をスタック上に待避しておく」
---------------------------------------- -}
// 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
{- -------------------------------------------
(1) コード生成:
「callee save レジスタをスタック上に待避しておく」
---------------------------------------- -}
// 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);
#ifdef _WIN64
for (int i = 6; i <= 15; i++) {
__ movdqu(xmm_save(i), as_XMMRegister(i));
}
const Address rdi_save(rbp, rdi_off * wordSize);
const Address rsi_save(rbp, rsi_off * wordSize);
__ movptr(rsi_save, rsi);
__ movptr(rdi_save, rdi);
#else
const Address mxcsr_save(rbp, mxcsr_off * wordSize);
{
Label skip_ldmx;
__ stmxcsr(mxcsr_save);
__ movl(rax, mxcsr_save);
__ andl(rax, MXCSR_MASK); // Only check control and mask bits
ExternalAddress mxcsr_std(StubRoutines::x86::mxcsr_std());
__ cmp32(rax, mxcsr_std);
__ jcc(Assembler::equal, skip_ldmx);
__ ldmxcsr(mxcsr_std);
__ bind(skip_ldmx);
}
#endif
{- -------------------------------------------
(1) コード生成:
「これから Java コードの実行が始まるので, G2_thread レジスタの値を適切に設定しておく.
(カレントスレッドに対応する JavaThread のアドレスが
第8引数として渡されているはずなので, それをロード)」
---------------------------------------- -}
// Load up thread register
__ movptr(r15_thread, thread);
{- -------------------------------------------
(1) コード生成:
「G6_heapbase レジスタに正しい値をセットしておく」
(See: [here](no289165bb.html) for details)
---------------------------------------- -}
__ reinit_heapbase();
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
コード生成: (デバッグ用の処理)
---------------------------------------- -}
#ifdef ASSERT
// make sure we have no pending exceptions
{
Label L;
__ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: entered with pending exception");
__ bind(L);
}
#endif
{- -------------------------------------------
(1) コード生成:
「呼び出す Java メソッドに引数がある場合は, スタック上にコピーしておく.
(これが, 呼び出した Java メソッドの局所変数領域(の一部)になる)」
(スタブコードが呼ばれた時点では, Java メソッド用の引数は JavaCallArguments オブジェクト内に格納されている.
そして, スタブコードの第6引数がその JavaCallArguments オブジェクトを指している.
局所変数領域は現在の SP の直下になるので, もし引数がある場合にはその位置にプッシュしていく)
---------------------------------------- -}
// pass parameters if any
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
{- -------------------------------------------
(1.1) (呼び出す Java メソッドの引数の個数が 0 ならば何もしない (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
{- -------------------------------------------
(1.1) (ここからがループの始まり. 全ての引数をスタック上にプッシュしていく)
---------------------------------------- -}
__ 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);
{- -------------------------------------------
(1.1) (ここまでがループ)
---------------------------------------- -}
{- -------------------------------------------
(1) (ここまでが引数をスタック上にコピーする処理)
---------------------------------------- -}
{- -------------------------------------------
(1) (以下で, 実際に Java メソッドを呼び出す)
---------------------------------------- -}
// call Java function
__ BIND(parameters_done);
{- -------------------------------------------
(1) コード生成:
「以下のレジスタに値をセットした後,
call 命令により, 第5引数で指定されたエントリポイントを呼び出す.
* rbx
第4引数で渡された methodOop のアドレスをセット
* r13
現在の rsp の値をセット (<= セットというか待避しておく処理) 」
---------------------------------------- -}
__ movptr(rbx, method); // get methodOop
__ movptr(c_rarg1, entry_point); // get entry_point
__ mov(r13, rsp); // set sender sp
BLOCK_COMMENT("call Java function");
__ call(c_rarg1);
{- -------------------------------------------
(1) (デバッグ用の処理) (See: BLOCK_COMMENT)
---------------------------------------- -}
BLOCK_COMMENT("call_stub_return_address:");
{- -------------------------------------------
(1) この時点でのコードのアドレスを取得し, 引数で渡された return_pc に記録しておく.
(これは, 上の call による呼び出しのリターンアドレスに相当.
return_pc は参照渡しであり, この値は呼び出し元から使用される)
---------------------------------------- -}
return_address = __ pc();
{- -------------------------------------------
(1) コード生成:
「呼び出した Java メソッドの返値を, 第2引数で指定されたアドレスに書き込む.
(なお, 返値の型に応じて適切なストア命令を実行する.
返値の型に関する情報は第3引数で渡されてくるので, その情報を動的にチェックして適切なストア命令を選ぶ)」
---------------------------------------- -}
// 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);
{- -------------------------------------------
(1.1) (ここが T_INT だった場合の処理.
それ以外のケースの処理 (is_long ラベル, is_float ラベル, is_double ラベル) は
この関数の末尾で生成されている)
---------------------------------------- -}
// handle T_INT case
__ movl(Address(c_rarg0, 0), rax);
__ BIND(exit);
{- -------------------------------------------
(1) コード生成:
「(この時点では引数をプッシュした分だけ rsp の値が変わってしまっているので)
rsp を引数をプッシュする前の値に戻しておく.」
---------------------------------------- -}
// pop parameters
__ lea(rsp, rsp_after_call);
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
コード生成: (デバッグ用の処理)
---------------------------------------- -}
#ifdef ASSERT
// verify that threads correspond
{
Label L, S;
__ cmpptr(r15_thread, thread);
__ jcc(Assembler::notEqual, S);
__ get_thread(rbx);
__ cmpptr(r15_thread, rbx);
__ jcc(Assembler::equal, L);
__ bind(S);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: threads must correspond");
__ bind(L);
}
#endif
{- -------------------------------------------
(1) コード生成:
「callee save レジスタの値を復帰させる」
---------------------------------------- -}
// restore regs belonging to calling function
#ifdef _WIN64
for (int i = 15; i >= 6; 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);
#ifdef _WIN64
__ movptr(rdi, rdi_save);
__ movptr(rsi, rsi_save);
#else
__ ldmxcsr(mxcsr_save);
#endif
{- -------------------------------------------
(1) コード生成:
「rsp の値を, スタブコードが呼び出された時点の値に戻す」
---------------------------------------- -}
// restore rsp
__ addptr(rsp, -rsp_after_call_off * wordSize);
{- -------------------------------------------
(1) コード生成:
「rbp の値を元に戻し, リターンする」
---------------------------------------- -}
// return
__ pop(rbp);
__ ret(0);
{- -------------------------------------------
(1) コード生成:
「(以下は, 返値が T_INT 以外の場合の処理)
それぞれの型に応じた適切なストア命令を実行した後, exit ラベルに飛んで本筋の処理に合流する.」
---------------------------------------- -}
// handle return types different from T_INT
__ BIND(is_long);
__ movq(Address(c_rarg0, 0), rax);
__ jmp(exit);
__ BIND(is_float);
__ movflt(Address(c_rarg0, 0), xmm0);
__ jmp(exit);
__ BIND(is_double);
__ movdbl(Address(c_rarg0, 0), xmm0);
__ jmp(exit);
{- -------------------------------------------
(1) 以上で生成したコードの先頭アドレスをリターン.
---------------------------------------- -}
return start;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.