• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   } else if (kind == CompilationKind::kBaseline || jit->GetJitCompiler()->IsBaselineCompiler()) {
280     ScopedObjectAccess soa(self);
281     if (jit->TryPatternMatch(method, CompilationKind::kBaseline)) {
282       return;
283     }
284     jit->MaybeEnqueueCompilation(method, self);
285   } else {
286     jit->EnqueueOptimizedCompilation(method, self);
287   }
288   do {
289     // Sleep to yield to the compiler thread.
290     usleep(1000);
291     const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
292     if (code_cache->ContainsPc(entry_point)) {
293       // If we're running baseline or not requesting optimized, we're good to go.
294       if (jit->GetJitCompiler()->IsBaselineCompiler() || kind != CompilationKind::kOptimized) {
295         break;
296       }
297       // If we're requesting optimized, check that we did get the method
298       // compiled optimized.
299       OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromEntryPoint(entry_point);
300       if (!CodeInfo::IsBaseline(method_header->GetOptimizedCodeInfoPtr())) {
301         break;
302       }
303     }
304   } while (true);
305 }
306 
Java_Main_ensureMethodJitCompiled(JNIEnv *,jclass,jobject meth)307 extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) {
308   jit::Jit* jit = GetJitIfEnabled();
309   if (jit == nullptr) {
310     return;
311   }
312 
313   Thread* self = Thread::Current();
314   ArtMethod* method;
315   {
316     ScopedObjectAccess soa(self);
317     method = ArtMethod::FromReflectedMethod(soa, meth);
318   }
319   ForceJitCompiled(self, method, CompilationKind::kOptimized);
320 }
321 
Java_Main_ensureJitCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)322 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
323                                                              jclass,
324                                                              jclass cls,
325                                                              jstring method_name) {
326   jit::Jit* jit = GetJitIfEnabled();
327   if (jit == nullptr) {
328     return;
329   }
330 
331   Thread* self = Thread::Current();
332   ArtMethod* method = nullptr;
333   {
334     ScopedObjectAccess soa(self);
335 
336     ScopedUtfChars chars(env, method_name);
337     method = GetMethod(soa, cls, chars);
338   }
339   ForceJitCompiled(self, method, CompilationKind::kOptimized);
340 }
341 
Java_Main_ensureJitBaselineCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)342 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitBaselineCompiled(JNIEnv* env,
343                                                                       jclass,
344                                                                       jclass cls,
345                                                                       jstring method_name) {
346   jit::Jit* jit = GetJitIfEnabled();
347   if (jit == nullptr) {
348     return;
349   }
350 
351   Thread* self = Thread::Current();
352   ArtMethod* method = nullptr;
353   {
354     ScopedObjectAccess soa(self);
355 
356     ScopedUtfChars chars(env, method_name);
357     method = GetMethod(soa, cls, chars);
358   }
359   ForceJitCompiled(self, method, CompilationKind::kBaseline);
360 }
361 
Java_Main_hasSingleImplementation(JNIEnv * env,jclass,jclass cls,jstring method_name)362 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env,
363                                                                         jclass,
364                                                                         jclass cls,
365                                                                         jstring method_name) {
366   ArtMethod* method = nullptr;
367   ScopedObjectAccess soa(Thread::Current());
368   ScopedUtfChars chars(env, method_name);
369   CHECK(chars.c_str() != nullptr);
370   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
371       chars.c_str(), kRuntimePointerSize);
372   return method->HasSingleImplementation();
373 }
374 
Java_Main_getHotnessCounter(JNIEnv * env,jclass,jclass cls,jstring method_name)375 extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env,
376                                                              jclass,
377                                                              jclass cls,
378                                                              jstring method_name) {
379   ScopedObjectAccess soa(Thread::Current());
380   ScopedUtfChars chars(env, method_name);
381   CHECK(chars.c_str() != nullptr);
382   ArtMethod* method =
383       soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(chars.c_str(),
384                                                                      kRuntimePointerSize);
385   if (method != nullptr) {
386     return method->GetCounter();
387   }
388 
389   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(chars.c_str(),
390                                                                            kRuntimePointerSize);
391   if (method != nullptr) {
392     return method->GetCounter();
393   }
394 
395   return std::numeric_limits<int32_t>::min();
396 }
397 
Java_Main_numberOfDeoptimizations(JNIEnv *,jclass)398 extern "C" JNIEXPORT int JNICALL Java_Main_numberOfDeoptimizations(JNIEnv*, jclass) {
399   return Runtime::Current()->GetNumberOfDeoptimizations();
400 }
401 
Java_Main_fetchProfiles(JNIEnv *,jclass)402 extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
403   jit::Jit* jit = GetJitIfEnabled();
404   if (jit == nullptr) {
405     return;
406   }
407   jit::JitCodeCache* code_cache = jit->GetCodeCache();
408   std::vector<ProfileMethodInfo> unused_vector;
409   std::set<std::string> unused_locations;
410   unused_locations.insert("fake_location");
411   ScopedObjectAccess soa(Thread::Current());
412   code_cache->GetProfiledMethods(unused_locations, unused_vector, /*inline_cache_threshold=*/0);
413 }
414 
Java_Main_waitForCompilation(JNIEnv *,jclass)415 extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
416   jit::Jit* jit = Runtime::Current()->GetJit();
417   if (jit != nullptr) {
418     jit->WaitForCompilationToFinish(Thread::Current());
419   }
420 }
421 
Java_Main_stopJit(JNIEnv *,jclass)422 extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
423   jit::Jit* jit = Runtime::Current()->GetJit();
424   if (jit != nullptr) {
425     jit->Stop();
426   }
427 }
428 
Java_Main_startJit(JNIEnv *,jclass)429 extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
430   jit::Jit* jit = Runtime::Current()->GetJit();
431   if (jit != nullptr) {
432     jit->Start();
433   }
434 }
435 
Java_Main_getJitThreshold(JNIEnv *,jclass)436 extern "C" JNIEXPORT jint JNICALL Java_Main_getJitThreshold(JNIEnv*, jclass) {
437   jit::Jit* jit = Runtime::Current()->GetJit();
438   return (jit != nullptr) ? jit->HotMethodThreshold() : 0;
439 }
440 
Java_Main_deoptimizeBootImage(JNIEnv *,jclass)441 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeBootImage(JNIEnv*, jclass) {
442   ScopedSuspendAll ssa(__FUNCTION__);
443   Runtime::Current()->DeoptimizeBootImage();
444 }
445 
Java_Main_deoptimizeNativeMethod(JNIEnv * env,jclass,jclass cls,jstring method_name)446 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeNativeMethod(JNIEnv* env,
447                                                                    jclass,
448                                                                    jclass cls,
449                                                                    jstring method_name) {
450   Thread* self = Thread::Current();
451   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
452   // Make initialized classes visibly initialized to avoid entrypoint being set to boot JNI stub
453   // after deoptimize.
454   class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
455   ScopedObjectAccess soa(self);
456   ScopedUtfChars chars(env, method_name);
457   ArtMethod* method = GetMethod(soa, cls, chars);
458   CHECK(method->IsNative());
459   Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
460 }
461 
Java_Main_isDebuggable(JNIEnv *,jclass)462 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDebuggable(JNIEnv*, jclass) {
463   return Runtime::Current()->IsJavaDebuggable() ? JNI_TRUE : JNI_FALSE;
464 }
465 
Java_Main_setTargetSdkVersion(JNIEnv *,jclass,jint version)466 extern "C" JNIEXPORT void JNICALL Java_Main_setTargetSdkVersion(JNIEnv*, jclass, jint version) {
467   Runtime::Current()->SetTargetSdkVersion(static_cast<uint32_t>(version));
468 }
469 
Java_Main_genericFieldOffset(JNIEnv * env,jclass,jobject fld)470 extern "C" JNIEXPORT jlong JNICALL Java_Main_genericFieldOffset(JNIEnv* env, jclass, jobject fld) {
471   jfieldID fid = env->FromReflectedField(fld);
472   ScopedObjectAccess soa(env);
473   ArtField* af = jni::DecodeArtField(fid);
474   return af->GetOffset().Int32Value();
475 }
476 
Java_Main_isObsoleteObject(JNIEnv * env,jclass,jclass c)477 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isObsoleteObject(JNIEnv* env, jclass, jclass c) {
478   ScopedObjectAccess soa(env);
479   return soa.Decode<mirror::Class>(c)->IsObsoleteObject();
480 }
481 
Java_Main_forceInterpreterOnThread(JNIEnv * env,jclass cls)482 extern "C" JNIEXPORT void JNICALL Java_Main_forceInterpreterOnThread(JNIEnv* env,
483                                                                      [[maybe_unused]] jclass cls) {
484   ScopedObjectAccess soa(env);
485   MutexLock thread_list_mu(soa.Self(), *Locks::thread_list_lock_);
486   soa.Self()->IncrementForceInterpreterCount();
487 }
488 
Java_Main_setAsyncExceptionsThrown(JNIEnv * env,jclass cls)489 extern "C" JNIEXPORT void JNICALL Java_Main_setAsyncExceptionsThrown([[maybe_unused]] JNIEnv* env,
490                                                                      [[maybe_unused]] jclass cls) {
491   Runtime::Current()->SetAsyncExceptionsThrown();
492 }
493 
Java_Main_setRlimitNoFile(JNIEnv *,jclass,jint value)494 extern "C" JNIEXPORT void JNICALL Java_Main_setRlimitNoFile(JNIEnv*, jclass, jint value) {
495   rlimit limit { static_cast<rlim_t>(value), static_cast<rlim_t>(value) };
496   setrlimit(RLIMIT_NOFILE, &limit);
497 }
498 
Java_Main_isInImageSpace(JNIEnv * env,jclass caller,jclass cls)499 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInImageSpace(JNIEnv* env,
500                                                                [[maybe_unused]] jclass caller,
501                                                                jclass cls) {
502   ScopedObjectAccess soa(env);
503 
504   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
505   gc::space::Space* space =
506       Runtime::Current()->GetHeap()->FindSpaceFromObject(klass, /*fail_ok=*/true);
507   if (space == nullptr) {
508     return JNI_FALSE;
509   }
510   return space->IsImageSpace() ? JNI_TRUE : JNI_FALSE;
511 }
512 
513 // Ensures the profile saver does its usual processing.
Java_Main_ensureProfileProcessing(JNIEnv *,jclass)514 extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfileProcessing(JNIEnv*, jclass) {
515   ProfileSaver::ForceProcessProfiles();
516 }
517 
Java_Main_isForBootImage(JNIEnv * env,jclass,jstring filename)518 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isForBootImage(JNIEnv* env,
519                                                                jclass,
520                                                                jstring filename) {
521   ScopedUtfChars filename_chars(env, filename);
522   CHECK(filename_chars.c_str() != nullptr);
523 
524   ProfileCompilationInfo info(/*for_boot_image=*/true);
525   bool result = info.Load(std::string(filename_chars.c_str()), /*clear_if_invalid=*/false);
526   return result ? JNI_TRUE : JNI_FALSE;
527 }
528 
GetMethodHotnessFromProfile(JNIEnv * env,jclass c,jstring filename,jobject method)529 static ProfileCompilationInfo::MethodHotness GetMethodHotnessFromProfile(JNIEnv* env,
530                                                                          jclass c,
531                                                                          jstring filename,
532                                                                          jobject method) {
533   bool for_boot_image = Java_Main_isForBootImage(env, c, filename) == JNI_TRUE;
534   ScopedUtfChars filename_chars(env, filename);
535   CHECK(filename_chars.c_str() != nullptr);
536   ScopedObjectAccess soa(env);
537   ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method);
538   ArtMethod* art_method = exec->GetArtMethod();
539   MethodReference ref(art_method->GetDexFile(), art_method->GetDexMethodIndex());
540 
541   ProfileCompilationInfo info(Runtime::Current()->GetArenaPool(), for_boot_image);
542   if (!info.Load(filename_chars.c_str(), /*clear_if_invalid=*/false)) {
543     LOG(ERROR) << "Failed to load profile from " << filename;
544     return ProfileCompilationInfo::MethodHotness();
545   }
546   return info.GetMethodHotness(ref);
547 }
548 
549 // Checks if the method is present in the profile.
Java_Main_presentInProfile(JNIEnv * env,jclass c,jstring filename,jobject method)550 extern "C" JNIEXPORT jboolean JNICALL Java_Main_presentInProfile(JNIEnv* env,
551                                                                  jclass c,
552                                                                  jstring filename,
553                                                                  jobject method) {
554   // TODO: Why do we check `hotness.IsHot()` instead of `hotness.IsInProfile()`
555   // in a method named `presentInProfile()`?
556   return GetMethodHotnessFromProfile(env, c, filename, method).IsHot() ? JNI_TRUE : JNI_FALSE;
557 }
558 
559 // Checks if the method has an inline cache in the profile that contains at least the given target
560 // types.
Java_Main_hasInlineCacheInProfile(JNIEnv * env,jclass c,jstring filename,jobject method,jobjectArray target_types)561 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasInlineCacheInProfile(
562     JNIEnv* env, jclass c, jstring filename, jobject method, jobjectArray target_types) {
563   ProfileCompilationInfo::MethodHotness hotness =
564       GetMethodHotnessFromProfile(env, c, filename, method);
565   if (hotness.GetInlineCacheMap() == nullptr) {
566     return JNI_FALSE;
567   }
568   ScopedObjectAccess soa(env);
569   ObjPtr<mirror::ObjectArray<mirror::Class>> types =
570       soa.Decode<mirror::ObjectArray<mirror::Class>>(target_types);
571   for (const auto& [dex_pc, dex_pc_data] : *hotness.GetInlineCacheMap()) {
572     bool match = true;
573     for (ObjPtr<mirror::Class> type : *types.Ptr()) {
574       dex::TypeIndex expected_index = type->GetDexTypeIndex();
575       if (!expected_index.IsValid()) {
576         return JNI_FALSE;
577       }
578       if (dex_pc_data.classes.find(expected_index) == dex_pc_data.classes.end()) {
579         match = false;
580         break;
581       }
582     }
583     if (match) {
584       return JNI_TRUE;
585     }
586   }
587   return JNI_FALSE;
588 }
589 
Java_Main_getCurrentGcNum(JNIEnv * env,jclass)590 extern "C" JNIEXPORT jint JNICALL Java_Main_getCurrentGcNum(JNIEnv* env, jclass) {
591   // Prevent any new GC before getting the current GC num.
592   ScopedObjectAccess soa(env);
593   gc::Heap* heap = Runtime::Current()->GetHeap();
594   heap->WaitForGcToComplete(gc::kGcCauseJitCodeCache, Thread::Current());
595   return heap->GetCurrentGcNum();
596 }
597 
Java_Main_removeJitCompiledMethod(JNIEnv * env,jclass,jobject java_method,jboolean release_memory)598 extern "C" JNIEXPORT jboolean Java_Main_removeJitCompiledMethod(JNIEnv* env,
599                                                                 jclass,
600                                                                 jobject java_method,
601                                                                 jboolean release_memory) {
602   if (!Runtime::Current()->UseJitCompilation()) {
603     return JNI_FALSE;
604   }
605 
606   jit::Jit* jit = Runtime::Current()->GetJit();
607   jit->WaitForCompilationToFinish(Thread::Current());
608 
609   ScopedObjectAccess soa(env);
610   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, java_method);
611 
612   jit::JitCodeCache* code_cache = jit->GetCodeCache();
613 
614   // Drop the shared mutator lock.
615   ScopedThreadSuspension self_suspension(Thread::Current(), art::ThreadState::kNative);
616   // Get exclusive mutator lock with suspend all.
617   ScopedSuspendAll suspend("Removing JIT compiled method", /*long_suspend=*/true);
618   bool removed = code_cache->RemoveMethod(method, static_cast<bool>(release_memory));
619   return removed ? JNI_TRUE : JNI_FALSE;
620 }
621 
622 }  // namespace art
623