mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 23:22:44 +00:00
add libc++ and libc++abi sources
upstream: LLVM 10
This commit is contained in:
parent
463b90b977
commit
ed0dbe1a64
95
lib/libcxx/src/algorithm.cpp
Normal file
95
lib/libcxx/src/algorithm.cpp
Normal 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
34
lib/libcxx/src/any.cpp
Normal 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
29
lib/libcxx/src/bind.cpp
Normal 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
160
lib/libcxx/src/charconv.cpp
Normal 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
233
lib/libcxx/src/chrono.cpp
Normal 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
|
93
lib/libcxx/src/condition_variable.cpp
Normal file
93
lib/libcxx/src/condition_variable.cpp
Normal 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
|
46
lib/libcxx/src/condition_variable_destructor.cpp
Normal file
46
lib/libcxx/src/condition_variable_destructor.cpp
Normal 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
578
lib/libcxx/src/debug.cpp
Normal 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
|
35
lib/libcxx/src/exception.cpp
Normal file
35
lib/libcxx/src/exception.cpp
Normal 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
|
161
lib/libcxx/src/experimental/memory_resource.cpp
Normal file
161
lib/libcxx/src/experimental/memory_resource.cpp
Normal 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
|
398
lib/libcxx/src/filesystem/directory_iterator.cpp
Normal file
398
lib/libcxx/src/filesystem/directory_iterator.cpp
Normal 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
|
435
lib/libcxx/src/filesystem/filesystem_common.h
Normal file
435
lib/libcxx/src/filesystem/filesystem_common.h
Normal 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
|
54
lib/libcxx/src/filesystem/int128_builtins.cpp
Normal file
54
lib/libcxx/src/filesystem/int128_builtins.cpp
Normal 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
|
1782
lib/libcxx/src/filesystem/operations.cpp
Normal file
1782
lib/libcxx/src/filesystem/operations.cpp
Normal file
File diff suppressed because it is too large
Load Diff
25
lib/libcxx/src/functional.cpp
Normal file
25
lib/libcxx/src/functional.cpp
Normal 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
277
lib/libcxx/src/future.cpp
Normal 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
561
lib/libcxx/src/hash.cpp
Normal 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
|
51
lib/libcxx/src/include/apple_availability.h
Normal file
51
lib/libcxx/src/include/apple_availability.h
Normal 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
|
176
lib/libcxx/src/include/atomic_support.h
Normal file
176
lib/libcxx/src/include/atomic_support.h
Normal 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
|
41
lib/libcxx/src/include/config_elast.h
Normal file
41
lib/libcxx/src/include/config_elast.h
Normal 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
|
127
lib/libcxx/src/include/refstring.h
Normal file
127
lib/libcxx/src/include/refstring.h
Normal 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
457
lib/libcxx/src/ios.cpp
Normal 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
159
lib/libcxx/src/iostream.cpp
Normal 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
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
237
lib/libcxx/src/memory.cpp
Normal 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
260
lib/libcxx/src/mutex.cpp
Normal 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
|
50
lib/libcxx/src/mutex_destructor.cpp
Normal file
50
lib/libcxx/src/mutex_destructor.cpp
Normal 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
297
lib/libcxx/src/new.cpp
Normal 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
|
41
lib/libcxx/src/optional.cpp
Normal file
41
lib/libcxx/src/optional.cpp
Normal 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
178
lib/libcxx/src/random.cpp
Normal 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
316
lib/libcxx/src/regex.cpp
Normal 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
|
118
lib/libcxx/src/shared_mutex.cpp
Normal file
118
lib/libcxx/src/shared_mutex.cpp
Normal 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
|
19
lib/libcxx/src/stdexcept.cpp
Normal file
19
lib/libcxx/src/stdexcept.cpp
Normal 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
458
lib/libcxx/src/string.cpp
Normal 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
|
335
lib/libcxx/src/strstream.cpp
Normal file
335
lib/libcxx/src/strstream.cpp
Normal 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
|
164
lib/libcxx/src/support/runtime/exception_fallback.ipp
Normal file
164
lib/libcxx/src/support/runtime/exception_fallback.ipp
Normal 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
|
32
lib/libcxx/src/support/runtime/exception_glibcxx.ipp
Normal file
32
lib/libcxx/src/support/runtime/exception_glibcxx.ipp
Normal 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
|
27
lib/libcxx/src/support/runtime/exception_libcxxabi.ipp
Normal file
27
lib/libcxx/src/support/runtime/exception_libcxxabi.ipp
Normal 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
|
25
lib/libcxx/src/support/runtime/exception_libcxxrt.ipp
Normal file
25
lib/libcxx/src/support/runtime/exception_libcxxrt.ipp
Normal 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
|
163
lib/libcxx/src/support/runtime/exception_msvc.ipp
Normal file
163
lib/libcxx/src/support/runtime/exception_msvc.ipp
Normal 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
|
73
lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
Normal file
73
lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
Normal 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
|
77
lib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
Normal file
77
lib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
Normal 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
|
86
lib/libcxx/src/support/runtime/exception_pointer_msvc.ipp
Normal file
86
lib/libcxx/src/support/runtime/exception_pointer_msvc.ipp
Normal 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
|
@ -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
|
26
lib/libcxx/src/support/runtime/new_handler_fallback.ipp
Normal file
26
lib/libcxx/src/support/runtime/new_handler_fallback.ipp
Normal 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
|
64
lib/libcxx/src/support/runtime/stdexcept_default.ipp
Normal file
64
lib/libcxx/src/support/runtime/stdexcept_default.ipp
Normal 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
|
16
lib/libcxx/src/support/runtime/stdexcept_vcruntime.ipp
Normal file
16
lib/libcxx/src/support/runtime/stdexcept_vcruntime.ipp
Normal 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
|
4
lib/libcxx/src/support/solaris/README
Normal file
4
lib/libcxx/src/support/solaris/README
Normal 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.
|
76
lib/libcxx/src/support/solaris/mbsnrtowcs.inc
Normal file
76
lib/libcxx/src/support/solaris/mbsnrtowcs.inc
Normal 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);
|
||||
}
|
92
lib/libcxx/src/support/solaris/wcsnrtombs.inc
Normal file
92
lib/libcxx/src/support/solaris/wcsnrtombs.inc
Normal 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);
|
||||
}
|
68
lib/libcxx/src/support/solaris/xlocale.cpp
Normal file
68
lib/libcxx/src/support/solaris/xlocale.cpp
Normal 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__
|
139
lib/libcxx/src/support/win32/locale_win32.cpp
Normal file
139
lib/libcxx/src/support/win32/locale_win32.cpp
Normal 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
|
164
lib/libcxx/src/support/win32/support.cpp
Normal file
164
lib/libcxx/src/support/win32/support.cpp
Normal 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;
|
||||
}
|
275
lib/libcxx/src/support/win32/thread_win32.cpp
Normal file
275
lib/libcxx/src/support/win32/thread_win32.cpp
Normal 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
|
295
lib/libcxx/src/system_error.cpp
Normal file
295
lib/libcxx/src/system_error.cpp
Normal 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
225
lib/libcxx/src/thread.cpp
Normal 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
|
57
lib/libcxx/src/typeinfo.cpp
Normal file
57
lib/libcxx/src/typeinfo.cpp
Normal 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
|
15
lib/libcxx/src/utility.cpp
Normal file
15
lib/libcxx/src/utility.cpp
Normal 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
|
57
lib/libcxx/src/valarray.cpp
Normal file
57
lib/libcxx/src/valarray.cpp
Normal 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
|
17
lib/libcxx/src/variant.cpp
Normal file
17
lib/libcxx/src/variant.cpp
Normal 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
15
lib/libcxx/src/vector.cpp
Normal 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
311
lib/libcxxabi/LICENSE.TXT
Normal 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.
|
79
lib/libcxxabi/include/__cxxabi_config.h
Normal file
79
lib/libcxxabi/include/__cxxabi_config.h
Normal 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
|
176
lib/libcxxabi/include/cxxabi.h
Normal file
176
lib/libcxxabi/include/cxxabi.h
Normal 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
|
77
lib/libcxxabi/src/abort_message.cpp
Normal file
77
lib/libcxxabi/src/abort_message.cpp
Normal 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();
|
||||
}
|
26
lib/libcxxabi/src/abort_message.h
Normal file
26
lib/libcxxabi/src/abort_message.h
Normal 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
|
||||
|
43
lib/libcxxabi/src/cxa_aux_runtime.cpp
Normal file
43
lib/libcxxabi/src/cxa_aux_runtime.cpp
Normal 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
|
124
lib/libcxxabi/src/cxa_default_handlers.cpp
Normal file
124
lib/libcxxabi/src/cxa_default_handlers.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
366
lib/libcxxabi/src/cxa_demangle.cpp
Normal file
366
lib/libcxxabi/src/cxa_demangle.cpp
Normal 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
|
755
lib/libcxxabi/src/cxa_exception.cpp
Normal file
755
lib/libcxxabi/src/cxa_exception.cpp
Normal 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
|
164
lib/libcxxabi/src/cxa_exception.h
Normal file
164
lib/libcxxabi/src/cxa_exception.h
Normal 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
|
105
lib/libcxxabi/src/cxa_exception_storage.cpp
Normal file
105
lib/libcxxabi/src/cxa_exception_storage.cpp
Normal 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
|
53
lib/libcxxabi/src/cxa_guard.cpp
Normal file
53
lib/libcxxabi/src/cxa_guard.cpp
Normal 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
|
567
lib/libcxxabi/src/cxa_guard_impl.h
Normal file
567
lib/libcxxabi/src/cxa_guard_impl.h
Normal 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
|
111
lib/libcxxabi/src/cxa_handlers.cpp
Normal file
111
lib/libcxxabi/src/cxa_handlers.cpp
Normal 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
|
55
lib/libcxxabi/src/cxa_handlers.h
Normal file
55
lib/libcxxabi/src/cxa_handlers.h
Normal 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
|
59
lib/libcxxabi/src/cxa_noexception.cpp
Normal file
59
lib/libcxxabi/src/cxa_noexception.cpp
Normal 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
|
1324
lib/libcxxabi/src/cxa_personality.cpp
Normal file
1324
lib/libcxxabi/src/cxa_personality.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
lib/libcxxabi/src/cxa_thread_atexit.cpp
Normal file
145
lib/libcxxabi/src/cxa_thread_atexit.cpp
Normal 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
|
22
lib/libcxxabi/src/cxa_unexpected.cpp
Normal file
22
lib/libcxxabi/src/cxa_unexpected.cpp
Normal 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
|
||||
|
421
lib/libcxxabi/src/cxa_vector.cpp
Normal file
421
lib/libcxxabi/src/cxa_vector.cpp
Normal 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
|
24
lib/libcxxabi/src/cxa_virtual.cpp
Normal file
24
lib/libcxxabi/src/cxa_virtual.cpp
Normal 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
|
2
lib/libcxxabi/src/demangle/.clang-format
Normal file
2
lib/libcxxabi/src/demangle/.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
97
lib/libcxxabi/src/demangle/DemangleConfig.h
Normal file
97
lib/libcxxabi/src/demangle/DemangleConfig.h
Normal 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
|
5545
lib/libcxxabi/src/demangle/ItaniumDemangle.h
Normal file
5545
lib/libcxxabi/src/demangle/ItaniumDemangle.h
Normal file
File diff suppressed because it is too large
Load Diff
52
lib/libcxxabi/src/demangle/README.txt
Normal file
52
lib/libcxxabi/src/demangle/README.txt
Normal 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.
|
126
lib/libcxxabi/src/demangle/StringView.h
Normal file
126
lib/libcxxabi/src/demangle/StringView.h
Normal 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
|
191
lib/libcxxabi/src/demangle/Utility.h
Normal file
191
lib/libcxxabi/src/demangle/Utility.h
Normal 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
|
27
lib/libcxxabi/src/demangle/cp-to-llvm.sh
Executable file
27
lib/libcxxabi/src/demangle/cp-to-llvm.sh
Executable 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
|
259
lib/libcxxabi/src/fallback_malloc.cpp
Normal file
259
lib/libcxxabi/src/fallback_malloc.cpp
Normal 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
|
28
lib/libcxxabi/src/fallback_malloc.h
Normal file
28
lib/libcxxabi/src/fallback_malloc.h
Normal 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
|
210
lib/libcxxabi/src/include/atomic_support.h
Normal file
210
lib/libcxxabi/src/include/atomic_support.h
Normal 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
|
131
lib/libcxxabi/src/include/refstring.h
Normal file
131
lib/libcxxabi/src/include/refstring.h
Normal 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
|
1291
lib/libcxxabi/src/private_typeinfo.cpp
Normal file
1291
lib/libcxxabi/src/private_typeinfo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
251
lib/libcxxabi/src/private_typeinfo.h
Normal file
251
lib/libcxxabi/src/private_typeinfo.h
Normal 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_
|
71
lib/libcxxabi/src/stdlib_exception.cpp
Normal file
71
lib/libcxxabi/src/stdlib_exception.cpp
Normal 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
|
262
lib/libcxxabi/src/stdlib_new_delete.cpp
Normal file
262
lib/libcxxabi/src/stdlib_new_delete.cpp
Normal 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
|
47
lib/libcxxabi/src/stdlib_stdexcept.cpp
Normal file
47
lib/libcxxabi/src/stdlib_stdexcept.cpp
Normal 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
|
52
lib/libcxxabi/src/stdlib_typeinfo.cpp
Normal file
52
lib/libcxxabi/src/stdlib_typeinfo.cpp
Normal 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
|
Loading…
Reference in New Issue
Block a user