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"),