1 /* 2 * Copyright (C) 2015 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 "jni.h" 18 19 #include "base/logging.h" 20 #include "dex_file-inl.h" 21 #include "jni_internal.h" 22 #include "mirror/class-inl.h" 23 #include "nth_caller_visitor.h" 24 #include "oat_file.h" 25 #include "runtime.h" 26 #include "scoped_thread_state_change-inl.h" 27 #include "stack.h" 28 #include "thread-current-inl.h" 29 30 namespace art { 31 32 static bool asserts_enabled = true; 33 34 // public static native void disableStackFrameAsserts(); 35 // Note: to globally disable asserts in unsupported configurations. 36 37 extern "C" JNIEXPORT void JNICALL Java_Main_disableStackFrameAsserts(JNIEnv* env ATTRIBUTE_UNUSED, 38 jclass cls ATTRIBUTE_UNUSED) { 39 asserts_enabled = false; 40 } 41 42 static jboolean IsInterpreted(JNIEnv* env, jclass, size_t level) { 43 ScopedObjectAccess soa(env); 44 NthCallerVisitor caller(soa.Self(), level, false); 45 caller.WalkStack(); 46 CHECK(caller.caller != nullptr); 47 return caller.GetCurrentShadowFrame() != nullptr ? JNI_TRUE : JNI_FALSE; 48 } 49 50 // public static native boolean isInterpreted(); 51 52 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpreted(JNIEnv* env, jclass klass) { 53 return IsInterpreted(env, klass, 1); 54 } 55 56 // public static native boolean isInterpreted(int depth); 57 58 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedAt(JNIEnv* env, 59 jclass klass, 60 jint depth) { 61 return IsInterpreted(env, klass, depth); 62 } 63 64 65 // public static native boolean isInterpretedFunction(String smali); 66 67 // TODO Remove 'allow_runtime_frames' option once we have deoptimization through runtime frames. 68 struct MethodIsInterpretedVisitor : public StackVisitor { 69 public: 70 MethodIsInterpretedVisitor(Thread* thread, ArtMethod* goal, bool require_deoptable) 71 : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), 72 goal_(goal), 73 method_is_interpreted_(true), 74 method_found_(false), 75 prev_was_runtime_(true), 76 require_deoptable_(require_deoptable) {} 77 78 virtual bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 79 if (goal_ == GetMethod()) { 80 method_is_interpreted_ = (require_deoptable_ && prev_was_runtime_) || IsShadowFrame(); 81 method_found_ = true; 82 return false; 83 } 84 prev_was_runtime_ = GetMethod()->IsRuntimeMethod(); 85 return true; 86 } 87 88 bool IsInterpreted() { 89 return method_is_interpreted_; 90 } 91 92 bool IsFound() { 93 return method_found_; 94 } 95 96 private: 97 const ArtMethod* goal_; 98 bool method_is_interpreted_; 99 bool method_found_; 100 bool prev_was_runtime_; 101 bool require_deoptable_; 102 }; 103 104 // TODO Remove 'require_deoptimizable' option once we have deoptimization through runtime frames. 105 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedFunction( 106 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean require_deoptimizable) { 107 // Return false if this seems to not be an ART runtime. 108 if (Runtime::Current() == nullptr) { 109 return JNI_FALSE; 110 } 111 if (method == nullptr) { 112 env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "method is null!"); 113 return JNI_FALSE; 114 } 115 jmethodID id = env->FromReflectedMethod(method); 116 if (id == nullptr) { 117 env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to interpret method argument!"); 118 return JNI_FALSE; 119 } 120 bool result; 121 bool found; 122 { 123 ScopedObjectAccess soa(env); 124 ArtMethod* goal = jni::DecodeArtMethod(id); 125 MethodIsInterpretedVisitor v(soa.Self(), goal, require_deoptimizable); 126 v.WalkStack(); 127 bool enters_interpreter = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge( 128 goal->GetEntryPointFromQuickCompiledCode()); 129 result = (v.IsInterpreted() || enters_interpreter); 130 found = v.IsFound(); 131 } 132 if (!found) { 133 env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to find given method in stack!"); 134 return JNI_FALSE; 135 } 136 return result; 137 } 138 139 // public static native void assertIsInterpreted(); 140 141 extern "C" JNIEXPORT void JNICALL Java_Main_assertIsInterpreted(JNIEnv* env, jclass klass) { 142 if (asserts_enabled) { 143 CHECK(Java_Main_isInterpreted(env, klass)); 144 } 145 } 146 147 static jboolean IsManaged(JNIEnv* env, jclass, size_t level) { 148 ScopedObjectAccess soa(env); 149 NthCallerVisitor caller(soa.Self(), level, false); 150 caller.WalkStack(); 151 CHECK(caller.caller != nullptr); 152 return caller.GetCurrentShadowFrame() != nullptr ? JNI_FALSE : JNI_TRUE; 153 } 154 155 // public static native boolean isManaged(); 156 157 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isManaged(JNIEnv* env, jclass cls) { 158 return IsManaged(env, cls, 1); 159 } 160 161 // public static native void assertIsManaged(); 162 163 extern "C" JNIEXPORT void JNICALL Java_Main_assertIsManaged(JNIEnv* env, jclass cls) { 164 if (asserts_enabled) { 165 CHECK(Java_Main_isManaged(env, cls)); 166 } 167 } 168 169 // public static native boolean isCallerInterpreted(); 170 171 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerInterpreted(JNIEnv* env, jclass klass) { 172 return IsInterpreted(env, klass, 2); 173 } 174 175 // public static native void assertCallerIsInterpreted(); 176 177 extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsInterpreted(JNIEnv* env, jclass klass) { 178 if (asserts_enabled) { 179 CHECK(Java_Main_isCallerInterpreted(env, klass)); 180 } 181 } 182 183 // public static native boolean isCallerManaged(); 184 185 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerManaged(JNIEnv* env, jclass cls) { 186 return IsManaged(env, cls, 2); 187 } 188 189 // public static native void assertCallerIsManaged(); 190 191 extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsManaged(JNIEnv* env, jclass cls) { 192 if (asserts_enabled) { 193 CHECK(Java_Main_isCallerManaged(env, cls)); 194 } 195 } 196 197 } // namespace art 198