PR libstdc++/70940 make pmr::resource_adaptor return aligned memory
PR libstdc++/70940 * include/experimental/memory_resource (__resource_adaptor_common): New base class. (__resource_adaptor_common::_AlignMgr): Helper for obtaining aligned pointer from unaligned, and vice versa. (__resource_adaptor_imp::do_allocate): Use _AlignMgr to adjust allocated pointer to meet alignment request. (__resource_adaptor_imp::do_deallocate): Use _AlignMgr to retrieve original pointer for deallocation. (__resource_adaptor_imp::do_is_equal): Reformat. (__resource_adaptor_imp::_S_aligned_size): Remove. (__resource_adaptor_imp::_S_supported): Remove. (new_delete_resource): Use __gnu_cxx::new_allocator. * testsuite/experimental/memory_resource/resource_adaptor.cc: Test extended alignments and use debug_allocator to check for matching allocate/deallocate pairs. From-SVN: r261849
This commit is contained in:
parent
67b3b8feb3
commit
7956c508dd
|
@ -1,3 +1,22 @@
|
|||
2018-06-21 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/70940
|
||||
* include/experimental/memory_resource (__resource_adaptor_common):
|
||||
New base class.
|
||||
(__resource_adaptor_common::_AlignMgr): Helper for obtaining aligned
|
||||
pointer from unaligned, and vice versa.
|
||||
(__resource_adaptor_imp::do_allocate): Use _AlignMgr to adjust
|
||||
allocated pointer to meet alignment request.
|
||||
(__resource_adaptor_imp::do_deallocate): Use _AlignMgr to retrieve
|
||||
original pointer for deallocation.
|
||||
(__resource_adaptor_imp::do_is_equal): Reformat.
|
||||
(__resource_adaptor_imp::_S_aligned_size): Remove.
|
||||
(__resource_adaptor_imp::_S_supported): Remove.
|
||||
(new_delete_resource): Use __gnu_cxx::new_allocator.
|
||||
* testsuite/experimental/memory_resource/resource_adaptor.cc: Test
|
||||
extended alignments and use debug_allocator to check for matching
|
||||
allocate/deallocate pairs.
|
||||
|
||||
2018-06-21 François Dumont <fdumont@gcc.gnu.org>
|
||||
|
||||
* include/debug/debug.h
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <new>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <ext/new_allocator.h>
|
||||
#include <experimental/bits/lfts_config.h>
|
||||
|
||||
namespace std {
|
||||
|
@ -253,9 +254,103 @@ namespace pmr {
|
|||
const polymorphic_allocator<_Tp2>& __b) noexcept
|
||||
{ return !(__a == __b); }
|
||||
|
||||
class __resource_adaptor_common
|
||||
{
|
||||
template<typename> friend class __resource_adaptor_imp;
|
||||
|
||||
struct _AlignMgr
|
||||
{
|
||||
_AlignMgr(size_t __nbytes, size_t __align)
|
||||
: _M_nbytes(__nbytes), _M_align(__align)
|
||||
{ }
|
||||
|
||||
// Total size that needs to be allocated.
|
||||
size_t
|
||||
_M_alloc_size() const { return _M_buf_size() + _M_token_size(); }
|
||||
|
||||
void*
|
||||
_M_adjust(void* __ptr) const
|
||||
{
|
||||
const auto __orig_ptr = static_cast<char*>(__ptr);
|
||||
size_t __space = _M_buf_size();
|
||||
// Align the pointer within the buffer:
|
||||
std::align(_M_align, _M_nbytes, __ptr, __space);
|
||||
const auto __aligned_ptr = static_cast<char*>(__ptr);
|
||||
const auto __token_size = _M_token_size();
|
||||
// Store token immediately after the aligned block:
|
||||
char* const __end = __aligned_ptr + _M_nbytes;
|
||||
if (__token_size == 1)
|
||||
_S_write<unsigned char>(__end, __aligned_ptr - __orig_ptr);
|
||||
else if (__token_size == sizeof(short))
|
||||
_S_write<unsigned short>(__end, __aligned_ptr - __orig_ptr);
|
||||
else if (__token_size == sizeof(int) && sizeof(int) < sizeof(char*))
|
||||
_S_write<unsigned int>(__end, __aligned_ptr - __orig_ptr);
|
||||
else // (__token_size == sizeof(char*))
|
||||
// Just store the original pointer:
|
||||
_S_write<char*>(__end, __orig_ptr);
|
||||
return __aligned_ptr;
|
||||
}
|
||||
|
||||
char*
|
||||
_M_unadjust(char* __ptr) const
|
||||
{
|
||||
const char* const __end = __ptr + _M_nbytes;
|
||||
char* __orig_ptr;
|
||||
const auto __token_size = _M_token_size();
|
||||
// Read the token and restore the original pointer:
|
||||
if (__token_size == 1)
|
||||
__orig_ptr = __ptr - _S_read<unsigned char>(__end);
|
||||
else if (__token_size == sizeof(short))
|
||||
__orig_ptr = __ptr - _S_read<unsigned short>(__end);
|
||||
else if (__token_size == sizeof(int)
|
||||
&& sizeof(int) < sizeof(char*))
|
||||
__orig_ptr = __ptr - _S_read<unsigned int>(__end);
|
||||
else // (__token_size == sizeof(char*))
|
||||
__orig_ptr = _S_read<char*>(__end);
|
||||
return __orig_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _M_nbytes;
|
||||
size_t _M_align;
|
||||
|
||||
// Number of bytes needed to fit block of given size and alignment.
|
||||
size_t
|
||||
_M_buf_size() const { return _M_nbytes + _M_align - 1; }
|
||||
|
||||
// Number of additional bytes needed to write the token.
|
||||
int
|
||||
_M_token_size() const
|
||||
{
|
||||
if (_M_align <= (1ul << __CHAR_BIT__))
|
||||
return 1;
|
||||
if (_M_align <= (1ul << (sizeof(short) * __CHAR_BIT__)))
|
||||
return sizeof(short);
|
||||
if (_M_align <= (1ul << (sizeof(int) * __CHAR_BIT__)))
|
||||
return sizeof(int);
|
||||
return sizeof(char*);
|
||||
}
|
||||
|
||||
template<typename _Tp>
|
||||
static void
|
||||
_S_write(void* __to, _Tp __val)
|
||||
{ __builtin_memcpy(__to, &__val, sizeof(_Tp)); }
|
||||
|
||||
template<typename _Tp>
|
||||
static _Tp
|
||||
_S_read(const void* __from)
|
||||
{
|
||||
_Tp __val;
|
||||
__builtin_memcpy(&__val, __from, sizeof(_Tp));
|
||||
return __val;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 8.7.1 __resource_adaptor_imp
|
||||
template <typename _Alloc>
|
||||
class __resource_adaptor_imp : public memory_resource
|
||||
class __resource_adaptor_imp
|
||||
: public memory_resource, private __resource_adaptor_common
|
||||
{
|
||||
static_assert(is_same<char,
|
||||
typename allocator_traits<_Alloc>::value_type>::value,
|
||||
|
@ -295,50 +390,41 @@ namespace pmr {
|
|||
|
||||
protected:
|
||||
virtual void*
|
||||
do_allocate(size_t __bytes, size_t __alignment)
|
||||
do_allocate(size_t __bytes, size_t __alignment) override
|
||||
{
|
||||
using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
|
||||
size_t __new_size = _S_aligned_size(__bytes,
|
||||
_S_supported(__alignment) ?
|
||||
__alignment : _S_max_align);
|
||||
return _Aligned_alloc(_M_alloc).allocate(__new_size);
|
||||
if (__alignment == 1)
|
||||
return _M_alloc.allocate(__bytes);
|
||||
|
||||
const _AlignMgr __mgr(__bytes, __alignment);
|
||||
// Assume _M_alloc returns 1-byte aligned memory, so allocate enough
|
||||
// space to fit a block of the right size and alignment, plus some
|
||||
// extra bytes to store a token for retrieving the original pointer.
|
||||
return __mgr._M_adjust(_M_alloc.allocate(__mgr._M_alloc_size()));
|
||||
}
|
||||
|
||||
virtual void
|
||||
do_deallocate(void* __p, size_t __bytes, size_t __alignment)
|
||||
do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept
|
||||
override
|
||||
{
|
||||
using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
|
||||
size_t __new_size = _S_aligned_size(__bytes,
|
||||
_S_supported(__alignment) ?
|
||||
__alignment : _S_max_align);
|
||||
using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer;
|
||||
_Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p),
|
||||
__new_size);
|
||||
auto __ptr = static_cast<char*>(__p);
|
||||
if (__alignment == 1)
|
||||
_M_alloc.deallocate(__ptr, __bytes);
|
||||
|
||||
const _AlignMgr __mgr(__bytes, __alignment);
|
||||
// Use the stored token to retrieve the original pointer to deallocate.
|
||||
_M_alloc.deallocate(__mgr._M_unadjust(__ptr), __mgr._M_alloc_size());
|
||||
}
|
||||
|
||||
virtual bool
|
||||
do_is_equal(const memory_resource& __other) const noexcept
|
||||
do_is_equal(const memory_resource& __other) const noexcept override
|
||||
{
|
||||
auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other);
|
||||
return __p ? (_M_alloc == __p->_M_alloc) : false;
|
||||
if (auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other))
|
||||
return _M_alloc == __p->_M_alloc;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// Calculate Aligned Size
|
||||
// Returns a size that is larger than or equal to __size and divisible
|
||||
// by __alignment, where __alignment is required to be a power of 2.
|
||||
static size_t
|
||||
_S_aligned_size(size_t __size, size_t __alignment)
|
||||
{ return ((__size - 1)|(__alignment - 1)) + 1; }
|
||||
|
||||
// Determine whether alignment meets one of those preconditions:
|
||||
// 1. Equal to Zero
|
||||
// 2. Is power of two
|
||||
static bool
|
||||
_S_supported (size_t __x)
|
||||
{ return ((__x != 0) && !(__x & (__x - 1))); }
|
||||
|
||||
_Alloc _M_alloc;
|
||||
_Alloc _M_alloc{};
|
||||
};
|
||||
|
||||
// Global memory resources
|
||||
|
@ -352,7 +438,7 @@ namespace pmr {
|
|||
inline memory_resource*
|
||||
new_delete_resource() noexcept
|
||||
{
|
||||
using type = resource_adaptor<std::allocator<char>>;
|
||||
using type = resource_adaptor<__gnu_cxx::new_allocator<char>>;
|
||||
alignas(type) static unsigned char __buf[sizeof(type)];
|
||||
static type* __r = new(__buf) type;
|
||||
return __r;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
#include <ext/debug_allocator.h>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_allocator.h>
|
||||
|
||||
|
@ -34,18 +35,22 @@ template<typename T>
|
|||
Allocator(const Allocator<U>&) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<std::size_t A>
|
||||
bool aligned(void* p)
|
||||
{
|
||||
return (reinterpret_cast<std::uintptr_t>(p) % alignof(T)) == 0;
|
||||
return (reinterpret_cast<std::uintptr_t>(p) % A) == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool aligned(void* p)
|
||||
{ return aligned<alignof(T)>(p); }
|
||||
|
||||
// resource_adaptor
|
||||
void
|
||||
test05()
|
||||
{
|
||||
using std::max_align_t;
|
||||
using std::uintptr_t;
|
||||
using std::size_t;
|
||||
void* p = nullptr;
|
||||
|
||||
Allocator<int> a1(1), a2(2); // minimal interface allocators
|
||||
|
@ -61,12 +66,18 @@ test05()
|
|||
p = r1.allocate(1, alignof(long));
|
||||
VERIFY( aligned<long>(p) );
|
||||
r1.deallocate(p, 1, alignof(long));
|
||||
constexpr size_t big_al = alignof(max_align_t) * 8;
|
||||
p = r1.allocate(1, big_al);
|
||||
VERIFY( aligned<big_al>(p) );
|
||||
r1.deallocate(p, 1, big_al);
|
||||
|
||||
__gnu_test::uneq_allocator<double> a3(3), a4(4); // non-equal allocators
|
||||
resource_adaptor<decltype(a3)> r3(a3), r4(a4);
|
||||
VERIFY( r3 == r3 );
|
||||
VERIFY( r4 == r4 );
|
||||
VERIFY( r3 != r4 );
|
||||
VERIFY( r3 != r1 );
|
||||
VERIFY( r3 != r2 );
|
||||
p = r3.allocate(1);
|
||||
VERIFY( aligned<max_align_t>(p) );
|
||||
r3.deallocate(p, 1);
|
||||
|
@ -76,9 +87,40 @@ test05()
|
|||
p = r3.allocate(1, alignof(long));
|
||||
VERIFY( aligned<long>(p) );
|
||||
r3.deallocate(p, 1, alignof(long));
|
||||
p = r3.allocate(1, big_al);
|
||||
VERIFY( aligned<big_al>(p) );
|
||||
r3.deallocate(p, 1, big_al);
|
||||
|
||||
// TODO test with an allocator that doesn't use new or malloc, so
|
||||
// returns pointers that are not suitably aligned for any type.
|
||||
__gnu_cxx::debug_allocator<std::allocator<short>> a5;
|
||||
resource_adaptor<decltype(a5)> r5(a5), r6(a5);
|
||||
VERIFY( r5 == r5 );
|
||||
VERIFY( r5 == r6 );
|
||||
VERIFY( r5 != r1 );
|
||||
VERIFY( r5 != r3 );
|
||||
p = r5.allocate(1);
|
||||
VERIFY( aligned<max_align_t>(p) );
|
||||
r5.deallocate(p, 1);
|
||||
p = r5.allocate(1, alignof(short));
|
||||
VERIFY( aligned<short>(p) );
|
||||
r5.deallocate(p, 1, alignof(short));
|
||||
p = r5.allocate(1, alignof(long));
|
||||
VERIFY( aligned<long>(p) );
|
||||
r5.deallocate(p, 1, alignof(long));
|
||||
p = r5.allocate(1, big_al);
|
||||
VERIFY( aligned<big_al>(p) );
|
||||
r5.deallocate(p, 1, big_al);
|
||||
|
||||
// Test extended alignments
|
||||
constexpr size_t al6 = (1ul << 6), al12 = (1ul << 12), al18 = (1ul << 18);
|
||||
p = r5.allocate(1024, al6);
|
||||
VERIFY( aligned<al6>(p) );
|
||||
r5.deallocate(p, 1024, al6);
|
||||
p = r5.allocate(1024, al12);
|
||||
VERIFY( aligned<al12>(p) );
|
||||
r5.deallocate(p, 1024, al12);
|
||||
p = r5.allocate(1024, al18);
|
||||
VERIFY( aligned<al18>(p) );
|
||||
r5.deallocate(p, 1024, al18);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
Loading…
Reference in New Issue