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 
Java_art_Test912_isModifiableClass(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassSignature(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_isInterface(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_isArrayClass(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassModifiers(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassFields(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassMethods(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getImplementedInterfaces(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassStatus(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassLoader(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_getClassLoaderClasses(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jobject jclassloader)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 
Java_art_Test912_getClassVersion(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
GetClassName(jvmtiEnv * jenv,JNIEnv * jni_env,jclass klass)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 
Java_art_Test912_getClassLoadMessages(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED)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:
ClassLoadCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)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 
ClassPrepareCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)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 
GetThreadName(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread)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 
Java_art_Test912_enableClassLoadPreparePrintEvents(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jboolean enable,jthread thread)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>
RunEventThread(const std::string & name,jvmtiEnv * jvmti,JNIEnv * env,void (* func)(jvmtiEnv *,JNIEnv *,T *),T * data)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 
JoinTread(JNIEnv * env,jthread thr)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 
AgentThreadTest(jvmtiEnv * jvmti ATTRIBUTE_UNUSED,JNIEnv * env,jobject * obj_global)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 
ClassLoadCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread ATTRIBUTE_UNUSED,jclass klass)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 
ClassPrepareCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread ATTRIBUTE_UNUSED,jclass klass)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 
SetOrCompare(JNIEnv * jni_env,jobject value,bool set)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 
CheckFound()538   static void CheckFound() {
539     CHECK(found_);
540     CHECK(compared_);
541   }
542 
Free(JNIEnv * env)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 
Java_art_Test912_setEqualityEventStorageClass(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jclass klass)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 
Java_art_Test912_enableClassLoadPrepareEqualityEvents(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jboolean b)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 // Global to pass information to the ClassPrepare event.
600 static jobject gRunnableGlobal = nullptr;
Java_art_Test912_runRecursiveClassPrepareEvents(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject runnable)601 extern "C" JNIEXPORT void JNICALL Java_art_Test912_runRecursiveClassPrepareEvents(
602     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject runnable) {
603   CHECK(gRunnableGlobal == nullptr);
604   gRunnableGlobal = env->NewGlobalRef(runnable);
605   EnableEvents(
606       env,
607       true,
608       nullptr,
609       [](jvmtiEnv* jenv ATTRIBUTE_UNUSED,
610          JNIEnv* jni_env,
611          jthread thread ATTRIBUTE_UNUSED,
612          jclass klass ATTRIBUTE_UNUSED) -> void {
613         jclass runnable_class = jni_env->FindClass("java/lang/Runnable");
614         jni_env->CallVoidMethod(
615             gRunnableGlobal, jni_env->GetMethodID(runnable_class, "run", "()V"));
616       });
617   jclass runnable_class = env->FindClass("java/lang/Runnable");
618   env->CallVoidMethod(
619       runnable, env->GetMethodID(runnable_class, "run", "()V"));
620   EnableEvents(env, false, nullptr, nullptr);
621   env->DeleteGlobalRef(gRunnableGlobal);
622   gRunnableGlobal = nullptr;
623 }
624 
625 }  // namespace Test912Classes
626 }  // namespace art
627