add libc++ and libc++abi sources

upstream: LLVM 10
This commit is contained in:
Andrew Kelley 2020-03-26 22:41:26 -04:00
parent 463b90b977
commit ed0dbe1a64
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
99 changed files with 30450 additions and 0 deletions

View File

@ -0,0 +1,95 @@
//===----------------------- algorithm.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "algorithm"
#include "random"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "mutex"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
template void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
template void __sort<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
template void __sort<__less<signed char>&, signed char*>(signed char*, signed char*, __less<signed char>&);
template void __sort<__less<unsigned char>&, unsigned char*>(unsigned char*, unsigned char*, __less<unsigned char>&);
template void __sort<__less<short>&, short*>(short*, short*, __less<short>&);
template void __sort<__less<unsigned short>&, unsigned short*>(unsigned short*, unsigned short*, __less<unsigned short>&);
template void __sort<__less<int>&, int*>(int*, int*, __less<int>&);
template void __sort<__less<unsigned>&, unsigned*>(unsigned*, unsigned*, __less<unsigned>&);
template void __sort<__less<long>&, long*>(long*, long*, __less<long>&);
template void __sort<__less<unsigned long>&, unsigned long*>(unsigned long*, unsigned long*, __less<unsigned long>&);
template void __sort<__less<long long>&, long long*>(long long*, long long*, __less<long long>&);
template void __sort<__less<unsigned long long>&, unsigned long long*>(unsigned long long*, unsigned long long*, __less<unsigned long long>&);
template void __sort<__less<float>&, float*>(float*, float*, __less<float>&);
template void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
template void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
template bool __insertion_sort_incomplete<__less<char>&, char*>(char*, char*, __less<char>&);
template bool __insertion_sort_incomplete<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
template bool __insertion_sort_incomplete<__less<signed char>&, signed char*>(signed char*, signed char*, __less<signed char>&);
template bool __insertion_sort_incomplete<__less<unsigned char>&, unsigned char*>(unsigned char*, unsigned char*, __less<unsigned char>&);
template bool __insertion_sort_incomplete<__less<short>&, short*>(short*, short*, __less<short>&);
template bool __insertion_sort_incomplete<__less<unsigned short>&, unsigned short*>(unsigned short*, unsigned short*, __less<unsigned short>&);
template bool __insertion_sort_incomplete<__less<int>&, int*>(int*, int*, __less<int>&);
template bool __insertion_sort_incomplete<__less<unsigned>&, unsigned*>(unsigned*, unsigned*, __less<unsigned>&);
template bool __insertion_sort_incomplete<__less<long>&, long*>(long*, long*, __less<long>&);
template bool __insertion_sort_incomplete<__less<unsigned long>&, unsigned long*>(unsigned long*, unsigned long*, __less<unsigned long>&);
template bool __insertion_sort_incomplete<__less<long long>&, long long*>(long long*, long long*, __less<long long>&);
template bool __insertion_sort_incomplete<__less<unsigned long long>&, unsigned long long*>(unsigned long long*, unsigned long long*, __less<unsigned long long>&);
template bool __insertion_sort_incomplete<__less<float>&, float*>(float*, float*, __less<float>&);
template bool __insertion_sort_incomplete<__less<double>&, double*>(double*, double*, __less<double>&);
template bool __insertion_sort_incomplete<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
#ifndef _LIBCPP_HAS_NO_THREADS
_LIBCPP_SAFE_STATIC static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER;
#endif
unsigned __rs_default::__c_ = 0;
__rs_default::__rs_default()
{
#ifndef _LIBCPP_HAS_NO_THREADS
__libcpp_mutex_lock(&__rs_mut);
#endif
__c_ = 1;
}
__rs_default::__rs_default(const __rs_default&)
{
++__c_;
}
__rs_default::~__rs_default()
{
#ifndef _LIBCPP_HAS_NO_THREADS
if (--__c_ == 0)
__libcpp_mutex_unlock(&__rs_mut);
#else
--__c_;
#endif
}
__rs_default::result_type
__rs_default::operator()()
{
static mt19937 __rs_g;
return __rs_g();
}
__rs_default
__rs_get()
{
return __rs_default();
}
_LIBCPP_END_NAMESPACE_STD

34
lib/libcxx/src/any.cpp Normal file
View File

@ -0,0 +1,34 @@
//===---------------------------- any.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "any"
namespace std {
const char* bad_any_cast::what() const _NOEXCEPT {
return "bad any cast";
}
}
#include <experimental/__config>
// Preserve std::experimental::any_bad_cast for ABI compatibility
// Even though it no longer exists in a header file
_LIBCPP_BEGIN_NAMESPACE_LFTS
class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_ANY_CAST bad_any_cast : public bad_cast
{
public:
virtual const char* what() const _NOEXCEPT;
};
const char* bad_any_cast::what() const _NOEXCEPT {
return "bad any cast";
}
_LIBCPP_END_NAMESPACE_LFTS

29
lib/libcxx/src/bind.cpp Normal file
View File

@ -0,0 +1,29 @@
//===-------------------------- bind.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "functional"
_LIBCPP_BEGIN_NAMESPACE_STD
namespace placeholders
{
const __ph<1> _1{};
const __ph<2> _2{};
const __ph<3> _3{};
const __ph<4> _4{};
const __ph<5> _5{};
const __ph<6> _6{};
const __ph<7> _7{};
const __ph<8> _8{};
const __ph<9> _9{};
const __ph<10> _10{};
} // placeholders
_LIBCPP_END_NAMESPACE_STD

160
lib/libcxx/src/charconv.cpp Normal file
View File

@ -0,0 +1,160 @@
//===------------------------- charconv.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "charconv"
#include <string.h>
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __itoa
{
static constexpr char cDigitsLut[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
'7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
'2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
'7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
'4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
'2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
'7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
'7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
'2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
'7', '9', '8', '9', '9'};
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append1(char* buffer, T i)
{
*buffer = '0' + static_cast<char>(i);
return buffer + 1;
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append2(char* buffer, T i)
{
memcpy(buffer, &cDigitsLut[(i)*2], 2);
return buffer + 2;
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append3(char* buffer, T i)
{
return append2(append1(buffer, (i) / 100), (i) % 100);
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append4(char* buffer, T i)
{
return append2(append2(buffer, (i) / 100), (i) % 100);
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append2_no_zeros(char* buffer, T v)
{
if (v < 10)
return append1(buffer, v);
else
return append2(buffer, v);
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append4_no_zeros(char* buffer, T v)
{
if (v < 100)
return append2_no_zeros(buffer, v);
else if (v < 1000)
return append3(buffer, v);
else
return append4(buffer, v);
}
template <typename T>
inline _LIBCPP_INLINE_VISIBILITY char*
append8_no_zeros(char* buffer, T v)
{
if (v < 10000)
{
buffer = append4_no_zeros(buffer, v);
}
else
{
buffer = append4_no_zeros(buffer, v / 10000);
buffer = append4(buffer, v % 10000);
}
return buffer;
}
char*
__u32toa(uint32_t value, char* buffer)
{
if (value < 100000000)
{
buffer = append8_no_zeros(buffer, value);
}
else
{
// value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
buffer = append2_no_zeros(buffer, a);
buffer = append4(buffer, value / 10000);
buffer = append4(buffer, value % 10000);
}
return buffer;
}
char*
__u64toa(uint64_t value, char* buffer)
{
if (value < 100000000)
{
uint32_t v = static_cast<uint32_t>(value);
buffer = append8_no_zeros(buffer, v);
}
else if (value < 10000000000000000)
{
const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
buffer = append8_no_zeros(buffer, v0);
buffer = append4(buffer, v1 / 10000);
buffer = append4(buffer, v1 % 10000);
}
else
{
const uint32_t a =
static_cast<uint32_t>(value / 10000000000000000); // 1 to 1844
value %= 10000000000000000;
buffer = append4_no_zeros(buffer, a);
const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
buffer = append4(buffer, v0 / 10000);
buffer = append4(buffer, v0 % 10000);
buffer = append4(buffer, v1 / 10000);
buffer = append4(buffer, v1 % 10000);
}
return buffer;
}
} // namespace __itoa
_LIBCPP_END_NAMESPACE_STD

233
lib/libcxx/src/chrono.cpp Normal file
View File

@ -0,0 +1,233 @@
//===------------------------- chrono.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "chrono"
#include "cerrno" // errno
#include "system_error" // __throw_system_error
#include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
#include "include/apple_availability.h"
#if !defined(__APPLE__)
#define _LIBCPP_USE_CLOCK_GETTIME
#endif // __APPLE__
#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRA_LEAN
#include <windows.h>
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#include <winapifamily.h>
#endif
#else
#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
#include <sys/time.h> // for gettimeofday and timeval
#endif // !defined(CLOCK_REALTIME)
#endif // defined(_LIBCPP_WIN32API)
#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
#if __APPLE__
#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
#error "Monotonic clock not implemented"
#endif
#endif
#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
#pragma comment(lib, "rt")
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
namespace chrono
{
// system_clock
const bool system_clock::is_steady;
system_clock::time_point
system_clock::now() _NOEXCEPT
{
#if defined(_LIBCPP_WIN32API)
// FILETIME is in 100ns units
using filetime_duration =
_VSTD::chrono::duration<__int64,
_VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
nanoseconds::period>>;
// The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};
FILETIME ft;
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
GetSystemTimePreciseAsFileTime(&ft);
#else
GetSystemTimeAsFileTime(&ft);
#endif
#else
GetSystemTimeAsFileTime(&ft);
#endif
filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
static_cast<__int64>(ft.dwLowDateTime)};
return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
#else
#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
struct timespec tp;
if (0 != clock_gettime(CLOCK_REALTIME, &tp))
__throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
#else
timeval tv;
gettimeofday(&tv, 0);
return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
#endif
}
time_t
system_clock::to_time_t(const time_point& t) _NOEXCEPT
{
return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
}
system_clock::time_point
system_clock::from_time_t(time_t t) _NOEXCEPT
{
return system_clock::time_point(seconds(t));
}
#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
// steady_clock
//
// Warning: If this is not truly steady, then it is non-conforming. It is
// better for it to not exist and have the rest of libc++ use system_clock
// instead.
const bool steady_clock::is_steady;
#if defined(__APPLE__)
// Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
struct timespec tp;
if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
__throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}
#else
// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
// are run time constants supplied by the OS. This clock has no relationship
// to the Gregorian calendar. It's main use is as a high resolution timer.
// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
// for that case as an optimization.
static
steady_clock::rep
steady_simplified()
{
return static_cast<steady_clock::rep>(mach_absolute_time());
}
static
double
compute_steady_factor()
{
mach_timebase_info_data_t MachInfo;
mach_timebase_info(&MachInfo);
return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}
static
steady_clock::rep
steady_full()
{
static const double factor = compute_steady_factor();
return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
}
typedef steady_clock::rep (*FP)();
static
FP
init_steady_clock()
{
mach_timebase_info_data_t MachInfo;
mach_timebase_info(&MachInfo);
if (MachInfo.numer == MachInfo.denom)
return &steady_simplified;
return &steady_full;
}
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
static FP fp = init_steady_clock();
return time_point(duration(fp()));
}
#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
#elif defined(_LIBCPP_WIN32API)
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says:
// If the function fails, the return value is zero. <snip>
// On systems that run Windows XP or later, the function will always succeed
// and will thus never return zero.
static LARGE_INTEGER
__QueryPerformanceFrequency()
{
LARGE_INTEGER val;
(void) QueryPerformanceFrequency(&val);
return val;
}
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
static const LARGE_INTEGER freq = __QueryPerformanceFrequency();
LARGE_INTEGER counter;
(void) QueryPerformanceCounter(&counter);
return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
}
#elif defined(CLOCK_MONOTONIC)
// On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
// time functions in the nanosecond range. Thus, they are the only acceptable
// implementations of steady_clock.
#ifdef __APPLE__
#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
#endif
steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
struct timespec tp;
if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
__throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}
#else
#error "Monotonic clock not implemented"
#endif
#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,93 @@
//===-------------------- condition_variable.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "condition_variable"
#include "thread"
#include "system_error"
#include "__undef_macros"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
// ~condition_variable is defined elsewhere.
void
condition_variable::notify_one() _NOEXCEPT
{
__libcpp_condvar_signal(&__cv_);
}
void
condition_variable::notify_all() _NOEXCEPT
{
__libcpp_condvar_broadcast(&__cv_);
}
void
condition_variable::wait(unique_lock<mutex>& lk) _NOEXCEPT
{
if (!lk.owns_lock())
__throw_system_error(EPERM,
"condition_variable::wait: mutex not locked");
int ec = __libcpp_condvar_wait(&__cv_, lk.mutex()->native_handle());
if (ec)
__throw_system_error(ec, "condition_variable wait failed");
}
void
condition_variable::__do_timed_wait(unique_lock<mutex>& lk,
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) _NOEXCEPT
{
using namespace chrono;
if (!lk.owns_lock())
__throw_system_error(EPERM,
"condition_variable::timed wait: mutex not locked");
nanoseconds d = tp.time_since_epoch();
if (d > nanoseconds(0x59682F000000E941))
d = nanoseconds(0x59682F000000E941);
__libcpp_timespec_t ts;
seconds s = duration_cast<seconds>(d);
typedef decltype(ts.tv_sec) ts_sec;
_LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
if (s.count() < ts_sec_max)
{
ts.tv_sec = static_cast<ts_sec>(s.count());
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
}
else
{
ts.tv_sec = ts_sec_max;
ts.tv_nsec = giga::num - 1;
}
int ec = __libcpp_condvar_timedwait(&__cv_, lk.mutex()->native_handle(), &ts);
if (ec != 0 && ec != ETIMEDOUT)
__throw_system_error(ec, "condition_variable timed_wait failed");
}
void
notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
{
auto& tl_ptr = __thread_local_data();
// If this thread was not created using std::thread then it will not have
// previously allocated.
if (tl_ptr.get() == nullptr) {
tl_ptr.set_pointer(new __thread_struct);
}
__thread_local_data()->notify_all_at_thread_exit(&cond, lk.release());
}
_LIBCPP_END_NAMESPACE_STD
#endif // !_LIBCPP_HAS_NO_THREADS

View File

@ -0,0 +1,46 @@
//===---------------- condition_variable_destructor.cpp ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Define ~condition_variable.
//
// On some platforms ~condition_variable has been made trivial and the
// definition is only provided for ABI compatibility.
#include "__config"
#include "__threading_support"
#if !defined(_LIBCPP_HAS_NO_THREADS)
# if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION)
# define NEEDS_CONDVAR_DESTRUCTOR
# endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef NEEDS_CONDVAR_DESTRUCTOR
class _LIBCPP_TYPE_VIS condition_variable
{
__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
public:
_LIBCPP_INLINE_VISIBILITY
constexpr condition_variable() noexcept = default;
~condition_variable();
condition_variable(const condition_variable&) = delete;
condition_variable& operator=(const condition_variable&) = delete;
};
condition_variable::~condition_variable()
{
__libcpp_condvar_destroy(&__cv_);
}
#endif
_LIBCPP_END_NAMESPACE_STD

578
lib/libcxx/src/debug.cpp Normal file
View File

@ -0,0 +1,578 @@
//===-------------------------- debug.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#include "__debug"
#include "functional"
#include "algorithm"
#include "string"
#include "cstdio"
#include "__hash_table"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "mutex"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
std::string __libcpp_debug_info::what() const {
string msg = __file_;
msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
msg += __pred_;
msg += "' failed. ";
msg += __msg_;
return msg;
}
_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
std::fprintf(stderr, "%s\n", info.what().c_str());
std::abort();
}
_LIBCPP_SAFE_STATIC __libcpp_debug_function_type
__libcpp_debug_function = __libcpp_abort_debug_function;
bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
__libcpp_debug_function = __func;
return true;
}
_LIBCPP_FUNC_VIS
__libcpp_db*
__get_db()
{
static _LIBCPP_NO_DESTROY __libcpp_db db;
return &db;
}
_LIBCPP_FUNC_VIS
const __libcpp_db*
__get_const_db()
{
return __get_db();
}
namespace
{
#ifndef _LIBCPP_HAS_NO_THREADS
typedef mutex mutex_type;
typedef lock_guard<mutex_type> WLock;
typedef lock_guard<mutex_type> RLock;
mutex_type&
mut()
{
static _LIBCPP_NO_DESTROY mutex_type m;
return m;
}
#endif // !_LIBCPP_HAS_NO_THREADS
} // unnamed namespace
__i_node::~__i_node()
{
if (__next_)
{
__next_->~__i_node();
free(__next_);
}
}
__c_node::~__c_node()
{
free(beg_);
if (__next_)
{
__next_->~__c_node();
free(__next_);
}
}
__libcpp_db::__libcpp_db()
: __cbeg_(nullptr),
__cend_(nullptr),
__csz_(0),
__ibeg_(nullptr),
__iend_(nullptr),
__isz_(0)
{
}
__libcpp_db::~__libcpp_db()
{
if (__cbeg_)
{
for (__c_node** p = __cbeg_; p != __cend_; ++p)
{
if (*p != nullptr)
{
(*p)->~__c_node();
free(*p);
}
}
free(__cbeg_);
}
if (__ibeg_)
{
for (__i_node** p = __ibeg_; p != __iend_; ++p)
{
if (*p != nullptr)
{
(*p)->~__i_node();
free(*p);
}
}
free(__ibeg_);
}
}
void*
__libcpp_db::__find_c_from_i(void* __i) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
_LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
}
void
__libcpp_db::__insert_ic(void* __i, const void* __c)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
if (__cbeg_ == __cend_)
return;
size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* c = __cbeg_[hc];
if (c == nullptr)
return;
while (c->__c_ != __c)
{
c = c->__next_;
if (c == nullptr)
return;
}
__i_node* i = __insert_iterator(__i);
c->__add(i);
i->__c_ = c;
}
void
__libcpp_db::__insert_c(void* __c, __libcpp_db::_InsertConstruct *__fn)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
{
size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
__c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(__c_node*)));
if (cbeg == nullptr)
__throw_bad_alloc();
for (__c_node** p = __cbeg_; p != __cend_; ++p)
{
__c_node* q = *p;
while (q != nullptr)
{
size_t h = hash<void*>()(q->__c_) % nc;
__c_node* r = q->__next_;
q->__next_ = cbeg[h];
cbeg[h] = q;
q = r;
}
}
free(__cbeg_);
__cbeg_ = cbeg;
__cend_ = __cbeg_ + nc;
}
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
void *buf = malloc(sizeof(__c_node));
if (buf == nullptr)
__throw_bad_alloc();
__cbeg_[hc] = __fn(buf, __c, p);
++__csz_;
}
void
__libcpp_db::__erase_i(void* __i)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
if (__ibeg_ != __iend_)
{
size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
__i_node* p = __ibeg_[hi];
if (p != nullptr)
{
__i_node* q = nullptr;
while (p->__i_ != __i)
{
q = p;
p = p->__next_;
if (p == nullptr)
return;
}
if (q == nullptr)
__ibeg_[hi] = p->__next_;
else
q->__next_ = p->__next_;
__c_node* c = p->__c_;
--__isz_;
if (c != nullptr)
c->__remove(p);
free(p);
}
}
}
void
__libcpp_db::__invalidate_all(void* __c)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
if (__cend_ != __cbeg_)
{
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
if (p == nullptr)
return;
while (p->__c_ != __c)
{
p = p->__next_;
if (p == nullptr)
return;
}
while (p->end_ != p->beg_)
{
--p->end_;
(*p->end_)->__c_ = nullptr;
}
}
}
__c_node*
__libcpp_db::__find_c_and_lock(void* __c) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
mut().lock();
#endif
if (__cend_ == __cbeg_)
{
#ifndef _LIBCPP_HAS_NO_THREADS
mut().unlock();
#endif
return nullptr;
}
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
if (p == nullptr)
{
#ifndef _LIBCPP_HAS_NO_THREADS
mut().unlock();
#endif
return nullptr;
}
while (p->__c_ != __c)
{
p = p->__next_;
if (p == nullptr)
{
#ifndef _LIBCPP_HAS_NO_THREADS
mut().unlock();
#endif
return nullptr;
}
}
return p;
}
__c_node*
__libcpp_db::__find_c(void* __c) const
{
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
_LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
while (p->__c_ != __c)
{
p = p->__next_;
_LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
}
return p;
}
void
__libcpp_db::unlock() const
{
#ifndef _LIBCPP_HAS_NO_THREADS
mut().unlock();
#endif
}
void
__libcpp_db::__erase_c(void* __c)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
if (__cend_ != __cbeg_)
{
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
if (p == nullptr)
return;
__c_node* q = nullptr;
_LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
while (p->__c_ != __c)
{
q = p;
p = p->__next_;
if (p == nullptr)
return;
_LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
}
if (q == nullptr)
__cbeg_[hc] = p->__next_;
else
q->__next_ = p->__next_;
while (p->end_ != p->beg_)
{
--p->end_;
(*p->end_)->__c_ = nullptr;
}
free(p->beg_);
free(p);
--__csz_;
}
}
void
__libcpp_db::__iterator_copy(void* __i, const void* __i0)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
__i_node* i0 = __find_iterator(__i0);
__c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
if (i == nullptr && i0 != nullptr)
i = __insert_iterator(__i);
__c_node* c = i != nullptr ? i->__c_ : nullptr;
if (c != c0)
{
if (c != nullptr)
c->__remove(i);
if (i != nullptr)
{
i->__c_ = nullptr;
if (c0 != nullptr)
{
i->__c_ = c0;
i->__c_->__add(i);
}
}
}
}
bool
__libcpp_db::__dereferenceable(const void* __i) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
}
bool
__libcpp_db::__decrementable(const void* __i) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
}
bool
__libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
}
bool
__libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
}
bool
__libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
{
#ifndef _LIBCPP_HAS_NO_THREADS
RLock _(mut());
#endif
__i_node* i = __find_iterator(__i);
__i_node* j = __find_iterator(__j);
__c_node* ci = i != nullptr ? i->__c_ : nullptr;
__c_node* cj = j != nullptr ? j->__c_ : nullptr;
return ci != nullptr && ci == cj;
}
void
__libcpp_db::swap(void* c1, void* c2)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p1 = __cbeg_[hc];
_LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
while (p1->__c_ != c1)
{
p1 = p1->__next_;
_LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
}
hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p2 = __cbeg_[hc];
_LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
while (p2->__c_ != c2)
{
p2 = p2->__next_;
_LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
}
std::swap(p1->beg_, p2->beg_);
std::swap(p1->end_, p2->end_);
std::swap(p1->cap_, p2->cap_);
for (__i_node** p = p1->beg_; p != p1->end_; ++p)
(*p)->__c_ = p1;
for (__i_node** p = p2->beg_; p != p2->end_; ++p)
(*p)->__c_ = p2;
}
void
__libcpp_db::__insert_i(void* __i)
{
#ifndef _LIBCPP_HAS_NO_THREADS
WLock _(mut());
#endif
__insert_iterator(__i);
}
void
__c_node::__add(__i_node* i)
{
if (end_ == cap_)
{
size_t nc = 2*static_cast<size_t>(cap_ - beg_);
if (nc == 0)
nc = 1;
__i_node** beg =
static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
if (beg == nullptr)
__throw_bad_alloc();
if (nc > 1)
memcpy(beg, beg_, nc/2*sizeof(__i_node*));
free(beg_);
beg_ = beg;
end_ = beg_ + nc/2;
cap_ = beg_ + nc;
}
*end_++ = i;
}
// private api
_LIBCPP_HIDDEN
__i_node*
__libcpp_db::__insert_iterator(void* __i)
{
if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
{
size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
__i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(__i_node*)));
if (ibeg == nullptr)
__throw_bad_alloc();
for (__i_node** p = __ibeg_; p != __iend_; ++p)
{
__i_node* q = *p;
while (q != nullptr)
{
size_t h = hash<void*>()(q->__i_) % nc;
__i_node* r = q->__next_;
q->__next_ = ibeg[h];
ibeg[h] = q;
q = r;
}
}
free(__ibeg_);
__ibeg_ = ibeg;
__iend_ = __ibeg_ + nc;
}
size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
__i_node* p = __ibeg_[hi];
__i_node* r = __ibeg_[hi] =
static_cast<__i_node*>(malloc(sizeof(__i_node)));
if (r == nullptr)
__throw_bad_alloc();
::new(r) __i_node(__i, p, nullptr);
++__isz_;
return r;
}
_LIBCPP_HIDDEN
__i_node*
__libcpp_db::__find_iterator(const void* __i) const
{
__i_node* r = nullptr;
if (__ibeg_ != __iend_)
{
size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
{
if (nd->__i_ == __i)
{
r = nd;
break;
}
}
}
return r;
}
_LIBCPP_HIDDEN
void
__c_node::__remove(__i_node* p)
{
__i_node** r = find(beg_, end_, p);
_LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
if (--end_ != r)
memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,35 @@
//===------------------------ exception.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "exception"
#include "new"
#include "typeinfo"
#if defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
#include <cxxabi.h>
using namespace __cxxabiv1;
#define HAVE_DEPENDENT_EH_ABI 1
#endif
#if defined(_LIBCPP_ABI_MICROSOFT)
#include "support/runtime/exception_msvc.ipp"
#include "support/runtime/exception_pointer_msvc.ipp"
#elif defined(_LIBCPPABI_VERSION)
#include "support/runtime/exception_libcxxabi.ipp"
#include "support/runtime/exception_pointer_cxxabi.ipp"
#elif defined(LIBCXXRT)
#include "support/runtime/exception_libcxxrt.ipp"
#include "support/runtime/exception_pointer_cxxabi.ipp"
#elif defined(__GLIBCXX__)
#include "support/runtime/exception_glibcxx.ipp"
#include "support/runtime/exception_pointer_glibcxx.ipp"
#else
#include "include/atomic_support.h"
#include "support/runtime/exception_fallback.ipp"
#include "support/runtime/exception_pointer_unimplemented.ipp"
#endif

View File

@ -0,0 +1,161 @@
//===------------------------ memory_resource.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "experimental/memory_resource"
#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
#include "atomic"
#elif !defined(_LIBCPP_HAS_NO_THREADS)
#include "mutex"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
// memory_resource
//memory_resource::~memory_resource() {}
// new_delete_resource()
class _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
: public memory_resource
{
void *do_allocate(size_t size, size_t align) override {
#ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
if (__is_overaligned_for_new(align))
__throw_bad_alloc();
#endif
return _VSTD::__libcpp_allocate(size, align);
}
void do_deallocate(void *p, size_t n, size_t align) override {
_VSTD::__libcpp_deallocate(p, n, align);
}
bool do_is_equal(memory_resource const & other) const _NOEXCEPT override
{ return &other == this; }
public:
~__new_delete_memory_resource_imp() override = default;
};
// null_memory_resource()
class _LIBCPP_TYPE_VIS __null_memory_resource_imp
: public memory_resource
{
public:
~__null_memory_resource_imp() = default;
protected:
virtual void* do_allocate(size_t, size_t) {
__throw_bad_alloc();
}
virtual void do_deallocate(void *, size_t, size_t) {}
virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
{ return &__other == this; }
};
namespace {
union ResourceInitHelper {
struct {
__new_delete_memory_resource_imp new_delete_res;
__null_memory_resource_imp null_res;
} resources;
char dummy;
_LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
~ResourceInitHelper() {}
};
// Detect if the init_priority attribute is supported.
#if (defined(_LIBCPP_COMPILER_GCC) && defined(__APPLE__)) \
|| defined(_LIBCPP_COMPILER_MSVC)
// GCC on Apple doesn't support the init priority attribute,
// and MSVC doesn't support any GCC attributes.
# define _LIBCPP_INIT_PRIORITY_MAX
#else
# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101)))
#endif
// When compiled in C++14 this initialization should be a constant expression.
// Only in C++11 is "init_priority" needed to ensure initialization order.
#if _LIBCPP_STD_VER > 11
_LIBCPP_SAFE_STATIC
#endif
ResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX;
} // end namespace
memory_resource * new_delete_resource() _NOEXCEPT {
return &res_init.resources.new_delete_res;
}
memory_resource * null_memory_resource() _NOEXCEPT {
return &res_init.resources.null_res;
}
// default_memory_resource()
static memory_resource *
__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
{
#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
_LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
if (set) {
new_res = new_res ? new_res : new_delete_resource();
// TODO: Can a weaker ordering be used?
return _VSTD::atomic_exchange_explicit(
&__res, new_res, memory_order_acq_rel);
}
else {
return _VSTD::atomic_load_explicit(
&__res, memory_order_acquire);
}
#elif !defined(_LIBCPP_HAS_NO_THREADS)
_LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
static mutex res_lock;
if (set) {
new_res = new_res ? new_res : new_delete_resource();
lock_guard<mutex> guard(res_lock);
memory_resource * old_res = res;
res = new_res;
return old_res;
} else {
lock_guard<mutex> guard(res_lock);
return res;
}
#else
_LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
if (set) {
new_res = new_res ? new_res : new_delete_resource();
memory_resource * old_res = res;
res = new_res;
return old_res;
} else {
return res;
}
#endif
}
memory_resource * get_default_resource() _NOEXCEPT
{
return __default_memory_resource();
}
memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
{
return __default_memory_resource(true, __new_res);
}
_LIBCPP_END_NAMESPACE_LFTS_PMR

View File

@ -0,0 +1,398 @@
//===------------------ directory_iterator.cpp ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "filesystem"
#include "__config"
#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#endif
#include <errno.h>
#include "filesystem_common.h"
_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
namespace detail {
namespace {
#if !defined(_LIBCPP_WIN32API)
#if defined(DT_BLK)
template <class DirEntT, class = decltype(DirEntT::d_type)>
static file_type get_file_type(DirEntT* ent, int) {
switch (ent->d_type) {
case DT_BLK:
return file_type::block;
case DT_CHR:
return file_type::character;
case DT_DIR:
return file_type::directory;
case DT_FIFO:
return file_type::fifo;
case DT_LNK:
return file_type::symlink;
case DT_REG:
return file_type::regular;
case DT_SOCK:
return file_type::socket;
// Unlike in lstat, hitting "unknown" here simply means that the underlying
// filesystem doesn't support d_type. Report is as 'none' so we correctly
// set the cache to empty.
case DT_UNKNOWN:
break;
}
return file_type::none;
}
#endif // defined(DT_BLK)
template <class DirEntT>
static file_type get_file_type(DirEntT* ent, long) {
return file_type::none;
}
static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
error_code& ec) {
struct dirent* dir_entry_ptr = nullptr;
errno = 0; // zero errno in order to detect errors
ec.clear();
if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
if (errno)
ec = capture_errno();
return {};
} else {
return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
}
}
#else
static file_type get_file_type(const WIN32_FIND_DATA& data) {
//auto attrs = data.dwFileAttributes;
// FIXME(EricWF)
return file_type::unknown;
}
static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
return (data.nFileSizeHigh * (MAXDWORD + 1)) + data.nFileSizeLow;
}
static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
ULARGE_INTEGER tmp;
const FILETIME& time = data.ftLastWriteTime;
tmp.u.LowPart = time.dwLowDateTime;
tmp.u.HighPart = time.dwHighDateTime;
return file_time_type(file_time_type::duration(tmp.QuadPart));
}
#endif
} // namespace
} // namespace detail
using detail::ErrorHandler;
#if defined(_LIBCPP_WIN32API)
class __dir_stream {
public:
__dir_stream() = delete;
__dir_stream& operator=(const __dir_stream&) = delete;
__dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_),
__root_(move(__ds.__root_)),
__entry_(move(__ds.__entry_)) {
__ds.__stream_ = INVALID_HANDLE_VALUE;
}
__dir_stream(const path& root, directory_options opts, error_code& ec)
: __stream_(INVALID_HANDLE_VALUE), __root_(root) {
__stream_ = ::FindFirstFile(root.c_str(), &__data_);
if (__stream_ == INVALID_HANDLE_VALUE) {
ec = error_code(::GetLastError(), generic_category());
const bool ignore_permission_denied =
bool(opts & directory_options::skip_permission_denied);
if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
ec.clear();
return;
}
}
~__dir_stream() noexcept {
if (__stream_ == INVALID_HANDLE_VALUE)
return;
close();
}
bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
bool advance(error_code& ec) {
while (::FindNextFile(__stream_, &__data_)) {
if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
continue;
// FIXME: Cache more of this
//directory_entry::__cached_data cdata;
//cdata.__type_ = get_file_type(__data_);
//cdata.__size_ = get_file_size(__data_);
//cdata.__write_time_ = get_write_time(__data_);
__entry_.__assign_iter_entry(
__root_ / __data_.cFileName,
directory_entry::__create_iter_result(detail::get_file_type(__data)));
return true;
}
ec = error_code(::GetLastError(), generic_category());
close();
return false;
}
private:
error_code close() noexcept {
error_code ec;
if (!::FindClose(__stream_))
ec = error_code(::GetLastError(), generic_category());
__stream_ = INVALID_HANDLE_VALUE;
return ec;
}
HANDLE __stream_{INVALID_HANDLE_VALUE};
WIN32_FIND_DATA __data_;
public:
path __root_;
directory_entry __entry_;
};
#else
class __dir_stream {
public:
__dir_stream() = delete;
__dir_stream& operator=(const __dir_stream&) = delete;
__dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_),
__root_(move(other.__root_)),
__entry_(move(other.__entry_)) {
other.__stream_ = nullptr;
}
__dir_stream(const path& root, directory_options opts, error_code& ec)
: __stream_(nullptr), __root_(root) {
if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
ec = detail::capture_errno();
const bool allow_eacess =
bool(opts & directory_options::skip_permission_denied);
if (allow_eacess && ec.value() == EACCES)
ec.clear();
return;
}
advance(ec);
}
~__dir_stream() noexcept {
if (__stream_)
close();
}
bool good() const noexcept { return __stream_ != nullptr; }
bool advance(error_code& ec) {
while (true) {
auto str_type_pair = detail::posix_readdir(__stream_, ec);
auto& str = str_type_pair.first;
if (str == "." || str == "..") {
continue;
} else if (ec || str.empty()) {
close();
return false;
} else {
__entry_.__assign_iter_entry(
__root_ / str,
directory_entry::__create_iter_result(str_type_pair.second));
return true;
}
}
}
private:
error_code close() noexcept {
error_code m_ec;
if (::closedir(__stream_) == -1)
m_ec = detail::capture_errno();
__stream_ = nullptr;
return m_ec;
}
DIR* __stream_{nullptr};
public:
path __root_;
directory_entry __entry_;
};
#endif
// directory_iterator
directory_iterator::directory_iterator(const path& p, error_code* ec,
directory_options opts) {
ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
error_code m_ec;
__imp_ = make_shared<__dir_stream>(p, opts, m_ec);
if (ec)
*ec = m_ec;
if (!__imp_->good()) {
__imp_.reset();
if (m_ec)
err.report(m_ec);
}
}
directory_iterator& directory_iterator::__increment(error_code* ec) {
_LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
ErrorHandler<void> err("directory_iterator::operator++()", ec);
error_code m_ec;
if (!__imp_->advance(m_ec)) {
path root = move(__imp_->__root_);
__imp_.reset();
if (m_ec)
err.report(m_ec, "at root \"%s\"", root);
}
return *this;
}
directory_entry const& directory_iterator::__dereference() const {
_LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
return __imp_->__entry_;
}
// recursive_directory_iterator
struct recursive_directory_iterator::__shared_imp {
stack<__dir_stream> __stack_;
directory_options __options_;
};
recursive_directory_iterator::recursive_directory_iterator(
const path& p, directory_options opt, error_code* ec)
: __imp_(nullptr), __rec_(true) {
ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
error_code m_ec;
__dir_stream new_s(p, opt, m_ec);
if (m_ec)
err.report(m_ec);
if (m_ec || !new_s.good())
return;
__imp_ = make_shared<__shared_imp>();
__imp_->__options_ = opt;
__imp_->__stack_.push(move(new_s));
}
void recursive_directory_iterator::__pop(error_code* ec) {
_LIBCPP_ASSERT(__imp_, "Popping the end iterator");
if (ec)
ec->clear();
__imp_->__stack_.pop();
if (__imp_->__stack_.size() == 0)
__imp_.reset();
else
__advance(ec);
}
directory_options recursive_directory_iterator::options() const {
return __imp_->__options_;
}
int recursive_directory_iterator::depth() const {
return __imp_->__stack_.size() - 1;
}
const directory_entry& recursive_directory_iterator::__dereference() const {
return __imp_->__stack_.top().__entry_;
}
recursive_directory_iterator&
recursive_directory_iterator::__increment(error_code* ec) {
if (ec)
ec->clear();
if (recursion_pending()) {
if (__try_recursion(ec) || (ec && *ec))
return *this;
}
__rec_ = true;
__advance(ec);
return *this;
}
void recursive_directory_iterator::__advance(error_code* ec) {
ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
const directory_iterator end_it;
auto& stack = __imp_->__stack_;
error_code m_ec;
while (stack.size() > 0) {
if (stack.top().advance(m_ec))
return;
if (m_ec)
break;
stack.pop();
}
if (m_ec) {
path root = move(stack.top().__root_);
__imp_.reset();
err.report(m_ec, "at root \"%s\"", root);
} else {
__imp_.reset();
}
}
bool recursive_directory_iterator::__try_recursion(error_code* ec) {
ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
auto& curr_it = __imp_->__stack_.top();
bool skip_rec = false;
error_code m_ec;
if (!rec_sym) {
file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
if (m_ec && status_known(st))
m_ec.clear();
if (m_ec || is_symlink(st) || !is_directory(st))
skip_rec = true;
} else {
file_status st(curr_it.__entry_.__get_ft(&m_ec));
if (m_ec && status_known(st))
m_ec.clear();
if (m_ec || !is_directory(st))
skip_rec = true;
}
if (!skip_rec) {
__dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
if (new_it.good()) {
__imp_->__stack_.push(move(new_it));
return true;
}
}
if (m_ec) {
const bool allow_eacess =
bool(__imp_->__options_ & directory_options::skip_permission_denied);
if (m_ec.value() == EACCES && allow_eacess) {
if (ec)
ec->clear();
} else {
path at_ent = move(curr_it.__entry_.__p_);
__imp_.reset();
err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
}
}
return false;
}
_LIBCPP_END_NAMESPACE_FILESYSTEM

