Home | History | Annotate | Download | only in common
      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