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