View File

@ -0,0 +1,435 @@
//===----------------------------------------------------------------------===////
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===////
#ifndef FILESYSTEM_COMMON_H
#define FILESYSTEM_COMMON_H
#include "__config"
#include "filesystem"
#include "array"
#include "chrono"
#include "cstdlib"
#include "climits"
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/time.h> // for ::utimes as used in __last_write_time
#include <fcntl.h> /* values for fchmodat */
#include "../include/apple_availability.h"
#if !defined(__APPLE__)
// We can use the presence of UTIME_OMIT to detect platforms that provide
// utimensat.
#if defined(UTIME_OMIT)
#define _LIBCPP_USE_UTIMENSAT
#endif
#endif
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
namespace detail {
namespace {
static string format_string_imp(const char* msg, ...) {
// we might need a second shot at this, so pre-emptivly make a copy
struct GuardVAList {
va_list& target;
bool active = true;
GuardVAList(va_list& target) : target(target), active(true) {}
void clear() {
if (active)
va_end(target);
active = false;
}
~GuardVAList() {
if (active)
va_end(target);
}
};
va_list args;
va_start(args, msg);
GuardVAList args_guard(args);
va_list args_cp;
va_copy(args_cp, args);
GuardVAList args_copy_guard(args_cp);
std::string result;
array<char, 256> local_buff;
size_t size_with_null = local_buff.size();
auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
args_copy_guard.clear();
// handle empty expansion
if (ret == 0)
return result;
if (static_cast<size_t>(ret) < size_with_null) {
result.assign(local_buff.data(), static_cast<size_t>(ret));
return result;
}
// we did not provide a long enough buffer on our first attempt. The
// return value is the number of bytes (excluding the null byte) that are
// needed for formatting.
size_with_null = static_cast<size_t>(ret) + 1;
result.__resize_default_init(size_with_null - 1);
ret = ::vsnprintf(&result[0], size_with_null, msg, args);
_LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
return result;
}
const char* unwrap(string const& s) { return s.c_str(); }
const char* unwrap(path const& p) { return p.native().c_str(); }
template <class Arg>
Arg const& unwrap(Arg const& a) {
static_assert(!is_class<Arg>::value, "cannot pass class here");
return a;
}
template <class... Args>
string format_string(const char* fmt, Args const&... args) {
return format_string_imp(fmt, unwrap(args)...);
}
error_code capture_errno() {
_LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
return error_code(errno, generic_category());
}
template <class T>
T error_value();
template <>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
template <>
bool error_value<bool>() {
return false;
}
template <>
uintmax_t error_value<uintmax_t>() {
return uintmax_t(-1);
}
template <>
_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
return file_time_type::min();
}
template <>
path error_value<path>() {
return {};
}
template <class T>
struct ErrorHandler {
const char* func_name;
error_code* ec = nullptr;
const path* p1 = nullptr;
const path* p2 = nullptr;
ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
const path* p2 = nullptr)
: func_name(fname), ec(ec), p1(p1), p2(p2) {
if (ec)
ec->clear();
}
T report(const error_code& m_ec) const {
if (ec) {
*ec = m_ec;
return error_value<T>();
}
string what = string("in ") + func_name;
switch (bool(p1) + bool(p2)) {
case 0:
__throw_filesystem_error(what, m_ec);
case 1:
__throw_filesystem_error(what, *p1, m_ec);
case 2:
__throw_filesystem_error(what, *p1, *p2, m_ec);
}
_LIBCPP_UNREACHABLE();
}
template <class... Args>
T report(const error_code& m_ec, const char* msg, Args const&... args) const {
if (ec) {
*ec = m_ec;
return error_value<T>();
}
string what =
string("in ") + func_name + ": " + format_string(msg, args...);
switch (bool(p1) + bool(p2)) {
case 0:
__throw_filesystem_error(what, m_ec);
case 1:
__throw_filesystem_error(what, *p1, m_ec);
case 2:
__throw_filesystem_error(what, *p1, *p2, m_ec);
}
_LIBCPP_UNREACHABLE();
}
T report(errc const& err) const { return report(make_error_code(err)); }
template <class... Args>
T report(errc const& err, const char* msg, Args const&... args) const {
return report(make_error_code(err), msg, args...);
}
private:
ErrorHandler(ErrorHandler const&) = delete;
ErrorHandler& operator=(ErrorHandler const&) = delete;
};
using chrono::duration;
using chrono::duration_cast;
using TimeSpec = struct ::timespec;
using StatT = struct ::stat;
template <class FileTimeT, class TimeT,
bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
struct time_util_base {
using rep = typename FileTimeT::rep;
using fs_duration = typename FileTimeT::duration;
using fs_seconds = duration<rep>;
using fs_nanoseconds = duration<rep, nano>;
using fs_microseconds = duration<rep, micro>;
static constexpr rep max_seconds =
duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
static constexpr rep max_nsec =
duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
fs_seconds(max_seconds))
.count();
static constexpr rep min_seconds =
duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
static constexpr rep min_nsec_timespec =
duration_cast<fs_nanoseconds>(
(FileTimeT::duration::min() - fs_seconds(min_seconds)) +
fs_seconds(1))
.count();
private:
#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
static constexpr fs_duration get_min_nsecs() {
return duration_cast<fs_duration>(
fs_nanoseconds(min_nsec_timespec) -
duration_cast<fs_nanoseconds>(fs_seconds(1)));
}
// Static assert that these values properly round trip.
static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
FileTimeT::duration::min(),
"value doesn't roundtrip");
static constexpr bool check_range() {
// This kinda sucks, but it's what happens when we don't have __int128_t.
if (sizeof(TimeT) == sizeof(rep)) {
typedef duration<long long, ratio<3600 * 24 * 365> > Years;
return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
}
return max_seconds >= numeric_limits<TimeT>::max() &&
min_seconds <= numeric_limits<TimeT>::min();
}
static_assert(check_range(), "the representable range is unacceptable small");
#endif
};
template <class FileTimeT, class TimeT>
struct time_util_base<FileTimeT, TimeT, true> {
using rep = typename FileTimeT::rep;
using fs_duration = typename FileTimeT::duration;
using fs_seconds = duration<rep>;
using fs_nanoseconds = duration<rep, nano>;
using fs_microseconds = duration<rep, micro>;
static const rep max_seconds;
static const rep max_nsec;
static const rep min_seconds;
static const rep min_nsec_timespec;
};
template <class FileTimeT, class TimeT>
const typename FileTimeT::rep
time_util_base<FileTimeT, TimeT, true>::max_seconds =
duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
template <class FileTimeT, class TimeT>
const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
fs_seconds(max_seconds))
.count();
template <class FileTimeT, class TimeT>
const typename FileTimeT::rep
time_util_base<FileTimeT, TimeT, true>::min_seconds =
duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
template <class FileTimeT, class TimeT>
const typename FileTimeT::rep
time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
fs_seconds(min_seconds)) +
fs_seconds(1))
.count();
template <class FileTimeT, class TimeT, class TimeSpecT>
struct time_util : time_util_base<FileTimeT, TimeT> {
using Base = time_util_base<FileTimeT, TimeT>;
using Base::max_nsec;
using Base::max_seconds;
using Base::min_nsec_timespec;
using Base::min_seconds;
using typename Base::fs_duration;
using typename Base::fs_microseconds;
using typename Base::fs_nanoseconds;
using typename Base::fs_seconds;
public:
template <class CType, class ChronoType>
static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
ChronoType time) {
using Lim = numeric_limits<CType>;
if (time > Lim::max() || time < Lim::min())
return false;
*out = static_cast<CType>(time);
return true;
}
static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
if (tm.tv_sec >= 0) {
return tm.tv_sec < max_seconds ||
(tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
} else if (tm.tv_sec == (min_seconds - 1)) {
return tm.tv_nsec >= min_nsec_timespec;
} else {
return tm.tv_sec >= min_seconds;
}
}
static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
if (nsecs.count() < 0) {
secs = secs + fs_seconds(1);
nsecs = nsecs + fs_seconds(1);
}
using TLim = numeric_limits<TimeT>;
if (secs.count() >= 0)
return secs.count() <= TLim::max();
return secs.count() >= TLim::min();
}
static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
convert_from_timespec(TimeSpecT tm) {
if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
return FileTimeT(fs_seconds(tm.tv_sec) +
duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
} else { // tm.tv_sec < 0
auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
fs_nanoseconds(tm.tv_nsec));
auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
return FileTimeT(Dur);
}
}
template <class SubSecT>
static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
auto dur = tp.time_since_epoch();
auto sec_dur = duration_cast<fs_seconds>(dur);
auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
// The tv_nsec and tv_usec fields must not be negative so adjust accordingly
if (subsec_dur.count() < 0) {
if (sec_dur.count() > min_seconds) {
sec_dur = sec_dur - fs_seconds(1);
subsec_dur = subsec_dur + fs_seconds(1);
} else {
subsec_dur = fs_nanoseconds::zero();
}
}
return checked_set(sec_out, sec_dur.count()) &&
checked_set(subsec_out, subsec_dur.count());
}
static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
FileTimeT tp) {
if (!is_representable(tp))
return false;
return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
}
};
using fs_time = time_util<file_time_type, time_t, TimeSpec>;
#if defined(__APPLE__)
TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
#else
TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
#endif
// allow the utimes implementation to compile even it we're not going
// to use it.
bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
error_code& ec) {
using namespace chrono;
auto Convert = [](long nsec) {
using int_type = decltype(std::declval< ::timeval>().tv_usec);
auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
return static_cast<int_type>(dur);
};
struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
{TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
if (::utimes(p.c_str(), ConvertedTS) == -1) {
ec = capture_errno();
return true;
}
return false;
}
#if defined(_LIBCPP_USE_UTIMENSAT)
bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
error_code& ec) {
if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
ec = capture_errno();
return true;
}
return false;
}
#endif
bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
error_code& ec) {
#if !defined(_LIBCPP_USE_UTIMENSAT)
return posix_utimes(p, TS, ec);
#else
return posix_utimensat(p, TS, ec);
#endif
}
} // namespace
} // end namespace detail
_LIBCPP_END_NAMESPACE_FILESYSTEM
#endif // FILESYSTEM_COMMON_H

View File

@ -0,0 +1,54 @@
/*===-- int128_builtins.cpp - Implement __muloti4 --------------------------===
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
* ===----------------------------------------------------------------------===
*
* This file implements __muloti4, and is stolen from the compiler_rt library.
*
* FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
* and requires this builtin when sanitized. See llvm.org/PR30643
*
* ===----------------------------------------------------------------------===
*/
#include "__config"
#include "climits"
#if !defined(_LIBCPP_HAS_NO_INT128)
extern "C" __attribute__((no_sanitize("undefined"))) _LIBCPP_FUNC_VIS
__int128_t __muloti4(__int128_t a, __int128_t b, int* overflow) {
const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
const __int128_t MIN = (__int128_t)1 << (N - 1);
const __int128_t MAX = ~MIN;
*overflow = 0;
__int128_t result = a * b;
if (a == MIN) {
if (b != 0 && b != 1)
*overflow = 1;
return result;
}
if (b == MIN) {
if (a != 0 && a != 1)
*overflow = 1;
return result;
}
__int128_t sa = a >> (N - 1);
__int128_t abs_a = (a ^ sa) - sa;
__int128_t sb = b >> (N - 1);
__int128_t abs_b = (b ^ sb) - sb;
if (abs_a < 2 || abs_b < 2)
return result;
if (sa == sb) {
if (abs_a > MAX / abs_b)
*overflow = 1;
} else {
if (abs_a > MIN / -abs_b)
*overflow = 1;
}
return result;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
//===----------------------- functional.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "functional"
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
bad_function_call::~bad_function_call() _NOEXCEPT
{
}
const char*
bad_function_call::what() const _NOEXCEPT
{
return "std::bad_function_call";
}
#endif
_LIBCPP_END_NAMESPACE_STD

277
lib/libcxx/src/future.cpp Normal file
View File

@ -0,0 +1,277 @@
//===------------------------- future.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "future"
#include "string"
_LIBCPP_BEGIN_NAMESPACE_STD
class _LIBCPP_HIDDEN __future_error_category
: public __do_message
{
public:
virtual const char* name() const _NOEXCEPT;
virtual string message(int ev) const;
};
const char*
__future_error_category::name() const _NOEXCEPT
{
return "future";
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch"
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
#endif
string
__future_error_category::message(int ev) const
{
switch (static_cast<future_errc>(ev))
{
case future_errc(0): // For backwards compatibility with C++11 (LWG 2056)
case future_errc::broken_promise:
return string("The associated promise has been destructed prior "
"to the associated state becoming ready.");
case future_errc::future_already_retrieved:
return string("The future has already been retrieved from "
"the promise or packaged_task.");
case future_errc::promise_already_satisfied:
return string("The state of the promise has already been set.");
case future_errc::no_state:
return string("Operation not permitted on an object without "
"an associated state.");
}
return string("unspecified future_errc value\n");
}
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#endif
const error_category&
future_category() _NOEXCEPT
{
static __future_error_category __f;
return __f;
}
future_error::future_error(error_code __ec)
: logic_error(__ec.message()),
__ec_(__ec)
{
}
future_error::~future_error() _NOEXCEPT
{
}
void
__assoc_sub_state::__on_zero_shared() _NOEXCEPT
{
delete this;
}
void
__assoc_sub_state::set_value()
{
unique_lock<mutex> __lk(__mut_);
if (__has_value())
__throw_future_error(future_errc::promise_already_satisfied);
__state_ |= __constructed | ready;
__cv_.notify_all();
}
void
__assoc_sub_state::set_value_at_thread_exit()
{
unique_lock<mutex> __lk(__mut_);
if (__has_value())
__throw_future_error(future_errc::promise_already_satisfied);
__state_ |= __constructed;
__thread_local_data()->__make_ready_at_thread_exit(this);
}
void
__assoc_sub_state::set_exception(exception_ptr __p)
{
unique_lock<mutex> __lk(__mut_);
if (__has_value())
__throw_future_error(future_errc::promise_already_satisfied);
__exception_ = __p;
__state_ |= ready;
__cv_.notify_all();
}
void
__assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p)
{
unique_lock<mutex> __lk(__mut_);
if (__has_value())
__throw_future_error(future_errc::promise_already_satisfied);
__exception_ = __p;
__thread_local_data()->__make_ready_at_thread_exit(this);
}
void
__assoc_sub_state::__make_ready()
{
unique_lock<mutex> __lk(__mut_);
__state_ |= ready;
__cv_.notify_all();
}
void
__assoc_sub_state::copy()
{
unique_lock<mutex> __lk(__mut_);
__sub_wait(__lk);
if (__exception_ != nullptr)
rethrow_exception(__exception_);
}
void
__assoc_sub_state::wait()
{
unique_lock<mutex> __lk(__mut_);
__sub_wait(__lk);
}
void
__assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk)
{
if (!__is_ready())
{
if (__state_ & static_cast<unsigned>(deferred))
{
__state_ &= ~static_cast<unsigned>(deferred);
__lk.unlock();
__execute();
}
else
while (!__is_ready())
__cv_.wait(__lk);
}
}
void
__assoc_sub_state::__execute()
{
__throw_future_error(future_errc::no_state);
}
future<void>::future(__assoc_sub_state* __state)
: __state_(__state)
{
__state_->__attach_future();
}
future<void>::~future()
{
if (__state_)
__state_->__release_shared();
}
void
future<void>::get()
{
unique_ptr<__shared_count, __release_shared_count> __(__state_);
__assoc_sub_state* __s = __state_;
__state_ = nullptr;
__s->copy();
}
promise<void>::promise()
: __state_(new __assoc_sub_state)
{
}
promise<void>::~promise()
{
if (__state_)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
if (!__state_->__has_value() && __state_->use_count() > 1)
__state_->set_exception(make_exception_ptr(
future_error(make_error_code(future_errc::broken_promise))
));
#endif // _LIBCPP_NO_EXCEPTIONS
__state_->__release_shared();
}
}
future<void>
promise<void>::get_future()
{
if (__state_ == nullptr)
__throw_future_error(future_errc::no_state);
return future<void>(__state_);
}
void
promise<void>::set_value()
{
if (__state_ == nullptr)
__throw_future_error(future_errc::no_state);
__state_->set_value();
}
void
promise<void>::set_exception(exception_ptr __p)
{
if (__state_ == nullptr)
__throw_future_error(future_errc::no_state);
__state_->set_exception(__p);
}
void
promise<void>::set_value_at_thread_exit()
{
if (__state_ == nullptr)
__throw_future_error(future_errc::no_state);
__state_->set_value_at_thread_exit();
}
void
promise<void>::set_exception_at_thread_exit(exception_ptr __p)
{
if (__state_ == nullptr)
__throw_future_error(future_errc::no_state);
__state_->set_exception_at_thread_exit(__p);
}
shared_future<void>::~shared_future()
{
if (__state_)
__state_->__release_shared();
}
shared_future<void>&
shared_future<void>::operator=(const shared_future& __rhs)
{
if (__rhs.__state_)
__rhs.__state_->__add_shared();
if (__state_)
__state_->__release_shared();
__state_ = __rhs.__state_;
return *this;
}
_LIBCPP_END_NAMESPACE_STD
#endif // !_LIBCPP_HAS_NO_THREADS

561
lib/libcxx/src/hash.cpp Normal file
View File

@ -0,0 +1,561 @@
//===-------------------------- hash.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__hash_table"
#include "algorithm"
#include "stdexcept"
#include "type_traits"
#ifdef __clang__
#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
namespace {
// handle all next_prime(i) for i in [1, 210), special case 0
const unsigned small_primes[] =
{
0,
2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
127,
131,
137,
139,
149,
151,
157,
163,
167,
173,
179,
181,
191,
193,
197,
199,
211
};
// potential primes = 210*k + indices[i], k >= 1
// these numbers are not divisible by 2, 3, 5 or 7
// (or any integer 2 <= j <= 10 for that matter).
const unsigned indices[] =
{
1,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
121,
127,
131,
137,
139,
143,
149,
151,
157,
163,
167,
169,
173,
179,
181,
187,
191,
193,
197,
199,
209
};
}
// Returns: If n == 0, returns 0. Else returns the lowest prime number that
// is greater than or equal to n.
//
// The algorithm creates a list of small primes, plus an open-ended list of
// potential primes. All prime numbers are potential prime numbers. However
// some potential prime numbers are not prime. In an ideal world, all potential
// prime numbers would be prime. Candidate prime numbers are chosen as the next
// highest potential prime. Then this number is tested for prime by dividing it
// by all potential prime numbers less than the sqrt of the candidate.
//
// This implementation defines potential primes as those numbers not divisible
// by 2, 3, 5, and 7. Other (common) implementations define potential primes
// as those not divisible by 2. A few other implementations define potential
// primes as those not divisible by 2 or 3. By raising the number of small
// primes which the potential prime is not divisible by, the set of potential
// primes more closely approximates the set of prime numbers. And thus there
// are fewer potential primes to search, and fewer potential primes to divide
// against.
template <size_t _Sz = sizeof(size_t)>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if<_Sz == 4, void>::type
__check_for_overflow(size_t N)
{
if (N > 0xFFFFFFFB)
__throw_overflow_error("__next_prime overflow");
}
template <size_t _Sz = sizeof(size_t)>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if<_Sz == 8, void>::type
__check_for_overflow(size_t N)
{
if (N > 0xFFFFFFFFFFFFFFC5ull)
__throw_overflow_error("__next_prime overflow");
}
size_t
__next_prime(size_t n)
{
const size_t L = 210;
const size_t N = sizeof(small_primes) / sizeof(small_primes[0]);
// If n is small enough, search in small_primes
if (n <= small_primes[N-1])
return *std::lower_bound(small_primes, small_primes + N, n);
// Else n > largest small_primes
// Check for overflow
__check_for_overflow(n);
// Start searching list of potential primes: L * k0 + indices[in]
const size_t M = sizeof(indices) / sizeof(indices[0]);
// Select first potential prime >= n
// Known a-priori n >= L
size_t k0 = n / L;
size_t in = static_cast<size_t>(std::lower_bound(indices, indices + M, n - k0 * L)
- indices);
n = L * k0 + indices[in];
while (true)
{
// Divide n by all primes or potential primes (i) until:
// 1. The division is even, so try next potential prime.
// 2. The i > sqrt(n), in which case n is prime.
// It is known a-priori that n is not divisible by 2, 3, 5 or 7,
// so don't test those (j == 5 -> divide by 11 first). And the
// potential primes start with 211, so don't test against the last
// small prime.
for (size_t j = 5; j < N - 1; ++j)
{
const std::size_t p = small_primes[j];
const std::size_t q = n / p;
if (q < p)
return n;
if (n == q * p)
goto next;
}
// n wasn't divisible by small primes, try potential primes
{
size_t i = 211;
while (true)
{
std::size_t q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 10;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 8;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 8;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 6;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 4;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 2;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
i += 10;
q = n / i;
if (q < i)
return n;
if (n == q * i)
break;
// This will loop i to the next "plane" of potential primes
i += 2;
}
}
next:
// n is not prime. Increment n to next potential prime.
if (++in == M)
{
++k0;
in = 0;
}
n = L * k0 + indices[in];
}
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,51 @@
//===------------------------ apple_availability.h ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
#define _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
#if defined(__APPLE__)
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300
#define _LIBCPP_USE_UTIMENSAT
#endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000
#define _LIBCPP_USE_UTIMENSAT
#endif
#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000
#define _LIBCPP_USE_UTIMENSAT
#endif
#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000
#define _LIBCPP_USE_UTIMENSAT
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
#define _LIBCPP_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCPP_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
#define _LIBCPP_USE_CLOCK_GETTIME
#endif
#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
#define _LIBCPP_USE_CLOCK_GETTIME
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#endif // __APPLE__
#endif // _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H

View File

@ -0,0 +1,176 @@
//===----------------------------------------------------------------------===////
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===////
#ifndef ATOMIC_SUPPORT_H
#define ATOMIC_SUPPORT_H
#include "__config"
#include "memory" // for __libcpp_relaxed_load
#if defined(__clang__) && __has_builtin(__atomic_load_n) \
&& __has_builtin(__atomic_store_n) \
&& __has_builtin(__atomic_add_fetch) \
&& __has_builtin(__atomic_exchange_n) \
&& __has_builtin(__atomic_compare_exchange_n) \
&& defined(__ATOMIC_RELAXED) \
&& defined(__ATOMIC_CONSUME) \
&& defined(__ATOMIC_ACQUIRE) \
&& defined(__ATOMIC_RELEASE) \
&& defined(__ATOMIC_ACQ_REL) \
&& defined(__ATOMIC_SEQ_CST)
# define _LIBCPP_HAS_ATOMIC_BUILTINS
#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
# define _LIBCPP_HAS_ATOMIC_BUILTINS
#endif
#if !defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
# if defined(_LIBCPP_WARNING)
_LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
# else
# warning Building libc++ without __atomic builtins is unsupported
# endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
namespace {
#if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
enum __libcpp_atomic_order {
_AO_Relaxed = __ATOMIC_RELAXED,
_AO_Consume = __ATOMIC_CONSUME,
_AO_Acquire = __ATOMIC_ACQUIRE,
_AO_Release = __ATOMIC_RELEASE,
_AO_Acq_Rel = __ATOMIC_ACQ_REL,
_AO_Seq = __ATOMIC_SEQ_CST
};
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
int __order = _AO_Seq)
{
__atomic_store_n(__dest, __val, __order);
}
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
{
__atomic_store_n(__dest, __val, _AO_Relaxed);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_load(_ValueType const* __val,
int __order = _AO_Seq)
{
return __atomic_load_n(__val, __order);
}
template <class _ValueType, class _AddType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
int __order = _AO_Seq)
{
return __atomic_add_fetch(__val, __a, __order);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_exchange(_ValueType* __target,
_ValueType __value, int __order = _AO_Seq)
{
return __atomic_exchange_n(__target, __value, __order);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
bool __libcpp_atomic_compare_exchange(_ValueType* __val,
_ValueType* __expected, _ValueType __after,
int __success_order = _AO_Seq,
int __fail_order = _AO_Seq)
{
return __atomic_compare_exchange_n(__val, __expected, __after, true,
__success_order, __fail_order);
}
#else // _LIBCPP_HAS_NO_THREADS
enum __libcpp_atomic_order {
_AO_Relaxed,
_AO_Consume,
_AO_Acquire,
_AO_Release,
_AO_Acq_Rel,
_AO_Seq
};
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
int = 0)
{
*__dest = __val;
}
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
{
*__dest = __val;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_load(_ValueType const* __val,
int = 0)
{
return *__val;
}
template <class _ValueType, class _AddType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
int = 0)
{
return *__val += __a;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_exchange(_ValueType* __target,
_ValueType __value, int __order = _AO_Seq)
{
_ValueType old = *__target;
*__target = __value;
return old;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
bool __libcpp_atomic_compare_exchange(_ValueType* __val,
_ValueType* __expected, _ValueType __after,
int = 0, int = 0)
{
if (*__val == *__expected) {
*__val = __after;
return true;
}
*__expected = *__val;
return false;
}
#endif // _LIBCPP_HAS_NO_THREADS
} // end namespace
_LIBCPP_END_NAMESPACE_STD
#endif // ATOMIC_SUPPORT_H

View File

@ -0,0 +1,41 @@
//===----------------------- config_elast.h -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_CONFIG_ELAST
#define _LIBCPP_CONFIG_ELAST
#include <__config>
#if defined(_LIBCPP_MSVCRT_LIKE)
#include <stdlib.h>
#else
#include <errno.h>
#endif
#if defined(ELAST)
#define _LIBCPP_ELAST ELAST
#elif defined(_NEWLIB_VERSION)
#define _LIBCPP_ELAST __ELASTERROR
#elif defined(__Fuchsia__)
// No _LIBCPP_ELAST needed on Fuchsia
#elif defined(__wasi__)
// No _LIBCPP_ELAST needed on WASI
#elif defined(__linux__) || defined(_LIBCPP_HAS_MUSL_LIBC)
#define _LIBCPP_ELAST 4095
#elif defined(__APPLE__)
// No _LIBCPP_ELAST needed on Apple
#elif defined(__sun__)
#define _LIBCPP_ELAST ESTALE
#elif defined(_LIBCPP_MSVCRT_LIKE)
#define _LIBCPP_ELAST (_sys_nerr - 1)
#else
// Warn here so that the person doing the libcxx port has an easier time:
#warning ELAST for this platform not yet implemented
#endif
#endif // _LIBCPP_CONFIG_ELAST

View File

@ -0,0 +1,127 @@
//===------------------------ __refstring ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_REFSTRING_H
#define _LIBCPP_REFSTRING_H
#include <__config>
#include <stdexcept>
#include <cstddef>
#include <cstring>
#ifdef __APPLE__
#include <dlfcn.h>
#include <mach-o/dyld.h>
#endif
#include "atomic_support.h"
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __refstring_imp { namespace {
typedef int count_t;
struct _Rep_base {
std::size_t len;
std::size_t cap;
count_t count;
};
inline _Rep_base* rep_from_data(const char *data_) noexcept {
char *data = const_cast<char *>(data_);
return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
}
inline char * data_from_rep(_Rep_base *rep) noexcept {
char *data = reinterpret_cast<char *>(rep);
return data + sizeof(*rep);
}
#if defined(__APPLE__)
inline
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));
}
inline
const char*
get_gcc_empty_string_storage() _NOEXCEPT
{
static const char* p = compute_gcc_empty_string_storage();
return p;
}
#endif
}} // namespace __refstring_imp
using namespace __refstring_imp;
inline
__libcpp_refstring::__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);
__imp_ = data;
}
inline
__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
: __imp_(s.__imp_)
{
if (__uses_refcount())
__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
}
inline
__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
bool adjust_old_count = __uses_refcount();
struct _Rep_base *old_rep = rep_from_data(__imp_);
__imp_ = s.__imp_;
if (__uses_refcount())
__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
if (adjust_old_count)
{
if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
{
::operator delete(old_rep);
}
}
return *this;
}
inline
__libcpp_refstring::~__libcpp_refstring() {
if (__uses_refcount()) {
_Rep_base* rep = rep_from_data(__imp_);
if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
::operator delete(rep);
}
}
}
inline
bool __libcpp_refstring::__uses_refcount() const {
#ifdef __APPLE__
return __imp_ != get_gcc_empty_string_storage();
#else
return true;
#endif
}
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_REFSTRING_H

457
lib/libcxx/src/ios.cpp Normal file
View File

