This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH][WIP] libstdc++: Make certain exceptions transaction_safe.


On Wed, 2015-12-16 at 21:05 +0000, Jonathan Wakely wrote:
> Sorry for the delay finishing this review, some of the code kept
> melting my brain ;-)

I know what you mean :)  Thanks for the review!

> On 14/11/15 20:45 +0100, Torvald Riegel wrote:
> >diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
> >index 1b3184a..d902b03 100644
> >--- a/libstdc++-v3/config/abi/pre/gnu.ver
> >+++ b/libstdc++-v3/config/abi/pre/gnu.ver
> >@@ -1876,6 +1876,12 @@ GLIBCXX_3.4.22 {
> >     _ZNSt6thread6_StateD[012]Ev;
> >     _ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE;
> > 
> >+    # Support for the Transactional Memory TS (N4514)
> >+    _ZGTtNSt11logic_errorC1EPKc;
> >+    _ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
> >+    _ZGTtNKSt11logic_error4whatEv;
> >+    _ZGTtNSt11logic_errorD1Ev;
> >+
> > } GLIBCXX_3.4.21;
> 
> This is OK but ...
> 
> > # Symbols in the support library (libsupc++) have their own tag.
> >@@ -2107,6 +2113,12 @@ CXXABI_1.3.9 {
> >     # operator delete[](void*, std::size_t)
> >     _ZdaPv[jmy];
> > 
> >+    # Support for the Transactional Memory TS (N4514)
> >+    _ZGTtNKSt9exceptionD1Ev;
> >+    _ZGTtNKSt9exception4whatEv;
> >+    _ZGTtNKSt13bad_exceptionD1Ev;
> >+    _ZGTtNKSt13bad_exception4whatEv;
> >+
> > } CXXABI_1.3.8;
> 
> That symbol version was already used in the gcc-5 release and so is
> frozen, you'll need CXXABI_1.3.10 for these new symbols (similar to
> https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00258.html so if
> Catherine's already added that version you can just add them there).

Fixed.

> >diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
> >index 723feb1..0e66bb0 100644
> >--- a/libstdc++-v3/include/bits/c++config
> >+++ b/libstdc++-v3/include/bits/c++config
> >@@ -481,6 +481,17 @@ namespace std
> > # define _GLIBCXX_BEGIN_EXTERN_C extern "C" {
> > # define _GLIBCXX_END_EXTERN_C }
> > 
> >+// Conditionally enable annotations for the Transactional Memory TS on C++11.
> >+#if __cplusplus >= 201103L && \
> >+  _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_USE_DUAL_ABI && \
> 
> It's possible we can make this work for the old ABI too, but this is
> OK for now. The old ABI always uses COW strings, but that's what the
> code you've written deals with anyway.

OK.  I would have to write the wrappers for the new strings too then,
and I wanted to avoid that for now.

> >+  defined(__cpp_transactional_memory) && __cpp_transactional_memory >= 201505L
> 
> The defined(__cpp_transactional_memory) check is redundant, isn't it?
> 
> Users aren't allowed to define it, so it will either be defined to an
> integer value or undefined and evaluate to zero.

Won't we get an undefined warning when using -Wundef if we remove the
first part?  That's what I wanted to avoid.

