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>
|
2018-08-05 François Dumont <fdumont@gcc.gnu.org>
|
||||||
|
|
||||||
* include/bits/stl_iterator.h: Fix comment.
|
* include/bits/stl_iterator.h: Fix comment.
|
||||||
|
|
|
||||||
|
|
@ -2043,6 +2043,8 @@ GLIBCXX_3.4.26 {
|
||||||
_ZNSt3pmr20null_memory_resourceEv;
|
_ZNSt3pmr20null_memory_resourceEv;
|
||||||
_ZNSt3pmr20get_default_resourceEv;
|
_ZNSt3pmr20get_default_resourceEv;
|
||||||
_ZNSt3pmr20set_default_resourceEPNS_15memory_resourceE;
|
_ZNSt3pmr20set_default_resourceEPNS_15memory_resourceE;
|
||||||
|
_ZNSt3pmr25monotonic_buffer_resource13_M_new_bufferE[jmy][jmy];
|
||||||
|
_ZNSt3pmr25monotonic_buffer_resource18_M_release_buffersEv;
|
||||||
|
|
||||||
} GLIBCXX_3.4.25;
|
} GLIBCXX_3.4.25;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -365,7 +365,8 @@ namespace pmr
|
||||||
void
|
void
|
||||||
release() noexcept
|
release() noexcept
|
||||||
{
|
{
|
||||||
_Chunk::release(_M_head, _M_upstream);
|
if (_M_head)
|
||||||
|
_M_release_buffers();
|
||||||
|
|
||||||
// reset to initial state at contruction:
|
// reset to initial state at contruction:
|
||||||
if ((_M_current_buf = _M_orig_buf))
|
if ((_M_current_buf = _M_orig_buf))
|
||||||
|
|
@ -392,19 +393,14 @@ namespace pmr
|
||||||
if (__bytes == 0)
|
if (__bytes == 0)
|
||||||
__bytes = 1; // Ensures we don't return the same pointer twice.
|
__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_new_buffer(__bytes, __alignment);
|
||||||
_M_avail -= __bytes;
|
__p = _M_current_buf;
|
||||||
return __p;
|
|
||||||
}
|
}
|
||||||
|
_M_current_buf = (char*)_M_current_buf + __bytes;
|
||||||
const size_t __n = std::max(__bytes, _M_next_bufsiz);
|
_M_avail -= __bytes;
|
||||||
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;
|
return __p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,6 +413,15 @@ namespace pmr
|
||||||
{ return this == &__other; }
|
{ return this == &__other; }
|
||||||
|
|
||||||
private:
|
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
|
static size_t
|
||||||
_S_next_bufsize(size_t __buffer_size) noexcept
|
_S_next_bufsize(size_t __buffer_size) noexcept
|
||||||
{
|
{
|
||||||
|
|
@ -437,68 +442,7 @@ namespace pmr
|
||||||
void* const _M_orig_buf = nullptr;
|
void* const _M_orig_buf = nullptr;
|
||||||
size_t const _M_orig_size = _M_next_bufsiz;
|
size_t const _M_orig_size = _M_next_bufsiz;
|
||||||
|
|
||||||
// Memory allocated by the upstream resource is managed in a linked list
|
class _Chunk;
|
||||||
// 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);
|
|
||||||
|
|
||||||
_Chunk* _M_head = nullptr;
|
_Chunk* _M_head = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,89 @@ namespace pmr
|
||||||
get_default_resource() noexcept
|
get_default_resource() noexcept
|
||||||
{ return default_res.obj.load(); }
|
{ 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
|
} // namespace pmr
|
||||||
_GLIBCXX_END_NAMESPACE_VERSION
|
_GLIBCXX_END_NAMESPACE_VERSION
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue