1 /*
2  * Copyright (C) 2016 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 "art_method-inl.h"
18 #include "jit/jit.h"
19 #include "jit/jit_code_cache.h"
20 #include "jit/profiling_info.h"
21 #include "nativehelper/ScopedUtfChars.h"
22 #include "oat_quick_method_header.h"
23 #include "scoped_thread_state_change-inl.h"
24 #include "stack.h"
25 #include "stack_map.h"
26 #include "thread-current-inl.h"
27 
28 namespace art {
29 
30 namespace {
31 
32 template <typename Handler>
ProcessMethodWithName(JNIEnv * env,jstring method_name,const Handler & handler)33 void ProcessMethodWithName(JNIEnv* env, jstring method_name, const Handler& handler) {
34   ScopedUtfChars chars(env, method_name);
35   CHECK(chars.c_str() != nullptr);
36   ScopedObjectAccess soa(Thread::Current());
37   StackVisitor::WalkStack(
38       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
39         std::string m_name(stack_visitor->GetMethod()->GetName());
40 
41         if (m_name.compare(chars.c_str()) == 0) {
42           handler(stack_visitor);
43           return false;
44         }
45         return true;
46       },
47       soa.Self(),
48       /* context= */ nullptr,
49       art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
50 }
51 
52 }  // namespace
53 
Java_Main_isInOsrCode(JNIEnv * env,jclass,jstring method_name)54 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInOsrCode(JNIEnv* env,
55                                                             jclass,
56                                                             jstring method_name) {
57   jit::Jit* jit = Runtime::Current()->GetJit();
58   if (jit == nullptr) {
59     // Just return true for non-jit configurations to stop the infinite loop.
60     return JNI_TRUE;
61   }
62   bool in_osr_code = false;
63   ProcessMethodWithName(
64       env,
65       method_name,
66       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
67         ArtMethod* m = stack_visitor->GetMethod();
68         const OatQuickMethodHeader* header =
69             Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
70         if (header != nullptr && header == stack_visitor->GetCurrentOatQuickMethodHeader()) {
71           in_osr_code = true;
72         }
73       });
74   return in_osr_code;
75 }
76 
Java_Main_isInInterpreter(JNIEnv * env,jclass,jstring method_name)77 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInInterpreter(JNIEnv* env,
78                                                                 jclass,
79                                                                 jstring method_name) {
80   if (!Runtime::Current()->UseJitCompilation()) {
81     // The return value is irrelevant if we're not using JIT.
82     return false;
83   }
84   bool in_interpreter = false;
85   ProcessMethodWithName(
86       env,
87       method_name,
88       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
89         ArtMethod* m = stack_visitor->GetMethod();
90         const OatQuickMethodHeader* header =
91             Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
92         if ((header == nullptr || header != stack_visitor->GetCurrentOatQuickMethodHeader()) &&
93             (stack_visitor->IsShadowFrame() ||
94              stack_visitor->GetCurrentOatQuickMethodHeader()->IsNterpMethodHeader())) {
95           in_interpreter = true;
96         }
97       });
98   return in_interpreter;
99 }
100 
Java_Main_ensureHasProfilingInfo(JNIEnv * env,jclass,jstring method_name)101 extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasProfilingInfo(JNIEnv* env,
102                                                                    jclass,
103                                                                    jstring method_name) {
104   if (!Runtime::Current()->UseJitCompilation()) {
105     return;
106   }
107   ProcessMethodWithName(
108       env,
109       method_name,
110       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
111         ArtMethod* m = stack_visitor->GetMethod();
112         ProfilingInfo::Create(Thread::Current(), m, /* retry_allocation */ true);
113       });
114 }
115 
Java_Main_ensureHasOsrCode(JNIEnv * env,jclass,jstring method_name)116 extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasOsrCode(JNIEnv* env,
117                                                              jclass,
118                                                              jstring method_name) {
119   if (!Runtime::Current()->UseJitCompilation()) {
120     return;
121   }
122   ProcessMethodWithName(
123       env,
124       method_name,
125       [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
126         ArtMethod* m = stack_visitor->GetMethod();
127         jit::Jit* jit = Runtime::Current()->GetJit();
128         while (jit->GetCodeCache()->LookupOsrMethodHeader(m) == nullptr) {
129           // Sleep to yield to the compiler thread.
130           usleep(1000);
131           // Will either ensure it's compiled or do the compilation itself.
132           jit->CompileMethod(
133               m, Thread::Current(), CompilationKind::kOsr, /*prejit=*/ false);
134         }
135       });
136 }
137 
138 }  // namespace art
139