Fix PR22634 - std::allocator doesn't respect over-aligned types.

This patch fixes std::allocator, and more specifically, all users
of __libcpp_allocate and __libcpp_deallocate, to support over-aligned
types.

__libcpp_allocate/deallocate now take an alignment parameter, and when
the specified alignment is greater than that supported by malloc/new,
the aligned version of operator new is called (assuming it's available).

When aligned new isn't available, the old behavior has been kept, and the
alignment parameter is ignored.

This patch depends on recent changes to __builtin_operator_new/delete which
allow them to be used to call any regular new/delete operator. By using
__builtin_operator_new/delete when possible, the new/delete erasure optimization
is maintained.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@328180 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2018-03-22 04:42:56 +00:00
parent 256f187bc6
commit a831287399
9 changed files with 343 additions and 87 deletions

View File

@@ -15,39 +15,93 @@
#include <memory>
#include <cassert>
#include "test_macros.h"
#include "count_new.hpp"
int A_constructed = 0;
struct A
{
int data;
A() {++A_constructed;}
A(const A&) {++A_constructed;}
~A() {--A_constructed;}
#ifdef TEST_HAS_NO_ALIGNED_ALLOCATION
static const bool UsingAlignedNew = false;
#else
static const bool UsingAlignedNew = true;
#endif
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
static const size_t MaxAligned = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
#else
static const size_t MaxAligned = std::alignment_of<std::max_align_t>::value;
#endif
static const size_t OverAligned = MaxAligned * 2;
template <size_t Align>
struct TEST_ALIGNAS(Align) AlignedType {
char data;
static int constructed;
AlignedType() { ++constructed; }
AlignedType(AlignedType const&) { ++constructed; }
~AlignedType() { --constructed; }
};
template <size_t Align>
int AlignedType<Align>::constructed = 0;
int main()
{
globalMemCounter.reset();
std::allocator<A> a;
template <size_t Align>
void test_aligned() {
typedef AlignedType<Align> T;
T::constructed = 0;
globalMemCounter.reset();
std::allocator<T> a;
const bool IsOverAlignedType = Align > MaxAligned;
const bool ExpectAligned = IsOverAlignedType && UsingAlignedNew;
{
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);
assert(T::constructed == 0);
globalMemCounter.last_new_size = 0;
A* volatile ap = a.allocate(3);
globalMemCounter.last_new_align = 0;
T* volatile ap = a.allocate(3);
assert(globalMemCounter.checkOutstandingNewEq(1));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int)));
assert(A_constructed == 0);
assert(globalMemCounter.checkNewCalledEq(1));
assert(globalMemCounter.checkAlignedNewCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(T)));
assert(globalMemCounter.checkLastNewAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
globalMemCounter.last_delete_align = 0;
a.deallocate(ap, 3);
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);
assert(globalMemCounter.checkDeleteCalledEq(1));
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
}
globalMemCounter.reset();
{
globalMemCounter.last_new_size = 0;
A* volatile ap2 = a.allocate(3, (const void*)5);
globalMemCounter.last_new_align = 0;
T* volatile ap2 = a.allocate(11, (const void*)5);
assert(globalMemCounter.checkOutstandingNewEq(1));
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(int)));
assert(A_constructed == 0);
a.deallocate(ap2, 3);
assert(globalMemCounter.checkNewCalledEq(1));
assert(globalMemCounter.checkAlignedNewCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastNewSizeEq(11 * sizeof(T)));
assert(globalMemCounter.checkLastNewAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
globalMemCounter.last_delete_align = 0;
a.deallocate(ap2, 11);
assert(globalMemCounter.checkOutstandingNewEq(0));
assert(A_constructed == 0);
assert(globalMemCounter.checkDeleteCalledEq(1));
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
assert(T::constructed == 0);
}
}
int main() {
test_aligned<1>();
test_aligned<2>();
test_aligned<4>();
test_aligned<8>();
test_aligned<16>();
test_aligned<MaxAligned>();
test_aligned<OverAligned>();
test_aligned<OverAligned * 2>();
}