@ -0,0 +1,457 @@
//===-------------------------- ios.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#include "ios"
#include <stdlib.h>
#include "__locale"
#include "algorithm"
#include "include/config_elast.h"
#include "istream"
#include "limits"
#include "memory"
#include "new"
#include "streambuf"
#include "string"
#include "__undef_macros"
_LIBCPP_BEGIN_NAMESPACE_STD
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>;
class _LIBCPP_HIDDEN __iostream_category
: public __do_message
{
public:
virtual const char* name() const _NOEXCEPT;
virtual string message(int ev) const;
};
const char*
__iostream_category::name() const _NOEXCEPT
{
return "iostream";
}
string
__iostream_category::message(int ev) const
{
if (ev != static_cast<int>(io_errc::stream)
#ifdef _LIBCPP_ELAST
&& ev <= _LIBCPP_ELAST
#endif // _LIBCPP_ELAST
)
return __do_message::message(ev);
return string("unspecified iostream_category error");
}
const error_category&
iostream_category() _NOEXCEPT
{
static __iostream_category s;
return s;
}
// ios_base::failure
ios_base::failure::failure(const string& msg, const error_code& ec)
: system_error(ec, msg)
{
}
ios_base::failure::failure(const char* msg, const error_code& ec)
: system_error(ec, msg)
{
}
ios_base::failure::~failure() throw()
{
}
// ios_base locale
const ios_base::fmtflags ios_base::boolalpha;
const ios_base::fmtflags ios_base::dec;
const ios_base::fmtflags ios_base::fixed;
const ios_base::fmtflags ios_base::hex;
const ios_base::fmtflags ios_base::internal;
const ios_base::fmtflags ios_base::left;
const ios_base::fmtflags ios_base::oct;
const ios_base::fmtflags ios_base::right;
const ios_base::fmtflags ios_base::scientific;
const ios_base::fmtflags ios_base::showbase;
const ios_base::fmtflags ios_base::showpoint;
const ios_base::fmtflags ios_base::showpos;
const ios_base::fmtflags ios_base::skipws;
const ios_base::fmtflags ios_base::unitbuf;
const ios_base::fmtflags ios_base::uppercase;
const ios_base::fmtflags ios_base::adjustfield;
const ios_base::fmtflags ios_base::basefield;
const ios_base::fmtflags ios_base::floatfield;
const ios_base::iostate ios_base::badbit;
const ios_base::iostate ios_base::eofbit;
const ios_base::iostate ios_base::failbit;
const ios_base::iostate ios_base::goodbit;
const ios_base::openmode ios_base::app;
const ios_base::openmode ios_base::ate;
const ios_base::openmode ios_base::binary;
const ios_base::openmode ios_base::in;
const ios_base::openmode ios_base::out;
const ios_base::openmode ios_base::trunc;
void
ios_base::__call_callbacks(event ev)
{
for (size_t i = __event_size_; i;)
{
--i;
__fn_[i](ev, *this, __index_[i]);
}
}
// locale
locale
ios_base::imbue(const locale& newloc)
{
static_assert(sizeof(locale) == sizeof(__loc_), "");
locale& loc_storage = *reinterpret_cast<locale*>(&__loc_);
locale oldloc = loc_storage;
loc_storage = newloc;
__call_callbacks(imbue_event);
return oldloc;
}
locale
ios_base::getloc() const
{
const locale& loc_storage = *reinterpret_cast<const locale*>(&__loc_);
return loc_storage;
}
// xalloc
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)
atomic<int> ios_base::__xindex_ = ATOMIC_VAR_INIT(0);
#else
int ios_base::__xindex_ = 0;
#endif
template <typename _Tp>
static size_t __ios_new_cap(size_t __req_size, size_t __current_cap)
{ // Precondition: __req_size > __current_cap
const size_t mx = std::numeric_limits<size_t>::max() / sizeof(_Tp);
if (__req_size < mx/2)
return _VSTD::max(2 * __current_cap, __req_size);
else
return mx;
}
int
ios_base::xalloc()
{
return __xindex_++;
}
long&
ios_base::iword(int index)
{
size_t req_size = static_cast<size_t>(index)+1;
if (req_size > __iarray_cap_)
{
size_t newcap = __ios_new_cap<long>(req_size, __iarray_cap_);
long* iarray = static_cast<long*>(realloc(__iarray_, newcap * sizeof(long)));
if (iarray == 0)
{
setstate(badbit);
static long error;
error = 0;
return error;
}
__iarray_ = iarray;
for (long* p = __iarray_ + __iarray_size_; p < __iarray_ + newcap; ++p)
*p = 0;
__iarray_cap_ = newcap;
}
__iarray_size_ = max<size_t>(__iarray_size_, req_size);
return __iarray_[index];
}
void*&
ios_base::pword(int index)
{
size_t req_size = static_cast<size_t>(index)+1;
if (req_size > __parray_cap_)
{
size_t newcap = __ios_new_cap<void *>(req_size, __iarray_cap_);
void** parray = static_cast<void**>(realloc(__parray_, newcap * sizeof(void *)));
if (parray == 0)
{
setstate(badbit);
static void* error;
error = 0;
return error;
}
__parray_ = parray;
for (void** p = __parray_ + __parray_size_; p < __parray_ + newcap; ++p)
*p = 0;
__parray_cap_ = newcap;
}
__parray_size_ = max<size_t>(__parray_size_, req_size);
return __parray_[index];
}
// register_callback
void
ios_base::register_callback(event_callback fn, int index)
{
size_t req_size = __event_size_ + 1;
if (req_size > __event_cap_)
{
size_t newcap = __ios_new_cap<event_callback>(req_size, __event_cap_);
event_callback* fns = static_cast<event_callback*>(realloc(__fn_, newcap * sizeof(event_callback)));
if (fns == 0)
setstate(badbit);
__fn_ = fns;
int* indxs = static_cast<int *>(realloc(__index_, newcap * sizeof(int)));
if (indxs == 0)
setstate(badbit);
__index_ = indxs;
__event_cap_ = newcap;
}
__fn_[__event_size_] = fn;
__index_[__event_size_] = index;
++__event_size_;
}
ios_base::~ios_base()
{
__call_callbacks(erase_event);
locale& loc_storage = *reinterpret_cast<locale*>(&__loc_);
loc_storage.~locale();
free(__fn_);
free(__index_);
free(__iarray_);
free(__parray_);
}
// iostate
void
ios_base::clear(iostate state)
{
if (__rdbuf_)
__rdstate_ = state;
else
__rdstate_ = state | badbit;
if (((state | (__rdbuf_ ? goodbit : badbit)) & __exceptions_) != 0)
__throw_failure("ios_base::clear");
}
// init
void
ios_base::init(void* sb)
{
__rdbuf_ = sb;
__rdstate_ = __rdbuf_ ? goodbit : badbit;
__exceptions_ = goodbit;
__fmtflags_ = skipws | dec;
__width_ = 0;
__precision_ = 6;
__fn_ = 0;
__index_ = 0;
__event_size_ = 0;
__event_cap_ = 0;
__iarray_ = 0;
__iarray_size_ = 0;
__iarray_cap_ = 0;
__parray_ = 0;
__parray_size_ = 0;
__parray_cap_ = 0;
::new(&__loc_) locale;
}
void
ios_base::copyfmt(const ios_base& rhs)
{
// If we can't acquire the needed resources, throw bad_alloc (can't set badbit)
// Don't alter *this until all needed resources are acquired
unique_ptr<event_callback, void (*)(void*)> new_callbacks(0, free);
unique_ptr<int, void (*)(void*)> new_ints(0, free);
unique_ptr<long, void (*)(void*)> new_longs(0, free);
unique_ptr<void*, void (*)(void*)> new_pointers(0, free);
if (__event_cap_ < rhs.__event_size_)
{
size_t newesize = sizeof(event_callback) * rhs.__event_size_;
new_callbacks.reset(static_cast<event_callback*>(malloc(newesize)));
if (!new_callbacks)
__throw_bad_alloc();
size_t newisize = sizeof(int) * rhs.__event_size_;
new_ints.reset(static_cast<int *>(malloc(newisize)));
if (!new_ints)
__throw_bad_alloc();
}
if (__iarray_cap_ < rhs.__iarray_size_)
{
size_t newsize = sizeof(long) * rhs.__iarray_size_;
new_longs.reset(static_cast<long*>(malloc(newsize)));
if (!new_longs)
__throw_bad_alloc();
}
if (__parray_cap_ < rhs.__parray_size_)
{
size_t newsize = sizeof(void*) * rhs.__parray_size_;
new_pointers.reset(static_cast<void**>(malloc(newsize)));
if (!new_pointers)
__throw_bad_alloc();
}
// Got everything we need. Copy everything but __rdstate_, __rdbuf_ and __exceptions_
__fmtflags_ = rhs.__fmtflags_;
__precision_ = rhs.__precision_;
__width_ = rhs.__width_;
locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_);
const locale& rhs_loc = *reinterpret_cast<const locale*>(&rhs.__loc_);
lhs_loc = rhs_loc;
if (__event_cap_ < rhs.__event_size_)
{
free(__fn_);
__fn_ = new_callbacks.release();
free(__index_);
__index_ = new_ints.release();
__event_cap_ = rhs.__event_size_;
}
for (__event_size_ = 0; __event_size_ < rhs.__event_size_; ++__event_size_)
{
__fn_[__event_size_] = rhs.__fn_[__event_size_];
__index_[__event_size_] = rhs.__index_[__event_size_];
}
if (__iarray_cap_ < rhs.__iarray_size_)
{
free(__iarray_);
__iarray_ = new_longs.release();
__iarray_cap_ = rhs.__iarray_size_;
}
for (__iarray_size_ = 0; __iarray_size_ < rhs.__iarray_size_; ++__iarray_size_)
__iarray_[__iarray_size_] = rhs.__iarray_[__iarray_size_];
if (__parray_cap_ < rhs.__parray_size_)
{
free(__parray_);
__parray_ = new_pointers.release();
__parray_cap_ = rhs.__parray_size_;
}
for (__parray_size_ = 0; __parray_size_ < rhs.__parray_size_; ++__parray_size_)
__parray_[__parray_size_] = rhs.__parray_[__parray_size_];
}
void
ios_base::move(ios_base& rhs)
{
// *this is uninitialized
__fmtflags_ = rhs.__fmtflags_;
__precision_ = rhs.__precision_;
__width_ = rhs.__width_;
__rdstate_ = rhs.__rdstate_;
__exceptions_ = rhs.__exceptions_;
__rdbuf_ = 0;
locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_);
::new(&__loc_) locale(rhs_loc);
__fn_ = rhs.__fn_;
rhs.__fn_ = 0;
__index_ = rhs.__index_;
rhs.__index_ = 0;
__event_size_ = rhs.__event_size_;
rhs.__event_size_ = 0;
__event_cap_ = rhs.__event_cap_;
rhs.__event_cap_ = 0;
__iarray_ = rhs.__iarray_;
rhs.__iarray_ = 0;
__iarray_size_ = rhs.__iarray_size_;
rhs.__iarray_size_ = 0;
__iarray_cap_ = rhs.__iarray_cap_;
rhs.__iarray_cap_ = 0;
__parray_ = rhs.__parray_;
rhs.__parray_ = 0;
__parray_size_ = rhs.__parray_size_;
rhs.__parray_size_ = 0;
__parray_cap_ = rhs.__parray_cap_;
rhs.__parray_cap_ = 0;
}
void
ios_base::swap(ios_base& rhs) _NOEXCEPT
{
_VSTD::swap(__fmtflags_, rhs.__fmtflags_);
_VSTD::swap(__precision_, rhs.__precision_);
_VSTD::swap(__width_, rhs.__width_);
_VSTD::swap(__rdstate_, rhs.__rdstate_);
_VSTD::swap(__exceptions_, rhs.__exceptions_);
locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_);
locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_);
_VSTD::swap(lhs_loc, rhs_loc);
_VSTD::swap(__fn_, rhs.__fn_);
_VSTD::swap(__index_, rhs.__index_);
_VSTD::swap(__event_size_, rhs.__event_size_);
_VSTD::swap(__event_cap_, rhs.__event_cap_);
_VSTD::swap(__iarray_, rhs.__iarray_);
_VSTD::swap(__iarray_size_, rhs.__iarray_size_);
_VSTD::swap(__iarray_cap_, rhs.__iarray_cap_);
_VSTD::swap(__parray_, rhs.__parray_);
_VSTD::swap(__parray_size_, rhs.__parray_size_);
_VSTD::swap(__parray_cap_, rhs.__parray_cap_);
}
void
ios_base::__set_badbit_and_consider_rethrow()
{
__rdstate_ |= badbit;
#ifndef _LIBCPP_NO_EXCEPTIONS
if (__exceptions_ & badbit)
throw;
#endif // _LIBCPP_NO_EXCEPTIONS
}
void
ios_base::__set_failbit_and_consider_rethrow()
{
__rdstate_ |= failbit;
#ifndef _LIBCPP_NO_EXCEPTIONS
if (__exceptions_ & failbit)
throw;
#endif // _LIBCPP_NO_EXCEPTIONS
}
bool
ios_base::sync_with_stdio(bool sync)
{
static bool previous_state = true;
bool r = previous_state;
previous_state = sync;
return r;
}
_LIBCPP_END_NAMESPACE_STD

159
lib/libcxx/src/iostream.cpp Normal file
View File

