Define monotonic_buffer_resource members out-of-line

Message ID 20180807113133.GA2878@redhat.com
State New
Headers show
Series
  • Define monotonic_buffer_resource members out-of-line
Related show

Commit Message

Jonathan Wakely Aug. 7, 2018, 11:31 a.m.
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.

Tested powerpc64le-linux, committed to trunk.
commit 736856a34ec11bdf4a4019eccead58b5c6a6b0cc
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Aug 6 23:50:54 2018 +0100

    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.

Patch

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 36459e88b6a..593783da1aa 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -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;
 
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index b3f8f7d9477..bb4e31551e6 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -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;
   };
 
diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc
index dd418c1b1aa..c3ae2b69f71 100644
--- a/libstdc++-v3/src/c++17/memory_resource.cc
+++ b/libstdc++-v3/src/c++17/memory_resource.cc
@@ -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