blob: 5bd34f6be8e6603aaf68f492ae4e072ead0d15f2 [file] [log] [blame]
Andreas Gampee492ae32016-10-28 19:34:57 -07001/*
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
Andreas Gampee492ae32016-10-28 19:34:57 -070017#include <stdio.h>
18
19#include "base/macros.h"
Andreas Gampee2744c62017-02-08 16:28:59 +000020#include "class_linker.h"
Andreas Gampee492ae32016-10-28 19:34:57 -070021#include "jni.h"
Andreas Gampee2744c62017-02-08 16:28:59 +000022#include "mirror/class_loader.h"
Andreas Gampe5e03a302017-03-13 13:10:00 -070023#include "jvmti.h"
Andreas Gampee2744c62017-02-08 16:28:59 +000024#include "runtime.h"
Andreas Gampee492ae32016-10-28 19:34:57 -070025#include "ScopedLocalRef.h"
Andreas Gampee2744c62017-02-08 16:28:59 +000026#include "ScopedUtfChars.h"
27#include "scoped_thread_state_change-inl.h"
Andreas Gampee6377462017-01-20 17:37:50 -080028#include "thread-inl.h"
Andreas Gampee492ae32016-10-28 19:34:57 -070029
Andreas Gampe336c3c32016-11-08 17:02:19 -080030#include "ti-agent/common_helper.h"
Andreas Gampee492ae32016-10-28 19:34:57 -070031#include "ti-agent/common_load.h"
32
33namespace art {
34namespace Test912Classes {
35
Alex Lighte4a88632017-01-10 07:41:24 -080036extern "C" JNIEXPORT jboolean JNICALL Java_Main_isModifiableClass(
37 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
38 jboolean res = JNI_FALSE;
39 jvmtiError result = jvmti_env->IsModifiableClass(klass, &res);
40 if (result != JVMTI_ERROR_NONE) {
41 char* err;
42 jvmti_env->GetErrorName(result, &err);
43 printf("Failure running IsModifiableClass: %s\n", err);
44 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
45 return JNI_FALSE;
46 }
47 return res;
48}
49
Andreas Gampee492ae32016-10-28 19:34:57 -070050extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature(
51 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
52 char* sig;
53 char* gen;
54 jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen);
55 if (result != JVMTI_ERROR_NONE) {
56 char* err;
57 jvmti_env->GetErrorName(result, &err);
58 printf("Failure running GetClassSignature: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -080059 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampee492ae32016-10-28 19:34:57 -070060 return nullptr;
61 }
62
Andreas Gampe336c3c32016-11-08 17:02:19 -080063 auto callback = [&](jint i) {
64 if (i == 0) {
65 return sig == nullptr ? nullptr : env->NewStringUTF(sig);
66 } else {
67 return gen == nullptr ? nullptr : env->NewStringUTF(gen);
68 }
69 };
70 jobjectArray ret = CreateObjectArray(env, 2, "java/lang/String", callback);
Andreas Gampee492ae32016-10-28 19:34:57 -070071
72 // Need to deallocate the strings.
73 if (sig != nullptr) {
74 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
75 }
76 if (gen != nullptr) {
77 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
78 }
79
80 return ret;
81}
82
Andreas Gampe4fd66ec2017-01-05 14:42:13 -080083extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterface(
84 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
85 jboolean is_interface = JNI_FALSE;
86 jvmtiError result = jvmti_env->IsInterface(klass, &is_interface);
87 if (result != JVMTI_ERROR_NONE) {
88 char* err;
89 jvmti_env->GetErrorName(result, &err);
90 printf("Failure running IsInterface: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -080091 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampe4fd66ec2017-01-05 14:42:13 -080092 return JNI_FALSE;
93 }
94 return is_interface;
95}
96
97extern "C" JNIEXPORT jboolean JNICALL Java_Main_isArrayClass(
98 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
99 jboolean is_array_class = JNI_FALSE;
100 jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class);
101 if (result != JVMTI_ERROR_NONE) {
102 char* err;
103 jvmti_env->GetErrorName(result, &err);
104 printf("Failure running IsArrayClass: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -0800105 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampe4fd66ec2017-01-05 14:42:13 -0800106 return JNI_FALSE;
107 }
108 return is_array_class;
109}
110
Andreas Gampe64013e52017-01-06 13:07:19 -0800111extern "C" JNIEXPORT jint JNICALL Java_Main_getClassModifiers(
112 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
113 jint mod;
114 jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod);
115 if (result != JVMTI_ERROR_NONE) {
116 char* err;
117 jvmti_env->GetErrorName(result, &err);
118 printf("Failure running GetClassModifiers: %s\n", err);
119 return JNI_FALSE;
120 }
121 return mod;
122}
123
Andreas Gampeac587272017-01-05 15:21:34 -0800124extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields(
125 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
126 jint count = 0;
127 jfieldID* fields = nullptr;
128 jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields);
129 if (result != JVMTI_ERROR_NONE) {
130 char* err;
131 jvmti_env->GetErrorName(result, &err);
132 printf("Failure running GetClassFields: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -0800133 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampeac587272017-01-05 15:21:34 -0800134 return nullptr;
135 }
136
137 auto callback = [&](jint i) {
138 jint modifiers;
139 // Ignore any errors for simplicity.
140 jvmti_env->GetFieldModifiers(klass, fields[i], &modifiers);
141 constexpr jint kStatic = 0x8;
142 return env->ToReflectedField(klass,
143 fields[i],
144 (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
145 };
Andreas Gampe8b07e472017-01-06 14:20:39 -0800146 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
147 if (fields != nullptr) {
148 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
149 }
150 return ret;
Andreas Gampeac587272017-01-05 15:21:34 -0800151}
152
Andreas Gampe18fee4d2017-01-06 11:36:35 -0800153extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods(
154 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
155 jint count = 0;
156 jmethodID* methods = nullptr;
157 jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods);
158 if (result != JVMTI_ERROR_NONE) {
159 char* err;
160 jvmti_env->GetErrorName(result, &err);
161 printf("Failure running GetClassMethods: %s\n", err);
162 return nullptr;
163 }
164
165 auto callback = [&](jint i) {
166 jint modifiers;
167 // Ignore any errors for simplicity.
168 jvmti_env->GetMethodModifiers(methods[i], &modifiers);
169 constexpr jint kStatic = 0x8;
170 return env->ToReflectedMethod(klass,
171 methods[i],
172 (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
173 };
Andreas Gampe8b07e472017-01-06 14:20:39 -0800174 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
175 if (methods != nullptr) {
176 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(methods));
177 }
178 return ret;
179}
180
181extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces(
182 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
183 jint count = 0;
184 jclass* classes = nullptr;
185 jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes);
186 if (result != JVMTI_ERROR_NONE) {
187 char* err;
188 jvmti_env->GetErrorName(result, &err);
189 printf("Failure running GetImplementedInterfaces: %s\n", err);
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;
Andreas Gampe18fee4d2017-01-06 11:36:35 -0800201}
202
Andreas Gampeff9d2092017-01-06 09:12:49 -0800203extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus(
204 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
205 jint status;
206 jvmtiError result = jvmti_env->GetClassStatus(klass, &status);
207 if (result != JVMTI_ERROR_NONE) {
208 char* err;
209 jvmti_env->GetErrorName(result, &err);
210 printf("Failure running GetClassStatus: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -0800211 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampeff9d2092017-01-06 09:12:49 -0800212 return JNI_FALSE;
213 }
214 return status;
215}
216
Andreas Gampe8f5b6032017-01-06 15:50:55 -0800217extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader(
218 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
219 jobject classloader;
220 jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader);
221 if (result != JVMTI_ERROR_NONE) {
222 char* err;
223 jvmti_env->GetErrorName(result, &err);
224 printf("Failure running GetClassLoader: %s\n", err);
225 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
226 return nullptr;
227 }
228 return classloader;
229}
230
Andreas Gampe70f16392017-01-16 14:20:10 -0800231extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses(
232 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) {
233 jint count = 0;
234 jclass* classes = nullptr;
235 jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes);
236 if (JvmtiErrorToException(env, result)) {
237 return nullptr;
238 }
239
240 auto callback = [&](jint i) {
241 return classes[i];
242 };
243 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
244 if (classes != nullptr) {
245 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
246 }
247 return ret;
248}
249
Andreas Gampe812a2442017-01-19 22:04:46 -0800250extern "C" JNIEXPORT jintArray JNICALL Java_Main_getClassVersion(
251 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
252 jint major, minor;
253 jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
254 if (JvmtiErrorToException(env, result)) {
255 return nullptr;
256 }
257
258 jintArray int_array = env->NewIntArray(2);
259 if (int_array == nullptr) {
260 return nullptr;
261 }
262 jint buf[2] = { major, minor };
263 env->SetIntArrayRegion(int_array, 0, 2, buf);
264
265 return int_array;
266}
267
Andreas Gampee6377462017-01-20 17:37:50 -0800268static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
269 char* name;
270 jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
271 if (result != JVMTI_ERROR_NONE) {
272 if (jni_env != nullptr) {
273 JvmtiErrorToException(jni_env, result);
274 } else {
275 printf("Failed to get class signature.\n");
276 }
277 return "";
278 }
279
280 std::string tmp(name);
281 jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
282
283 return tmp;
284}
285
Andreas Gampee2744c62017-02-08 16:28:59 +0000286static void EnableEvents(JNIEnv* env,
287 jboolean enable,
288 decltype(jvmtiEventCallbacks().ClassLoad) class_load,
289 decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
290 if (enable == JNI_FALSE) {
Andreas Gampee6377462017-01-20 17:37:50 -0800291 jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
292 JVMTI_EVENT_CLASS_LOAD,
293 nullptr);
294 if (JvmtiErrorToException(env, ret)) {
295 return;
296 }
297 ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
298 JVMTI_EVENT_CLASS_PREPARE,
299 nullptr);
300 JvmtiErrorToException(env, ret);
301 return;
302 }
303
304 jvmtiEventCallbacks callbacks;
305 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
Andreas Gampee2744c62017-02-08 16:28:59 +0000306 callbacks.ClassLoad = class_load;
307 callbacks.ClassPrepare = class_prepare;
Andreas Gampee6377462017-01-20 17:37:50 -0800308 jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
309 if (JvmtiErrorToException(env, ret)) {
310 return;
311 }
312
313 ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
314 JVMTI_EVENT_CLASS_LOAD,
315 nullptr);
316 if (JvmtiErrorToException(env, ret)) {
317 return;
318 }
319 ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
320 JVMTI_EVENT_CLASS_PREPARE,
321 nullptr);
322 JvmtiErrorToException(env, ret);
323}
324
Andreas Gampee2744c62017-02-08 16:28:59 +0000325class ClassLoadPreparePrinter {
326 public:
327 static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
328 JNIEnv* jni_env,
329 jthread thread,
330 jclass klass) {
331 std::string name = GetClassName(jenv, jni_env, klass);
332 if (name == "") {
333 return;
334 }
335 std::string thread_name = GetThreadName(jenv, jni_env, thread);
336 if (thread_name == "") {
337 return;
338 }
339 printf("Load: %s on %s\n", name.c_str(), thread_name.c_str());
340 }
341
342 static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
343 JNIEnv* jni_env,
344 jthread thread,
345 jclass klass) {
346 std::string name = GetClassName(jenv, jni_env, klass);
347 if (name == "") {
348 return;
349 }
350 std::string thread_name = GetThreadName(jenv, jni_env, thread);
351 if (thread_name == "") {
352 return;
353 }
354 std::string cur_thread_name = GetThreadName(Thread::Current());
355 printf("Prepare: %s on %s (cur=%s)\n",
356 name.c_str(),
357 thread_name.c_str(),
358 cur_thread_name.c_str());
359 }
360
361 private:
362 static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) {
363 jvmtiThreadInfo info;
364 jvmtiError result = jenv->GetThreadInfo(thread, &info);
365 if (result != JVMTI_ERROR_NONE) {
366 if (jni_env != nullptr) {
367 JvmtiErrorToException(jni_env, result);
368 } else {
369 printf("Failed to get thread name.\n");
370 }
371 return "";
372 }
373
374 std::string tmp(info.name);
375 jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name));
376 jni_env->DeleteLocalRef(info.context_class_loader);
377 jni_env->DeleteLocalRef(info.thread_group);
378
379 return tmp;
380 }
381
382 static std::string GetThreadName(Thread* thread) {
383 std::string tmp;
384 thread->GetThreadName(tmp);
385 return tmp;
386 }
387};
388
389extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPreparePrintEvents(
390 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable) {
391 EnableEvents(env,
392 enable,
393 ClassLoadPreparePrinter::ClassLoadCallback,
394 ClassLoadPreparePrinter::ClassPrepareCallback);
395}
396
397struct ClassLoadSeen {
398 static void JNICALL ClassLoadSeenCallback(jvmtiEnv* jenv ATTRIBUTE_UNUSED,
399 JNIEnv* jni_env ATTRIBUTE_UNUSED,
400 jthread thread ATTRIBUTE_UNUSED,
401 jclass klass ATTRIBUTE_UNUSED) {
402 saw_event = true;
403 }
404
405 static bool saw_event;
406};
407bool ClassLoadSeen::saw_event = false;
408
409extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadSeenEvents(
410 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
411 EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr);
412}
413
414extern "C" JNIEXPORT jboolean JNICALL Java_Main_hadLoadEvent(
415 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) {
416 return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE;
417}
418
419extern "C" JNIEXPORT jboolean JNICALL Java_Main_isLoadedClass(
420 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) {
421 ScopedUtfChars name(env, class_name);
422 ScopedObjectAccess soa(Thread::Current());
423 Runtime* current = Runtime::Current();
424 ClassLinker* class_linker = current->GetClassLinker();
425 bool found =
426 class_linker->LookupClass(
427 soa.Self(),
428 name.c_str(),
429 soa.Decode<mirror::ClassLoader>(current->GetSystemClassLoader())) != nullptr;
430 return found ? JNI_TRUE : JNI_FALSE;
431}
432
Andreas Gampe691051b2017-02-09 09:15:24 -0800433class ClassLoadPrepareEquality {
434 public:
435 static constexpr const char* kClassName = "LMain$ClassE;";
Andreas Gampea67354b2017-02-10 16:18:30 -0800436 static constexpr const char* kStorageFieldName = "STATIC";
437 static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;";
Andreas Gampe52784ac2017-02-13 18:10:09 -0800438 static constexpr const char* kStorageWeakFieldName = "WEAK";
439 static constexpr const char* kStorageWeakFieldSig = "Ljava/lang/ref/Reference;";
440 static constexpr const char* kWeakClassName = "java/lang/ref/WeakReference";
441 static constexpr const char* kWeakInitSig = "(Ljava/lang/Object;)V";
442 static constexpr const char* kWeakGetSig = "()Ljava/lang/Object;";
Andreas Gampe691051b2017-02-09 09:15:24 -0800443
444 static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
445 JNIEnv* jni_env,
446 jthread thread ATTRIBUTE_UNUSED,
447 jclass klass) {
448 std::string name = GetClassName(jenv, jni_env, klass);
449 if (name == kClassName) {
450 found_ = true;
451 stored_class_ = jni_env->NewGlobalRef(klass);
452 weakly_stored_class_ = jni_env->NewWeakGlobalRef(klass);
Andreas Gampe94dda932017-02-09 18:19:21 -0800453 // The following is bad and relies on implementation details. But otherwise a test would be
454 // a lot more complicated.
455 local_stored_class_ = jni_env->NewLocalRef(klass);
Andreas Gampea67354b2017-02-10 16:18:30 -0800456 // Store the value into a field in the heap.
457 SetOrCompare(jni_env, klass, true);
Andreas Gampe691051b2017-02-09 09:15:24 -0800458 }
459 }
460
461 static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
462 JNIEnv* jni_env,
463 jthread thread ATTRIBUTE_UNUSED,
464 jclass klass) {
465 std::string name = GetClassName(jenv, jni_env, klass);
466 if (name == kClassName) {
467 CHECK(stored_class_ != nullptr);
468 CHECK(jni_env->IsSameObject(stored_class_, klass));
469 CHECK(jni_env->IsSameObject(weakly_stored_class_, klass));
Andreas Gampe94dda932017-02-09 18:19:21 -0800470 CHECK(jni_env->IsSameObject(local_stored_class_, klass));
Andreas Gampea67354b2017-02-10 16:18:30 -0800471 // Look up the value in a field in the heap.
472 SetOrCompare(jni_env, klass, false);
Andreas Gampe691051b2017-02-09 09:15:24 -0800473 compared_ = true;
474 }
475 }
476
Andreas Gampea67354b2017-02-10 16:18:30 -0800477 static void SetOrCompare(JNIEnv* jni_env, jobject value, bool set) {
478 CHECK(storage_class_ != nullptr);
Andreas Gampe52784ac2017-02-13 18:10:09 -0800479
480 // Simple direct storage.
Andreas Gampea67354b2017-02-10 16:18:30 -0800481 jfieldID field = jni_env->GetStaticFieldID(storage_class_, kStorageFieldName, kStorageFieldSig);
482 CHECK(field != nullptr);
483
484 if (set) {
485 jni_env->SetStaticObjectField(storage_class_, field, value);
486 CHECK(!jni_env->ExceptionCheck());
487 } else {
488 ScopedLocalRef<jobject> stored(jni_env, jni_env->GetStaticObjectField(storage_class_, field));
489 CHECK(jni_env->IsSameObject(value, stored.get()));
490 }
Andreas Gampe52784ac2017-02-13 18:10:09 -0800491
492 // Storage as a reference.
493 ScopedLocalRef<jclass> weak_ref_class(jni_env, jni_env->FindClass(kWeakClassName));
494 CHECK(weak_ref_class.get() != nullptr);
495 jfieldID weak_field = jni_env->GetStaticFieldID(storage_class_,
496 kStorageWeakFieldName,
497 kStorageWeakFieldSig);
498 CHECK(weak_field != nullptr);
499 if (set) {
500 // Create a WeakReference.
501 jmethodID weak_init = jni_env->GetMethodID(weak_ref_class.get(), "<init>", kWeakInitSig);
502 CHECK(weak_init != nullptr);
503 ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->NewObject(weak_ref_class.get(),
504 weak_init,
505 value));
506 CHECK(weak_obj.get() != nullptr);
507 jni_env->SetStaticObjectField(storage_class_, weak_field, weak_obj.get());
508 CHECK(!jni_env->ExceptionCheck());
509 } else {
510 // Check the reference value.
511 jmethodID get_referent = jni_env->GetMethodID(weak_ref_class.get(), "get", kWeakGetSig);
512 CHECK(get_referent != nullptr);
513 ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->GetStaticObjectField(storage_class_,
514 weak_field));
515 CHECK(weak_obj.get() != nullptr);
516 ScopedLocalRef<jobject> weak_referent(jni_env, jni_env->CallObjectMethod(weak_obj.get(),
517 get_referent));
518 CHECK(weak_referent.get() != nullptr);
519 CHECK(jni_env->IsSameObject(value, weak_referent.get()));
520 }
Andreas Gampea67354b2017-02-10 16:18:30 -0800521 }
522
Andreas Gampe691051b2017-02-09 09:15:24 -0800523 static void CheckFound() {
524 CHECK(found_);
525 CHECK(compared_);
526 }
527
528 static void Free(JNIEnv* env) {
529 if (stored_class_ != nullptr) {
530 env->DeleteGlobalRef(stored_class_);
531 DCHECK(weakly_stored_class_ != nullptr);
532 env->DeleteWeakGlobalRef(weakly_stored_class_);
Andreas Gampe94dda932017-02-09 18:19:21 -0800533 // Do not attempt to delete the local ref. It will be out of date by now.
Andreas Gampe691051b2017-02-09 09:15:24 -0800534 }
535 }
536
Andreas Gampea67354b2017-02-10 16:18:30 -0800537 static jclass storage_class_;
538
Andreas Gampe691051b2017-02-09 09:15:24 -0800539 private:
540 static jobject stored_class_;
541 static jweak weakly_stored_class_;
Andreas Gampe94dda932017-02-09 18:19:21 -0800542 static jobject local_stored_class_;
Andreas Gampe691051b2017-02-09 09:15:24 -0800543 static bool found_;
544 static bool compared_;
545};
Andreas Gampea67354b2017-02-10 16:18:30 -0800546jclass ClassLoadPrepareEquality::storage_class_ = nullptr;
Andreas Gampe691051b2017-02-09 09:15:24 -0800547jobject ClassLoadPrepareEquality::stored_class_ = nullptr;
548jweak ClassLoadPrepareEquality::weakly_stored_class_ = nullptr;
Andreas Gampe94dda932017-02-09 18:19:21 -0800549jobject ClassLoadPrepareEquality::local_stored_class_ = nullptr;
Andreas Gampe691051b2017-02-09 09:15:24 -0800550bool ClassLoadPrepareEquality::found_ = false;
551bool ClassLoadPrepareEquality::compared_ = false;
552
Andreas Gampea67354b2017-02-10 16:18:30 -0800553extern "C" JNIEXPORT void JNICALL Java_Main_setEqualityEventStorageClass(
554 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
555 ClassLoadPrepareEquality::storage_class_ =
556 reinterpret_cast<jclass>(env->NewGlobalRef(klass));
557}
558
Andreas Gampe691051b2017-02-09 09:15:24 -0800559extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPrepareEqualityEvents(
560 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
561 EnableEvents(env,
562 b,
563 ClassLoadPrepareEquality::ClassLoadCallback,
564 ClassLoadPrepareEquality::ClassPrepareCallback);
565 if (b == JNI_FALSE) {
566 ClassLoadPrepareEquality::Free(env);
567 ClassLoadPrepareEquality::CheckFound();
Andreas Gampea67354b2017-02-10 16:18:30 -0800568 env->DeleteGlobalRef(ClassLoadPrepareEquality::storage_class_);
569 ClassLoadPrepareEquality::storage_class_ = nullptr;
Andreas Gampe691051b2017-02-09 09:15:24 -0800570 }
571}
572
Andreas Gampee492ae32016-10-28 19:34:57 -0700573} // namespace Test912Classes
574} // namespace art