[libcxx] r207695 - Exceptions store the message as reference counted string for

Joerg Sonnenberger joerg at bec.de
Wed Apr 30 12:54:12 PDT 2014


Author: joerg
Date: Wed Apr 30 14:54:11 2014
New Revision: 207695

URL: http://llvm.org/viewvc/llvm-project?rev=207695&view=rev
Log:
Exceptions store the message as reference counted string for
compatibility to libstdc++. Move the implementation into a header for
easier sharing with libc++abi. Merge a number of improvements from that
version. Provide a POD definition for <stdexcept>'s public use to avoid
cast dances. Discussed with Marshall Clow.

Added:
    libcxx/trunk/include/__refstring
Modified:
    libcxx/trunk/include/stdexcept
    libcxx/trunk/src/stdexcept.cpp

Added: libcxx/trunk/include/__refstring
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__refstring?rev=207695&view=auto
==============================================================================
--- libcxx/trunk/include/__refstring (added)
+++ libcxx/trunk/include/__refstring Wed Apr 30 14:54:11 2014
@@ -0,0 +1,139 @@
+//===------------------------ __refstring ---------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REFSTRING
+#define _LIBCPP___REFSTRING
+
+#include <__config>
+#include <cstddef>
+#include <cstring>
+#if __APPLE__
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+class _LIBCPP_HIDDEN __libcpp_refstring
+{
+private:
+    const char* str_;
+
+    typedef int count_t;
+
+    struct _Rep_base
+    {
+        std::size_t len;
+        std::size_t cap;
+        count_t     count;
+    };
+
+    static
+    _Rep_base*
+    rep_from_data(const char *data_) _NOEXCEPT
+    {
+        char *data = const_cast<char *>(data_);
+        return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
+    }
+    static
+    char *
+    data_from_rep(_Rep_base *rep) _NOEXCEPT
+    {
+        char *data = reinterpret_cast<char *>(rep);
+        return data + sizeof(*rep);
+    }
+
+#if __APPLE__
+    static
+    const char*
+    compute_gcc_empty_string_storage() _NOEXCEPT
+    {
+        void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
+        if (handle == nullptr)
+            return nullptr;
+        void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
+        if (sym == nullptr)
+            return nullptr;
+        return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
+    }
+
+    static
+    const char*
+    get_gcc_empty_string_storage() _NOEXCEPT
+    {
+        static const char* p = compute_gcc_empty_string_storage();
+        return p;
+    }
+
+    bool
+    uses_refcount() const
+    {
+        return str_ != get_gcc_empty_string_storage();
+    }
+#else
+    bool
+    uses_refcount() const
+    {
+        return true;
+    }
+#endif
+
+public:
+    explicit __libcpp_refstring(const char* msg) {
+        std::size_t len = strlen(msg);
+        _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
+        rep->len = len;
+        rep->cap = len;
+        rep->count = 0;
+        char *data = data_from_rep(rep);
+        std::memcpy(data, msg, len + 1);
+        str_ = data;
+    }
+
+    __libcpp_refstring(const __libcpp_refstring& s) _NOEXCEPT : str_(s.str_)
+    {
+        if (uses_refcount())
+            __sync_add_and_fetch(&rep_from_data(str_)->count, 1);
+    }
+
+    __libcpp_refstring& operator=(const __libcpp_refstring& s) _NOEXCEPT
+    {
+        bool adjust_old_count = uses_refcount();
+        struct _Rep_base *old_rep = rep_from_data(str_);
+        str_ = s.str_;
+        if (uses_refcount())
+            __sync_add_and_fetch(&rep_from_data(str_)->count, 1);
+        if (adjust_old_count)
+        {
+            if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0)
+            {
+                ::operator delete(old_rep);
+            }
+        }
+        return *this;
+    }
+
+    ~__libcpp_refstring()
+    {
+        if (uses_refcount())
+        {
+            _Rep_base* rep = rep_from_data(str_);
+            if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0)
+            {
+                ::operator delete(rep);
+            }
+        }
+    }
+
+    const char* c_str() const _NOEXCEPT {return str_;}
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif //_LIBCPP___REFSTRING

Modified: libcxx/trunk/include/stdexcept
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/stdexcept?rev=207695&r1=207694&r2=207695&view=diff
==============================================================================
--- libcxx/trunk/include/stdexcept (original)
+++ libcxx/trunk/include/stdexcept Wed Apr 30 14:54:11 2014
@@ -50,6 +50,14 @@ public:
 #pragma GCC system_header
 #endif
 
