Smarter set intersection between app image and non boot image strings
If there are fewer non boot image strings in the runtime, iterate
over those strings instead of the set being newly added.
On AOSP, nonBootImageInternStrings is around 500.
Test: test-art-host
Bug: 116059983
Change-Id: I76b49f2090971cf593ba487889b35dfc1fa8cf13
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e3dfdb3..6a5e8b6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1495,18 +1495,44 @@
intern_table->AddImageStringsToTable(space, [&](InternTable::UnorderedSet& interns)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::intern_table_lock_) {
+ const size_t non_boot_image_strings = intern_table->CountInterns(
+ /*visit_boot_images=*/false,
+ /*visit_non_boot_images=*/true);
VLOG(image) << "AppImage:stringsInInternTableSize = " << interns.size();
- for (auto it = interns.begin(); it != interns.end(); ) {
- ObjPtr<mirror::String> string = it->Read();
- ObjPtr<mirror::String> existing = intern_table->LookupWeakLocked(string);
- if (existing == nullptr) {
- existing = intern_table->LookupStrongLocked(string);
+ VLOG(image) << "AppImage:nonBootImageInternStrings = " << non_boot_image_strings;
+ // Visit the smaller of the two sets to compute the intersection.
+ if (interns.size() < non_boot_image_strings) {
+ for (auto it = interns.begin(); it != interns.end(); ) {
+ ObjPtr<mirror::String> string = it->Read();
+ ObjPtr<mirror::String> existing = intern_table->LookupWeakLocked(string);
+ if (existing == nullptr) {
+ existing = intern_table->LookupStrongLocked(string);
+ }
+ if (existing != nullptr) {
+ intern_remap.Put(string.Ptr(), existing.Ptr());
+ it = interns.erase(it);
+ } else {
+ ++it;
+ }
}
- if (existing != nullptr) {
- intern_remap.Put(string.Ptr(), existing.Ptr());
- it = interns.erase(it);
- } else {
- ++it;
+ } else {
+ intern_table->VisitInterns([&](const GcRoot<mirror::String>& root)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::intern_table_lock_) {
+ auto it = interns.find(root);
+ if (it != interns.end()) {
+ ObjPtr<mirror::String> existing = root.Read();
+ intern_remap.Put(it->Read(), existing.Ptr());
+ it = interns.erase(it);
+ }
+ }, /*visit_boot_images=*/false, /*visit_non_boot_images=*/true);
+ }
+ // Sanity check to ensure correctness.
+ if (kIsDebugBuild) {
+ for (GcRoot<mirror::String>& root : interns) {
+ ObjPtr<mirror::String> string = root.Read();
+ CHECK(intern_table->LookupWeakLocked(string) == nullptr) << string->ToModifiedUtf8();
+ CHECK(intern_table->LookupStrongLocked(string) == nullptr) << string->ToModifiedUtf8();
}
}
});