@ -0,0 +1,159 @@
//===------------------------ iostream.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__std_stream"
#include "__locale"
#include "string"
#include "new"
#define _str(s) #s
#define str(s) _str(s)
#define _LIBCPP_ABI_NAMESPACE_STR str(_LIBCPP_ABI_NAMESPACE)
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_HAS_NO_STDIN
_ALIGNAS_TYPE (istream) _LIBCPP_FUNC_VIS char cin[sizeof(istream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdinbuf<char> ) static char __cin[sizeof(__stdinbuf <char>)];
static mbstate_t mb_cin;
_ALIGNAS_TYPE (wistream) _LIBCPP_FUNC_VIS char wcin[sizeof(wistream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdinbuf<wchar_t> ) static char __wcin[sizeof(__stdinbuf <wchar_t>)];
static mbstate_t mb_wcin;
#endif
#ifndef _LIBCPP_HAS_NO_STDOUT
_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cout[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cout;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcout[sizeof(wostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcout;
#endif
_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cerr[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cerr;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcerr[sizeof(wostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcerr;
_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char clog[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?clog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
#endif
;
_LIBCPP_HIDDEN ios_base::Init __start_std_streams;
// On Windows the TLS storage for locales needs to be initialized before we create
// the standard streams, otherwise it may not be alive during program termination
// when we flush the streams.
static void force_locale_initialization() {
#if defined(_LIBCPP_MSVCRT_LIKE)
static bool once = []() {
auto loc = newlocale(LC_ALL_MASK, "C", 0);
{
__libcpp_locale_guard g(loc); // forces initialization of locale TLS
((void)g);
}
freelocale(loc);
return true;
}();
((void)once);
#endif
}
class DoIOSInit {
public:
DoIOSInit();
~DoIOSInit();
};
DoIOSInit::DoIOSInit()
{
force_locale_initialization();
#ifndef _LIBCPP_HAS_NO_STDIN
istream* cin_ptr = ::new(cin) istream(::new(__cin) __stdinbuf <char>(stdin, &mb_cin));
wistream* wcin_ptr = ::new(wcin) wistream(::new(__wcin) __stdinbuf <wchar_t>(stdin, &mb_wcin));
#endif
#ifndef _LIBCPP_HAS_NO_STDOUT
ostream* cout_ptr = ::new(cout) ostream(::new(__cout) __stdoutbuf<char>(stdout, &mb_cout));
wostream* wcout_ptr = ::new(wcout) wostream(::new(__wcout) __stdoutbuf<wchar_t>(stdout, &mb_wcout));
#endif
ostream* cerr_ptr = ::new(cerr) ostream(::new(__cerr) __stdoutbuf<char>(stderr, &mb_cerr));
::new(clog) ostream(cerr_ptr->rdbuf());
wostream* wcerr_ptr = ::new(wcerr) wostream(::new(__wcerr) __stdoutbuf<wchar_t>(stderr, &mb_wcerr));
::new(wclog) wostream(wcerr_ptr->rdbuf());
#if !defined(_LIBCPP_HAS_NO_STDIN) && !defined(_LIBCPP_HAS_NO_STDOUT)
cin_ptr->tie(cout_ptr);
wcin_ptr->tie(wcout_ptr);
#endif
_VSTD::unitbuf(*cerr_ptr);
_VSTD::unitbuf(*wcerr_ptr);
#ifndef _LIBCPP_HAS_NO_STDOUT
cerr_ptr->tie(cout_ptr);
wcerr_ptr->tie(wcout_ptr);
#endif
}
DoIOSInit::~DoIOSInit()
{
#ifndef _LIBCPP_HAS_NO_STDOUT
ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
wostream* wcout_ptr = reinterpret_cast<wostream*>(wcout);
cout_ptr->flush();
wcout_ptr->flush();
#endif
ostream* clog_ptr = reinterpret_cast<ostream*>(clog);
wostream* wclog_ptr = reinterpret_cast<wostream*>(wclog);
clog_ptr->flush();
wclog_ptr->flush();
}
ios_base::Init::Init()
{
static DoIOSInit init_the_streams; // gets initialized once
}
ios_base::Init::~Init()
{
}
_LIBCPP_END_NAMESPACE_STD

6154
lib/libcxx/src/locale.cpp Normal file

File diff suppressed because it is too large Load Diff

237
lib/libcxx/src/memory.cpp Normal file
View File

@ -0,0 +1,237 @@
//===------------------------ memory.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "memory"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "mutex"
#include "thread"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
#include "include/atomic_support.h"
_LIBCPP_BEGIN_NAMESPACE_STD
const allocator_arg_t allocator_arg = allocator_arg_t();
bad_weak_ptr::~bad_weak_ptr() _NOEXCEPT {}
const char*
bad_weak_ptr::what() const _NOEXCEPT
{
return "bad_weak_ptr";
}
__shared_count::~__shared_count()
{
}
__shared_weak_count::~__shared_weak_count()
{
}
#if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
void
__shared_count::__add_shared() _NOEXCEPT
{
__libcpp_atomic_refcount_increment(__shared_owners_);
}
bool
__shared_count::__release_shared() _NOEXCEPT
{
if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1)
{
__on_zero_shared();
return true;
}
return false;
}
void
__shared_weak_count::__add_shared() _NOEXCEPT
{
__shared_count::__add_shared();
}
void
__shared_weak_count::__add_weak() _NOEXCEPT
{
__libcpp_atomic_refcount_increment(__shared_weak_owners_);
}
void
__shared_weak_count::__release_shared() _NOEXCEPT
{
if (__shared_count::__release_shared())
__release_weak();
}
#endif // _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
void
__shared_weak_count::__release_weak() _NOEXCEPT
{
// NOTE: The acquire load here is an optimization of the very
// common case where a shared pointer is being destructed while
// having no other contended references.
//
// BENEFIT: We avoid expensive atomic stores like XADD and STREX
// in a common case. Those instructions are slow and do nasty
// things to caches.
//
// IS THIS SAFE? Yes. During weak destruction, if we see that we
// are the last reference, we know that no-one else is accessing
// us. If someone were accessing us, then they would be doing so
// while the last shared / weak_ptr was being destructed, and
// that's undefined anyway.
//
// If we see anything other than a 0, then we have possible
// contention, and need to use an atomicrmw primitive.
// The same arguments don't apply for increment, where it is legal
// (though inadvisable) to share shared_ptr references between
// threads, and have them all get copied at once. The argument
// also doesn't apply for __release_shared, because an outstanding
// weak_ptr::lock() could read / modify the shared count.
if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0)
{
// no need to do this store, because we are about
// to destroy everything.
//__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
__on_zero_shared_weak();
}
else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
__on_zero_shared_weak();
}
__shared_weak_count*
__shared_weak_count::lock() _NOEXCEPT
{
long object_owners = __libcpp_atomic_load(&__shared_owners_);
while (object_owners != -1)
{
if (__libcpp_atomic_compare_exchange(&__shared_owners_,
&object_owners,
object_owners+1))
return this;
}
return nullptr;
}
#if !defined(_LIBCPP_NO_RTTI) || !defined(_LIBCPP_BUILD_STATIC)
const void*
__shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT
{
return nullptr;
}
#endif // _LIBCPP_NO_RTTI
#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
_LIBCPP_SAFE_STATIC static const std::size_t __sp_mut_count = 16;
_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut_back[__sp_mut_count] =
{
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
_LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER
};
_LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT
: __lx(p)
{
}
void
__sp_mut::lock() _NOEXCEPT
{
auto m = static_cast<__libcpp_mutex_t*>(__lx);
unsigned count = 0;
while (!__libcpp_mutex_trylock(m))
{
if (++count > 16)
{
__libcpp_mutex_lock(m);
break;
}
this_thread::yield();
}
}
void
__sp_mut::unlock() _NOEXCEPT
{
__libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx));
}
__sp_mut&
__get_sp_mut(const void* p)
{
static __sp_mut muts[__sp_mut_count]
{
&mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3],
&mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7],
&mut_back[ 8], &mut_back[ 9], &mut_back[10], &mut_back[11],
&mut_back[12], &mut_back[13], &mut_back[14], &mut_back[15]
};
return muts[hash<const void*>()(p) & (__sp_mut_count-1)];
}
#endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
void
declare_reachable(void*)
{
}
void
declare_no_pointers(char*, size_t)
{
}
void
undeclare_no_pointers(char*, size_t)
{
}
#if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE)
pointer_safety get_pointer_safety() _NOEXCEPT
{
return pointer_safety::relaxed;
}
#endif
void*
__undeclare_reachable(void* p)
{
return p;
}
void*
align(size_t alignment, size_t size, void*& ptr, size_t& space)
{
void* r = nullptr;
if (size <= space)
{
char* p1 = static_cast<char*>(ptr);
char* p2 = reinterpret_cast<char*>(reinterpret_cast<size_t>(p1 + (alignment - 1)) & -alignment);
size_t d = static_cast<size_t>(p2 - p1);
if (d <= space - size)
{
r = p2;
ptr = r;
space -= d;
}
}
return r;
}
_LIBCPP_END_NAMESPACE_STD

260
lib/libcxx/src/mutex.cpp Normal file
View File

@ -0,0 +1,260 @@
//===------------------------- mutex.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "mutex"
#include "limits"
#include "system_error"
#include "include/atomic_support.h"
#include "__undef_macros"
#ifndef _LIBCPP_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_HAS_NO_THREADS
const defer_lock_t defer_lock{};
const try_to_lock_t try_to_lock{};
const adopt_lock_t adopt_lock{};
// ~mutex is defined elsewhere
void
mutex::lock()
{
int ec = __libcpp_mutex_lock(&__m_);
if (ec)
__throw_system_error(ec, "mutex lock failed");
}
bool
mutex::try_lock() _NOEXCEPT
{
return __libcpp_mutex_trylock(&__m_);
}
void
mutex::unlock() _NOEXCEPT
{
int ec = __libcpp_mutex_unlock(&__m_);
(void)ec;
_LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
}
// recursive_mutex
recursive_mutex::recursive_mutex()
{
int ec = __libcpp_recursive_mutex_init(&__m_);
if (ec)
__throw_system_error(ec, "recursive_mutex constructor failed");
}
recursive_mutex::~recursive_mutex()
{
int e = __libcpp_recursive_mutex_destroy(&__m_);
(void)e;
_LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
}
void
recursive_mutex::lock()
{
int ec = __libcpp_recursive_mutex_lock(&__m_);
if (ec)
__throw_system_error(ec, "recursive_mutex lock failed");
}
void
recursive_mutex::unlock() _NOEXCEPT
{
int e = __libcpp_recursive_mutex_unlock(&__m_);
(void)e;
_LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
}
bool
recursive_mutex::try_lock() _NOEXCEPT
{
return __libcpp_recursive_mutex_trylock(&__m_);
}
// timed_mutex
timed_mutex::timed_mutex()
: __locked_(false)
{
}
timed_mutex::~timed_mutex()
{
lock_guard<mutex> _(__m_);
}
void
timed_mutex::lock()
{
unique_lock<mutex> lk(__m_);
while (__locked_)
__cv_.wait(lk);
__locked_ = true;
}
bool
timed_mutex::try_lock() _NOEXCEPT
{
unique_lock<mutex> lk(__m_, try_to_lock);
if (lk.owns_lock() && !__locked_)
{
__locked_ = true;
return true;
}
return false;
}
void
timed_mutex::unlock() _NOEXCEPT
{
lock_guard<mutex> _(__m_);
__locked_ = false;
__cv_.notify_one();
}
// recursive_timed_mutex
recursive_timed_mutex::recursive_timed_mutex()
: __count_(0),
__id_{}
{
}
recursive_timed_mutex::~recursive_timed_mutex()
{
lock_guard<mutex> _(__m_);
}
void
recursive_timed_mutex::lock()
{
__thread_id id = this_thread::get_id();
unique_lock<mutex> lk(__m_);
if (id ==__id_)
{
if (__count_ == numeric_limits<size_t>::max())
__throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
++__count_;
return;
}
while (__count_ != 0)
__cv_.wait(lk);
__count_ = 1;
__id_ = id;
}
bool
recursive_timed_mutex::try_lock() _NOEXCEPT
{
__thread_id id = this_thread::get_id();
unique_lock<mutex> lk(__m_, try_to_lock);
if (lk.owns_lock() && (__count_ == 0 || id == __id_))
{
if (__count_ == numeric_limits<size_t>::max())
return false;
++__count_;
__id_ = id;
return true;
}
return false;
}
void
recursive_timed_mutex::unlock() _NOEXCEPT
{
unique_lock<mutex> lk(__m_);
if (--__count_ == 0)
{
__id_.__reset();
lk.unlock();
__cv_.notify_one();
}
}
#endif // !_LIBCPP_HAS_NO_THREADS
// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
// without illegal macros (unexpected macros not beginning with _UpperCase or
// __lowercase), and if it stops spinning waiting threads, then call_once should
// call into dispatch_once_f instead of here. Relevant radar this code needs to
// keep in sync with: 7741191.
#ifndef _LIBCPP_HAS_NO_THREADS
_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
_LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
#endif
void __call_once(volatile once_flag::_State_type& flag, void* arg,
void (*func)(void*))
{
#if defined(_LIBCPP_HAS_NO_THREADS)
if (flag == 0)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
flag = 1;
func(arg);
flag = ~once_flag::_State_type(0);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
flag = 0;
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
#else // !_LIBCPP_HAS_NO_THREADS
__libcpp_mutex_lock(&mut);
while (flag == 1)
__libcpp_condvar_wait(&cv, &mut);
if (flag == 0)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
__libcpp_relaxed_store(&flag, once_flag::_State_type(1));
__libcpp_mutex_unlock(&mut);
func(arg);
__libcpp_mutex_lock(&mut);
__libcpp_atomic_store(&flag, ~once_flag::_State_type(0),
_AO_Release);
__libcpp_mutex_unlock(&mut);
__libcpp_condvar_broadcast(&cv);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
__libcpp_mutex_lock(&mut);
__libcpp_relaxed_store(&flag, once_flag::_State_type(0));
__libcpp_mutex_unlock(&mut);
__libcpp_condvar_broadcast(&cv);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
else
__libcpp_mutex_unlock(&mut);
#endif // !_LIBCPP_HAS_NO_THREADS
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,50 @@
//===--------------------- mutex_destructor.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Define ~mutex.
//
// On some platforms ~mutex has been made trivial and the definition is only
// provided for ABI compatibility.
//
// In order to avoid ODR violations within libc++ itself, we need to ensure
// that *nothing* sees the non-trivial mutex declaration. For this reason
// we re-declare the entire class in this file instead of using
// _LIBCPP_BUILDING_LIBRARY to change the definition in the headers.
#include "__config"
#include "__threading_support"
#if !defined(_LIBCPP_HAS_NO_THREADS)
#if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
#define NEEDS_MUTEX_DESTRUCTOR
#endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef NEEDS_MUTEX_DESTRUCTOR
class _LIBCPP_TYPE_VIS mutex
{
__libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
public:
_LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY
constexpr mutex() = default;
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
~mutex() noexcept;
};
mutex::~mutex() _NOEXCEPT
{
__libcpp_mutex_destroy(&__m_);
}
#endif // !_LIBCPP_HAS_NO_THREADS
_LIBCPP_END_NAMESPACE_STD

297
lib/libcxx/src/new.cpp Normal file
View File

@ -0,0 +1,297 @@
//===--------------------------- new.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include "new"
#include "include/atomic_support.h"
#if defined(_LIBCPP_ABI_MICROSOFT)
# if !defined(_LIBCPP_ABI_VCRUNTIME)
# include "support/runtime/new_handler_fallback.ipp"
# endif
#elif defined(LIBCXX_BUILDING_LIBCXXABI)
# include <cxxabi.h>
#elif defined(LIBCXXRT)
# include <cxxabi.h>
# include "support/runtime/new_handler_fallback.ipp"
#elif defined(__GLIBCXX__)
// nothing to do
#else
# include "support/runtime/new_handler_fallback.ipp"
#endif
namespace std
{
#ifndef __GLIBCXX__
const nothrow_t nothrow{};
#endif
#ifndef LIBSTDCXX
void
__throw_bad_alloc()
{
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
#else
_VSTD::abort();
#endif
}
#endif // !LIBSTDCXX
} // std
#if !defined(__GLIBCXX__) && \
!defined(_LIBCPP_ABI_VCRUNTIME) && \
!defined(_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS)
// Implement all new and delete operators as weak definitions
// in this shared library, so that they can be overridden by programs
// that define non-weak copies of the functions.
_LIBCPP_WEAK
void *
operator new(std::size_t size) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
void* p;
while ((p = ::malloc(size)) == 0)
{
// If malloc fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
#ifndef _LIBCPP_NO_EXCEPTIONS
throw std::bad_alloc();
#else
break;
#endif
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
p = ::operator new(size);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void*
operator new[](size_t size) _THROW_BAD_ALLOC
{
return ::operator new(size);
}
_LIBCPP_WEAK
void*
operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
p = ::operator new[](size);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void
operator delete(void* ptr) _NOEXCEPT
{
::free(ptr);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT
{
::operator delete[](ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t) _NOEXCEPT
{
::operator delete[](ptr);
}
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
_LIBCPP_WEAK
void *
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
if (static_cast<size_t>(alignment) < sizeof(void*))
alignment = std::align_val_t(sizeof(void*));
void* p;
#if defined(_LIBCPP_MSVCRT_LIKE)
while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr)
#else
while (::posix_memalign(&p, static_cast<size_t>(alignment), size) != 0)
#endif
{
// If posix_memalign fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else {
#ifndef _LIBCPP_NO_EXCEPTIONS
throw std::bad_alloc();
#else
p = nullptr; // posix_memalign doesn't initialize 'p' on failure
break;
#endif
}
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
p = ::operator new(size, alignment);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
return ::operator new(size, alignment);
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
p = ::operator new[](size, alignment);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t) _NOEXCEPT
{
#if defined(_LIBCPP_MSVCRT_LIKE)
::_aligned_free(ptr);
#else
::free(ptr);
#endif
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
::operator delete[](ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
{
::operator delete[](ptr, alignment);
}
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
#endif // !__GLIBCXX__ && !_LIBCPP_ABI_VCRUNTIME && !_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS

View File

@ -0,0 +1,41 @@
//===------------------------ optional.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "optional"
namespace std
{
bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
const char* bad_optional_access::what() const _NOEXCEPT {
return "bad_optional_access";
}
} // std
#include <experimental/__config>
// Preserve std::experimental::bad_optional_access for ABI compatibility
// Even though it no longer exists in a header file
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS bad_optional_access
: public std::logic_error
{
public:
bad_optional_access() : std::logic_error("Bad optional Access") {}
// Get the key function ~bad_optional_access() into the dylib
virtual ~bad_optional_access() _NOEXCEPT;
};
bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
_LIBCPP_END_NAMESPACE_EXPERIMENTAL

178
lib/libcxx/src/random.cpp Normal file
View File

@ -0,0 +1,178 @@
//===-------------------------- random.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__config>
#if defined(_LIBCPP_USING_WIN32_RANDOM)
// Must be defined before including stdlib.h to enable rand_s().
#define _CRT_RAND_S
#endif // defined(_LIBCPP_USING_WIN32_RANDOM)
#include "random"
#include "system_error"
#if defined(__sun__)
#define rename solaris_headers_are_broken
#endif // defined(__sun__)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(_LIBCPP_USING_GETENTROPY)
#include <sys/random.h>
#elif defined(_LIBCPP_USING_DEV_RANDOM)
#include <fcntl.h>
#include <unistd.h>
#elif defined(_LIBCPP_USING_NACL_RANDOM)
#include <nacl/nacl_random.h>
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if defined(_LIBCPP_USING_GETENTROPY)
random_device::random_device(const string& __token)
{
if (__token != "/dev/urandom")
__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
}
random_device::~random_device()
{
}
unsigned
random_device::operator()()
{
unsigned r;
size_t n = sizeof(r);
int err = getentropy(&r, n);
if (err)
__throw_system_error(errno, "random_device getentropy failed");
return r;
}
#elif defined(_LIBCPP_USING_ARC4_RANDOM)
random_device::random_device(const string& __token)
{
if (__token != "/dev/urandom")
__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
}
random_device::~random_device()
{
}
unsigned
random_device::operator()()
{
return arc4random();
}
#elif defined(_LIBCPP_USING_DEV_RANDOM)
random_device::random_device(const string& __token)
: __f_(open(__token.c_str(), O_RDONLY))
{
if (__f_ < 0)
__throw_system_error(errno, ("random_device failed to open " + __token).c_str());
}
random_device::~random_device()
{
close(__f_);
}
unsigned
random_device::operator()()
{
unsigned r;
size_t n = sizeof(r);
char* p = reinterpret_cast<char*>(&r);
while (n > 0)
{
ssize_t s = read(__f_, p, n);
if (s == 0)
__throw_system_error(ENODATA, "random_device got EOF");
if (s == -1)
{
if (errno != EINTR)
__throw_system_error(errno, "random_device got an unexpected error");
continue;
}
n -= static_cast<size_t>(s);
p += static_cast<size_t>(s);
}
return r;
}
#elif defined(_LIBCPP_USING_NACL_RANDOM)
random_device::random_device(const string& __token)
{
if (__token != "/dev/urandom")
__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
int error = nacl_secure_random_init();
if (error)
__throw_system_error(error, ("random device failed to open " + __token).c_str());
}
random_device::~random_device()
{
}
unsigned
random_device::operator()()
{
unsigned r;
size_t n = sizeof(r);
size_t bytes_written;
int error = nacl_secure_random(&r, n, &bytes_written);
if (error != 0)
__throw_system_error(error, "random_device failed getting bytes");
else if (bytes_written != n)
__throw_runtime_error("random_device failed to obtain enough bytes");
return r;
}
#elif defined(_LIBCPP_USING_WIN32_RANDOM)
random_device::random_device(const string& __token)
{
if (__token != "/dev/urandom")
__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
}
random_device::~random_device()
{
}
unsigned
random_device::operator()()
{
unsigned r;
errno_t err = rand_s(&r);
if (err)
__throw_system_error(err, "random_device rand_s failed.");
return r;
}
#else
#error "Random device not implemented for this architecture"
#endif
double
random_device::entropy() const _NOEXCEPT
{
return 0;
}
_LIBCPP_END_NAMESPACE_STD

316
lib/libcxx/src/regex.cpp Normal file
View File

@ -0,0 +1,316 @@
//===-------------------------- regex.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "regex"
#include "algorithm"
#include "iterator"
_LIBCPP_BEGIN_NAMESPACE_STD
static
const char*
make_error_type_string(regex_constants::error_type ecode)
{
switch (ecode)
{
case regex_constants::error_collate:
return "The expression contained an invalid collating element name.";
case regex_constants::error_ctype:
return "The expression contained an invalid character class name.";
case regex_constants::error_escape:
return "The expression contained an invalid escaped character, or a "
"trailing escape.";
case regex_constants::error_backref:
return "The expression contained an invalid back reference.";
case regex_constants::error_brack:
return "The expression contained mismatched [ and ].";
case regex_constants::error_paren:
return "The expression contained mismatched ( and ).";
case regex_constants::error_brace:
return "The expression contained mismatched { and }.";
case regex_constants::error_badbrace:
return "The expression contained an invalid range in a {} expression.";
case regex_constants::error_range:
return "The expression contained an invalid character range, "
"such as [b-a] in most encodings.";
case regex_constants::error_space:
return "There was insufficient memory to convert the expression into "
"a finite state machine.";
case regex_constants::error_badrepeat:
return "One of *?+{ was not preceded by a valid regular expression.";
case regex_constants::error_complexity:
return "The complexity of an attempted match against a regular "
"expression exceeded a pre-set level.";
case regex_constants::error_stack:
return "There was insufficient memory to determine whether the regular "
"expression could match the specified character sequence.";
case regex_constants::__re_err_grammar:
return "An invalid regex grammar has been requested.";
case regex_constants::__re_err_empty:
return "An empty regex is not allowed in the POSIX grammar.";
case regex_constants::__re_err_parse:
return "The parser did not consume the entire regular expression.";
default:
break;
}
return "Unknown error type";
}
regex_error::regex_error(regex_constants::error_type ecode)
: runtime_error(make_error_type_string(ecode)),
__code_(ecode)
{}
regex_error::~regex_error() throw() {}
namespace {
struct collationnames
{
const char* elem_;
char char_;
};
const collationnames collatenames[] =
{
{"A", 0x41},
{"B", 0x42},
{"C", 0x43},
{"D", 0x44},
{"E", 0x45},
{"F", 0x46},
{"G", 0x47},
{"H", 0x48},
{"I", 0x49},
{"J", 0x4a},
{"K", 0x4b},
{"L", 0x4c},
{"M", 0x4d},
{"N", 0x4e},
{"NUL", 0x00},
{"O", 0x4f},
{"P", 0x50},
{"Q", 0x51},
{"R", 0x52},
{"S", 0x53},
{"T", 0x54},
{"U", 0x55},
{"V", 0x56},
{"W", 0x57},
{"X", 0x58},
{"Y", 0x59},
{"Z", 0x5a},
{"a", 0x61},
{"alert", 0x07},
{"ampersand", 0x26},
{"apostrophe", 0x27},
{"asterisk", 0x2a},
{"b", 0x62},
{"backslash", 0x5c},
{"backspace", 0x08},
{"c", 0x63},
{"carriage-return", 0x0d},
{"circumflex", 0x5e},
{"circumflex-accent", 0x5e},
{"colon", 0x3a},
{"comma", 0x2c},
{"commercial-at", 0x40},
{"d", 0x64},
{"dollar-sign", 0x24},
{"e", 0x65},
{"eight", 0x38},
{"equals-sign", 0x3d},
{"exclamation-mark", 0x21},
{"f", 0x66},
{"five", 0x35},
{"form-feed", 0x0c},
{"four", 0x34},
{"full-stop", 0x2e},
{"g", 0x67},
{"grave-accent", 0x60},
{"greater-than-sign", 0x3e},
{"h", 0x68},
{"hyphen", 0x2d},
{"hyphen-minus", 0x2d},
{"i", 0x69},
{"j", 0x6a},
{"k", 0x6b},
{"l", 0x6c},
{"left-brace", 0x7b},
{"left-curly-bracket", 0x7b},
{"left-parenthesis", 0x28},
{"left-square-bracket", 0x5b},
{"less-than-sign", 0x3c},
{"low-line", 0x5f},
{"m", 0x6d},
{"n", 0x6e},
{"newline", 0x0a},
{"nine", 0x39},
{"number-sign", 0x23},
{"o", 0x6f},
{"one", 0x31},
{"p", 0x70},
{"percent-sign", 0x25},
{"period", 0x2e},
{"plus-sign", 0x2b},
{"q", 0x71},
{"question-mark", 0x3f},
{"quotation-mark", 0x22},
{"r", 0x72},
{"reverse-solidus", 0x5c},
{"right-brace", 0x7d},
{"right-curly-bracket", 0x7d},
{"right-parenthesis", 0x29},
{"right-square-bracket", 0x5d},
{"s", 0x73},
{"semicolon", 0x3b},
{"seven", 0x37},
{"six", 0x36},
{"slash", 0x2f},
{"solidus", 0x2f},
{"space", 0x20},
{"t", 0x74},
{"tab", 0x09},
{"three", 0x33},
{"tilde", 0x7e},
{"two", 0x32},
{"u", 0x75},
{"underscore", 0x5f},
{"v", 0x76},
{"vertical-line", 0x7c},
{"vertical-tab", 0x0b},
{"w", 0x77},
{"x", 0x78},
{"y", 0x79},
{"z", 0x7a},
{"zero", 0x30}
};
struct classnames
{
const char* elem_;
regex_traits<char>::char_class_type mask_;
};
const classnames ClassNames[] =
{
{"alnum", ctype_base::alnum},
{"alpha", ctype_base::alpha},
{"blank", ctype_base::blank},
{"cntrl", ctype_base::cntrl},
{"d", ctype_base::digit},
{"digit", ctype_base::digit},
{"graph", ctype_base::graph},
{"lower", ctype_base::lower},
{"print", ctype_base::print},
{"punct", ctype_base::punct},
{"s", ctype_base::space},
{"space", ctype_base::space},
{"upper", ctype_base::upper},
{"w", regex_traits<char>::__regex_word},
{"xdigit", ctype_base::xdigit}
};
struct use_strcmp
{
bool operator()(const collationnames& x, const char* y)
{return strcmp(x.elem_, y) < 0;}
bool operator()(const classnames& x, const char* y)
{return strcmp(x.elem_, y) < 0;}
};
}
string
__get_collation_name(const char* s)
{
const collationnames* i =
_VSTD::lower_bound(begin(collatenames), end(collatenames), s, use_strcmp());
string r;
if (i != end(collatenames) && strcmp(s, i->elem_) == 0)
r = char(i->char_);
return r;
}
regex_traits<char>::char_class_type
__get_classname(const char* s, bool __icase)
{
const classnames* i =
_VSTD::lower_bound(begin(ClassNames), end(ClassNames), s, use_strcmp());
regex_traits<char>::char_class_type r = 0;
if (i != end(ClassNames) && strcmp(s, i->elem_) == 0)
{
r = i->mask_;
if (r == regex_traits<char>::__regex_word)
r |= ctype_base::alnum | ctype_base::upper | ctype_base::lower;
else if (__icase)
{
if (r & (ctype_base::lower | ctype_base::upper))
r |= ctype_base::alpha;
}
}
return r;
}
template <>
void
__match_any_but_newline<char>::__exec(__state& __s) const
{
if (__s.__current_ != __s.__last_)
{
switch (*__s.__current_)
{
case '\r':
case '\n':
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
break;
default:
__s.__do_ = __state::__accept_and_consume;
++__s.__current_;
__s.__node_ = this->first();
break;
}
}
else
{
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
}
}
template <>
void
__match_any_but_newline<wchar_t>::__exec(__state& __s) const
{
if (__s.__current_ != __s.__last_)
{
switch (*__s.__current_)
{
case '\r':
case '\n':
case 0x2028:
case 0x2029:
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
break;
default:
__s.__do_ = __state::__accept_and_consume;
++__s.__current_;
__s.__node_ = this->first();
break;
}
}
else
{
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
}
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,118 @@
//===---------------------- shared_mutex.cpp ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "shared_mutex"
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
// Shared Mutex Base
__shared_mutex_base::__shared_mutex_base()
: __state_(0)
{
}
// Exclusive ownership
void
__shared_mutex_base::lock()
{
unique_lock<mutex> lk(__mut_);
while (__state_ & __write_entered_)
__gate1_.wait(lk);
__state_ |= __write_entered_;
while (__state_ & __n_readers_)
__gate2_.wait(lk);
}
bool
__shared_mutex_base::try_lock()
{
unique_lock<mutex> lk(__mut_);
if (__state_ == 0)
{
__state_ = __write_entered_;
return true;
}
return false;
}
void
__shared_mutex_base::unlock()
{
lock_guard<mutex> _(__mut_);
__state_ = 0;
__gate1_.notify_all();
}
// Shared ownership
void
__shared_mutex_base::lock_shared()
{
unique_lock<mutex> lk(__mut_);
while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
__gate1_.wait(lk);
unsigned num_readers = (__state_ & __n_readers_) + 1;
__state_ &= ~__n_readers_;
__state_ |= num_readers;
}
bool
__shared_mutex_base::try_lock_shared()
{
unique_lock<mutex> lk(__mut_);
unsigned num_readers = __state_ & __n_readers_;
if (!(__state_ & __write_entered_) && num_readers != __n_readers_)
{
++num_readers;
__state_ &= ~__n_readers_;
__state_ |= num_readers;
return true;
}
return false;
}
void
__shared_mutex_base::unlock_shared()
{
lock_guard<mutex> _(__mut_);
unsigned num_readers = (__state_ & __n_readers_) - 1;
__state_ &= ~__n_readers_;
__state_ |= num_readers;
if (__state_ & __write_entered_)
{
if (num_readers == 0)
__gate2_.notify_one();
}
else
{
if (num_readers == __n_readers_ - 1)
__gate1_.notify_one();
}
}
// Shared Timed Mutex
// These routines are here for ABI stability
shared_timed_mutex::shared_timed_mutex() : __base() {}
void shared_timed_mutex::lock() { return __base.lock(); }
bool shared_timed_mutex::try_lock() { return __base.try_lock(); }
void shared_timed_mutex::unlock() { return __base.unlock(); }
void shared_timed_mutex::lock_shared() { return __base.lock_shared(); }
bool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); }
void shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); }
_LIBCPP_END_NAMESPACE_STD
#endif // !_LIBCPP_HAS_NO_THREADS

View File

@ -0,0 +1,19 @@
//===------------------------ stdexcept.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "stdexcept"
#include "new"
#include "string"
#include "system_error"
#ifdef _LIBCPP_ABI_VCRUNTIME
#include "support/runtime/stdexcept_vcruntime.ipp"
#else
#include "support/runtime/stdexcept_default.ipp"
#endif

458
lib/libcxx/src/string.cpp Normal file
View File

@ -0,0 +1,458 @@
//===------------------------- string.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "string"
#include "charconv"
#include "cstdlib"
#include "cwchar"
#include "cerrno"
#include "limits"
#include "stdexcept"
#include <stdio.h>
#include "__debug"
_LIBCPP_BEGIN_NAMESPACE_STD
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
template
string
operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
namespace
{
template<typename T>
inline
void throw_helper( const string& msg )
{
#ifndef _LIBCPP_NO_EXCEPTIONS
throw T( msg );
#else
fprintf(stderr, "%s\n", msg.c_str());
_VSTD::abort();
#endif
}
inline
void throw_from_string_out_of_range( const string& func )
{
throw_helper<out_of_range>(func + ": out of range");
}
inline
void throw_from_string_invalid_arg( const string& func )
{
throw_helper<invalid_argument>(func + ": no conversion");
}
// as_integer
template<typename V, typename S, typename F>
inline
V
as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
{
typename S::value_type* ptr = nullptr;
const typename S::value_type* const p = str.c_str();
typename remove_reference<decltype(errno)>::type errno_save = errno;
errno = 0;
V r = f(p, &ptr, base);
swap(errno, errno_save);
if (errno_save == ERANGE)
throw_from_string_out_of_range(func);
if (ptr == p)
throw_from_string_invalid_arg(func);
if (idx)
*idx = static_cast<size_t>(ptr - p);
return r;
}
template<typename V, typename S>
inline
V
as_integer(const string& func, const S& s, size_t* idx, int base);
// string
template<>
inline
int
as_integer(const string& func, const string& s, size_t* idx, int base )
{
// Use long as no Standard string to integer exists.
long r = as_integer_helper<long>( func, s, idx, base, strtol );
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
throw_from_string_out_of_range(func);
return static_cast<int>(r);
}
template<>
inline
long
as_integer(const string& func, const string& s, size_t* idx, int base )
{
return as_integer_helper<long>( func, s, idx, base, strtol );
}
template<>
inline
unsigned long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
}
template<>
inline
long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
return as_integer_helper<long long>( func, s, idx, base, strtoll );
}
template<>
inline
unsigned long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
}
// wstring
template<>
inline
int
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
// Use long as no Stantard string to integer exists.
long r = as_integer_helper<long>( func, s, idx, base, wcstol );
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
throw_from_string_out_of_range(func);
return static_cast<int>(r);
}
template<>
inline
long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
return as_integer_helper<long>( func, s, idx, base, wcstol );
}
template<>
inline
unsigned long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
}
template<>
inline
long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
return as_integer_helper<long long>( func, s, idx, base, wcstoll );
}
template<>
inline
unsigned long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
}
// as_float
template<typename V, typename S, typename F>
inline
V
as_float_helper(const string& func, const S& str, size_t* idx, F f )
{
typename S::value_type* ptr = nullptr;
const typename S::value_type* const p = str.c_str();
typename remove_reference<decltype(errno)>::type errno_save = errno;
errno = 0;
V r = f(p, &ptr);
swap(errno, errno_save);
if (errno_save == ERANGE)
throw_from_string_out_of_range(func);
if (ptr == p)
throw_from_string_invalid_arg(func);
if (idx)
*idx = static_cast<size_t>(ptr - p);
return r;
}
template<typename V, typename S>
inline
V as_float( const string& func, const S& s, size_t* idx = nullptr );
template<>
inline
float
as_float( const string& func, const string& s, size_t* idx )
{
return as_float_helper<float>( func, s, idx, strtof );
}
template<>
inline
double
as_float(const string& func, const string& s, size_t* idx )
{
return as_float_helper<double>( func, s, idx, strtod );
}
template<>
inline
long double
as_float( const string& func, const string& s, size_t* idx )
{
return as_float_helper<long double>( func, s, idx, strtold );
}
template<>
inline
float
as_float( const string& func, const wstring& s, size_t* idx )
{
return as_float_helper<float>( func, s, idx, wcstof );
}
template<>
inline
double
as_float( const string& func, const wstring& s, size_t* idx )
{
return as_float_helper<double>( func, s, idx, wcstod );
}
template<>
inline
long double
as_float( const string& func, const wstring& s, size_t* idx )
{
return as_float_helper<long double>( func, s, idx, wcstold );
}
} // unnamed namespace
int
stoi(const string& str, size_t* idx, int base)
{
return as_integer<int>( "stoi", str, idx, base );
}
int
stoi(const wstring& str, size_t* idx, int base)
{
return as_integer<int>( "stoi", str, idx, base );
}
long
stol(const string& str, size_t* idx, int base)
{
return as_integer<long>( "stol", str, idx, base );
}
long
stol(const wstring& str, size_t* idx, int base)
{
return as_integer<long>( "stol", str, idx, base );
}
unsigned long
stoul(const string& str, size_t* idx, int base)
{
return as_integer<unsigned long>( "stoul", str, idx, base );
}
unsigned long
stoul(const wstring& str, size_t* idx, int base)
{
return as_integer<unsigned long>( "stoul", str, idx, base );
}
long long
stoll(const string& str, size_t* idx, int base)
{
return as_integer<long long>( "stoll", str, idx, base );
}
long long
stoll(const wstring& str, size_t* idx, int base)
{
return as_integer<long long>( "stoll", str, idx, base );
}
unsigned long long
stoull(const string& str, size_t* idx, int base)
{
return as_integer<unsigned long long>( "stoull", str, idx, base );
}
unsigned long long
stoull(const wstring& str, size_t* idx, int base)
{
return as_integer<unsigned long long>( "stoull", str, idx, base );
}
float
stof(const string& str, size_t* idx)
{
return as_float<float>( "stof", str, idx );
}
float
stof(const wstring& str, size_t* idx)
{
return as_float<float>( "stof", str, idx );
}
double
stod(const string& str, size_t* idx)
{
return as_float<double>( "stod", str, idx );
}
double
stod(const wstring& str, size_t* idx)
{
return as_float<double>( "stod", str, idx );
}
long double
stold(const string& str, size_t* idx)
{
return as_float<long double>( "stold", str, idx );
}
long double
stold(const wstring& str, size_t* idx)
{
return as_float<long double>( "stold", str, idx );
}
// to_string
namespace
{
// as_string
template<typename S, typename P, typename V >
inline
S
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
typedef typename S::size_type size_type;
size_type available = s.size();
while (true)
{
int status = sprintf_like(&s[0], available + 1, fmt, a);
if ( status >= 0 )
{
size_type used = static_cast<size_type>(status);
if ( used <= available )
{
s.resize( used );
break;
}
available = used; // Assume this is advice of how much space we need.
}
else
available = available * 2 + 1;
s.resize(available);
}
return s;
}
template <class S>
struct initial_string;
template <>
struct initial_string<string>
{
string
operator()() const
{
string s;
s.resize(s.capacity());
return s;
}
};
template <>
struct initial_string<wstring>
{
wstring
operator()() const
{
wstring s(20, wchar_t());
s.resize(s.capacity());
return s;
}
};
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
inline
wide_printf
get_swprintf()
{
#ifndef _LIBCPP_MSVCRT
return swprintf;
#else
return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
#endif
}
template <typename S, typename V>
S i_to_string(const V v)
{
// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
// so we need +1 here.
constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10
char buf[bufsize];
const auto res = to_chars(buf, buf + bufsize, v);
_LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
return S(buf, res.ptr);
}
} // unnamed namespace
string to_string (int val) { return i_to_string< string>(val); }
string to_string (long val) { return i_to_string< string>(val); }
string to_string (long long val) { return i_to_string< string>(val); }
string to_string (unsigned val) { return i_to_string< string>(val); }
string to_string (unsigned long val) { return i_to_string< string>(val); }
string to_string (unsigned long long val) { return i_to_string< string>(val); }
wstring to_wstring(int val) { return i_to_string<wstring>(val); }
wstring to_wstring(long val) { return i_to_string<wstring>(val); }
wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
string to_string (float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
string to_string (double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
string to_string (long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,335 @@
//===------------------------ strstream.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "strstream"
#include "algorithm"
#include "climits"
#include "cstring"
#include "cstdlib"
#include "__debug"
#include "__undef_macros"
_LIBCPP_BEGIN_NAMESPACE_STD
strstreambuf::strstreambuf(streamsize __alsize)
: __strmode_(__dynamic),
__alsize_(__alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
}
strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
: __strmode_(__dynamic),
__alsize_(__default_alsize),
__palloc_(__palloc),
__pfree_(__pfree)
{
}
void
strstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg)
{
if (__n == 0)
__n = static_cast<streamsize>(strlen(__gnext));
else if (__n < 0)
__n = INT_MAX;
if (__pbeg == nullptr)
setg(__gnext, __gnext, __gnext + __n);
else
{
setg(__gnext, __gnext, __pbeg);
setp(__pbeg, __pbeg + __n);
}
}
strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
: __strmode_(),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(__gnext, __n, __pbeg);
}
strstreambuf::strstreambuf(const char* __gnext, streamsize __n)
: __strmode_(__constant),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(const_cast<char *>(__gnext), __n, nullptr);
}
strstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)
: __strmode_(),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
}
strstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)
: __strmode_(__constant),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
}
strstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)
: __strmode_(),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
}
strstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)
: __strmode_(__constant),
__alsize_(__default_alsize),
__palloc_(nullptr),
__pfree_(nullptr)
{
__init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
}
strstreambuf::~strstreambuf()
{
if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0)
{
if (__pfree_)
__pfree_(eback());
else
delete [] eback();
}
}
void
strstreambuf::swap(strstreambuf& __rhs)
{
streambuf::swap(__rhs);
_VSTD::swap(__strmode_, __rhs.__strmode_);
_VSTD::swap(__alsize_, __rhs.__alsize_);
_VSTD::swap(__palloc_, __rhs.__palloc_);
_VSTD::swap(__pfree_, __rhs.__pfree_);
}
void
strstreambuf::freeze(bool __freezefl)
{
if (__strmode_ & __dynamic)
{
if (__freezefl)
__strmode_ |= __frozen;
else
__strmode_ &= ~__frozen;
}
}
char*
strstreambuf::str()
{
if (__strmode_ & __dynamic)
__strmode_ |= __frozen;
return eback();
}
int
strstreambuf::pcount() const
{
return static_cast<int>(pptr() - pbase());
}
strstreambuf::int_type
strstreambuf::overflow(int_type __c)
{
if (__c == EOF)
return int_type(0);
if (pptr() == epptr())
{
if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
return int_type(EOF);
size_t old_size = static_cast<size_t> ((epptr() ? epptr() : egptr()) - eback());
size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2*old_size);
if (new_size == 0)
new_size = __default_alsize;
char* buf = nullptr;
if (__palloc_)
buf = static_cast<char*>(__palloc_(new_size));
else
buf = new char[new_size];
if (buf == nullptr)
return int_type(EOF);
if (old_size != 0) {
_LIBCPP_ASSERT(eback(), "overflow copying from NULL");
memcpy(buf, eback(), static_cast<size_t>(old_size));
}
ptrdiff_t ninp = gptr() - eback();
ptrdiff_t einp = egptr() - eback();
ptrdiff_t nout = pptr() - pbase();
if (__strmode_ & __allocated)
{
if (__pfree_)
__pfree_(eback());
else
delete [] eback();
}
setg(buf, buf + ninp, buf + einp);
setp(buf + einp, buf + new_size);
__pbump(nout);
__strmode_ |= __allocated;
}
*pptr() = static_cast<char>(__c);
pbump(1);
return int_type(static_cast<unsigned char>(__c));
}
strstreambuf::int_type
strstreambuf::pbackfail(int_type __c)
{
if (eback() == gptr())
return EOF;
if (__c == EOF)
{
gbump(-1);
return int_type(0);
}
if (__strmode_ & __constant)
{
if (gptr()[-1] == static_cast<char>(__c))
{
gbump(-1);
return __c;
}
return EOF;
}
gbump(-1);
*gptr() = static_cast<char>(__c);
return __c;
}
strstreambuf::int_type
strstreambuf::underflow()
{
if (gptr() == egptr())
{
if (egptr() >= pptr())
return EOF;
setg(eback(), gptr(), pptr());
}
return int_type(static_cast<unsigned char>(*gptr()));
}
strstreambuf::pos_type
strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
{
off_type __p(-1);
bool pos_in = (__which & ios::in) != 0;
bool pos_out = (__which & ios::out) != 0;
bool legal = false;
switch (__way)
{
case ios::beg:
case ios::end:
if (pos_in || pos_out)
legal = true;
break;
case ios::cur:
if (pos_in != pos_out)
legal = true;
break;
}
if (pos_in && gptr() == nullptr)
legal = false;
if (pos_out && pptr() == nullptr)
legal = false;
if (legal)
{
off_type newoff;
char* seekhigh = epptr() ? epptr() : egptr();
switch (__way)
{
case ios::beg:
newoff = 0;
break;
case ios::cur:
newoff = (pos_in ? gptr() : pptr()) - eback();
break;
case ios::end:
newoff = seekhigh - eback();
break;
default:
_LIBCPP_UNREACHABLE();
}
newoff += __off;
if (0 <= newoff && newoff <= seekhigh - eback())
{
char* newpos = eback() + newoff;
if (pos_in)
setg(eback(), newpos, _VSTD::max(newpos, egptr()));
if (pos_out)
{
// min(pbase, newpos), newpos, epptr()
__off = epptr() - newpos;
setp(min(pbase(), newpos), epptr());
__pbump((epptr() - pbase()) - __off);
}
__p = newoff;
}
}
return pos_type(__p);
}
strstreambuf::pos_type
strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which)
{
off_type __p(-1);
bool pos_in = (__which & ios::in) != 0;
bool pos_out = (__which & ios::out) != 0;
if (pos_in || pos_out)
{
if (!((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr)))
{
off_type newoff = __sp;
char* seekhigh = epptr() ? epptr() : egptr();
if (0 <= newoff && newoff <= seekhigh - eback())
{
char* newpos = eback() + newoff;
if (pos_in)
setg(eback(), newpos, _VSTD::max(newpos, egptr()));
if (pos_out)
{
// min(pbase, newpos), newpos, epptr()
off_type temp = epptr() - newpos;
setp(min(pbase(), newpos), epptr());
__pbump((epptr() - pbase()) - temp);
}
__p = newoff;
}
}
}
return pos_type(__p);
}
istrstream::~istrstream()
{
}
ostrstream::~ostrstream()
{
}
strstream::~strstream()
{
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,164 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <cstdio>
namespace std {
_LIBCPP_SAFE_STATIC static std::terminate_handler __terminate_handler;
_LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler;
// libcxxrt provides implementations of these functions itself.
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
return __libcpp_atomic_exchange(&__unexpected_handler, func);
}
unexpected_handler
get_unexpected() _NOEXCEPT
{
return __libcpp_atomic_load(&__unexpected_handler);
}
_LIBCPP_NORETURN
void unexpected()
{
(*get_unexpected())();
// unexpected handler should not return
terminate();
}
terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
return __libcpp_atomic_exchange(&__terminate_handler, func);
}
terminate_handler
get_terminate() _NOEXCEPT
{
return __libcpp_atomic_load(&__terminate_handler);
}
#ifndef __EMSCRIPTEN__ // We provide this in JS
_LIBCPP_NORETURN
void
terminate() _NOEXCEPT
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
(*get_terminate())();
// handler should not return
fprintf(stderr, "terminate_handler unexpectedly returned\n");
::abort();
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
// handler should not throw exception
fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
::abort();
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
#endif // !__EMSCRIPTEN__
#if !defined(__EMSCRIPTEN__)
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
int uncaught_exceptions() _NOEXCEPT
{
#warning uncaught_exception not yet implemented
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
::abort();
}
#endif // !__EMSCRIPTEN__
exception::~exception() _NOEXCEPT
{
}
const char* exception::what() const _NOEXCEPT
{
return "std::exception";
}
bad_exception::~bad_exception() _NOEXCEPT
{
}
const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
bad_alloc::bad_alloc() _NOEXCEPT
{
}
bad_alloc::~bad_alloc() _NOEXCEPT
{
}
const char*
bad_alloc::what() const _NOEXCEPT
{
return "std::bad_alloc";
}
bad_array_new_length::bad_array_new_length() _NOEXCEPT
{
}
bad_array_new_length::~bad_array_new_length() _NOEXCEPT
{
}
const char*
bad_array_new_length::what() const _NOEXCEPT
{
return "bad_array_new_length";
}
bad_cast::bad_cast() _NOEXCEPT
{
}
bad_typeid::bad_typeid() _NOEXCEPT
{
}
bad_cast::~bad_cast() _NOEXCEPT
{
}
const char*
bad_cast::what() const _NOEXCEPT
{
return "std::bad_cast";
}
bad_typeid::~bad_typeid() _NOEXCEPT
{
}
const char*
bad_typeid::what() const _NOEXCEPT
{
return "std::bad_typeid";
}
} // namespace std

View File

@ -0,0 +1,32 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef __GLIBCXX__
#error header can only be used when targeting libstdc++ or libsupc++
#endif
namespace std {
bad_alloc::bad_alloc() _NOEXCEPT
{
}
bad_array_new_length::bad_array_new_length() _NOEXCEPT
{
}
bad_cast::bad_cast() _NOEXCEPT
{
}
bad_typeid::bad_typeid() _NOEXCEPT
{
}
} // namespace std

View File

@ -0,0 +1,27 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPPABI_VERSION
#error this header can only be used with libc++abi
#endif
namespace std {
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
int uncaught_exceptions() _NOEXCEPT
{
# if _LIBCPPABI_VERSION > 1001
return __cxa_uncaught_exceptions();
# else
return __cxa_uncaught_exception() ? 1 : 0;
# endif
}
} // namespace std

View File

@ -0,0 +1,25 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXXRT
#error this header may only be used when targeting libcxxrt
#endif
namespace std {
bad_exception::~bad_exception() _NOEXCEPT
{
}
const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
} // namespace std

View File

@ -0,0 +1,163 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_ABI_MICROSOFT
#error this header can only be used when targeting the MSVC ABI
#endif
#include <stdio.h>
#include <stdlib.h>
extern "C" {
typedef void (__cdecl* terminate_handler)();
_LIBCPP_CRT_FUNC terminate_handler __cdecl set_terminate(
terminate_handler _NewTerminateHandler) throw();
_LIBCPP_CRT_FUNC terminate_handler __cdecl _get_terminate();
typedef void (__cdecl* unexpected_handler)();
unexpected_handler __cdecl set_unexpected(
unexpected_handler _NewUnexpectedHandler) throw();
unexpected_handler __cdecl _get_unexpected();
int __cdecl __uncaught_exceptions();
}
namespace std {
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT {
return ::set_unexpected(func);
}
unexpected_handler get_unexpected() _NOEXCEPT {
return ::_get_unexpected();
}
_LIBCPP_NORETURN
void unexpected() {
(*get_unexpected())();
// unexpected handler should not return
terminate();
}
terminate_handler set_terminate(terminate_handler func) _NOEXCEPT {
return ::set_terminate(func);
}
terminate_handler get_terminate() _NOEXCEPT {
return ::_get_terminate();
}
_LIBCPP_NORETURN
void terminate() _NOEXCEPT
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
(*get_terminate())();
// handler should not return
fprintf(stderr, "terminate_handler unexpectedly returned\n");
::abort();
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
// handler should not throw exception
fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
::abort();
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
int uncaught_exceptions() _NOEXCEPT {
return __uncaught_exceptions();
}
#if !defined(_LIBCPP_ABI_VCRUNTIME)
bad_cast::bad_cast() _NOEXCEPT
{
}
bad_cast::~bad_cast() _NOEXCEPT
{
}
const char *
bad_cast::what() const _NOEXCEPT
{
return "std::bad_cast";
}
bad_typeid::bad_typeid() _NOEXCEPT
{
}
bad_typeid::~bad_typeid() _NOEXCEPT
{
}
const char *
bad_typeid::what() const _NOEXCEPT
{
return "std::bad_typeid";
}
exception::~exception() _NOEXCEPT
{
}
const char* exception::what() const _NOEXCEPT
{
return "std::exception";
}
bad_exception::~bad_exception() _NOEXCEPT
{
}
const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
bad_alloc::bad_alloc() _NOEXCEPT
{
}
bad_alloc::~bad_alloc() _NOEXCEPT
{
}
const char*
bad_alloc::what() const _NOEXCEPT
{
return "std::bad_alloc";
}
bad_array_new_length::bad_array_new_length() _NOEXCEPT
{
}
bad_array_new_length::~bad_array_new_length() _NOEXCEPT
{
}
const char*
bad_array_new_length::what() const _NOEXCEPT
{
return "bad_array_new_length";
}
#endif // !_LIBCPP_ABI_VCRUNTIME
} // namespace std

View File

@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef HAVE_DEPENDENT_EH_ABI
#error this header may only be used with libc++abi or libcxxrt
#endif
namespace std {
exception_ptr::~exception_ptr() _NOEXCEPT {
__cxa_decrement_exception_refcount(__ptr_);
}
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
: __ptr_(other.__ptr_)
{
__cxa_increment_exception_refcount(__ptr_);
}
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
if (__ptr_ != other.__ptr_)
{
__cxa_increment_exception_refcount(other.__ptr_);
__cxa_decrement_exception_refcount(__ptr_);
__ptr_ = other.__ptr_;
}
return *this;
}
nested_exception::nested_exception() _NOEXCEPT
: __ptr_(current_exception())
{
}
nested_exception::~nested_exception() _NOEXCEPT
{
}
_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
}
exception_ptr current_exception() _NOEXCEPT
{
// be nicer if there was a constructor that took a ptr, then
// this whole function would be just:
// return exception_ptr(__cxa_current_primary_exception());
exception_ptr ptr;
ptr.__ptr_ = __cxa_current_primary_exception();
return ptr;
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
__cxa_rethrow_primary_exception(p.__ptr_);
// if p.__ptr_ is NULL, above returns so we terminate
terminate();
}
} // namespace std

View File

@ -0,0 +1,77 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// libsupc++ does not implement the dependent EH ABI and the functionality
// it uses to implement std::exception_ptr (which it declares as an alias of
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
// (which fortunately has the same layout as our std::exception_ptr) copy
// constructor, assignment operator and destructor (which are part of its
// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
// function.
namespace std {
namespace __exception_ptr
{
struct exception_ptr
{
void* __ptr_;
exception_ptr(const exception_ptr&) _NOEXCEPT;
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
~exception_ptr() _NOEXCEPT;
};
}
_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
exception_ptr::~exception_ptr() _NOEXCEPT
{
reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
}
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
: __ptr_(other.__ptr_)
{
new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
}
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
*reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
return *this;
}
nested_exception::nested_exception() _NOEXCEPT
: __ptr_(current_exception())
{
}
_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
}
} // namespace std

View File

@ -0,0 +1,86 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <stdlib.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCreate(void*);
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrDestroy(void*);
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopy(void*, const void*);
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrAssign(void*, const void*);
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrCompare(const void*, const void*);
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrToBool(const void*);
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrSwap(void*, void*);
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCurrentException(void*);
[[noreturn]] _LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrRethrow(const void*);
_LIBCPP_CRT_FUNC void __cdecl
__ExceptionPtrCopyException(void*, const void*, const void*);
namespace std {
exception_ptr::exception_ptr() _NOEXCEPT { __ExceptionPtrCreate(this); }
exception_ptr::exception_ptr(nullptr_t) _NOEXCEPT { __ExceptionPtrCreate(this); }
exception_ptr::exception_ptr(const exception_ptr& __other) _NOEXCEPT {
__ExceptionPtrCopy(this, &__other);
}
exception_ptr& exception_ptr::operator=(const exception_ptr& __other) _NOEXCEPT {
__ExceptionPtrAssign(this, &__other);
return *this;
}
exception_ptr& exception_ptr::operator=(nullptr_t) _NOEXCEPT {
exception_ptr dummy;
__ExceptionPtrAssign(this, &dummy);
return *this;
}
exception_ptr::~exception_ptr() _NOEXCEPT { __ExceptionPtrDestroy(this); }
exception_ptr::operator bool() const _NOEXCEPT {
return __ExceptionPtrToBool(this);
}
bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
return __ExceptionPtrCompare(&__x, &__y);
}
void swap(exception_ptr& lhs, exception_ptr& rhs) _NOEXCEPT {
__ExceptionPtrSwap(&rhs, &lhs);
}
exception_ptr __copy_exception_ptr(void* __except, const void* __ptr) {
exception_ptr __ret = nullptr;
if (__ptr)
__ExceptionPtrCopyException(&__ret, __except, __ptr);
return __ret;
}
exception_ptr current_exception() _NOEXCEPT {
exception_ptr __ret;
__ExceptionPtrCurrentException(&__ret);
return __ret;
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p) { __ExceptionPtrRethrow(&p); }
nested_exception::nested_exception() _NOEXCEPT : __ptr_(current_exception()) {}
nested_exception::~nested_exception() _NOEXCEPT {}
_LIBCPP_NORETURN
void nested_exception::rethrow_nested() const {
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
}
} // namespace std

View File

@ -0,0 +1,79 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <stdlib.h>
namespace std {
exception_ptr::~exception_ptr() _NOEXCEPT
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
: __ptr_(other.__ptr_)
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
nested_exception::nested_exception() _NOEXCEPT
: __ptr_(current_exception())
{
}
#if !defined(__GLIBCXX__)
nested_exception::~nested_exception() _NOEXCEPT
{
}
#endif
_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
#if 0
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
#endif // FIXME
}
exception_ptr current_exception() _NOEXCEPT
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
# warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
} // namespace std

View File

@ -0,0 +1,26 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
namespace std {
_LIBCPP_SAFE_STATIC static std::new_handler __new_handler;
new_handler
set_new_handler(new_handler handler) _NOEXCEPT
{
return __libcpp_atomic_exchange(&__new_handler, handler);
}
new_handler
get_new_handler() _NOEXCEPT
{
return __libcpp_atomic_load(&__new_handler);
}
} // namespace std

View File

