Add implementation for Unsafe.compareAndExchangeLong
Bug: 365968691
Test: atest CtsLibcoreTestCases:libcore.jdk.internal.misc.UnsafeTest
Change-Id: Ia2af27d0fbaabd140cb24b57c36cf13a644aef2b
diff --git a/libartbase/base/atomic.h b/libartbase/base/atomic.h
index 91f1982..e68b277 100644
--- a/libartbase/base/atomic.h
+++ b/libartbase/base/atomic.h
@@ -105,6 +105,19 @@
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
}
+ // Atomically replace the value with desired_value if it matches the expected_value.
+ // Participates in total ordering of atomic operations.
+ // Returns the existing value before the exchange. In other words, if the returned value is the
+ // same as expected_value, as passed to this method, the exchange has completed successfully.
+ // Otherwise the value was left unchanged.
+ T CompareAndExchangeStrongSequentiallyConsistent(T expected_value, T desired_value) {
+ // compare_exchange_strong() modifies expected_value if the actual value found is different from
+ // what was expected. In other words expected_value is changed if compare_exchange_strong
+ // returns false.
+ this->compare_exchange_strong(expected_value, desired_value, std::memory_order_seq_cst);
+ return expected_value;
+ }
+
bool CompareAndSet(T expected_value,
T desired_value,
CASMode mode,
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 6a6f503..9e807d1 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -585,6 +585,23 @@
return success;
}
+template <bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline int64_t Object::CaeFieldStrongSequentiallyConsistent64(MemberOffset field_offset,
+ int64_t old_value,
+ int64_t new_value) {
+ VerifyTransaction<kTransactionActive, kCheckTransaction>();
+ Verify<kVerifyFlags>();
+ uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+ Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
+ int64_t found_value =
+ atomic_addr->CompareAndExchangeStrongSequentiallyConsistent(old_value, new_value);
+ if (kTransactionActive && found_value == old_value) {
+ Runtime::Current()->GetClassLinker()->RecordWriteField64(
+ this, field_offset, old_value, /*is_volatile=*/true);
+ }
+ return found_value;
+}
+
/*
* Returns a pointer to an object representing what the field points to, not an
* object representing the field.
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 97e218b..2b04a55 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -550,14 +550,22 @@
int64_t new_value)
REQUIRES_SHARED(Locks::mutator_lock_);
- template<bool kTransactionActive,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ template <bool kTransactionActive,
+ bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset,
int64_t old_value,
int64_t new_value)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template <bool kTransactionActive,
+ bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ int64_t CaeFieldStrongSequentiallyConsistent64(MemberOffset field_offset,
+ int64_t old_value,
+ int64_t new_value)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
template<bool kTransactionActive,
bool kCheckTransaction = true,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
diff --git a/runtime/native/jdk_internal_misc_Unsafe.cc b/runtime/native/jdk_internal_misc_Unsafe.cc
index ba64c81..4fe6ef4 100644
--- a/runtime/native/jdk_internal_misc_Unsafe.cc
+++ b/runtime/native/jdk_internal_misc_Unsafe.cc
@@ -84,6 +84,15 @@
return success ? JNI_TRUE : JNI_FALSE;
}
+static jlong Unsafe_compareAndExchangeLong(
+ JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong expectedValue, jlong newValue) {
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ // JNI must use non transactional mode.
+ return obj->CaeFieldStrongSequentiallyConsistent64<false>(
+ MemberOffset(offset), expectedValue, newValue);
+}
+
static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject obj, jobject javaObj, jlong offset,
jlong expectedValue, jlong newValue) {
// compareAndSetLong has the same semantics as compareAndSwapLong, except for
@@ -514,6 +523,7 @@
Unsafe, compareAndSwapObject, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z"),
FAST_NATIVE_METHOD(Unsafe, compareAndSetInt, "(Ljava/lang/Object;JII)Z"),
FAST_NATIVE_METHOD(Unsafe, compareAndSetLong, "(Ljava/lang/Object;JJJ)Z"),
+ FAST_NATIVE_METHOD(Unsafe, compareAndExchangeLong, "(Ljava/lang/Object;JJJ)J"),
FAST_NATIVE_METHOD(Unsafe,
compareAndSetReference,
"(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z"),