> >+#define _GLIBCXX_TXN_SAFE transaction_safe
> >+#define _GLIBCXX_TXN_SAFE_DYN transaction_safe_dynamic
> >+#else
> >+#define _GLIBCXX_TXN_SAFE
> >+#define _GLIBCXX_TXN_SAFE_DYN
> >+#endif
> >+
> > #else // !__cplusplus
> > # define _GLIBCXX_BEGIN_EXTERN_C
> > # define _GLIBCXX_END_EXTERN_C
> 
> 
> >@@ -44,7 +46,36 @@ std::exception::what() const _GLIBCXX_USE_NOEXCEPT
> > }
> > 
> > const char* 
> >-std::bad_exception::what() const _GLIBCXX_USE_NOEXCEPT
> >+std::bad_exception::what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT
> > {
> >   return "std::bad_exception";
> > }
> >+
> >+// Transactional clones for the destructors and what().
> >+// what() is effectively transaction_pure, but we do not want to annotate it
> >+// as such; thus, we call exactly the respective nontransactional function.
> >+extern "C" {
> >+
> >+void
> >+_ZGTtNKSt9exceptionD1Ev(const std::exception*)
> >+{ }
> >+
> >+const char*
> >+_ZGTtNKSt9exception4whatEv(const std::exception* that)
> >+{
> >+  return that->std::exception::what();
> >+}
> 
> This makes a non-virtual call, is that correct?
> 
> If users derive from std::exception and override what() they will
> expect a call to what() to dispatch to their override in the derived
> class, but IIUC in a transactional block they would call this
> function, which would call the base what(), not their override.

Yes.  I added this comment to _ZGTtNKSt9exception4whatEv and also
referenced it from a comment in _ZGTtNKSt13bad_exception4whatEv.

  // We really want the non-virtual call here.  We already executed the
  // indirect call representing the virtual call, and the TM runtime or the
  // compiler resolved it to this transactional clone.  In the clone, we want
  // to do the same as for the nontransactional original, so we just call it.


> >+_ZGTtNKSt13bad_exception4whatEv(
> >+    const std::bad_exception* that)
> >+{
> >+  return that->std::bad_exception::what();
> >+}
> 
> Ditto.

See above.

> >@@ -151,3 +164,220 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > 
> > _GLIBCXX_END_NAMESPACE_VERSION
> > } // namespace
> >+
> >+// Support for the Transactional Memory TS (N4514).
> >+//
> >+// logic_error and runtime_error both carry a message in the form of a COW
> >+// string.  This COW string is never made visible to users of the exception
> >+// because what() returns a C string.  The COW string can be constructed as
> >+// either a copy of a COW string of another logic_error/runtime_error, or
> >+// using a C string or SSO string; thus, the COW string's _Rep is only
> >+// accessed by logic_error operations.  We control all txnal clones of those
> >+// operations and thus can ensure that _Rep is never accessed transactionally.
> >+// Furthermore, _Rep will always have been allocated or deallocated via
> >+// global new or delete, so nontransactional writes we do to _Rep cannot
> 
> Hmm, will it always be global new/delete? It uses std::allocator,
> which by default uses new/delete but libstdc++ can be configured to
> use a different std::allocator implementation. If they always use new
> at some point maybe we're OK, but I'd have to check the alternative
> allocators. Maybe we just say only new_allocator is supported for TM.

I wasn't aware that a different std::allocator can be hooked in at
compile time.  Can we check for this (I assume there must be some build
flag for the new allocator?), and simply disable support for the TM TS
if this is the case?

An alternative would be to call the transactional clones of the
std::allocator allocate/deallocate functions -- but even if we did that,
and created txnal clones for those of new_allocator so that we
eventually reach the txnal global new/delete functions that I'm calling
directly in this patch, we'd still need to check whether other
allocators provide them.

What would you like to see?  Or should we just document that limitation
somewhere for now?

> I assume we want to avoid making a txnal std::allocator.

I'm not quite sure what you mean, but the TM support should work with
the default std::allocator at least.

> >+extern "C" {
> >+
> >+void
> >+_ZGTtNSt11logic_errorC1EPKc (std::logic_error *that, const char* s)
> >+{
> >+  // This will use the singleton _Rep for an empty string and just point
> >+  // to it instead of allocating memory.  Thus, we can use it as source, copy
> >+  // it into the object we are constructing, and then construct the COW string
> >+  // in the latter manually.
> >+  std::logic_error le("");
> >+  _ITM_memcpyRnWt(that, &le, sizeof(std::logic_error));
> >+  _txnal_cow_string_C1_for_exceptions(_txnal_logic_error_get_msg(that),
> >+				      s, that);
> 
> The shared empty _Rep is also only used conditionally, it can be
> disabled with --enable-fully-dynamic-string. Maybe another thing we
> just don't deal with for now.

What would you like to see?

Also, can you give me some guidance on the remaining FIXME's in this
patch, please?  In particular, these:

+// FIXME copy over libitm's configury for MANGLE_SIZE_T?
Is there some way to get this from libstdc++ already, or how do you
prefer we handle this?

+// If there is no support for weak, create dummies.
+// FIXME really needed for libstdc++?
+//#if !defined (HAVE_ELF_STYLE_WEAKREF)
Can I assume weak refs to be supported, or how do I check for whether
they are?  What's your preference?

+  // FIXME make a true compile-time choice to prevent warnings.
+  if (sizeof(uint64_t)== sizeof(void*))
+    return (void*)_ITM_RU8((const uint64_t*)ptr);
+  else
+    return (void*)_ITM_RU4((const uint32_t*)ptr);

I've attached a patch with changes for V2 of this (for ease of review,
this is on top of the patch I sent).  This now makes the other
exceptions besides logic_error transaction-safe too.  Please have a
look. 

I tested this on x86_64-linux by running the libitm test that is added
by the V2 changes.  I haven't run a full test of the library so far.

And now with changelogs too! ;)

