mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
4c9291262a
commit
ea2329d170
|
|
@ -1,3 +1,19 @@
|
|||
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,22 +393,17 @@ 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_new_buffer(__bytes, __alignment);
|
||||
__p = _M_current_buf;
|
||||
}
|
||||
_M_current_buf = (char*)_M_current_buf + __bytes;
|
||||
_M_avail -= __bytes;
|
||||
return __p;
|
||||
}
|
||||
|
||||
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;
|
||||
return __p;
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(void*, size_t, size_t) override
|
||||
{ }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue