ART: Faster type check bitstring initialization.

Reuse depth from recursive call instead of calculating it
repeatedly at every level of recursion. Pass pointers by
value instead of reference.

Test: m test-art-host-gtest
Test: testrunner.py --host --jit
Bug: 70734806
Change-Id: Idd405a2c3b04adbfd544639358dc562b32e4c34f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 192517f..727dd14 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -462,10 +462,8 @@
     //
     // We take the lock here to avoid using NO_THREAD_SAFETY_ANALYSIS.
     MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
-    mirror::Class* java_lang_Object_ptr = java_lang_Object.Get();
-    SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Object_ptr);
-    mirror::Class* java_lang_Class_ptr =  java_lang_Class.Get();
-    SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Class_ptr);
+    SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Object.Get());
+    SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Class.Get());
   }
 
   // Object[] next to hold class roots.
@@ -1872,8 +1870,7 @@
       ScopedTrace trace("Recalculate app image SubtypeCheck bitstrings");
       MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
       for (const ClassTable::TableSlot& root : temp_set) {
-        mirror::Class* root_klass = root.Read();
-        SubtypeCheck<mirror::Class*>::EnsureInitialized(root_klass);
+        SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(root.Read());
       }
     }
   }
@@ -5220,8 +5217,7 @@
   // or Overflowed (can be used as a source for IsSubClass check).
   {
     MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
-    ObjPtr<mirror::Class> c_ptr(c.Get());
-    SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c_ptr);
+    SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c.Get());
     // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck is already initialized.
   }
   const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 1556abe..54d2f00 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -216,12 +216,13 @@
  * All node targets (in `src <: target`) get Assigned, and any parent of an Initialized
  * node also gets Assigned.
  */
-struct MockSubtypeCheck;  // Forward declaration for testing.
 namespace art {
 
-// This is class is using a template parameter to enable testability without losing performance.
-// KlassT is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
-template <typename KlassT /* Pointer-like type to Class */>
+struct MockSubtypeCheck;  // Forward declaration for testing.
+
+// This class is using a template parameter to enable testability without losing performance.
+// ClassPtr is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
+template <typename ClassPtr /* Pointer-like type to Class */>
 struct SubtypeCheck {
   // Force this class's SubtypeCheckInfo state into at least Initialized.
   // As a side-effect, all parent classes also become Assigned|Overflowed.
@@ -230,7 +231,7 @@
   //
   // Post-condition: State is >= Initialized.
   // Returns: The precise SubtypeCheckInfo::State.
-  static SubtypeCheckInfo::State EnsureInitialized(KlassT& klass)
+  static SubtypeCheckInfo::State EnsureInitialized(ClassPtr klass)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return InitializeOrAssign(klass, /*assign*/false).GetState();
@@ -243,7 +244,7 @@
   //
   // Post-condition: State is Assigned|Overflowed.
   // Returns: The precise SubtypeCheckInfo::State.
-  static SubtypeCheckInfo::State EnsureAssigned(KlassT& klass)
+  static SubtypeCheckInfo::State EnsureAssigned(ClassPtr klass)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return InitializeOrAssign(klass, /*assign*/true).GetState();
@@ -258,7 +259,7 @@
   // Cost: O(1).
   //
   // Returns: A state that is always Uninitialized.
-  static SubtypeCheckInfo::State ForceUninitialize(KlassT& klass)
+  static SubtypeCheckInfo::State ForceUninitialize(ClassPtr klass)
     REQUIRES(Locks::subtype_check_lock_)
     REQUIRES_SHARED(Locks::mutator_lock_) {
     // Trying to do this in a real runtime will break thread safety invariants
@@ -288,7 +289,7 @@
   // Cost: O(Depth(Class)).
   //
   // Returns the encoded_src value. Must be >= Initialized (EnsureInitialized).
-  static BitString::StorageType GetEncodedPathToRootForSource(const KlassT& klass)
+  static BitString::StorageType GetEncodedPathToRootForSource(ClassPtr klass)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK_NE(SubtypeCheckInfo::kUninitialized, GetSubtypeCheckInfo(klass).GetState());
@@ -301,7 +302,7 @@
   // Cost: O(Depth(Class)).
   //
   // Returns the encoded_target value. Must be Assigned (EnsureAssigned).
-  static BitString::StorageType GetEncodedPathToRootForTarget(const KlassT& klass)
+  static BitString::StorageType GetEncodedPathToRootForTarget(ClassPtr klass)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -314,7 +315,7 @@
   // Cost: O(Depth(Class)).
   //
   // Returns the mask_target value. Must be Assigned (EnsureAssigned).
-  static BitString::StorageType GetEncodedPathToRootMask(const KlassT& klass)
+  static BitString::StorageType GetEncodedPathToRootMask(ClassPtr klass)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -333,7 +334,7 @@
   // Runtime cost: O(Depth(Class)), but would be O(1) if depth was known.
   //
   // If the result is known, return kSubtypeOf or kNotSubtypeOf.
-  static SubtypeCheckInfo::Result IsSubtypeOf(const KlassT& source, const KlassT& target)
+  static SubtypeCheckInfo::Result IsSubtypeOf(ClassPtr source, ClassPtr target)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     SubtypeCheckInfo sci = GetSubtypeCheckInfo(source);
     SubtypeCheckInfo target_sci = GetSubtypeCheckInfo(target);
@@ -342,24 +343,24 @@
   }
 
   // Print SubtypeCheck bitstring and overflow to a stream (e.g. for oatdump).
-  static std::ostream& Dump(const KlassT& klass, std::ostream& os)
+  static std::ostream& Dump(ClassPtr klass, std::ostream& os)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return os << GetSubtypeCheckInfo(klass);
   }
 
-  static void WriteStatus(const KlassT& klass, ClassStatus status)
+  static void WriteStatus(ClassPtr klass, ClassStatus status)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     WriteStatusImpl(klass, status);
   }
 
  private:
