* [PATCH] PR libstdc++/80285 optimize std::make_shared for -fno-rtti
@ 2017-05-11 14:25 Jonathan Wakely
2017-05-16 13:19 ` Jonathan Wakely
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2017-05-11 14:25 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1264 bytes --]
std::make_shared didn't support embedding the object within the
shared_ptr bookkeeping structure when -fno-rtti was used. This was
because the trick I use for getting the address of the embedded
object relied on typeid, so without RTTI it just creating the object
separately on the heap.
This removes the alternative code path for -fno-rtti and simply forms
a fake std::type_info& reference using reinterpret_cast. This allows
us to embed the object and get its address without typeid, so we avoid
the second allocation even when -fno-rtti is used.
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.
Tested powerpc64le-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 9162 bytes --]
commit 868bd0876256d0f533614458360e5dfc5545388d
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu May 11 12:34:26 2017 +0100
PR libstdc++/80285 optimize std::make_shared for -fno-rtti
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.
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index c32cd0f..6918579 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -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));
+#else
+ 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);
}
-#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;
- _M_enable_shared_from_this_with(_M_ptr);
- }
-#endif
template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
typename... _Args>
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
index b17387f..7e53e41 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
@@ -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
index 0000000..51b6b1b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation.cc
@@ -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
index 0000000..ba94f3c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc
@@ -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();
+}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] PR libstdc++/80285 optimize std::make_shared for -fno-rtti
2017-05-11 14:25 [PATCH] PR libstdc++/80285 optimize std::make_shared for -fno-rtti Jonathan Wakely
@ 2017-05-16 13:19 ` Jonathan Wakely
0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2017-05-16 13:19 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]
On 11/05/17 15:19 +0100, Jonathan Wakely wrote:
>std::make_shared didn't support embedding the object within the
>shared_ptr bookkeeping structure when -fno-rtti was used. This was
>because the trick I use for getting the address of the embedded
>object relied on typeid, so without RTTI it just creating the object
>separately on the heap.
>
>This removes the alternative code path for -fno-rtti and simply forms
>a fake std::type_info& reference using reinterpret_cast. This allows
>us to embed the object and get its address without typeid, so we avoid
>the second allocation even when -fno-rtti is used.
>
> 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.
>
>Tested powerpc64le-linux, committed to trunk.
This fix is needed for gnu-versioned-namespace builds, because
std::type_info should not be declared inside the versioned namespace.
Tested x86_64-linux, comitted to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 982 bytes --]
commit e14f89bd9e529b3343c0b8c5fce3377394f6cbc7
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue May 16 14:13:40 2017 +0100
Fix forward declaration of std::type_info for versioned-namespace
PR libstdc++/80285
* include/bits/shared_ptr_base.h [!__cpp_rtti] (type_info): Declare
outside versioned namespace.
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index 6918579..b4a5edf 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -59,6 +59,10 @@
namespace std _GLIBCXX_VISIBILITY(default)
{
+#if !__cpp_rtti
+ class type_info;
+#endif
+
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#if _GLIBCXX_USE_DEPRECATED
@@ -68,10 +72,6 @@ _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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2017-05-16 13:16 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-11 14:25 [PATCH] PR libstdc++/80285 optimize std::make_shared for -fno-rtti Jonathan Wakely
2017-05-16 13:19 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).