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 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 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 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 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