libstdc++-v3:
2015-12-23  Torvald Riegel  <triegel@redhat.com>

	* include/bits/basic_string.h (basic_string): Declare friends.
	* include/bits/c++config (_GLIBCXX_TXN_SAFE,
	_GLIBCXX_TXN_SAFE_DYN): New.
	* include/std/stdexcept (logic_error, domain_error, invalid_argument,
	length_error, out_of_range, runtime_error, range_error,
	underflow_error, overflow_error): Declare members as transaction-safe.
	(logic_error, runtime_error): Declare friend functions.
	* libsupc++/exception (exception, bad_exception): Declare members as
	transaction-safe.
	* src/c++11/cow-stdexcept.cc: Define transactional clones for the
	transaction-safe members of exceptions and helper functions.
	* libsupc++/eh_exception.cc: Adjust and define transactional clones.
	* config/abi/pre/gnu.ver (GLIBCXX_3.4.22) Add transactional clones.
	(CXXABI_1.3.10): New.

libitm:
2015-12-23  Torvald Riegel  <triegel@redhat.com>

	testsuite/libitm.c++/libstdc++-safeexc.C: New.

commit c8457910bf92772e60f77935f687dad1b4cf2b6a
Author: Torvald Riegel <triegel@redhat.com>
Date:   Wed Dec 23 18:19:32 2015 +0100

    v2 changes

diff --git a/libitm/testsuite/libitm.c++/libstdc++-safeexc.C b/libitm/testsuite/libitm.c++/libstdc++-safeexc.C
new file mode 100644
index 0000000..3e1655e
--- /dev/null
+++ b/libitm/testsuite/libitm.c++/libstdc++-safeexc.C
@@ -0,0 +1,89 @@
+// Tests that the exceptions declared by the TM TS (N4514) as transaction_safe
+// are indeed that.  Thus, this also tests the transactional clones in
+// libstdc++ and libsupc++.
+
+// { dg-do run }
+
+#include <iostream>
+#include <exception>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
+
+template<typename T> void thrower(const T& t)
+{
+  try
+    {
+      atomic_commit
+      {
+	throw t;
+      }
+    }
+  catch (T ex)
+    {
+      if (ex != t) abort ();
+    }
+}
+
+template<typename T> void thrower1(const string& what)
+{
+  try
+    {
+      atomic_commit
+      {
+	throw T ();
+      }
+    }
+  catch (T ex)
+    {
+      if (what != ex.what()) abort ();
+    }
+}
+
+template<typename T> void thrower2(const string& what)
+{
+  try
+    {
+      atomic_commit
+      {
+	throw T (what);
+      }
+    }
+  catch (T ex)
+    {
+      if (what != ex.what()) abort ();
+    }
+}
+
+
+int main ()
+{
+  thrower<unsigned int> (23);
+  thrower<int> (23);
+  thrower<unsigned short> (23);
+  thrower<short> (23);
+  thrower<unsigned char> (23);
+  thrower<char> (23);
+  thrower<unsigned long int> (42);
+  thrower<long int> (42);
+  thrower<unsigned long long int> (42);
+  thrower<long long int> (42);
+  thrower<double> (23.42);
+  thrower<long double> (23.42);
+  thrower<float> (23.42);
+  thrower<void*> (0);
+  thrower<void**> (0);
+  thrower1<exception> ("std::exception");
+  thrower1<bad_exception> ("std::bad_exception");
+  thrower2<logic_error> ("test");
+  thrower2<domain_error> ("test");
+  thrower2<invalid_argument> ("test");
+  thrower2<length_error> ("test");
+  thrower2<out_of_range> ("test");
+  thrower2<runtime_error> ("test");
+  thrower2<range_error> ("test");
+  thrower2<overflow_error> ("test");
+  thrower2<underflow_error> ("test");
+  return 0;
+}
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 2777c49..730d339 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1881,6 +1881,31 @@ GLIBCXX_3.4.22 {
     _ZGTtNSt11logic_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
     _ZGTtNKSt11logic_error4whatEv;
     _ZGTtNSt11logic_errorD[012]Ev;
+    _ZGTtNSt12domain_errorC[12]EPKc;
+    _ZGTtNSt12domain_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt12domain_errorD[012]Ev;
+    _ZGTtNSt16invalid_argumentC[12]EPKc;
+    _ZGTtNSt16invalid_argumentC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt16invalid_argumentD[012]Ev;
+    _ZGTtNSt12length_errorC[12]EPKc;
+    _ZGTtNSt12length_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt12length_errorD[012]Ev;
+    _ZGTtNSt12out_of_rangeC[12]EPKc;
+    _ZGTtNSt12out_of_rangeC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt12out_of_rangeD[012]Ev;
+    _ZGTtNSt13runtime_errorC[12]EPKc;
+    _ZGTtNSt13runtime_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNKSt13runtime_error4whatEv;
+    _ZGTtNSt13runtime_errorD[012]Ev;
+    _ZGTtNSt11range_errorC[12]EPKc;
+    _ZGTtNSt11range_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt11range_errorD[012]Ev;
+    _ZGTtNSt14overflow_errorC[12]EPKc;
+    _ZGTtNSt14overflow_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt14overflow_errorD[012]Ev;
+    _ZGTtNSt15underflow_errorC[12]EPKc;
+    _ZGTtNSt15underflow_errorC[12]ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+    _ZGTtNSt15underflow_errorD[012]Ev;
 
 } GLIBCXX_3.4.21;
 
