AlignedAlloc<>: Use posix_memalloc() on MacOS While on MacOS aligned_alloc() is only available starting from 10.15, the posix_memalign() is available on older releases and can be used directly, instead of the current malloc()-based over-allocating solution. Bug: None Change-Id: I726aedc4b917dffc091698dbf7832a8f740c10f1 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/13720 Reviewed-by: Sylvain Defresne <sdefresne@chromium.org> Reviewed-by: Takuto Ikuta <tikuta@google.com> Commit-Queue: David Turner <digit@google.com>
diff --git a/src/util/aligned_alloc.h b/src/util/aligned_alloc.h index f5cf757..99ecd29 100644 --- a/src/util/aligned_alloc.h +++ b/src/util/aligned_alloc.h
@@ -13,17 +13,15 @@ #define IMPL_ALIGNED_ALLOC_CXX17 1 #define IMPL_ALIGNED_ALLOC_WIN32 2 -#define IMPL_ALIGNED_ALLOC_MALLOC 3 +#define IMPL_ALIGNED_ALLOC_POSIX 3 #ifndef IMPL_ALIGNED_ALLOC #ifdef _WIN32 #define IMPL_ALIGNED_ALLOC IMPL_ALIGNED_ALLOC_WIN32 -#elif defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ - __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 +#elif defined(__APPLE__) // Note that aligned_alloc() is only available at runtime starting from -// OSX 10.15, so use malloc() when compiling binaries that must run on older -// releases. -#define IMPL_ALIGNED_ALLOC IMPL_ALIGNED_ALLOC_MALLOC +// OSX 10.15, so use posix_memalign() instead which is more portable. +#define IMPL_ALIGNED_ALLOC IMPL_ALIGNED_ALLOC_POSIX #else #define IMPL_ALIGNED_ALLOC IMPL_ALIGNED_ALLOC_CXX17 #endif @@ -33,8 +31,8 @@ #include <malloc.h> // for _aligned_malloc() and _aligned_free() #endif -#if IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_MALLOC -#include "base/logging.h" // For DCHECK() +#if IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_POSIX +#include "base/logging.h" // for CHECK() #endif // AlignedAlloc<N> provides Alloc() and Free() methods that can be @@ -43,8 +41,8 @@ // // The implementation uses std::aligned_alloc() when it is available, // or uses fallbacks otherwise. On Win32, _aligned_malloc() and -// _aligned_free() are used, while for older MacOS releases, ::malloc() is -// used directly with a small trick. +// _aligned_free() are used, while for MacOS releases, ::posix_memaloc() +// is used. template <size_t ALIGNMENT> struct AlignedAlloc { static void* Alloc(size_t size) { @@ -52,35 +50,10 @@ "ALIGNMENT must be a power of 2"); #if IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_WIN32 return _aligned_malloc(size, ALIGNMENT); -#elif IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_MALLOC - if (ALIGNMENT <= sizeof(void*)) { - return ::malloc(size); - } else if (size == 0) { - return nullptr; - } else { - // Allocation size must be a multiple of ALIGNMENT - DCHECK((size % ALIGNMENT) == 0); - - // Allocate block and store its address just before just before the - // result's address, as in: - // ________________________________________ - // | | | | - // | | real_ptr | | - // |____|__________|________________________| - // - // ^ ^ - // real_ptr result - // - // Note that malloc() guarantees that results are aligned on sizeof(void*) - // if the allocation size if larger than sizeof(void*). Hence, only - // |ALIGNMENT - sizeof(void*)| extra bytes are required. - void* real_block = ::malloc(size + ALIGNMENT - sizeof(void*)); - auto addr = reinterpret_cast<uintptr_t>(real_block) + sizeof(void*); - uintptr_t padding = (ALIGNMENT - addr) % ALIGNMENT; - addr += padding; - reinterpret_cast<void**>(addr - sizeof(void*))[0] = real_block; - return reinterpret_cast<void*>(addr); - } +#elif IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_POSIX + void* ptr = nullptr; + CHECK(!posix_memalign(&ptr, ALIGNMENT, size)); + return ptr; #else // IMPL_ALIGNED_ALLOC_CXX17 return std::aligned_alloc(ALIGNMENT, size); #endif @@ -89,16 +62,8 @@ static void Free(void* block) { #if IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_WIN32 _aligned_free(block); -#elif IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_MALLOC - if (ALIGNMENT <= sizeof(void*)) { - ::free(block); - } else if (block) { - if (ALIGNMENT > sizeof(void*)) { - // Read address of real block just before the aligned block. - block = *(reinterpret_cast<void**>(block) - 1); - } - ::free(block); - } +#elif IMPL_ALIGNED_ALLOC == IMPL_ALIGNED_ALLOC_POSIX + return ::free(block); #else // Allocation came from std::aligned_alloc() return std::free(block);