1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "jni.h" 18 #include "jvmti.h" 19 20 #include <vector> 21 22 #include "jvmti_helper.h" 23 #include "jni_helper.h" 24 #include "test_env.h" 25 #include "scoped_local_ref.h" 26 27 namespace art { 28 namespace common_monitors { 29 30 extern "C" JNIEXPORT jobject JNICALL Java_art_Monitors_getCurrentContendedMonitor( 31 JNIEnv* env, jclass, jthread thr) { 32 jobject out = nullptr; 33 JvmtiErrorToException(env, jvmti_env, jvmti_env->GetCurrentContendedMonitor(thr, &out)); 34 return out; 35 } 36 37 extern "C" JNIEXPORT jobject JNICALL Java_art_Monitors_getObjectMonitorUsage( 38 JNIEnv* env, jclass, jobject obj) { 39 ScopedLocalRef<jclass> klass(env, env->FindClass("art/Monitors$MonitorUsage")); 40 if (env->ExceptionCheck()) { 41 return nullptr; 42 } 43 jmethodID constructor = env->GetMethodID( 44 klass.get(), 45 "<init>", 46 "(Ljava/lang/Object;Ljava/lang/Thread;I[Ljava/lang/Thread;[Ljava/lang/Thread;)V"); 47 if (env->ExceptionCheck()) { 48 return nullptr; 49 } 50 jvmtiMonitorUsage usage; 51 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetObjectMonitorUsage(obj, &usage))) { 52 return nullptr; 53 } 54 jobjectArray wait = CreateObjectArray(env, usage.waiter_count, "java/lang/Thread", 55 [&](jint i) { return usage.waiters[i]; }); 56 if (env->ExceptionCheck()) { 57 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.waiters)); 58 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.notify_waiters)); 59 return nullptr; 60 } 61 jobjectArray notify_wait = CreateObjectArray(env, usage.notify_waiter_count, "java/lang/Thread", 62 [&](jint i) { return usage.notify_waiters[i]; }); 63 if (env->ExceptionCheck()) { 64 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.waiters)); 65 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.notify_waiters)); 66 return nullptr; 67 } 68 return env->NewObject(klass.get(), constructor, 69 obj, usage.owner, usage.entry_count, wait, notify_wait); 70 } 71 72 struct MonitorsData { 73 jclass test_klass; 74 jmethodID monitor_enter; 75 jmethodID monitor_entered; 76 jmethodID monitor_wait; 77 jmethodID monitor_waited; 78 jclass monitor_klass; 79 }; 80 81 static void monitorEnterCB(jvmtiEnv* jvmti, 82 JNIEnv* jnienv, 83 jthread thr, 84 jobject obj) { 85 MonitorsData* data = nullptr; 86 if (JvmtiErrorToException(jnienv, jvmti, 87 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 88 return; 89 } 90 if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) { 91 return; 92 } 93 jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_enter, thr, obj); 94 } 95 static void monitorEnteredCB(jvmtiEnv* jvmti, 96 JNIEnv* jnienv, 97 jthread thr, 98 jobject obj) { 99 MonitorsData* data = nullptr; 100 if (JvmtiErrorToException(jnienv, jvmti, 101 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 102 return; 103 } 104 if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) { 105 return; 106 } 107 jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_entered, thr, obj); 108 } 109 static void monitorWaitCB(jvmtiEnv* jvmti, 110 JNIEnv* jnienv, 111 jthread thr, 112 jobject obj, 113 jlong timeout) { 114 MonitorsData* data = nullptr; 115 if (JvmtiErrorToException(jnienv, jvmti, 116 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 117 return; 118 } 119 if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) { 120 return; 121 } 122 jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_wait, thr, obj, timeout); 123 } 124 static void monitorWaitedCB(jvmtiEnv* jvmti, 125 JNIEnv* jnienv, 126 jthread thr, 127 jobject obj, 128 jboolean timed_out) { 129 MonitorsData* data = nullptr; 130 if (JvmtiErrorToException(jnienv, jvmti, 131 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 132 return; 133 } 134 if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) { 135 return; 136 } 137 jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_waited, thr, obj, timed_out); 138 } 139 140 extern "C" JNIEXPORT void JNICALL Java_art_Monitors_setupMonitorEvents( 141 JNIEnv* env, 142 jclass, 143 jclass test_klass, 144 jobject monitor_enter, 145 jobject monitor_entered, 146 jobject monitor_wait, 147 jobject monitor_waited, 148 jclass monitor_klass, 149 jthread thr) { 150 MonitorsData* data = nullptr; 151 if (JvmtiErrorToException(env, 152 jvmti_env, 153 jvmti_env->Allocate(sizeof(MonitorsData), 154 reinterpret_cast<unsigned char**>(&data)))) { 155 return; 156 } 157 jvmtiCapabilities caps; 158 memset(&caps, 0, sizeof(caps)); 159 caps.can_generate_monitor_events = 1; 160 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) { 161 return; 162 } 163 164 memset(data, 0, sizeof(MonitorsData)); 165 data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(test_klass)); 166 data->monitor_enter = env->FromReflectedMethod(monitor_enter); 167 data->monitor_entered = env->FromReflectedMethod(monitor_entered); 168 data->monitor_wait = env->FromReflectedMethod(monitor_wait); 169 data->monitor_waited = env->FromReflectedMethod(monitor_waited); 170 data->monitor_klass = reinterpret_cast<jclass>(env->NewGlobalRef(monitor_klass)); 171 MonitorsData* old_data = nullptr; 172 if (JvmtiErrorToException(env, jvmti_env, 173 jvmti_env->GetEnvironmentLocalStorage( 174 reinterpret_cast<void**>(&old_data)))) { 175 return; 176 } else if (old_data != nullptr && old_data->test_klass != nullptr) { 177 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); 178 env->ThrowNew(rt_exception.get(), "Environment already has local storage set!"); 179 return; 180 } 181 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) { 182 return; 183 } 184 185 current_callbacks.MonitorContendedEnter = monitorEnterCB; 186 current_callbacks.MonitorContendedEntered = monitorEnteredCB; 187 current_callbacks.MonitorWait = monitorWaitCB; 188 current_callbacks.MonitorWaited = monitorWaitedCB; 189 if (JvmtiErrorToException(env, 190 jvmti_env, 191 jvmti_env->SetEventCallbacks(¤t_callbacks, 192 sizeof(current_callbacks)))) { 193 return; 194 } 195 if (JvmtiErrorToException(env, 196 jvmti_env, 197 jvmti_env->SetEventNotificationMode( 198 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, thr))) { 199 return; 200 } 201 if (JvmtiErrorToException(env, 202 jvmti_env, 203 jvmti_env->SetEventNotificationMode( 204 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, thr))) { 205 return; 206 } 207 if (JvmtiErrorToException(env, 208 jvmti_env, 209 jvmti_env->SetEventNotificationMode( 210 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, thr))) { 211 return; 212 } 213 if (JvmtiErrorToException(env, 214 jvmti_env, 215 jvmti_env->SetEventNotificationMode( 216 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, thr))) { 217 return; 218 } 219 } 220 221 } // namespace common_monitors 222 } // namespace art 223 224