hotspot/src/share/vm/prims/jni.cpp
static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
{- -------------------------------------------
(1) もし引数で指定された receiver が NULL だったら. NullPointerException.
---------------------------------------- -}
oop recv = JNIHandles::resolve(receiver);
if (recv == NULL) {
THROW(vmSymbols::java_lang_NullPointerException());
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Handle h_recv(THREAD, recv);
int number_of_parameters;
methodOop selected_method;
{- -------------------------------------------
(1) 以下のブロック内で dynamic dispatch 処理を行い, 実際に呼び出す methodOop を探し当てる.
---------------------------------------- -}
{
methodOop m = JNIHandles::resolve_jmethod_id(method_id);
number_of_parameters = m->size_of_parameters();
klassOop holder = m->method_holder();
if (!(Klass::cast(holder))->is_interface()) {
// non-interface call -- for that little speed boost, don't handlize
debug_only(No_Safepoint_Verifier nosafepoint;)
if (call_type == JNI_VIRTUAL) {
// jni_GetMethodID makes sure class is linked and initialized
// so m should have a valid vtable index.
int vtbl_index = m->vtable_index();
if (vtbl_index != methodOopDesc::nonvirtual_vtable_index) {
klassOop k = h_recv->klass();
// k might be an arrayKlassOop but all vtables start at
// the same place. The cast is to avoid virtual call and assertion.
instanceKlass *ik = (instanceKlass*)k->klass_part();
selected_method = ik->method_at_vtable(vtbl_index);
} else {
// final method
selected_method = m;
}
} else {
// JNI_NONVIRTUAL call
selected_method = m;
}
} else {
// interface call
KlassHandle h_holder(THREAD, holder);
int itbl_index = m->cached_itable_index();
if (itbl_index == -1) {
itbl_index = klassItable::compute_itable_index(m);
m->set_cached_itable_index(itbl_index);
// the above may have grabbed a lock, 'm' and anything non-handlized can't be used again
}
klassOop k = h_recv->klass();
selected_method = instanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
}
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
methodHandle method(THREAD, selected_method);
{- -------------------------------------------
(1) (JavaCalls::call() では引数を JavaCallArguments オブジェクトに入れて渡す必要があるので)
JavaCallArguments オブジェクトを用意し,
引数で渡された JNI_ArgumentPusher オブジェクト(args)にセットしておく.
---------------------------------------- -}
// Create object to hold arguments for the JavaCall, and associate it with
// the jni parser
ResourceMark rm(THREAD);
JavaCallArguments java_args(number_of_parameters);
args->set_java_argument_object(&java_args);
{- -------------------------------------------
(1) #TODO
---------------------------------------- -}
// handle arguments
assert(!method->is_static(), "method should not be static");
args->push_receiver(h_recv); // Push jobject handle
{- -------------------------------------------
(1) JNI_ArgumentPusher::iterate() を呼んで,
JavaCallArguments オブジェクト内に引数を詰め直す.
---------------------------------------- -}
// Fill out JavaCallArguments object
args->iterate( Fingerprinter(method).fingerprint() );
{- -------------------------------------------
(1) JavaValue::set_type() を呼んで,
引数で渡された JavaValue (result) に返値の型をセットしておく
---------------------------------------- -}
// Initialize result type
result->set_type(args->get_ret_type());
{- -------------------------------------------
(1) JavaCalls::call() によって, 引数で指定されたメソッドを呼び出す.
---------------------------------------- -}
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
{- -------------------------------------------
(1) 返値がポインタ(オブジェクト or 配列)の場合には, JNI Handle 化しておく.
---------------------------------------- -}
// Convert result
if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) {
result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject()));
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.