1 /*
2 * Copyright (C) 2017 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 "common_helper.h"
18
19 #include "jni.h"
20 #include "jvmti.h"
21
22 #include "jvmti_helper.h"
23 #include "scoped_local_ref.h"
24 #include "test_env.h"
25
26 namespace art {
27 namespace common_frame_pop {
28
29 struct FramePopData {
30 jclass test_klass;
31 jmethodID pop_method;
32 };
33
framePopCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jmethodID method ATTRIBUTE_UNUSED,jboolean was_popped_by_exception)34 static void framePopCB(jvmtiEnv* jvmti,
35 JNIEnv* jnienv,
36 jthread thr,
37 jmethodID method ATTRIBUTE_UNUSED,
38 jboolean was_popped_by_exception) {
39 FramePopData* data = nullptr;
40 if (JvmtiErrorToException(jnienv, jvmti,
41 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
42 return;
43 }
44 jlong location;
45 jmethodID frame_method;
46 if (JvmtiErrorToException(jnienv,
47 jvmti,
48 jvmti->GetFrameLocation(thr, 0, &frame_method, &location))) {
49 return;
50 }
51 CHECK(data->pop_method != nullptr);
52 jobject method_arg = GetJavaMethod(jvmti, jnienv, frame_method);
53 jnienv->CallStaticVoidMethod(data->test_klass,
54 data->pop_method,
55 method_arg,
56 was_popped_by_exception,
57 location);
58 jnienv->DeleteLocalRef(method_arg);
59 }
60
Java_art_FramePop_enableFramePopEvent(JNIEnv * env,jclass,jclass klass,jobject notify_method,jthread thr)61 extern "C" JNIEXPORT void JNICALL Java_art_FramePop_enableFramePopEvent(
62 JNIEnv* env, jclass, jclass klass, jobject notify_method, jthread thr) {
63 FramePopData* data = nullptr;
64 if (JvmtiErrorToException(env,
65 jvmti_env,
66 jvmti_env->Allocate(sizeof(FramePopData),
67 reinterpret_cast<unsigned char**>(&data)))) {
68 return;
69 }
70 memset(data, 0, sizeof(FramePopData));
71 data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
72 data->pop_method = env->FromReflectedMethod(notify_method);
73 if (env->ExceptionCheck()) {
74 return;
75 }
76 void* old_data = nullptr;
77 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
78 return;
79 } else if (old_data != nullptr) {
80 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
81 env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
82 return;
83 }
84 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
85 return;
86 }
87 jvmtiCapabilities caps;
88 memset(&caps, 0, sizeof(caps));
89 caps.can_generate_frame_pop_events = 1;
90 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
91 return;
92 }
93 current_callbacks.FramePop = framePopCB;
94 if (JvmtiErrorToException(env,
95 jvmti_env,
96 jvmti_env->SetEventCallbacks(¤t_callbacks,
97 sizeof(current_callbacks)))) {
98 return;
99 }
100 JvmtiErrorToException(env,
101 jvmti_env,
102 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
103 JVMTI_EVENT_FRAME_POP,
104 thr));
105 }
106
Java_art_FramePop_makeJvmtiEnvForFramePop(JNIEnv * env,jclass)107 extern "C" JNIEXPORT jlong JNICALL Java_art_FramePop_makeJvmtiEnvForFramePop(JNIEnv* env, jclass) {
108 JavaVM* vm;
109 jvmtiEnv* out_jvmti_env = nullptr;
110 if (env->GetJavaVM(&vm) != JNI_OK ||
111 vm->GetEnv(reinterpret_cast<void**>(&out_jvmti_env), JVMTI_VERSION_1_0) != JNI_OK) {
112 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
113 if (rt_exception.get() == nullptr) {
114 // CNFE should be pending.
115 return 0L;
116 }
117 env->ThrowNew(rt_exception.get(), "Unable to create new jvmti_env");
118 return 0L;
119 }
120 SetAllCapabilities(out_jvmti_env);
121 return static_cast<jlong>(reinterpret_cast<intptr_t>(out_jvmti_env));
122 }
123
Java_art_FramePop_notifyFramePop(JNIEnv * env,jclass,jthread thr,jint depth)124 extern "C" JNIEXPORT void JNICALL Java_art_FramePop_notifyFramePop(
125 JNIEnv* env, jclass, jthread thr, jint depth) {
126 JvmtiErrorToException(env, jvmti_env, jvmti_env->NotifyFramePop(thr, depth));
127 }
128
129 } // namespace common_frame_pop
130 } // namespace art
131
132