1.命名規(guī)則
JNI命名規(guī)則:
- 1)使用完整的Java方法名妻率,如果屬于某個包,前面添加包名
- 2)將句點換為下劃線,并在前面加上Java_前綴
- 3)對于重載方法啡捶,會在名稱最后加上兩個下劃線__,然后再加上已編碼的參數(shù)類型
2.以newInstance為例
2.1 調(diào)用NativeConstructorAccessorImpl的native方法 newInstance0
import java.lang.reflect.Method;
public class TestClassLoader {
public static final MyClassLoader WZ_LOADER = new MyClassLoader(null,"/home/wz/eclipse-workspace/TestHotspot/bin/","wz");
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
Class<?> c = WZ_LOADER.loadClass("com.enjoy.learn.core.classloader.Test");
Object obj = c.newInstance();
Method method = c.getMethod("sayHello", null);
method.invoke(obj, null);
}
}
注意<clinit>和<init>方法是由編譯器生成的道逗。
如下就是Test類的<clinit>方法的字節(jié)碼:
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: iconst_1
1: putstatic #10 // Field a:I
4: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
7: getstatic #10 // Field a:I
10: invokevirtual #18 // Method java/io/PrintStream.println:(I)V
13: return
LineNumberTable:
line 4: 0
line 6: 4
line 7: 13
LocalVariableTable:
Start Length Slot Name Signature
最后調(diào)用NativeConstructorAccessorImpl的
private static native Object newInstance0(Constructor<?> c, Object[] args)
throws InstantiationException,
IllegalArgumentException,
InvocationTargetException;
2.2 根據(jù)命名規(guī)則進(jìn)行搜索
grep -rn "NativeConstructorAccessorImpl" . | grep -v "build" |grep newInstance0
./jdk/src/java.base/share/native/libjava/NativeAccessors.c:36:
JNIEXPORT jobject JNICALL
Java_jdk_internal_reflect_NativeConstructorAccessorImpl_newInstance0
2.3 查看源碼
JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_NativeConstructorAccessorImpl_newInstance0
(JNIEnv *env, jclass unused, jobject c, jobjectArray args)
{
return JVM_NewInstanceFromConstructor(env, c, args);
}
繼續(xù)搜索:
grep -rn "JVM_NewInstanceFromConstructor" ./ |grep -v "build"
./jdk/src/java.base/share/native/include/jvm.h:550:JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0);
./jdk/src/java.base/share/native/libjava/NativeAccessors.c:39: return JVM_NewInstanceFromConstructor(env, c, args);
./hotspot/src/share/vm/prims/jvm.cpp:3645:JVM_ENTRY(jobject, JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0))
./hotspot/src/share/vm/prims/jvm.cpp:3646: JVMWrapper("JVM_NewInstanceFromConstructor");
./hotspot/src/share/vm/prims/jvm.h:1223:JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0);
./hotspot/make/symbols/symbols-unix:162:JVM_NewInstanceFromConstructor
在/hotspot/src/share/vm/prims/jvm.cpp中:
JVM_ENTRY(jobject, JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0))
JVMWrapper("JVM_NewInstanceFromConstructor");
oop constructor_mirror = JNIHandles::resolve(c);
objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
oop result = Reflection::invoke_constructor(constructor_mirror, args, CHECK_NULL);
jobject res = JNIHandles::make_local(env, result);
if (JvmtiExport::should_post_vm_object_alloc()) {
JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
}
return res;
JVM_END
查看宏定義:
#define JVM_ENTRY(result_type, header) \
extern "C" { \
result_type JNICALL header { \
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
VM_ENTRY_BASE(result_type, header, thread)
// ENTRY routines may lock, GC and throw exceptions
#define VM_ENTRY_BASE(result_type, header, thread) \
TRACE_CALL(result_type, header) \
HandleMarkCleaner __hm(thread); \
Thread* THREAD = thread; \
os::verify_stack_alignment(); \
/* begin of body */
#define JVM_END } }
展開上面的JVM_NewInstanceFromConstructor宏定義兵罢,如下:
extern "C" {
jobject JNICALL JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0) {
JavaThread* thread=JavaThread::thread_from_jni_environment(env);
ThreadInVMfromNative __tiv(thread);
debug_only(VMNativeEntryWrapper __vew;)
TRACE_CALL(result_type, header)
HandleMarkCleaner __hm(thread);
Thread* THREAD = thread;
os::verify_stack_alignment();
/* begin of body */
JVMWrapper("JVM_NewInstanceFromConstructor");
oop constructor_mirror = JNIHandles::resolve(c);
objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
oop result = Reflection::invoke_constructor(constructor_mirror, args, CHECK_NULL);
jobject res = JNIHandles::make_local(env, result);
if (JvmtiExport::should_post_vm_object_alloc()) {
JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
}
return res;
}
}
3.整理從JVM_NewInstanceFromConstructor到<cinit>的調(diào)用棧
測試代碼:
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
System.out.println("step1 before load Test");
Class<?> c = WZ_LOADER.loadClass("com.enjoy.learn.core.classloader.Test");
System.out.println("step2 after load Test");
Object obj = c.newInstance();
System.out.println("step3 after newInstance");
Method method = c.getMethod("sayHello", null);
method.invoke(obj, null);
}
調(diào)試方法:
- step1.在/jdk/src/java.base/share/native/libjli/java.c的JavaMain方法的mainID = (*env)->GetStaticMethodID(env, mainClass, "main","([Ljava/lang/String;)V");處打斷點,運行至這個地方
- step2.在/hotspot/src/share/vm/prims/jvm.cpp的JVM_NewInstanceFromConstructor方法開始處打斷點滓窍,不斷重復(fù)運行卖词,直到出現(xiàn)如下。表明此時已經(jīng)運行到 c.newInstance()
step1 before load Test
step2 after load Test
-
step3.在hostspot/src/share/vm/oops/instanceKlass.cpp的call_class_initializer_impl方法最后地方打斷點吏夯,運行到此處
可以看到在Reflection::invoke_constructor方法中會調(diào)用klass->initialize(CHECK_NULL);保證類進(jìn)行初始化此蜈。
在隨后的InstanceKlass::call_class_initializer_impl方法中,methodHandle h_method(THREAD, this_k->class_initializer());
Method* InstanceKlass::class_initializer() {
Method* clinit = find_method(
vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
if (clinit != NULL && clinit->has_valid_initializer_flags()) {
return clinit;
}
return NULL;
}
在hotspot/src/share/vm/classfile/vmSymbols.hpp中有如下定義:
#define VM_SYMBOLS_DO(template, do_alias)
template(class_initializer_name, "<clinit>")
template(void_method_signature, "()V")