Commit ea2329d1 by Jonathan Wakely Committed by Jonathan Wakely

Define monotonic_buffer_resource members out-of-line

Move the allocation logic into libstdc++.so so that it can be changed
without worrying about inlined code in existing binaries.

Leave do_allocate inline so that calls to it can be devirtualized, and
only the slow path needs to call into the library.

	* config/abi/pre/gnu.ver: Export monotonic_buffer_resource members.
	* include/std/memory_resource (monotonic_buffer_resource::release):
	Call _M_release_buffers to free buffers.
	(monotonic_buffer_resource::do_allocate): Call _M_new_buffer to
	allocate a new buffer from upstream.
	(monotonic_buffer_resource::_M_new_buffer): Declare.
	(monotonic_buffer_resource::_M_release_buffers): Declare.
	(monotonic_buffer_resource::_Chunk): Replace definition with
	declaration as opaque type.
	* src/c++17/memory_resource.cc (monotonic_buffer_resource::_Chunk):
	Define.
	(monotonic_buffer_resource::_M_new_buffer): Define.
	(monotonic_buffer_resource::_M_release_buffers): Define.

From-SVN: r263354
parent 4c929126
2018-08-07 Jonathan Wakely <jwakely@redhat.com>
* config/abi/pre/gnu.ver: Export monotonic_buffer_resource members.
* include/std/memory_resource (monotonic_buffer_resource::release):
Call _M_release_buffers to free buffers.
(monotonic_buffer_resource::do_allocate): Call _M_new_buffer to
allocate a new buffer from upstream.
(monotonic_buffer_resource::_M_new_buffer): Declare.
(monotonic_buffer_resource::_M_release_buffers): Declare.
(monotonic_buffer_resource::_Chunk): Replace definition with
declaration as opaque type.
* src/c++17/memory_resource.cc (monotonic_buffer_resource::_Chunk):
Define.
(monotonic_buffer_resource::_M_new_buffer): Define.
(monotonic_buffer_resource::_M_release_buffers): Define.
2018-08-05 François Dumont <fdumont@gcc.gnu.org>
* include/bits/stl_iterator.h: Fix comment.
......
......@@ -2043,6 +2043,8 @@ GLIBCXX_3.4.26 {
_ZNSt3pmr20null_memory_resourceEv;
_ZNSt3pmr20get_default_resourceEv;
_ZNSt3pmr20set_default_resourceEPNS_15memory_resourceE;
_ZNSt3pmr25monotonic_buffer_resource13_M_new_bufferE[jmy][jmy];
_ZNSt3pmr25monotonic_buffer_resource18_M_release_buffersEv;
} GLIBCXX_3.4.25;
......
......@@ -365,7 +365,8 @@ namespace pmr
void
release() noexcept
{
_Chunk::release(_M_head, _M_upstream);
if (_M_head)
_M_release_buffers();
// reset to initial state at contruction:
if ((_M_current_buf = _M_orig_buf))
......@@ -392,19 +393,14 @@ namespace pmr
if (__bytes == 0)
__bytes = 1; // Ensures we don't return the same pointer twice.
if (auto __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail))
void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
if (!__p)
{
_M_current_buf = (char*)_M_current_buf + __bytes;
_M_avail -= __bytes;
return __p;
_M_new_buffer(__bytes, __alignment);
__p = _M_current_buf;
}
const size_t __n = std::max(__bytes, _M_next_bufsiz);
const size_t __m = std::max(__alignment, alignof(std::max_align_t));
auto [__p, __size] = _Chunk::allocate(_M_upstream, __n, __m, _M_head);
_M_current_buf = (char*)__p + __bytes;
_M_avail = __size - __bytes;
_M_next_bufsiz *= _S_growth_factor;
_M_current_buf = (char*)_M_current_buf + __bytes;
_M_avail -= __bytes;
return __p;
}
......@@ -417,6 +413,15 @@ namespace pmr
{ return this == &__other; }
private:
// Update _M_current_buf and _M_avail to refer to a new buffer with
// at least the specified size and alignment, allocated from upstream.
void
_M_new_buffer(size_t __bytes, size_t __alignment);
// Deallocate all buffers obtained from upstream.
void
_M_release_buffers() noexcept;
static size_t
_S_next_bufsize(size_t __buffer_size) noexcept
{
......@@ -437,68 +442,7 @@ namespace pmr
void* const _M_orig_buf = nullptr;
size_t const _M_orig_size = _M_next_bufsiz;
// Memory allocated by the upstream resource is managed in a linked list
// of _Chunk objects. A _Chunk object recording the size and alignment of
// the allocated block and a pointer to the previous chunk is placed
// at end of the block.
class _Chunk
{
public:
// Return the address and size of a block of memory allocated from __r,
// of at least __size bytes and aligned to __align.
// Add a new _Chunk to the front of the linked list at __head.
static pair<void*, size_t>
allocate(memory_resource* __r, size_t __size, size_t __align,
_Chunk*& __head)
{
__size = std::__ceil2(__size + sizeof(_Chunk));
void* __p = __r->allocate(__size, __align);
// Add a chunk defined by (__p, __size, __align) to linked list __head.
void* const __back = (char*)__p + __size - sizeof(_Chunk);
__head = ::new(__back) _Chunk(__size, __align, __head);
return { __p, __size - sizeof(_Chunk) };
}
// Return every chunk in linked list __head to resource __r.
static void
release(_Chunk*& __head, memory_resource* __r) noexcept
{
_Chunk* __next = __head;
__head = nullptr;
while (__next)
{
_Chunk* __ch = __next;
__builtin_memcpy(&__next, __ch->_M_next, sizeof(_Chunk*));
__glibcxx_assert(__ch->_M_canary != 0);
__glibcxx_assert(__ch->_M_canary == (__ch->_M_size|__ch->_M_align));
if (__ch->_M_canary != (__ch->_M_size | __ch->_M_align))
return; // buffer overflow detected!
size_t __size = (1u << __ch->_M_size);
size_t __align = (1u << __ch->_M_align);
void* __start = (char*)(__ch + 1) - __size;
__r->deallocate(__start, __size, __align);
}
}
private:
_Chunk(size_t __size, size_t __align, _Chunk* __next) noexcept
: _M_size(std::__log2p1(__size) - 1),
_M_align(std::__log2p1(__align) - 1)
{
__builtin_memcpy(_M_next, &__next, sizeof(__next));
_M_canary = _M_size | _M_align;
}
unsigned char _M_canary;
unsigned char _M_size;
unsigned char _M_align;
unsigned char _M_next[sizeof(_Chunk*)];
};
static_assert(alignof(_Chunk) == 1);
class _Chunk;
_Chunk* _M_head = nullptr;
};
......
......@@ -104,6 +104,89 @@ namespace pmr
get_default_resource() noexcept
{ return default_res.obj.load(); }
// Member functions for std::pmr::monotonic_buffer_resource
// Memory allocated by the upstream resource is managed in a linked list
// of _Chunk objects. A _Chunk object recording the size and alignment of
// the allocated block and a pointer to the previous chunk is placed
// at end of the block.
class monotonic_buffer_resource::_Chunk
{
public:
// Return the address and size of a block of memory allocated from __r,
// of at least __size bytes and aligned to __align.
// Add a new _Chunk to the front of the linked list at __head.
static pair<void*, size_t>
allocate(memory_resource* __r, size_t __size, size_t __align,
_Chunk*& __head)
{
__size = std::__ceil2(__size + sizeof(_Chunk));
void* __p = __r->allocate(__size, __align);
// Add a chunk defined by (__p, __size, __align) to linked list __head.
void* const __back = (char*)__p + __size - sizeof(_Chunk);
__head = ::new(__back) _Chunk(__size, __align, __head);
return { __p, __size - sizeof(_Chunk) };
}
// Return every chunk in linked list __head to resource __r.
static void
release(_Chunk*& __head, memory_resource* __r) noexcept
{
_Chunk* __next = __head;
__head = nullptr;
while (__next)
{
_Chunk* __ch = __next;
__builtin_memcpy(&__next, __ch->_M_next, sizeof(_Chunk*));
__glibcxx_assert(__ch->_M_canary != 0);
__glibcxx_assert(__ch->_M_canary == (__ch->_M_size|__ch->_M_align));
if (__ch->_M_canary != (__ch->_M_size | __ch->_M_align))
return; // buffer overflow detected!
size_t __size = (1u << __ch->_M_size);
size_t __align = (1u << __ch->_M_align);
void* __start = (char*)(__ch + 1) - __size;
__r->deallocate(__start, __size, __align);
}
}
private:
_Chunk(size_t __size, size_t __align, _Chunk* __next) noexcept
: _M_size(std::__log2p1(__size) - 1),
_M_align(std::__log2p1(__align) - 1)
{
__builtin_memcpy(_M_next, &__next, sizeof(__next));
_M_canary = _M_size | _M_align;
}
unsigned char _M_canary;
unsigned char _M_size;
unsigned char _M_align;
unsigned char _M_next[sizeof(_Chunk*)];
};
void
monotonic_buffer_resource::_M_new_buffer(size_t bytes, size_t alignment)
{
// Need to check this somewhere, so put it here:
static_assert(alignof(monotonic_buffer_resource::_Chunk) == 1);
const size_t n = std::max(bytes, _M_next_bufsiz);
const size_t m = std::max(alignment, alignof(std::max_align_t));
auto [p, size] = _Chunk::allocate(_M_upstream, n, m, _M_head);
_M_current_buf = p;
_M_avail = size;
_M_next_bufsiz *= _S_growth_factor;
}
void
monotonic_buffer_resource::_M_release_buffers() noexcept
{
_Chunk::release(_M_head, _M_upstream);
}
} // namespace pmr
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment