Commit 2177f05a authored by Phil Willoughby's avatar Phil Willoughby Committed by Facebook Github Bot

Introduce folly::max_align_t and folly::max_align_v

Summary:
`folly::max_align_t` is a portable replacement for `std::max_align_t`.

`folly::max_align_v` is a `constexpr size_t` with the same value as `alignof(folly::max_align_t)`

32-bit iOS environments have `alignof(std::max_align_t) == 4`, which is not correct. This is more
correct in that I have not yet found a more-aligned basic type.

Reviewed By: yfeldblum

Differential Revision: D5442333

fbshipit-source-id: 0a93e48a730d65ef76e04f132b5976c93587b14c
parent 339c14d3
......@@ -18,6 +18,7 @@
#include <cstddef>
#include <folly/Portability.h>
#include <folly/concurrency/CacheLocality.h>
namespace folly {
......@@ -32,8 +33,8 @@ namespace folly {
template <typename T>
class CachelinePadded {
static_assert(
alignof(T) < CacheLocality::kFalseSharingRange,
"CachelinePadded does not support types aligned >= a cache-line.");
alignof(T) <= folly::max_align_v,
"CachelinePadded does not support over-aligned types.");
public:
template <typename... Args>
......
......@@ -142,9 +142,10 @@ struct FOLLY_ALIGNED_MAX SpinLockArray {
"Invalid size of PaddedSpinLock");
// Check if T can theoretically cross a cache line.
static_assert(alignof(std::max_align_t) > 0 &&
FOLLY_CACHE_LINE_SIZE % alignof(std::max_align_t) == 0 &&
sizeof(T) <= alignof(std::max_align_t),
static_assert(
folly::max_align_v > 0 &&
FOLLY_CACHE_LINE_SIZE % folly::max_align_v == 0 &&
sizeof(T) <= folly::max_align_v,
"T can cross cache line boundaries");
char padding_[FOLLY_CACHE_LINE_SIZE];
......
......@@ -19,6 +19,7 @@
#include <string.h>
#include <cstddef>
#include <type_traits>
#include <folly/portability/Config.h>
......@@ -31,7 +32,75 @@ constexpr bool kHasUnalignedAccess = true;
#else
constexpr bool kHasUnalignedAccess = false;
#endif
}
namespace detail {
template <typename I, I A, I... Bs>
struct integral_max
: std::integral_constant<
I,
(A > integral_max<I, Bs...>::value) ? A
: integral_max<I, Bs...>::value> {
};
template <typename I, size_t A>
struct integral_max<I, A> : std::integral_constant<I, A> {};
template <typename... Ts>
using max_alignment = integral_max<size_t, alignof(Ts)...>;
using max_basic_alignment = max_alignment<
std::max_align_t,
long double,
double,
float,
long long int,
long int,
int,
short int,
bool,
char,
char16_t,
char32_t,
wchar_t,
std::nullptr_t>;
} // namespace detail
constexpr size_t max_align_v = detail::max_basic_alignment::value;
// max_align_t is a type which is aligned at least as strictly as the
// most-aligned basic type (see the specification of std::max_align_t). This
// implementation exists because 32-bit iOS platforms have a broken
// std::max_align_t (see below).
//
// You should refer to this as `::folly::max_align_t` in portable code, even if
// you have `using namespace folly;` because C11 defines a global namespace
// `max_align_t` type.
//
// To be certain, we consider every non-void fundamental type specified by the
// standard. On most platforms `long double` would be enough, but iOS 32-bit
// has an 8-byte aligned `double` and `long long int` and a 4-byte aligned
// `long double`.
//
// So far we've covered locals and other non-allocated storage, but we also need
// confidence that allocated storage from `malloc`, `new`, etc will also be
// suitable for objects with this alignment reuirement.
//
// Apple document that their implementation of malloc will issue 16-byte
// granularity chunks for small allocations (large allocations are page-size
// granularity and page-aligned). We think that allocated storage will be
// suitable for these objects based on the following assumptions:
//
// 1. 16-byte granularity also means 16-byte aligned.
// 2. `new` and other allocators follow the `malloc` rules.
//
// We also have some anecdotal evidence: we don't see lots of misaligned-storage
// crashes on 32-bit iOS apps that use `double`.
//
// Apple's allocation reference: http://bit.ly/malloc-small
struct alignas(max_align_v) max_align_t {};
} // namespace folly
// compiler specific attribute translation
// msvc should come first, so if clang is in msvc mode it gets the right defines
......@@ -43,7 +112,7 @@ constexpr bool kHasUnalignedAccess = false;
#else
# error Cannot define FOLLY_ALIGNED on this platform
#endif
#define FOLLY_ALIGNED_MAX FOLLY_ALIGNED(alignof(std::max_align_t))
#define FOLLY_ALIGNED_MAX FOLLY_ALIGNED(::folly::max_align_v)
// NOTE: this will only do checking in msvc with versions that support /analyze
#if _MSC_VER
......
......@@ -257,9 +257,8 @@ void* SimpleAllocator::allocateHard() {
// Install a pointer to ourselves as the allocator.
*reinterpret_cast<SimpleAllocator**>(mem_) = this;
static_assert(
alignof(std::max_align_t) >= sizeof(SimpleAllocator*),
"alignment too small");
mem_ += std::min(sz_, alignof(std::max_align_t));
folly::max_align_v >= sizeof(SimpleAllocator*), "alignment too small");
mem_ += std::min(sz_, folly::max_align_v);
// New allocation.
auto mem = mem_;
......
......@@ -390,7 +390,7 @@ class SimpleAllocator {
if (intptr_t(mem_) % 128 == 0) {
// Avoid allocating pointers that may look like malloc
// pointers.
mem_ += std::min(sz_, alignof(std::max_align_t));
mem_ += std::min(sz_, folly::max_align_v);
}
if (mem_ && (mem_ + sz_ <= end_)) {
auto mem = mem_;
......
......@@ -22,7 +22,7 @@
/// std::pmr::memory_resource (C++17) as needed for developing a
/// hazptr prototype.
////////////////////////////////////////////////////////////////////////////////
#include <cstddef>
#include <folly/Portability.h>
#include <memory>
namespace folly {
......@@ -33,11 +33,11 @@ class memory_resource {
virtual ~memory_resource() = default;
virtual void* allocate(
const size_t bytes,
const size_t alignment = alignof(std::max_align_t)) = 0;
const size_t alignment = folly::max_align_v) = 0;
virtual void deallocate(
void* p,
const size_t bytes,
const size_t alignment = alignof(std::max_align_t)) = 0;
const size_t alignment = folly::max_align_v) = 0;
};
memory_resource* get_default_resource();
......@@ -70,7 +70,7 @@ inline memory_resource* new_delete_resource() {
public:
void* allocate(
const size_t bytes,
const size_t alignment = alignof(std::max_align_t)) override {
const size_t alignment = folly::max_align_v) override {
(void)alignment;
void* p = static_cast<void*>(new char[bytes]);
DEBUG_PRINT(this << " " << p << " " << bytes);
......@@ -79,7 +79,7 @@ inline memory_resource* new_delete_resource() {
void deallocate(
void* p,
const size_t bytes,
const size_t alignment = alignof(std::max_align_t)) override {
const size_t alignment = folly::max_align_v) override {
(void)alignment;
(void)bytes;
DEBUG_PRINT(p << " " << bytes);
......
......@@ -114,7 +114,7 @@ struct IOBuf::HeapFullStorage {
HeapStorage hs;
SharedInfo shared;
std::max_align_t align;
folly::max_align_t align;
};
IOBuf::SharedInfo::SharedInfo()
......
......@@ -67,7 +67,7 @@ using CachelinePaddedTypes = ::testing::Types<
SizedData<kCachelineSize / 2>,
SizedData<kCachelineSize + kCachelineSize / 2>,
// Mimic single basic types:
SizedDataMimic<std::max_align_t>,
SizedDataMimic<folly::max_align_t>,
SizedDataMimic<void*>,
SizedDataMimic<long double>,
SizedDataMimic<double>,
......@@ -78,7 +78,7 @@ using CachelinePaddedTypes = ::testing::Types<
SizedDataMimic<short>,
SizedDataMimic<char>,
// Mimic small arrays of basic types:
SizedDataMimic<std::max_align_t, 3>,
SizedDataMimic<folly::max_align_t, 3>,
SizedDataMimic<void*, 3>,
SizedDataMimic<long double, 3>,
SizedDataMimic<double, 3>,
......@@ -89,7 +89,7 @@ using CachelinePaddedTypes = ::testing::Types<
SizedDataMimic<short, 3>,
SizedDataMimic<char, 3>,
// Mimic large arrays of basic types:
SizedDataMimic<std::max_align_t, kCachelineSize + 3>,
SizedDataMimic<folly::max_align_t, kCachelineSize + 3>,
SizedDataMimic<void*, kCachelineSize + 3>,
SizedDataMimic<long double, kCachelineSize + 3>,
SizedDataMimic<double, kCachelineSize + 3>,
......
......@@ -92,7 +92,7 @@ void ArenaTester::merge(ArenaTester&& other) {
} // namespace
TEST(ThreadCachedArena, BlockSize) {
static const size_t alignment = alignof(std::max_align_t);
static const size_t alignment = folly::max_align_v;
static const size_t requestedBlockSize = 64;
ThreadCachedArena arena(requestedBlockSize);
......
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