@ -0,0 +1,64 @@
//===--------------------- stdexcept_default.ipp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "../../include/refstring.h"
/* For _LIBCPPABI_VERSION */
#if !defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY) && \
(defined(LIBCXX_BUILDING_LIBCXXABI) || defined(LIBCXXRT))
#include <cxxabi.h>
#endif
static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char*), "");
namespace std // purposefully not using versioning namespace
{
logic_error::logic_error(const string& msg) : __imp_(msg.c_str()) {}
logic_error::logic_error(const char* msg) : __imp_(msg) {}
logic_error::logic_error(const logic_error& le) _NOEXCEPT : __imp_(le.__imp_) {}
logic_error& logic_error::operator=(const logic_error& le) _NOEXCEPT {
__imp_ = le.__imp_;
return *this;
}
runtime_error::runtime_error(const string& msg) : __imp_(msg.c_str()) {}
runtime_error::runtime_error(const char* msg) : __imp_(msg) {}
runtime_error::runtime_error(const runtime_error& re) _NOEXCEPT
: __imp_(re.__imp_) {}
runtime_error& runtime_error::operator=(const runtime_error& re) _NOEXCEPT {
__imp_ = re.__imp_;
return *this;
}
#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)
const char* logic_error::what() const _NOEXCEPT { return __imp_.c_str(); }
const char* runtime_error::what() const _NOEXCEPT { return __imp_.c_str(); }
logic_error::~logic_error() _NOEXCEPT {}
domain_error::~domain_error() _NOEXCEPT {}
invalid_argument::~invalid_argument() _NOEXCEPT {}
length_error::~length_error() _NOEXCEPT {}
out_of_range::~out_of_range() _NOEXCEPT {}
runtime_error::~runtime_error() _NOEXCEPT {}
range_error::~range_error() _NOEXCEPT {}
overflow_error::~overflow_error() _NOEXCEPT {}
underflow_error::~underflow_error() _NOEXCEPT {}
#endif
} // namespace std

View File

@ -0,0 +1,16 @@
//===------------------- stdexcept_vcruntime.ipp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_ABI_VCRUNTIME
#error This file may only be used when defering to vcruntime
#endif
namespace std {
logic_error::logic_error(std::string const& s) : exception(s.c_str()) {}
runtime_error::runtime_error(std::string const& s) : exception(s.c_str()) {}
} // namespace std

View File

@ -0,0 +1,4 @@
This directory contains a partial implementation of the xlocale APIs for
Solaris. Some portions are lifted from FreeBSD libc, and so are covered by a
2-clause BSD license instead of the MIT/UUIC license that the rest of libc++ is
distributed under.

View File

@ -0,0 +1,76 @@
/*-
* As noted in the source, some portions of this implementation are copied from
* FreeBSD libc. These are covered by the following copyright:
*
* Copyright (c) 2002-2004 Tim J. Robbins.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
size_t
mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps, locale_t loc)
{
const char *s;
size_t nchr;
wchar_t wc;
size_t nb;
FIX_LOCALE(loc);
s = *src;
nchr = 0;
if (dst == NULL) {
for (;;) {
if ((nb = mbrtowc_l(&wc, s, nms, ps, loc)) == (size_t)-1)
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
else if (nb == 0 || nb == (size_t)-2)
return (nchr);
s += nb;
nms -= nb;
nchr++;
}
/*NOTREACHED*/
}
while (len-- > 0) {
if ((nb = mbrtowc_l(dst, s, nms, ps, loc)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
*src = s + nms;
return (nchr);
} else if (nb == 0) {
*src = NULL;
return (nchr);
}
s += nb;
nms -= nb;
nchr++;
dst++;
}
*src = s;
return (nchr);
}

View File

@ -0,0 +1,92 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
size_t
wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps, locale_t loc)
{
FIX_LOCALE(loc);
mbstate_t mbsbak;
char buf[MB_CUR_MAX_L(loc)];
const wchar_t *s;
size_t nbytes;
size_t nb;
s = *src;
nbytes = 0;
if (dst == NULL) {
while (nwc-- > 0) {
if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1)
/* Invalid character - wcrtomb() sets errno. */
return ((size_t)-1);
else if (*s == L'\0')
return (nbytes + nb - 1);
s++;
nbytes += nb;
}
return (nbytes);
}
while (len > 0 && nwc-- > 0) {
if (len > (size_t)MB_CUR_MAX_L(loc)) {
/* Enough space to translate in-place. */
if ((nb = wcrtomb_l(dst, *s, ps, loc)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
} else {
/*
* May not be enough space; use temp. buffer.
*
* We need to save a copy of the conversion state
* here so we can restore it if the multibyte
* character is too long for the buffer.
*/
mbsbak = *ps;
if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
if (nb > (int)len) {
/* MB sequence for character won't fit. */
*ps = mbsbak;
break;
}
memcpy(dst, buf, nb);
}
if (*s == L'\0') {
*src = NULL;
return (nbytes + nb - 1);
}
s++;
dst += nb;
len -= nb;
nbytes += nb;
}
*src = s;
return (nbytes);
}

View File

@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifdef __sun__
#include "support/solaris/xlocale.h"
#include <stdarg.h>
#include <stdio.h>
#include <sys/localedef.h>
extern "C" {
int isxdigit_l(int __c, locale_t __l) {
return isxdigit(__c);
}
int iswxdigit_l(wint_t __c, locale_t __l) {
return isxdigit(__c);
}
// FIXME: This disregards the locale, which is Very Wrong
#define vsnprintf_l(__s, __n, __l, __format, __va) \
vsnprintf(__s, __n, __format, __va)
int snprintf_l(char *__s, size_t __n, locale_t __l, const char *__format, ...)
{
va_list __va;
va_start(__va, __format);
int __res = vsnprintf_l(__s, __n , __l, __format, __va);
va_end(__va);
return __res;
}
int asprintf_l(char **__s, locale_t __l, const char *__format, ...) {
va_list __va;
va_start(__va, __format);
// FIXME:
int __res = vasprintf(__s, __format, __va);
va_end(__va);
return __res;
}
int sscanf_l(const char *__s, locale_t __l, const char *__format, ...) {
va_list __va;
va_start(__va, __format);
// FIXME:
int __res = vsscanf(__s, __format, __va);
va_end(__va);
return __res;
}
size_t mbrtowc_l(wchar_t *__pwc, const char *__pmb,
size_t __max, mbstate_t *__ps, locale_t __loc) {
return mbrtowc(__pwc, __pmb, __max, __ps);
}
struct lconv *localeconv_l(locale_t __l) {
return localeconv();
}
};
#endif // __sun__

View File

@ -0,0 +1,139 @@
// -*- C++ -*-
//===-------------------- support/win32/locale_win32.cpp ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <locale>
#include <cstdarg> // va_start, va_end
#include <memory>
#include <type_traits>
int __libcpp_vasprintf(char **sptr, const char *__restrict fmt, va_list ap);
using std::__libcpp_locale_guard;
// FIXME: base currently unused. Needs manual work to construct the new locale
locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
{
return {_create_locale( LC_ALL, locale ), locale};
}
decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
{
#if defined(_LIBCPP_MSVCRT)
return ___mb_cur_max_l_func(__l);
#else
__libcpp_locale_guard __current(__l);
return MB_CUR_MAX;
#endif
}
lconv *localeconv_l( locale_t &loc )
{
__libcpp_locale_guard __current(loc);
lconv *lc = localeconv();
if (!lc)
return lc;
return loc.__store_lconv(lc);
}
size_t mbrlen_l( const char *__restrict s, size_t n,
mbstate_t *__restrict ps, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return mbrlen( s, n, ps );
}
size_t mbsrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
size_t len, mbstate_t *__restrict ps, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return mbsrtowcs( dst, src, len, ps );
}
size_t wcrtomb_l( char *__restrict s, wchar_t wc, mbstate_t *__restrict ps,
locale_t loc )
{
__libcpp_locale_guard __current(loc);
return wcrtomb( s, wc, ps );
}
size_t mbrtowc_l( wchar_t *__restrict pwc, const char *__restrict s,
size_t n, mbstate_t *__restrict ps, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return mbrtowc( pwc, s, n, ps );
}
size_t mbsnrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
size_t nms, size_t len, mbstate_t *__restrict ps, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return mbsnrtowcs( dst, src, nms, len, ps );
}
size_t wcsnrtombs_l( char *__restrict dst, const wchar_t **__restrict src,
size_t nwc, size_t len, mbstate_t *__restrict ps, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return wcsnrtombs( dst, src, nwc, len, ps );
}
wint_t btowc_l( int c, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return btowc( c );
}
int wctob_l( wint_t c, locale_t loc )
{
__libcpp_locale_guard __current(loc);
return wctob( c );
}
int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...)
{
va_list ap;
va_start( ap, format );
#if defined(_LIBCPP_MSVCRT)
// FIXME: Remove usage of internal CRT function and globals.
int result = __stdio_common_vsprintf(
_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS | _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR,
ret, n, format, loc, ap);
#else
__libcpp_locale_guard __current(loc);
int result = vsnprintf( ret, n, format, ap );
#endif
va_end(ap);
return result;
}
int asprintf_l( char **ret, locale_t loc, const char *format, ... )
{
va_list ap;
va_start( ap, format );
int result = vasprintf_l( ret, loc, format, ap );
va_end(ap);
return result;
}
int vasprintf_l( char **ret, locale_t loc, const char *format, va_list ap )
{
__libcpp_locale_guard __current(loc);
return __libcpp_vasprintf( ret, format, ap );
}
#if !defined(_LIBCPP_MSVCRT)
float strtof_l(const char* nptr, char** endptr, locale_t loc) {
__libcpp_locale_guard __current(loc);
return strtof(nptr, endptr);
}
long double strtold_l(const char* nptr, char** endptr, locale_t loc) {
__libcpp_locale_guard __current(loc);
return strtold(nptr, endptr);
}
#endif
#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800
size_t strftime_l(char *ret, size_t n, const char *format, const struct tm *tm,
locale_t loc) {
__libcpp_locale_guard __current(loc);
return strftime(ret, n, format, tm);
}
#endif

View File

@ -0,0 +1,164 @@
// -*- C++ -*-
//===----------------------- support/win32/support.h ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <cstdarg> // va_start, va_end
#include <cstddef> // size_t
#include <cstdlib> // malloc
#include <cstdio> // vsprintf, vsnprintf
#include <cstring> // strcpy, wcsncpy
#include <cwchar> // mbstate_t
// Like sprintf, but when return value >= 0 it returns
// a pointer to a malloc'd string in *sptr.
// If return >= 0, use free to delete *sptr.
int __libcpp_vasprintf( char **sptr, const char *__restrict format, va_list ap )
{
*sptr = NULL;
// Query the count required.
int count = _vsnprintf( NULL, 0, format, ap );
if (count < 0)
return count;
size_t buffer_size = static_cast<size_t>(count) + 1;
char* p = static_cast<char*>(malloc(buffer_size));
if ( ! p )
return -1;
// If we haven't used exactly what was required, something is wrong.
// Maybe bug in vsnprintf. Report the error and return.
if (_vsnprintf(p, buffer_size, format, ap) != count) {
free(p);
return -1;
}
// All good. This is returning memory to the caller not freeing it.
*sptr = p;
return count;
}
// Returns >= 0: the number of wide characters found in the
// multi byte sequence src (of src_size_bytes), that fit in the buffer dst
// (of max_dest_chars elements size). The count returned excludes the
// null terminator. When dst is NULL, no characters are copied
// and no "out" parameters are updated.
// Returns (size_t) -1: an incomplete sequence encountered.
// Leaves *src pointing the next character to convert or NULL
// if a null character was converted from *src.
size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
{
const size_t terminated_sequence = static_cast<size_t>(0);
//const size_t invalid_sequence = static_cast<size_t>(-1);
const size_t incomplete_sequence = static_cast< size_t>(-2);
size_t dest_converted = 0;
size_t source_converted = 0;
size_t source_remaining = src_size_bytes;
size_t result = 0;
bool have_result = false;
// If dst is null then max_dest_chars should be ignored according to the
// standard. Setting max_dest_chars to a large value has this effect.
if (!dst)
max_dest_chars = static_cast<size_t>(-1);
while ( source_remaining ) {
if ( dst && dest_converted >= max_dest_chars )
break;
// Converts one multi byte character.
// if result > 0, it's the size in bytes of that character.
// othewise if result is zero it indicates the null character has been found.
// otherwise it's an error and errno may be set.
size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
// Don't do anything to change errno from here on.
if ( char_size > 0 ) {
source_remaining -= char_size;
source_converted += char_size;
++dest_converted;
continue;
}
result = char_size;
have_result = true;
break;
}
if ( dst ) {
if ( have_result && result == terminated_sequence )
*src = NULL;
else
*src += source_converted;
}
if ( have_result && result != terminated_sequence && result != incomplete_sequence )
return static_cast<size_t>(-1);
return dest_converted;
}
// Converts max_source_chars from the wide character buffer pointer to by *src,
// into the multi byte character sequence buffer stored at dst which must be
// dst_size_bytes bytes in size.
// Returns >= 0: the number of bytes in the sequence
// converted from *src, excluding the null terminator.
// Returns size_t(-1) if an error occurs, also sets errno.
// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
// and no "out" parameters are updated.
size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
{
//const size_t invalid_sequence = static_cast<size_t>(-1);
size_t source_converted = 0;
size_t dest_converted = 0;
size_t dest_remaining = dst_size_bytes;
size_t char_size = 0;
const errno_t no_error = ( errno_t) 0;
errno_t result = ( errno_t ) 0;
bool have_result = false;
bool terminator_found = false;
// If dst is null then dst_size_bytes should be ignored according to the
// standard. Setting dest_remaining to a large value has this effect.
if (!dst)
dest_remaining = static_cast<size_t>(-1);
while ( source_converted != max_source_chars ) {
if ( ! dest_remaining )
break;
wchar_t c = (*src)[source_converted];
if ( dst )
result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
else
result = wcrtomb_s( &char_size, NULL, 0, c, ps);
// If result is zero there is no error and char_size contains the
// size of the multi-byte-sequence converted.
// Otherwise result indicates an errno type error.
if ( result == no_error ) {
if ( c == L'\0' ) {
terminator_found = true;
break;
}
++source_converted;
if ( dst )
dest_remaining -= char_size;
dest_converted += char_size;
continue;
}
have_result = true;
break;
}
if ( dst ) {
if ( terminator_found )
*src = NULL;
else
*src = *src + source_converted;
}
if ( have_result && result != no_error ) {
errno = result;
return static_cast<size_t>(-1);
}
return dest_converted;
}

View File

@ -0,0 +1,275 @@
// -*- C++ -*-
//===-------------------- support/win32/thread_win32.cpp ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__threading_support>
#include <windows.h>
#include <process.h>
#include <fibersapi.h>
_LIBCPP_BEGIN_NAMESPACE_STD
static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
"");
static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
"");
static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
// Mutex
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
{
InitializeCriticalSection((LPCRITICAL_SECTION)__m);
return 0;
}
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
{
EnterCriticalSection((LPCRITICAL_SECTION)__m);
return 0;
}
bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
{
return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
}
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
{
LeaveCriticalSection((LPCRITICAL_SECTION)__m);
return 0;
}
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
{
DeleteCriticalSection((LPCRITICAL_SECTION)__m);
return 0;
}
int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
{
AcquireSRWLockExclusive((PSRWLOCK)__m);
return 0;
}
bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
{
return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
}
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
{
ReleaseSRWLockExclusive((PSRWLOCK)__m);
return 0;
}
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
{
static_cast<void>(__m);
return 0;
}
// Condition Variable
int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
{
WakeConditionVariable((PCONDITION_VARIABLE)__cv);
return 0;
}
int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
{
WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
return 0;
}
int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
{
SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
return 0;
}
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
__libcpp_timespec_t *__ts)
{
using namespace _VSTD::chrono;
auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
auto abstime =
system_clock::time_point(duration_cast<system_clock::duration>(duration));
auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
timeout_ms.count() > 0 ? timeout_ms.count()
: 0,
0))
{
auto __ec = GetLastError();
return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
}
return 0;
}
int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
{
static_cast<void>(__cv);
return 0;
}
// Execute Once
static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
PVOID *__context)
{
static_cast<void>(__init_once);
static_cast<void>(__context);
void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
init_routine();
return TRUE;
}
int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
void (*__init_routine)(void))
{
if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
reinterpret_cast<void *>(__init_routine), NULL))
return GetLastError();
return 0;
}
// Thread ID
bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
__libcpp_thread_id __rhs)
{
return __lhs == __rhs;
}
bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
{
return __lhs < __rhs;
}
// Thread
struct __libcpp_beginthreadex_thunk_data
{
void *(*__func)(void *);
void *__arg;
};
static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
__libcpp_beginthreadex_thunk(void *__raw_data)
{
auto *__data =
static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
auto *__func = __data->__func;
void *__arg = __data->__arg;
delete __data;
return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
}
bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
return *__t == 0;
}
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
void *__arg)
{
auto *__data = new __libcpp_beginthreadex_thunk_data;
__data->__func = __func;
__data->__arg = __arg;
*__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
__libcpp_beginthreadex_thunk,
__data, 0, nullptr));
if (*__t)
return 0;
return GetLastError();
}
__libcpp_thread_id __libcpp_thread_get_current_id()
{
return GetCurrentThreadId();
}
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
{
return GetThreadId(*__t);
}
int __libcpp_thread_join(__libcpp_thread_t *__t)
{
if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
return GetLastError();
if (!CloseHandle(*__t))
return GetLastError();
return 0;
}
int __libcpp_thread_detach(__libcpp_thread_t *__t)
{
if (!CloseHandle(*__t))
return GetLastError();
return 0;
}
void __libcpp_thread_yield()
{
SwitchToThread();
}
void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
{
using namespace chrono;
// round-up to the nearest milisecond
milliseconds __ms =
duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999));
// FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
Sleep(__ms.count());
}
// Thread Local Storage
int __libcpp_tls_create(__libcpp_tls_key* __key,
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
{
DWORD index = FlsAlloc(__at_exit);
if (index == FLS_OUT_OF_INDEXES)
return GetLastError();
*__key = index;
return 0;
}
void *__libcpp_tls_get(__libcpp_tls_key __key)
{
return FlsGetValue(__key);
}
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
{
if (!FlsSetValue(__key, __p))
return GetLastError();
return 0;
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,295 @@
//===---------------------- system_error.cpp ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#include "system_error"
#include "include/config_elast.h"
#include "cerrno"
#include "cstring"
#include "cstdio"
#include "cstdlib"
#include "string"
#include "string.h"
#include "__debug"
#if defined(__ANDROID__)
#include <android/api-level.h>
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
// class error_category
#if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
error_category::error_category() _NOEXCEPT
{
}
#endif
error_category::~error_category() _NOEXCEPT
{
}
error_condition
error_category::default_error_condition(int ev) const _NOEXCEPT
{
return error_condition(ev, *this);
}
bool
error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT
{
return default_error_condition(code) == condition;
}
bool
error_category::equivalent(const error_code& code, int condition) const _NOEXCEPT
{
return *this == code.category() && code.value() == condition;
}
#if !defined(_LIBCPP_HAS_NO_THREADS)
namespace {
// GLIBC also uses 1024 as the maximum buffer size internally.
constexpr size_t strerror_buff_size = 1024;
string do_strerror_r(int ev);
#if defined(_LIBCPP_MSVCRT_LIKE)
string do_strerror_r(int ev) {
char buffer[strerror_buff_size];
if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
return string(buffer);
std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
return string(buffer);
}
#else
// Only one of the two following functions will be used, depending on
// the return type of strerror_r:
// For the GNU variant, a char* return value:
__attribute__((unused)) const char *
handle_strerror_r_return(char *strerror_return, char *buffer) {
// GNU always returns a string pointer in its return value. The
// string might point to either the input buffer, or a static
// buffer, but we don't care which.
return strerror_return;
}
// For the POSIX variant: an int return value.
__attribute__((unused)) const char *
handle_strerror_r_return(int strerror_return, char *buffer) {
// The POSIX variant either:
// - fills in the provided buffer and returns 0
// - returns a positive error value, or
// - returns -1 and fills in errno with an error value.
if (strerror_return == 0)
return buffer;
// Only handle EINVAL. Other errors abort.
int new_errno = strerror_return == -1 ? errno : strerror_return;
if (new_errno == EINVAL)
return "";
_LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r");
// FIXME maybe? 'strerror_buff_size' is likely to exceed the
// maximum error size so ERANGE shouldn't be returned.
std::abort();
}
// This function handles both GNU and POSIX variants, dispatching to
// one of the two above functions.
string do_strerror_r(int ev) {
char buffer[strerror_buff_size];
// Preserve errno around the call. (The C++ standard requires that
// system_error functions not modify errno).
const int old_errno = errno;
const char *error_message = handle_strerror_r_return(
::strerror_r(ev, buffer, strerror_buff_size), buffer);
// If we didn't get any message, print one now.
if (!error_message[0]) {
std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
error_message = buffer;
}
errno = old_errno;
return string(error_message);
}
#endif
} // end namespace
#endif
string
__do_message::message(int ev) const
{
#if defined(_LIBCPP_HAS_NO_THREADS)
return string(::strerror(ev));
#else
return do_strerror_r(ev);
#endif
}
class _LIBCPP_HIDDEN __generic_error_category
: public __do_message
{
public:
virtual const char* name() const _NOEXCEPT;
virtual string message(int ev) const;
};
const char*
__generic_error_category::name() const _NOEXCEPT
{
return "generic";
}
string
__generic_error_category::message(int ev) const
{
#ifdef _LIBCPP_ELAST
if (ev > _LIBCPP_ELAST)
return string("unspecified generic_category error");
#endif // _LIBCPP_ELAST
return __do_message::message(ev);
}
const error_category&
generic_category() _NOEXCEPT
{
static __generic_error_category s;
return s;
}
class _LIBCPP_HIDDEN __system_error_category
: public __do_message
{
public:
virtual const char* name() const _NOEXCEPT;
virtual string message(int ev) const;
virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
};
const char*
__system_error_category::name() const _NOEXCEPT
{
return "system";
}
string
__system_error_category::message(int ev) const
{
#ifdef _LIBCPP_ELAST
if (ev > _LIBCPP_ELAST)
return string("unspecified system_category error");
#endif // _LIBCPP_ELAST
return __do_message::message(ev);
}
error_condition
__system_error_category::default_error_condition(int ev) const _NOEXCEPT
{
#ifdef _LIBCPP_ELAST
if (ev > _LIBCPP_ELAST)
return error_condition(ev, system_category());
#endif // _LIBCPP_ELAST
return error_condition(ev, generic_category());
}
const error_category&
system_category() _NOEXCEPT
{
static __system_error_category s;
return s;
}
// error_condition
string
error_condition::message() const
{
return __cat_->message(__val_);
}
// error_code
string
error_code::message() const
{
return __cat_->message(__val_);
}
// system_error
string
system_error::__init(const error_code& ec, string what_arg)
{
if (ec)
{
if (!what_arg.empty())
what_arg += ": ";
what_arg += ec.message();
}
return what_arg;
}
system_error::system_error(error_code ec, const string& what_arg)
: runtime_error(__init(ec, what_arg)),
__ec_(ec)
{
}
system_error::system_error(error_code ec, const char* what_arg)
: runtime_error(__init(ec, what_arg)),
__ec_(ec)
{
}
system_error::system_error(error_code ec)
: runtime_error(__init(ec, "")),
__ec_(ec)
{
}
system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
: runtime_error(__init(error_code(ev, ecat), what_arg)),
__ec_(error_code(ev, ecat))
{
}
system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
: runtime_error(__init(error_code(ev, ecat), what_arg)),
__ec_(error_code(ev, ecat))
{
}
system_error::system_error(int ev, const error_category& ecat)
: runtime_error(__init(error_code(ev, ecat), "")),
__ec_(error_code(ev, ecat))
{
}
system_error::~system_error() _NOEXCEPT
{
}
void
__throw_system_error(int ev, const char* what_arg)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
throw system_error(error_code(ev, system_category()), what_arg);
#else
(void)ev;
(void)what_arg;
_VSTD::abort();
#endif
}
_LIBCPP_END_NAMESPACE_STD

225
lib/libcxx/src/thread.cpp Normal file
View File

@ -0,0 +1,225 @@
//===------------------------- thread.cpp----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS
#include "thread"
#include "exception"
#include "vector"
#include "future"
#include "limits"
#include <sys/types.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
# include <sys/sysctl.h>
# endif
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
# include <unistd.h>
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
#if defined(__NetBSD__)
#pragma weak pthread_create // Do not create libpthread dependency
#endif
#if defined(_LIBCPP_WIN32API)
#include <windows.h>
#endif
#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
thread::~thread()
{
if (!__libcpp_thread_isnull(&__t_))
terminate();
}
void
thread::join()
{
int ec = EINVAL;
if (!__libcpp_thread_isnull(&__t_))
{
ec = __libcpp_thread_join(&__t_);
if (ec == 0)
__t_ = _LIBCPP_NULL_THREAD;
}
if (ec)
__throw_system_error(ec, "thread::join failed");
}
void
thread::detach()
{
int ec = EINVAL;
if (!__libcpp_thread_isnull(&__t_))
{
ec = __libcpp_thread_detach(&__t_);
if (ec == 0)
__t_ = _LIBCPP_NULL_THREAD;
}
if (ec)
__throw_system_error(ec, "thread::detach failed");
}
unsigned
thread::hardware_concurrency() _NOEXCEPT
{
#if defined(CTL_HW) && defined(HW_NCPU)
unsigned n;
int mib[2] = {CTL_HW, HW_NCPU};
std::size_t s = sizeof(n);
sysctl(mib, 2, &n, &s, 0, 0);
return n;
#elif defined(_SC_NPROCESSORS_ONLN)
long result = sysconf(_SC_NPROCESSORS_ONLN);
// sysconf returns -1 if the name is invalid, the option does not exist or
// does not have a definite limit.
// if sysconf returns some other negative number, we have no idea
// what is going on. Default to something safe.
if (result < 0)
return 0;
return static_cast<unsigned>(result);
#elif defined(_LIBCPP_WIN32API)
SYSTEM_INFO info;
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
#else // defined(CTL_HW) && defined(HW_NCPU)
// TODO: grovel through /proc or check cpuid on x86 and similar
// instructions on other architectures.
# if defined(_LIBCPP_WARNING)
_LIBCPP_WARNING("hardware_concurrency not yet implemented")
# else
# warning hardware_concurrency not yet implemented
# endif
return 0; // Means not computable [thread.thread.static]
#endif // defined(CTL_HW) && defined(HW_NCPU)
}
namespace this_thread
{
void
sleep_for(const chrono::nanoseconds& ns)
{
if (ns > chrono::nanoseconds::zero())
{
__libcpp_thread_sleep_for(ns);
}
}
} // this_thread
__thread_specific_ptr<__thread_struct>&
__thread_local_data()
{
static __thread_specific_ptr<__thread_struct> __p;
return __p;
}
// __thread_struct_imp
template <class T>
class _LIBCPP_HIDDEN __hidden_allocator
{
public:
typedef T value_type;
T* allocate(size_t __n)
{return static_cast<T*>(::operator new(__n * sizeof(T)));}
void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
size_t max_size() const {return size_t(~0) / sizeof(T);}
};
class _LIBCPP_HIDDEN __thread_struct_imp
{
typedef vector<__assoc_sub_state*,
__hidden_allocator<__assoc_sub_state*> > _AsyncStates;
typedef vector<pair<condition_variable*, mutex*>,
__hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
_AsyncStates async_states_;
_Notify notify_;
__thread_struct_imp(const __thread_struct_imp&);
__thread_struct_imp& operator=(const __thread_struct_imp&);
public:
__thread_struct_imp() {}
~__thread_struct_imp();
void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
void __make_ready_at_thread_exit(__assoc_sub_state* __s);
};
__thread_struct_imp::~__thread_struct_imp()
{
for (_Notify::iterator i = notify_.begin(), e = notify_.end();
i != e; ++i)
{
i->second->unlock();
i->first->notify_all();
}
for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
i != e; ++i)
{
(*i)->__make_ready();
(*i)->__release_shared();
}
}
void
__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
}
void
__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
async_states_.push_back(__s);
__s->__add_shared();
}
// __thread_struct
__thread_struct::__thread_struct()
: __p_(new __thread_struct_imp)
{
}
__thread_struct::~__thread_struct()
{
delete __p_;
}
void
__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
__p_->notify_all_at_thread_exit(cv, m);
}
void
__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
__p_->__make_ready_at_thread_exit(__s);
}
_LIBCPP_END_NAMESPACE_STD
#endif // !_LIBCPP_HAS_NO_THREADS

View File

@ -0,0 +1,57 @@
//===------------------------- typeinfo.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "typeinfo"
#if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_ABI_VCRUNTIME)
#include <string.h>
int std::type_info::__compare(const type_info &__rhs) const _NOEXCEPT {
if (&__data == &__rhs.__data)
return 0;
return strcmp(&__data.__decorated_name[1], &__rhs.__data.__decorated_name[1]);
}
const char *std::type_info::name() const _NOEXCEPT {
// TODO(compnerd) cache demangled &__data.__decorated_name[1]
return &__data.__decorated_name[1];
}
size_t std::type_info::hash_code() const _NOEXCEPT {
#if defined(_WIN64)
constexpr size_t fnv_offset_basis = 14695981039346656037ull;
constexpr size_t fnv_prime = 10995116282110ull;
#else
constexpr size_t fnv_offset_basis = 2166136261ull;
constexpr size_t fnv_prime = 16777619ull;
#endif
size_t value = fnv_offset_basis;
for (const char* c = &__data.__decorated_name[1]; *c; ++c) {
value ^= static_cast<size_t>(static_cast<unsigned char>(*c));
value *= fnv_prime;
}
#if defined(_WIN64)
value ^= value >> 32;
#endif
return value;
}
#endif // _LIBCPP_ABI_MICROSOFT
// FIXME: Remove the _LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY configuration.
#if (!defined(LIBCXX_BUILDING_LIBCXXABI) && \
!defined(LIBCXXRT) && \
!defined(__GLIBCXX__) && \
!defined(_LIBCPP_ABI_VCRUNTIME)) || \
defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY)
std::type_info::~type_info()
{
}
#endif

View File

@ -0,0 +1,15 @@
//===------------------------ utility.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "utility"
_LIBCPP_BEGIN_NAMESPACE_STD
const piecewise_construct_t piecewise_construct{};
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,57 @@
//===------------------------ valarray.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "valarray"
_LIBCPP_BEGIN_NAMESPACE_STD
// These two symbols are part of the v1 ABI but not part of the >=v2 ABI.
#if _LIBCPP_ABI_VERSION == 1
template _LIBCPP_FUNC_VIS valarray<size_t>::valarray(size_t);
template _LIBCPP_FUNC_VIS valarray<size_t>::~valarray();
#endif
template void valarray<size_t>::resize(size_t, size_t);
void
gslice::__init(size_t __start)
{
valarray<size_t> __indices(__size_.size());
size_t __k = __size_.size() != 0;
for (size_t __i = 0; __i < __size_.size(); ++__i)
__k *= __size_[__i];
__1d_.resize(__k);
if (__1d_.size())
{
__k = 0;
__1d_[__k] = __start;
while (true)
{
size_t __i = __indices.size() - 1;
while (true)
{
if (++__indices[__i] < __size_[__i])
{
++__k;
__1d_[__k] = __1d_[__k-1] + __stride_[__i];
for (size_t __j = __i + 1; __j != __indices.size(); ++__j)
__1d_[__k] -= __stride_[__j] * (__size_[__j] - 1);
break;
}
else
{
if (__i == 0)
return;
__indices[__i--] = 0;
}
}
}
}
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,17 @@
//===------------------------ variant.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "variant"
namespace std {
const char* bad_variant_access::what() const noexcept {
return "bad_variant_access";
}
} // namespace std

15
lib/libcxx/src/vector.cpp Normal file
View File

@ -0,0 +1,15 @@
//===------------------------- vector.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "vector"
_LIBCPP_BEGIN_NAMESPACE_STD
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD

311
lib/libcxxabi/LICENSE.TXT Normal file
View File

@ -0,0 +1,311 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
The libc++abi library is dual licensed under both the University of Illinois
"BSD-Like" license and the MIT license. As a user of this code you may choose
to use it under either license. As a contributor, you agree to allow your code
to be used under both.
Full text of the relevant licenses is included below.
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,79 @@
//===-------------------------- __cxxabi_config.h -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef ____CXXABI_CONFIG_H
#define ____CXXABI_CONFIG_H
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
!defined(__ARM_DWARF_EH__)
#define _LIBCXXABI_ARM_EHABI
#endif
#if !defined(__has_attribute)
#define __has_attribute(_attribute_) 0
#endif
#if defined(_WIN32)
#if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS
#define _LIBCXXABI_FUNC_VIS
#define _LIBCXXABI_TYPE_VIS
#elif defined(_LIBCXXABI_BUILDING_LIBRARY)
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS __declspec(dllexport)
#define _LIBCXXABI_FUNC_VIS __declspec(dllexport)
#define _LIBCXXABI_TYPE_VIS __declspec(dllexport)
#else
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS __declspec(dllimport)
#define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
#define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
#endif
#else
#if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
#define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
#define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default")))
#define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default")))
#if __has_attribute(__type_visibility__)
#define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default")))
#else
#define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default")))
#endif
#else
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS
#define _LIBCXXABI_FUNC_VIS
#define _LIBCXXABI_TYPE_VIS
#endif
#endif
#if defined(_WIN32)
#define _LIBCXXABI_WEAK
#else
#define _LIBCXXABI_WEAK __attribute__((__weak__))
#endif
#if defined(__clang__)
#define _LIBCXXABI_COMPILER_CLANG
#elif defined(__GNUC__)
#define _LIBCXXABI_COMPILER_GCC
#endif
#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG)
#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi")))
#else
#define _LIBCXXABI_NO_CFI
#endif
// wasm32 follows the arm32 ABI convention of using 32-bit guard.
#if defined(__arm__) || defined(__wasm32__)
# define _LIBCXXABI_GUARD_ABI_ARM
#endif
#endif // ____CXXABI_CONFIG_H

View File

@ -0,0 +1,176 @@
//===--------------------------- cxxabi.h ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef __CXXABI_H
#define __CXXABI_H
/*
* This header provides the interface to the C++ ABI as defined at:
* https://itanium-cxx-abi.github.io/cxx-abi/
*/
#include <stddef.h>
#include <stdint.h>
#include <__cxxabi_config.h>
#define _LIBCPPABI_VERSION 1002
#define _LIBCXXABI_NORETURN __attribute__((noreturn))
#ifdef __cplusplus
namespace std {
#if defined(_WIN32)
class _LIBCXXABI_TYPE_VIS type_info; // forward declaration
#else
class type_info; // forward declaration
#endif
}
// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
namespace __cxxabiv1 {
extern "C" {
// 2.4.2 Allocating the Exception Object
extern _LIBCXXABI_FUNC_VIS void *
__cxa_allocate_exception(size_t thrown_size) throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_free_exception(void *thrown_exception) throw();
// 2.4.3 Throwing the Exception Object
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
void (*dest)(void *));
// 2.5.3 Exception Handlers
extern _LIBCXXABI_FUNC_VIS void *
__cxa_get_exception_ptr(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void *
__cxa_begin_catch(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
#if defined(_LIBCXXABI_ARM_EHABI)
extern _LIBCXXABI_FUNC_VIS bool
__cxa_begin_cleanup(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup();
#endif
extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type();
// 2.5.4 Rethrowing Exceptions
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow();
// 2.6 Auxiliary Runtime APIs
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw_bad_array_new_length(void);
// 3.2.6 Pure Virtual Function API
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
// 3.2.7 Deleted Virtual Function API
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
// 3.3.2 One-time Construction API
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint32_t *);
extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint32_t *);
extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint32_t *);
#else
extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint64_t *);
extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint64_t *);
extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint64_t *);
#endif
// 3.3.3 Array Construction and Destruction API
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *));
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *, size_t));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
void (*constructor)(void *), void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
size_t element_size,
size_t padding_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete3(void *__array_address, size_t element_size,
size_t padding_size, void (*destructor)(void *),
void (*dealloc)(void *, size_t));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count,
size_t element_size, void (*constructor)(void *, void *),
void (*destructor)(void *));
// 3.3.5.3 Runtime API
extern _LIBCXXABI_FUNC_VIS int __cxa_atexit(void (*f)(void *), void *p,
void *d);
extern _LIBCXXABI_FUNC_VIS int __cxa_finalize(void *);
// 3.4 Demangler API
extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
char *output_buffer,
size_t *length, int *status);
// Apple additions to support C++ 0x exception_ptr class
// These are primitives to wrap a smart pointer around an exception object
extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_rethrow_primary_exception(void *primary_exception);
extern _LIBCXXABI_FUNC_VIS void
__cxa_increment_exception_refcount(void *primary_exception) throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_decrement_exception_refcount(void *primary_exception) throw();
// Apple extension to support std::uncaught_exception()
extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
#if defined(__linux__) || defined(__Fuchsia__)
// Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
void *) throw();
#endif
} // extern "C"
} // namespace __cxxabiv1
namespace abi = __cxxabiv1;
#endif // __cplusplus
#endif // __CXXABI_H