+#ifndef _LIBCPP___REFSTRING
+_LIBCPP_BEGIN_NAMESPACE_STD
+class _LIBCPP_HIDDEN __libcpp_refstring {
+    const char *__imp_;
+};
+_LIBCPP_END_NAMESPACE_STD
+#endif
+
 namespace std  // purposefully not using versioning namespace
 {
 
@@ -57,7 +65,7 @@ class _LIBCPP_EXCEPTION_ABI logic_error
     : public exception
 {
 private:
-    void* __imp_;
+    _VSTD::__libcpp_refstring __imp_;
 public:
     explicit logic_error(const string&);
     explicit logic_error(const char*);
@@ -74,7 +82,7 @@ class _LIBCPP_EXCEPTION_ABI runtime_erro
     : public exception
 {
 private:
-    void* __imp_;
+    _VSTD::__libcpp_refstring __imp_;
 public:
     explicit runtime_error(const string&);
     explicit runtime_error(const char*);

Modified: libcxx/trunk/src/stdexcept.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/stdexcept.cpp?rev=207695&r1=207694&r2=207695&view=diff
==============================================================================
--- libcxx/trunk/src/stdexcept.cpp (original)
+++ libcxx/trunk/src/stdexcept.cpp Wed Apr 30 14:54:11 2014
@@ -7,124 +7,42 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "__refstring"
 #include "stdexcept"
 #include "new"
 #include "string"
-#include <cstdlib>
-#include <cstring>
-#include <cstdint>
-#include <cstddef>
 #include "system_error"
 
 #ifndef __has_include
 #define __has_include(inc) 0
 #endif
 
-#ifdef __APPLE__
+/* For _LIBCPPABI_VERSION */
+#if __has_include(<cxxabi.h>) || defined(__APPLE_) || defined(LIBCXXRT)
 #include <cxxabi.h>
-#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
-#include <cxxabi.h>
-#endif
-
-// Note:  optimize for size
-
-#if ! defined(_LIBCPP_MSVC)
-#pragma GCC visibility push(hidden)
 #endif
 
-namespace
-{
-
-class __libcpp_nmstr
-{
-private:
-    const char* str_;
-
-    typedef std::size_t unused_t;
-    typedef std::ptrdiff_t count_t;
-
-    static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(2*sizeof(unused_t) +
-                                                                       sizeof(count_t));
-
-    count_t& count() const _NOEXCEPT {return *const_cast<count_t *>(reinterpret_cast<const count_t *>(str_ - sizeof(count_t)));}
-public:
-    explicit __libcpp_nmstr(const char* msg);
-    __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
-    __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
-    ~__libcpp_nmstr();
-    const char* c_str() const _NOEXCEPT {return str_;}
-};
-
-__libcpp_nmstr::__libcpp_nmstr(const char* msg)
-{
-    std::size_t len = strlen(msg);
-    str_ = new char[len + 1 + offset];
-    unused_t* c = reinterpret_cast<unused_t*>(const_cast<char *>(str_));
-    c[0] = c[1] = len;
-    str_ += offset;
-    count() = 0;
-    std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
-}
-
-inline
-__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
-    : str_(s.str_)
-{
-    __sync_add_and_fetch(&count(), 1);
-}
-
-__libcpp_nmstr&
-__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
-{
-    const char* p = str_;
-    str_ = s.str_;
-    __sync_add_and_fetch(&count(), 1);
-    if (__sync_add_and_fetch(reinterpret_cast<count_t*>(const_cast<char*>(p)-sizeof(count_t)), count_t(-1)) < 0)
-        delete [] (p-offset);
-    return *this;
-}
-
-inline
-__libcpp_nmstr::~__libcpp_nmstr()
-{
-    if (__sync_add_and_fetch(&count(), count_t(-1)) < 0)
-        delete [] (str_ - offset);
-}
-
-}
-
-#if ! defined(_LIBCPP_MSVC)
-#pragma GCC visibility pop
-#endif
+static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
 
 namespace std  // purposefully not using versioning namespace
 {
 
-logic_error::logic_error(const string& msg)
+logic_error::logic_error(const string& msg) : __imp_(msg.c_str())
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    ::new(s) __libcpp_nmstr(msg.c_str());
 }
 
-logic_error::logic_error(const char* msg)
+logic_error::logic_error(const char* msg) : __imp_(msg)
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    ::new(s) __libcpp_nmstr(msg);
 }
 
-logic_error::logic_error(const logic_error& le) _NOEXCEPT
+logic_error::logic_error(const logic_error& le) _NOEXCEPT : __imp_(le.__imp_)
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
-    ::new(s) __libcpp_nmstr(*s2);
 }
 
 logic_error&
 logic_error::operator=(const logic_error& le) _NOEXCEPT
 {
-    __libcpp_nmstr *s1 = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
-    *s1 = *s2;
+    __imp_ = le.__imp_;
     return *this;
 }
 
@@ -132,44 +50,33 @@ logic_error::operator=(const logic_error
 
 logic_error::~logic_error() _NOEXCEPT
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    s->~__libcpp_nmstr();
 }
 
 const char*
 logic_error::what() const _NOEXCEPT
 {
-    const __libcpp_nmstr *s = reinterpret_cast<const __libcpp_nmstr *>(&__imp_);
-    return s->c_str();
+    return __imp_.c_str();
 }
 
 #endif
 
-runtime_error::runtime_error(const string& msg)
+runtime_error::runtime_error(const string& msg) : __imp_(msg.c_str())
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    ::new(s) __libcpp_nmstr(msg.c_str());
 }
 
-runtime_error::runtime_error(const char* msg)
+runtime_error::runtime_error(const char* msg) : __imp_(msg)
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    ::new(s) __libcpp_nmstr(msg);
 }
 
 runtime_error::runtime_error(const runtime_error& le) _NOEXCEPT
+  : __imp_(le.__imp_)
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
-    ::new(s) __libcpp_nmstr(*s2);
 }
 
 runtime_error&
 runtime_error::operator=(const runtime_error& le) _NOEXCEPT
 {
-    __libcpp_nmstr *s1 = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
-    *s1 = *s2;
+    __imp_ = le.__imp_;
     return *this;
 }
 
@@ -177,15 +84,12 @@ runtime_error::operator=(const runtime_e
 
 runtime_error::~runtime_error() _NOEXCEPT
 {
-    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
-    s->~__libcpp_nmstr();
 }
 
 const char*
 runtime_error::what() const _NOEXCEPT
 {
-    const __libcpp_nmstr *s = reinterpret_cast<const __libcpp_nmstr *>(&__imp_);
-    return s->c_str();
+    return __imp_.c_str();
 }
 
 domain_error::~domain_error() _NOEXCEPT {}





More information about the cfe-commits mailing list