PR libstdc++/80285 optimize std::make_shared for -fno-rtti
authorJonathan Wakely <jwakely@redhat.com>
Thu, 11 May 2017 13:21:07 +0000 (14:21 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 11 May 2017 13:21:07 +0000 (14:21 +0100)
PR libstdc++/80285
* include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_ti): Define
function to get unique fake std::type_info reference.
(_Sp_counted_ptr_inplace::_M_get_deleter) [!__cpp_rtti]: Compare to
_S_ti() fake reference.
(__shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...)): Share
single implementation with or without RTTI enable.
[!__cpp_rtti]: Pass fake reference to _M_get_deleter.
* testsuite/20_util/shared_ptr/creation/alloc.cc: Change expected
allocation and deallocation counts.
* testsuite/20_util/shared_ptr/creation/single_allocation.cc: New.
* testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc:
New.

From-SVN: r247905

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/shared_ptr_base.h
libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc [new file with mode: 0644]

index e39cfecb84d8eb68abc724c68ad5af0d33e8c58c..298d35182e67ef5eaf89bbe81e5ee6c5a58dc24d 100644 (file)
@@ -1,3 +1,19 @@
+2017-05-11  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/80285
+       * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_ti): Define
+       function to get unique fake std::type_info reference.
+       (_Sp_counted_ptr_inplace::_M_get_deleter) [!__cpp_rtti]: Compare to
+       _S_ti() fake reference.
+       (__shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...)): Share
+       single implementation with or without RTTI enable.
+       [!__cpp_rtti]: Pass fake reference to _M_get_deleter.
+       * testsuite/20_util/shared_ptr/creation/alloc.cc: Change expected
+       allocation and deallocation counts.
+       * testsuite/20_util/shared_ptr/creation/single_allocation.cc: New.
+       * testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc:
+       New.
+
 2017-05-10  François Dumont  <fdumont@gcc.gnu.org>
 
        Bump version namespace.
index c32cd0f3cf09b725f6f62f94566c76c190b4cb6d..69185794a855afdf268527a88a102d48e15e798d 100644 (file)
@@ -68,6 +68,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #pragma GCC diagnostic pop
 #endif
 
+#if !__cpp_rtti
+  class type_info;
+#endif
+
  /**
    *  @brief  Exception possibly thrown by @c shared_ptr.
    *  @ingroup exceptions
@@ -498,7 +502,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // helpers for make_shared / allocate_shared
 
-  struct _Sp_make_shared_tag { };
+  struct _Sp_make_shared_tag
+  {
+#if !__cpp_rtti
+  private:
+    template<typename _Tp, _Lock_policy _Lp>
+      friend class __shared_ptr;
+    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
+      friend class _Sp_counted_ptr_inplace;
+
+    static const type_info&
+    _S_ti() noexcept
+    {
+      static constexpr _Sp_make_shared_tag __tag;
+      return reinterpret_cast<const type_info&>(__tag);
+    }
+#endif
+  };
 
   template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
     class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
@@ -551,8 +571,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
 #if __cpp_rtti
        if (__ti == typeid(_Sp_make_shared_tag))
-         return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
+#else
+       if (&__ti == &_Sp_make_shared_tag::_S_ti())
 #endif
+         return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
        return nullptr;
       }
 
@@ -1295,7 +1317,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const
        { return _M_refcount._M_less(__rhs._M_refcount); }
 
-#if __cpp_rtti
     protected:
       // This constructor is non-standard, it is used by allocate_shared.
       template<typename _Alloc, typename... _Args>
@@ -1306,43 +1327,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          // _M_ptr needs to point to the newly constructed object.
          // This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
+#if __cpp_rtti
          void* __p = _M_refcount._M_get_deleter(typeid(__tag));
-         _M_ptr = static_cast<_Tp*>(__p);
-         _M_enable_shared_from_this_with(_M_ptr);
-       }
 #else
-      template<typename _Alloc>
-        struct _Deleter
-        {
-          void operator()(typename _Alloc::value_type* __ptr)
-          {
-           __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
-           allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());
-          }
-          _Alloc _M_alloc;
-        };
-
-      template<typename _Alloc, typename... _Args>
-       __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
-                    _Args&&... __args)
-       : _M_ptr(), _M_refcount()
-       {
-         typedef typename allocator_traits<_Alloc>::template
-           rebind_traits<typename std::remove_cv<_Tp>::type> __traits;
-         _Deleter<typename __traits::allocator_type> __del = { __a };
-         auto __guard = std::__allocate_guarded(__del._M_alloc);
-         auto __ptr = __guard.get();
-         // _GLIBCXX_RESOLVE_LIB_DEFECTS
-         // 2070. allocate_shared should use allocator_traits<A>::construct
-         __traits::construct(__del._M_alloc, __ptr,
-                             std::forward<_Args>(__args)...);
-         __guard = nullptr;
-         __shared_count<_Lp> __count(__ptr, __del, __del._M_alloc);
-         _M_refcount._M_swap(__count);
-         _M_ptr = __ptr;
+         void* __p = _M_refcount._M_get_deleter(_Sp_make_shared_tag::_S_ti());
+#endif
+         _M_ptr = static_cast<_Tp*>(__p);
          _M_enable_shared_from_this_with(_M_ptr);
        }
-#endif
 
       template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
               typename... _Args>
index b17387f11bcf281742601a0ee6c9168f7a9d6c70..7e53e41a72fdc7caf8c1737a3490da75435a0247 100644 (file)
@@ -63,7 +63,7 @@ test01()
     VERIFY( p1.get() != 0 );
     VERIFY( p1.use_count() == 1 );
     VERIFY( A::ctor_count == 1 );
-    VERIFY( tracker_allocator_counter::get_allocation_count() > 0 );
+    VERIFY( tracker_allocator_counter::get_allocation_count() > sizeof(A) );
   }
   VERIFY( A::ctor_count == A::dtor_count );
   VERIFY( tracker_allocator_counter::get_allocation_count()
@@ -79,12 +79,12 @@ test02()
   
   p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1);
   VERIFY( A::ctor_count == 1 );
-  VERIFY( tracker_allocator_counter::get_allocation_count() > 0 );
+  VERIFY( tracker_allocator_counter::get_allocation_count() > sizeof(A) );
 
   p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1, 2.0);
   VERIFY( A::ctor_count == 2 );
   VERIFY( A::dtor_count == 1 );
-  VERIFY( tracker_allocator_counter::get_deallocation_count() > 0 );
+  VERIFY( tracker_allocator_counter::get_deallocation_count() > sizeof(A) );
 
   p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1, 2.0, '3');
   VERIFY( A::ctor_count == 3 );
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation.cc
new file mode 100644 (file)
index 0000000..51b6b1b
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { using other = Alloc<U>; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U>&) { }
+
+  T* allocate(std::size_t n)
+  {
+    ++counter;
+    return std::allocator<T>::allocate(n);
+  }
+};
+
+
+void
+test01()
+{
+  std::allocate_shared<int>(Alloc<int>());
+  VERIFY( counter == 1 );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc
new file mode 100644 (file)
index 0000000..ba94f3c
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-fno-rtti" }
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { using other = Alloc<U>; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U>&) { }
+
+  T* allocate(std::size_t n)
+  {
+    ++counter;
+    return std::allocator<T>::allocate(n);
+  }
+};
+
+
+void
+test01()
+{
+  std::allocate_shared<int>(Alloc<int>());
+  VERIFY( counter == 1 );
+}
+
+int
+main()
+{
+  test01();
+}