View File

@ -0,0 +1,77 @@
//===------------------------- abort_message.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "abort_message.h"
#ifdef __BIONIC__
#include <android/api-level.h>
#if __ANDROID_API__ >= 21
#include <syslog.h>
extern "C" void android_set_abort_message(const char* msg);
#else
#include <assert.h>
#endif // __ANDROID_API__ >= 21
#endif // __BIONIC__
#ifdef __APPLE__
# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
# define HAVE_CRASHREPORTERCLIENT_H
# include <CrashReporterClient.h>
# endif
#endif
void abort_message(const char* format, ...)
{
// write message to stderr
#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL)
#ifdef __APPLE__
fprintf(stderr, "libc++abi.dylib: ");
#endif
va_list list;
va_start(list, format);
vfprintf(stderr, format, list);
va_end(list);
fprintf(stderr, "\n");
#endif
#if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H)
// record message in crash report
char* buffer;
va_list list2;
va_start(list2, format);
vasprintf(&buffer, format, list2);
va_end(list2);
CRSetCrashLogMessage(buffer);
#elif defined(__BIONIC__)
char* buffer;
va_list list2;
va_start(list2, format);
vasprintf(&buffer, format, list2);
va_end(list2);
#if __ANDROID_API__ >= 21
// Show error in tombstone.
android_set_abort_message(buffer);
// Show error in logcat.
openlog("libc++abi", 0, 0);
syslog(LOG_CRIT, "%s", buffer);
closelog();
#else
// The good error reporting wasn't available in Android until L. Since we're
// about to abort anyway, just call __assert2, which will log _somewhere_
// (tombstone and/or logcat) in older releases.
__assert2(__FILE__, __LINE__, __func__, buffer);
#endif // __ANDROID_API__ >= 21
#endif // __BIONIC__
abort();
}

View File

@ -0,0 +1,26 @@
//===-------------------------- abort_message.h-----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef __ABORT_MESSAGE_H_
#define __ABORT_MESSAGE_H_
#include "cxxabi.h"
#ifdef __cplusplus
extern "C" {
#endif
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,43 @@
//===------------------------ cxa_aux_runtime.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the "Auxiliary Runtime APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-aux
//===----------------------------------------------------------------------===//
#include "cxxabi.h"
#include <new>
#include <typeinfo>
namespace __cxxabiv1 {
extern "C" {
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_cast();
#else
std::terminate();
#endif
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_typeid();
#else
std::terminate();
#endif
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw_bad_array_new_length(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_array_new_length();
#else
std::terminate();
#endif
}
} // extern "C"
} // abi

View File

@ -0,0 +1,124 @@
//===------------------------- cxa_default_handlers.cpp -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the default terminate_handler and unexpected_handler.
//===----------------------------------------------------------------------===//
#include <exception>
#include <stdlib.h>
#include "abort_message.h"
#include "cxxabi.h"
#include "cxa_handlers.h"
#include "cxa_exception.h"
#include "private_typeinfo.h"
#include "include/atomic_support.h"
#if !defined(LIBCXXABI_SILENT_TERMINATE)
_LIBCPP_SAFE_STATIC
static const char* cause = "uncaught";
__attribute__((noreturn))
static void demangling_terminate_handler()
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
// If there might be an uncaught exception
using namespace __cxxabiv1;
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (globals)
{
__cxa_exception* exception_header = globals->caughtExceptions;
// If there is an uncaught exception
if (exception_header)
{
_Unwind_Exception* unwind_exception =
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
if (__isOurExceptionClass(unwind_exception))
{
void* thrown_object =
__getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
((__cxa_dependent_exception*)exception_header)->primaryException :
exception_header + 1;
const __shim_type_info* thrown_type =
static_cast<const __shim_type_info*>(exception_header->exceptionType);
// Try to get demangled name of thrown_type
int status;
char buf[1024];
size_t len = sizeof(buf);
const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
if (status != 0)
name = thrown_type->name();
// If the uncaught exception can be caught with std::exception&
const __shim_type_info* catch_type =
static_cast<const __shim_type_info*>(&typeid(std::exception));
if (catch_type->can_catch(thrown_type, thrown_object))
{
// Include the what() message from the exception
const std::exception* e = static_cast<const std::exception*>(thrown_object);
abort_message("terminating with %s exception of type %s: %s",
cause, name, e->what());
}
else
// Else just note that we're terminating with an exception
abort_message("terminating with %s exception of type %s",
cause, name);
}
else
// Else we're terminating with a foreign exception
abort_message("terminating with %s foreign exception", cause);
}
}
#endif
// Else just note that we're terminating
abort_message("terminating");
}
__attribute__((noreturn))
static void demangling_unexpected_handler()
{
cause = "unexpected";
std::terminate();
}
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
#else
static constexpr std::terminate_handler default_terminate_handler = ::abort;
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
#endif
//
// Global variables that hold the pointers to the current handler
//
_LIBCXXABI_DATA_VIS
_LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
_LIBCXXABI_DATA_VIS
_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
namespace std
{
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
if (func == 0)
func = default_unexpected_handler;
return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
_AO_Acq_Rel);
}
terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
if (func == 0)
func = default_terminate_handler;
return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
_AO_Acq_Rel);
}
}

View File

@ -0,0 +1,366 @@
//===-------------------------- cxa_demangle.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// FIXME: (possibly) incomplete list of features that clang mangles that this
// file does not yet support:
// - C++ modules TS
#include "demangle/ItaniumDemangle.h"
#include "__cxxabi_config.h"
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <utility>
using namespace itanium_demangle;
constexpr const char *itanium_demangle::FloatData<float>::spec;
constexpr const char *itanium_demangle::FloatData<double>::spec;
constexpr const char *itanium_demangle::FloatData<long double>::spec;
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+ # at the end of string
const char *itanium_demangle::parse_discriminator(const char *first,
const char *last) {
// parse but ignore discriminator
if (first != last) {
if (*first == '_') {
const char *t1 = first + 1;
if (t1 != last) {
if (std::isdigit(*t1))
first = t1 + 1;
else if (*t1 == '_') {
for (++t1; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 != last && *t1 == '_')
first = t1 + 1;
}
}
} else if (std::isdigit(*first)) {
const char *t1 = first + 1;
for (; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 == last)
first = last;
}
}
return first;
}
#ifndef NDEBUG
namespace {
struct DumpVisitor {
unsigned Depth = 0;
bool PendingNewline = false;
template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
return true;
}
static bool wantsNewline(NodeArray A) { return !A.empty(); }
static constexpr bool wantsNewline(...) { return false; }
template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
for (bool B : {wantsNewline(Vs)...})
if (B)
return true;
return false;
}
void printStr(const char *S) { fprintf(stderr, "%s", S); }
void print(StringView SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
}
void print(const Node *N) {
if (N)
N->visit(std::ref(*this));
else
printStr("<null>");
}
void print(NodeArray A) {
++Depth;
printStr("{");
bool First = true;
for (const Node *N : A) {
if (First)
print(N);
else
printWithComma(N);
First = false;
}
printStr("}");
--Depth;
}
// Overload used when T is exactly 'bool', not merely convertible to 'bool'.
void print(bool B) { printStr(B ? "true" : "false"); }
template <class T>
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
fprintf(stderr, "%llu", (unsigned long long)N);
}
template <class T>
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
fprintf(stderr, "%lld", (long long)N);
}
void print(ReferenceKind RK) {
switch (RK) {
case ReferenceKind::LValue:
return printStr("ReferenceKind::LValue");
case ReferenceKind::RValue:
return printStr("ReferenceKind::RValue");
}
}
void print(FunctionRefQual RQ) {
switch (RQ) {
case FunctionRefQual::FrefQualNone:
return printStr("FunctionRefQual::FrefQualNone");
case FunctionRefQual::FrefQualLValue:
return printStr("FunctionRefQual::FrefQualLValue");
case FunctionRefQual::FrefQualRValue:
return printStr("FunctionRefQual::FrefQualRValue");
}
}
void print(Qualifiers Qs) {
if (!Qs) return printStr("QualNone");
struct QualName { Qualifiers Q; const char *Name; } Names[] = {
{QualConst, "QualConst"},
{QualVolatile, "QualVolatile"},
{QualRestrict, "QualRestrict"},
};
for (QualName Name : Names) {
if (Qs & Name.Q) {
printStr(Name.Name);
Qs = Qualifiers(Qs & ~Name.Q);
if (Qs) printStr(" | ");
}
}
}
void print(SpecialSubKind SSK) {
switch (SSK) {
case SpecialSubKind::allocator:
return printStr("SpecialSubKind::allocator");
case SpecialSubKind::basic_string:
return printStr("SpecialSubKind::basic_string");
case SpecialSubKind::string:
return printStr("SpecialSubKind::string");
case SpecialSubKind::istream:
return printStr("SpecialSubKind::istream");
case SpecialSubKind::ostream:
return printStr("SpecialSubKind::ostream");
case SpecialSubKind::iostream:
return printStr("SpecialSubKind::iostream");
}
}
void print(TemplateParamKind TPK) {
switch (TPK) {
case TemplateParamKind::Type:
return printStr("TemplateParamKind::Type");
case TemplateParamKind::NonType:
return printStr("TemplateParamKind::NonType");
case TemplateParamKind::Template:
return printStr("TemplateParamKind::Template");
}
}
void newLine() {
printStr("\n");
for (unsigned I = 0; I != Depth; ++I)
printStr(" ");
PendingNewline = false;
}
template<typename T> void printWithPendingNewline(T V) {
print(V);
if (wantsNewline(V))
PendingNewline = true;
}
template<typename T> void printWithComma(T V) {
if (PendingNewline || wantsNewline(V)) {
printStr(",");
newLine();
} else {
printStr(", ");
}
printWithPendingNewline(V);
}
struct CtorArgPrinter {
DumpVisitor &Visitor;
template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
if (Visitor.anyWantNewline(V, Vs...))
Visitor.newLine();
Visitor.printWithPendingNewline(V);
int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
(void)PrintInOrder;
}
};
template<typename NodeT> void operator()(const NodeT *Node) {
Depth += 2;
fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
Node->match(CtorArgPrinter{*this});
fprintf(stderr, ")");
Depth -= 2;
}
void operator()(const ForwardTemplateReference *Node) {
Depth += 2;
fprintf(stderr, "ForwardTemplateReference(");
if (Node->Ref && !Node->Printing) {
Node->Printing = true;
CtorArgPrinter{*this}(Node->Ref);
Node->Printing = false;
} else {
CtorArgPrinter{*this}(Node->Index);
}
fprintf(stderr, ")");
Depth -= 2;
}
};
}
void itanium_demangle::Node::dump() const {
DumpVisitor V;
visit(std::ref(V));
V.newLine();
}
#endif
namespace {
class BumpPointerAllocator {
struct BlockMeta {
BlockMeta* Next;
size_t Current;
};
static constexpr size_t AllocSize = 4096;
static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
alignas(long double) char InitialBuffer[AllocSize];
BlockMeta* BlockList = nullptr;
void grow() {
char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
if (NewMeta == nullptr)
std::terminate();
BlockList = new (NewMeta) BlockMeta{BlockList, 0};
}
void* allocateMassive(size_t NBytes) {
NBytes += sizeof(BlockMeta);
BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
if (NewMeta == nullptr)
std::terminate();
BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
return static_cast<void*>(NewMeta + 1);
}
public:
BumpPointerAllocator()
: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
void* allocate(size_t N) {
N = (N + 15u) & ~15u;
if (N + BlockList->Current >= UsableAllocSize) {
if (N > UsableAllocSize)
return allocateMassive(N);
grow();
}
BlockList->Current += N;
return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
BlockList->Current - N);
}
void reset() {
while (BlockList) {
BlockMeta* Tmp = BlockList;
BlockList = BlockList->Next;
if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
std::free(Tmp);
}
BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
}
~BumpPointerAllocator() { reset(); }
};
class DefaultAllocator {
BumpPointerAllocator Alloc;
public:
void reset() { Alloc.reset(); }
template<typename T, typename ...Args> T *makeNode(Args &&...args) {
return new (Alloc.allocate(sizeof(T)))
T(std::forward<Args>(args)...);
}
void *allocateNodeArray(size_t sz) {
return Alloc.allocate(sizeof(Node *) * sz);
}
};
} // unnamed namespace
//===----------------------------------------------------------------------===//
// Code beyond this point should not be synchronized with LLVM.
//===----------------------------------------------------------------------===//
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
namespace {
enum : int {
demangle_invalid_args = -3,
demangle_invalid_mangled_name = -2,
demangle_memory_alloc_failure = -1,
demangle_success = 0,
};
}
namespace __cxxabiv1 {
extern "C" _LIBCXXABI_FUNC_VIS char *
__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
if (Status)
*Status = demangle_invalid_args;
return nullptr;
}
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
OutputStream S;
Node *AST = Parser.parse();
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))
InternalStatus = demangle_memory_alloc_failure;
else {
assert(Parser.ForwardTemplateRefs.empty());
AST->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
}
if (Status)
*Status = InternalStatus;
return InternalStatus == demangle_success ? Buf : nullptr;
}
} // __cxxabiv1

View File

@ -0,0 +1,755 @@
//===------------------------- cxa_exception.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the "Exception Handling APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
//===----------------------------------------------------------------------===//
#include "cxxabi.h"
#include <exception> // for std::terminate
#include <string.h> // for memset
#include "cxa_exception.h"
#include "cxa_handlers.h"
#include "fallback_malloc.h"
#include "include/atomic_support.h"
#if __has_feature(address_sanitizer)
extern "C" void __asan_handle_no_return(void);
#endif
// +---------------------------+-----------------------------+---------------+
// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
// +---------------------------+-----------------------------+---------------+
// ^
// |
// +-------------------------------------------------------+
// |
// +---------------------------+-----------------------------+
// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
// +---------------------------+-----------------------------+
namespace __cxxabiv1 {
// Utility routines
static
inline
__cxa_exception*
cxa_exception_from_thrown_object(void* thrown_object)
{
return static_cast<__cxa_exception*>(thrown_object) - 1;
}
// Note: This is never called when exception_header is masquerading as a
// __cxa_dependent_exception.
static
inline
void*
thrown_object_from_cxa_exception(__cxa_exception* exception_header)
{
return static_cast<void*>(exception_header + 1);
}
// Get the exception object from the unwind pointer.
// Relies on the structure layout, where the unwind pointer is right in
// front of the user's exception object
static
inline
__cxa_exception*
cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
{
return cxa_exception_from_thrown_object(unwind_exception + 1 );
}
// Round s up to next multiple of a.
static inline
size_t aligned_allocation_size(size_t s, size_t a) {
return (s + a - 1) & ~(a - 1);
}
static inline
size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
return aligned_allocation_size(size + sizeof (__cxa_exception),
alignof(__cxa_exception));
}
void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) {
::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue));
}
static void setOurExceptionClass(_Unwind_Exception* unwind_exception) {
__setExceptionClass(unwind_exception, kOurExceptionClass);
}
static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
__setExceptionClass(unwind_exception, kOurDependentExceptionClass);
}
// Is it one of ours?
uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
// On x86 and some ARM unwinders, unwind_exception->exception_class is
// a uint64_t. On other ARM unwinders, it is a char[8].
// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
// So we just copy it into a uint64_t to be sure.
uint64_t exClass;
::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
return exClass;
}
bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
(kOurExceptionClass & get_vendor_and_language);
}
static bool isDependentException(_Unwind_Exception* unwind_exception) {
return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01;
}
// This does not need to be atomic
static inline int incrementHandlerCount(__cxa_exception *exception) {
return ++exception->handlerCount;
}
// This does not need to be atomic
static inline int decrementHandlerCount(__cxa_exception *exception) {
return --exception->handlerCount;
}
/*
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
stored in exc is called. Otherwise the exceptionDestructor stored in
exc is called, and then the memory for the exception is deallocated.
This is never called for a __cxa_dependent_exception.
*/
static
void
exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
{
__cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
std::__terminate(exception_header->terminateHandler);
// Just in case there exists a dependent exception that is pointing to this,
// check the reference count and only destroy this if that count goes to zero.
__cxa_decrement_exception_refcount(unwind_exception + 1);
}
static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
// Section 2.5.3 says:
// * For purposes of this ABI, several things are considered exception handlers:
// ** A terminate() call due to a throw.
// and
// * Upon entry, Following initialization of the catch parameter,
// a handler must call:
// * void *__cxa_begin_catch(void *exceptionObject );
(void) __cxa_begin_catch(&exception_header->unwindHeader);
std::__terminate(exception_header->terminateHandler);
}
// Return the offset of the __cxa_exception header from the start of the
// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
// useful alignment for the target machine, padding has to be inserted before
// the header to ensure the thrown object that follows the header is
// sufficiently aligned. This happens if _Unwind_exception isn't double-word
// aligned (on Darwin, for example).
static size_t get_cxa_exception_offset() {
struct S {
} __attribute__((aligned));
// Compute the maximum alignment for the target machine.
constexpr size_t alignment = alignof(S);
constexpr size_t excp_size = sizeof(__cxa_exception);
constexpr size_t aligned_size =
(excp_size + alignment - 1) / alignment * alignment;
constexpr size_t offset = aligned_size - excp_size;
static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment),
"offset is non-zero only if _Unwind_Exception isn't aligned");
return offset;
}
extern "C" {
// Allocate a __cxa_exception object, and zero-fill it.
// Reserve "thrown_size" bytes on the end for the user's exception
// object. Zero-fill the object. If memory can't be allocated, call
// std::terminate. Return a pointer to the memory to be used for the
// user's exception object.
void *__cxa_allocate_exception(size_t thrown_size) throw() {
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
// Allocate extra space before the __cxa_exception header to ensure the
// start of the thrown object is sufficiently aligned.
size_t header_offset = get_cxa_exception_offset();
char *raw_buffer =
(char *)__aligned_malloc_with_fallback(header_offset + actual_size);
if (NULL == raw_buffer)
std::terminate();
__cxa_exception *exception_header =
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
::memset(exception_header, 0, actual_size);
return thrown_object_from_cxa_exception(exception_header);
}
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
void __cxa_free_exception(void *thrown_object) throw() {
// Compute the size of the padding before the header.
size_t header_offset = get_cxa_exception_offset();
char *raw_buffer =
((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
__aligned_free_with_fallback((void *)raw_buffer);
}
// This function shall allocate a __cxa_dependent_exception and
// return a pointer to it. (Really to the object, not past its' end).
// Otherwise, it will work like __cxa_allocate_exception.
void * __cxa_allocate_dependent_exception () {
size_t actual_size = sizeof(__cxa_dependent_exception);
void *ptr = __aligned_malloc_with_fallback(actual_size);
if (NULL == ptr)
std::terminate();
::memset(ptr, 0, actual_size);
return ptr;
}
// This function shall free a dependent_exception.
// It does not affect the reference count of the primary exception.
void __cxa_free_dependent_exception (void * dependent_exception) {
__aligned_free_with_fallback(dependent_exception);
}
// 2.4.3 Throwing the Exception Object
/*
After constructing the exception object with the throw argument value,
the generated code calls the __cxa_throw runtime library routine. This
routine never returns.
The __cxa_throw routine will do the following:
* Obtain the __cxa_exception header from the thrown exception object address,
which can be computed as follows:
__cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
* Save the tinfo and dest arguments in the __cxa_exception header.
* Set the exception_class field in the unwind header. This is a 64-bit value
representing the ASCII string "XXXXC++\0", where "XXXX" is a
vendor-dependent string. That is, for implementations conforming to this
ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
* Increment the uncaught_exception flag.
* Call _Unwind_RaiseException in the system unwind library, Its argument is the
pointer to the thrown exception, which __cxa_throw itself received as an argument.
__Unwind_RaiseException begins the process of stack unwinding, described
in Section 2.5. In special cases, such as an inability to find a
handler, _Unwind_RaiseException may return. In that case, __cxa_throw
will call terminate, assuming that there was no handler for the
exception.
*/
void
__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) {
__cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
exception_header->unexpectedHandler = std::get_unexpected();
exception_header->terminateHandler = std::get_terminate();
exception_header->exceptionType = tinfo;
exception_header->exceptionDestructor = dest;
setOurExceptionClass(&exception_header->unwindHeader);
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
#if __has_feature(address_sanitizer)
// Inform the ASan runtime that now might be a good time to clean stuff up.
__asan_handle_no_return();
#endif
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
_Unwind_RaiseException(&exception_header->unwindHeader);
#endif
// This only happens when there is no handler, or some unexpected unwinding
// error happens.
failed_throw(exception_header);
}
// 2.5.3 Exception Handlers
/*
The adjusted pointer is computed by the personality routine during phase 1
and saved in the exception header (either __cxa_exception or
__cxa_dependent_exception).
Requires: exception is native
*/
void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
#if defined(_LIBCXXABI_ARM_EHABI)
return reinterpret_cast<void*>(
static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
#else
return cxa_exception_from_exception_unwind_exception(
static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
#endif
}
#if defined(_LIBCXXABI_ARM_EHABI)
/*
The routine to be called before the cleanup. This will save __cxa_exception in
__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
*/
bool __cxa_begin_cleanup(void *unwind_arg) throw() {
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header =
cxa_exception_from_exception_unwind_exception(unwind_exception);
if (__isOurExceptionClass(unwind_exception))
{
if (0 == exception_header->propagationCount)
{
exception_header->nextPropagatingException = globals->propagatingExceptions;
globals->propagatingExceptions = exception_header;
}
++exception_header->propagationCount;
}
else
{
// If the propagatingExceptions stack is not empty, since we can't
// chain the foreign exception, terminate it.
if (NULL != globals->propagatingExceptions)
std::terminate();
globals->propagatingExceptions = exception_header;
}
return true;
}
/*
The routine to be called after the cleanup has been performed. It will get the
propagating __cxa_exception from __cxa_eh_globals, and continue the stack
unwinding with _Unwind_Resume.
According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
register, thus we have to write this function in assembly so that we can save
{r1, r2, r3}. We don't have to save r0 because it is the return value and the
first argument to _Unwind_Resume(). In addition, we are saving r4 in order to
align the stack to 16 bytes, even though it is a callee-save register.
*/
__attribute__((used)) static _Unwind_Exception *
__cxa_end_cleanup_impl()
{
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header = globals->propagatingExceptions;
if (NULL == exception_header)
{
// It seems that __cxa_begin_cleanup() is not called properly.
// We have no choice but terminate the program now.
std::terminate();
}
if (__isOurExceptionClass(&exception_header->unwindHeader))
{
--exception_header->propagationCount;
if (0 == exception_header->propagationCount)
{
globals->propagatingExceptions = exception_header->nextPropagatingException;
exception_header->nextPropagatingException = NULL;
}
}
else
{
globals->propagatingExceptions = NULL;
}
return &exception_header->unwindHeader;
}
asm (
" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
" .globl __cxa_end_cleanup\n"
" .type __cxa_end_cleanup,%function\n"
"__cxa_end_cleanup:\n"
" push {r1, r2, r3, r4}\n"
" bl __cxa_end_cleanup_impl\n"
" pop {r1, r2, r3, r4}\n"
" bl _Unwind_Resume\n"
" bl abort\n"
" .popsection"
);
#endif // defined(_LIBCXXABI_ARM_EHABI)
/*
This routine can catch foreign or native exceptions. If native, the exception
can be a primary or dependent variety. This routine may remain blissfully
ignorant of whether the native exception is primary or dependent.
If the exception is native:
* Increment's the exception's handler count.
* Push the exception on the stack of currently-caught exceptions if it is not
already there (from a rethrow).
* Decrements the uncaught_exception count.
* Returns the adjusted pointer to the exception object, which is stored in
the __cxa_exception by the personality routine.
If the exception is foreign, this means it did not originate from one of throw
routines. The foreign exception does not necessarily have a __cxa_exception
header. However we can catch it here with a catch (...), or with a call
to terminate or unexpected during unwinding.
* Do not try to increment the exception's handler count, we don't know where
it is.
* Push the exception on the stack of currently-caught exceptions only if the
stack is empty. The foreign exception has no way to link to the current
top of stack. If the stack is not empty, call terminate. Even with an
empty stack, this is hacked in by pushing a pointer to an imaginary
__cxa_exception block in front of the foreign exception. It would be better
if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
doesn't. It has a stack of __cxa_exception (which has a next* in it).
* Do not decrement the uncaught_exception count because we didn't increment it
in __cxa_throw (or one of our rethrow functions).
* If we haven't terminated, assume the exception object is just past the
_Unwind_Exception and return a pointer to that.
*/
void*
__cxa_begin_catch(void* unwind_arg) throw()
{
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
bool native_exception = __isOurExceptionClass(unwind_exception);
__cxa_eh_globals* globals = __cxa_get_globals();
// exception_header is a hackish offset from a foreign exception, but it
// works as long as we're careful not to try to access any __cxa_exception
// parts.
__cxa_exception* exception_header =
cxa_exception_from_exception_unwind_exception
(
static_cast<_Unwind_Exception*>(unwind_exception)
);
if (native_exception)
{
// Increment the handler count, removing the flag about being rethrown
exception_header->handlerCount = exception_header->handlerCount < 0 ?
-exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
// place the exception on the top of the stack if it's not already
// there by a previous rethrow
if (exception_header != globals->caughtExceptions)
{
exception_header->nextException = globals->caughtExceptions;
globals->caughtExceptions = exception_header;
}
globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
#if defined(_LIBCXXABI_ARM_EHABI)
return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
#else
return exception_header->adjustedPtr;
#endif
}
// Else this is a foreign exception
// If the caughtExceptions stack is not empty, terminate
if (globals->caughtExceptions != 0)
std::terminate();
// Push the foreign exception on to the stack
globals->caughtExceptions = exception_header;
return unwind_exception + 1;
}
/*
Upon exit for any reason, a handler must call:
void __cxa_end_catch ();
This routine can be called for either a native or foreign exception.
For a native exception:
* Locates the most recently caught exception and decrements its handler count.
* Removes the exception from the caught exception stack, if the handler count goes to zero.
* If the handler count goes down to zero, and the exception was not re-thrown
by throw, it locates the primary exception (which may be the same as the one
it's handling) and decrements its reference count. If that reference count
goes to zero, the function destroys the exception. In any case, if the current
exception is a dependent exception, it destroys that.
For a foreign exception:
* If it has been rethrown, there is nothing to do.
* Otherwise delete the exception and pop the catch stack to empty.
*/
void __cxa_end_catch() {
static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
"sizeof(__cxa_exception) must be equal to "
"sizeof(__cxa_dependent_exception)");
static_assert(__builtin_offsetof(__cxa_exception, referenceCount) ==
__builtin_offsetof(__cxa_dependent_exception,
primaryException),
"the layout of __cxa_exception must match the layout of "
"__cxa_dependent_exception");
static_assert(__builtin_offsetof(__cxa_exception, handlerCount) ==
__builtin_offsetof(__cxa_dependent_exception, handlerCount),
"the layout of __cxa_exception must match the layout of "
"__cxa_dependent_exception");
__cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
__cxa_exception* exception_header = globals->caughtExceptions;
// If we've rethrown a foreign exception, then globals->caughtExceptions
// will have been made an empty stack by __cxa_rethrow() and there is
// nothing more to be done. Do nothing!
if (NULL != exception_header)
{
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
if (native_exception)
{
// This is a native exception
if (exception_header->handlerCount < 0)
{
// The exception has been rethrown by __cxa_rethrow, so don't delete it
if (0 == incrementHandlerCount(exception_header))
{
// Remove from the chain of uncaught exceptions
globals->caughtExceptions = exception_header->nextException;
// but don't destroy
}
// Keep handlerCount negative in case there are nested catch's
// that need to be told that this exception is rethrown. Don't
// erase this rethrow flag until the exception is recaught.
}
else
{
// The native exception has not been rethrown
if (0 == decrementHandlerCount(exception_header))
{
// Remove from the chain of uncaught exceptions
globals->caughtExceptions = exception_header->nextException;
// Destroy this exception, being careful to distinguish
// between dependent and primary exceptions
if (isDependentException(&exception_header->unwindHeader))
{
// Reset exception_header to primaryException and deallocate the dependent exception
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
exception_header =
cxa_exception_from_thrown_object(dep_exception_header->primaryException);
__cxa_free_dependent_exception(dep_exception_header);
}
// Destroy the primary exception only if its referenceCount goes to 0
// (this decrement must be atomic)
__cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
}
}
}
else
{
// The foreign exception has not been rethrown. Pop the stack
// and delete it. If there are nested catch's and they try
// to touch a foreign exception in any way, that is undefined
// behavior. They likely can't since the only way to catch
// a foreign exception is with catch (...)!
_Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
globals->caughtExceptions = 0;
}
}
}
// Note: exception_header may be masquerading as a __cxa_dependent_exception
// and that's ok. exceptionType is there too.
// However watch out for foreign exceptions. Return null for them.
std::type_info *__cxa_current_exception_type() {
// get the current exception
__cxa_eh_globals *globals = __cxa_get_globals_fast();
if (NULL == globals)
return NULL; // If there have never been any exceptions, there are none now.
__cxa_exception *exception_header = globals->caughtExceptions;
if (NULL == exception_header)
return NULL; // No current exception
if (!__isOurExceptionClass(&exception_header->unwindHeader))
return NULL;
return exception_header->exceptionType;
}
// 2.5.4 Rethrowing Exceptions
/* This routine can rethrow native or foreign exceptions.
If the exception is native:
* marks the exception object on top of the caughtExceptions stack
(in an implementation-defined way) as being rethrown.
* If the caughtExceptions stack is empty, it calls terminate()
(see [C++FDIS] [except.throw], 15.1.8).
* It then calls _Unwind_RaiseException which should not return
(terminate if it does).
Note: exception_header may be masquerading as a __cxa_dependent_exception
and that's ok.
*/
void __cxa_rethrow() {
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header = globals->caughtExceptions;
if (NULL == exception_header)
std::terminate(); // throw; called outside of a exception handler
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
if (native_exception)
{
// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
exception_header->handlerCount = -exception_header->handlerCount;
globals->uncaughtExceptions += 1;
// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
}
else // this is a foreign exception
{
// The only way to communicate to __cxa_end_catch that we've rethrown
// a foreign exception, so don't delete us, is to pop the stack here
// which must be empty afterwards. Then __cxa_end_catch will do
// nothing
globals->caughtExceptions = 0;
}
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
_Unwind_RaiseException(&exception_header->unwindHeader);
#endif
// If we get here, some kind of unwinding error has occurred.
// There is some weird code generation bug happening with
// Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
// If we call failed_throw here. Turns up with -O2 or higher, and -Os.
__cxa_begin_catch(&exception_header->unwindHeader);
if (native_exception)
std::__terminate(exception_header->terminateHandler);
// Foreign exception: can't get exception_header->terminateHandler
std::terminate();
}
/*
If thrown_object is not null, atomically increment the referenceCount field
of the __cxa_exception header associated with the thrown object referred to
by thrown_object.
Requires: If thrown_object is not NULL, it is a native exception.
*/
void
__cxa_increment_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
}
}
/*
If thrown_object is not null, atomically decrement the referenceCount field
of the __cxa_exception header associated with the thrown object referred to
by thrown_object. If the referenceCount drops to zero, destroy and
deallocate the exception.
Requires: If thrown_object is not NULL, it is a native exception.
*/
_LIBCXXABI_NO_CFI
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
{
if (NULL != exception_header->exceptionDestructor)
exception_header->exceptionDestructor(thrown_object);
__cxa_free_exception(thrown_object);
}
}
}
/*
Returns a pointer to the thrown object (if any) at the top of the
caughtExceptions stack. Atomically increment the exception's referenceCount.
If there is no such thrown object or if the thrown object is foreign,
returns null.
We can use __cxa_get_globals_fast here to get the globals because if there have
been no exceptions thrown, ever, on this thread, we can return NULL without
the need to allocate the exception-handling globals.
*/
void *__cxa_current_primary_exception() throw() {
// get the current exception
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (NULL == globals)
return NULL; // If there are no globals, there is no exception
__cxa_exception* exception_header = globals->caughtExceptions;
if (NULL == exception_header)
return NULL; // No current exception
if (!__isOurExceptionClass(&exception_header->unwindHeader))
return NULL; // Can't capture a foreign exception (no way to refcount it)
if (isDependentException(&exception_header->unwindHeader)) {
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
}
void* thrown_object = thrown_object_from_cxa_exception(exception_header);
__cxa_increment_exception_refcount(thrown_object);
return thrown_object;
}
/*
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
stored in exc is called. Otherwise the referenceCount stored in the
primary exception is decremented, destroying the primary if necessary.
Finally the dependent exception is destroyed.
*/
static
void
dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
{
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
std::__terminate(dep_exception_header->terminateHandler);
__cxa_decrement_exception_refcount(dep_exception_header->primaryException);
__cxa_free_dependent_exception(dep_exception_header);
}
/*
If thrown_object is not null, allocate, initialize and throw a dependent
exception.
*/
void
__cxa_rethrow_primary_exception(void* thrown_object)
{
if ( thrown_object != NULL )
{
// thrown_object guaranteed to be native because
// __cxa_current_primary_exception returns NULL for foreign exceptions
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
__cxa_dependent_exception* dep_exception_header =
static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
dep_exception_header->primaryException = thrown_object;
__cxa_increment_exception_refcount(thrown_object);
dep_exception_header->exceptionType = exception_header->exceptionType;
dep_exception_header->unexpectedHandler = std::get_unexpected();
dep_exception_header->terminateHandler = std::get_terminate();
setDependentExceptionClass(&dep_exception_header->unwindHeader);
__cxa_get_globals()->uncaughtExceptions += 1;
dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
#else
_Unwind_RaiseException(&dep_exception_header->unwindHeader);
#endif
// Some sort of unwinding error. Note that terminate is a handler.
__cxa_begin_catch(&dep_exception_header->unwindHeader);
}
// If we return client will call terminate()
}
bool
__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
unsigned int
__cxa_uncaught_exceptions() throw()
{
// This does not report foreign exceptions in flight
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (globals == 0)
return 0;
return globals->uncaughtExceptions;
}
} // extern "C"
} // abi

