hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode))
{- -------------------------------------------
(1) (変数宣言など)
(receiver は, 対象のメソッドのレシーバー情報)
---------------------------------------- -}
// extract receiver from the outgoing argument list if necessary
Handle receiver(thread, NULL);
if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
ResourceMark rm(thread);
methodHandle m (thread, method(thread));
Bytecode_invoke call(m, bci(thread));
Symbol* signature = call.signature();
receiver = Handle(thread,
thread->last_frame().interpreter_callee_receiver(signature));
assert(Universe::heap()->is_in_reserved_or_null(receiver()),
"sanity check");
assert(receiver.is_null() ||
Universe::heap()->is_in_reserved(receiver->klass()),
"sanity check");
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// resolve method
CallInfo info;
constantPoolHandle pool(thread, method(thread)->constants());
{- -------------------------------------------
(1) LinkResolver::resolve_invoke() を呼んで, メソッド情報の解決を行う.
(引数で渡した CallInfo オブジェクト(以下の info)に, 解決結果がセットされて返される)
(もしおかしなメソッドアクセスであれば, ここで例外が出る)
(なお, 解決中にメソッドが redefine された場合は, 解決処理をやり直す.
やり直しの解決処理も redefine と重なった場合は, 最新の情報が取れるまでやり直す.
(現状の実装ではやり直しは最大 100 回まで. 100 回以上ぶつかるのはバグの可能性が高いとのこと))
(なお, この処理の間は SingleStep イベントは無効にしている. (See: JvmtiHideSingleStepping))
---------------------------------------- -}
{
JvmtiHideSingleStepping jhss(thread);
LinkResolver::resolve_invoke(info, receiver, pool,
get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
if (JvmtiExport::can_hotswap_or_post_breakpoint()) {
int retry_count = 0;
while (info.resolved_method()->is_old()) {
// It is very unlikely that method is redefined more than 100 times
// in the middle of resolve. If it is looping here more than 100 times
// means then there could be a bug here.
guarantee((retry_count++ < 100),
"Could not resolve to latest version of redefined method");
// method is redefined in the middle of resolve so re-try.
LinkResolver::resolve_invoke(info, receiver, pool,
get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
}
}
} // end JvmtiHideSingleStepping
{- -------------------------------------------
(1) もし, 対象スレッドが現在実行しているバイトコード箇所の
CPCache エントリが既に resolve 済みであれば,
(することはないので) ここでリターン.
---------------------------------------- -}
// check if link resolution caused cpCache to be updated
if (already_resolved(thread)) return;
{- -------------------------------------------
(1) 対象スレッドが現在実行しているバイトコード箇所の CPCache エントリに
解決結果をセットする.
なお, この処理はバイトコード種別(及び対象クラス)に応じて以下のように行う.
* invokeinterface で, 対象クラスが java.lang.Object の場合:
ConstantPoolCacheEntry::set_method() でセットする
(これは Java 仮想マシン仕様のコーナーケース, とのこと.
仕様上は invokeinterface で java.lang.Object のメソッドを呼び出すことができる, という話のことだと思われる. #TODO)
* invokeinterface で, 対象クラスが java.lang.Object 以外の場合:
ConstantPoolCacheEntry::set_interface_call() でセットする
* invokeinterface 以外の場合:
ConstantPoolCacheEntry::set_method() でセットする
---------------------------------------- -}
if (bytecode == Bytecodes::_invokeinterface) {
if (TraceItables && Verbose) {
ResourceMark rm(thread);
tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
}
if (info.resolved_method()->method_holder() ==
SystemDictionary::Object_klass()) {
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
// (see also cpCacheOop.cpp for details)
methodHandle rm = info.resolved_method();
assert(rm->is_final() || info.has_vtable_index(),
"should have been set already");
cache_entry(thread)->set_method(bytecode, rm, info.vtable_index());
} else {
// Setup itable entry
int index = klassItable::compute_itable_index(info.resolved_method()());
cache_entry(thread)->set_interface_call(info.resolved_method(), index);
}
} else {
cache_entry(thread)->set_method(
bytecode,
info.resolved_method(),
info.vtable_index());
}
IRT_END
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.