暗黙的なダイナミック処理は以下の2つの契機で行われる.
どちらの場合も, 実際の処理は NativeLookup クラスの lookup() メソッドで行われる.
NativeLookup 内では, JNI 仕様で定められた名前のネイティブ関数を JNI 仕様で定められた順番で探索する. 見つからなければ, JVMTI で指定された prefix 分を無視するなど何通りかの可能性を考慮して, 複数回探索を行う.
この探索処理は, (システムクラスか否か等に応じて少し変わるが) 一般的には Java の ClassLoader オブジェクトの findNative() メソッドで行われ, どの場合も最後は os::dll_lookup() によって関数ポインタが探索される.
なお, 最後まで見つからなかった場合は UnsatisfiedLinkError になる.
Java_${mangled fully-qualified class name}_${mangled method name}
.(オーバーロードされたメソッドでは, それぞれを区別できるように, この後に __${mangled argument signature} が続く)
探索の順番としては, まず "${mangled argument signature}" 部分のない短い名前を探索し, 見つからなければ "${mangled argument signature}" まで付けた長い名前で探索することになっている.
(参考: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp615 (See: Resolving Native Method Names))
(なお, HotSpot で対応しているのは, 32bit Windows での _stdcall 用に prefix/suffix のみ)
参考: x86 Windows 環境では JNICALL マクロが __stdcall に #define されている
((cite: hotspot/src/cpu/x86/vm/jni_x86.h))
#if defined(SOLARIS) || defined(LINUX)
...
#else
...
#define JNICALL __stdcall
この対応づけ情報は, lookup_special_native_methods という配列に納められている.
((cite: hotspot/src/share/vm/prims/nativeLookup.cpp))
static JNINativeMethod lookup_special_native_methods[] = {
// Next two functions only exist for compatibility with 1.3.1 and earlier.
{ CC"Java_java_io_ObjectOutputStream_getPrimitiveFieldValues", NULL, FN_PTR(JVM_GetPrimitiveFieldValues) }, // intercept ObjectOutputStream getPrimitiveFieldValues for faster serialization
{ CC"Java_java_io_ObjectInputStream_setPrimitiveFieldValues", NULL, FN_PTR(JVM_SetPrimitiveFieldValues) }, // intercept ObjectInputStream setPrimitiveFieldValues for faster serialization
{ CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) },
{ CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
{ CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }
};
(See: here for details) -> InterpreterRuntime::prepare_native_call() -> NativeLookup::lookup() -> NativeLookup::lookup_base() -> (1) まず, JVMTI で指定された prefix を除去しない状態で探索してみる. -> NativeLookup::lookup_entry() この中で, NativeLookup::lookup_style() を最大4回呼び出す. (1) まず "__${mangled argument signature}" 部分のない短い名前を探索. (1) 次に "__${mangled argument signature}" まで付けた長い名前で探索. (1) 次に, os 固有の prefix/suffix を付けずに, "__${mangled argument signature}" 部分のない短い名前を探索. (1) 次に, os 固有の prefix/suffix を付けずに, "__${mangled argument signature}" まで付けた長い名前で探索. -> NativeLookup::lookup_style() -> (1) システムクラスの場合には, 最初に以下の関数で探索しておく (lookup_special_native() で調べた後, なければ libjava 内から探索する) -> lookup_special_native() -> os::dll_lookup() (1) Java の ClassLoader オブジェクトの findNative() メソッドで探索する. -> JavaCalls::call_static() -> (See: here for details) -> java.lang.ClassLoader.findNative() -> java.lang.ClassLoader$NativeLibrary.find() -> Java_java_lang_ClassLoader_00024NativeLibrary_find() -> JVM_FindLibraryEntry() -> os::dll_lookup() (1) 見つからなければ, JVMTI agent としてロードしたライブラリ内を探索する. -> os::dll_lookup() (1) 見つからなければ, JVMTI で指定された prefix を除去した名前で再度探索する. -> NativeLookup::lookup_entry_prefixed() -> NativeLookup::lookup_entry() -> (同上) -> methodOopDesc::set_native_function()
(See: here for details) -> CompileBroker::compile_method() -> NativeLookup::lookup() -> (同上)
See: here for details
See: here for details
See: here for details
(#Under Construction)
(#Under Construction)
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.