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 <jwak...@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.

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

Reply via email to