hotspot/src/share/vm/runtime/javaCalls.cpp
void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
methodHandle method = *m;
JavaThread* thread = (JavaThread*)THREAD;
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(thread->is_Java_thread(), "must be called by a java thread");
assert(method.not_null(), "must have a method to call");
assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation");
assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here");
{- -------------------------------------------
(1) (デバッグ用の処理) (CHECK_UNHANDLED_OOPS_ONLY 時にのみ実行) (See: UnhandledOops)
unhandled oop をクリアする (? #TODO)
---------------------------------------- -}
CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
// Verify the arguments
if (CheckJNICalls) {
args->verify(method, result->get_type(), thread);
}
else debug_only(args->verify(method, result->get_type(), thread));
{- -------------------------------------------
(1) もし呼び出し対象のメソッドが空であれば, 呼び出しても意味が無いので, ここでリターン
---------------------------------------- -}
// Ignore call if method is empty
if (method->is_empty_method()) {
assert(result->get_type() == T_VOID, "an empty method must return a void value");
return;
}
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
---------------------------------------- -}
#ifdef ASSERT
{ klassOop holder = method->method_holder();
// A klass might not be initialized since JavaCall's might be used during the executing of
// the <clinit>. For example, a Thread.start might start executing on an object that is
// not fully initialized! (bad Java programming style)
assert(instanceKlass::cast(holder)->is_linked(), "rewritting must have taken place");
}
#endif
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");
{- -------------------------------------------
(1) 呼び出し対象となっているメソッドが, 呼び出し前であってもコンパイルするべきメソッドの場合,
CompileBroker::compile_method() を呼んで JIT コンパイルを開始させる.
---------------------------------------- -}
if (CompilationPolicy::must_be_compiled(method)) {
CompileBroker::compile_method(method, InvocationEntryBci,
CompLevel_initial_compile,
methodHandle(), 0, "must_be_compiled", CHECK);
}
{- -------------------------------------------
(1) メソッドのエントリポイントを取得する.
(通常は methodOop の from_interpreted_entry フィールドのものを使用するが,
JVMTI の状況によっては, 実行がインタープリタのみに制限されることがある. (See: [here](no3059eFS.html) for details)
この場合には, 代わりに interpreter_entry フィールドのものを使用する.)
---------------------------------------- -}
// Since the call stub sets up like the interpreter we call the from_interpreted_entry
// so we can go compiled via a i2c. Otherwise initial entry method will always
// run interpreted.
address entry_point = method->from_interpreted_entry();
if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
entry_point = method->interpreter_entry();
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Figure out if the result value is an oop or not (Note: This is a different value
// than result_type. result_type will be T_INT of oops. (it is about size)
BasicType result_type = runtime_type_from(result);
bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY);
// NOTE: if we move the computation of the result_val_address inside
// the call to call_stub, the optimizer produces wrong code.
intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());
// Find receiver
Handle receiver = (!method->is_static()) ? args->receiver() : Handle();
{- -------------------------------------------
(1) もしスタック上の Yellow Page が無効にされていたら,
JavaThread::reguard_stack() を呼んで有効化しておく.
---------------------------------------- -}
// When we reenter Java, we need to reenable the yellow zone which
// might already be disabled when we are in VM.
if (thread->stack_yellow_zone_disabled()) {
thread->reguard_stack();
}
{- -------------------------------------------
(1) もしこの時点でスタック状の空き領域が shadow page として不十分な量であれば, StackOverflowError.
そうでなければ, os::bang_stack_shadow_pages() を呼んで十分な物理メモリを割り当てておく.
---------------------------------------- -}
// Check that there are shadow pages available before changing thread state
// to Java
if (!os::stack_shadow_pages_available(THREAD, method)) {
// Throw stack overflow exception with preinitialized exception.
Exceptions::throw_stack_overflow_exception(THREAD, __FILE__, __LINE__, method);
return;
} else {
// Touch pages checked if the OS needs them to be touched to be mapped.
os::bang_stack_shadow_pages();
}
{- -------------------------------------------
(1) StubRoutines::call_stub() が指しているコードにより,
指定の Java メソッドの呼び出しを行う.
呼び出しから返ってきたら, 返値がポインタ(オブジェクトや配列)の場合には
カレントスレッドの vm_result フィールドに入れておく.
(これは, 以下のブロックを抜ける際に Safepoint が発生しうるため.
どこかのフィールドに入れておかないと回収される恐れがある.)
---------------------------------------- -}
// do call
{ JavaCallWrapper link(method, receiver, result, CHECK);
{ HandleMark hm(thread); // HandleMark used by HandleMarkCleaner
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
);
result = link.result(); // circumvent MS C++ 5.0 compiler bug (result is clobbered across call)
// Preserve oop return value across possible gc points
if (oop_result_flag) {
thread->set_vm_result((oop) result->get_jobject());
}
}
} // Exit JavaCallWrapper (can block - potential return oop must be preserved)
{- -------------------------------------------
(1) (thread が stop() や suspend() されていないかチェックするための
assert があったようだがコメントアウトされている.
しかも, この assert は現実的じゃないみたいな指摘も付いている.)
---------------------------------------- -}
// Check if a thread stop or suspend should be executed
// The following assert was not realistic. Thread.stop can set that bit at any moment.
//assert(!thread->has_special_runtime_exit_condition(), "no async. exceptions should be installed");
{- -------------------------------------------
(1) 返値がポインタ(オブジェクトや配列)の場合には
カレントスレッドの vm_result フィールドに入れておいた返値を
カレントスレッドの jobject フィールドに入れ直す.
(vm_result フィールドの方は NULL でクリアしておく)
---------------------------------------- -}
// Restore possible oop return
if (oop_result_flag) {
result->set_jobject((jobject)thread->vm_result());
thread->set_vm_result(NULL);
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.