hotspot/src/cpu/x86/vm/assembler_x86.cpp
void MacroAssembler::call_VM_base(Register oop_result,
Register java_thread,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
{- -------------------------------------------
(1) (引数でカレントスレッドの JavaThread オブジェクトを指したレジスタ(java_thread)が指定されていなければ,
以下のレジスタを代わりに使うことにする.
* 64bit の場合
r15_thread レジスタ
* 32bit の場合
rdi レジスタ
なお, 32bit の場合には, MacroAssembler::get_thread() が生成するコードで
rdi にスレッドのアドレスをロードする処理も行っておく)
(といっても, 64bit 版の場合は明示的に r15_thread が指定されていることが多いような気がするが...
まぁ全部調べたわけじゃないが... #TODO)
---------------------------------------- -}
// determine java_thread register
if (!java_thread->is_valid()) {
#ifdef _LP64
java_thread = r15_thread;
#else
java_thread = rdi;
get_thread(java_thread);
#endif // LP64
}
{- -------------------------------------------
(1) (引数で last_java_sp に使うレジスタが指定されていなければ, SP を使うこととする)
(通常は SP でも良さそうだが,
last_java_sp を元に last_Java_pc を取得できるように調整していたりするので
このように指定できるようになっている模様.
See: MacroAssembler::call_VM_helper())
---------------------------------------- -}
// determine last_java_sp register
if (!last_java_sp->is_valid()) {
last_java_sp = rsp;
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// debugging support
assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
LP64_ONLY(assert(java_thread == r15_thread, "unexpected register"));
#ifdef ASSERT
LP64_ONLY(if (UseCompressedOops) verify_heapbase("call_VM_base");)
#endif // ASSERT
assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result");
assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp");
{- -------------------------------------------
(1) コード生成:
「呼び出し時の第一引数として,
カレントスレッドを表す JavaThread をセットする.
(32bit の場合はスタックに積む. 64bit なら c_rarg0 レジスタにセット)」
(せっかく MacroAssembler::pass_arg0() があるんだから使えばいいのに...)
---------------------------------------- -}
// push java thread (becomes first argument of C function)
NOT_LP64(push(java_thread); number_of_arguments++);
LP64_ONLY(mov(c_rarg0, r15_thread));
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// set last Java frame before call
assert(last_java_sp != rbp, "can't use ebp/rbp");
{- -------------------------------------------
(1) コード生成:
「MacroAssembler::call_VM_leaf_base() が生成するコードにより,
引数で指定されたエントリポイントを呼び出す.」
(なお, 呼び出しの前後で last_Java_sp への SP のセット/クリアも行っている. (set_last_Java_frame/reset_last_Java_frame))
(また, 呼び出し後で引数で指定された java_thread レジスタの復帰も行っている)
---------------------------------------- -}
// Only interpreter should have to set fp
set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);
// do the call, remove parameters
MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
// restore the thread (cannot use the pushed argument since arguments
// may be overwritten by C code generated by an optimizing compiler);
// however can use the register value directly if it is callee saved.
if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) {
// rdi & rsi (also r15) are callee saved -> nothing to do
#ifdef ASSERT
guarantee(java_thread != rax, "change this code");
push(rax);
{ Label L;
get_thread(rax);
cmpptr(java_thread, rax);
jcc(Assembler::equal, L);
stop("MacroAssembler::call_VM_base: rdi not callee saved?");
bind(L);
}
pop(rax);
#endif
} else {
get_thread(java_thread);
}
// reset last Java frame
// Only interpreter should have to clear fp
reset_last_Java_frame(java_thread, true, false);
{- -------------------------------------------
(1) コード生成: (なお, CC_INTERP が #define されている場合には生成しない)
「InterpreterMacroAssembler::check_and_handle_popframe() や
InterpreterMacroAssembler::check_and_handle_earlyret() が生成したコードにより,
JVMTI の PopFrame() や ForceEarlyReturn*() が呼ばれていないかをチェックする.
もし呼ばれていれば, ここでそれぞれの処理ルーチンへジャンプする.」
(See: [here](no3059hIn.html) for details)
---------------------------------------- -}
#ifndef CC_INTERP
// C++ interp handles this in the interpreter
check_and_handle_popframe(java_thread);
check_and_handle_earlyret(java_thread);
#endif /* CC_INTERP */
{- -------------------------------------------
(1) コード生成: (ただし, 引数で例外チェックコードを生成するように
指定されている場合(check_exeptions が true の場合)にのみ生成する)
「カレントスレッドの pending_exception フィールドを確認する.
もし 0 でなければ, 例外が発生したということなので
StubRoutines::forward_exception_entry() が指しているコードを呼び出す.
(0 であればこのままフォールスルー)」
(See: [here](no3059uSt.html) for details)
---------------------------------------- -}
if (check_exceptions) {
// check for pending exceptions (java_thread is set upon return)
cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
#ifndef _LP64
jump_cc(Assembler::notEqual,
RuntimeAddress(StubRoutines::forward_exception_entry()));
#else
// This used to conditionally jump to forward_exception however it is
// possible if we relocate that the branch will not reach. So we must jump
// around so we can always reach
Label ok;
jcc(Assembler::equal, ok);
jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
bind(ok);
#endif // LP64
}
{- -------------------------------------------
(1) コード生成: (ただし, 引数で指定された oop_result が valid でなければ生成しない)
「呼び出し結果(返値)をカレントスレッドの JavaThread::vm_result フィールドから取り出し,
引数で指定された oop_result レジスタ内に格納する.
(ついでに, 取り出した後で JavaThread::vm_result フィールドは 0 クリアしておく)」
---------------------------------------- -}
// get oop result if there is one and reset the value in the thread
if (oop_result->is_valid()) {
movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset()));
movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD);
verify_oop(oop_result, "broken oop in call_VM_base");
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.