Use strong CAS for identity hash code

Fixes an issue where the boot image was undeterministic when the
weak CAS supriously failed.

Bug: 70918261
Test: test-art-host
Change-Id: I30854d72955dae7224b4952d3c60b0ebf428c1c6
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index aeaa850..2988d06 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -39,7 +39,8 @@
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
 inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset,
-                                          int32_t old_value, int32_t new_value) {
+                                          int32_t old_value,
+                                          int32_t new_value) {
   if (kCheckTransaction) {
     DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
   }
@@ -55,10 +56,37 @@
   return atomic_addr->CompareAndSetWeakRelaxed(old_value, new_value);
 }
 
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongRelaxed32(MemberOffset field_offset,
+                                            int32_t old_value,
+                                            int32_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
+
+  return atomic_addr->CompareAndSetStrongRelaxed(old_value, new_value);
+}
+
 inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) {
   // Force use of non-transactional mode and do not check.
-  return CasFieldWeakRelaxed32<false, false>(
-      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
+  return CasFieldWeakRelaxed32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_),
+                                             old_val.GetValue(),
+                                             new_val.GetValue());
+}
+
+inline bool Object::CasLockWordStrongRelaxed(LockWord old_val, LockWord new_val) {
+  // Force use of non-transactional mode and do not check.
+  return CasFieldStrongRelaxed32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_),
+                                               old_val.GetValue(),
+                                               new_val.GetValue());
 }
 
 inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) {
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 4240e70..200bc47 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -197,7 +197,9 @@
         // loop iteration.
         LockWord hash_word = LockWord::FromHashCode(GenerateIdentityHashCode(), lw.GCState());
         DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode);
-        if (current_this->CasLockWordWeakRelaxed(lw, hash_word)) {
+        // Use a strong CAS to prevent spurious failures since these can make the boot image
+        // non-deterministic.
+        if (current_this->CasLockWordStrongRelaxed(lw, hash_word)) {
           return hash_word.GetHashCode();
         }
         break;
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index a89d632..f92ff1e 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -159,6 +159,8 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
   bool CasLockWordWeakRelease(LockWord old_val, LockWord new_val)
       REQUIRES_SHARED(Locks::mutator_lock_);
+  bool CasLockWordStrongRelaxed(LockWord old_val, LockWord new_val)
+      REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t GetLockOwnerThreadId();
 
   // Try to enter the monitor, returns non null if we succeeded.
@@ -539,6 +541,14 @@
   template<bool kTransactionActive,
            bool kCheckTransaction = true,
            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE bool CasFieldStrongRelaxed32(MemberOffset field_offset,
+                                             int32_t old_value,
+                                             int32_t new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive,
+           bool kCheckTransaction = true,
+           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ALWAYS_INLINE bool CasFieldWeakAcquire32(MemberOffset field_offset,
                                            int32_t old_value,
                                            int32_t new_value)
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 2c38de5..e723169 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -134,13 +134,15 @@
 }
 
 int32_t Monitor::GetHashCode() {
-  while (!HasHashCode()) {
-    if (hash_code_.CompareAndSetWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) {
-      break;
-    }
+  int32_t hc = hash_code_.load(std::memory_order_relaxed);
+  if (!HasHashCode()) {
+    // Use a strong CAS to prevent spurious failures since these can make the boot image
+    // non-deterministic.
+    hash_code_.CompareAndSetStrongRelaxed(0, mirror::Object::GenerateIdentityHashCode());
+    hc = hash_code_.load(std::memory_order_relaxed);
   }
   DCHECK(HasHashCode());
-  return hash_code_.load(std::memory_order_relaxed);
+  return hc;
 }
 
 bool Monitor::Install(Thread* self) {