From ace4c2f060160bd3ef9032cc151e36b84e4ba3e8 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 14 Oct 2016 13:03:47 +0100 Subject: [PATCH] PR65122 extended alignment support in allocators PR libstdc++/65122 * include/ext/malloc_allocator.h (malloc_allocator::allocate): Use aligned_alloc for types with extended alignment if available, otherwise throw bad_alloc if malloc doesn't return a suitable value. * include/ext/bitmap_allocator.h (bitmap_allocator::allocate) (bitmap_allocator::deallocate): Use aligned new/delete for types with extended alignment. * include/ext/mt_allocator.h (__mt_alloc::allocate) (__mt_alloc::deallocate): Likewise. * include/ext/new_allocator.h (new_allocator::allocate) (new_allocator::deallocate): Likewise. * include/ext/pool_allocator.h (__pool_alloc::allocate) (__pool_alloc::deallocate): Likewise. * testsuite/20_util/allocator/overaligned.cc: New test. * testsuite/ext/bitmap_allocator/overaligned.cc: New test. * testsuite/ext/malloc_allocator/overaligned.cc: New test. * testsuite/ext/mt_allocator/overaligned.cc: New test. * testsuite/ext/new_allocator/overaligned.cc: New test. * testsuite/ext/pool_allocator/overaligned.cc: New test. From-SVN: r241158 --- libstdc++-v3/ChangeLog | 25 ++++++- libstdc++-v3/include/ext/bitmap_allocator.h | 18 +++++ libstdc++-v3/include/ext/malloc_allocator.h | 25 ++++++- libstdc++-v3/include/ext/mt_allocator.h | 18 +++++ libstdc++-v3/include/ext/new_allocator.h | 18 ++++- libstdc++-v3/include/ext/pool_allocator.h | 18 ++++- .../20_util/allocator/overaligned.cc | 48 +++++++++++++ .../ext/bitmap_allocator/overaligned.cc | 48 +++++++++++++ .../ext/malloc_allocator/overaligned.cc | 68 +++++++++++++++++++ .../testsuite/ext/mt_allocator/overaligned.cc | 48 +++++++++++++ .../ext/new_allocator/overaligned.cc | 48 +++++++++++++ .../ext/pool_allocator/overaligned.cc | 48 +++++++++++++ 12 files changed, 426 insertions(+), 4 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/allocator/overaligned.cc create mode 100644 libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc create mode 100644 libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc create mode 100644 libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc create mode 100644 libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc create mode 100644 libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4a052f4dd53..a401ee0b84a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,7 +1,30 @@ +2016-10-14 Jonathan Wakely + + PR libstdc++/65122 + * include/ext/malloc_allocator.h (malloc_allocator::allocate): Use + aligned_alloc for types with extended alignment if available, + otherwise throw bad_alloc if malloc doesn't return a suitable value. + * include/ext/bitmap_allocator.h (bitmap_allocator::allocate) + (bitmap_allocator::deallocate): Use aligned new/delete for types with + extended alignment. + * include/ext/mt_allocator.h (__mt_alloc::allocate) + (__mt_alloc::deallocate): Likewise. + * include/ext/new_allocator.h (new_allocator::allocate) + (new_allocator::deallocate): Likewise. + * include/ext/pool_allocator.h (__pool_alloc::allocate) + (__pool_alloc::deallocate): Likewise. + * testsuite/20_util/allocator/overaligned.cc: New test. + * testsuite/ext/bitmap_allocator/overaligned.cc: New test. + * testsuite/ext/malloc_allocator/overaligned.cc: New test. + * testsuite/ext/mt_allocator/overaligned.cc: New test. + * testsuite/ext/new_allocator/overaligned.cc: New test. + * testsuite/ext/pool_allocator/overaligned.cc: New test. + 2016-10-14 Tim Shen PR libstdc++/77944 - * include/std/variant: include for __try and __catch. + * include/std/variant: Include for __try and + __catch. 2016-10-14 Jonathan Wakely diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h index c7fbd3e20c7..836abc8c530 100644 --- a/libstdc++-v3/include/ext/bitmap_allocator.h +++ b/libstdc++-v3/include/ext/bitmap_allocator.h @@ -1018,6 +1018,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__n > this->max_size()) std::__throw_bad_alloc(); +#if __cpp_aligned_new + if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + const size_type __b = __n * sizeof(value_type); + std::align_val_t __al = std::align_val_t(alignof(value_type)); + return static_cast(::operator new(__b, __al)); + } +#endif + if (__builtin_expect(__n == 1, true)) return this->_M_allocate_single_object(); else @@ -1036,6 +1045,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (__builtin_expect(__p != 0, true)) { +#if __cpp_aligned_new + // Types with extended alignment are handled by operator delete. + if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete(__p, std::align_val_t(alignof(value_type))); + return; + } +#endif + if (__builtin_expect(__n == 1, true)) this->_M_deallocate_single_object(__p); else diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h index 5c32eab70c3..acb60a2a3cf 100644 --- a/libstdc++-v3/include/ext/malloc_allocator.h +++ b/libstdc++-v3/include/ext/malloc_allocator.h @@ -30,6 +30,7 @@ #define _MALLOC_ALLOCATOR_H 1 #include +#include #include #include #include @@ -100,9 +101,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__n > this->max_size()) std::__throw_bad_alloc(); - pointer __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp))); + pointer __ret; +#if __cpp_aligned_new +#if __cplusplus > 201402L && _GLIBCXX_HAVE_ALIGNED_ALLOC + if (alignof(_Tp) > alignof(std::max_align_t)) + { + __ret = static_cast<_Tp*>(::aligned_alloc(alignof(_Tp), + __n * sizeof(_Tp))); + } +#else +# define _GLIBCXX_CHECK_MALLOC_RESULT +#endif +#endif + if (!__ret) + __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp))); if (!__ret) std::__throw_bad_alloc(); +#ifdef _GLIBCXX_CHECK_MALLOC_RESULT +#undef _GLIBCXX_CHECK_MALLOC_RESULT + if (reinterpret_cast(__ret) % alignof(_Tp)) + { + // Memory returned by malloc is not suitably aligned for _Tp. + deallocate(__ret, __n); + std::__throw_bad_alloc(); + } +#endif return __ret; } diff --git a/libstdc++-v3/include/ext/mt_allocator.h b/libstdc++-v3/include/ext/mt_allocator.h index 7016e489d41..d7ea7c1a8c3 100644 --- a/libstdc++-v3/include/ext/mt_allocator.h +++ b/libstdc++-v3/include/ext/mt_allocator.h @@ -691,6 +691,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__n > this->max_size()) std::__throw_bad_alloc(); +#if __cpp_aligned_new + // Types with extended alignment are handled by operator new/delete. + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + std::align_val_t __al = std::align_val_t(alignof(_Tp)); + return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al)); + } +#endif + __policy_type::_S_initialize_once(); // Requests larger than _M_max_bytes are handled by operator @@ -737,6 +746,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (__builtin_expect(__p != 0, true)) { +#if __cpp_aligned_new + // Types with extended alignment are handled by operator new/delete. + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete(__p, std::align_val_t(alignof(_Tp))); + return; + } +#endif + // Requests larger than _M_max_bytes are handled by // operators new/delete directly. __pool_type& __pool = __policy_type::_S_get_pool(); diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index dd00b7384aa..2ff4780f0e0 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -101,13 +101,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__n > this->max_size()) std::__throw_bad_alloc(); +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + std::align_val_t __al = std::align_val_t(alignof(_Tp)); + return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al)); + } +#endif return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); } // __p is not permitted to be a null pointer. void deallocate(pointer __p, size_type) - { ::operator delete(__p); } + { +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete(__p, std::align_val_t(alignof(_Tp))); + return; + } +#endif + ::operator delete(__p); + } size_type max_size() const _GLIBCXX_USE_NOEXCEPT diff --git a/libstdc++-v3/include/ext/pool_allocator.h b/libstdc++-v3/include/ext/pool_allocator.h index ee60e90166e..9e0511de19a 100644 --- a/libstdc++-v3/include/ext/pool_allocator.h +++ b/libstdc++-v3/include/ext/pool_allocator.h @@ -219,6 +219,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__n > this->max_size()) std::__throw_bad_alloc(); + const size_t __bytes = __n * sizeof(_Tp); + +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + std::align_val_t __al = std::align_val_t(alignof(_Tp)); + return static_cast<_Tp*>(::operator new(__bytes, __al)); + } +#endif + // If there is a race through here, assume answer from getenv // will resolve in same direction. Inspired by techniques // to efficiently support threading found in basic_string.h. @@ -230,7 +240,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_add_dispatch(&_S_force_new, -1); } - const size_t __bytes = __n * sizeof(_Tp); if (__bytes > size_t(_S_max_bytes) || _S_force_new > 0) __ret = static_cast<_Tp*>(::operator new(__bytes)); else @@ -259,6 +268,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (__builtin_expect(__n != 0 && __p != 0, true)) { +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete(__p, std::align_val_t(alignof(_Tp))); + return; + } +#endif const size_t __bytes = __n * sizeof(_Tp); if (__bytes > static_cast(_S_max_bytes) || _S_force_new > 0) ::operator delete(__p); diff --git a/libstdc++-v3/testsuite/20_util/allocator/overaligned.cc b/libstdc++-v3/testsuite/20_util/allocator/overaligned.cc new file mode 100644 index 00000000000..384d1d213c0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/overaligned.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 4; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + std::allocator a; + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc new file mode 100644 index 00000000000..7d365dec629 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 4; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + __gnu_cxx::bitmap_allocator a; + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc new file mode 100644 index 00000000000..87182f157a9 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 2; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + __gnu_cxx::malloc_allocator a; +#if __cplusplus > 201402L && _GLIBCXX_HAVE_ALIGNED_ALLOC + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +#else + // Allocating for extended alignment is unreliable without aligned_alloc() + try + { + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + } + catch (const std::bad_alloc&) + { } + try + { + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); + } + catch (const std::bad_alloc&) + { } +#endif +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc new file mode 100644 index 00000000000..41b8b46243c --- /dev/null +++ b/libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 4; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + __gnu_cxx::__mt_alloc a; + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc new file mode 100644 index 00000000000..27413cfb26d --- /dev/null +++ b/libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 4; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + __gnu_cxx::new_allocator a; + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc new file mode 100644 index 00000000000..b509b7958bb --- /dev/null +++ b/libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-faligned-new" } +// { dg-do run { target c++11 } } + +#include +#include +#include +#include + +constexpr std::size_t align = alignof(std::max_align_t) * 4; + +struct X { + alignas(align) char c; +}; + +void +test01() +{ + __gnu_cxx::__pool_alloc a; + X* p1 = a.allocate(1); + VERIFY( (reinterpret_cast(p1) % align) == 0 ); + a.deallocate(p1, 1); + X* p2 = a.allocate(20); + VERIFY( (reinterpret_cast(p2) % align) == 0 ); + a.deallocate(p2, 20); +} + +int +main() +{ + test01(); +} -- 2.30.2