| 75 | } |
| 76 | |
| 77 | Error LockTracer::initialize(jvmtiEnv* jvmti, JNIEnv* env) { |
| 78 | if (CAN_USE_TLS) { |
| 79 | pthread_key_create(&lock_tracer_tls, NULL); |
| 80 | } |
| 81 | |
| 82 | // Try JDK 9+ package first, then fallback to JDK 8 package |
| 83 | jclass unsafe = env->FindClass("jdk/internal/misc/Unsafe"); |
| 84 | if (unsafe == NULL) { |
| 85 | env->ExceptionClear(); |
| 86 | if ((unsafe = env->FindClass("sun/misc/Unsafe")) == NULL) { |
| 87 | return Error("Unsafe class not found"); |
| 88 | } |
| 89 | } |
| 90 | _Unsafe = (jclass)env->NewGlobalRef(unsafe); |
| 91 | |
| 92 | jmethodID register_natives = env->GetStaticMethodID(_Unsafe, "registerNatives", "()V"); |
| 93 | if (register_natives == NULL) { |
| 94 | return Error("registerNatives method not found"); |
| 95 | } |
| 96 | |
| 97 | jniNativeInterface* jni_functions; |
| 98 | if (jvmti->GetJNIFunctionTable(&jni_functions) == 0) { |
| 99 | _orig_register_natives = jni_functions->RegisterNatives; |
| 100 | jni_functions->RegisterNatives = RegisterNativesHook; |
| 101 | jvmti->SetJNIFunctionTable(jni_functions); |
| 102 | |
| 103 | // Trace Unsafe.registerNatives() to find the original address of Unsafe.park() native |
| 104 | env->CallStaticVoidMethod(_Unsafe, register_natives); |
| 105 | |
| 106 | jni_functions->RegisterNatives = _orig_register_natives; |
| 107 | jvmti->SetJNIFunctionTable(jni_functions); |
| 108 | jvmti->Deallocate((unsigned char*)jni_functions); |
| 109 | } |
| 110 | if (env->ExceptionCheck() || _orig_unsafe_park == NULL) { |
| 111 | return Error("Unsafe_park address not found"); |
| 112 | } |
| 113 | |
| 114 | _parkBlocker = env->GetFieldID(env->FindClass("java/lang/Thread"), "parkBlocker", "Ljava/lang/Object;"); |
| 115 | if (_parkBlocker == NULL) { |
| 116 | return Error("parkBlocker field not found"); |
| 117 | } |
| 118 | |
| 119 | jclass cls = env->DefineClass(LOCK_TRACER_NAME, NULL, (const jbyte*)LOCK_TRACER_CLASS, INCBIN_SIZEOF(LOCK_TRACER_CLASS)); |
| 120 | if (cls != NULL) { |
| 121 | const JNINativeMethod method = {(char*)"setEntry0", (char*)"(J)V", (void*)setEntry0}; |
| 122 | if (env->RegisterNatives(cls, &method, 1) != 0) { |
| 123 | return Error("LockTracer registration failed"); |
| 124 | } |
| 125 | } else { |
| 126 | env->ExceptionClear(); |
| 127 | if ((cls = env->FindClass(LOCK_TRACER_NAME)) == NULL) { |
| 128 | return Error("LockTracer registration failed"); |
| 129 | } |
| 130 | } |
| 131 | _LockTracer = (jclass)env->NewGlobalRef(cls); |
| 132 | |
| 133 | _setEntry = env->GetStaticMethodID(_LockTracer, "setEntry", "(J)V"); |
| 134 | if (_setEntry == NULL) { |