Call strong CAS from unsafe. Add more CAS versions.
Adds a number of additional CAS versions. Calls the correct
one from sun.misc.unsafe, fixing a recently introduced bug.
Avoid unnecessary ordering constraint when installing hash code.
Change-Id: I7c09d0c95ceb2a549ec28ee34084198ab3107946
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 2db62f8..e3068b3 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -95,11 +95,11 @@
jint newValue = args[4];
bool success;
if (Runtime::Current()->IsActiveTransaction()) {
- success = obj->CasFieldWeakSequentiallyConsistent32<true>(MemberOffset(offset),
- expectedValue, newValue);
+ success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
+ expectedValue, newValue);
} else {
- success = obj->CasFieldWeakSequentiallyConsistent32<false>(MemberOffset(offset),
- expectedValue, newValue);
+ success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
+ expectedValue, newValue);
}
result->SetZ(success ? JNI_TRUE : JNI_FALSE);
} else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 089ef57..3a691ed 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -75,6 +75,12 @@
OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
}
+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());
+}
+
inline uint32_t Object::GetLockOwnerThreadId() {
return Monitor::GetLockOwnerThreadId(this);
}
@@ -443,6 +449,8 @@
SetField32<kTransactionActive, kCheckTransaction, kVerifyFlags, true>(field_offset, new_value);
}
+// TODO: Pass memory_order_ and strong/weak as arguments to avoid code duplication?
+
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
int32_t old_value, int32_t new_value) {
@@ -461,6 +469,42 @@
return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
}
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldWeakRelaxed32(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);
+ }
+ byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+ AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
+
+ return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistent32(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);
+ }
+ byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+ AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
+
+ return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+}
+
template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
inline int64_t Object::GetField64(MemberOffset field_offset) {
if (kVerifyFlags & kVerifyThis) {
@@ -526,6 +570,23 @@
return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
}
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset,
+ int64_t old_value, int64_t new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteField64(this, field_offset, old_value, true);
+ }
+ if (kVerifyFlags & kVerifyThis) {
+ VerifyObject(this);
+ }
+ byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+ Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
+ return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+}
+
template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption,
bool kIsVolatile>
inline T* Object::GetFieldObject(MemberOffset field_offset) {
@@ -644,6 +705,38 @@
return success;
}
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset,
+ Object* old_value, Object* new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kVerifyFlags & kVerifyThis) {
+ VerifyObject(this);
+ }
+ if (kVerifyFlags & kVerifyWrites) {
+ VerifyObject(new_value);
+ }
+ if (kVerifyFlags & kVerifyReads) {
+ VerifyObject(old_value);
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+ }
+ HeapReference<Object> old_ref(HeapReference<Object>::FromMirrorPtr(old_value));
+ HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_value));
+ byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+ Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+
+ bool success = atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_ref.reference_,
+ new_ref.reference_);
+
+ if (success) {
+ Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value);
+ }
+ return success;
+}
+
template<bool kVisitClass, bool kIsStatic, typename Visitor>
inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) {
if (LIKELY(ref_offsets != CLASS_WALK_SUPER)) {
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index e58091f..5f88d54 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -156,7 +156,7 @@
// loop iteration.
LockWord hash_word(LockWord::FromHashCode(GenerateIdentityHashCode()));
DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode);
- if (const_cast<Object*>(this)->CasLockWordWeakSequentiallyConsistent(lw, hash_word)) {
+ if (const_cast<Object*>(this)->CasLockWordWeakRelaxed(lw, hash_word)) {
return hash_word.GetHashCode();
}
break;
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index d29011a..bf952f2 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -99,19 +99,14 @@
return OFFSET_OF_OBJECT_MEMBER(Object, monitor_);
}
- // As volatile can be false if the mutators are suspended. This is an optimization since it
+ // As_volatile can be false if the mutators are suspended. This is an optimization since it
// avoids the barriers.
LockWord GetLockWord(bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetLockWord(LockWord new_val, bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // All Cas operations defined here have C++11 memory_order_seq_cst ordering
- // semantics: Preceding memory operations become visible to other threads
- // before the CAS, and subsequent operations become visible after the CAS.
- // The Cas operations defined here do not fail spuriously, i.e. they
- // have C++11 "strong" semantics.
- // TODO: In most, possibly all, cases, these assumptions are too strong.
- // Confirm and weaken the implementation.
bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint32_t GetLockOwnerThreadId();
mirror::Object* MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -231,6 +226,12 @@
Object* new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive, bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset, Object* old_value,
+ Object* new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset);
@@ -258,6 +259,18 @@
int32_t new_value) ALWAYS_INLINE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive, bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldWeakRelaxed32(MemberOffset field_offset, int32_t old_value,
+ int32_t new_value) ALWAYS_INLINE
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ template<bool kTransactionActive, bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset, int32_t old_value,
+ int32_t new_value) ALWAYS_INLINE
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
int64_t GetField64(MemberOffset field_offset) ALWAYS_INLINE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -283,6 +296,12 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<bool kTransactionActive, bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset, int64_t old_value,
+ int64_t new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ template<bool kTransactionActive, bool kCheckTransaction = true,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T>
void SetFieldPtr(MemberOffset field_offset, T new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 7cc4cac..65dece0 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -28,8 +28,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
// JNI must use non transactional mode.
- bool success = obj->CasFieldWeakSequentiallyConsistent32<false>(MemberOffset(offset),
- expectedValue, newValue);
+ bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
+ expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
@@ -38,8 +38,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
// JNI must use non transactional mode.
- bool success = obj->CasFieldWeakSequentiallyConsistent64<false>(MemberOffset(offset),
- expectedValue, newValue);
+ bool success = obj->CasFieldStrongSequentiallyConsistent64<false>(MemberOffset(offset),
+ expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
@@ -50,8 +50,8 @@
mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
// JNI must use non transactional mode.
- bool success = obj->CasFieldWeakSequentiallyConsistentObject<false>(MemberOffset(offset),
- expectedValue, newValue);
+ bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset),
+ expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}