Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2008 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 "dalvik_system_VMRuntime.h"
     18 
     19 #ifdef HAVE_ANDROID_OS
     20 extern "C" void android_set_application_target_sdk_version(uint32_t version);
     21 #endif
     22 #include <limits.h>
     23 #include <ScopedUtfChars.h>
     24 
     25 #pragma GCC diagnostic push
     26 #pragma GCC diagnostic ignored "-Wshadow"
     27 #include "toStringArray.h"
     28 #pragma GCC diagnostic pop
     29 
     30 #include "art_method-inl.h"
     31 #include "arch/instruction_set.h"
     32 #include "class_linker-inl.h"
     33 #include "common_throws.h"
     34 #include "debugger.h"
     35 #include "dex_file-inl.h"
     36 #include "gc/accounting/card_table-inl.h"
     37 #include "gc/allocator/dlmalloc.h"
     38 #include "gc/heap.h"
     39 #include "gc/space/dlmalloc_space.h"
     40 #include "gc/space/image_space.h"
     41 #include "gc/task_processor.h"
     42 #include "intern_table.h"
     43 #include "jni_internal.h"
     44 #include "mirror/class-inl.h"
     45 #include "mirror/dex_cache-inl.h"
     46 #include "mirror/object-inl.h"
     47 #include "runtime.h"
     48 #include "scoped_fast_native_object_access.h"
     49 #include "scoped_thread_state_change.h"
     50 #include "thread.h"
     51 #include "thread_list.h"
     52 
     53 namespace art {
     54 
     55 static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
     56   return Runtime::Current()->GetHeap()->GetTargetHeapUtilization();
     57 }
     58 
     59 static void VMRuntime_nativeSetTargetHeapUtilization(JNIEnv*, jobject, jfloat target) {
     60   Runtime::Current()->GetHeap()->SetTargetHeapUtilization(target);
     61 }
     62 
     63 static void VMRuntime_startJitCompilation(JNIEnv*, jobject) {
     64 }
     65 
     66 static void VMRuntime_disableJitCompilation(JNIEnv*, jobject) {
     67 }
     68 
     69 static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass,
     70                                             jint length) {
     71   ScopedFastNativeObjectAccess soa(env);
     72   if (UNLIKELY(length < 0)) {
     73     ThrowNegativeArraySizeException(length);
     74     return nullptr;
     75   }
     76   mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
     77   if (UNLIKELY(element_class == nullptr)) {
     78     ThrowNullPointerException("element class == null");
     79     return nullptr;
     80   }
     81   Runtime* runtime = Runtime::Current();
     82   mirror::Class* array_class =
     83       runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
     84   if (UNLIKELY(array_class == nullptr)) {
     85     return nullptr;
     86   }
     87   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentNonMovingAllocator();
     88   mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length,
     89                                                      array_class->GetComponentSizeShift(),
     90                                                      allocator);
     91   return soa.AddLocalReference<jobject>(result);
     92 }
     93 
     94 static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaElementClass,
     95                                           jint length) {
     96   ScopedFastNativeObjectAccess soa(env);
     97   if (UNLIKELY(length < 0)) {
     98     ThrowNegativeArraySizeException(length);
     99     return nullptr;
    100   }
    101   mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
    102   if (UNLIKELY(element_class == nullptr)) {
    103     ThrowNullPointerException("element class == null");
    104     return nullptr;
    105   }
    106   Runtime* runtime = Runtime::Current();
    107   mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
    108                                                                          &element_class);
    109   if (UNLIKELY(array_class == nullptr)) {
    110     return nullptr;
    111   }
    112   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
    113   mirror::Array* result = mirror::Array::Alloc<true, true>(soa.Self(), array_class, length,
    114                                                            array_class->GetComponentSizeShift(),
    115                                                            allocator);
    116   return soa.AddLocalReference<jobject>(result);
    117 }
    118 
    119 static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
    120   if (javaArray == nullptr) {  // Most likely allocation failed
    121     return 0;
    122   }
    123   ScopedFastNativeObjectAccess soa(env);
    124   mirror::Array* array = soa.Decode<mirror::Array*>(javaArray);
    125   if (!array->IsArrayInstance()) {
    126     ThrowIllegalArgumentException("not an array");
    127     return 0;
    128   }
    129   if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
    130     ThrowRuntimeException("Trying to get address of movable array object");
    131     return 0;
    132   }
    133   return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize(), 0));
    134 }
    135 
    136 static void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) {
    137   Runtime::Current()->GetHeap()->ClearGrowthLimit();
    138 }
    139 
    140 static void VMRuntime_clampGrowthLimit(JNIEnv*, jobject) {
    141   Runtime::Current()->GetHeap()->ClampGrowthLimit();
    142 }
    143 
    144 static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
    145   return Dbg::IsDebuggerActive();
    146 }
    147 
    148 static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) {
    149   return toStringArray(env, Runtime::Current()->GetProperties());
    150 }
    151 
    152 // This is for backward compatibility with dalvik which returned the
    153 // meaningless "." when no boot classpath or classpath was
    154 // specified. Unfortunately, some tests were using java.class.path to
    155 // lookup relative file locations, so they are counting on this to be
    156 // ".", presumably some applications or libraries could have as well.
    157 static const char* DefaultToDot(const std::string& class_path) {
    158   return class_path.empty() ? "." : class_path.c_str();
    159 }
    160 
    161 static jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) {
    162   return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPathString()));
    163 }
    164 
    165 static jstring VMRuntime_classPath(JNIEnv* env, jobject) {
    166   return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetClassPathString()));
    167 }
    168 
    169 static jstring VMRuntime_vmVersion(JNIEnv* env, jobject) {
    170   return env->NewStringUTF(Runtime::GetVersion());
    171 }
    172 
    173 static jstring VMRuntime_vmLibrary(JNIEnv* env, jobject) {
    174   return env->NewStringUTF(kIsDebugBuild ? "libartd.so" : "libart.so");
    175 }
    176 
    177 static jstring VMRuntime_vmInstructionSet(JNIEnv* env, jobject) {
    178   InstructionSet isa = Runtime::Current()->GetInstructionSet();
    179   const char* isa_string = GetInstructionSetString(isa);
    180   return env->NewStringUTF(isa_string);
    181 }
    182 
    183 static jboolean VMRuntime_is64Bit(JNIEnv*, jobject) {
    184   bool is64BitMode = (sizeof(void*) == sizeof(uint64_t));
    185   return is64BitMode ? JNI_TRUE : JNI_FALSE;
    186 }
    187 
    188 static jboolean VMRuntime_isCheckJniEnabled(JNIEnv* env, jobject) {
    189   return down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
    190 }
    191 
    192 static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sdk_version) {
    193   // This is the target SDK version of the app we're about to run. It is intended that this a place
    194   // where workarounds can be enabled.
    195   // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
    196   // Note that targetSdkVersion may be 0, meaning "current".
    197   Runtime::Current()->SetTargetSdkVersion(target_sdk_version);
    198 
    199 #ifdef HAVE_ANDROID_OS
    200   // This part is letting libc/dynamic linker know about current app's
    201   // target sdk version to enable compatibility workarounds.
    202   android_set_application_target_sdk_version(static_cast<uint32_t>(target_sdk_version));
    203 #endif
    204 }
    205 
    206 static void VMRuntime_registerNativeAllocation(JNIEnv* env, jobject, jint bytes) {
    207   if (UNLIKELY(bytes < 0)) {
    208     ScopedObjectAccess soa(env);
    209     ThrowRuntimeException("allocation size negative %d", bytes);
    210     return;
    211   }
    212   Runtime::Current()->GetHeap()->RegisterNativeAllocation(env, static_cast<size_t>(bytes));
    213 }
    214 
    215 static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) {
    216   if (UNLIKELY(bytes < 0)) {
    217     ScopedObjectAccess soa(env);
    218     ThrowRuntimeException("allocation size negative %d", bytes);
    219     return;
    220   }
    221   Runtime::Current()->GetHeap()->RegisterNativeFree(env, static_cast<size_t>(bytes));
    222 }
    223 
    224 static void VMRuntime_updateProcessState(JNIEnv*, jobject, jint process_state) {
    225   Runtime* runtime = Runtime::Current();
    226   runtime->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
    227   runtime->UpdateProfilerState(process_state);
    228 }
    229 
    230 static void VMRuntime_trimHeap(JNIEnv* env, jobject) {
    231   Runtime::Current()->GetHeap()->Trim(ThreadForEnv(env));
    232 }
    233 
    234 static void VMRuntime_concurrentGC(JNIEnv* env, jobject) {
    235   Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env), true);
    236 }
    237 
    238 static void VMRuntime_requestHeapTrim(JNIEnv* env, jobject) {
    239   Runtime::Current()->GetHeap()->RequestTrim(ThreadForEnv(env));
    240 }
    241 
    242 static void VMRuntime_requestConcurrentGC(JNIEnv* env, jobject) {
    243   Runtime::Current()->GetHeap()->RequestConcurrentGC(ThreadForEnv(env), true);
    244 }
    245 
    246 static void VMRuntime_startHeapTaskProcessor(JNIEnv* env, jobject) {
    247   Runtime::Current()->GetHeap()->GetTaskProcessor()->Start(ThreadForEnv(env));
    248 }
    249 
    250 static void VMRuntime_stopHeapTaskProcessor(JNIEnv* env, jobject) {
    251   Runtime::Current()->GetHeap()->GetTaskProcessor()->Stop(ThreadForEnv(env));
    252 }
    253 
    254 static void VMRuntime_runHeapTasks(JNIEnv* env, jobject) {
    255   Runtime::Current()->GetHeap()->GetTaskProcessor()->RunAllTasks(ThreadForEnv(env));
    256 }
    257 
    258 typedef std::map<std::string, mirror::String*> StringTable;
    259 
    260 class PreloadDexCachesStringsVisitor : public SingleRootVisitor {
    261  public:
    262   explicit PreloadDexCachesStringsVisitor(StringTable* table) : table_(table) { }
    263 
    264   void VisitRoot(mirror::Object* root, const RootInfo& info ATTRIBUTE_UNUSED)
    265       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    266     mirror::String* string = root->AsString();
    267     table_->operator[](string->ToModifiedUtf8()) = string;
    268   }
    269 
    270  private:
    271   StringTable* const table_;
    272 };
    273 
    274 // Based on ClassLinker::ResolveString.
    275 static void PreloadDexCachesResolveString(
    276     Handle<mirror::DexCache> dex_cache, uint32_t string_idx, StringTable& strings)
    277     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    278   mirror::String* string = dex_cache->GetResolvedString(string_idx);
    279   if (string != nullptr) {
    280     return;
    281   }
    282   const DexFile* dex_file = dex_cache->GetDexFile();
    283   const char* utf8 = dex_file->StringDataByIdx(string_idx);
    284   string = strings[utf8];
    285   if (string == nullptr) {
    286     return;
    287   }
    288   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved string=" << utf8;
    289   dex_cache->SetResolvedString(string_idx, string);
    290 }
    291 
    292 // Based on ClassLinker::ResolveType.
    293 static void PreloadDexCachesResolveType(
    294     Thread* self, mirror::DexCache* dex_cache, uint32_t type_idx)
    295     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    296   mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
    297   if (klass != nullptr) {
    298     return;
    299   }
    300   const DexFile* dex_file = dex_cache->GetDexFile();
    301   const char* class_name = dex_file->StringByTypeIdx(type_idx);
    302   ClassLinker* linker = Runtime::Current()->GetClassLinker();
    303   if (class_name[1] == '\0') {
    304     klass = linker->FindPrimitiveClass(class_name[0]);
    305   } else {
    306     klass = linker->LookupClass(self, class_name, ComputeModifiedUtf8Hash(class_name), nullptr);
    307   }
    308   if (klass == nullptr) {
    309     return;
    310   }
    311   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved klass=" << class_name;
    312   dex_cache->SetResolvedType(type_idx, klass);
    313   // Skip uninitialized classes because filled static storage entry implies it is initialized.
    314   if (!klass->IsInitialized()) {
    315     // LOG(INFO) << "VMRuntime.preloadDexCaches uninitialized klass=" << class_name;
    316     return;
    317   }
    318   // LOG(INFO) << "VMRuntime.preloadDexCaches static storage klass=" << class_name;
    319 }
    320 
    321 // Based on ClassLinker::ResolveField.
    322 static void PreloadDexCachesResolveField(Handle<mirror::DexCache> dex_cache, uint32_t field_idx,
    323                                          bool is_static)
    324     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    325   ArtField* field = dex_cache->GetResolvedField(field_idx, sizeof(void*));
    326   if (field != nullptr) {
    327     return;
    328   }
    329   const DexFile* dex_file = dex_cache->GetDexFile();
    330   const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
    331   Thread* const self = Thread::Current();
    332   StackHandleScope<1> hs(self);
    333   Handle<mirror::Class> klass(hs.NewHandle(dex_cache->GetResolvedType(field_id.class_idx_)));
    334   if (klass.Get() == nullptr) {
    335     return;
    336   }
    337   if (is_static) {
    338     field = mirror::Class::FindStaticField(self, klass, dex_cache.Get(), field_idx);
    339   } else {
    340     field = klass->FindInstanceField(dex_cache.Get(), field_idx);
    341   }
    342   if (field == nullptr) {
    343     return;
    344   }
    345   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved field " << PrettyField(field);
    346   dex_cache->SetResolvedField(field_idx, field, sizeof(void*));
    347 }
    348 
    349 // Based on ClassLinker::ResolveMethod.
    350 static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, uint32_t method_idx,
    351                                           InvokeType invoke_type)
    352     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    353   ArtMethod* method = dex_cache->GetResolvedMethod(method_idx, sizeof(void*));
    354   if (method != nullptr) {
    355     return;
    356   }
    357   const DexFile* dex_file = dex_cache->GetDexFile();
    358   const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
    359   mirror::Class* klass = dex_cache->GetResolvedType(method_id.class_idx_);
    360   if (klass == nullptr) {
    361     return;
    362   }
    363   switch (invoke_type) {
    364     case kDirect:
    365     case kStatic:
    366       method = klass->FindDirectMethod(dex_cache.Get(), method_idx, sizeof(void*));
    367       break;
    368     case kInterface:
    369       method = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, sizeof(void*));
    370       break;
    371     case kSuper:
    372     case kVirtual:
    373       method = klass->FindVirtualMethod(dex_cache.Get(), method_idx, sizeof(void*));
    374       break;
    375     default:
    376       LOG(FATAL) << "Unreachable - invocation type: " << invoke_type;
    377       UNREACHABLE();
    378   }
    379   if (method == nullptr) {
    380     return;
    381   }
    382   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved method " << PrettyMethod(method);
    383   dex_cache->SetResolvedMethod(method_idx, method, sizeof(void*));
    384 }
    385 
    386 struct DexCacheStats {
    387     uint32_t num_strings;
    388     uint32_t num_types;
    389     uint32_t num_fields;
    390     uint32_t num_methods;
    391     DexCacheStats() : num_strings(0),
    392                       num_types(0),
    393                       num_fields(0),
    394                       num_methods(0) {}
    395 };
    396 
    397 static const bool kPreloadDexCachesEnabled = true;
    398 
    399 // Disabled because it takes a long time (extra half second) but
    400 // gives almost no benefit in terms of saving private dirty pages.
    401 static const bool kPreloadDexCachesStrings = false;
    402 
    403 static const bool kPreloadDexCachesTypes = true;
    404 static const bool kPreloadDexCachesFieldsAndMethods = true;
    405 
    406 static const bool kPreloadDexCachesCollectStats = true;
    407 
    408 static void PreloadDexCachesStatsTotal(DexCacheStats* total) {
    409   if (!kPreloadDexCachesCollectStats) {
    410     return;
    411   }
    412 
    413   ClassLinker* linker = Runtime::Current()->GetClassLinker();
    414   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
    415   for (size_t i = 0; i< boot_class_path.size(); i++) {
    416     const DexFile* dex_file = boot_class_path[i];
    417     CHECK(dex_file != nullptr);
    418     total->num_strings += dex_file->NumStringIds();
    419     total->num_fields += dex_file->NumFieldIds();
    420     total->num_methods += dex_file->NumMethodIds();
    421     total->num_types += dex_file->NumTypeIds();
    422   }
    423 }
    424 
    425 static void PreloadDexCachesStatsFilled(DexCacheStats* filled)
    426     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    427   if (!kPreloadDexCachesCollectStats) {
    428       return;
    429   }
    430   ClassLinker* linker = Runtime::Current()->GetClassLinker();
    431   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
    432   for (size_t i = 0; i< boot_class_path.size(); i++) {
    433     const DexFile* dex_file = boot_class_path[i];
    434     CHECK(dex_file != nullptr);
    435     mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
    436     for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
    437       mirror::String* string = dex_cache->GetResolvedString(j);
    438       if (string != nullptr) {
    439         filled->num_strings++;
    440       }
    441     }
    442     for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
    443       mirror::Class* klass = dex_cache->GetResolvedType(j);
    444       if (klass != nullptr) {
    445         filled->num_types++;
    446       }
    447     }
    448     for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
    449       ArtField* field = linker->GetResolvedField(j, dex_cache);
    450       if (field != nullptr) {
    451         filled->num_fields++;
    452       }
    453     }
    454     for (size_t j = 0; j < dex_cache->NumResolvedMethods(); j++) {
    455       ArtMethod* method = dex_cache->GetResolvedMethod(j, sizeof(void*));
    456       if (method != nullptr) {
    457         filled->num_methods++;
    458       }
    459     }
    460   }
    461 }
    462 
    463 // TODO: http://b/11309598 This code was ported over based on the
    464 // Dalvik version. However, ART has similar code in other places such
    465 // as the CompilerDriver. This code could probably be refactored to
    466 // serve both uses.
    467 static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
    468   if (!kPreloadDexCachesEnabled) {
    469     return;
    470   }
    471 
    472   ScopedObjectAccess soa(env);
    473 
    474   DexCacheStats total;
    475   DexCacheStats before;
    476   if (kPreloadDexCachesCollectStats) {
    477     LOG(INFO) << "VMRuntime.preloadDexCaches starting";
    478     PreloadDexCachesStatsTotal(&total);
    479     PreloadDexCachesStatsFilled(&before);
    480   }
    481 
    482   Runtime* runtime = Runtime::Current();
    483   ClassLinker* linker = runtime->GetClassLinker();
    484 
    485   // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
    486   StringTable strings;
    487   if (kPreloadDexCachesStrings) {
    488     PreloadDexCachesStringsVisitor visitor(&strings);
    489     runtime->GetInternTable()->VisitRoots(&visitor, kVisitRootFlagAllRoots);
    490   }
    491 
    492   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
    493   for (size_t i = 0; i< boot_class_path.size(); i++) {
    494     const DexFile* dex_file = boot_class_path[i];
    495     CHECK(dex_file != nullptr);
    496     StackHandleScope<1> hs(soa.Self());
    497     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
    498 
    499     if (kPreloadDexCachesStrings) {
    500       for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
    501         PreloadDexCachesResolveString(dex_cache, j, strings);
    502       }
    503     }
    504 
    505     if (kPreloadDexCachesTypes) {
    506       for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
    507         PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), j);
    508       }
    509     }
    510 
    511     if (kPreloadDexCachesFieldsAndMethods) {
    512       for (size_t class_def_index = 0;
    513            class_def_index < dex_file->NumClassDefs();
    514            class_def_index++) {
    515         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    516         const uint8_t* class_data = dex_file->GetClassData(class_def);
    517         if (class_data == nullptr) {
    518           continue;
    519         }
    520         ClassDataItemIterator it(*dex_file, class_data);
    521         for (; it.HasNextStaticField(); it.Next()) {
    522           uint32_t field_idx = it.GetMemberIndex();
    523           PreloadDexCachesResolveField(dex_cache, field_idx, true);
    524         }
    525         for (; it.HasNextInstanceField(); it.Next()) {
    526           uint32_t field_idx = it.GetMemberIndex();
    527           PreloadDexCachesResolveField(dex_cache, field_idx, false);
    528         }
    529         for (; it.HasNextDirectMethod(); it.Next()) {
    530           uint32_t method_idx = it.GetMemberIndex();
    531           InvokeType invoke_type = it.GetMethodInvokeType(class_def);
    532           PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
    533         }
    534         for (; it.HasNextVirtualMethod(); it.Next()) {
    535           uint32_t method_idx = it.GetMemberIndex();
    536           InvokeType invoke_type = it.GetMethodInvokeType(class_def);
    537           PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
    538         }
    539       }
    540     }
    541   }
    542 
    543   if (kPreloadDexCachesCollectStats) {
    544     DexCacheStats after;
    545     PreloadDexCachesStatsFilled(&after);
    546     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d",
    547                               total.num_strings, before.num_strings, after.num_strings);
    548     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches types total=%d before=%d after=%d",
    549                               total.num_types, before.num_types, after.num_types);
    550     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d",
    551                               total.num_fields, before.num_fields, after.num_fields);
    552     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d",
    553                               total.num_methods, before.num_methods, after.num_methods);
    554     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches finished");
    555   }
    556 }
    557 
    558 
    559 /*
    560  * This is called by the framework when it knows the application directory and
    561  * process name.  We use this information to start up the sampling profiler for
    562  * for ART.
    563  */
    564 static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName,
    565                                       jstring appDir ATTRIBUTE_UNUSED,
    566                                       jstring procName ATTRIBUTE_UNUSED) {
    567   const char *pkgNameChars = env->GetStringUTFChars(pkgName, nullptr);
    568   std::string profileFile = StringPrintf("/data/dalvik-cache/profiles/%s", pkgNameChars);
    569 
    570   Runtime::Current()->StartProfiler(profileFile.c_str());
    571 
    572   env->ReleaseStringUTFChars(pkgName, pkgNameChars);
    573 }
    574 
    575 static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
    576   ScopedUtfChars instruction_set(env, java_instruction_set);
    577   if (instruction_set.c_str() == nullptr) {
    578     return JNI_FALSE;
    579   }
    580   InstructionSet isa = GetInstructionSetFromString(instruction_set.c_str());
    581   if (isa == kNone) {
    582     ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException"));
    583     std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str()));
    584     env->ThrowNew(iae.get(), message.c_str());
    585     return JNI_FALSE;
    586   }
    587   std::string error_msg;
    588   std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeader(
    589       Runtime::Current()->GetImageLocation().c_str(), isa, &error_msg));
    590   return image_header.get() != nullptr;
    591 }
    592 
    593 static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) {
    594   return env->NewStringUTF(GetInstructionSetString(kRuntimeISA));
    595 }
    596 
    597 static JNINativeMethod gMethods[] = {
    598   NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
    599   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
    600   NATIVE_METHOD(VMRuntime, clampGrowthLimit, "()V"),
    601   NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"),
    602   NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
    603   NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
    604   NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
    605   NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
    606   NATIVE_METHOD(VMRuntime, isDebuggerActive, "!()Z"),
    607   NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
    608   NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
    609   NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
    610   NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
    611   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
    612   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
    613   NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
    614   NATIVE_METHOD(VMRuntime, requestConcurrentGC, "()V"),
    615   NATIVE_METHOD(VMRuntime, requestHeapTrim, "()V"),
    616   NATIVE_METHOD(VMRuntime, runHeapTasks, "()V"),
    617   NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
    618   NATIVE_METHOD(VMRuntime, startHeapTaskProcessor, "()V"),
    619   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
    620   NATIVE_METHOD(VMRuntime, stopHeapTaskProcessor, "()V"),
    621   NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
    622   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
    623   NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"),
    624   NATIVE_METHOD(VMRuntime, vmInstructionSet, "()Ljava/lang/String;"),
    625   NATIVE_METHOD(VMRuntime, is64Bit, "!()Z"),
    626   NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "!()Z"),
    627   NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
    628   NATIVE_METHOD(VMRuntime, registerAppInfo,
    629                 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
    630   NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
    631   NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
    632 };
    633 
    634 void register_dalvik_system_VMRuntime(JNIEnv* env) {
    635   REGISTER_NATIVE_METHODS("dalvik/system/VMRuntime");
    636 }
    637 
    638 }  // namespace art
    639