xref: /aosp_15_r20/art/test/common/runtime_state.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 <android-base/logging.h>
18 #include <android-base/macros.h>
19 #include <sys/resource.h>
20 
21 #include "art_field.h"
22 #include "art_method-inl.h"
23 #include "base/pointer_size.h"
24 #include "common_throws.h"
25 #include "dex/dex_file-inl.h"
26 #include "dex/dex_file_types.h"
27 #include "gc/heap.h"
28 #include "instrumentation.h"
29 #include "jit/jit.h"
30 #include "jit/jit_code_cache.h"
31 #include "jit/profile_saver.h"
32 #include "jit/profiling_info.h"
33 #include "jni.h"
34 #include "jni/jni_internal.h"
35 #include "mirror/class-inl.h"
36 #include "mirror/class.h"
37 #include "mirror/executable.h"
38 #include "nativehelper/ScopedUtfChars.h"
39 #include "oat/oat.h"
40 #include "oat/oat_file.h"
41 #include "oat/oat_quick_method_header.h"
42 #include "profile/profile_compilation_info.h"
43 #include "runtime.h"
44 #include "scoped_thread_state_change-inl.h"
45 #include "scoped_thread_state_change.h"
46 #include "thread-current-inl.h"
47 
48 namespace art {
49 
50 // public static native boolean hasJit();
51 
GetJitIfEnabled()52 static jit::Jit* GetJitIfEnabled() {
53   Runtime* runtime = Runtime::Current();
54   bool can_jit =
55       runtime != nullptr
56       && runtime->GetJit() != nullptr
57       && runtime->UseJitCompilation()
58       && runtime->GetInstrumentation()->GetCurrentInstrumentationLevel() !=
59             instrumentation::Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter;
60   return can_jit ? runtime->GetJit() : nullptr;
61 }
62 
Java_Main_hasJit(JNIEnv *,jclass)63 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass) {
64   return GetJitIfEnabled() != nullptr;
65 }
66 
67 // public static native boolean hasOatFile();
68 
Java_Main_hasOatFile(JNIEnv * env,jclass cls)69 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass cls) {
70   ScopedObjectAccess soa(env);
71 
72   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
73   const DexFile& dex_file = klass->GetDexFile();
74   const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
75   return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
76 }
77 
Java_Main_getCompilerFilter(JNIEnv * env,jclass caller,jclass cls)78 extern "C" JNIEXPORT jobject JNICALL Java_Main_getCompilerFilter(JNIEnv* env,
79                                                                  [[maybe_unused]] jclass caller,
80                                                                  jclass cls) {
81   ScopedObjectAccess soa(env);
82 
83   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
84   const DexFile& dex_file = klass->GetDexFile();
85   const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
86   if (oat_dex_file == nullptr) {
87     return nullptr;
88   }
89 
90   std::string filter =
91       CompilerFilter::NameOfFilter(oat_dex_file->GetOatFile()->GetCompilerFilter());
92   return soa.AddLocalReference<jobject>(
93       mirror::String::AllocFromModifiedUtf8(soa.Self(), filter.c_str()));
94 }
95 
96 // public static native boolean runtimeIsSoftFail();
97 
Java_Main_runtimeIsSoftFail(JNIEnv * env,jclass cls)98 extern "C" JNIEXPORT jboolean JNICALL Java_Main_runtimeIsSoftFail([[maybe_unused]] JNIEnv* env,
99                                                                   [[maybe_unused]] jclass cls) {
100   return Runtime::Current()->IsVerificationSoftFail() ? JNI_TRUE : JNI_FALSE;
101 }
102 
103 // public static native boolean hasImage();
104 
Java_Main_hasImage(JNIEnv * env,jclass cls)105 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage([[maybe_unused]] JNIEnv* env,
106                                                          [[maybe_unused]] jclass cls) {
107   return Runtime::Current()->GetHeap()->HasBootImageSpace();
108 }
109 
110 // public static native boolean isImageDex2OatEnabled();
111 
Java_Main_isImageDex2OatEnabled(JNIEnv * env,jclass cls)112 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled([[maybe_unused]] JNIEnv* env,
113                                                                       [[maybe_unused]] jclass cls) {
114   return Runtime::Current()->IsImageDex2OatEnabled();
115 }
116 
117 // public static native boolean compiledWithOptimizing();
118 // Did we use the optimizing compiler to compile this?
119 
Java_Main_compiledWithOptimizing(JNIEnv * env,jclass cls)120 extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
121   ScopedObjectAccess soa(env);
122 
123   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
124   const DexFile& dex_file = klass->GetDexFile();
125   const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
126   if (oat_dex_file == nullptr) {
127     // Could be JIT, which also uses optimizing, but conservatively say no.
128     return JNI_FALSE;
129   }
130   const OatFile* oat_file = oat_dex_file->GetOatFile();
131   CHECK(oat_file != nullptr);
132 
133   const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
134   if (cmd_line == nullptr) {
135     // Vdex-only execution, conservatively say no.
136     return JNI_FALSE;
137   }
138 
139   // Check the backend.
140   constexpr const char* kCompilerBackend = "--compiler-backend=";
141   const char* backend = strstr(cmd_line, kCompilerBackend);
142   if (backend != nullptr) {
143     // If it's set, make sure it's optimizing.
144     backend += strlen(kCompilerBackend);
145     if (strncmp(backend, "Optimizing", strlen("Optimizing")) != 0) {
146       return JNI_FALSE;
147     }
148   }
149 
150   // Check the filter.
151   constexpr const char* kCompilerFilter = "--compiler-filter=";
152   const char* filter = strstr(cmd_line, kCompilerFilter);
153   if (filter != nullptr) {
154     filter += strlen(kCompilerFilter);
155     const char* end = strchr(filter, ' ');
156     std::string string_filter(filter, (end == nullptr) ? strlen(filter) : end - filter);
157     CompilerFilter::Filter compiler_filter;
158     bool success = CompilerFilter::ParseCompilerFilter(string_filter.c_str(), &compiler_filter);
159     CHECK(success);
160     return CompilerFilter::IsAotCompilationEnabled(compiler_filter) ? JNI_TRUE : JNI_FALSE;
161   }
162 
163   // No filter passed, assume default has AOT.
164   return JNI_TRUE;
165 }
166 
Java_Main_isAotCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)167 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotCompiled(JNIEnv* env,
168                                                               jclass,
169                                                               jclass cls,
170                                                               jstring method_name) {
171   Thread* self = Thread::Current();
172   ScopedObjectAccess soa(self);
173   ScopedUtfChars chars(env, method_name);
174   CHECK(chars.c_str() != nullptr);
175   ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
176         chars.c_str(), kRuntimePointerSize);
177   const void* oat_code = method->GetOatMethodQuickCode(kRuntimePointerSize);
178   if (oat_code == nullptr) {
179     return false;
180   }
181   const void* actual_code = Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method);
182   return actual_code == oat_code;
183 }
184 
GetMethod(ScopedObjectAccess & soa,jclass cls,const ScopedUtfChars & chars)185 static ArtMethod* GetMethod(ScopedObjectAccess& soa, jclass cls, const ScopedUtfChars& chars)
186     REQUIRES_SHARED(Locks::mutator_lock_) {
187   CHECK(chars.c_str() != nullptr);
188   ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
189         chars.c_str(), kRuntimePointerSize);
190   if (method == nullptr) {
191     method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
192         chars.c_str(), kRuntimePointerSize);
193   }
194   DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
195   return method;
196 }
197 
Java_Main_hasJitCompiledEntrypoint(JNIEnv * env,jclass,jclass cls,jstring method_name)198 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
199                                                                          jclass,
200                                                                          jclass cls,
201                                                                          jstring method_name) {
202   jit::Jit* jit = GetJitIfEnabled();
203   if (jit == nullptr) {
204     return false;
205   }
206   Thread* self = Thread::Current();
207   ScopedObjectAccess soa(self);
208   ScopedUtfChars chars(env, method_name);
209   ArtMethod* method = GetMethod(soa, cls, chars);
210   ScopedAssertNoThreadSuspension sants(__FUNCTION__);
211   return jit->GetCodeCache()->ContainsPc(
212       Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method));
213 }
214 
Java_Main_hasJitCompiledCode(JNIEnv * env,jclass,jclass cls,jstring method_name)215 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env,
216                                                                    jclass,
217                                                                    jclass cls,
218                                                                    jstring method_name) {
219   jit::Jit* jit = GetJitIfEnabled();
220   if (jit == nullptr) {
221     return false;
222   }
223   Thread* self = Thread::Current();
224   ScopedObjectAccess soa(self);
225   ScopedUtfChars chars(env, method_name);
226   ArtMethod* method = GetMethod(soa, cls, chars);
227   return jit->GetCodeCache()->ContainsMethod(method);
228 }
229 
ForceJitCompiled(Thread * self,ArtMethod * method,CompilationKind kind)230 static void ForceJitCompiled(Thread* self,
231                              ArtMethod* method,
232                              CompilationKind kind) REQUIRES(!Locks::mutator_lock_) {
233   // TODO(mythria): Update this check once we support method entry / exit hooks directly from
234   // JIT code instead of installing EntryExit stubs.
235   if (Runtime::Current()->GetInstrumentation()->EntryExitStubsInstalled() &&
236       (method->IsNative() || !Runtime::Current()->IsJavaDebuggable())) {
237     return;
238   }
239 
240   {
241     ScopedObjectAccess soa(self);
242     if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
243       std::string msg(method->PrettyMethod());
244       msg += ": is not safe to jit!";
245       ThrowIllegalStateException(msg.c_str());
246       return;
247     }
248     // We force visible initialization of the declaring class to make sure the method
249     // doesn't keep the resolution stub as entrypoint.
250     StackHandleScope<1> hs(self);
251     Handle<mirror::Class> h_klass(hs.NewHandle(method->GetDeclaringClass()));
252     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
253     if (!class_linker->EnsureInitialized(self, h_klass, true, true)) {
254       self->AssertPendingException();
255       return;
256     }
257     if (UNLIKELY(!h_klass->IsInitialized())) {
258       // Must be initializing in this thread.
259       CHECK_EQ(h_klass->GetStatus(), ClassStatus::kInitializing);
260       CHECK_EQ(h_klass->GetClinitThreadId(), self->GetTid());
261       std::string msg(method->PrettyMethod());
262       msg += ": is not safe to jit because the class is being initialized in this thread!";
263       ThrowIllegalStateException(msg.c_str());
264       return;
265     }
266     if (!h_klass->IsVisiblyInitialized()) {
267       ScopedThreadSuspension sts(self, ThreadState::kNative);
268       class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
269     }
270   }
271   jit::Jit* jit = GetJitIfEnabled();
272   jit::JitCodeCache* code_cache = jit->GetCodeCache();
273   // Update the code cache to make sure the JIT code does not get deleted.
274   // Note: this will apply to all JIT compilations.
275   code_cache->SetGarbageCollectCode(false);
276   if (jit->JitAtFirstUse()) {
277     ScopedObjectAccess soa(self);
278     jit->CompileMethod(method, self, kind, /*prejit=*/ false);
279     return;
280   }
281   if (kind == CompilationKind::kBaseline || jit->GetJitCompiler()->IsBaselineCompiler()) {
282     ScopedObjectAccess soa(self);
283     if (jit->TryPatternMatch(method, CompilationKind::kBaseline)) {
284       return;
285     }
286     jit->MaybeEnqueueCompilation(method, self);
287   } else {
288     jit->EnqueueOptimizedCompilation(method, self);
289   }
290   do {
291     // Sleep to yield to the compiler thread.
292     usleep(1000);
293     const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
294     if (code_cache->ContainsPc(entry_point)) {
295       // If we're running baseline or not requesting optimized, we're good to go.
296       if (jit->GetJitCompiler()->IsBaselineCompiler() || kind != CompilationKind::kOptimized) {
297         break;
298       }
299       // If we're requesting optimized, check that we did get the method
300       // compiled optimized.
301       OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromEntryPoint(entry_point);
302       if (!CodeInfo::IsBaseline(method_header->GetOptimizedCodeInfoPtr())) {
303         break;
304       }
305     }
306   } while (true);
307 }
308 
Java_Main_ensureMethodJitCompiled(JNIEnv *,jclass,jobject meth)309 extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) {
310   jit::Jit* jit = GetJitIfEnabled();
311   if (jit == nullptr) {
312     return;
313   }
314 
315   Thread* self = Thread::Current();
316   ArtMethod* method;
317   {
318     ScopedObjectAccess soa(self);
319     method = ArtMethod::FromReflectedMethod(soa, meth);
320   }
321   ForceJitCompiled(self, method, CompilationKind::kOptimized);
322 }
323 
Java_Main_ensureJitCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)324 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
325                                                              jclass,
326                                                              jclass cls,
327                                                              jstring method_name) {
328   jit::Jit* jit = GetJitIfEnabled();
329   if (jit == nullptr) {
330     return;
331   }
332 
333   Thread* self = Thread::Current();
334   ArtMethod* method = nullptr;
335   {
336     ScopedObjectAccess soa(self);
337 
338     ScopedUtfChars chars(env, method_name);
339     method = GetMethod(soa, cls, chars);
340   }
341   ForceJitCompiled(self, method, CompilationKind::kOptimized);
342 }
343 
Java_Main_ensureJitBaselineCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)344 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitBaselineCompiled(JNIEnv* env,
345                                                                       jclass,
346                                                                       jclass cls,
347                                                                       jstring method_name) {
348   jit::Jit* jit = GetJitIfEnabled();
349   if (jit == nullptr) {
350     return;
351   }
352 
353   Thread* self = Thread::Current();
354   ArtMethod* method = nullptr;
355   {
356     ScopedObjectAccess soa(self);
357 
358     ScopedUtfChars chars(env, method_name);
359     method = GetMethod(soa, cls, chars);
360   }
361   ForceJitCompiled(self, method, CompilationKind::kBaseline);
362 }
363 
Java_Main_hasSingleImplementation(JNIEnv * env,jclass,jclass cls,jstring method_name)364 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env,
365                                                                         jclass,
366                                                                         jclass cls,
367                                                                         jstring method_name) {
368   ArtMethod* method = nullptr;
369   ScopedObjectAccess soa(Thread::Current());
370   ScopedUtfChars chars(env, method_name);
371   CHECK(chars.c_str() != nullptr);
372   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
373       chars.c_str(), kRuntimePointerSize);
374   return method->HasSingleImplementation();
375 }
376 
Java_Main_getHotnessCounter(JNIEnv * env,jclass,jclass cls,jstring method_name)377 extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env,
378                                                              jclass,
379                                                              jclass cls,
380                                                              jstring method_name) {
381   ScopedObjectAccess soa(Thread::Current());
382   ScopedUtfChars chars(env, method_name);
383   CHECK(chars.c_str() != nullptr);
384   ArtMethod* method =
385       soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(chars.c_str(),
386                                                                      kRuntimePointerSize);
387   if (method != nullptr) {
388     return method->GetCounter();
389   }
390 
391   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(chars.c_str(),
392                                                                            kRuntimePointerSize);
393   if (method != nullptr) {
394     return method->GetCounter();
395   }
396 
397   return std::numeric_limits<int32_t>::min();
398 }
399 
Java_Main_numberOfDeoptimizations(JNIEnv *,jclass)400 extern "C" JNIEXPORT int JNICALL Java_Main_numberOfDeoptimizations(JNIEnv*, jclass) {
401   return Runtime::Current()->GetNumberOfDeoptimizations();
402 }
403 
Java_Main_fetchProfiles(JNIEnv *,jclass)404 extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
405   jit::Jit* jit = GetJitIfEnabled();
406   if (jit == nullptr) {
407     return;
408   }
409   jit::JitCodeCache* code_cache = jit->GetCodeCache();
410   std::vector<ProfileMethodInfo> unused_vector;
411   std::set<std::string> unused_locations;
412   unused_locations.insert("fake_location");
413   ScopedObjectAccess soa(Thread::Current());
414   code_cache->GetProfiledMethods(unused_locations, unused_vector, /*inline_cache_threshold=*/0);
415 }
416 
Java_Main_waitForCompilation(JNIEnv *,jclass)417 extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
418   jit::Jit* jit = Runtime::Current()->GetJit();
419   if (jit != nullptr) {
420     jit->WaitForCompilationToFinish(Thread::Current());
421   }
422 }
423 
Java_Main_stopJit(JNIEnv *,jclass)424 extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
425   jit::Jit* jit = Runtime::Current()->GetJit();
426   if (jit != nullptr) {
427     jit->Stop();
428   }
429 }
430 
Java_Main_startJit(JNIEnv *,jclass)431 extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
432   jit::Jit* jit = Runtime::Current()->GetJit();
433   if (jit != nullptr) {
434     jit->Start();
435   }
436 }
437 
Java_Main_getJitThreshold(JNIEnv *,jclass)438 extern "C" JNIEXPORT jint JNICALL Java_Main_getJitThreshold(JNIEnv*, jclass) {
439   jit::Jit* jit = Runtime::Current()->GetJit();
440   return (jit != nullptr) ? jit->HotMethodThreshold() : 0;
441 }
442 
Java_Main_deoptimizeBootImage(JNIEnv *,jclass)443 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeBootImage(JNIEnv*, jclass) {
444   ScopedSuspendAll ssa(__FUNCTION__);
445   Runtime::Current()->DeoptimizeBootImage();
446 }
447 
Java_Main_deoptimizeNativeMethod(JNIEnv * env,jclass,jclass cls,jstring method_name)448 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeNativeMethod(JNIEnv* env,
449                                                                    jclass,
450                                                                    jclass cls,
451                                                                    jstring method_name) {
452   Thread* self = Thread::Current();
453   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
454   // Make initialized classes visibly initialized to avoid entrypoint being set to boot JNI stub
455   // after deoptimize.
456   class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
457   ScopedObjectAccess soa(self);
458   ScopedUtfChars chars(env, method_name);
459   ArtMethod* method = GetMethod(soa, cls, chars);
460   CHECK(method->IsNative());
461   Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
462 }
463 
Java_Main_isDebuggable(JNIEnv *,jclass)464 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDebuggable(JNIEnv*, jclass) {
465   return Runtime::Current()->IsJavaDebuggable() ? JNI_TRUE : JNI_FALSE;
466 }
467 
Java_Main_setTargetSdkVersion(JNIEnv *,jclass,jint version)468 extern "C" JNIEXPORT void JNICALL Java_Main_setTargetSdkVersion(JNIEnv*, jclass, jint version) {
469   Runtime::Current()->SetTargetSdkVersion(static_cast<uint32_t>(version));
470 }
471 
Java_Main_genericFieldOffset(JNIEnv * env,jclass,jobject fld)472 extern "C" JNIEXPORT jlong JNICALL Java_Main_genericFieldOffset(JNIEnv* env, jclass, jobject fld) {
473   jfieldID fid = env->FromReflectedField(fld);
474   ScopedObjectAccess soa(env);
475   ArtField* af = jni::DecodeArtField(fid);
476   return af->GetOffset().Int32Value();
477 }
478 
Java_Main_isObsoleteObject(JNIEnv * env,jclass,jclass c)479 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isObsoleteObject(JNIEnv* env, jclass, jclass c) {
480   ScopedObjectAccess soa(env);
481   return soa.Decode<mirror::Class>(c)->IsObsoleteObject();
482 }
483 
Java_Main_forceInterpreterOnThread(JNIEnv * env,jclass cls)484 extern "C" JNIEXPORT void JNICALL Java_Main_forceInterpreterOnThread(JNIEnv* env,
485                                                                      [[maybe_unused]] jclass cls) {
486   ScopedObjectAccess soa(env);
487   MutexLock thread_list_mu(soa.Self(), *Locks::thread_list_lock_);
488   soa.Self()->IncrementForceInterpreterCount();
489 }
490 
Java_Main_setAsyncExceptionsThrown(JNIEnv * env,jclass cls)491 extern "C" JNIEXPORT void JNICALL Java_Main_setAsyncExceptionsThrown([[maybe_unused]] JNIEnv* env,
492                                                                      [[maybe_unused]] jclass cls) {
493   Runtime::Current()->SetAsyncExceptionsThrown();
494 }
495 
Java_Main_setRlimitNoFile(JNIEnv *,jclass,jint value)496 extern "C" JNIEXPORT void JNICALL Java_Main_setRlimitNoFile(JNIEnv*, jclass, jint value) {
497   rlimit limit { static_cast<rlim_t>(value), static_cast<rlim_t>(value) };
498   setrlimit(RLIMIT_NOFILE, &limit);
499 }
500 
Java_Main_isInImageSpace(JNIEnv * env,jclass caller,jclass cls)501 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInImageSpace(JNIEnv* env,
502                                                                [[maybe_unused]] jclass caller,
503                                                                jclass cls) {
504   ScopedObjectAccess soa(env);
505 
506   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
507   gc::space::Space* space =
508       Runtime::Current()->GetHeap()->FindSpaceFromObject(klass, /*fail_ok=*/true);
509   if (space == nullptr) {
510     return JNI_FALSE;
511   }
512   return space->IsImageSpace() ? JNI_TRUE : JNI_FALSE;
513 }
514 
515 // Ensures the profile saver does its usual processing.
Java_Main_ensureProfileProcessing(JNIEnv *,jclass)516 extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfileProcessing(JNIEnv*, jclass) {
517   ProfileSaver::ForceProcessProfiles();
518 }
519 
Java_Main_isForBootImage(JNIEnv * env,jclass,jstring filename)520 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isForBootImage(JNIEnv* env,
521                                                                jclass,
522                                                                jstring filename) {
523   ScopedUtfChars filename_chars(env, filename);
524   CHECK(filename_chars.c_str() != nullptr);
525 
526   ProfileCompilationInfo info(/*for_boot_image=*/true);
527   bool result = info.Load(std::string(filename_chars.c_str()), /*clear_if_invalid=*/false);
528   return result ? JNI_TRUE : JNI_FALSE;
529 }
530 
GetMethodHotnessFromProfile(JNIEnv * env,jclass c,jstring filename,jobject method)531 static ProfileCompilationInfo::MethodHotness GetMethodHotnessFromProfile(JNIEnv* env,
532                                                                          jclass c,
533                                                                          jstring filename,
534                                                                          jobject method) {
535   bool for_boot_image = Java_Main_isForBootImage(env, c, filename) == JNI_TRUE;
536   ScopedUtfChars filename_chars(env, filename);
537   CHECK(filename_chars.c_str() != nullptr);
538   ScopedObjectAccess soa(env);
539   ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method);
540   ArtMethod* art_method = exec->GetArtMethod();
541   MethodReference ref(art_method->GetDexFile(), art_method->GetDexMethodIndex());
542 
543   ProfileCompilationInfo info(Runtime::Current()->GetArenaPool(), for_boot_image);
544   if (!info.Load(filename_chars.c_str(), /*clear_if_invalid=*/false)) {
545     LOG(ERROR) << "Failed to load profile from " << filename;
546     return ProfileCompilationInfo::MethodHotness();
547   }
548   return info.GetMethodHotness(ref);
549 }
550 
551 // Checks if the method is present in the profile.
Java_Main_presentInProfile(JNIEnv * env,jclass c,jstring filename,jobject method)552 extern "C" JNIEXPORT jboolean JNICALL Java_Main_presentInProfile(JNIEnv* env,
553                                                                  jclass c,
554                                                                  jstring filename,
555                                                                  jobject method) {
556   // TODO: Why do we check `hotness.IsHot()` instead of `hotness.IsInProfile()`
557   // in a method named `presentInProfile()`?
558   return GetMethodHotnessFromProfile(env, c, filename, method).IsHot() ? JNI_TRUE : JNI_FALSE;
559 }
560 
561 // Checks if the method has an inline cache in the profile that contains at least the given target
562 // types.
Java_Main_hasInlineCacheInProfile(JNIEnv * env,jclass c,jstring filename,jobject method,jobjectArray target_types)563 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasInlineCacheInProfile(
564     JNIEnv* env, jclass c, jstring filename, jobject method, jobjectArray target_types) {
565   ProfileCompilationInfo::MethodHotness hotness =
566       GetMethodHotnessFromProfile(env, c, filename, method);
567   if (hotness.GetInlineCacheMap() == nullptr) {
568     return JNI_FALSE;
569   }
570   ScopedObjectAccess soa(env);
571   ObjPtr<mirror::ObjectArray<mirror::Class>> types =
572       soa.Decode<mirror::ObjectArray<mirror::Class>>(target_types);
573   for (const auto& [dex_pc, dex_pc_data] : *hotness.GetInlineCacheMap()) {
574     bool match = true;
575     for (ObjPtr<mirror::Class> type : *types.Ptr()) {
576       dex::TypeIndex expected_index = type->GetDexTypeIndex();
577       if (!expected_index.IsValid()) {
578         return JNI_FALSE;
579       }
580       if (dex_pc_data.classes.find(expected_index) == dex_pc_data.classes.end()) {
581         match = false;
582         break;
583       }
584     }
585     if (match) {
586       return JNI_TRUE;
587     }
588   }
589   return JNI_FALSE;
590 }
591 
Java_Main_getCurrentGcNum(JNIEnv * env,jclass)592 extern "C" JNIEXPORT jint JNICALL Java_Main_getCurrentGcNum(JNIEnv* env, jclass) {
593   // Prevent any new GC before getting the current GC num.
594   ScopedObjectAccess soa(env);
595   gc::Heap* heap = Runtime::Current()->GetHeap();
596   heap->WaitForGcToComplete(gc::kGcCauseJitCodeCache, Thread::Current());
597   return heap->GetCurrentGcNum();
598 }
599 
Java_Main_removeJitCompiledMethod(JNIEnv * env,jclass,jobject java_method,jboolean release_memory)600 extern "C" JNIEXPORT jboolean Java_Main_removeJitCompiledMethod(JNIEnv* env,
601                                                                 jclass,
602                                                                 jobject java_method,
603                                                                 jboolean release_memory) {
604   if (!Runtime::Current()->UseJitCompilation()) {
605     return JNI_FALSE;
606   }
607 
608   jit::Jit* jit = Runtime::Current()->GetJit();
609   jit->WaitForCompilationToFinish(Thread::Current());
610 
611   ScopedObjectAccess soa(env);
612   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, java_method);
613 
614   jit::JitCodeCache* code_cache = jit->GetCodeCache();
615 
616   // Drop the shared mutator lock.
617   ScopedThreadSuspension self_suspension(Thread::Current(), art::ThreadState::kNative);
618   // Get exclusive mutator lock with suspend all.
619   ScopedSuspendAll suspend("Removing JIT compiled method", /*long_suspend=*/true);
620   bool removed = code_cache->RemoveMethod(method, static_cast<bool>(release_memory));
621   return removed ? JNI_TRUE : JNI_FALSE;
622 }
623 
624 }  // namespace art
625