• 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 
GetMethod(ScopedObjectAccess & soa,jclass cls,const ScopedUtfChars & chars)167 static ArtMethod* GetMethod(ScopedObjectAccess& soa, jclass cls, const ScopedUtfChars& chars)
168     REQUIRES_SHARED(Locks::mutator_lock_) {
169   CHECK(chars.c_str() != nullptr);
170   ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
171       chars.c_str(), kRuntimePointerSize);
172   if (method == nullptr) {
173     method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(chars.c_str(),
174                                                                              kRuntimePointerSize);
175   }
176   DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
177   return method;
178 }
179 
Java_Main_isAotCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)180 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotCompiled(JNIEnv* env,
181                                                               jclass,
182                                                               jclass cls,
183                                                               jstring method_name) {
184   Thread* self = Thread::Current();
185   ScopedObjectAccess soa(self);
186   ScopedUtfChars chars(env, method_name);
187   CHECK(chars.c_str() != nullptr);
188   ArtMethod* method = GetMethod(soa, cls, chars);
189   const void* oat_code = method->GetOatMethodQuickCode(kRuntimePointerSize);
190   if (oat_code == nullptr) {
191     return false;
192   }
193   const void* actual_code = Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method);
194   return actual_code == oat_code;
195 }
196 
Java_Main_hasJitCompiledEntrypoint(JNIEnv * env,jclass,jclass cls,jstring method_name)197 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
198                                                                          jclass,
199                                                                          jclass cls,
200                                                                          jstring method_name) {
201   jit::Jit* jit = GetJitIfEnabled();
202   if (jit == nullptr) {
203     return false;
204   }
205   Thread* self = Thread::Current();
206   ScopedObjectAccess soa(self);
207   ScopedUtfChars chars(env, method_name);
208   ArtMethod* method = GetMethod(soa, cls, chars);
209   ScopedAssertNoThreadSuspension sants(__FUNCTION__);
210   return jit->GetCodeCache()->ContainsPc(
211       Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method));
212 }
213 
Java_Main_hasJitCompiledCode(JNIEnv * env,jclass,jclass cls,jstring method_name)214 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env,
215                                                                    jclass,
216                                                                    jclass cls,
217                                                                    jstring method_name) {
218   jit::Jit* jit = GetJitIfEnabled();
219   if (jit == nullptr) {
220     return false;
221   }
222   Thread* self = Thread::Current();
223   ScopedObjectAccess soa(self);
224   ScopedUtfChars chars(env, method_name);
225   ArtMethod* method = GetMethod(soa, cls, chars);
226   return jit->GetCodeCache()->ContainsMethod(method);
227 }
228 
ForceJitCompiled(Thread * self,ArtMethod * method,CompilationKind kind)229 static void ForceJitCompiled(Thread* self,
230                              ArtMethod* method,
231                              CompilationKind kind) REQUIRES(!Locks::mutator_lock_) {
232   // TODO(mythria): Update this check once we support method entry / exit hooks directly from
233   // JIT code instead of installing EntryExit stubs.
234   if (Runtime::Current()->GetInstrumentation()->EntryExitStubsInstalled() &&
235       (method->IsNative() || !Runtime::Current()->IsJavaDebuggable())) {
236     return;
237   }
238 
239   {
240     ScopedObjectAccess soa(self);
241     if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
242       std::string msg(method->PrettyMethod());
243       msg += ": is not safe to jit!";
244       ThrowIllegalStateException(msg.c_str());
245       return;
246     }
247     // We force visible initialization of the declaring class to make sure the method
248     // doesn't keep the resolution stub as entrypoint.
249     StackHandleScope<1> hs(self);
250     Handle<mirror::Class> h_klass(hs.NewHandle(method->GetDeclaringClass()));
251     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
252     if (!class_linker->EnsureInitialized(self, h_klass, true, true)) {
253       self->AssertPendingException();
254       return;
255     }
256     if (UNLIKELY(!h_klass->IsInitialized())) {
257       // Must be initializing in this thread.
258       CHECK_EQ(h_klass->GetStatus(), ClassStatus::kInitializing);
259       CHECK_EQ(h_klass->GetClinitThreadId(), self->GetTid());
260       std::string msg(method->PrettyMethod());
261       msg += ": is not safe to jit because the class is being initialized in this thread!";
262       ThrowIllegalStateException(msg.c_str());
263       return;
264     }
265     if (!h_klass->IsVisiblyInitialized()) {
266       ScopedThreadSuspension sts(self, ThreadState::kNative);
267       class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
268     }
269   }
270   jit::Jit* jit = GetJitIfEnabled();
271   jit::JitCodeCache* code_cache = jit->GetCodeCache();
272   // Update the code cache to make sure the JIT code does not get deleted.
273   // Note: this will apply to all JIT compilations.
274   code_cache->SetGarbageCollectCode(false);
275   if (jit->JitAtFirstUse()) {
276     ScopedObjectAccess soa(self);
277     jit->CompileMethod(method, self, kind, /*prejit=*/ false);
278     return;
279   }
280   if (kind == CompilationKind::kBaseline || jit->GetJitCompiler()->IsBaselineCompiler()) {
281     ScopedObjectAccess soa(self);
282     if (jit->TryPatternMatch(method, CompilationKind::kBaseline)) {
283       return;
284     }
285     jit->MaybeEnqueueCompilation(method, self);
286   } else {
287     jit->EnqueueOptimizedCompilation(method, self);
288   }
289   do {
290     // Sleep to yield to the compiler thread.
291     usleep(1000);
292     const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
293     if (code_cache->ContainsPc(entry_point)) {
294       // If we're running baseline or not requesting optimized, we're good to go.
295       if (jit->GetJitCompiler()->IsBaselineCompiler() || kind != CompilationKind::kOptimized) {
296         break;
297       }
298       // If we're requesting optimized, check that we did get the method
299       // compiled optimized.
300       OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromEntryPoint(entry_point);
301       if (!CodeInfo::IsBaseline(method_header->GetOptimizedCodeInfoPtr())) {
302         break;
303       }
304     }
305   } while (true);
306 }
307 
Java_Main_ensureMethodJitCompiled(JNIEnv *,jclass,jobject meth)308 extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) {
309   jit::Jit* jit = GetJitIfEnabled();
310   if (jit == nullptr) {
311     return;
312   }
313 
314   Thread* self = Thread::Current();
315   ArtMethod* method;
316   {
317     ScopedObjectAccess soa(self);
318     method = ArtMethod::FromReflectedMethod(soa, meth);
319   }
320   ForceJitCompiled(self, method, CompilationKind::kOptimized);
321 }
322 
Java_Main_ensureJitCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)323 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
324                                                              jclass,
325                                                              jclass cls,
326                                                              jstring method_name) {
327   jit::Jit* jit = GetJitIfEnabled();
328   if (jit == nullptr) {
329     return;
330   }
331 
332   Thread* self = Thread::Current();
333   ArtMethod* method = nullptr;
334   {
335     ScopedObjectAccess soa(self);
336 
337     ScopedUtfChars chars(env, method_name);
338     method = GetMethod(soa, cls, chars);
339   }
340   ForceJitCompiled(self, method, CompilationKind::kOptimized);
341 }
342 
Java_Main_ensureJitBaselineCompiled(JNIEnv * env,jclass,jclass cls,jstring method_name)343 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitBaselineCompiled(JNIEnv* env,
344                                                                       jclass,
345                                                                       jclass cls,
346                                                                       jstring method_name) {
347   jit::Jit* jit = GetJitIfEnabled();
348   if (jit == nullptr) {
349     return;
350   }
351 
352   Thread* self = Thread::Current();
353   ArtMethod* method = nullptr;
354   {
355     ScopedObjectAccess soa(self);
356 
357     ScopedUtfChars chars(env, method_name);
358     method = GetMethod(soa, cls, chars);
359   }
360   ForceJitCompiled(self, method, CompilationKind::kBaseline);
361 }
362 
Java_Main_hasSingleImplementation(JNIEnv * env,jclass,jclass cls,jstring method_name)363 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env,
364                                                                         jclass,
365                                                                         jclass cls,
366                                                                         jstring method_name) {
367   ArtMethod* method = nullptr;
368   ScopedObjectAccess soa(Thread::Current());
369   ScopedUtfChars chars(env, method_name);
370   CHECK(chars.c_str() != nullptr);
371   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
372       chars.c_str(), kRuntimePointerSize);
373   return method->HasSingleImplementation();
374 }
375 
Java_Main_getHotnessCounter(JNIEnv * env,jclass,jclass cls,jstring method_name)376 extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env,
377                                                              jclass,
378                                                              jclass cls,
379                                                              jstring method_name) {
380   ScopedObjectAccess soa(Thread::Current());
381   ScopedUtfChars chars(env, method_name);
382   CHECK(chars.c_str() != nullptr);
383   ArtMethod* method =
384       soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(chars.c_str(),
385                                                                      kRuntimePointerSize);
386   if (method != nullptr) {
387     return method->GetCounter();
388   }
389 
390   method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(chars.c_str(),
391                                                                            kRuntimePointerSize);
392   if (method != nullptr) {
393     return method->GetCounter();
394   }
395 
396   return std::numeric_limits<int32_t>::min();
397 }
398 
Java_Main_numberOfDeoptimizations(JNIEnv *,jclass)399 extern "C" JNIEXPORT int JNICALL Java_Main_numberOfDeoptimizations(JNIEnv*, jclass) {
400   return Runtime::Current()->GetNumberOfDeoptimizations();
401 }
402 
Java_Main_fetchProfiles(JNIEnv *,jclass)403 extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
404   jit::Jit* jit = GetJitIfEnabled();
405   if (jit == nullptr) {
406     return;
407   }
408   jit::JitCodeCache* code_cache = jit->GetCodeCache();
409   std::vector<ProfileMethodInfo> unused_vector;
410   std::set<std::string> unused_locations;
411   unused_locations.insert("fake_location");
412   ScopedObjectAccess soa(Thread::Current());
413   code_cache->GetProfiledMethods(unused_locations, unused_vector, /*inline_cache_threshold=*/0);
414 }
415 
Java_Main_waitForCompilation(JNIEnv *,jclass)416 extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
417   jit::Jit* jit = Runtime::Current()->GetJit();
418   if (jit != nullptr) {
419     jit->WaitForCompilationToFinish(Thread::Current());
420   }
421 }
422 
Java_Main_stopJit(JNIEnv *,jclass)423 extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
424   jit::Jit* jit = Runtime::Current()->GetJit();
425   if (jit != nullptr) {
426     jit->Stop();
427   }
428 }
429 
Java_Main_startJit(JNIEnv *,jclass)430 extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
431   jit::Jit* jit = Runtime::Current()->GetJit();
432   if (jit != nullptr) {
433     jit->Start();
434   }
435 }
436 
Java_Main_getJitThreshold(JNIEnv *,jclass)437 extern "C" JNIEXPORT jint JNICALL Java_Main_getJitThreshold(JNIEnv*, jclass) {
438   jit::Jit* jit = Runtime::Current()->GetJit();
439   return (jit != nullptr) ? jit->HotMethodThreshold() : 0;
440 }
441 
Java_Main_deoptimizeBootImage(JNIEnv *,jclass)442 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeBootImage(JNIEnv*, jclass) {
443   ScopedSuspendAll ssa(__FUNCTION__);
444   Runtime::Current()->DeoptimizeBootImage();
445 }
446 
Java_Main_deoptimizeNativeMethod(JNIEnv * env,jclass,jclass cls,jstring method_name)447 extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeNativeMethod(JNIEnv* env,
448                                                                    jclass,
449                                                                    jclass cls,
450                                                                    jstring method_name) {
451   Thread* self = Thread::Current();
452   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
453   // Make initialized classes visibly initialized to avoid entrypoint being set to boot JNI stub
454   // after deoptimize.
455   class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
456   ScopedObjectAccess soa(self);
457   ScopedUtfChars chars(env, method_name);
458   ArtMethod* method = GetMethod(soa, cls, chars);
459   CHECK(method->IsNative());
460   Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(method);
461 }
462 
Java_Main_isDebuggable(JNIEnv *,jclass)463 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDebuggable(JNIEnv*, jclass) {
464   return Runtime::Current()->IsJavaDebuggable() ? JNI_TRUE : JNI_FALSE;
465 }
466 
Java_Main_setTargetSdkVersion(JNIEnv *,jclass,jint version)467 extern "C" JNIEXPORT void JNICALL Java_Main_setTargetSdkVersion(JNIEnv*, jclass, jint version) {
468   Runtime::Current()->SetTargetSdkVersion(static_cast<uint32_t>(version));
469 }
470 
Java_Main_genericFieldOffset(JNIEnv * env,jclass,jobject fld)471 extern "C" JNIEXPORT jlong JNICALL Java_Main_genericFieldOffset(JNIEnv* env, jclass, jobject fld) {
472   jfieldID fid = env->FromReflectedField(fld);
473   ScopedObjectAccess soa(env);
474   ArtField* af = jni::DecodeArtField(fid);
475   return af->GetOffset().Int32Value();
476 }
477 
Java_Main_isObsoleteObject(JNIEnv * env,jclass,jclass c)478 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isObsoleteObject(JNIEnv* env, jclass, jclass c) {
479   ScopedObjectAccess soa(env);
480   return soa.Decode<mirror::Class>(c)->IsObsoleteObject();
481 }
482 
Java_Main_forceInterpreterOnThread(JNIEnv * env,jclass cls)483 extern "C" JNIEXPORT void JNICALL Java_Main_forceInterpreterOnThread(JNIEnv* env,
484                                                                      [[maybe_unused]] jclass cls) {
485   ScopedObjectAccess soa(env);
486   MutexLock thread_list_mu(soa.Self(), *Locks::thread_list_lock_);
487   soa.Self()->IncrementForceInterpreterCount();
488 }
489 
Java_Main_setAsyncExceptionsThrown(JNIEnv * env,jclass cls)490 extern "C" JNIEXPORT void JNICALL Java_Main_setAsyncExceptionsThrown([[maybe_unused]] JNIEnv* env,
491                                                                      [[maybe_unused]] jclass cls) {
492   Runtime::Current()->SetAsyncExceptionsThrown();
493 }
494 
Java_Main_setRlimitNoFile(JNIEnv *,jclass,jint value)495 extern "C" JNIEXPORT void JNICALL Java_Main_setRlimitNoFile(JNIEnv*, jclass, jint value) {
496   rlimit limit { static_cast<rlim_t>(value), static_cast<rlim_t>(value) };
497   setrlimit(RLIMIT_NOFILE, &limit);
498 }
499 
Java_Main_isInImageSpace(JNIEnv * env,jclass caller,jclass cls)500 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInImageSpace(JNIEnv* env,
501                                                                [[maybe_unused]] jclass caller,
502                                                                jclass cls) {
503   ScopedObjectAccess soa(env);
504 
505   ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
506   gc::space::Space* space =
507       Runtime::Current()->GetHeap()->FindSpaceFromObject(klass, /*fail_ok=*/true);
508   if (space == nullptr) {
509     return JNI_FALSE;
510   }
511   return space->IsImageSpace() ? JNI_TRUE : JNI_FALSE;
512 }
513 
514 // Ensures the profile saver does its usual processing.
Java_Main_ensureProfileProcessing(JNIEnv *,jclass)515 extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfileProcessing(JNIEnv*, jclass) {
516   ProfileSaver::ForceProcessProfiles();
517 }
518 
Java_Main_isForBootImage(JNIEnv * env,jclass,jstring filename)519 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isForBootImage(JNIEnv* env,
520                                                                jclass,
521                                                                jstring filename) {
522   ScopedUtfChars filename_chars(env, filename);
523   CHECK(filename_chars.c_str() != nullptr);
524 
525   ProfileCompilationInfo info(/*for_boot_image=*/true);
526   bool result = info.Load(std::string(filename_chars.c_str()), /*clear_if_invalid=*/false);
527   return result ? JNI_TRUE : JNI_FALSE;
528 }
529 
GetMethodHotnessFromProfile(JNIEnv * env,jclass c,jstring filename,jobject method)530 static ProfileCompilationInfo::MethodHotness GetMethodHotnessFromProfile(JNIEnv* env,
531                                                                          jclass c,
532                                                                          jstring filename,
533                                                                          jobject method) {
534   bool for_boot_image = Java_Main_isForBootImage(env, c, filename) == JNI_TRUE;
535   ScopedUtfChars filename_chars(env, filename);
536   CHECK(filename_chars.c_str() != nullptr);
537   ScopedObjectAccess soa(env);
538   ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method);
539   ArtMethod* art_method = exec->GetArtMethod();
540   MethodReference ref(art_method->GetDexFile(), art_method->GetDexMethodIndex());
541 
542   ProfileCompilationInfo info(Runtime::Current()->GetArenaPool(), for_boot_image);
543   if (!info.Load(filename_chars.c_str(), /*clear_if_invalid=*/false)) {
544     LOG(ERROR) << "Failed to load profile from " << filename;
545     return ProfileCompilationInfo::MethodHotness();
546   }
547   return info.GetMethodHotness(ref);
548 }
549 
550 // Checks if the method is present in the profile.
Java_Main_presentInProfile(JNIEnv * env,jclass c,jstring filename,jobject method)551 extern "C" JNIEXPORT jboolean JNICALL Java_Main_presentInProfile(JNIEnv* env,
552                                                                  jclass c,
553                                                                  jstring filename,
554                                                                  jobject method) {
555   // TODO: Why do we check `hotness.IsHot()` instead of `hotness.IsInProfile()`
556   // in a method named `presentInProfile()`?
557   return GetMethodHotnessFromProfile(env, c, filename, method).IsHot() ? JNI_TRUE : JNI_FALSE;
558 }
559 
560 // Checks if the method has an inline cache in the profile that contains at least the given target
561 // types.
Java_Main_hasInlineCacheInProfile(JNIEnv * env,jclass c,jstring filename,jobject method,jobjectArray target_types)562 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasInlineCacheInProfile(
563     JNIEnv* env, jclass c, jstring filename, jobject method, jobjectArray target_types) {
564   ProfileCompilationInfo::MethodHotness hotness =
565       GetMethodHotnessFromProfile(env, c, filename, method);
566   if (hotness.GetInlineCacheMap() == nullptr) {
567     return JNI_FALSE;
568   }
569   ScopedObjectAccess soa(env);
570   ObjPtr<mirror::ObjectArray<mirror::Class>> types =
571       soa.Decode<mirror::ObjectArray<mirror::Class>>(target_types);
572   for (const auto& [dex_pc, dex_pc_data] : *hotness.GetInlineCacheMap()) {
573     bool match = true;
574     for (ObjPtr<mirror::Class> type : *types.Ptr()) {
575       dex::TypeIndex expected_index = type->GetDexTypeIndex();
576       if (!expected_index.IsValid()) {
577         return JNI_FALSE;
578       }
579       if (dex_pc_data.classes.find(expected_index) == dex_pc_data.classes.end()) {
580         match = false;
581         break;
582       }
583     }
584     if (match) {
585       return JNI_TRUE;
586     }
587   }
588   return JNI_FALSE;
589 }
590 
Java_Main_getCurrentGcNum(JNIEnv * env,jclass)591 extern "C" JNIEXPORT jint JNICALL Java_Main_getCurrentGcNum(JNIEnv* env, jclass) {
592   // Prevent any new GC before getting the current GC num.
593   ScopedObjectAccess soa(env);
594   gc::Heap* heap = Runtime::Current()->GetHeap();
595   heap->WaitForGcToComplete(gc::kGcCauseJitCodeCache, Thread::Current());
596   return heap->GetCurrentGcNum();
597 }
598 
Java_Main_removeJitCompiledMethod(JNIEnv * env,jclass,jobject java_method,jboolean release_memory)599 extern "C" JNIEXPORT jboolean Java_Main_removeJitCompiledMethod(JNIEnv* env,
600                                                                 jclass,
601                                                                 jobject java_method,
602                                                                 jboolean release_memory) {
603   if (!Runtime::Current()->UseJitCompilation()) {
604     return JNI_FALSE;
605   }
606 
607   jit::Jit* jit = Runtime::Current()->GetJit();
608   jit->WaitForCompilationToFinish(Thread::Current());
609 
610   ScopedObjectAccess soa(env);
611   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, java_method);
612 
613   jit::JitCodeCache* code_cache = jit->GetCodeCache();
614 
615   // Drop the shared mutator lock.
616   ScopedThreadSuspension self_suspension(Thread::Current(), art::ThreadState::kNative);
617   // Get exclusive mutator lock with suspend all.
618   ScopedSuspendAll suspend("Removing JIT compiled method", /*long_suspend=*/true);
619   bool removed = code_cache->RemoveMethod(method, static_cast<bool>(release_memory));
620   return removed ? JNI_TRUE : JNI_FALSE;
621 }
622 
623 }  // namespace art
624