View File

@ -0,0 +1,164 @@
//===------------------------- cxa_exception.h ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the "Exception Handling APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
//===----------------------------------------------------------------------===//
#ifndef _CXA_EXCEPTION_H
#define _CXA_EXCEPTION_H
#include <exception> // for std::unexpected_handler and std::terminate_handler
#include "cxxabi.h"
#include "unwind.h"
namespace __cxxabiv1 {
static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++
_LIBCXXABI_HIDDEN uint64_t __getExceptionClass (const _Unwind_Exception*);
_LIBCXXABI_HIDDEN void __setExceptionClass ( _Unwind_Exception*, uint64_t);
_LIBCXXABI_HIDDEN bool __isOurExceptionClass(const _Unwind_Exception*);
struct _LIBCXXABI_HIDDEN __cxa_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
// Now _Unwind_Exception is marked with __attribute__((aligned)),
// which implies __cxa_exception is also aligned. Insert padding
// in the beginning of the struct, rather than before unwindHeader.
void *reserve;
// This is a new field to support C++ 0x exception_ptr.
// For binary compatibility it is at the start of this
// struct which is prepended to the object thrown in
// __cxa_allocate_exception.
size_t referenceCount;
#endif
// Manage the exception object itself.
std::type_info *exceptionType;
void (*exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception *nextException;
int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void *catchTemp;
void *adjustedPtr;
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
// This is a new field to support C++ 0x exception_ptr.
// For binary compatibility it is placed where the compiler
// previously adding padded to 64-bit align unwindHeader.
size_t referenceCount;
#endif
_Unwind_Exception unwindHeader;
};
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
// The layout of this structure MUST match the layout of __cxa_exception, with
// primaryException instead of referenceCount.
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
void* reserve; // padding.
void* primaryException;
#endif
std::type_info *exceptionType;
void (*exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception *nextException;
int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void * catchTemp;
void *adjustedPtr;
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
void* primaryException;
#endif
_Unwind_Exception unwindHeader;
};
// Verify the negative offsets of different fields.
static_assert(sizeof(_Unwind_Exception) +
offsetof(__cxa_exception, unwindHeader) ==
sizeof(__cxa_exception),
"unwindHeader has wrong negative offsets");
static_assert(sizeof(_Unwind_Exception) +
offsetof(__cxa_dependent_exception, unwindHeader) ==
sizeof(__cxa_dependent_exception),
"unwindHeader has wrong negative offsets");
#if defined(_LIBCXXABI_ARM_EHABI)
static_assert(offsetof(__cxa_exception, propagationCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"propagationCount has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, propagationCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"propagationCount has wrong negative offset");
#elif defined(__LP64__) || defined(_WIN64)
static_assert(offsetof(__cxa_exception, adjustedPtr) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"adjustedPtr has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, adjustedPtr) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"adjustedPtr has wrong negative offset");
#else
static_assert(offsetof(__cxa_exception, referenceCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"referenceCount has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, primaryException) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"primaryException has wrong negative offset");
#endif
struct _LIBCXXABI_HIDDEN __cxa_eh_globals {
__cxa_exception * caughtExceptions;
unsigned int uncaughtExceptions;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* propagatingExceptions;
#endif
};
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals ();
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast ();
extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
} // namespace __cxxabiv1
#endif // _CXA_EXCEPTION_H

View File

@ -0,0 +1,105 @@
//===--------------------- cxa_exception_storage.cpp ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the storage for the "Caught Exception Stack"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack
//
//===----------------------------------------------------------------------===//
#include "cxa_exception.h"
#include <__threading_support>
#if defined(_LIBCXXABI_HAS_NO_THREADS)
namespace __cxxabiv1 {
extern "C" {
static __cxa_eh_globals eh_globals;
__cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
__cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
}
}
#elif defined(HAS_THREAD_LOCAL)
namespace __cxxabiv1 {
namespace {
__cxa_eh_globals * __globals () {
static thread_local __cxa_eh_globals eh_globals;
return &eh_globals;
}
}
extern "C" {
__cxa_eh_globals * __cxa_get_globals () { return __globals (); }
__cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); }
}
}
#else
#include "abort_message.h"
#include "fallback_malloc.h"
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
// In general, we treat all threading errors as fatal.
// We cannot call std::terminate() because that will in turn
// call __cxa_get_globals() and cause infinite recursion.
namespace __cxxabiv1 {
namespace {
std::__libcpp_tls_key key_;
std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) {
__free_with_fallback ( p );
if ( 0 != std::__libcpp_tls_set ( key_, NULL ) )
abort_message("cannot zero out thread value for __cxa_get_globals()");
}
void construct_ () {
if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) )
abort_message("cannot create thread specific key for __cxa_get_globals()");
}
}
extern "C" {
__cxa_eh_globals * __cxa_get_globals () {
// Try to get the globals for this thread
__cxa_eh_globals* retVal = __cxa_get_globals_fast ();
// If this is the first time we've been asked for these globals, create them
if ( NULL == retVal ) {
retVal = static_cast<__cxa_eh_globals*>
(__calloc_with_fallback (1, sizeof (__cxa_eh_globals)));
if ( NULL == retVal )
abort_message("cannot allocate __cxa_eh_globals");
if ( 0 != std::__libcpp_tls_set ( key_, retVal ) )
abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
}
return retVal;
}
// Note that this implementation will reliably return NULL if not
// preceded by a call to __cxa_get_globals(). This is an extension
// to the Itanium ABI and is taken advantage of in several places in
// libc++abi.
__cxa_eh_globals * __cxa_get_globals_fast () {
// First time through, create the key.
if (0 != std::__libcpp_execute_once(&flag_, construct_))
abort_message("execute once failure in __cxa_get_globals_fast()");
// static int init = construct_();
return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
}
}
}
#endif

View File

@ -0,0 +1,53 @@
//===---------------------------- cxa_guard.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "__cxxabi_config.h"
#include "cxxabi.h"
// Tell the implementation that we're building the actual implementation
// (and not testing it)
#define BUILDING_CXA_GUARD
#include "cxa_guard_impl.h"
/*
This implementation must be careful to not call code external to this file
which will turn around and try to call __cxa_guard_acquire reentrantly.
For this reason, the headers of this file are as restricted as possible.
Previous implementations of this code for __APPLE__ have used
std::__libcpp_mutex_lock and the abort_message utility without problem. This
implementation also uses std::__libcpp_condvar_wait which has tested
to not be a problem.
*/
namespace __cxxabiv1 {
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
using guard_type = uint32_t;
#else
using guard_type = uint64_t;
#endif
extern "C"
{
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
return static_cast<int>(imp.cxa_guard_acquire());
}
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
imp.cxa_guard_release();
}
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
imp.cxa_guard_abort();
}
} // extern "C"
} // __cxxabiv1

View File

@ -0,0 +1,567 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
#define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
/* cxa_guard_impl.h - Implements the C++ runtime support for function local
* static guards.
* The layout of the guard object is the same across ARM and Itanium.
*
* The first "guard byte" (which is checked by the compiler) is set only upon
* the completion of cxa release.
*
* The second "init byte" does the rest of the bookkeeping. It tracks if
* initialization is complete or pending, and if there are waiting threads.
*
* If the guard variable is 64-bits and the platforms supplies a 32-bit thread
* identifier, it is used to detect recursive initialization. The thread ID of
* the thread currently performing initialization is stored in the second word.
*
* Guard Object Layout:
* -------------------------------------------------------------------------
* |a: guard byte | a+1: init byte | a+2 : unused ... | a+4: thread-id ... |
* ------------------------------------------------------------------------
*
* Access Protocol:
* For each implementation the guard byte is checked and set before accessing
* the init byte.
*
* Overall Design:
* The implementation was designed to allow each implementation to be tested
* independent of the C++ runtime or platform support.
*
*/
#include "__cxxabi_config.h"
#include "include/atomic_support.h"
#include <unistd.h>
#include <sys/types.h>
#if defined(__has_include)
# if __has_include(<sys/syscall.h>)
# include <sys/syscall.h>
# endif
#endif
#include <stdlib.h>
#include <__threading_support>
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
// To make testing possible, this header is included from both cxa_guard.cpp
// and a number of tests.
//
// For this reason we place everything in an anonymous namespace -- even though
// we're in a header. We want the actual implementation and the tests to have
// unique definitions of the types in this header (since the tests may depend
// on function local statics).
//
// To enforce this either `BUILDING_CXA_GUARD` or `TESTING_CXA_GUARD` must be
// defined when including this file. Only `src/cxa_guard.cpp` should define
// the former.
#ifdef BUILDING_CXA_GUARD
# include "abort_message.h"
# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
#elif defined(TESTING_CXA_GUARD)
# define ABORT_WITH_MESSAGE(...) ::abort()
#else
# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
#endif
#if __has_feature(thread_sanitizer)
extern "C" void __tsan_acquire(void*);
extern "C" void __tsan_release(void*);
#else
#define __tsan_acquire(addr) ((void)0)
#define __tsan_release(addr) ((void)0)
#endif
namespace __cxxabiv1 {
// Use an anonymous namespace to ensure that the tests and actual implementation
// have unique definitions of these symbols.
namespace {
//===----------------------------------------------------------------------===//
// Misc Utilities
//===----------------------------------------------------------------------===//
template <class T, T(*Init)()>
struct LazyValue {
LazyValue() : is_init(false) {}
T& get() {
if (!is_init) {
value = Init();
is_init = true;
}
return value;
}
private:
T value;
bool is_init = false;
};
//===----------------------------------------------------------------------===//
// PlatformGetThreadID
//===----------------------------------------------------------------------===//
#if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
uint32_t PlatformThreadID() {
static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
return static_cast<uint32_t>(
pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
}
#elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
uint32_t PlatformThreadID() {
static_assert(sizeof(pid_t) == sizeof(uint32_t), "");
return static_cast<uint32_t>(syscall(SYS_gettid));
}
#else
constexpr uint32_t (*PlatformThreadID)() = nullptr;
#endif
constexpr bool PlatformSupportsThreadID() {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif
return +PlatformThreadID != nullptr;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
}
//===----------------------------------------------------------------------===//
// GuardBase
//===----------------------------------------------------------------------===//
enum class AcquireResult {
INIT_IS_DONE,
INIT_IS_PENDING,
};
constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
static constexpr uint8_t UNSET = 0;
static constexpr uint8_t COMPLETE_BIT = (1 << 0);
static constexpr uint8_t PENDING_BIT = (1 << 1);
static constexpr uint8_t WAITING_BIT = (1 << 2);
template <class Derived>
struct GuardObject {
GuardObject() = delete;
GuardObject(GuardObject const&) = delete;
GuardObject& operator=(GuardObject const&) = delete;
explicit GuardObject(uint32_t* g)
: base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
thread_id_address(nullptr) {}
explicit GuardObject(uint64_t* g)
: base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
thread_id_address(reinterpret_cast<uint32_t*>(g) + 1) {}
public:
/// Implements __cxa_guard_acquire
AcquireResult cxa_guard_acquire() {
AtomicInt<uint8_t> guard_byte(guard_byte_address);
if (guard_byte.load(std::_AO_Acquire) != UNSET)
return INIT_IS_DONE;
return derived()->acquire_init_byte();
}
/// Implements __cxa_guard_release
void cxa_guard_release() {
AtomicInt<uint8_t> guard_byte(guard_byte_address);
// Store complete first, so that when release wakes other folks, they see
// it as having been completed.
guard_byte.store(COMPLETE_BIT, std::_AO_Release);
derived()->release_init_byte();
}
/// Implements __cxa_guard_abort
void cxa_guard_abort() { derived()->abort_init_byte(); }
public:
/// base_address - the address of the original guard object.
void* const base_address;
/// The address of the guord byte at offset 0.
uint8_t* const guard_byte_address;
/// The address of the byte used by the implementation during initialization.
uint8_t* const init_byte_address;
/// An optional address storing an identifier for the thread performing initialization.
/// It's used to detect recursive initialization.
uint32_t* const thread_id_address;
private:
Derived* derived() { return static_cast<Derived*>(this); }
};
//===----------------------------------------------------------------------===//
// Single Threaded Implementation
//===----------------------------------------------------------------------===//
struct InitByteNoThreads : GuardObject<InitByteNoThreads> {
using GuardObject::GuardObject;
AcquireResult acquire_init_byte() {
if (*init_byte_address == COMPLETE_BIT)
return INIT_IS_DONE;
if (*init_byte_address & PENDING_BIT)
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
*init_byte_address = PENDING_BIT;
return INIT_IS_PENDING;
}
void release_init_byte() { *init_byte_address = COMPLETE_BIT; }
void abort_init_byte() { *init_byte_address = UNSET; }
};
//===----------------------------------------------------------------------===//
// Global Mutex Implementation
//===----------------------------------------------------------------------===//
struct LibcppMutex;
struct LibcppCondVar;
#ifndef _LIBCXXABI_HAS_NO_THREADS
struct LibcppMutex {
LibcppMutex() = default;
LibcppMutex(LibcppMutex const&) = delete;
LibcppMutex& operator=(LibcppMutex const&) = delete;
bool lock() { return std::__libcpp_mutex_lock(&mutex); }
bool unlock() { return std::__libcpp_mutex_unlock(&mutex); }
private:
friend struct LibcppCondVar;
std::__libcpp_mutex_t mutex = _LIBCPP_MUTEX_INITIALIZER;
};
struct LibcppCondVar {
LibcppCondVar() = default;
LibcppCondVar(LibcppCondVar const&) = delete;
LibcppCondVar& operator=(LibcppCondVar const&) = delete;
bool wait(LibcppMutex& mut) {
return std::__libcpp_condvar_wait(&cond, &mut.mutex);
}
bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
private:
std::__libcpp_condvar_t cond = _LIBCPP_CONDVAR_INITIALIZER;
};
#else
struct LibcppMutex {};
struct LibcppCondVar {};
#endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
uint32_t (*GetThreadID)() = PlatformThreadID>
struct InitByteGlobalMutex
: GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond,
GetThreadID>> {
using BaseT = typename InitByteGlobalMutex::GuardObject;
using BaseT::BaseT;
explicit InitByteGlobalMutex(uint32_t *g)
: BaseT(g), has_thread_id_support(false) {}
explicit InitByteGlobalMutex(uint64_t *g)
: BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {}
public:
AcquireResult acquire_init_byte() {
LockGuard g("__cxa_guard_acquire");
// Check for possible recursive initialization.
if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
if (*thread_id_address == current_thread_id.get())
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
}
// Wait until the pending bit is not set.
while (*init_byte_address & PENDING_BIT) {
*init_byte_address |= WAITING_BIT;
global_cond.wait(global_mutex);
}
if (*init_byte_address == COMPLETE_BIT)
return INIT_IS_DONE;
if (has_thread_id_support)
*thread_id_address = current_thread_id.get();
*init_byte_address = PENDING_BIT;
return INIT_IS_PENDING;
}
void release_init_byte() {
bool has_waiting;
{
LockGuard g("__cxa_guard_release");
has_waiting = *init_byte_address & WAITING_BIT;
*init_byte_address = COMPLETE_BIT;
}
if (has_waiting) {
if (global_cond.broadcast()) {
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_release");
}
}
}
void abort_init_byte() {
bool has_waiting;
{
LockGuard g("__cxa_guard_abort");
if (has_thread_id_support)
*thread_id_address = 0;
has_waiting = *init_byte_address & WAITING_BIT;
*init_byte_address = UNSET;
}
if (has_waiting) {
if (global_cond.broadcast()) {
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_abort");
}
}
}
private:
using BaseT::init_byte_address;
using BaseT::thread_id_address;
const bool has_thread_id_support;
LazyValue<uint32_t, GetThreadID> current_thread_id;
private:
struct LockGuard {
LockGuard() = delete;
LockGuard(LockGuard const&) = delete;
LockGuard& operator=(LockGuard const&) = delete;
explicit LockGuard(const char* calling_func)
: calling_func(calling_func) {
if (global_mutex.lock())
ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func);
}
~LockGuard() {
if (global_mutex.unlock())
ABORT_WITH_MESSAGE("%s failed to release mutex", calling_func);
}
private:
const char* const calling_func;
};
};
//===----------------------------------------------------------------------===//
// Futex Implementation
//===----------------------------------------------------------------------===//
#if defined(SYS_futex)
void PlatformFutexWait(int* addr, int expect) {
constexpr int WAIT = 0;
syscall(SYS_futex, addr, WAIT, expect, 0);
__tsan_acquire(addr);
}
void PlatformFutexWake(int* addr) {
constexpr int WAKE = 1;
__tsan_release(addr);
syscall(SYS_futex, addr, WAKE, INT_MAX);
}
#else
constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
constexpr void (*PlatformFutexWake)(int*) = nullptr;
#endif
constexpr bool PlatformSupportsFutex() {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif
return +PlatformFutexWait != nullptr;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
}
/// InitByteFutex - Manages initialization using atomics and the futex syscall
/// for waiting and waking.
template <void (*Wait)(int*, int) = PlatformFutexWait,
void (*Wake)(int*) = PlatformFutexWake,
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
struct InitByteFutex : GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>> {
using BaseT = typename InitByteFutex::GuardObject;
/// ARM Constructor
explicit InitByteFutex(uint32_t *g) : BaseT(g),
init_byte(this->init_byte_address),
has_thread_id_support(this->thread_id_address && GetThreadIDArg),
thread_id(this->thread_id_address) {}
/// Itanium Constructor
explicit InitByteFutex(uint64_t *g) : BaseT(g),
init_byte(this->init_byte_address),
has_thread_id_support(this->thread_id_address && GetThreadIDArg),
thread_id(this->thread_id_address) {}
public:
AcquireResult acquire_init_byte() {
while (true) {
uint8_t last_val = UNSET;
if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel,
std::_AO_Acquire)) {
if (has_thread_id_support) {
thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
}
return INIT_IS_PENDING;
}
if (last_val == COMPLETE_BIT)
return INIT_IS_DONE;
if (last_val & PENDING_BIT) {
// Check for recursive initialization
if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
}
if ((last_val & WAITING_BIT) == 0) {
// This compare exchange can fail for several reasons
// (1) another thread finished the whole thing before we got here
// (2) another thread set the waiting bit we were trying to thread
// (3) another thread had an exception and failed to finish
if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT,
std::_AO_Acq_Rel, std::_AO_Release)) {
// (1) success, via someone else's work!
if (last_val == COMPLETE_BIT)
return INIT_IS_DONE;
// (3) someone else, bailed on doing the work, retry from the start!
if (last_val == UNSET)
continue;
// (2) the waiting bit got set, so we are happy to keep waiting
}
}
wait_on_initialization();
}
}
}
void release_init_byte() {
uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
if (old & WAITING_BIT)
wake_all();
}
void abort_init_byte() {
if (has_thread_id_support)
thread_id.store(0, std::_AO_Relaxed);
uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel);
if (old & WAITING_BIT)
wake_all();
}
private:
/// Use the futex to wait on the current guard variable. Futex expects a
/// 32-bit 4-byte aligned address as the first argument, so we have to use use
/// the base address of the guard variable (not the init byte).
void wait_on_initialization() {
Wait(static_cast<int*>(this->base_address),
expected_value_for_futex(PENDING_BIT | WAITING_BIT));
}
void wake_all() { Wake(static_cast<int*>(this->base_address)); }
private:
AtomicInt<uint8_t> init_byte;
const bool has_thread_id_support;
// Unsafe to use unless has_thread_id_support
AtomicInt<uint32_t> thread_id;
LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
/// Create the expected integer value for futex `wait(int* addr, int expected)`.
/// We pass the base address as the first argument, So this function creates
/// an zero-initialized integer with `b` copied at the correct offset.
static int expected_value_for_futex(uint8_t b) {
int dest_val = 0;
std::memcpy(reinterpret_cast<char*>(&dest_val) + 1, &b, 1);
return dest_val;
}
static_assert(Wait != nullptr && Wake != nullptr, "");
};
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
template <class T>
struct GlobalStatic {
static T instance;
};
template <class T>
_LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
enum class Implementation {
NoThreads,
GlobalLock,
Futex
};
template <Implementation Impl>
struct SelectImplementation;
template <>
struct SelectImplementation<Implementation::NoThreads> {
using type = InitByteNoThreads;
};
template <>
struct SelectImplementation<Implementation::GlobalLock> {
using type = InitByteGlobalMutex<
LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
};
template <>
struct SelectImplementation<Implementation::Futex> {
using type =
InitByteFutex<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
};
// TODO(EricWF): We should prefer the futex implementation when available. But
// it should be done in a separate step from adding the implementation.
constexpr Implementation CurrentImplementation =
#if defined(_LIBCXXABI_HAS_NO_THREADS)
Implementation::NoThreads;
#elif defined(_LIBCXXABI_USE_FUTEX)
Implementation::Futex;
#else
Implementation::GlobalLock;
#endif
static_assert(CurrentImplementation != Implementation::Futex
|| PlatformSupportsFutex(), "Futex selected but not supported");
using SelectedImplementation =
SelectImplementation<CurrentImplementation>::type;
} // end namespace
} // end namespace __cxxabiv1
#endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H

View File

@ -0,0 +1,111 @@
//===------------------------- cxa_handlers.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the functionality associated with the terminate_handler,
// unexpected_handler, and new_handler.
//===----------------------------------------------------------------------===//
#include <stdexcept>
#include <new>
#include <exception>
#include "abort_message.h"
#include "cxxabi.h"
#include "cxa_handlers.h"
#include "cxa_exception.h"
#include "private_typeinfo.h"
#include "include/atomic_support.h"
namespace std
{
unexpected_handler
get_unexpected() _NOEXCEPT
{
return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire);
}
void
__unexpected(unexpected_handler func)
{
func();
// unexpected handler should not return
abort_message("unexpected_handler unexpectedly returned");
}
__attribute__((noreturn))
void
unexpected()
{
__unexpected(get_unexpected());
}
terminate_handler
get_terminate() _NOEXCEPT
{
return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire);
}
void
__terminate(terminate_handler func) _NOEXCEPT
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
func();
// handler should not return
abort_message("terminate_handler unexpectedly returned");
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
// handler should not throw exception
abort_message("terminate_handler unexpectedly threw an exception");
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
}
__attribute__((noreturn))
void
terminate() _NOEXCEPT
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
// If there might be an uncaught exception
using namespace __cxxabiv1;
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (globals)
{
__cxa_exception* exception_header = globals->caughtExceptions;
if (exception_header)
{
_Unwind_Exception* unwind_exception =
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
if (__isOurExceptionClass(unwind_exception))
__terminate(exception_header->terminateHandler);
}
}
#endif
__terminate(get_terminate());
}
extern "C" {
new_handler __cxa_new_handler = 0;
}
new_handler
set_new_handler(new_handler handler) _NOEXCEPT
{
return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
}
new_handler
get_new_handler() _NOEXCEPT
{
return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire);
}
} // std

View File

@ -0,0 +1,55 @@
//===------------------------- cxa_handlers.h -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the functionality associated with the terminate_handler,
// unexpected_handler, and new_handler.
//===----------------------------------------------------------------------===//
#ifndef _CXA_HANDLERS_H
#define _CXA_HANDLERS_H
#include <__cxxabi_config.h>
#include <exception>
namespace std
{
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
void
__unexpected(unexpected_handler func);
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
void
__terminate(terminate_handler func) _NOEXCEPT;
} // std
extern "C"
{
_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)();
_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)();
_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)();
/*
At some point in the future these three symbols will become
C++11 atomic variables:
extern std::atomic<std::terminate_handler> __cxa_terminate_handler;
extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler;
extern std::atomic<std::new_handler> __cxa_new_handler;
This change will not impact their ABI. But it will allow for a
portable performance optimization.
*/
} // extern "C"
#endif // _CXA_HANDLERS_H

View File

@ -0,0 +1,59 @@
//===------------------------- cxa_exception.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the "Exception Handling APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
//===----------------------------------------------------------------------===//
// Support functions for the no-exceptions libc++ library
#include "cxxabi.h"
#include <exception> // for std::terminate
#include "cxa_exception.h"
#include "cxa_handlers.h"
namespace __cxxabiv1 {
extern "C" {
void
__cxa_increment_exception_refcount(void *thrown_object) throw() {
if (thrown_object != nullptr)
std::terminate();
}
void
__cxa_decrement_exception_refcount(void *thrown_object) throw() {
if (thrown_object != nullptr)
std::terminate();
}
void *__cxa_current_primary_exception() throw() { return nullptr; }
void
__cxa_rethrow_primary_exception(void* thrown_object) {
if (thrown_object != nullptr)
std::terminate();
}
bool
__cxa_uncaught_exception() throw() { return false; }
unsigned int
__cxa_uncaught_exceptions() throw() { return 0; }
} // extern "C"
// provide dummy implementations for the 'no exceptions' case.
uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; }
void __setExceptionClass ( _Unwind_Exception*, uint64_t) {}
bool __isOurExceptionClass(const _Unwind_Exception*) { return false; }
} // abi

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
//===----------------------- cxa_thread_atexit.cpp ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "abort_message.h"
#include "cxxabi.h"
#include <__threading_support>
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
#include <stdlib.h>
namespace __cxxabiv1 {
using Dtor = void(*)(void*);
extern "C"
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
// A weak symbol is used to detect this function's presence in the C library
// at runtime, even if libc++ is built against an older libc
_LIBCXXABI_WEAK
#endif
int __cxa_thread_atexit_impl(Dtor, void*, void*);
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
namespace {
// This implementation is used if the C library does not provide
// __cxa_thread_atexit_impl() for us. It has a number of limitations that are
// difficult to impossible to address without ..._impl():
//
// - dso_symbol is ignored. This means that a shared library may be unloaded
// (via dlclose()) before its thread_local destructors have run.
//
// - thread_local destructors for the main thread are run by the destructor of
// a static object. This is later than expected; they should run before the
// destructors of any objects with static storage duration.
//
// - thread_local destructors on non-main threads run on the first iteration
// through the __libccpp_tls_key destructors.
// std::notify_all_at_thread_exit() and similar functions must be careful to
// wait until the second iteration to provide their intended ordering
// guarantees.
//
// Another limitation, though one shared with ..._impl(), is that any
// thread_locals that are first initialized after non-thread_local global
// destructors begin to run will not be destroyed. [basic.start.term] states
// that all thread_local destructors are sequenced before the destruction of
// objects with static storage duration, resulting in a contradiction if a
// thread_local is constructed after that point. Thus we consider such
// programs ill-formed, and don't bother to run those destructors. (If the
// program terminates abnormally after such a thread_local is constructed,
// the destructor is not expected to run and thus there is no contradiction.
// So construction still has to work.)
struct DtorList {
Dtor dtor;
void* obj;
DtorList* next;
};
// The linked list of thread-local destructors to run
__thread DtorList* dtors = nullptr;
// True if the destructors are currently scheduled to run on this thread
__thread bool dtors_alive = false;
// Used to trigger destructors on thread exit; value is ignored
std::__libcpp_tls_key dtors_key;
void run_dtors(void*) {
while (auto head = dtors) {
dtors = head->next;
head->dtor(head->obj);
::free(head);
}
dtors_alive = false;
}
struct DtorsManager {
DtorsManager() {
// There is intentionally no matching std::__libcpp_tls_delete call, as
// __cxa_thread_atexit() may be called arbitrarily late (for example, from
// global destructors or atexit() handlers).
if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
}
}
~DtorsManager() {
// std::__libcpp_tls_key destructors do not run on threads that call exit()
// (including when the main thread returns from main()), so we explicitly
// call the destructor here. This runs at exit time (potentially earlier
// if libc++abi is dlclose()'d). Any thread_locals initialized after this
// point will not be destroyed.
run_dtors(nullptr);
}
};
} // namespace
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
extern "C" {
_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
#else
if (__cxa_thread_atexit_impl) {
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
} else {
// Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
// one-time initialization and __cxa_atexit() for destruction)
static DtorsManager manager;
if (!dtors_alive) {
if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
return -1;
}
dtors_alive = true;
}
auto head = static_cast<DtorList*>(::malloc(sizeof(DtorList)));
if (!head) {
return -1;
}
head->dtor = dtor;
head->obj = obj;
head->next = dtors;
dtors = head;
return 0;
}
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
}
} // extern "C"
} // namespace __cxxabiv1

View File

@ -0,0 +1,22 @@
//===------------------------- cxa_unexpected.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <exception>
#include "cxxabi.h"
#include "cxa_exception.h"
namespace __cxxabiv1
{
extern "C"
{
}
} // namespace __cxxabiv1

View File