diff --git a/libstdc++-v3/include/std/stdexcept b/libstdc++-v3/include/std/stdexcept
index 620a2f4..51ea91a 100644
--- a/libstdc++-v3/include/std/stdexcept
+++ b/libstdc++-v3/include/std/stdexcept
@@ -146,9 +146,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class domain_error : public logic_error 
   {
   public:
-    explicit domain_error(const string& __arg);
+    explicit domain_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit domain_error(const char*);
+    explicit domain_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~domain_error() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -157,9 +157,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class invalid_argument : public logic_error 
   {
   public:
-    explicit invalid_argument(const string& __arg);
+    explicit invalid_argument(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit invalid_argument(const char*);
+    explicit invalid_argument(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~invalid_argument() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -169,9 +169,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class length_error : public logic_error 
   {
   public:
-    explicit length_error(const string& __arg);
+    explicit length_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit length_error(const char*);
+    explicit length_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~length_error() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -181,9 +181,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class out_of_range : public logic_error 
   {
   public:
-    explicit out_of_range(const string& __arg);
+    explicit out_of_range(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit out_of_range(const char*);
+    explicit out_of_range(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~out_of_range() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -200,11 +200,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   public:
     /** Takes a character string describing the error.  */
     explicit 
-    runtime_error(const string& __arg);
+    runtime_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 
 #if __cplusplus >= 201103L
     explicit
-    runtime_error(const char*);
+    runtime_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
 
 #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS
@@ -212,21 +212,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     runtime_error& operator=(const runtime_error&) _GLIBCXX_USE_NOEXCEPT;
 #endif
 
-    virtual ~runtime_error() _GLIBCXX_USE_NOEXCEPT;
+    virtual ~runtime_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
 
     /** Returns a C-style character string describing the general cause of
      *  the current error (the same string passed to the ctor).  */
     virtual const char* 
-    what() const _GLIBCXX_USE_NOEXCEPT;
+    what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
+# ifdef _GLIBCXX_TM_TS_INTERNAL
+    friend void*
+    ::_txnal_runtime_error_get_msg(void* e);
+# endif
   };
 
   /** Thrown to indicate range errors in internal computations.  */
   class range_error : public runtime_error 
   {
   public:
-    explicit range_error(const string& __arg);
+    explicit range_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit range_error(const char*);
+    explicit range_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~range_error() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -235,9 +239,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class overflow_error : public runtime_error 
   {
   public:
-    explicit overflow_error(const string& __arg);
+    explicit overflow_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit overflow_error(const char*);
+    explicit overflow_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~overflow_error() _GLIBCXX_USE_NOEXCEPT;
   };
@@ -246,9 +250,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class underflow_error : public runtime_error 
   {
   public:
-    explicit underflow_error(const string& __arg);
+    explicit underflow_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
-    explicit underflow_error(const char*);
+    explicit underflow_error(const char*) _GLIBCXX_TXN_SAFE;
 #endif
     virtual ~underflow_error() _GLIBCXX_USE_NOEXCEPT;
   };
diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc b/libstdc++-v3/src/c++11/cow-stdexcept.cc
index b158f7b..b2a912f 100644
--- a/libstdc++-v3/src/c++11/cow-stdexcept.cc
+++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc
@@ -38,6 +38,8 @@ void
 _txnal_cow_string_D1_commit(void* that);
 void*
 _txnal_logic_error_get_msg(void* e);
+void*
+_txnal_runtime_error_get_msg(void* e);
 
 // All exception classes still use the classic COW std::string.
 #define _GLIBCXX_USE_CXX11_ABI 0
@@ -244,8 +246,8 @@ _txnal_cow_string_C1_for_exceptions(void* that, const char* s, void *exc)
   // transactional clone of global new[]; if this throws, it will do so in a
   // transaction-compatible way.
   // The allocation belongs to this exception, so tell the runtime about it.
-  // TODO associate exception
-//  void *prev = _ITM_setAssociatedException(exc);
+  // TODO Once this is supported, link the following allocation to this
+  // exception: void *prev = _ITM_setAssociatedException(exc);
   bs_type::_Rep *rep;
   try
     {
@@ -254,12 +256,14 @@ _txnal_cow_string_C1_for_exceptions(void* that, const char* s, void *exc)
   catch (...)
     {
       // Pop the association with this exception.
-//      _ITM_setAssociatedException(prev);
+      // TODO Once this is supported, link the following allocation to this
+      // exception: _ITM_setAssociatedException(prev);
       // We do not need to instrument a rethrow.
       throw;
     }
   // Pop the association with this exception.
-//  _ITM_setAssociatedException(prev);
+  // TODO Once this is supported, link the following allocation to this
+  // exception: _ITM_setAssociatedException(prev);
 
   // Now initialize the rest of the string and copy the C string.  The memory
   // will be freshly allocated, so nontransactional accesses are sufficient,
@@ -332,45 +336,78 @@ _txnal_logic_error_get_msg(void* e)
   return &le->_M_msg;
 }
 
-extern "C" {
-
-void
-_ZGTtNSt11logic_errorC1EPKc (std::logic_error* that, const char* s)
+void*
+_txnal_runtime_error_get_msg(void* e)
 {
-  // This will use the singleton _Rep for an empty string and just point
-  // to it instead of allocating memory.  Thus, we can use it as source, copy
-  // it into the object we are constructing, and then construct the COW string
-  // in the latter manually.
-  std::logic_error le("");
-  _ITM_memcpyRnWt(that, &le, sizeof(std::logic_error));
-  _txnal_cow_string_C1_for_exceptions(_txnal_logic_error_get_msg(that),
-				      s, that);
+  std::runtime_error* le = (std::runtime_error*) e;
+  return &le->_M_msg;
 }
-void
-_ZGTtNSt11logic_errorC2EPKc (std::logic_error*, const char*)
-  __attribute__((alias ("_ZGTtNSt11logic_errorC1EPKc")));
 
-void
-_ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE(
-    std::logic_error* that, const std::__sso_string& s)
-{
-  std::logic_error le("");
-  _ITM_memcpyRnWt(that, &le, sizeof(std::logic_error));
-  // This constructor is only declared transaction-safe if the C++11 ABI is
-  // used for std::string yet logic_error used a COW string internally.  A
-  // user must not call this constructor otherwise; although we can still
-  // compile and provide it, calling it would result in undefined behavior,
-  // which is in this case not initializing the message.
+// The constructors are only declared transaction-safe if the C++11 ABI is
+// used for std::string and the exception classes use a COW string internally.
+// A user must not call these constructors otherwise; if they do, it will
+// result in undefined behavior, which is in this case not initializing this
+// string.
 #if _GLIBCXX_USE_DUAL_ABI
-  // Get the C string from the SSO string.
-  _txnal_cow_string_C1_for_exceptions(_txnal_logic_error_get_msg(that),
-				      _txnal_sso_string_c_str(&s), that);
+#define CTORDTORSTRINGCSTR(s) _txnal_sso_string_c_str((s))
+#else
+#define CTORDTORSTRINGCSTR(s) ""
 #endif
+
+// This macro defines transaction constructors and destructors for a specific
+// exception class.  NAME is the variable part of the mangled name, CLASS is
+// the class name, and BASE must be logic_error or runtime_error (which is
+// then used to call the proper friend function that can return a pointer to
+// the _M_msg member declared by the given (base) class).
+#define CTORDTOR(NAME, CLASS, BASE)					\
+void									\
+_ZGTtNSt##NAME##C1EPKc (CLASS* that, const char* s)			\
+{									\
+  /* This will use the singleton _Rep for an empty string and just	\
+     point to it instead of allocating memory.  Thus, we can use it as	\
+     source, copy it into the object we are constructing, and then	\
+     construct the COW string in the latter manually.  */		\
+  CLASS e("");								\
+  _ITM_memcpyRnWt(that, &e, sizeof(CLASS));				\
+  _txnal_cow_string_C1_for_exceptions(_txnal_##BASE##_get_msg(that),	\
+				      s, that);				\
+}									\
+void									\
+_ZGTtNSt##NAME##C2EPKc (CLASS*, const char*)				\
+  __attribute__((alias ("_ZGTtNSt" #NAME "C1EPKc")));			\
+void									\
+_ZGTtNSt##NAME##C1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE( \
+    CLASS* that, const std::__sso_string& s)				\
+{									\
+  CLASS e("");								\
+  _ITM_memcpyRnWt(that, &e, sizeof(CLASS));				\
+  /* Get the C string from the SSO string.  */				\
+  _txnal_cow_string_C1_for_exceptions(_txnal_##BASE##_get_msg(that),	\
+				      CTORDTORSTRINGCSTR(&s), that);	\
+}									\
+void									\
+_ZGTtNSt##NAME##C2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE( \
+    CLASS*, const std::__sso_string&) __attribute__((alias		\
+("_ZGTtNSt" #NAME							\
+  "C1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")));	\
+void									\
+_ZGTtNSt##NAME##D1Ev(CLASS* that)					\
+{ _txnal_cow_string_D1(_txnal_##BASE##_get_msg(that)); }		\
+void									\
+_ZGTtNSt##NAME##D2Ev(CLASS*)						\
+__attribute__((alias ("_ZGTtNSt" #NAME "D1Ev")));			\
+void									\
+_ZGTtNSt##NAME##D0Ev(CLASS* that)					\
+{									\
+  _ZGTtNSt##NAME##D1Ev(that);						\
+  _ZGTtdlPv(that);							\
 }
-void
-_ZGTtNSt11logic_errorC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE(
-    std::logic_error*, const std::__sso_string&) __attribute__((alias
-("_ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")));
+
+// Now create all transactional constructors and destructors, as well as the
+// two virtual what() functions.
+extern "C" {
+
+CTORDTOR(11logic_error, std::logic_error, logic_error)
 
 const char*
 _ZGTtNKSt11logic_error4whatEv(const std::logic_error* that)
@@ -379,19 +416,23 @@ _ZGTtNKSt11logic_error4whatEv(const std::logic_error* that)
       const_cast<std::logic_error*>(that)));
 }
 
-void
-_ZGTtNSt11logic_errorD1Ev(std::logic_error* that)
-{
-  _txnal_cow_string_D1(_txnal_logic_error_get_msg(that));
-}
-void
-_ZGTtNSt11logic_errorD2Ev(std::logic_error*)
-__attribute__((alias ("_ZGTtNSt11logic_errorD1Ev")));
-void
-_ZGTtNSt11logic_errorD0Ev(std::logic_error* that)
+CTORDTOR(12domain_error, std::domain_error, logic_error)
+CTORDTOR(16invalid_argument, std::invalid_argument, logic_error)
+CTORDTOR(12length_error, std::length_error, logic_error)
+CTORDTOR(12out_of_range, std::out_of_range, logic_error)
+
+
+CTORDTOR(13runtime_error, std::runtime_error, runtime_error)
+
+const char*
+_ZGTtNKSt13runtime_error4whatEv(const std::runtime_error* that)
 {
-  _ZGTtNSt11logic_errorD1Ev(that);
-  _ZGTtdlPv(that);
+  return _txnal_cow_string_c_str(_txnal_runtime_error_get_msg(
+      const_cast<std::runtime_error*>(that)));
 }
 
+CTORDTOR(11range_error, std::range_error, runtime_error)
+CTORDTOR(14overflow_error, std::overflow_error, runtime_error)
+CTORDTOR(15underflow_error, std::underflow_error, runtime_error)
+
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]