Commit 89535612 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[base] Add byte level CAS atomic op.

This replaces custom Release_CompareAndSwap implementation with a call
to compiler intrinsic / std:atomic, which is TSAN friendly.

Bug: chromium:694255
Change-Id: Iab67c8f5a3a2329b18030a70f3dbf3cb5530374e
Reviewed-on: https://chromium-review.googlesource.com/622431
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47469}
parent 87613860
......@@ -296,37 +296,12 @@ class AsAtomic8 {
template <typename T>
static T Release_CompareAndSwap(
T* byte_addr, typename std::remove_reference<T>::type old_value,
T* addr, typename std::remove_reference<T>::type old_value,
typename std::remove_reference<T>::type new_value) {
STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
// Since there is no byte level CAS, we use word level CAS. For that we
// need to find the word containing the byte and do a CAS loop that re-
// tries if unrelated bits of the word change concurrently.
const uintptr_t kAlignmentSize = sizeof(base::AtomicWord);
const uintptr_t kAlignmentMask = kAlignmentSize - 1;
uintptr_t word_addr =
reinterpret_cast<uintptr_t>(byte_addr) & ~kAlignmentMask;
uintptr_t byte_offset =
reinterpret_cast<uintptr_t>(byte_addr) & kAlignmentMask;
#if defined(V8_TARGET_BIG_ENDIAN)
uintptr_t byte_shift = (kAlignmentSize - 1 - byte_offset) * 8u;
#else
uintptr_t byte_shift = byte_offset * 8u;
#endif
uintptr_t byte_mask = static_cast<uintptr_t>(0xFFu) << byte_shift;
uintptr_t* addr = reinterpret_cast<uintptr_t*>(word_addr);
uintptr_t actual_word, new_word;
base::Atomic8 actual_byte;
do {
actual_word = base::AsAtomicWord::Relaxed_Load(addr);
actual_byte = to_storage_type((actual_word & byte_mask) >> byte_shift);
if (actual_byte != to_storage_type(old_value))
return to_return_type<T>(actual_byte);
uintptr_t new_byte = static_cast<uintptr_t>(new_value);
new_word = (actual_word & ~byte_mask) | (new_byte << byte_shift);
} while (base::AsAtomicWord::Release_CompareAndSwap(
addr, actual_word, new_word) != actual_word);
return old_value;
return to_return_type<T>(base::Release_CompareAndSwap(
to_storage_addr(addr), to_storage_type(old_value),
to_storage_type(new_value)));
}
private:
......
......@@ -32,6 +32,7 @@
#include <atomic>
#include "src/base/build_config.h"
#include "src/base/macros.h"
namespace v8 {
namespace base {
......@@ -78,6 +79,14 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
return old_value;
}
inline Atomic8 Release_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value,
Atomic8 new_value) {
bool result = __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELEASE, __ATOMIC_RELAXED);
USE(result); // Make gcc compiler happy.
return old_value;
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
......
......@@ -8,6 +8,7 @@
#include <atomic>
#include "src/base/build_config.h"
#include "src/base/macros.h"
namespace v8 {
namespace base {
......@@ -63,6 +64,15 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
return old_value;
}
inline Atomic8 Release_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value,
Atomic8 new_value) {
bool result = atomic_compare_exchange_strong_explicit(
helper::to_std_atomic(ptr), &old_value, new_value,
std::memory_order_release, std::memory_order_relaxed);
USE(result); // Make gcc compiler happy.
return old_value;
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 new_value) {
atomic_compare_exchange_strong_explicit(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment