hotspot/src/share/vm/interpreter/linkResolver.cpp
// throws runtime exceptions
void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
methodHandle resolved_method,
KlassHandle resolved_klass,
Handle recv,
KlassHandle recv_klass,
bool check_null_and_abstract,
TRAPS) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// setup default return values
int vtable_index = methodOopDesc::invalid_vtable_index;
methodHandle selected_method;
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(recv.is_null() || recv->is_oop(), "receiver is not an oop");
{- -------------------------------------------
(1) check_null_and_abstract 引数が true の場合はチェックを行う.
レシーバーが null であれば NullPointerException.
---------------------------------------- -}
// runtime method resolution
if (check_null_and_abstract && recv.is_null()) { // check if receiver exists
THROW(vmSymbols::java_lang_NullPointerException());
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the methodOop's
// has not been rewritten, and the vtable initialized.
assert(instanceKlass::cast(resolved_method->method_holder())->is_linked(), "must be linked");
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the methodOop's
// has not been rewritten, and the vtable initialized. Make sure to do this after the nullcheck, since
// a missing receiver might result in a bogus lookup.
assert(instanceKlass::cast(resolved_method->method_holder())->is_linked(), "must be linked");
{- -------------------------------------------
(1) (局所変数の初期化)
#TODO
---------------------------------------- -}
// do lookup based on receiver klass using the vtable index
if (resolved_method->method_holder()->klass_part()->is_interface()) { // miranda method
vtable_index = vtable_index_of_miranda_method(resolved_klass,
resolved_method->name(),
resolved_method->signature(), CHECK);
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
instanceKlass* inst = instanceKlass::cast(recv_klass());
selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
} else {
// at this point we are sure that resolved_method is virtual and not
// a miranda method; therefore, it must have a valid vtable index.
vtable_index = resolved_method->vtable_index();
// We could get a negative vtable_index for final methods,
// because as an optimization they are they are never put in the vtable,
// unless they override an existing method.
// If we do get a negative, it means the resolved method is the the selected
// method, and it can never be changed by an override.
if (vtable_index == methodOopDesc::nonvirtual_vtable_index) {
assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method;
} else {
// recv_klass might be an arrayKlassOop but all vtables start at
// the same place. The cast is to avoid virtual call and assertion.
instanceKlass* inst = (instanceKlass*)recv_klass()->klass_part();
selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
}
}
{- -------------------------------------------
(1) もし対象のメソッドが定義されていなければ AbstractMethodError.
---------------------------------------- -}
// check if method exists
if (selected_method.is_null()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),
resolved_method->name(),
resolved_method->signature()));
}
{- -------------------------------------------
(1) check_null_and_abstract 引数が true の場合はチェックを行う.
解決結果が abstract method であれば AbstractMethodError.
---------------------------------------- -}
// check if abstract
if (check_null_and_abstract && selected_method->is_abstract()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),
selected_method->name(),
selected_method->signature()));
}
{- -------------------------------------------
(1) CallInfo::set_virtual() を呼んで,
引数で渡された CallInfo オブジェクト内に
解決結果をセットする
---------------------------------------- -}
// setup result
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.