summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc344
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,