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
35namespace art {
36namespace Test912ArtClasses {
37
38static void EnableEvents(JNIEnv* env,
39                         jboolean enable,
40                         decltype(jvmtiEventCallbacks().ClassLoad) class_load,
41                         decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
42  if (enable == JNI_FALSE) {
43    jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
44                                                         JVMTI_EVENT_CLASS_LOAD,
45                                                         nullptr);
46    if (JvmtiErrorToException(env, jvmti_env, ret)) {
47      return;
48    }
49    ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
50                                              JVMTI_EVENT_CLASS_PREPARE,
51                                              nullptr);
52    JvmtiErrorToException(env, jvmti_env, ret);
53    return;
54  }
55
56  jvmtiEventCallbacks callbacks;
57  memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
58  callbacks.ClassLoad = class_load;
59  callbacks.ClassPrepare = class_prepare;
60  jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
61  if (JvmtiErrorToException(env, jvmti_env, ret)) {
62    return;
63  }
64
65  ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
66                                            JVMTI_EVENT_CLASS_LOAD,
67                                            nullptr);
68  if (JvmtiErrorToException(env, jvmti_env, ret)) {
69    return;
70  }
71  ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
72                                            JVMTI_EVENT_CLASS_PREPARE,
73                                            nullptr);
74  JvmtiErrorToException(env, jvmti_env, ret);
75}
76
77struct ClassLoadSeen {
78  static void JNICALL ClassLoadSeenCallback(jvmtiEnv* jenv ATTRIBUTE_UNUSED,
79                                            JNIEnv* jni_env ATTRIBUTE_UNUSED,
80                                            jthread thread ATTRIBUTE_UNUSED,
81                                            jclass klass ATTRIBUTE_UNUSED) {
82    saw_event = true;
83  }
84
85  static bool saw_event;
86};
87bool ClassLoadSeen::saw_event = false;
88
89extern "C" JNIEXPORT void JNICALL Java_art_Test912Art_enableClassLoadSeenEvents(
90    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
91  EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr);
92}
93
94extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hadLoadEvent(
95    JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) {
96  return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE;
97}
98
99extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_isLoadedClass(
100    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) {
101  ScopedUtfChars name(env, class_name);
102
103  jint class_count;
104  jclass* classes;
105  jvmtiError res = jvmti_env->GetLoadedClasses(&class_count, &classes);
106  if (JvmtiErrorToException(env, jvmti_env, res)) {
107    return JNI_FALSE;
108  }
109
110  bool found = false;
111  for (jint i = 0; !found && i < class_count; ++i) {
112    char* sig;
113    jvmtiError res2 = jvmti_env->GetClassSignature(classes[i], &sig, nullptr);
114    if (JvmtiErrorToException(env, jvmti_env, res2)) {
115      return JNI_FALSE;
116    }
117
118    found = strcmp(name.c_str(), sig) == 0;
119
120    CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig)));
121  }
122
123  CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)));
124
125  return found;
126}
127
128// We use the implementations from runtime_state.cc.
129
130extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
131                                                             jclass,
132                                                             jclass cls,
133                                                             jstring method_name);
134extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass);
135
136extern "C" JNIEXPORT void JNICALL Java_art_Test912Art_ensureJitCompiled(
137    JNIEnv* env, jclass klass, jclass test_class, jstring name) {
138  Java_Main_ensureJitCompiled(env, klass, test_class, name);
139}
140
141extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hasJit(JNIEnv* env, jclass klass) {
142  return Java_Main_hasJit(env, klass);
143}
144
145}  // namespace Test912ArtClasses
146}  // namespace art
147