Home | History | Annotate | Download | only in 912-classes
      1 /*
      2  * Copyright (C) 2013 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 <stdio.h>
     18 
     19 #include <condition_variable>
     20 #include <mutex>
     21 #include <vector>
     22 
     23 #include "android-base/macros.h"
     24 #include "android-base/stringprintf.h"
     25 
     26 #include "jni.h"
     27 #include "jvmti.h"
     28 
     29 // Test infrastructure
     30 #include "jni_helper.h"
     31 #include "jvmti_helper.h"
     32 #include "scoped_local_ref.h"
     33 #include "scoped_utf_chars.h"
     34 #include "test_env.h"
     35 
     36 namespace art {
     37 namespace Test912Classes {
     38 
     39 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isModifiableClass(
     40     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
     41   jboolean res = JNI_FALSE;
     42   jvmtiError result = jvmti_env->IsModifiableClass(klass, &res);
     43   JvmtiErrorToException(env, jvmti_env, result);
     44   return res;
     45 }
     46 
     47 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassSignature(
     48     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
     49   char* sig;
     50   char* gen;
     51   jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen);
     52   if (JvmtiErrorToException(env, jvmti_env, result)) {
     53     return nullptr;
     54   }
     55 
     56   auto callback = [&](jint i) {
     57     if (i == 0) {
     58       return sig == nullptr ? nullptr : env->NewStringUTF(sig);
     59     } else {
     60       return gen == nullptr ? nullptr : env->NewStringUTF(gen);
     61     }
     62   };
     63   jobjectArray ret = CreateObjectArray(env, 2, "java/lang/String", callback);
     64 
     65   // Need to deallocate the strings.
     66   if (sig != nullptr) {
     67     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
     68   }
     69   if (gen != nullptr) {
     70     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
     71   }
     72 
     73   return ret;
     74 }
     75 
     76 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isInterface(
     77     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
     78   jboolean is_interface = JNI_FALSE;
     79   jvmtiError result = jvmti_env->IsInterface(klass, &is_interface);
     80   JvmtiErrorToException(env, jvmti_env, result);
     81   return is_interface;
     82 }
     83 
     84 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isArrayClass(
     85     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
     86   jboolean is_array_class = JNI_FALSE;
     87   jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class);
     88   JvmtiErrorToException(env, jvmti_env, result);
     89   return is_array_class;
     90 }
     91 
     92 extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassModifiers(
     93     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
     94   jint mod;
     95   jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod);
     96   JvmtiErrorToException(env, jvmti_env, result);
     97   return mod;
     98 }
     99 
    100 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassFields(
    101     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    102   jint count = 0;
    103   jfieldID* fields = nullptr;
    104   jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields);
    105   if (JvmtiErrorToException(env, jvmti_env, result)) {
    106     return nullptr;
    107   }
    108 
    109   auto callback = [&](jint i) {
    110     jint modifiers;
    111     // Ignore any errors for simplicity.
    112     jvmti_env->GetFieldModifiers(klass, fields[i], &modifiers);
    113     constexpr jint kStatic = 0x8;
    114     return env->ToReflectedField(klass,
    115                                  fields[i],
    116                                  (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
    117   };
    118   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
    119   if (fields != nullptr) {
    120     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
    121   }
    122   return ret;
    123 }
    124 
    125 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassMethods(
    126     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    127   jint count = 0;
    128   jmethodID* methods = nullptr;
    129   jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods);
    130   if (JvmtiErrorToException(env, jvmti_env, result)) {
    131     return nullptr;
    132   }
    133 
    134   auto callback = [&](jint i) {
    135     jint modifiers;
    136     // Ignore any errors for simplicity.
    137     jvmti_env->GetMethodModifiers(methods[i], &modifiers);
    138     constexpr jint kStatic = 0x8;
    139     return env->ToReflectedMethod(klass,
    140                                   methods[i],
    141                                   (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
    142   };
    143   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
    144   if (methods != nullptr) {
    145     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(methods));
    146   }
    147   return ret;
    148 }
    149 
    150 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getImplementedInterfaces(
    151     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    152   jint count = 0;
    153   jclass* classes = nullptr;
    154   jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes);
    155   if (JvmtiErrorToException(env, jvmti_env, result)) {
    156     return nullptr;
    157   }
    158 
    159   auto callback = [&](jint i) {
    160     return classes[i];
    161   };
    162   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
    163   if (classes != nullptr) {
    164     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
    165   }
    166   return ret;
    167 }
    168 
    169 extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassStatus(
    170     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    171   jint status;
    172   jvmtiError result = jvmti_env->GetClassStatus(klass, &status);
    173   JvmtiErrorToException(env, jvmti_env, result);
    174   return status;
    175 }
    176 
    177 extern "C" JNIEXPORT jobject JNICALL Java_art_Test912_getClassLoader(
    178     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    179   jobject classloader;
    180   jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader);
    181   JvmtiErrorToException(env, jvmti_env, result);
    182   return classloader;
    183 }
    184 
    185 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoaderClasses(
    186     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) {
    187   jint count = 0;
    188   jclass* classes = nullptr;
    189   jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes);
    190   if (JvmtiErrorToException(env, jvmti_env, result)) {
    191     return nullptr;
    192   }
    193 
    194   auto callback = [&](jint i) {
    195     return classes[i];
    196   };
    197   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
    198   if (classes != nullptr) {
    199     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
    200   }
    201   return ret;
    202 }
    203 
    204 extern "C" JNIEXPORT jintArray JNICALL Java_art_Test912_getClassVersion(
    205     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    206   jint major, minor;
    207   jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
    208   if (JvmtiErrorToException(env, jvmti_env, result)) {
    209     return nullptr;
    210   }
    211 
    212   jintArray int_array = env->NewIntArray(2);
    213   if (int_array == nullptr) {
    214     return nullptr;
    215   }
    216   jint buf[2] = { major, minor };
    217   env->SetIntArrayRegion(int_array, 0, 2, buf);
    218 
    219   return int_array;
    220 }
    221 
    222 static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
    223   char* name;
    224   jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
    225   if (result != JVMTI_ERROR_NONE) {
    226     if (jni_env != nullptr) {
    227       JvmtiErrorToException(jni_env, jenv, result);
    228     } else {
    229       printf("Failed to get class signature.\n");
    230     }
    231     return "";
    232   }
    233 
    234   std::string tmp(name);
    235   jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
    236 
    237   return tmp;
    238 }
    239 
    240 static void EnableEvents(JNIEnv* env,
    241                          jboolean enable,
    242                          decltype(jvmtiEventCallbacks().ClassLoad) class_load,
    243                          decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
    244   if (enable == JNI_FALSE) {
    245     jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
    246                                                          JVMTI_EVENT_CLASS_LOAD,
    247                                                          nullptr);
    248     if (JvmtiErrorToException(env, jvmti_env, ret)) {
    249       return;
    250     }
    251     ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
    252                                               JVMTI_EVENT_CLASS_PREPARE,
    253                                               nullptr);
    254     JvmtiErrorToException(env, jvmti_env, ret);
    255     return;
    256   }
    257 
    258   jvmtiEventCallbacks callbacks;
    259   memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
    260   callbacks.ClassLoad = class_load;
    261   callbacks.ClassPrepare = class_prepare;
    262   jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
    263   if (JvmtiErrorToException(env, jvmti_env, ret)) {
    264     return;
    265   }
    266 
    267   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
    268                                             JVMTI_EVENT_CLASS_LOAD,
    269                                             nullptr);
    270   if (JvmtiErrorToException(env, jvmti_env, ret)) {
    271     return;
    272   }
    273   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
    274                                             JVMTI_EVENT_CLASS_PREPARE,
    275                                             nullptr);
    276   JvmtiErrorToException(env, jvmti_env, ret);
    277 }
    278 
    279 static std::mutex gEventsMutex;
    280 static std::vector<std::string> gEvents;
    281 
    282 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoadMessages(
    283     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
    284   std::lock_guard<std::mutex> guard(gEventsMutex);
    285   jobjectArray ret = CreateObjectArray(env,
    286                                        static_cast<jint>(gEvents.size()),
    287                                        "java/lang/String",
    288                                        [&](jint i) {
    289     return env->NewStringUTF(gEvents[i].c_str());
    290   });
    291   gEvents.clear();
    292   return ret;
    293 }
    294 
    295 class ClassLoadPreparePrinter {
    296  public:
    297   static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
    298                                         JNIEnv* jni_env,
    299                                         jthread thread,
    300                                         jclass klass) {
    301     std::string name = GetClassName(jenv, jni_env, klass);
    302     if (name == "") {
    303       return;
    304     }
    305     std::string thread_name = GetThreadName(jenv, jni_env, thread);
    306     if (thread_name == "") {
    307       return;
    308     }
    309     if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
    310       return;
    311     }
    312 
    313     std::lock_guard<std::mutex> guard(gEventsMutex);
    314     gEvents.push_back(android::base::StringPrintf("Load: %s on %s",
    315                                                   name.c_str(),
    316                                                   thread_name.c_str()));
    317   }
    318 
    319   static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
    320                                            JNIEnv* jni_env,
    321                                            jthread thread,
    322                                            jclass klass) {
    323     std::string name = GetClassName(jenv, jni_env, klass);
    324     if (name == "") {
    325       return;
    326     }
    327     std::string thread_name = GetThreadName(jenv, jni_env, thread);
    328     if (thread_name == "") {
    329       return;
    330     }
    331     if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
    332       return;
    333     }
    334     std::string cur_thread_name = GetThreadName(jenv, jni_env, nullptr);
    335 
    336     std::lock_guard<std::mutex> guard(gEventsMutex);
    337     gEvents.push_back(android::base::StringPrintf("Prepare: %s on %s (cur=%s)",
    338                                                   name.c_str(),
    339                                                   thread_name.c_str(),
    340                                                   cur_thread_name.c_str()));
    341   }
    342 
    343   static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) {
    344     jvmtiThreadInfo info;
    345     jvmtiError result = jenv->GetThreadInfo(thread, &info);
    346     if (result != JVMTI_ERROR_NONE) {
    347       if (jni_env != nullptr) {
    348         JvmtiErrorToException(jni_env, jenv, result);
    349       } else {
    350         printf("Failed to get thread name.\n");
    351       }
    352       return "";
    353     }
    354 
    355     std::string tmp(info.name);
    356     jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name));
    357     jni_env->DeleteLocalRef(info.context_class_loader);
    358     jni_env->DeleteLocalRef(info.thread_group);
    359 
    360     return tmp;
    361   }
    362 
    363   static std::string thread_name_filter_;
    364 };
    365 std::string ClassLoadPreparePrinter::thread_name_filter_;  // NOLINT [runtime/string] [4]
    366 
    367 extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPreparePrintEvents(
    368     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable, jthread thread) {
    369   if (thread != nullptr) {
    370     ClassLoadPreparePrinter::thread_name_filter_ =
    371         ClassLoadPreparePrinter::GetThreadName(jvmti_env, env, thread);
    372   } else {
    373     ClassLoadPreparePrinter::thread_name_filter_ = "";
    374   }
    375 
    376   EnableEvents(env,
    377                enable,
    378                ClassLoadPreparePrinter::ClassLoadCallback,
    379                ClassLoadPreparePrinter::ClassPrepareCallback);
    380 }
    381 
    382 template<typename T>
    383 static jthread RunEventThread(const std::string& name,
    384                               jvmtiEnv* jvmti,
    385                               JNIEnv* env,
    386                               void (*func)(jvmtiEnv*, JNIEnv*, T*),
    387                               T* data) {
    388   // Create a Thread object.
    389   std::string name_str = name;
    390   name_str += ": JVMTI_THREAD-Test912";
    391   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name_str.c_str()));
    392   CHECK(thread_name.get() != nullptr);
    393 
    394   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
    395   CHECK(thread_klass.get() != nullptr);
    396 
    397   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
    398   CHECK(thread.get() != nullptr);
    399 
    400   jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V");
    401   CHECK(initID != nullptr);
    402 
    403   env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get());
    404   CHECK(!env->ExceptionCheck());
    405 
    406   // Run agent thread.
    407   CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(),
    408                                                reinterpret_cast<jvmtiStartFunction>(func),
    409                                                reinterpret_cast<void*>(data),
    410                                                JVMTI_THREAD_NORM_PRIORITY));
    411   return thread.release();
    412 }
    413 
    414 static void JoinTread(JNIEnv* env, jthread thr) {
    415   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
    416   CHECK(thread_klass.get() != nullptr);
    417 
    418   jmethodID joinID = env->GetMethodID(thread_klass.get(), "join", "()V");
    419   CHECK(joinID != nullptr);
    420 
    421   env->CallVoidMethod(thr, joinID);
    422 }
    423 
    424 class ClassLoadPrepareEquality {
    425  public:
    426   static constexpr const char* kClassName = "Lart/Test912$ClassE;";
    427   static constexpr const char* kStorageFieldName = "STATIC";
    428   static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;";
    429   static constexpr const char* kStorageWeakFieldName = "WEAK";
    430   static constexpr const char* kStorageWeakFieldSig = "Ljava/lang/ref/Reference;";
    431   static constexpr const char* kWeakClassName = "java/lang/ref/WeakReference";
    432   static constexpr const char* kWeakInitSig = "(Ljava/lang/Object;)V";
    433   static constexpr const char* kWeakGetSig = "()Ljava/lang/Object;";
    434 
    435   static void AgentThreadTest(jvmtiEnv* jvmti ATTRIBUTE_UNUSED,
    436                               JNIEnv* env,
    437                               jobject* obj_global) {
    438     jobject target = *obj_global;
    439     jobject target_local = env->NewLocalRef(target);
    440     {
    441       std::unique_lock<std::mutex> lk(mutex_);
    442       started_ = true;
    443       cond_started_.notify_all();
    444       cond_finished_.wait(lk, [] { return finished_; });
    445       CHECK(finished_);
    446     }
    447     CHECK(env->IsSameObject(target, target_local));
    448   }
    449 
    450   static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
    451                                         JNIEnv* jni_env,
    452                                         jthread thread ATTRIBUTE_UNUSED,
    453                                         jclass klass) {
    454     std::string name = GetClassName(jenv, jni_env, klass);
    455     if (name == kClassName) {
    456       found_ = true;
    457       stored_class_ = jni_env->NewGlobalRef(klass);
    458       weakly_stored_class_ = jni_env->NewWeakGlobalRef(klass);
    459       // Check that we update the local refs.
    460       agent_thread_ = static_cast<jthread>(jni_env->NewGlobalRef(RunEventThread<jobject>(
    461           "local-ref", jenv, jni_env, &AgentThreadTest, static_cast<jobject*>(&stored_class_))));
    462       {
    463         std::unique_lock<std::mutex> lk(mutex_);
    464         cond_started_.wait(lk, [] { return started_; });
    465       }
    466       // Store the value into a field in the heap.
    467       SetOrCompare(jni_env, klass, true);
    468     }
    469   }
    470 
    471   static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
    472                                            JNIEnv* jni_env,
    473                                            jthread thread ATTRIBUTE_UNUSED,
    474                                            jclass klass) {
    475     std::string name = GetClassName(jenv, jni_env, klass);
    476     if (name == kClassName) {
    477       CHECK(stored_class_ != nullptr);
    478       CHECK(jni_env->IsSameObject(stored_class_, klass));
    479       CHECK(jni_env->IsSameObject(weakly_stored_class_, klass));
    480       {
    481         std::unique_lock<std::mutex> lk(mutex_);
    482         finished_ = true;
    483         cond_finished_.notify_all();
    484       }
    485       // Look up the value in a field in the heap.
    486       SetOrCompare(jni_env, klass, false);
    487       JoinTread(jni_env, agent_thread_);
    488       compared_ = true;
    489     }
    490   }
    491 
    492   static void SetOrCompare(JNIEnv* jni_env, jobject value, bool set) {
    493     CHECK(storage_class_ != nullptr);
    494 
    495     // Simple direct storage.
    496     jfieldID field = jni_env->GetStaticFieldID(storage_class_, kStorageFieldName, kStorageFieldSig);
    497     CHECK(field != nullptr);
    498 
    499     if (set) {
    500       jni_env->SetStaticObjectField(storage_class_, field, value);
    501       CHECK(!jni_env->ExceptionCheck());
    502     } else {
    503       ScopedLocalRef<jobject> stored(jni_env, jni_env->GetStaticObjectField(storage_class_, field));
    504       CHECK(jni_env->IsSameObject(value, stored.get()));
    505     }
    506 
    507     // Storage as a reference.
    508     ScopedLocalRef<jclass> weak_ref_class(jni_env, jni_env->FindClass(kWeakClassName));
    509     CHECK(weak_ref_class.get() != nullptr);
    510     jfieldID weak_field = jni_env->GetStaticFieldID(storage_class_,
    511                                                     kStorageWeakFieldName,
    512                                                     kStorageWeakFieldSig);
    513     CHECK(weak_field != nullptr);
    514     if (set) {
    515       // Create a WeakReference.
    516       jmethodID weak_init = jni_env->GetMethodID(weak_ref_class.get(), "<init>", kWeakInitSig);
    517       CHECK(weak_init != nullptr);
    518       ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->NewObject(weak_ref_class.get(),
    519                                                                    weak_init,
    520                                                                    value));
    521       CHECK(weak_obj.get() != nullptr);
    522       jni_env->SetStaticObjectField(storage_class_, weak_field, weak_obj.get());
    523       CHECK(!jni_env->ExceptionCheck());
    524     } else {
    525       // Check the reference value.
    526       jmethodID get_referent = jni_env->GetMethodID(weak_ref_class.get(), "get", kWeakGetSig);
    527       CHECK(get_referent != nullptr);
    528       ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->GetStaticObjectField(storage_class_,
    529                                                                               weak_field));
    530       CHECK(weak_obj.get() != nullptr);
    531       ScopedLocalRef<jobject> weak_referent(jni_env, jni_env->CallObjectMethod(weak_obj.get(),
    532                                                                                get_referent));
    533       CHECK(weak_referent.get() != nullptr);
    534       CHECK(jni_env->IsSameObject(value, weak_referent.get()));
    535     }
    536   }
    537 
    538   static void CheckFound() {
    539     CHECK(found_);
    540     CHECK(compared_);
    541   }
    542 
    543   static void Free(JNIEnv* env) {
    544     if (stored_class_ != nullptr) {
    545       env->DeleteGlobalRef(stored_class_);
    546       DCHECK(weakly_stored_class_ != nullptr);
    547       env->DeleteWeakGlobalRef(weakly_stored_class_);
    548       // Do not attempt to delete the local ref. It will be out of date by now.
    549     }
    550   }
    551 
    552   static jclass storage_class_;
    553 
    554  private:
    555   static jobject stored_class_;
    556   static jweak weakly_stored_class_;
    557   static jthread agent_thread_;
    558   static std::mutex mutex_;
    559   static bool started_;
    560   static std::condition_variable cond_finished_;
    561   static bool finished_;
    562   static std::condition_variable cond_started_;
    563   static bool found_;
    564   static bool compared_;
    565 };
    566 
    567 jclass ClassLoadPrepareEquality::storage_class_ = nullptr;
    568 jobject ClassLoadPrepareEquality::stored_class_ = nullptr;
    569 jweak ClassLoadPrepareEquality::weakly_stored_class_ = nullptr;
    570 jthread ClassLoadPrepareEquality::agent_thread_ = nullptr;
    571 std::mutex ClassLoadPrepareEquality::mutex_;
    572 bool ClassLoadPrepareEquality::started_ = false;
    573 std::condition_variable ClassLoadPrepareEquality::cond_started_;
    574 bool ClassLoadPrepareEquality::finished_ = false;
    575 std::condition_variable ClassLoadPrepareEquality::cond_finished_;
    576 bool ClassLoadPrepareEquality::found_ = false;
    577 bool ClassLoadPrepareEquality::compared_ = false;
    578 
    579 extern "C" JNIEXPORT void JNICALL Java_art_Test912_setEqualityEventStorageClass(
    580     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
    581   ClassLoadPrepareEquality::storage_class_ =
    582       reinterpret_cast<jclass>(env->NewGlobalRef(klass));
    583 }
    584 
    585 extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPrepareEqualityEvents(
    586     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
    587   EnableEvents(env,
    588                b,
    589                ClassLoadPrepareEquality::ClassLoadCallback,
    590                ClassLoadPrepareEquality::ClassPrepareCallback);
    591   if (b == JNI_FALSE) {
    592     ClassLoadPrepareEquality::Free(env);
    593     ClassLoadPrepareEquality::CheckFound();
    594     env->DeleteGlobalRef(ClassLoadPrepareEquality::storage_class_);
    595     ClassLoadPrepareEquality::storage_class_ = nullptr;
    596   }
    597 }
    598 
    599 }  // namespace Test912Classes
    600 }  // namespace art
    601