stdexcept.cpp revision cdf7d557bd6835f66fe707ca7b1a8f22010ffb66
1//===------------------------ stdexcept.cpp -------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "stdexcept"
11#include "new"
12#include <cstdlib>
13#include <cstring>
14#include <cstdint>
15#include <cstddef>
16
17#if __APPLE__
18#include <dlfcn.h>
19#include <mach-o/dyld.h>
20#endif
21
22// Note:  optimize for size
23
24#pragma GCC visibility push(hidden)
25
26namespace
27{
28
29class __libcpp_nmstr
30{
31private:
32    const char* str_;
33
34    typedef int count_t;
35
36    struct _Rep_base
37    {
38        std::size_t len;
39        std::size_t cap;
40        count_t     count;
41    };
42
43    static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(sizeof(_Rep_base));
44
45    count_t& count() const _NOEXCEPT {return ((_Rep_base*)(str_ - offset))->count;}
46
47#if __APPLE__
48    static
49    const void*
50    compute_gcc_empty_string_storage() _LIBCPP_CANTTHROW
51    {
52        void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
53        if (handle == 0)
54            return 0;
55        return (const char*)dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE") + offset;
56    }
57
58    static
59    const void*
60    get_gcc_empty_string_storage() _LIBCPP_CANTTHROW
61    {
62        static const void* p = compute_gcc_empty_string_storage();
63        return p;
64    }
65#endif
66
67public:
68    explicit __libcpp_nmstr(const char* msg);
69    __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
70    __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
71    ~__libcpp_nmstr();
72    const char* c_str() const _NOEXCEPT {return str_;}
73};
74
75__libcpp_nmstr::__libcpp_nmstr(const char* msg)
76{
77    std::size_t len = strlen(msg);
78    str_ = static_cast<const char*>(::operator new(len + 1 + offset));
79    _Rep_base* c = (_Rep_base*)str_;
80    c->len = c->cap = len;
81    str_ += offset;
82    count() = 0;
83    std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
84}
85
86inline
87__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
88    : str_(s.str_)
89{
90#if __APPLE__
91    if (str_ != get_gcc_empty_string_storage())
92#endif
93        __sync_add_and_fetch(&count(), 1);
94}
95
96__libcpp_nmstr&
97__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
98{
99    const char* p = str_;
100    str_ = s.str_;
101#if __APPLE__
102    if (str_ != get_gcc_empty_string_storage())
103#endif
104        __sync_add_and_fetch(&count(), 1);
105#if __APPLE__
106    if (p != get_gcc_empty_string_storage())
107#endif
108        if (__sync_add_and_fetch((count_t*)(p-sizeof(count_t)), count_t(-1)) < 0)
109        {
110            ::operator delete(const_cast<char*>(p-offset));
111        }
112    return *this;
113}
114
115inline
116__libcpp_nmstr::~__libcpp_nmstr()
117{
118#if __APPLE__
119    if (str_ != get_gcc_empty_string_storage())
120#endif
121        if (__sync_add_and_fetch(&count(), count_t(-1)) < 0)
122        {
123            ::operator delete(const_cast<char*>(str_ - offset));
124        }
125}
126
127}
128
129#pragma GCC visibility pop
130
131namespace std  // purposefully not using versioning namespace
132{
133
134logic_error::~logic_error() _NOEXCEPT
135{
136    __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
137    s.~__libcpp_nmstr();
138}
139
140const char*
141logic_error::what() const _NOEXCEPT
142{
143    __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
144    return s.c_str();
145}
146
147runtime_error::~runtime_error() _NOEXCEPT
148{
149    __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
150    s.~__libcpp_nmstr();
151}
152
153const char*
154runtime_error::what() const _NOEXCEPT
155{
156    __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
157    return s.c_str();
158}
159
160domain_error::~domain_error() _NOEXCEPT {}
161invalid_argument::~invalid_argument() _NOEXCEPT {}
162length_error::~length_error() _NOEXCEPT {}
163out_of_range::~out_of_range() _NOEXCEPT {}
164
165range_error::~range_error() _NOEXCEPT {}
166overflow_error::~overflow_error() _NOEXCEPT {}
167underflow_error::~underflow_error() _NOEXCEPT {}
168
169}  // std
170