Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions src/hotspot/share/runtime/atomic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#define SHARE_RUNTIME_ATOMIC_HPP

#include "cppstdlib/type_traits.hpp"
#include "metaprogramming/enableIf.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "runtime/atomicAccess.hpp"
#include "utilities/globalDefinitions.hpp"
Expand Down Expand Up @@ -89,8 +88,12 @@
// value will be initialized as if by translating the value that would be
// provided by default constructing an atomic type for the value type's
// decayed type.

// (3) Atomic pointers and atomic integers additionally provide
//
// (3) Constructors for all atomic types are constexpr, to ensure non-local
// atomic variables are constant initialized (C++17 6.6.2) when initialized
// with suitable arguments.
//
// (4) Atomic pointers and atomic integers additionally provide
//
// member functions:
// v.add_then_fetch(i [, o]) -> T
Expand All @@ -102,7 +105,7 @@
// type of i must be signed, or both must be unsigned. Atomic pointers perform
// element arithmetic.
//
// (4) Atomic integers additionally provide
// (5) Atomic integers additionally provide
//
// member functions:
// v.and_then_fetch(x [, o]) -> T
Expand All @@ -112,7 +115,7 @@
// v.fetch_then_or(x [, o]) -> T
// v.fetch_then_xor(x [, o]) -> T
//
// (5) Atomic pointers additionally provide
// (6) Atomic pointers additionally provide
//
// nested types:
// ElementType -> std::remove_pointer_t<T>
Expand Down Expand Up @@ -217,7 +220,7 @@ class AtomicImpl::CommonCore {
T volatile _value;

protected:
explicit CommonCore(T value) : _value(value) {}
explicit constexpr CommonCore(T value) : _value(value) {}
~CommonCore() = default;

T volatile* value_ptr() { return &_value; }
Expand Down Expand Up @@ -290,7 +293,7 @@ class AtomicImpl::SupportsArithmetic : public CommonCore<T> {
}

protected:
explicit SupportsArithmetic(T value) : CommonCore<T>(value) {}
explicit constexpr SupportsArithmetic(T value) : CommonCore<T>(value) {}
~SupportsArithmetic() = default;

public:
Expand Down Expand Up @@ -333,7 +336,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Integer>
: public SupportsArithmetic<T>
{
public:
explicit Atomic(T value = 0) : SupportsArithmetic<T>(value) {}
explicit constexpr Atomic(T value = 0) : SupportsArithmetic<T>(value) {}

NONCOPYABLE(Atomic);

Expand Down Expand Up @@ -373,7 +376,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Byte>
: public CommonCore<T>
{
public:
explicit Atomic(T value = 0) : CommonCore<T>(value) {}
explicit constexpr Atomic(T value = 0) : CommonCore<T>(value) {}

NONCOPYABLE(Atomic);

Expand All @@ -389,7 +392,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Pointer>
: public SupportsArithmetic<T>
{
public:
explicit Atomic(T value = nullptr) : SupportsArithmetic<T>(value) {}
explicit constexpr Atomic(T value = nullptr) : SupportsArithmetic<T>(value) {}

NONCOPYABLE(Atomic);

Expand All @@ -410,12 +413,21 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Translated> {

Atomic<Decayed> _value;

static Decayed decay(T x) { return Translator::decay(x); }
// The decay function and the constructors are constexpr so that a non-local
// atomic object constructed with constant arguments will be a constant
// initialization. One might ask why it's not a problem that some
// specializations of these functions are not constant expressions. The
// answer lies in C++17 10.1.5/6, along with us having *some* constexpr
// translator decay functions, constexpr ctors for some translated types,
// and constexpr ctors for some decayed types. Also, C++23 removes those
// restrictions on constexpr functions and ctors.

static constexpr Decayed decay(T x) { return Translator::decay(x); }
static T recover(Decayed x) { return Translator::recover(x); }

// Support for default construction via the default construction of _value.
struct UseDecayedCtor {};
explicit Atomic(UseDecayedCtor) : _value() {}
explicit constexpr Atomic(UseDecayedCtor) : _value() {}
using DefaultCtorSelect =
std::conditional_t<std::is_default_constructible_v<T>, T, UseDecayedCtor>;

Expand All @@ -424,9 +436,9 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Translated> {

// If T is default constructible, construct from a default constructed T.
// Otherwise, default construct the underlying Atomic<Decayed>.
Atomic() : Atomic(DefaultCtorSelect()) {}
constexpr Atomic() : Atomic(DefaultCtorSelect()) {}

explicit Atomic(T value) : _value(decay(value)) {}
explicit constexpr Atomic(T value) : _value(decay(value)) {}

NONCOPYABLE(Atomic);

Expand Down