Disable bitstring type check runtime hooks.

Introduce a build flag for the bitstring type check, put
runtime hooks behind the flag and set the flag to false.

Also add bitstring initialization for proxy classes, a test
and a benchmark for the type checks.

Test: m test-art-host-gtest
Test: testrunner.py --host --interpreter
Test: Repeat with kBitstringSubtypeCheckEnabled = true.
Bug: 73299705
Change-Id: Ibcd88a828c7addc0473d8c428818734f80226b19
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 800427d..c4b1bf8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -457,7 +457,7 @@
                                                          VoidFunctor()));
 
   // Initialize the SubtypeCheck bitstring for java.lang.Object and java.lang.Class.
-  {
+  if (kBitstringSubtypeCheckEnabled) {
     // It might seem the lock here is unnecessary, however all the SubtypeCheck
     // functions are annotated to require locks all the way down.
     //
@@ -1856,7 +1856,7 @@
       visitor(root.Read());
     }
 
-    {
+    if (kBitstringSubtypeCheckEnabled) {
       // Every class in the app image has initially SubtypeCheckInfo in the
       // Uninitialized state.
       //
@@ -4484,6 +4484,14 @@
 
   Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass);
 
+  // SubtypeCheckInfo::Initialized must happen-before any new-instance for that type.
+  // See also ClassLinker::EnsureInitialized().
+  if (kBitstringSubtypeCheckEnabled) {
+    MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
+    SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(klass.Get());
+    // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck for j.l.r.Proxy is already assigned.
+  }
+
   {
     // Lock on klass is released. Lock new class object.
     ObjectLock<mirror::Class> initialization_lock(self, klass);
@@ -5231,7 +5239,7 @@
   // can be used as a source for the IsSubClass check, and that all ancestors
   // of the class are Assigned (can be used as a target for IsSubClass check)
   // or Overflowed (can be used as a source for IsSubClass check).
-  {
+  if (kBitstringSubtypeCheckEnabled) {
     MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
     SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c.Get());
     // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck is already initialized.
diff --git a/runtime/image.cc b/runtime/image.cc
index 8e3615f..9940622 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '4', '\0' };  // Math.pow() intrinsic.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '5', '\0' };  // Bitstring type check off.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 36388eb..86d538e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -550,7 +550,7 @@
     current = current->GetSuperClass();
   } while (current != nullptr);
 
-  if (kIsDebugBuild) {
+  if (kIsDebugBuild && kBitstringSubtypeCheckEnabled) {
     ObjPtr<mirror::Class> dis(this);
 
     SubtypeCheckInfo::Result sc_result = SubtypeCheck<ObjPtr<Class>>::IsSubtypeOf(dis, klass);
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 8a7defd..9246bae 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -156,9 +156,19 @@
     self->AssertPendingException();
   }
 
-  {
+  if (kBitstringSubtypeCheckEnabled) {
+    // FIXME: This looks broken with respect to aborted transactions.
     ObjPtr<mirror::Class> h_this_ptr = h_this.Get();
     SubtypeCheck<ObjPtr<mirror::Class>>::WriteStatus(h_this_ptr, new_status);
+  } else {
+    // The ClassStatus is always in the 4 most-significant bits of status_.
+    static_assert(sizeof(status_) == sizeof(uint32_t), "Size of status_ not equal to uint32");
+    uint32_t new_status_value = static_cast<uint32_t>(new_status) << (32 - kClassStatusBitSize);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      h_this->SetField32Volatile<true>(StatusOffset(), new_status_value);
+    } else {
+      h_this->SetField32Volatile<false>(StatusOffset(), new_status_value);
+    }
   }
 
   // Setting the object size alloc fast path needs to be after the status write so that if the
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index ced7c7c..b5deffb 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -81,7 +81,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
     // Avoid including "subtype_check_bits_and_status.h" to get the field.
-    // The ClassStatus is always in the 4 most-significant of status_.
+    // The ClassStatus is always in the 4 most-significant bits of status_.
     return enum_cast<ClassStatus>(
         static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) >> (32 - 4));
   }
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 54d2f00..3b1d5f8 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -24,6 +24,9 @@
 #include "mirror/class.h"
 #include "runtime.h"
 
+// Build flag for the bitstring subtype check runtime hooks.
+constexpr bool kBitstringSubtypeCheckEnabled = false;
+
 /**
  * Any node in a tree can have its path (from the root to the node) represented as a string by
  * concatenating the path of the parent to that of the current node.