blob: 55631a9651bcd5cecd44f8a8c168064413e196cb [file] [log] [blame]
Andreas Gampe89df7bf2015-09-30 13:13:21 -07001/*
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
Andreas Gampe57943812017-12-06 21:39:13 -080019#include <android-base/logging.h>
20#include <android-base/macros.h>
21
Andreas Gampec6ea7d02017-02-01 16:46:28 -080022#include "art_method-inl.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070023#include "base/enums.h"
Alex Light0aa7a5a2018-10-10 15:58:14 +000024#include "common_throws.h"
David Sehr9e734c72018-01-04 17:56:19 -080025#include "dex/dex_file-inl.h"
Alex Lightdba61482016-12-21 08:20:29 -080026#include "instrumentation.h"
Nicolas Geoffray491617a2016-07-19 17:06:23 +010027#include "jit/jit.h"
28#include "jit/jit_code_cache.h"
Andreas Gampec6ea7d02017-02-01 16:46:28 -080029#include "jit/profiling_info.h"
Alex Light0aa7a5a2018-10-10 15:58:14 +000030#include "jni/jni_internal.h"
Andreas Gampe89df7bf2015-09-30 13:13:21 -070031#include "mirror/class-inl.h"
Steven Morelande431e272017-07-18 16:53:49 -070032#include "nativehelper/ScopedUtfChars.h"
Vladimir Markob0b68cf2017-11-14 18:11:50 +000033#include "oat_file.h"
Nicolas Geoffray491617a2016-07-19 17:06:23 +010034#include "oat_quick_method_header.h"
David Sehr82d046e2018-04-23 08:14:19 -070035#include "profile/profile_compilation_info.h"
Andreas Gampe89df7bf2015-09-30 13:13:21 -070036#include "runtime.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070037#include "scoped_thread_state_change-inl.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070038#include "thread-current-inl.h"
Andreas Gampe89df7bf2015-09-30 13:13:21 -070039
40namespace art {
41
Alex Lightdba61482016-12-21 08:20:29 -080042// public static native boolean hasJit();
43
Alex Light4e03c522017-01-14 01:48:01 +000044static jit::Jit* GetJitIfEnabled() {
Alex Lightdba61482016-12-21 08:20:29 -080045 Runtime* runtime = Runtime::Current();
Alex Light4e03c522017-01-14 01:48:01 +000046 bool can_jit =
47 runtime != nullptr
Alex Lightdba61482016-12-21 08:20:29 -080048 && runtime->GetJit() != nullptr
49 && runtime->GetInstrumentation()->GetCurrentInstrumentationLevel() !=
50 instrumentation::Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter;
Alex Light4e03c522017-01-14 01:48:01 +000051 return can_jit ? runtime->GetJit() : nullptr;
52}
53
54extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass) {
55 return GetJitIfEnabled() != nullptr;
Alex Lightdba61482016-12-21 08:20:29 -080056}
57
Andreas Gampe89df7bf2015-09-30 13:13:21 -070058// public static native boolean hasOatFile();
59
60extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass cls) {
61 ScopedObjectAccess soa(env);
62
Mathieu Chartier0795f232016-09-27 18:43:30 -070063 ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
Andreas Gampe89df7bf2015-09-30 13:13:21 -070064 const DexFile& dex_file = klass->GetDexFile();
Andreas Gampeb40d3612018-06-26 15:49:42 -070065 const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
Andreas Gampe89df7bf2015-09-30 13:13:21 -070066 return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
67}
68
69// public static native boolean runtimeIsSoftFail();
70
71extern "C" JNIEXPORT jboolean JNICALL Java_Main_runtimeIsSoftFail(JNIEnv* env ATTRIBUTE_UNUSED,
72 jclass cls ATTRIBUTE_UNUSED) {
73 return Runtime::Current()->IsVerificationSoftFail() ? JNI_TRUE : JNI_FALSE;
74}
75
Andreas Gampe89df7bf2015-09-30 13:13:21 -070076// public static native boolean hasImage();
77
78extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv* env ATTRIBUTE_UNUSED,
79 jclass cls ATTRIBUTE_UNUSED) {
Jeff Haodcdc85b2015-12-04 14:06:18 -080080 return Runtime::Current()->GetHeap()->HasBootImageSpace();
Andreas Gampe89df7bf2015-09-30 13:13:21 -070081}
82
83// public static native boolean isImageDex2OatEnabled();
84
85extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv* env ATTRIBUTE_UNUSED,
86 jclass cls ATTRIBUTE_UNUSED) {
87 return Runtime::Current()->IsImageDex2OatEnabled();
88}
89
Andreas Gampe0dfc9bc2015-09-30 17:13:59 -070090// public static native boolean compiledWithOptimizing();
91// Did we use the optimizing compiler to compile this?
92
93extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
94 ScopedObjectAccess soa(env);
95
Mathieu Chartier0795f232016-09-27 18:43:30 -070096 ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
Andreas Gampe0dfc9bc2015-09-30 17:13:59 -070097 const DexFile& dex_file = klass->GetDexFile();
Andreas Gampeb40d3612018-06-26 15:49:42 -070098 const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
Andreas Gampe0dfc9bc2015-09-30 17:13:59 -070099 if (oat_dex_file == nullptr) {
100 // Could be JIT, which also uses optimizing, but conservatively say no.
101 return JNI_FALSE;
102 }
103 const OatFile* oat_file = oat_dex_file->GetOatFile();
104 CHECK(oat_file != nullptr);
105
106 const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
107 CHECK(cmd_line != nullptr); // Huh? This should not happen.
108
109 // Check the backend.
110 constexpr const char* kCompilerBackend = "--compiler-backend=";
111 const char* backend = strstr(cmd_line, kCompilerBackend);
112 if (backend != nullptr) {
113 // If it's set, make sure it's optimizing.
114 backend += strlen(kCompilerBackend);
115 if (strncmp(backend, "Optimizing", strlen("Optimizing")) != 0) {
116 return JNI_FALSE;
117 }
118 }
119
120 // Check the filter.
121 constexpr const char* kCompilerFilter = "--compiler-filter=";
122 const char* filter = strstr(cmd_line, kCompilerFilter);
123 if (filter != nullptr) {
124 // If it's set, make sure it's not interpret-only|verify-none|verify-at-runtime.
125 // Note: The space filter might have an impact on the test, but ignore that for now.
126 filter += strlen(kCompilerFilter);
127 constexpr const char* kInterpretOnly = "interpret-only";
128 constexpr const char* kVerifyNone = "verify-none";
129 constexpr const char* kVerifyAtRuntime = "verify-at-runtime";
Alexey Grebenkince750492018-05-31 23:42:20 +0300130 constexpr const char* kQuicken = "quicken";
131 constexpr const char* kExtract = "extract";
Andreas Gampe0dfc9bc2015-09-30 17:13:59 -0700132 if (strncmp(filter, kInterpretOnly, strlen(kInterpretOnly)) == 0 ||
133 strncmp(filter, kVerifyNone, strlen(kVerifyNone)) == 0 ||
Alexey Grebenkince750492018-05-31 23:42:20 +0300134 strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0 ||
135 strncmp(filter, kExtract, strlen(kExtract)) == 0 ||
136 strncmp(filter, kQuicken, strlen(kQuicken)) == 0) {
Andreas Gampe0dfc9bc2015-09-30 17:13:59 -0700137 return JNI_FALSE;
138 }
139 }
140
141 return JNI_TRUE;
142}
143
Nicolas Geoffray51c17fa2016-11-25 15:56:12 +0000144extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotCompiled(JNIEnv* env,
145 jclass,
146 jclass cls,
147 jstring method_name) {
148 Thread* self = Thread::Current();
149 ScopedObjectAccess soa(self);
150 ScopedUtfChars chars(env, method_name);
151 CHECK(chars.c_str() != nullptr);
152 ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
153 chars.c_str(), kRuntimePointerSize);
Andreas Gampe035a2962018-02-02 13:23:57 -0800154 const void* oat_code = method->GetOatMethodQuickCode(kRuntimePointerSize);
155 if (oat_code == nullptr) {
156 return false;
157 }
158 const void* actual_code = method->GetEntryPointFromQuickCompiledCodePtrSize(kRuntimePointerSize);
159 bool interpreter =
160 Runtime::Current()->GetClassLinker()->ShouldUseInterpreterEntrypoint(method, actual_code);
161 return !interpreter;
Nicolas Geoffray23ddfe82017-06-07 14:09:43 +0100162}
163
Vladimir Marko2196c652017-11-30 16:16:07 +0000164extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
165 jclass,
166 jclass cls,
167 jstring method_name) {
Nicolas Geoffray23ddfe82017-06-07 14:09:43 +0100168 jit::Jit* jit = GetJitIfEnabled();
169 if (jit == nullptr) {
170 return false;
Nicolas Geoffray51c17fa2016-11-25 15:56:12 +0000171 }
Nicolas Geoffray23ddfe82017-06-07 14:09:43 +0100172 Thread* self = Thread::Current();
173 ScopedObjectAccess soa(self);
174 ScopedUtfChars chars(env, method_name);
175 CHECK(chars.c_str() != nullptr);
176 ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
177 chars.c_str(), kRuntimePointerSize);
Alex Light2d441b12018-06-08 15:33:21 -0700178 ScopedAssertNoThreadSuspension sants(__FUNCTION__);
179 return jit->GetCodeCache()->ContainsPc(
180 Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method));
Nicolas Geoffray51c17fa2016-11-25 15:56:12 +0000181}
182
Vladimir Marko2196c652017-11-30 16:16:07 +0000183extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env,
184 jclass,
185 jclass cls,
186 jstring method_name) {
187 jit::Jit* jit = GetJitIfEnabled();
188 if (jit == nullptr) {
189 return false;
190 }
191 Thread* self = Thread::Current();
192 ScopedObjectAccess soa(self);
193 ScopedUtfChars chars(env, method_name);
194 CHECK(chars.c_str() != nullptr);
195 ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
196 chars.c_str(), kRuntimePointerSize);
197 return jit->GetCodeCache()->ContainsMethod(method);
198}
199
Alex Light0aa7a5a2018-10-10 15:58:14 +0000200static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::mutator_lock_) {
201 {
202 ScopedObjectAccess soa(self);
203 if (method->IsNative()) {
204 std::string msg(method->PrettyMethod());
205 msg += ": is native";
206 ThrowIllegalArgumentException(msg.c_str());
207 return;
208 } else if (!Runtime::Current()->GetRuntimeCallbacks()->IsMethodSafeToJit(method)) {
209 std::string msg(method->PrettyMethod());
210 msg += ": is not safe to jit!";
211 ThrowIllegalStateException(msg.c_str());
212 return;
213 }
214 }
215 jit::Jit* jit = GetJitIfEnabled();
216 jit::JitCodeCache* code_cache = jit->GetCodeCache();
217 // Update the code cache to make sure the JIT code does not get deleted.
218 // Note: this will apply to all JIT compilations.
219 code_cache->SetGarbageCollectCode(false);
220 while (true) {
221 if (code_cache->WillExecuteJitCode(method)) {
222 break;
223 } else {
224 // Sleep to yield to the compiler thread.
225 usleep(1000);
226 ScopedObjectAccess soa(self);
227 // Make sure there is a profiling info, required by the compiler.
228 ProfilingInfo::Create(self, method, /* retry_allocation */ true);
229 // Will either ensure it's compiled or do the compilation itself.
Nicolas Geoffray075456e2018-12-14 08:54:21 +0000230 jit->CompileMethod(method, self, /*baseline=*/ false, /*osr=*/ false);
Alex Light0aa7a5a2018-10-10 15:58:14 +0000231 }
232 }
233}
234
235extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) {
236 jit::Jit* jit = GetJitIfEnabled();
237 if (jit == nullptr) {
238 return;
239 }
240
241 Thread* self = Thread::Current();
242 ArtMethod* method;
243 {
244 ScopedObjectAccess soa(self);
245 method = ArtMethod::FromReflectedMethod(soa, meth);
246 }
247 ForceJitCompiled(self, method);
248}
249
Nicolas Geoffray491617a2016-07-19 17:06:23 +0100250extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
251 jclass,
252 jclass cls,
253 jstring method_name) {
Alex Light4e03c522017-01-14 01:48:01 +0000254 jit::Jit* jit = GetJitIfEnabled();
Nicolas Geoffray491617a2016-07-19 17:06:23 +0100255 if (jit == nullptr) {
256 return;
257 }
258
Nicolas Geoffray44cea192016-08-03 20:48:13 +0100259 Thread* self = Thread::Current();
Nicolas Geoffrayd55f4ab2016-08-02 18:49:25 +0100260 ArtMethod* method = nullptr;
261 {
Nicolas Geoffray44cea192016-08-03 20:48:13 +0100262 ScopedObjectAccess soa(self);
Nicolas Geoffray491617a2016-07-19 17:06:23 +0100263
Nicolas Geoffrayd55f4ab2016-08-02 18:49:25 +0100264 ScopedUtfChars chars(env, method_name);
265 CHECK(chars.c_str() != nullptr);
Mathieu Chartier0795f232016-09-27 18:43:30 -0700266 method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
Nicolas Geoffrayd55f4ab2016-08-02 18:49:25 +0100267 chars.c_str(), kRuntimePointerSize);
Alex Light4e03c522017-01-14 01:48:01 +0000268 if (method == nullptr) {
269 method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
270 chars.c_str(), kRuntimePointerSize);
271 }
272 DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
Nicolas Geoffrayd55f4ab2016-08-02 18:49:25 +0100273 }
Alex Light0aa7a5a2018-10-10 15:58:14 +0000274 ForceJitCompiled(self, method);
Nicolas Geoffray491617a2016-07-19 17:06:23 +0100275}
276
Mingyao Yang063fc772016-08-02 11:02:54 -0700277extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env,
278 jclass,
279 jclass cls,
280 jstring method_name) {
281 ArtMethod* method = nullptr;
282 ScopedObjectAccess soa(Thread::Current());
283 ScopedUtfChars chars(env, method_name);
284 CHECK(chars.c_str() != nullptr);
285 method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
286 chars.c_str(), kRuntimePointerSize);
287 return method->HasSingleImplementation();
288}
289
Calin Juravle857f0582016-12-20 14:36:59 +0000290extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env,
291 jclass,
292 jclass cls,
293 jstring method_name) {
Orion Hodson52f5a1f2018-05-02 11:05:44 +0100294 ScopedObjectAccess soa(Thread::Current());
295 ScopedUtfChars chars(env, method_name);
296 CHECK(chars.c_str() != nullptr);
297 ArtMethod* method =
298 soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(chars.c_str(),
299 kRuntimePointerSize);
300 if (method != nullptr) {
301 return method->GetCounter();
Calin Juravle857f0582016-12-20 14:36:59 +0000302 }
303
Orion Hodson52f5a1f2018-05-02 11:05:44 +0100304 method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(chars.c_str(),
305 kRuntimePointerSize);
306 if (method != nullptr) {
307 return method->GetCounter();
308 }
309
310 return std::numeric_limits<int32_t>::min();
Calin Juravle857f0582016-12-20 14:36:59 +0000311}
312
Nicolas Geoffrayb9bec2e2017-05-24 15:59:18 +0100313extern "C" JNIEXPORT int JNICALL Java_Main_numberOfDeoptimizations(JNIEnv*, jclass) {
314 return Runtime::Current()->GetNumberOfDeoptimizations();
315}
316
Nicolas Geoffray48b40cc2017-08-07 16:52:40 +0100317extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
318 jit::Jit* jit = GetJitIfEnabled();
319 if (jit == nullptr) {
320 return;
321 }
322 jit::JitCodeCache* code_cache = jit->GetCodeCache();
323 std::vector<ProfileMethodInfo> unused_vector;
324 std::set<std::string> unused_locations;
325 unused_locations.insert("fake_location");
326 ScopedObjectAccess soa(Thread::Current());
327 code_cache->GetProfiledMethods(unused_locations, unused_vector);
328}
329
Mathieu Chartier45caa1d2018-01-31 07:45:20 -0800330extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
331 jit::Jit* jit = Runtime::Current()->GetJit();
332 if (jit != nullptr) {
333 jit->WaitForCompilationToFinish(Thread::Current());
334 }
335}
336
337extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
338 jit::Jit* jit = Runtime::Current()->GetJit();
339 if (jit != nullptr) {
340 jit->Stop();
341 }
342}
343
344extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
345 jit::Jit* jit = Runtime::Current()->GetJit();
346 if (jit != nullptr) {
347 jit->Start();
348 }
349}
350
Vladimir Markoeece4942018-10-03 13:46:31 +0100351extern "C" JNIEXPORT jint JNICALL Java_Main_getJitThreshold(JNIEnv*, jclass) {
352 jit::Jit* jit = Runtime::Current()->GetJit();
353 return (jit != nullptr) ? jit->HotMethodThreshold() : 0;
354}
355
Andreas Gampe89df7bf2015-09-30 13:13:21 -0700356} // namespace art