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);