-  static KlassT GetParentClass(const KlassT& klass)
+  static ClassPtr GetParentClass(ClassPtr klass)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK(klass->HasSuperClass());
-    return KlassT(klass->GetSuperClass());
+    return ClassPtr(klass->GetSuperClass());
   }
 
-  static SubtypeCheckInfo InitializeOrAssign(KlassT& klass, bool assign)
+  static SubtypeCheckInfo InitializeOrAssign(ClassPtr klass, bool assign)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     if (UNLIKELY(!klass->HasSuperClass())) {
@@ -380,8 +381,8 @@
     }
 
     // Force all ancestors to Assigned | Overflowed.
-    KlassT parent_klass = GetParentClass(klass);
-    EnsureAssigned(parent_klass);
+    ClassPtr parent_klass = GetParentClass(klass);
+    size_t parent_depth = InitializeOrAssign(parent_klass, /*assign*/true).GetDepth();
     if (kIsDebugBuild) {
       SubtypeCheckInfo::State parent_state = GetSubtypeCheckInfo(parent_klass).GetState();
       DCHECK(parent_state == SubtypeCheckInfo::kAssigned ||
@@ -390,8 +391,8 @@
     }
 
     // Read.
-    SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass);
-    SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass);
+    SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass, parent_depth + 1u);
+    SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass, parent_depth);
 
     // Modify.
     const SubtypeCheckInfo::State sci_state = sci.GetState();
@@ -426,7 +427,7 @@
     return sci;
   }
 
-  static SubtypeCheckBitsAndStatus ReadField(const KlassT& klass)
+  static SubtypeCheckBitsAndStatus ReadField(ClassPtr klass)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     SubtypeCheckBitsAndStatus current_bits_and_status;
 
@@ -441,7 +442,7 @@
     return current_bits_and_status;
   }
 
-  static void WriteSubtypeCheckBits(const KlassT& klass, const SubtypeCheckBits& new_bits)
+  static void WriteSubtypeCheckBits(ClassPtr klass, const SubtypeCheckBits& new_bits)
       REQUIRES(Locks::subtype_check_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Use a "CAS" to write the SubtypeCheckBits in the class.
@@ -490,7 +491,7 @@
     }
   }
 
-  static void WriteStatusImpl(const KlassT& klass, ClassStatus status)
+  static void WriteStatusImpl(ClassPtr klass, ClassStatus status)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Despite not having a lock annotation, this is done with mutual exclusion.
     // See Class::SetStatus for more details.
@@ -519,7 +520,7 @@
     }
   }
 
-  static bool CasFieldWeakSequentiallyConsistent32(const KlassT& klass,
+  static bool CasFieldWeakSequentiallyConsistent32(ClassPtr klass,
                                                    MemberOffset offset,
                                                    int32_t old_value,
                                                    int32_t new_value)
@@ -541,18 +542,23 @@
   // it also requires calling klass->Depth.
   //
   // Anything calling this function will also be O(Depth(Class)).
-  static SubtypeCheckInfo GetSubtypeCheckInfo(const KlassT& klass)
+  static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass)
         REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetSubtypeCheckInfo(klass, klass->Depth());
+  }
+
+  // Get the SubtypeCheckInfo for a klass with known depth.
+  static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass, size_t depth)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
+    DCHECK_EQ(depth, klass->Depth());
     SubtypeCheckBitsAndStatus current_bits_and_status = ReadField(klass);
 
-    size_t depth = klass->Depth();
     const SubtypeCheckInfo current =
         SubtypeCheckInfo::Create(current_bits_and_status.subtype_check_info_, depth);
     return current;
   }
 
-  static void SetSubtypeCheckInfo(KlassT& klass,
-                                  const SubtypeCheckInfo& new_sci)
+  static void SetSubtypeCheckInfo(ClassPtr klass, const SubtypeCheckInfo& new_sci)
         REQUIRES(Locks::subtype_check_lock_)
         REQUIRES_SHARED(Locks::mutator_lock_) {
     SubtypeCheckBits new_bits = new_sci.GetSubtypeCheckBits();
@@ -565,7 +571,7 @@
   SubtypeCheck(SubtypeCheck&& other) = default;
   ~SubtypeCheck() = default;
 
-  friend struct ::MockSubtypeCheck;
+  friend struct MockSubtypeCheck;
 };
 
 }  // namespace art
diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h
index 8320fb3..61d590b 100644
--- a/runtime/subtype_check_info.h
+++ b/runtime/subtype_check_info.h
@@ -138,6 +138,11 @@
     kSubtypeOf          // Enough data. src is a subchild of the target.
   };
 
+  // Get the raw depth.
+  size_t GetDepth() const {
+    return depth_;
+  }
+
   // Chop off the depth, returning only the bitstring+of state.
   // (Used to store into memory, since storing the depth would be redundant.)
   SubtypeCheckBits GetSubtypeCheckBits() const {
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index dd51c18..e297d0b 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -24,10 +24,6 @@
 constexpr size_t BitString::kBitSizeAtPosition[BitString::kCapacity];
 constexpr size_t BitString::kCapacity;
 
-};  // namespace art
-
-using namespace art;  // NOLINT
-
 struct MockClass {
   explicit MockClass(MockClass* parent, size_t x = 0, size_t y = 0) {
     parent_ = parent;
@@ -1061,3 +1057,5 @@
 }
 
 // TODO: add dcheck for child-parent invariants (e.g. child < parent.next) and death tests
+
+}  // namespace art