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/gc_root.h b/runtime/gc_root.h
index 85cd0a4..b795409 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -267,6 +267,43 @@
   size_t buffer_pos_;
 };
 
+class UnbufferedRootVisitor {
+ public:
+  UnbufferedRootVisitor(RootVisitor* visitor, const RootInfo& root_info)
+      : visitor_(visitor), root_info_(root_info) {}
+
+  template <class MirrorType>
+  ALWAYS_INLINE void VisitRootIfNonNull(GcRoot<MirrorType>& root) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (!root.IsNull()) {
+      VisitRoot(root);
+    }
+  }
+
+  template <class MirrorType>
+  ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<MirrorType>* root) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (!root->IsNull()) {
+      VisitRoot(root);
+    }
+  }
+
+  template <class MirrorType>
+  void VisitRoot(GcRoot<MirrorType>& root) const REQUIRES_SHARED(Locks::mutator_lock_) {
+    VisitRoot(root.AddressWithoutBarrier());
+  }
+
+  template <class MirrorType>
+  void VisitRoot(mirror::CompressedReference<MirrorType>* root) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    visitor_->VisitRoots(&root, 1, root_info_);
+  }
+
+ private:
+  RootVisitor* const visitor_;
+  RootInfo root_info_;
+};
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_GC_ROOT_H_