aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/c++11/cow-stdexcept.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/src/c++11/cow-stdexcept.cc')
-rw-r--r--libstdc++-v3/src/c++11/cow-stdexcept.cc290
1 files changed, 290 insertions, 0 deletions
diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc b/libstdc++-v3/src/c++11/cow-stdexcept.cc
index 782b96c6d4f..eddb36b48c4 100644
--- a/libstdc++-v3/src/c++11/cow-stdexcept.cc
+++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc
@@ -26,6 +26,21 @@
// ISO C++ 14882: 19.1 Exception classes
//
+// Enable hooks for support for the Transactional Memory TS (N4514).
+#define _GLIBCXX_TM_TS_INTERNAL
+void
+_txnal_cow_string_C1_for_exceptions(void* that, const char* s, void* exc);
+const char*
+_txnal_cow_string_c_str(const void* that);
+void
+_txnal_cow_string_D1(void* that);
+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
#define _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS 1
@@ -151,3 +166,278 @@ _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
+// interfere with transactional accesses.
+extern "C" {
+
+#ifndef _GLIBCXX_MANGLE_SIZE_T
+#error Mangled name of size_t type not defined.
+#endif
+#define CONCAT1(x,y) x##y
+#define CONCAT(x,y) CONCAT1(x,y)
+#define _ZGTtnaX CONCAT(_ZGTtna,_GLIBCXX_MANGLE_SIZE_T)
+
+#ifdef __i386__
+/* Only for 32-bit x86. */
+# define ITM_REGPARM __attribute__((regparm(2)))
+#else
+# define ITM_REGPARM
+#endif
+
+#if __GXX_WEAK__
+// Declare all libitm symbols we rely on, but make them weak so that we do
+// not depend on libitm.
+extern void* _ZGTtnaX (size_t sz) __attribute__((weak));
+extern void _ZGTtdlPv (void* ptr) __attribute__((weak));
+extern uint8_t _ITM_RU1(const uint8_t *p)
+ ITM_REGPARM __attribute__((weak));
+extern uint32_t _ITM_RU4(const uint32_t *p)
+ ITM_REGPARM __attribute__((weak));
+extern uint64_t _ITM_RU8(const uint64_t *p)
+ ITM_REGPARM __attribute__((weak));
+extern void _ITM_memcpyRtWn(void *, const void *, size_t)
+ ITM_REGPARM __attribute__((weak));
+extern void _ITM_memcpyRnWt(void *, const void *, size_t)
+ ITM_REGPARM __attribute__((weak));
+extern void _ITM_addUserCommitAction(void (*)(void *), uint64_t, void *)
+ ITM_REGPARM __attribute__((weak));
+
+#else
+// If there is no support for weak symbols, create dummies. The exceptions
+// will not be declared transaction_safe in this case.
+void* _ZGTtnaX (size_t) { return NULL; }
+void _ZGTtdlPv (void*) { }
+uint8_t _ITM_RU1(const uint8_t *) { return 0; }
+uint32_t _ITM_RU4(const uint32_t *) { return 0; }
+uint64_t _ITM_RU8(const uint64_t *) { return 0; }
+void _ITM_memcpyRtWn(void *, const void *, size_t) { }
+void _ITM_memcpyRnWt(void *, const void *, size_t) { }
+void _ITM_addUserCommitAction(void (*)(void *), uint64_t, void *) { };
+#endif
+
+}
+
+// A transactional version of basic_string::basic_string(const char *s)
+// that also notifies the TM runtime about allocations belonging to this
+// exception.
+void
+_txnal_cow_string_C1_for_exceptions(void* that, const char* s,
+ void *exc __attribute__((unused)))
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type *bs = (bs_type*) that;
+
+ // First, do a transactional strlen, but including the trailing zero.
+ bs_type::size_type len = 1;
+ for (const char *ss = s; _ITM_RU1((const uint8_t*) ss) != 0; ss++, len++);
+
+
+ // Allocate memory for the string and the refcount. We use the
+ // 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 Once this is supported, link the following allocation to this
+ // exception: void *prev = _ITM_setAssociatedException(exc);
+ bs_type::_Rep *rep;
+ __try
+ {
+ rep = (bs_type::_Rep*) _ZGTtnaX (len + sizeof (bs_type::_Rep));
+ }
+ __catch (...)
+ {
+ // Pop the association with this exception.
+ // TODO Once this is supported, link the following allocation to this
+ // exception: _ITM_setAssociatedException(prev);
+ // We do not need to instrument a rethrow.
+ __throw_exception_again;
+ }
+ // Pop the association with this exception.
+ // 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,
+ // including the writes when copying the string (see above).
+ rep->_M_set_sharable();
+ rep->_M_length = rep->_M_capacity = len - 1;
+ _ITM_memcpyRtWn(rep->_M_refdata(), s, len);
+ new (&bs->_M_dataplus) bs_type::_Alloc_hider(rep->_M_refdata(),
+ bs_type::allocator_type());
+}
+
+static void* txnal_read_ptr(void* const * ptr)
+{
+ static_assert(sizeof(uint64_t) == sizeof(void*)
+ || sizeof(uint32_t) == sizeof(void*),
+ "Pointers must be 32 bits or 64 bits wide");
+#if __UINTPTR_MAX__ == __UINT64_MAX__
+ return (void*)_ITM_RU8((const uint64_t*)ptr);
+#else
+ return (void*)_ITM_RU4((const uint32_t*)ptr);
+#endif
+}
+
+// We must access the data pointer in the COW string transactionally because
+// another transaction can delete the string and reuse the memory.
+const char*
+_txnal_cow_string_c_str(const void* that)
+{
+ typedef std::basic_string<char> bs_type;
+ const bs_type *bs = (const bs_type*) that;
+
+ return (const char*) txnal_read_ptr((void**)&bs->_M_dataplus._M_p);
+}
+
+const char*
+_txnal_sso_string_c_str(const void* that)
+{
+ return (const char*) txnal_read_ptr(
+ (void* const*)const_cast<char* const*>(
+ &((const std::__sso_string*) that)->_M_s._M_p));
+}
+
+void
+_txnal_cow_string_D1_commit(void* data)
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type::_Rep *rep = (bs_type::_Rep*) data;
+ rep->_M_dispose(bs_type::allocator_type());
+}
+
+void
+_txnal_cow_string_D1(void* that)
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type::_Rep *rep = reinterpret_cast<bs_type::_Rep*>(
+ const_cast<char*>(_txnal_cow_string_c_str(that))) - 1;
+
+ // The string can be shared, in which case we would need to decrement the
+ // reference count. We cannot undo that because we might lose the string
+ // otherwise. Therefore, we register a commit action that will dispose of
+ // the string's _Rep.
+ enum {_ITM_noTransactionId = 1};
+ _ITM_addUserCommitAction(_txnal_cow_string_D1_commit, _ITM_noTransactionId,
+ rep);
+}
+
+void*
+_txnal_logic_error_get_msg(void* e)
+{
+ std::logic_error* le = (std::logic_error*) e;
+ return &le->_M_msg;
+}
+
+void*
+_txnal_runtime_error_get_msg(void* e)
+{
+ std::runtime_error* le = (std::runtime_error*) e;
+ return &le->_M_msg;
+}
+
+// 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
+#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. Note that the \
+ exception classes will not be declared transaction_safe if the \
+ shared empty _Rep is disabled with --enable-fully-dynamic-string \
+ (in which case _GLIBCXX_FULLY_DYNAMIC_STRING is nonzero). */ \
+ 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); \
+}
+
+// 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)
+{
+ return _txnal_cow_string_c_str(_txnal_logic_error_get_msg(
+ const_cast<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)
+{
+ 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)
+
+}