ALWAYS_INLINE inline size_t InternTable::StringHash::operator()(const GcRoot<mirror::String>& root) const {
ObjPtr<mirror::String> s = root.Read<kWithoutReadBarrier>();
int32_t hash = s->GetStoredHashCode();
DCHECK_EQ(hash, s->ComputeHashCode()); // An additional cast to prevent undesired sign extension. returnstatic_cast<uint32_t>(hash);
}
ALWAYS_INLINE inlinebool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a, const GcRoot<mirror::String>& b) const { return a.Read<kWithoutReadBarrier>()->Equals(b.Read<kWithoutReadBarrier>());
}
ALWAYS_INLINE inlinebool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a, const Utf8String& b) const {
ObjPtr<mirror::String> a_string = a.Read<kWithoutReadBarrier>();
uint32_t a_length = static_cast<uint32_t>(a_string->GetLength()); if (a_length != b.GetUtf16Length()) { returnfalse;
}
DCHECK_GE(strlen(b.GetUtf8Data()), a_length); if (a_string->IsCompressed()) { // Modified UTF-8 single byte character range is 0x01 .. 0x7f. // The string compression occurs on regular ASCII with same exact range, // not on extended ASCII which is up to 0xff. return b.GetUtf8Data()[a_length] == 0 &&
memcmp(b.GetUtf8Data(), a_string->GetValueCompressed(), a_length * sizeof(uint8_t)) == 0;
} elseif (mirror::kUseStringCompression && b.GetUtf8Data()[a_length] == 0) { // ASCII string `b` cannot equal non-ASCII `a_string`. returnfalse;
} else { const uint16_t* a_value = a_string->GetValue(); return CompareModifiedUtf8ToUtf16AsCodePointValues(b.GetUtf8Data(), a_value, a_length) == 0;
}
}
template <typename Visitor> inlinevoid InternTable::AddImageStringsToTable(gc::space::ImageSpace* image_space, const Visitor& visitor) {
DCHECK(image_space != nullptr); // Only add if we have the interned strings section. const ImageHeader& header = image_space->GetImageHeader(); const ImageSection& section = header.GetInternedStringsSection(); if (section.Size() > 0) {
AddTableFromMemory(image_space->Begin() + section.Offset(), visitor, !header.IsAppImage());
}
}
template <typename Visitor> inline size_t InternTable::AddTableFromMemory(const uint8_t* ptr, const Visitor& visitor, bool is_boot_image) {
size_t read_count = 0;
UnorderedSet set(ptr, /*make copy*/false, &read_count);
{ // Hold the lock while calling the visitor to prevent possible race // conditions with another thread adding intern strings.
MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); // Visit the unordered set, may remove elements.
visitor(set); if (!set.empty()) {
strong_interns_.AddInternStrings(std::move(set), is_boot_image);
}
} return read_count;
}
inlinevoid InternTable::Table::AddInternStrings(UnorderedSet&& intern_strings, bool is_boot_image) { if (kIsDebugBuild) { // Avoid doing read barriers since the space might not yet be added to the heap. // See b/117803941 for (GcRoot<mirror::String>& string : intern_strings) {
ObjPtr<mirror::String> s = string.Read<kWithoutReadBarrier>();
uint32_t hash = static_cast<uint32_t>(s->GetStoredHashCode());
CHECK_EQ(hash, static_cast<uint32_t>(s->ComputeHashCode()));
CHECK(Find(s, hash) == nullptr)
<< "Already found " << string.Read<kWithoutReadBarrier>()->ToModifiedUtf8()
<< " in the intern table";
}
}
// Insert before the last (unfrozen) table since we add new interns into the back. // Keep the order of previous frozen tables unchanged, so that we can can remember // the number of searched frozen tables and not search them again.
DCHECK(!tables_.empty());
tables_.insert(tables_.end() - 1, InternalTable(std::move(intern_strings), is_boot_image));
}
template <typename Visitor> inlinevoid InternTable::VisitInterns(const Visitor& visitor, bool visit_boot_images, bool visit_non_boot_images) { auto visit_tables = [&](dchecked_vector<Table::InternalTable>& tables)
NO_THREAD_SAFETY_ANALYSIS { for (Table::InternalTable& table : tables) { // Determine if we want to visit the table based on the flags. constbool visit = table.IsBootImage() ? visit_boot_images : visit_non_boot_images; if (visit) { for (auto& intern : table.set_) {
visitor(intern);
}
}
}
};
visit_tables(strong_interns_.tables_);
visit_tables(weak_interns_.tables_);
}
inline size_t InternTable::CountInterns(bool visit_boot_images, bool visit_non_boot_images) const {
size_t ret = 0u; auto visit_tables = [&](const dchecked_vector<Table::InternalTable>& tables)
NO_THREAD_SAFETY_ANALYSIS { for (const Table::InternalTable& table : tables) { // Determine if we want to visit the table based on the flags. constbool visit = table.IsBootImage() ? visit_boot_images : visit_non_boot_images; if (visit) {
ret += table.set_.size();
}
}
};
visit_tables(strong_interns_.tables_);
visit_tables(weak_interns_.tables_); return ret;
}
} // namespace art
#endif// ART_RUNTIME_INTERN_TABLE_INL_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.