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) {