@ -0,0 +1,421 @@
//===-------------------------- cxa_vector.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the "Array Construction and Destruction APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
//
//===----------------------------------------------------------------------===//
#include "cxxabi.h"
#include "__cxxabi_config.h"
#include <exception> // for std::terminate
#include <new> // for std::bad_array_new_length
#include "abort_message.h"
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
namespace __cxxabiv1 {
#if 0
#pragma mark --Helper routines and classes --
#endif
namespace {
inline static size_t __get_element_count ( void *p ) {
return static_cast <size_t *> (p)[-1];
}
inline static void __set_element_count ( void *p, size_t element_count ) {
static_cast <size_t *> (p)[-1] = element_count;
}
// A pair of classes to simplify exception handling and control flow.
// They get passed a block of memory in the constructor, and unless the
// 'release' method is called, they deallocate the memory in the destructor.
// Preferred usage is to allocate some memory, attach it to one of these objects,
// and then, when all the operations to set up the memory block have succeeded,
// call 'release'. If any of the setup operations fail, or an exception is
// thrown, then the block is automatically deallocated.
//
// The only difference between these two classes is the signature for the
// deallocation function (to match new2/new3 and delete2/delete3.
class st_heap_block2 {
public:
typedef void (*dealloc_f)(void *);
st_heap_block2 ( dealloc_f dealloc, void *ptr )
: dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
void release () { enabled_ = false; }
private:
dealloc_f dealloc_;
void *ptr_;
bool enabled_;
};
class st_heap_block3 {
public:
typedef void (*dealloc_f)(void *, size_t);
st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
: dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
void release () { enabled_ = false; }
private:
dealloc_f dealloc_;
void *ptr_;
size_t size_;
bool enabled_;
};
class st_cxa_cleanup {
public:
typedef void (*destruct_f)(void *);
st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
: ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
destructor_ ( destructor ), enabled_ ( true ) {}
~st_cxa_cleanup () {
if ( enabled_ )
__cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
}
void release () { enabled_ = false; }
private:
void *ptr_;
size_t &idx_;
size_t element_size_;
destruct_f destructor_;
bool enabled_;
};
class st_terminate {
public:
st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
~st_terminate () { if ( enabled_ ) std::terminate (); }
void release () { enabled_ = false; }
private:
bool enabled_ ;
};
}
#if 0
#pragma mark --Externally visible routines--
#endif
namespace {
_LIBCXXABI_NORETURN
void throw_bad_array_new_length() {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_array_new_length();
#else
abort_message("__cxa_vec_new failed to allocate memory");
#endif
}
bool mul_overflow(size_t x, size_t y, size_t *res) {
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
|| defined(_LIBCXXABI_COMPILER_GCC)
return __builtin_mul_overflow(x, y, res);
#else
*res = x * y;
return x && ((*res / x) != y);
#endif
}
bool add_overflow(size_t x, size_t y, size_t *res) {
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
|| defined(_LIBCXXABI_COMPILER_GCC)
return __builtin_add_overflow(x, y, res);
#else
*res = x + y;
return *res < y;
#endif
}
size_t calculate_allocation_size_or_throw(size_t element_count,
size_t element_size,
size_t padding_size) {
size_t element_heap_size;
if (mul_overflow(element_count, element_size, &element_heap_size))
throw_bad_array_new_length();
size_t allocation_size;
if (add_overflow(element_heap_size, padding_size, &allocation_size))
throw_bad_array_new_length();
return allocation_size;
}
} // namespace
extern "C" {
// Equivalent to
//
// __cxa_vec_new2(element_count, element_size, padding_size, constructor,
// destructor, &::operator new[], &::operator delete[])
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *)) {
return __cxa_vec_new2 ( element_count, element_size, padding_size,
constructor, destructor, &::operator new [], &::operator delete [] );
}
// Given the number and size of elements for an array and the non-negative
// size of prefix padding for a cookie, allocate space (using alloc) for
// the array preceded by the specified padding, initialize the cookie if
// the padding is non-zero, and call the given constructor on each element.
// Return the address of the array proper, after the padding.
//
// If alloc throws an exception, rethrow the exception. If alloc returns
// NULL, return NULL. If the constructor throws an exception, call
// destructor for any already constructed elements, and rethrow the
// exception. If the destructor throws an exception, call std::terminate.
//
// The constructor may be NULL, in which case it must not be called. If the
// padding_size is zero, the destructor may be NULL; in that case it must
// not be called.
//
// Neither alloc nor dealloc may be NULL.
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *)) {
const size_t heap_size = calculate_allocation_size_or_throw(
element_count, element_size, padding_size);
char* const heap_block = static_cast<char*>(alloc(heap_size));
char* vec_base = heap_block;
if (NULL != vec_base) {
st_heap_block2 heap(dealloc, heap_block);
// put the padding before the array elements
if ( 0 != padding_size ) {
vec_base += padding_size;
__set_element_count ( vec_base, element_count );
}
// Construct the elements
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
heap.release (); // We're good!
}
return vec_base;
}
// Same as __cxa_vec_new2 except that the deallocation function takes both
// the object address and its size.
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
const size_t heap_size = calculate_allocation_size_or_throw(
element_count, element_size, padding_size);
char* const heap_block = static_cast<char*>(alloc(heap_size));
char* vec_base = heap_block;
if (NULL != vec_base) {
st_heap_block3 heap(dealloc, heap_block, heap_size);
// put the padding before the array elements
if ( 0 != padding_size ) {
vec_base += padding_size;
__set_element_count ( vec_base, element_count );
}
// Construct the elements
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
heap.release (); // We're good!
}
return vec_base;
}
// Given the (data) addresses of a destination and a source array, an
// element count and an element size, call the given copy constructor to
// copy each element from the source array to the destination array. The
// copy constructor's arguments are the destination address and source
// address, respectively. If an exception occurs, call the given destructor
// (if non-NULL) on each copied element and rethrow. If the destructor
// throws an exception, call terminate(). The constructor and or destructor
// pointers may be NULL. If either is NULL, no action is taken when it
// would have been called.
_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
size_t element_count,
size_t element_size,
void (*constructor)(void *, void *),
void (*destructor)(void *)) {
if ( NULL != constructor ) {
size_t idx = 0;
char *src_ptr = static_cast<char *>(src_array);
char *dest_ptr = static_cast<char *>(dest_array);
st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
for ( idx = 0; idx < element_count;
++idx, src_ptr += element_size, dest_ptr += element_size )
constructor ( dest_ptr, src_ptr );
cleanup.release (); // We're good!
}
}
// Given the (data) address of an array, not including any cookie padding,
// and the number and size of its elements, call the given constructor on
// each element. If the constructor throws an exception, call the given
// destructor for any already-constructed elements, and rethrow the
// exception. If the destructor throws an exception, call terminate(). The
// constructor and/or destructor pointers may be NULL. If either is NULL,
// no action is taken when it would have been called.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
void (*constructor)(void *), void (*destructor)(void *)) {
if ( NULL != constructor ) {
size_t idx;
char *ptr = static_cast <char *> ( array_address );
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
// Construct the elements
for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
constructor ( ptr );
cleanup.release (); // We're good!
}
}
// Given the (data) address of an array, the number of elements, and the
// size of its elements, call the given destructor on each element. If the
// destructor throws an exception, rethrow after destroying the remaining
// elements if possible. If the destructor throws a second exception, call
// terminate(). The destructor pointer may be NULL, in which case this
// routine does nothing.
_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *)) {
if ( NULL != destructor ) {
char *ptr = static_cast <char *> (array_address);
size_t idx = element_count;
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
{
st_terminate exception_guard (__cxa_uncaught_exception ());
ptr += element_count * element_size; // one past the last element
while ( idx-- > 0 ) {
ptr -= element_size;
destructor ( ptr );
}
exception_guard.release (); // We're good !
}
cleanup.release (); // We're still good!
}
}
// Given the (data) address of an array, the number of elements, and the
// size of its elements, call the given destructor on each element. If the
// destructor throws an exception, call terminate(). The destructor pointer
// may be NULL, in which case this routine does nothing.
_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *)) {
if ( NULL != destructor ) {
char *ptr = static_cast <char *> (array_address);
size_t idx = element_count;
st_terminate exception_guard;
ptr += element_count * element_size; // one past the last element
while ( idx-- > 0 ) {
ptr -= element_size;
destructor ( ptr );
}
exception_guard.release (); // We're done!
}
}
// If the array_address is NULL, return immediately. Otherwise, given the
// (data) address of an array, the non-negative size of prefix padding for
// the cookie, and the size of its elements, call the given destructor on
// each element, using the cookie to determine the number of elements, and
// then delete the space by calling ::operator delete[](void *). If the
// destructor throws an exception, rethrow after (a) destroying the
// remaining elements, and (b) deallocating the storage. If the destructor
// throws a second exception, call terminate(). If padding_size is 0, the
// destructor pointer must be NULL. If the destructor pointer is NULL, no
// destructor call is to be made.
//
// The intent of this function is to permit an implementation to call this
// function when confronted with an expression of the form delete[] p in
// the source code, provided that the default deallocation function can be
// used. Therefore, the semantics of this function are consistent with
// those required by the standard. The requirement that the deallocation
// function be called even if the destructor throws an exception derives
// from the resolution to DR 353 to the C++ standard, which was adopted in
// April, 2003.
_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
size_t element_size,
size_t padding_size,
void (*destructor)(void *)) {
__cxa_vec_delete2 ( array_address, element_size, padding_size,
destructor, &::operator delete [] );
}
// Same as __cxa_vec_delete, except that the given function is used for
// deallocation instead of the default delete function. If dealloc throws
// an exception, the result is undefined. The dealloc pointer may not be
// NULL.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *)) {
if ( NULL != array_address ) {
char *vec_base = static_cast <char *> (array_address);
char *heap_block = vec_base - padding_size;
st_heap_block2 heap ( dealloc, heap_block );
if ( 0 != padding_size && NULL != destructor ) // call the destructors
__cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
element_size, destructor );
}
}
// Same as __cxa_vec_delete, except that the given function is used for
// deallocation instead of the default delete function. The deallocation
// function takes both the object address and its size. If dealloc throws
// an exception, the result is undefined. The dealloc pointer may not be
// NULL.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
if ( NULL != array_address ) {
char *vec_base = static_cast <char *> (array_address);
char *heap_block = vec_base - padding_size;
const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
const size_t heap_block_size = element_size * element_count + padding_size;
st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
if ( 0 != padding_size && NULL != destructor ) // call the destructors
__cxa_vec_dtor ( array_address, element_count, element_size, destructor );
}
}
} // extern "C"
} // abi

View File

@ -0,0 +1,24 @@
//===-------------------------- cxa_virtual.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "cxxabi.h"
#include "abort_message.h"
namespace __cxxabiv1 {
extern "C" {
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
void __cxa_pure_virtual(void) {
abort_message("Pure virtual function called!");
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
void __cxa_deleted_virtual(void) {
abort_message("Deleted virtual function called!");
}
} // extern "C"
} // abi

View File

@ -0,0 +1,2 @@
BasedOnStyle: LLVM

View File

@ -0,0 +1,97 @@
//===--- DemangleConfig.h --------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// This file is contains a subset of macros copied from
// llvm/include/llvm/Demangle/DemangleConfig.h
//===----------------------------------------------------------------------===//
#ifndef LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
#define LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
#include <ciso646>
#ifdef _MSC_VER
// snprintf is implemented in VS 2015
#if _MSC_VER < 1900
#define snprintf _snprintf_s
#endif
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef DEMANGLE_GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
((maj) << 20) + ((min) << 10) + (patch))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
#else
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
#endif
#endif
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
#else
#define DEMANGLE_ATTRIBUTE_USED
#endif
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define DEMANGLE_UNREACHABLE __assume(false)
#else
#define DEMANGLE_UNREACHABLE
#endif
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if !defined(NDEBUG)
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
#else
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define DEMANGLE_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
#else
#define DEMANGLE_FALLTHROUGH
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }
#endif // LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
Itanium Name Demangler Library
==============================
Introduction
------------
This directory contains the generic itanium name demangler library. The main
purpose of the library is to demangle C++ symbols, i.e. convert the string
"_Z1fv" into "f()". You can also use the CRTP base ManglingParser to perform
some simple analysis on the mangled name, or (in LLVM) use the opaque
ItaniumPartialDemangler to query the demangled AST.
Why are there multiple copies of the this library in the source tree?
---------------------------------------------------------------------
This directory is mirrored between libcxxabi/demangle and
llvm/include/llvm/Demangle. The simple reason for this is that both projects
need to demangle symbols, but neither can depend on each other. libcxxabi needs
the demangler to implement __cxa_demangle, which is part of the itanium ABI
spec. LLVM needs a copy for a bunch of places, but doesn't want to use the
system's __cxa_demangle because it a) might not be available (i.e., on Windows),
and b) probably isn't that up-to-date on the latest language features.
The copy of the demangler in LLVM has some extra stuff that aren't needed in
libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), which depend on the
shared generic components. Despite these differences, we want to keep the "core"
generic demangling library identical between both copies to simplify development
and testing.
If you're working on the generic library, then do the work first in libcxxabi,
then run the cp-to-llvm.sh script in src/demangle. This script takes as an
argument the path to llvm, and re-copies the changes you made to libcxxabi over.
Note that this script just blindly overwrites all changes to the generic library
in llvm, so be careful.
Because the core demangler needs to work in libcxxabi, everything needs to be
declared in an anonymous namespace (see DEMANGLE_NAMESPACE_BEGIN), and you can't
introduce any code that depends on the libcxx dylib.
Hopefully, when LLVM becomes a monorepo, we can de-duplicate this code, and have
both LLVM and libcxxabi depend on a shared demangler library.
Testing
-------
The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
llvm/unittest/Demangle. The llvm directory should only get tests for stuff not
included in the core library. In the future though, we should probably move all
the tests to LLVM.
It is also a really good idea to run libFuzzer after non-trivial changes, see
libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html.

View File

@ -0,0 +1,126 @@
//===--- StringView.h -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
DEMANGLE_NAMESPACE_BEGIN
class StringView {
const char *First;
const char *Last;
public:
static const size_t npos = ~size_t(0);
template <size_t N>
StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
StringView(const char *First_, const char *Last_)
: First(First_), Last(Last_) {}
StringView(const char *First_, size_t Len)
: First(First_), Last(First_ + Len) {}
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const {
return StringView(begin() + From, size() - From);
}
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
if (FindBegin < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First + N, Last);
}
StringView dropBack(size_t N = 1) const {
if (N >= size())
N = size();
return StringView(First, Last - N);
}
char front() const {
assert(!empty());
return *begin();
}
char back() const {
assert(!empty());
return *(end() - 1);
}
char popFront() {
assert(!empty());
return *First++;
}
bool consumeFront(char C) {
if (!startsWith(C))
return false;
*this = dropFront(1);
return true;
}
bool consumeFront(StringView S) {
if (!startsWith(S))
return false;
*this = dropFront(S.size());
return true;
}
bool startsWith(char C) const { return !empty() && *begin() == C; }
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
return std::equal(Str.begin(), Str.end(), begin());
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
const char *begin() const { return First; }
const char *end() const { return Last; }
size_t size() const { return static_cast<size_t>(Last - First); }
bool empty() const { return First == Last; }
};
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -0,0 +1,191 @@
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there is at least n more positions in buffer.
void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) {
BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition)
BufferCapacity = N + CurrentPosition;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
void writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case...
if (N == 0) {
*this << '0';
return;
}
char Temp[21];
char *TempPtr = std::end(Temp);
while (N) {
*--TempPtr = '0' + char(N % 10);
N /= 10;
}
// Add negative sign...
if (isNeg)
*--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
}
public:
OutputStream(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputStream() = default;
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) {
size_t Size = R.size();
if (Size == 0)
return *this;
grow(Size);
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputStream &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputStream &operator<<(StringView R) { return (*this += R); }
OutputStream &operator<<(char C) { return (*this += C); }
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
OutputStream &operator<<(unsigned long long N) {
writeUnsigned(N, false);
return *this;
}
OutputStream &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputStream &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class SwapAndRestore {
T &Restore;
T OriginalValue;
bool ShouldRestore = true;
public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
SwapAndRestore(T &Restore_, T NewVal)
: Restore(Restore_), OriginalValue(Restore) {
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
}
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
};
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -0,0 +1,27 @@
#!/bin/bash
# Copies the 'demangle' library, excluding 'DemangleConfig.h', to llvm. If no
# llvm directory is specified, then assume a monorepo layout.
set -e
FILES="ItaniumDemangle.h StringView.h Utility.h README.txt"
LLVM_DEMANGLE_DIR=$1
if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then
LLVM_DEMANGLE_DIR="../../../llvm/include/llvm/Demangle"
fi
if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
echo "No such directory: $LLVM_DEMANGLE_DIR" >&2
exit 1
fi
read -p "This will overwrite the copies of $FILES in $LLVM_DEMANGLE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
echo
if [[ $ANSWER =~ ^[Yy]$ ]]; then
for I in $FILES ; do
cp $I $LLVM_DEMANGLE_DIR/$I
done
fi

View File

@ -0,0 +1,259 @@
//===------------------------ fallback_malloc.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
// is only defined when libc aligned allocation is not available.
#define _LIBCPP_BUILDING_LIBRARY
#include "fallback_malloc.h"
#include <__threading_support>
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
#include <stdlib.h> // for malloc, calloc, free
#include <string.h> // for memset
// A small, simple heap manager based (loosely) on
// the startup heap manager from FreeBSD, optimized for space.
//
// Manages a fixed-size memory pool, supports malloc and free only.
// No support for realloc.
//
// Allocates chunks in multiples of four bytes, with a four byte header
// for each chunk. The overhead of each chunk is kept low by keeping pointers
// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
namespace {
// When POSIX threads are not available, make the mutex operations a nop
#ifndef _LIBCXXABI_HAS_NO_THREADS
_LIBCPP_SAFE_STATIC
static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
#else
static void* heap_mutex = 0;
#endif
class mutexor {
public:
#ifndef _LIBCXXABI_HAS_NO_THREADS
mutexor(std::__libcpp_mutex_t* m) : mtx_(m) {
std::__libcpp_mutex_lock(mtx_);
}
~mutexor() { std::__libcpp_mutex_unlock(mtx_); }
#else
mutexor(void*) {}
~mutexor() {}
#endif
private:
mutexor(const mutexor& rhs);
mutexor& operator=(const mutexor& rhs);
#ifndef _LIBCXXABI_HAS_NO_THREADS
std::__libcpp_mutex_t* mtx_;
#endif
};
static const size_t HEAP_SIZE = 512;
char heap[HEAP_SIZE] __attribute__((aligned));
typedef unsigned short heap_offset;
typedef unsigned short heap_size;
struct heap_node {
heap_offset next_node; // offset into heap
heap_size len; // size in units of "sizeof(heap_node)"
};
static const heap_node* list_end =
(heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap
static heap_node* freelist = NULL;
heap_node* node_from_offset(const heap_offset offset) {
return (heap_node*)(heap + (offset * sizeof(heap_node)));
}
heap_offset offset_from_node(const heap_node* ptr) {
return static_cast<heap_offset>(
static_cast<size_t>(reinterpret_cast<const char*>(ptr) - heap) /
sizeof(heap_node));
}
void init_heap() {
freelist = (heap_node*)heap;
freelist->next_node = offset_from_node(list_end);
freelist->len = HEAP_SIZE / sizeof(heap_node);
}
// How big a chunk we allocate
size_t alloc_size(size_t len) {
return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1;
}
bool is_fallback_ptr(void* ptr) {
return ptr >= heap && ptr < (heap + HEAP_SIZE);
}
void* fallback_malloc(size_t len) {
heap_node *p, *prev;
const size_t nelems = alloc_size(len);
mutexor mtx(&heap_mutex);
if (NULL == freelist)
init_heap();
// Walk the free list, looking for a "big enough" chunk
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
if (p->len > nelems) { // chunk is larger, shorten, and return the tail
heap_node* q;
p->len = static_cast<heap_size>(p->len - nelems);
q = p + p->len;
q->next_node = 0;
q->len = static_cast<heap_size>(nelems);
return (void*)(q + 1);
}
if (p->len == nelems) { // exact size match
if (prev == 0)
freelist = node_from_offset(p->next_node);
else
prev->next_node = p->next_node;
p->next_node = 0;
return (void*)(p + 1);
}
}
return NULL; // couldn't find a spot big enough
}
// Return the start of the next block
heap_node* after(struct heap_node* p) { return p + p->len; }
void fallback_free(void* ptr) {
struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk
struct heap_node *p, *prev;
mutexor mtx(&heap_mutex);
#ifdef DEBUG_FALLBACK_MALLOC
std::cout << "Freeing item at " << offset_from_node(cp) << " of size "
<< cp->len << std::endl;
#endif
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
#ifdef DEBUG_FALLBACK_MALLOC
std::cout << " p, cp, after (p), after(cp) " << offset_from_node(p) << ' '
<< offset_from_node(cp) << ' ' << offset_from_node(after(p))
<< ' ' << offset_from_node(after(cp)) << std::endl;
#endif
if (after(p) == cp) {
#ifdef DEBUG_FALLBACK_MALLOC
std::cout << " Appending onto chunk at " << offset_from_node(p)
<< std::endl;
#endif
p->len = static_cast<heap_size>(
p->len + cp->len); // make the free heap_node larger
return;
} else if (after(cp) == p) { // there's a free heap_node right after
#ifdef DEBUG_FALLBACK_MALLOC
std::cout << " Appending free chunk at " << offset_from_node(p)
<< std::endl;
#endif
cp->len = static_cast<heap_size>(cp->len + p->len);
if (prev == 0) {
freelist = cp;
cp->next_node = p->next_node;
} else
prev->next_node = offset_from_node(cp);
return;
}
}
// Nothing to merge with, add it to the start of the free list
#ifdef DEBUG_FALLBACK_MALLOC
std::cout << " Making new free list entry " << offset_from_node(cp)
<< std::endl;
#endif
cp->next_node = offset_from_node(freelist);
freelist = cp;
}
#ifdef INSTRUMENT_FALLBACK_MALLOC
size_t print_free_list() {
struct heap_node *p, *prev;
heap_size total_free = 0;
if (NULL == freelist)
init_heap();
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
std::cout << (prev == 0 ? "" : " ") << "Offset: " << offset_from_node(p)
<< "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
total_free += p->len;
}
std::cout << "Total Free space: " << total_free << std::endl;
return total_free;
}
#endif
} // end unnamed namespace
namespace __cxxabiv1 {
struct __attribute__((aligned)) __aligned_type {};
void* __aligned_malloc_with_fallback(size_t size) {
#if defined(_WIN32)
if (void* dest = _aligned_malloc(size, alignof(__aligned_type)))
return dest;
#elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
if (void* dest = ::malloc(size))
return dest;
#else
if (size == 0)
size = 1;
void* dest;
if (::posix_memalign(&dest, __alignof(__aligned_type), size) == 0)
return dest;
#endif
return fallback_malloc(size);
}
void* __calloc_with_fallback(size_t count, size_t size) {
void* ptr = ::calloc(count, size);
if (NULL != ptr)
return ptr;
// if calloc fails, fall back to emergency stash
ptr = fallback_malloc(size * count);
if (NULL != ptr)
::memset(ptr, 0, size * count);
return ptr;
}
void __aligned_free_with_fallback(void* ptr) {
if (is_fallback_ptr(ptr))
fallback_free(ptr);
else {
#if defined(_WIN32)
::_aligned_free(ptr);
#else
::free(ptr);
#endif
}
}
void __free_with_fallback(void* ptr) {
if (is_fallback_ptr(ptr))
fallback_free(ptr);
else
::free(ptr);
}
} // namespace __cxxabiv1

View File

@ -0,0 +1,28 @@
//===------------------------- fallback_malloc.h --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _FALLBACK_MALLOC_H
#define _FALLBACK_MALLOC_H
#include "__cxxabi_config.h"
#include <stddef.h> // for size_t
namespace __cxxabiv1 {
// Allocate some memory from _somewhere_
_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size);
// Allocate and zero-initialize memory from _somewhere_
_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size);
_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr);
_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr);
} // namespace __cxxabiv1
#endif

View File

@ -0,0 +1,210 @@
//===----------------------------------------------------------------------===////
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===////
// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead
// of duplicating the file in libc++abi we should require that the libc++
// sources are available when building libc++abi.
#ifndef ATOMIC_SUPPORT_H
#define ATOMIC_SUPPORT_H
#include "__config"
#include "memory" // for __libcpp_relaxed_load
#if defined(__clang__) && __has_builtin(__atomic_load_n) \
&& __has_builtin(__atomic_store_n) \
&& __has_builtin(__atomic_add_fetch) \
&& __has_builtin(__atomic_exchange_n) \
&& __has_builtin(__atomic_compare_exchange_n) \
&& defined(__ATOMIC_RELAXED) \
&& defined(__ATOMIC_CONSUME) \
&& defined(__ATOMIC_ACQUIRE) \
&& defined(__ATOMIC_RELEASE) \
&& defined(__ATOMIC_ACQ_REL) \
&& defined(__ATOMIC_SEQ_CST)
# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
#endif
#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
# if defined(_LIBCPP_WARNING)
_LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
# else
# warning Building libc++ without __atomic builtins is unsupported
# endif
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
namespace {
#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
enum __libcpp_atomic_order {
_AO_Relaxed = __ATOMIC_RELAXED,
_AO_Consume = __ATOMIC_CONSUME,
_AO_Acquire = __ATOMIC_ACQUIRE,
_AO_Release = __ATOMIC_RELEASE,
_AO_Acq_Rel = __ATOMIC_ACQ_REL,
_AO_Seq = __ATOMIC_SEQ_CST
};
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
int __order = _AO_Seq)
{
__atomic_store_n(__dest, __val, __order);
}
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
{
__atomic_store_n(__dest, __val, _AO_Relaxed);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_load(_ValueType const* __val,
int __order = _AO_Seq)
{
return __atomic_load_n(__val, __order);
}
template <class _ValueType, class _AddType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
int __order = _AO_Seq)
{
return __atomic_add_fetch(__val, __a, __order);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_exchange(_ValueType* __target,
_ValueType __value, int __order = _AO_Seq)
{
return __atomic_exchange_n(__target, __value, __order);
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
bool __libcpp_atomic_compare_exchange(_ValueType* __val,
_ValueType* __expected, _ValueType __after,
int __success_order = _AO_Seq,
int __fail_order = _AO_Seq)
{
return __atomic_compare_exchange_n(__val, __expected, __after, true,
__success_order, __fail_order);
}
#else // _LIBCPP_HAS_NO_THREADS
enum __libcpp_atomic_order {
_AO_Relaxed,
_AO_Consume,
_AO_Acquire,
_AO_Release,
_AO_Acq_Rel,
_AO_Seq
};
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
int = 0)
{
*__dest = __val;
}
template <class _ValueType, class _FromType>
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
{
*__dest = __val;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_load(_ValueType const* __val,
int = 0)
{
return *__val;
}
template <class _ValueType, class _AddType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
int = 0)
{
return *__val += __a;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_ValueType __libcpp_atomic_exchange(_ValueType* __target,
_ValueType __value, int = _AO_Seq)
{
_ValueType old = *__target;
*__target = __value;
return old;
}
template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
bool __libcpp_atomic_compare_exchange(_ValueType* __val,
_ValueType* __expected, _ValueType __after,
int = 0, int = 0)
{
if (*__val == *__expected) {
*__val = __after;
return true;
}
*__expected = *__val;
return false;
}
#endif // _LIBCPP_HAS_NO_THREADS
} // end namespace
_LIBCPP_END_NAMESPACE_STD
namespace {
template <class IntType>
class AtomicInt {
public:
using MemoryOrder = std::__libcpp_atomic_order;
explicit AtomicInt(IntType *b) : b(b) {}
AtomicInt(AtomicInt const&) = delete;
AtomicInt& operator=(AtomicInt const&) = delete;
IntType load(MemoryOrder ord) {
return std::__libcpp_atomic_load(b, ord);
}
void store(IntType val, MemoryOrder ord) {
std::__libcpp_atomic_store(b, val, ord);
}
IntType exchange(IntType new_val, MemoryOrder ord) {
return std::__libcpp_atomic_exchange(b, new_val, ord);
}
bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
return std::__libcpp_atomic_compare_exchange(b, expected, desired, ord_success, ord_failure);
}
private:
IntType *b;
};
} // end namespace
#endif // ATOMIC_SUPPORT_H

View File

@ -0,0 +1,131 @@
//===------------------------ __refstring ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of
// duplicating the file in libc++abi we should require that the libc++ sources
// are available when building libc++abi.
#ifndef _LIBCPPABI_REFSTRING_H
#define _LIBCPPABI_REFSTRING_H
#include <__config>
#include <stdexcept>
#include <cstddef>
#include <cstring>
#ifdef __APPLE__
#include <dlfcn.h>
#include <mach-o/dyld.h>
#endif
#include "atomic_support.h"
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __refstring_imp { namespace {
typedef int count_t;
struct _Rep_base {
std::size_t len;
std::size_t cap;
count_t count;
};
inline _Rep_base* rep_from_data(const char *data_) noexcept {
char *data = const_cast<char *>(data_);
return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
}
inline char * data_from_rep(_Rep_base *rep) noexcept {
char *data = reinterpret_cast<char *>(rep);
return data + sizeof(*rep);
}
#if defined(__APPLE__)
inline
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));
}
inline
const char*
get_gcc_empty_string_storage() _NOEXCEPT
{
static const char* p = compute_gcc_empty_string_storage();
return p;
}
#endif
}} // namespace __refstring_imp
using namespace __refstring_imp;
inline
__libcpp_refstring::__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);
__imp_ = data;
}
inline
__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
: __imp_(s.__imp_)
{
if (__uses_refcount())
__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
}
inline
__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
bool adjust_old_count = __uses_refcount();
struct _Rep_base *old_rep = rep_from_data(__imp_);
__imp_ = s.__imp_;
if (__uses_refcount())
__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
if (adjust_old_count)
{
if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
{
::operator delete(old_rep);
}
}
return *this;
}
inline
__libcpp_refstring::~__libcpp_refstring() {
if (__uses_refcount()) {
_Rep_base* rep = rep_from_data(__imp_);
if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
::operator delete(rep);
}
}
}
inline
bool __libcpp_refstring::__uses_refcount() const {
#ifdef __APPLE__
return __imp_ != get_gcc_empty_string_storage();
#else
return true;
#endif
}
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPPABI_REFSTRING_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,251 @@
//===------------------------ private_typeinfo.h --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef __PRIVATE_TYPEINFO_H_
#define __PRIVATE_TYPEINFO_H_
#include "__cxxabi_config.h"
#include <typeinfo>
#include <stddef.h>
namespace __cxxabiv1 {
class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__shim_type_info();
_LIBCXXABI_HIDDEN virtual void noop1() const;
_LIBCXXABI_HIDDEN virtual void noop2() const;
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type,
void *&adjustedPtr) const = 0;
};
class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__fundamental_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__array_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__function_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__enum_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
enum
{
unknown = 0,
public_path,
not_public_path,
yes,
no
};
class _LIBCXXABI_TYPE_VIS __class_type_info;
struct _LIBCXXABI_HIDDEN __dynamic_cast_info
{
// const data supplied to the search:
const __class_type_info* dst_type;
const void* static_ptr;
const __class_type_info* static_type;
ptrdiff_t src2dst_offset;
// Data that represents the answer:
// pointer to a dst_type which has (static_ptr, static_type) above it
const void* dst_ptr_leading_to_static_ptr;
// pointer to a dst_type which does not have (static_ptr, static_type) above it
const void* dst_ptr_not_leading_to_static_ptr;
// The following three paths are either unknown, public_path or not_public_path.
// access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
int path_dst_ptr_to_static_ptr;
// access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
// when there is no dst_type along the path
int path_dynamic_ptr_to_static_ptr;
// access of path from (dynamic_ptr, dynamic_type) to dst_type
// (not used if there is a (static_ptr, static_type) above a dst_type).
int path_dynamic_ptr_to_dst_ptr;
// Number of dst_types below (static_ptr, static_type)
int number_to_static_ptr;
// Number of dst_types not below (static_ptr, static_type)
int number_to_dst_ptr;
// Data that helps stop the search before the entire tree is searched:
// is_dst_type_derived_from_static_type is either unknown, yes or no.
int is_dst_type_derived_from_static_type;
// Number of dst_type in tree. If 0, then that means unknown.
int number_of_dst_type;
// communicates to a dst_type node that (static_ptr, static_type) was found
// above it.
bool found_our_static_ptr;
// communicates to a dst_type node that a static_type was found
// above it, but it wasn't (static_ptr, static_type)
bool found_any_static_type;
// Set whenever a search can be stopped
bool search_done;
};
// Has no base class
class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__class_type_info();
_LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
const void *,
const void *, int) const;
_LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
const void *, int) const;
_LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *,
int) const;
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
// Has one non-virtual public base class at offset zero
class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
public:
const __class_type_info *__base_type;
_LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
struct _LIBCXXABI_HIDDEN __base_class_type_info
{
public:
const __class_type_info* __base_type;
long __offset_flags;
enum __offset_flags_masks
{
__virtual_mask = 0x1,
__public_mask = 0x2, // base is public
__offset_shift = 8
};
void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
};
// Has one or more base classes
class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
public:
unsigned int __flags;
unsigned int __base_count;
__base_class_type_info __base_info[1];
enum __flags_masks {
__non_diamond_repeat_mask = 0x1, // has two or more distinct base class
// objects of the same type
__diamond_shaped_mask = 0x2 // has base class object with two or
// more derived objects
};
_LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info();
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
public:
unsigned int __flags;
const __shim_type_info *__pointee;
enum __masks {
__const_mask = 0x1,
__volatile_mask = 0x2,
__restrict_mask = 0x4,
__incomplete_mask = 0x8,
__incomplete_class_mask = 0x10,
__transaction_safe_mask = 0x20,
// This implements the following proposal from cxx-abi-dev (not yet part of
// the ABI document):
//
// http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html
//
// This is necessary for support of http://wg21.link/p0012, which permits
// throwing noexcept function and member function pointers and catching
// them as non-noexcept pointers.
__noexcept_mask = 0x40,
// Flags that cannot be removed by a standard conversion.
__no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask,
// Flags that cannot be added by a standard conversion.
__no_add_flags_mask = __transaction_safe_mask | __noexcept_mask
};
_LIBCXXABI_HIDDEN virtual ~__pbase_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__pointer_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
};
class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
: public __pbase_type_info {
public:
const __class_type_info *__context;
_LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
};
} // __cxxabiv1
#endif // __PRIVATE_TYPEINFO_H_

View File

@ -0,0 +1,71 @@
//===---------------------------- exception.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#define _LIBCPP_BUILDING_LIBRARY
#include <new>
#include <exception>
namespace std
{
// exception
exception::~exception() _NOEXCEPT
{
}
const char* exception::what() const _NOEXCEPT
{
return "std::exception";
}
// bad_exception
bad_exception::~bad_exception() _NOEXCEPT
{
}
const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
// bad_alloc
bad_alloc::bad_alloc() _NOEXCEPT
{
}
bad_alloc::~bad_alloc() _NOEXCEPT
{
}
const char*
bad_alloc::what() const _NOEXCEPT
{
return "std::bad_alloc";
}
// bad_array_new_length
bad_array_new_length::bad_array_new_length() _NOEXCEPT
{
}
bad_array_new_length::~bad_array_new_length() _NOEXCEPT
{
}
const char*
bad_array_new_length::what() const _NOEXCEPT
{
return "bad_array_new_length";
}
} // std

View File

@ -0,0 +1,262 @@
//===--------------------- stdlib_new_delete.cpp --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// This file implements the new and delete operators.
//===----------------------------------------------------------------------===//
#define _LIBCPP_BUILDING_LIBRARY
#include "__cxxabi_config.h"
#include <new>
#include <cstdlib>
#if !defined(_THROW_BAD_ALLOC) || !defined(_NOEXCEPT) || !defined(_LIBCXXABI_WEAK)
#error The _THROW_BAD_ALLOC, _NOEXCEPT, and _LIBCXXABI_WEAK libc++ macros must \
already be defined by libc++.
#endif
// Implement all new and delete operators as weak definitions
// in this shared library, so that they can be overridden by programs
// that define non-weak copies of the functions.
_LIBCXXABI_WEAK
void *
operator new(std::size_t size) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
void* p;
while ((p = ::malloc(size)) == 0)
{
// If malloc fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_alloc();
#else
break;
#endif
}
return p;
}
_LIBCXXABI_WEAK
void*
operator new(size_t size, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
p = ::operator new(size);
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
return p;
}
_LIBCXXABI_WEAK
void*
operator new[](size_t size) _THROW_BAD_ALLOC
{
return ::operator new(size);
}
_LIBCXXABI_WEAK
void*
operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
p = ::operator new[](size);
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
return p;
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr) _NOEXCEPT
{
if (ptr)
::free(ptr);
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr, size_t) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr) _NOEXCEPT
{
::operator delete(ptr);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT
{
::operator delete[](ptr);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr, size_t) _NOEXCEPT
{
::operator delete[](ptr);
}
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
_LIBCXXABI_WEAK
void *
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
if (static_cast<size_t>(alignment) < sizeof(void*))
alignment = std::align_val_t(sizeof(void*));
void* p;
#if defined(_LIBCPP_WIN32API)
while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr)
#else
while (::posix_memalign(&p, static_cast<size_t>(alignment), size) != 0)
#endif
{
// If posix_memalign fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_alloc();
#else
p = nullptr; // posix_memalign doesn't initialize 'p' on failure
break;
#endif
}
}
return p;
}
_LIBCXXABI_WEAK
void*
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
p = ::operator new(size, alignment);
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
return p;
}
_LIBCXXABI_WEAK
void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
return ::operator new(size, alignment);
}
_LIBCXXABI_WEAK
void*
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
void* p = 0;
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
p = ::operator new[](size, alignment);
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
return p;
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr, std::align_val_t) _NOEXCEPT
{
if (ptr)
#if defined(_LIBCPP_WIN32API)
::_aligned_free(ptr);
#else
::free(ptr);
#endif
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCXXABI_WEAK
void
operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT
{
::operator delete(ptr, alignment);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
{
::operator delete[](ptr, alignment);
}
_LIBCXXABI_WEAK
void
operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
{
::operator delete[](ptr, alignment);
}
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION

View File

@ -0,0 +1,47 @@
//===------------------------ stdexcept.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "include/refstring.h"
#include "stdexcept"
#include "new"
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <cstddef>
static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
namespace std // purposefully not using versioning namespace
{
logic_error::~logic_error() _NOEXCEPT {}
const char*
logic_error::what() const _NOEXCEPT
{
return __imp_.c_str();
}
runtime_error::~runtime_error() _NOEXCEPT {}
const char*
runtime_error::what() const _NOEXCEPT
{
return __imp_.c_str();
}
domain_error::~domain_error() _NOEXCEPT {}
invalid_argument::~invalid_argument() _NOEXCEPT {}
length_error::~length_error() _NOEXCEPT {}
out_of_range::~out_of_range() _NOEXCEPT {}
range_error::~range_error() _NOEXCEPT {}
overflow_error::~overflow_error() _NOEXCEPT {}
underflow_error::~underflow_error() _NOEXCEPT {}
} // std

View File

@ -0,0 +1,52 @@
//===----------------------------- typeinfo.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <typeinfo>
namespace std
{
// type_info
type_info::~type_info()
{
}
// bad_cast
bad_cast::bad_cast() _NOEXCEPT
{
}
bad_cast::~bad_cast() _NOEXCEPT
{
}
const char*
bad_cast::what() const _NOEXCEPT
{
return "std::bad_cast";
}
// bad_typeid
bad_typeid::bad_typeid() _NOEXCEPT
{
}
bad_typeid::~bad_typeid() _NOEXCEPT
{
}
const char*
bad_typeid::what() const _NOEXCEPT
{
return "std::bad_typeid";
}
} // std