Clean up `DexCacheData` records earlier.
Remove old `DexCacheData` entries while cleaning up class
loaders instead of delayed cleanup while registering a new
dex file.
`ClassLoader`s and `DexCache`s are closely tied together
and keep each other alive, so it is logical to clean up
their `ClassLinker` records together when unloaing.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 38383823
Change-Id: I170b1675cfefcefb4a4490072fb4aa93abb65015
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 44a72c5..4bccd55 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3885,34 +3885,30 @@
// dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk
CHECK_EQ(dex_cache_location, dex_file_suffix);
}
+
+ // Check if we need to initialize OatFile data (.data.bimg.rel.ro and .bss
+ // sections) needed for code execution.
const OatFile* oat_file =
(dex_file.GetOatDexFile() != nullptr) ? dex_file.GetOatDexFile()->GetOatFile() : nullptr;
- // Clean up pass to remove null dex caches; null dex caches can occur due to class unloading
- // and we are lazily removing null entries. Also check if we need to initialize OatFile data
- // (.data.bimg.rel.ro and .bss sections) needed for code execution.
bool initialize_oat_file_data = (oat_file != nullptr) && oat_file->IsExecutable();
- JavaVMExt* const vm = self->GetJniEnv()->GetVm();
- for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) {
- const DexCacheData& data = it->second;
- if (self->IsJWeakCleared(data.weak_root)) {
- vm->DeleteWeakGlobalRef(self, data.weak_root);
- it = dex_caches_.erase(it);
- } else {
- if (initialize_oat_file_data &&
- it->first->GetOatDexFile() != nullptr &&
- it->first->GetOatDexFile()->GetOatFile() == oat_file) {
+ if (initialize_oat_file_data) {
+ for (const auto& entry : dex_caches_) {
+ if (!self->IsJWeakCleared(entry.second.weak_root) &&
+ entry.first->GetOatDexFile() != nullptr &&
+ entry.first->GetOatDexFile()->GetOatFile() == oat_file) {
initialize_oat_file_data = false; // Already initialized.
+ break;
}
- ++it;
}
}
if (initialize_oat_file_data) {
oat_file->InitializeRelocations();
}
+
// Let hiddenapi assign a domain to the newly registered dex file.
hiddenapi::InitializeDexFileDomain(dex_file, class_loader);
- jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache);
+ jweak dex_cache_jweak = self->GetJniEnv()->GetVm()->AddWeakGlobalRef(self, dex_cache);
DexCacheData data;
data.weak_root = dex_cache_jweak;
data.class_table = ClassTableForClassLoader(class_loader);
@@ -10326,6 +10322,23 @@
}
}
}
+ if (!to_delete.empty()) {
+ JavaVMExt* vm = self->GetJniEnv()->GetVm();
+ WriterMutexLock mu(self, *Locks::dex_lock_);
+ for (auto it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ) {
+ const DexCacheData& data = it->second;
+ if (self->DecodeJObject(data.weak_root) == nullptr) {
+ DCHECK(to_delete.end() != std::find_if(
+ to_delete.begin(),
+ to_delete.end(),
+ [&](const ClassLoaderData& cld) { return cld.class_table == data.class_table; }));
+ vm->DeleteWeakGlobalRef(self, data.weak_root);
+ it = dex_caches_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
for (ClassLoaderData& data : to_delete) {
// CHA unloading analysis and SingleImplementaion cleanups are required.
DeleteClassLoader(self, data, /*cleanup_cha=*/ true);