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