xref: /aosp_15_r20/art/test/common/stack_inspect.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "jni.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "arch/context.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "jni/jni_internal.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "nth_caller_visitor.h"
27*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file.h"
28*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
29*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
30*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "stack.h"
32*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker static bool asserts_enabled = true;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // public static native void disableStackFrameAsserts();
39*795d594fSAndroid Build Coastguard Worker // Note: to globally disable asserts in unsupported configurations.
40*795d594fSAndroid Build Coastguard Worker 
Java_Main_disableStackFrameAsserts(JNIEnv * env,jclass cls)41*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_disableStackFrameAsserts([[maybe_unused]] JNIEnv* env,
42*795d594fSAndroid Build Coastguard Worker                                                                      [[maybe_unused]] jclass cls) {
43*795d594fSAndroid Build Coastguard Worker   asserts_enabled = false;
44*795d594fSAndroid Build Coastguard Worker }
45*795d594fSAndroid Build Coastguard Worker 
IsInterpreted(JNIEnv * env,jclass,size_t level)46*795d594fSAndroid Build Coastguard Worker static jboolean IsInterpreted(JNIEnv* env, jclass, size_t level) {
47*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(env);
48*795d594fSAndroid Build Coastguard Worker   NthCallerVisitor caller(soa.Self(), level, false);
49*795d594fSAndroid Build Coastguard Worker   caller.WalkStack();
50*795d594fSAndroid Build Coastguard Worker   CHECK(caller.caller != nullptr);
51*795d594fSAndroid Build Coastguard Worker   bool is_shadow_frame = (caller.GetCurrentShadowFrame() != nullptr);
52*795d594fSAndroid Build Coastguard Worker   bool is_nterp_frame = (caller.GetCurrentQuickFrame() != nullptr) &&
53*795d594fSAndroid Build Coastguard Worker       (caller.GetCurrentOatQuickMethodHeader()->IsNterpMethodHeader());
54*795d594fSAndroid Build Coastguard Worker   return (is_shadow_frame || is_nterp_frame) ? JNI_TRUE : JNI_FALSE;
55*795d594fSAndroid Build Coastguard Worker }
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker // public static native boolean isInterpreted();
58*795d594fSAndroid Build Coastguard Worker 
Java_Main_isInterpreted(JNIEnv * env,jclass klass)59*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpreted(JNIEnv* env, jclass klass) {
60*795d594fSAndroid Build Coastguard Worker   return IsInterpreted(env, klass, 1);
61*795d594fSAndroid Build Coastguard Worker }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker // public static native boolean isInterpreted(int depth);
64*795d594fSAndroid Build Coastguard Worker 
Java_Main_isInterpretedAt(JNIEnv * env,jclass klass,jint depth)65*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedAt(JNIEnv* env,
66*795d594fSAndroid Build Coastguard Worker                                                                 jclass klass,
67*795d594fSAndroid Build Coastguard Worker                                                                 jint depth) {
68*795d594fSAndroid Build Coastguard Worker   return IsInterpreted(env, klass, depth);
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker // public static native boolean isInterpretedFunction(String smali);
73*795d594fSAndroid Build Coastguard Worker 
IsMethodInterpreted(Thread * self,const ArtMethod * goal,const bool require_deoptable,bool * method_is_interpreted)74*795d594fSAndroid Build Coastguard Worker static bool IsMethodInterpreted(Thread* self,
75*795d594fSAndroid Build Coastguard Worker                                 const ArtMethod* goal,
76*795d594fSAndroid Build Coastguard Worker                                 const bool require_deoptable,
77*795d594fSAndroid Build Coastguard Worker                                 /* out */ bool* method_is_interpreted)
78*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
79*795d594fSAndroid Build Coastguard Worker   *method_is_interpreted = true;
80*795d594fSAndroid Build Coastguard Worker   bool method_found = false;
81*795d594fSAndroid Build Coastguard Worker   bool prev_was_runtime = true;
82*795d594fSAndroid Build Coastguard Worker   StackVisitor::WalkStack(
83*795d594fSAndroid Build Coastguard Worker       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
84*795d594fSAndroid Build Coastguard Worker         if (goal == stack_visitor->GetMethod()) {
85*795d594fSAndroid Build Coastguard Worker           // We don't deoptimize beyond a runtime frame. So if we need the method to be
86*795d594fSAndroid Build Coastguard Worker           // deoptimizeable we cannot allow the previous frame to be a runtime frame.
87*795d594fSAndroid Build Coastguard Worker           *method_is_interpreted =
88*795d594fSAndroid Build Coastguard Worker               (require_deoptable && prev_was_runtime) || stack_visitor->IsShadowFrame();
89*795d594fSAndroid Build Coastguard Worker           method_found = true;
90*795d594fSAndroid Build Coastguard Worker           return false;
91*795d594fSAndroid Build Coastguard Worker         }
92*795d594fSAndroid Build Coastguard Worker         prev_was_runtime = stack_visitor->GetMethod()->IsRuntimeMethod();
93*795d594fSAndroid Build Coastguard Worker         return true;
94*795d594fSAndroid Build Coastguard Worker       },
95*795d594fSAndroid Build Coastguard Worker       self,
96*795d594fSAndroid Build Coastguard Worker       /* context= */ nullptr,
97*795d594fSAndroid Build Coastguard Worker       art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
98*795d594fSAndroid Build Coastguard Worker   return method_found;
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker // TODO Remove 'require_deoptimizable' option once we have deoptimization through runtime frames.
Java_Main_isInterpretedFunction(JNIEnv * env,jclass klass,jobject method,jboolean require_deoptimizable)102*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedFunction(
103*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jobject method, jboolean require_deoptimizable) {
104*795d594fSAndroid Build Coastguard Worker   // Return false if this seems to not be an ART runtime.
105*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current() == nullptr) {
106*795d594fSAndroid Build Coastguard Worker     return JNI_FALSE;
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker   if (method == nullptr) {
109*795d594fSAndroid Build Coastguard Worker     env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "method is null!");
110*795d594fSAndroid Build Coastguard Worker     return JNI_FALSE;
111*795d594fSAndroid Build Coastguard Worker   }
112*795d594fSAndroid Build Coastguard Worker   jmethodID id = env->FromReflectedMethod(method);
113*795d594fSAndroid Build Coastguard Worker   if (id == nullptr) {
114*795d594fSAndroid Build Coastguard Worker     env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to interpret method argument!");
115*795d594fSAndroid Build Coastguard Worker     return JNI_FALSE;
116*795d594fSAndroid Build Coastguard Worker   }
117*795d594fSAndroid Build Coastguard Worker   {
118*795d594fSAndroid Build Coastguard Worker     ScopedObjectAccess soa(env);
119*795d594fSAndroid Build Coastguard Worker     ArtMethod* goal = jni::DecodeArtMethod(id);
120*795d594fSAndroid Build Coastguard Worker     bool is_interpreted;
121*795d594fSAndroid Build Coastguard Worker     if (!IsMethodInterpreted(soa.Self(), goal, require_deoptimizable, &is_interpreted)) {
122*795d594fSAndroid Build Coastguard Worker       env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to find given method in stack!");
123*795d594fSAndroid Build Coastguard Worker       return JNI_FALSE;
124*795d594fSAndroid Build Coastguard Worker     }
125*795d594fSAndroid Build Coastguard Worker     bool enters_interpreter = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(
126*795d594fSAndroid Build Coastguard Worker         goal->GetEntryPointFromQuickCompiledCode());
127*795d594fSAndroid Build Coastguard Worker     return (is_interpreted || enters_interpreter);
128*795d594fSAndroid Build Coastguard Worker   }
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker // public static native void assertIsInterpreted();
132*795d594fSAndroid Build Coastguard Worker 
Java_Main_assertIsInterpreted(JNIEnv * env,jclass klass)133*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_assertIsInterpreted(JNIEnv* env, jclass klass) {
134*795d594fSAndroid Build Coastguard Worker   if (asserts_enabled) {
135*795d594fSAndroid Build Coastguard Worker     CHECK(Java_Main_isInterpreted(env, klass));
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker 
IsManaged(JNIEnv * env,jclass,size_t level)139*795d594fSAndroid Build Coastguard Worker static jboolean IsManaged(JNIEnv* env, jclass, size_t level) {
140*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(env);
141*795d594fSAndroid Build Coastguard Worker   NthCallerVisitor caller(soa.Self(), level, false);
142*795d594fSAndroid Build Coastguard Worker   caller.WalkStack();
143*795d594fSAndroid Build Coastguard Worker   CHECK(caller.caller != nullptr);
144*795d594fSAndroid Build Coastguard Worker   return caller.GetCurrentShadowFrame() != nullptr ? JNI_FALSE : JNI_TRUE;
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker // public static native boolean isManaged();
148*795d594fSAndroid Build Coastguard Worker 
Java_Main_isManaged(JNIEnv * env,jclass cls)149*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isManaged(JNIEnv* env, jclass cls) {
150*795d594fSAndroid Build Coastguard Worker   return IsManaged(env, cls, 1);
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker // public static native void assertIsManaged();
154*795d594fSAndroid Build Coastguard Worker 
Java_Main_assertIsManaged(JNIEnv * env,jclass cls)155*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_assertIsManaged(JNIEnv* env, jclass cls) {
156*795d594fSAndroid Build Coastguard Worker   if (asserts_enabled) {
157*795d594fSAndroid Build Coastguard Worker     CHECK(Java_Main_isManaged(env, cls));
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker // public static native boolean isCallerInterpreted();
162*795d594fSAndroid Build Coastguard Worker 
Java_Main_isCallerInterpreted(JNIEnv * env,jclass klass)163*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerInterpreted(JNIEnv* env, jclass klass) {
164*795d594fSAndroid Build Coastguard Worker   return IsInterpreted(env, klass, 2);
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker // public static native void assertCallerIsInterpreted();
168*795d594fSAndroid Build Coastguard Worker 
Java_Main_assertCallerIsInterpreted(JNIEnv * env,jclass klass)169*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsInterpreted(JNIEnv* env, jclass klass) {
170*795d594fSAndroid Build Coastguard Worker   if (asserts_enabled) {
171*795d594fSAndroid Build Coastguard Worker     CHECK(Java_Main_isCallerInterpreted(env, klass));
172*795d594fSAndroid Build Coastguard Worker   }
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker // public static native boolean isCallerManaged();
176*795d594fSAndroid Build Coastguard Worker 
Java_Main_isCallerManaged(JNIEnv * env,jclass cls)177*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerManaged(JNIEnv* env, jclass cls) {
178*795d594fSAndroid Build Coastguard Worker   return IsManaged(env, cls, 2);
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker // public static native void assertCallerIsManaged();
182*795d594fSAndroid Build Coastguard Worker 
Java_Main_assertCallerIsManaged(JNIEnv * env,jclass cls)183*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsManaged(JNIEnv* env, jclass cls) {
184*795d594fSAndroid Build Coastguard Worker   if (asserts_enabled) {
185*795d594fSAndroid Build Coastguard Worker     CHECK(Java_Main_isCallerManaged(env, cls));
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker 
Java_Main_getThisOfCaller(JNIEnv * env,jclass cls)189*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobject JNICALL Java_Main_getThisOfCaller(
190*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass cls) {
191*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(env);
192*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<art::Context> context(art::Context::Create());
193*795d594fSAndroid Build Coastguard Worker   jobject result = nullptr;
194*795d594fSAndroid Build Coastguard Worker   StackVisitor::WalkStack(
195*795d594fSAndroid Build Coastguard Worker       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
196*795d594fSAndroid Build Coastguard Worker         // Discard stubs and Main.getThisOfCaller and methods without vreg info.
197*795d594fSAndroid Build Coastguard Worker         if (stack_visitor->GetMethod() == nullptr ||
198*795d594fSAndroid Build Coastguard Worker             stack_visitor->GetMethod()->IsNative() ||
199*795d594fSAndroid Build Coastguard Worker             (stack_visitor->GetCurrentShadowFrame() == nullptr &&
200*795d594fSAndroid Build Coastguard Worker              !Runtime::Current()->IsAsyncDeoptimizeable(stack_visitor->GetOuterMethod(),
201*795d594fSAndroid Build Coastguard Worker                                                         stack_visitor->GetCurrentQuickFramePc()))) {
202*795d594fSAndroid Build Coastguard Worker           return true;
203*795d594fSAndroid Build Coastguard Worker         }
204*795d594fSAndroid Build Coastguard Worker         result = soa.AddLocalReference<jobject>(stack_visitor->GetThisObject());
205*795d594fSAndroid Build Coastguard Worker         return false;
206*795d594fSAndroid Build Coastguard Worker       },
207*795d594fSAndroid Build Coastguard Worker       soa.Self(),
208*795d594fSAndroid Build Coastguard Worker       context.get(),
209*795d594fSAndroid Build Coastguard Worker       art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
210*795d594fSAndroid Build Coastguard Worker   return result;
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker }  // namespace art
214