|
18 | 18 | #define SWIFT_RUNTIME_ATOMIC_H |
19 | 19 |
|
20 | 20 | #include "swift/Runtime/Config.h" |
| 21 | +#include "swift/Runtime/Heap.h" |
| 22 | + |
21 | 23 | #include <assert.h> |
22 | 24 | #include <atomic> |
23 | 25 | #if defined(_WIN64) |
|
44 | 46 | namespace swift { |
45 | 47 | namespace impl { |
46 | 48 |
|
| 49 | +// FIXME: why can we not use the definitions from Heap.h? It seems that we |
| 50 | +// would fail to collapse the structure down in that case and end up with size |
| 51 | +// differences. |
| 52 | +template <std::size_t Alignment_> |
| 53 | +struct requires_aligned_alloc { |
| 54 | +#if defined(__cpp_aligned_new) |
| 55 | + // If we have C++17 or newer we can use the alignment aware allocation |
| 56 | + // implicitly. |
| 57 | + static constexpr const bool value = false; |
| 58 | +#else |
| 59 | +#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) |
| 60 | + static constexpr const bool value = |
| 61 | + Alignment_ > std::alignment_of<std::max_align_t>::value && |
| 62 | + Alignment_ > __STDCPP_DEFAULT_NEW_ALIGNMENT__; |
| 63 | +#else |
| 64 | + static constexpr const bool value = |
| 65 | + Alignment_ > std::alignment_of<std::max_align_t>::value; |
| 66 | +#endif |
| 67 | +#endif |
| 68 | +}; |
| 69 | + |
| 70 | +template <std::size_t Alignment_, |
| 71 | + bool = requires_aligned_alloc<Alignment_>::value> |
| 72 | +struct aligned_alloc; |
| 73 | + |
| 74 | +template <std::size_t Alignment_> |
| 75 | +struct aligned_alloc<Alignment_, false> {}; |
| 76 | + |
| 77 | +template <std::size_t Alignment_> |
| 78 | +struct aligned_alloc<Alignment_, true> { |
| 79 | + [[nodiscard]] void *operator new(std::size_t size) noexcept { |
| 80 | +#if defined(_WIN32) |
| 81 | + return _aligned_malloc(size, Alignment_); |
| 82 | +#else |
| 83 | + static_assert(Alignment_ >= sizeof(void *), |
| 84 | + "posix_memalign requires minimal alignment of pointer"); |
| 85 | + void *ptr = nullptr; |
| 86 | + (void)posix_memalign(&ptr, Alignment_, size); |
| 87 | + return ptr; |
| 88 | +#endif |
| 89 | + } |
| 90 | + |
| 91 | + void operator delete(void *ptr) noexcept { |
| 92 | +#if defined(_WIN32) |
| 93 | + _aligned_free(ptr); |
| 94 | +#else |
| 95 | + free(ptr); |
| 96 | +#endif |
| 97 | + } |
| 98 | + |
| 99 | +#if defined(_WIN32) |
| 100 | + // FIXME: why is this even needed? This is not permitted as per the C++ |
| 101 | + // standrd new.delete.placement (§17.6.3.4). |
| 102 | + [[nodiscard]] void *operator new(std::size_t size, void *where) noexcept { |
| 103 | + return ::operator new(size, where); |
| 104 | + } |
| 105 | +#endif |
| 106 | +}; |
| 107 | + |
47 | 108 | /// The default implementation for swift::atomic<T>, which just wraps |
48 | 109 | /// std::atomic with minor differences. |
49 | 110 | /// |
50 | 111 | /// TODO: should we make this use non-atomic operations when the runtime |
51 | 112 | /// is single-threaded? |
52 | 113 | template <class Value, size_t Size = sizeof(Value)> |
53 | | -class alignas(Size) atomic_impl { |
| 114 | +class alignas(Size) atomic_impl : public aligned_alloc<Size> { |
54 | 115 | std::atomic<Value> value; |
55 | 116 | public: |
56 | 117 | constexpr atomic_impl(Value value) : value(value) {} |
|
0 commit comments