diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 344 |
1 files changed, 247 insertions, 97 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 5278d1bb05..a13a2e337c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -36,6 +36,7 @@ #include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" +#include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "base/value_object.h" @@ -58,6 +59,7 @@ #include "interpreter/interpreter.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" +#include "jit/offline_profiling_info.h" #include "leb128.h" #include "linear_alloc.h" #include "mirror/class.h" @@ -759,7 +761,7 @@ static void SanityCheckArtMethod(ArtMethod* m, SHARED_REQUIRES(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { CHECK(m->GetDeclaringClass() == nullptr) << PrettyMethod(m); - } else if (m->IsMiranda()) { + } else if (m->IsCopied()) { CHECK(m->GetDeclaringClass() != nullptr) << PrettyMethod(m); } else if (expected_class != nullptr) { CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << PrettyMethod(m); @@ -1137,18 +1139,18 @@ class FixupArtMethodArrayVisitor : public ArtMethodVisitor { virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) { GcRoot<mirror::Class>* resolved_types = method->GetDexCacheResolvedTypes(sizeof(void*)); - const bool is_miranda = method->IsMiranda(); + const bool is_copied = method->IsCopied(); if (resolved_types != nullptr) { bool in_image_space = false; - if (kIsDebugBuild || is_miranda) { + if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast<const uint8_t*>(resolved_types) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. - DCHECK(is_miranda || in_image_space) + DCHECK(is_copied || in_image_space) << resolved_types << " is not in image starting at " << reinterpret_cast<void*>(header_.GetImageBegin()); - if (!is_miranda || in_image_space) { + if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedTypes(*reinterpret_cast<GcRoot<mirror::Class>**>(resolved_types), sizeof(void*)); @@ -1157,15 +1159,15 @@ class FixupArtMethodArrayVisitor : public ArtMethodVisitor { ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(sizeof(void*)); if (resolved_methods != nullptr) { bool in_image_space = false; - if (kIsDebugBuild || is_miranda) { + if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast<const uint8_t*>(resolved_methods) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. - DCHECK(is_miranda || in_image_space) + DCHECK(is_copied || in_image_space) << resolved_methods << " is not in image starting at " << reinterpret_cast<void*>(header_.GetImageBegin()); - if (!is_miranda || in_image_space) { + if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedMethods(*reinterpret_cast<ArtMethod***>(resolved_methods), sizeof(void*)); @@ -1197,7 +1199,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches, - bool added_class_table, + ClassTable::ClassSet* new_class_set, bool* out_forward_dex_cache_array, std::string* out_error_msg) { DCHECK(out_forward_dex_cache_array != nullptr); @@ -1216,20 +1218,40 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( for (size_t i = 0; i < num_dex_caches; i++) { mirror::DexCache* const dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); - // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and - // copy over the arrays. - DCHECK(dex_file != nullptr); - const size_t num_strings = dex_file->NumStringIds(); - const size_t num_types = dex_file->NumTypeIds(); - const size_t num_methods = dex_file->NumMethodIds(); - const size_t num_fields = dex_file->NumFieldIds(); - CHECK_EQ(num_strings, dex_cache->NumStrings()); - CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); - CHECK_EQ(num_methods, dex_cache->NumResolvedMethods()); - CHECK_EQ(num_fields, dex_cache->NumResolvedFields()); const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { ++num_dex_caches_with_bss_arrays; + } + } + *out_forward_dex_cache_array = num_dex_caches_with_bss_arrays != 0; + if (*out_forward_dex_cache_array) { + if (num_dex_caches_with_bss_arrays != num_dex_caches) { + // Reject application image since we cannot forward only some of the dex cache arrays. + // TODO: We could get around this by having a dedicated forwarding slot. It should be an + // uncommon case. + *out_error_msg = StringPrintf("Dex caches in bss does not match total: %zu vs %zu", + num_dex_caches_with_bss_arrays, + num_dex_caches); + return false; + } + } + // Only add the classes to the class loader after the points where we can return false. + for (size_t i = 0; i < num_dex_caches; i++) { + mirror::DexCache* const dex_cache = dex_caches->Get(i); + const DexFile* const dex_file = dex_cache->GetDexFile(); + const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); + if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { + // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and + // copy over the arrays. + DCHECK(dex_file != nullptr); + const size_t num_strings = dex_file->NumStringIds(); + const size_t num_types = dex_file->NumTypeIds(); + const size_t num_methods = dex_file->NumMethodIds(); + const size_t num_fields = dex_file->NumFieldIds(); + CHECK_EQ(num_strings, dex_cache->NumStrings()); + CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); + CHECK_EQ(num_methods, dex_cache->NumResolvedMethods()); + CHECK_EQ(num_fields, dex_cache->NumResolvedFields()); DexCacheArraysLayout layout(image_pointer_size_, dex_file); uint8_t* const raw_arrays = oat_dex_file->GetDexCacheArrays(); // The space is not yet visible to the GC, we can avoid the read barriers and use std::copy_n. @@ -1291,10 +1313,11 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( RegisterDexFileLocked(*dex_file, hs3.NewHandle(dex_cache)); } GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes(); - if (!added_class_table) { + const size_t num_types = dex_cache->NumResolvedTypes(); + if (new_class_set == nullptr) { for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. - mirror::Class* klass = types[j].Read<kWithoutReadBarrier>(); + mirror::Class* klass = types[j].Read(); if (klass != nullptr) { DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); // Update the class loader from the one in the image class loader to the one that loaded @@ -1340,14 +1363,26 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( if (kIsDebugBuild) { for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. - mirror::Class* klass = types[j].Read<kWithoutReadBarrier>(); + mirror::Class* klass = types[j].Read(); if (klass != nullptr) { DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); if (kIsDebugBuild) { - DCHECK_EQ(table->LookupByDescriptor(klass), klass); - mirror::Class* super_class = klass->GetSuperClass(); - if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { - CHECK_EQ(table->LookupByDescriptor(super_class), super_class); + if (new_class_set != nullptr) { + auto it = new_class_set->Find(GcRoot<mirror::Class>(klass)); + DCHECK(it != new_class_set->end()); + DCHECK_EQ(it->Read(), klass); + mirror::Class* super_class = klass->GetSuperClass(); + if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { + auto it2 = new_class_set->Find(GcRoot<mirror::Class>(super_class)); + DCHECK(it2 != new_class_set->end()); + DCHECK_EQ(it2->Read(), super_class); + } + } else { + DCHECK_EQ(table->LookupByDescriptor(klass), klass); + mirror::Class* super_class = klass->GetSuperClass(); + if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { + CHECK_EQ(table->LookupByDescriptor(super_class), super_class); + } } } if (kIsDebugBuild) { @@ -1361,7 +1396,6 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( DCHECK_EQ(code, oat_code) << PrettyMethod(&m); } } - VLOG(image) << "Virtual methods"; for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; @@ -1377,17 +1411,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } } } - *out_forward_dex_cache_array = num_dex_caches_with_bss_arrays != 0; if (*out_forward_dex_cache_array) { - if (num_dex_caches_with_bss_arrays != num_dex_caches) { - // Reject application image since we cannot forward only some of the dex cache arrays. - // TODO: We could get around this by having a dedicated forwarding slot. It should be an - // uncommon case. - *out_error_msg = StringPrintf("Dex caches in bss does not match total: %zu vs %zu", - num_dex_caches_with_bss_arrays, - num_dex_caches); - return false; - } FixupArtMethodArrayVisitor visitor(header); header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( &visitor, @@ -1395,17 +1419,11 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( sizeof(void*)); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } - if (kIsDebugBuild) { - ClassTable* const class_table = class_loader.Get()->GetClassTable(); - VerifyClassInTableArtMethodVisitor visitor2(class_table); - header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( - &visitor2, - space->Begin(), - sizeof(void*)); - } return true; } +// Update the class loader and resolved string dex cache array of classes. Should only be used on +// classes in the image space. class UpdateClassLoaderAndResolvedStringsVisitor { public: UpdateClassLoaderAndResolvedStringsVisitor(gc::space::ImageSpace* space, @@ -1615,7 +1633,8 @@ bool ClassLinker::AddImageSpace( VLOG(image) << name->ToModifiedUtf8(); } *error_msg = "Rejecting application image due to class loader mismatch"; - return false; + // Ignore class loader mismatch for now since these would just use possibly incorrect + // oat code anyways. The structural class check should be done in the parent. } } } @@ -1642,43 +1661,46 @@ bool ClassLinker::AddImageSpace( methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); } - const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable); - bool added_class_table = false; - if (app_image) { - GetOrCreateAllocatorForClassLoader(class_loader.Get()); // Make sure we have a linear alloc. - } ClassTable* class_table = nullptr; { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table = InsertClassTableForClassLoader(class_loader.Get()); - if (class_table_section.Size() > 0u) { - const uint64_t start_time2 = NanoTime(); - class_table->ReadFromMemory(space->Begin() + class_table_section.Offset()); - if (!app_image) { - dex_cache_boot_image_class_lookup_required_ = false; - } - VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); - added_class_table = true; + } + // If we have a class table section, read it and use it for verification in + // UpdateAppImageClassLoadersAndDexCaches. + ClassTable::ClassSet temp_set; + const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable); + const bool added_class_table = class_table_section.Size() > 0u; + if (added_class_table) { + const uint64_t start_time2 = NanoTime(); + size_t read_count = 0; + temp_set = ClassTable::ClassSet(space->Begin() + class_table_section.Offset(), + /*make copy*/false, + &read_count); + if (!app_image) { + dex_cache_boot_image_class_lookup_required_ = false; } + VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); } if (app_image) { bool forward_dex_cache_arrays = false; if (!UpdateAppImageClassLoadersAndDexCaches(space, class_loader, dex_caches, - added_class_table, + added_class_table ? &temp_set : nullptr, /*out*/&forward_dex_cache_arrays, /*out*/error_msg)) { return false; } + // Update class loader and resolved strings. If added_class_table is false, the resolved + // strings were forwarded UpdateAppImageClassLoadersAndDexCaches. + UpdateClassLoaderAndResolvedStringsVisitor visitor(space, + class_loader.Get(), + forward_dex_cache_arrays); if (added_class_table) { - WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - // Update class loader and resolved strings. If added_class_table is false, the resolved - // strings were already updated in UpdateAppImageClassLoadersAndDexCaches. - UpdateClassLoaderAndResolvedStringsVisitor visitor(space, - class_loader.Get(), - forward_dex_cache_arrays); - class_table->Visit(visitor); + for (GcRoot<mirror::Class>& root : temp_set) { + visitor(root.Read()); + } } // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss. // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and @@ -1697,6 +1719,19 @@ bool ClassLinker::AddImageSpace( } } } + if (added_class_table) { + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); + class_table->AddClassSet(std::move(temp_set)); + } + if (kIsDebugBuild && app_image) { + // This verification needs to happen after the classes have been added to the class loader. + // Since it ensures classes are in the class table. + VerifyClassInTableArtMethodVisitor visitor2(class_table); + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor2, + space->Begin(), + sizeof(void*)); + } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } @@ -2608,18 +2643,6 @@ const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) { return nullptr; } -const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, - uint16_t class_def_idx, - uint32_t method_idx) { - bool found; - OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found); - if (!found) { - return nullptr; - } - uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); - return oat_class.GetOatMethod(oat_method_idx).GetQuickCode(); -} - bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) { if (UNLIKELY(method->IsNative() || method->IsProxyMethod())) { return false; @@ -2650,6 +2673,11 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* return true; } + if (Dbg::IsDebuggerActive()) { + // Boot image classes are AOT-compiled as non-debuggable. + return runtime->GetHeap()->IsInBootImageOatFile(quick_code); + } + return false; } @@ -2860,8 +2888,9 @@ LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(mirror::ClassLoader WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); LinearAlloc* allocator = class_loader->GetAllocator(); if (allocator == nullptr) { - allocator = Runtime::Current()->CreateLinearAlloc(); - class_loader->SetAllocator(allocator); + RegisterClassLoader(class_loader); + allocator = class_loader->GetAllocator(); + CHECK(allocator != nullptr); } return allocator; } @@ -4822,24 +4851,31 @@ void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(new_class); } +void ClassLinker::RegisterClassLoader(mirror::ClassLoader* class_loader) { + CHECK(class_loader->GetAllocator() == nullptr); + CHECK(class_loader->GetClassTable() == nullptr); + Thread* const self = Thread::Current(); + ClassLoaderData data; + data.weak_root = self->GetJniEnv()->vm->AddWeakGlobalRef(self, class_loader); + // Create and set the class table. + data.class_table = new ClassTable; + class_loader->SetClassTable(data.class_table); + // Create and set the linear allocator. + data.allocator = Runtime::Current()->CreateLinearAlloc(); + class_loader->SetAllocator(data.allocator); + // Add to the list so that we know to free the data later. + class_loaders_.push_back(data); +} + ClassTable* ClassLinker::InsertClassTableForClassLoader(mirror::ClassLoader* class_loader) { if (class_loader == nullptr) { return &boot_class_table_; } ClassTable* class_table = class_loader->GetClassTable(); if (class_table == nullptr) { - class_table = new ClassTable; - Thread* const self = Thread::Current(); - ClassLoaderData data; - data.weak_root = self->GetJniEnv()->vm->AddWeakGlobalRef(self, class_loader); - data.class_table = class_table; - // Don't already have a class table, add it to the class loader. - CHECK(class_loader->GetClassTable() == nullptr); - class_loader->SetClassTable(data.class_table); - // Should have been set when we registered the dex file. - data.allocator = class_loader->GetAllocator(); - CHECK(data.allocator != nullptr); - class_loaders_.push_back(data); + RegisterClassLoader(class_loader); + class_table = class_loader->GetClassTable(); + DCHECK(class_table != nullptr); } return class_table; } @@ -6459,7 +6495,7 @@ bool ClassLinker::LinkInterfaceMethods( for (ArtMethod* mir_method : miranda_methods) { ArtMethod& new_method = *out; new_method.CopyFrom(mir_method, image_pointer_size_); - new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda); + new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda | kAccCopied); DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u) << "Miranda method should be abstract!"; move_table.emplace(mir_method, &new_method); @@ -6478,7 +6514,9 @@ bool ClassLinker::LinkInterfaceMethods( // yet it shouldn't have methods that are skipping access checks. // TODO This is rather arbitrary. We should maybe support classes where only some of its // methods are skip_access_checks. - new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccSkipAccessChecks); + constexpr uint32_t kSetFlags = kAccDefault | kAccCopied; + constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks; + new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); move_table.emplace(def_method, &new_method); ++out; } @@ -6489,7 +6527,7 @@ bool ClassLinker::LinkInterfaceMethods( // this as a default, non-abstract method, since thats what it is. Also clear the // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have // methods that are skipping access checks. - constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict; + constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied; constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks); new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); DCHECK(new_method.IsDefaultConflicting()); @@ -7633,6 +7671,118 @@ void ClassLinker::CleanupClassLoaders() { } } +std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { + ScopedTrace trace(__PRETTY_FUNCTION__); + ScopedObjectAccess soa(Thread::Current()); + ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__); + std::set<DexCacheResolvedClasses> ret; + VLOG(class_linker) << "Collecting resolved classes"; + const uint64_t start_time = NanoTime(); + ReaderMutexLock mu(soa.Self(), *DexLock()); + // Loop through all the dex caches and inspect resolved classes. + for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { + if (soa.Self()->IsJWeakCleared(data.weak_root)) { + continue; + } + mirror::DexCache* dex_cache = + down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root)); + if (dex_cache == nullptr) { + continue; + } + const DexFile* dex_file = dex_cache->GetDexFile(); + const std::string& location = dex_file->GetLocation(); + const size_t num_class_defs = dex_file->NumClassDefs(); + // Use the resolved types, this will miss array classes. + const size_t num_types = dex_file->NumTypeIds(); + VLOG(class_linker) << "Collecting class profile for dex file " << location + << " types=" << num_types << " class_defs=" << num_class_defs; + DexCacheResolvedClasses resolved_classes(dex_file->GetLocation(), + dex_file->GetLocationChecksum()); + size_t num_resolved = 0; + std::unordered_set<uint16_t> class_set; + CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); + for (size_t i = 0; i < num_types; ++i) { + mirror::Class* klass = dex_cache->GetResolvedType(i); + // Filter out null class loader since that is the boot class loader. + if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) { + continue; + } + ++num_resolved; + DCHECK(!klass->IsProxyClass()); + DCHECK(klass->IsResolved()); + mirror::DexCache* klass_dex_cache = klass->GetDexCache(); + if (klass_dex_cache == dex_cache) { + const size_t class_def_idx = klass->GetDexClassDefIndex(); + DCHECK(klass->IsResolved()); + CHECK_LT(class_def_idx, num_class_defs); + class_set.insert(class_def_idx); + } + } + + if (!class_set.empty()) { + auto it = ret.find(resolved_classes); + if (it != ret.end()) { + // Already have the key, union the class def idxs. + it->AddClasses(class_set.begin(), class_set.end()); + } else { + resolved_classes.AddClasses(class_set.begin(), class_set.end()); + ret.insert(resolved_classes); + } + } + + VLOG(class_linker) << "Dex location " << location << " has " << num_resolved << " / " + << num_class_defs << " resolved classes"; + } + VLOG(class_linker) << "Collecting class profile took " << PrettyDuration(NanoTime() - start_time); + return ret; +} + +std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys( + const std::set<DexCacheResolvedClasses>& classes) { + ScopedTrace trace(__PRETTY_FUNCTION__); + std::unordered_set<std::string> ret; + Thread* const self = Thread::Current(); + std::unordered_map<std::string, const DexFile*> location_to_dex_file; + ScopedObjectAccess soa(self); + ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__); + ReaderMutexLock mu(self, *DexLock()); + for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { + if (!self->IsJWeakCleared(data.weak_root)) { + mirror::DexCache* dex_cache = + down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root)); + if (dex_cache != nullptr) { + const DexFile* dex_file = dex_cache->GetDexFile(); + // There could be duplicates if two dex files with the same location are mapped. + location_to_dex_file.emplace( + ProfileCompilationInfo::GetProfileDexFileKey(dex_file->GetLocation()), dex_file); + } + } + } + for (const DexCacheResolvedClasses& info : classes) { + const std::string& profile_key = info.GetDexLocation(); + auto found = location_to_dex_file.find(profile_key); + if (found != location_to_dex_file.end()) { + const DexFile* dex_file = found->second; + VLOG(profiler) << "Found opened dex file for " << dex_file->GetLocation() << " with " + << info.GetClasses().size() << " classes"; + DCHECK_EQ(dex_file->GetLocationChecksum(), info.GetLocationChecksum()); + for (uint16_t class_def_idx : info.GetClasses()) { + if (class_def_idx >= dex_file->NumClassDefs()) { + LOG(WARNING) << "Class def index " << class_def_idx << " >= " << dex_file->NumClassDefs(); + continue; + } + const DexFile::TypeId& type_id = dex_file->GetTypeId( + dex_file->GetClassDef(class_def_idx).class_idx_); + const char* descriptor = dex_file->GetTypeDescriptor(type_id); + ret.insert(descriptor); + } + } else { + VLOG(class_linker) << "Failed to find opened dex file for profile key " << profile_key; + } + } + return ret; +} + // Instantiate ResolveMethod. template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kForceICCECheck>( const DexFile& dex_file, |