Reduce calls to DescriptorEquals
Store the low 3 bits of the descriptor hash inside of class set
entries. Compare these bits before comparing descriptors.
Simpleperf interpret-only compile of facebook:
mirror::Class::DescriptorEquals(char const*): 3.66% -> 1.03%
Bug: 32641252
Test: test-art-host
Change-Id: I8d898d4ac7c95383c49401fbcd85bfde226e026c
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index 3e54a64..229cd47 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -26,8 +26,8 @@
void ClassTable::VisitRoots(Visitor& visitor) {
ReaderMutexLock mu(Thread::Current(), lock_);
for (ClassSet& class_set : classes_) {
- for (GcRoot<mirror::Class>& root : class_set) {
- visitor.VisitRoot(root.AddressWithoutBarrier());
+ for (TableSlot& table_slot : class_set) {
+ table_slot.VisitRoot(visitor);
}
}
for (GcRoot<mirror::Object>& root : strong_roots_) {
@@ -44,8 +44,8 @@
void ClassTable::VisitRoots(const Visitor& visitor) {
ReaderMutexLock mu(Thread::Current(), lock_);
for (ClassSet& class_set : classes_) {
- for (GcRoot<mirror::Class>& root : class_set) {
- visitor.VisitRoot(root.AddressWithoutBarrier());
+ for (TableSlot& table_slot : class_set) {
+ table_slot.VisitRoot(visitor);
}
}
for (GcRoot<mirror::Object>& root : strong_roots_) {
@@ -62,8 +62,8 @@
bool ClassTable::Visit(Visitor& visitor) {
ReaderMutexLock mu(Thread::Current(), lock_);
for (ClassSet& class_set : classes_) {
- for (GcRoot<mirror::Class>& root : class_set) {
- if (!visitor(root.Read())) {
+ for (TableSlot& table_slot : class_set) {
+ if (!visitor(table_slot.Read())) {
return false;
}
}
@@ -71,6 +71,51 @@
return true;
}
+template<ReadBarrierOption kReadBarrierOption>
+inline mirror::Class* ClassTable::TableSlot::Read() const {
+ const uint32_t before = data_.LoadRelaxed();
+ ObjPtr<mirror::Class> const before_ptr(ExtractPtr(before));
+ ObjPtr<mirror::Class> const after_ptr(
+ GcRoot<mirror::Class>(before_ptr).Read<kReadBarrierOption>());
+ if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
+ // If another thread raced and updated the reference, do not store the read barrier updated
+ // one.
+ data_.CompareExchangeStrongRelaxed(before, Encode(after_ptr, MaskHash(before)));
+ }
+ return after_ptr.Ptr();
+}
+
+template<typename Visitor>
+inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
+ const uint32_t before = data_.LoadRelaxed();
+ ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
+ GcRoot<mirror::Class> root(before_ptr);
+ visitor.VisitRoot(root.AddressWithoutBarrier());
+ ObjPtr<mirror::Class> after_ptr(root.Read<kWithoutReadBarrier>());
+ if (before_ptr != after_ptr) {
+ // If another thread raced and updated the reference, do not store the read barrier updated
+ // one.
+ data_.CompareExchangeStrongRelaxed(before, Encode(after_ptr, MaskHash(before)));
+ }
+}
+
+inline ObjPtr<mirror::Class> ClassTable::TableSlot::ExtractPtr(uint32_t data) {
+ return reinterpret_cast<mirror::Class*>(data & ~kHashMask);
+}
+
+inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) {
+ DCHECK_LE(hash_bits, kHashMask);
+ return reinterpret_cast<uintptr_t>(klass.Ptr()) | hash_bits;
+}
+
+inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash)
+ : data_(Encode(klass, MaskHash(descriptor_hash))) {
+ if (kIsDebugBuild) {
+ std::string temp;
+ const uint32_t hash = ComputeModifiedUtf8Hash(klass->GetDescriptor(&temp));
+ CHECK_EQ(descriptor_hash, hash);
+ }
+}
} // namespace art