Up Top

JNI の処理 : native method の処理 : native method の dynamic linking 処理 : 暗黙的なダイナミックリンク


概要(Summary)

暗黙的なダイナミック処理は以下の2つの契機で行われる.

どちらの場合も, 実際の処理は NativeLookup クラスの lookup() メソッドで行われる.

NativeLookup 内では, JNI 仕様で定められた名前のネイティブ関数を JNI 仕様で定められた順番で探索する. 見つからなければ, JVMTI で指定された prefix 分を無視するなど何通りかの可能性を考慮して, 複数回探索を行う.

この探索処理は, (システムクラスか否か等に応じて少し変わるが) 一般的には Java の ClassLoader オブジェクトの findNative() メソッドで行われ, どの場合も最後は os::dll_lookup() によって関数ポインタが探索される.

なお, 最後まで見つからなかった場合は UnsatisfiedLinkError になる.

備考(Notes)

(オーバーロードされたメソッドでは, それぞれを区別できるように, この後に __${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)         }
    };

処理の流れ (概要)(Execution Flows : Summary)

該当のネイティブメソッドが呼び出された時の処理

(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()

該当のネイティブメソッドが JIT コンパイルされた時の処理

(See: here for details)
-> CompileBroker::compile_method()
   -> NativeLookup::lookup()
      -> (同上)

処理の流れ (詳細)(Execution Flows : Details)

NativeLookup::lookup()

See: here for details

NativeLookup::lookup_base()

See: here for details

NativeLookup::lookup_entry()

See: here for details

NativeLookup::pure_jni_name()

(#Under Construction)

NativeLookup::long_jni_name()

(#Under Construction)

NativeLookup::lookup_style()

See: here for details

os::print_jni_name_prefix_on() (Linux の場合)

See: here for details

os::print_jni_name_suffix_on() (Linux の場合)

See: here for details

os::print_jni_name_prefix_on() (Solaris の場合)

See: here for details

os::print_jni_name_suffix_on() (Solaris の場合)

See: here for details

os::print_jni_name_prefix_on() (Windows の場合)

See: here for details

os::print_jni_name_suffix_on() (Windows の場合)

See: here for details

lookup_special_native()

See: here for details

os::native_java_library()

See: here for details

os::dll_lookup() (Linux の場合)

See: here for details

os::dll_lookup() (Solaris の場合)

See: here for details

os::dll_lookup() (Windows の場合)

See: here for details

java.lang.ClassLoader.findNative()

See: here for details

Java_java_lang_ClassLoader_00024NativeLibrary_find()

See: here for details

JVM_FindLibraryEntry()

See: here for details

os::dll_lookup() (Linux の場合)

See: here for details

os::dll_lookup() (Solaris の場合)

See: here for details

os::dll_lookup() (Windows の場合)

See: here for details

NativeLookup::lookup_entry_prefixed()

See: here for details


This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.