From aa964bd555bf7d034b5bfea6275d6edddc35cb8c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Jul 2022 16:36:40 -0700 Subject: [PATCH] update libcxxabi to llvm 14.0.6 --- lib/libcxxabi/include/__cxxabi_config.h | 4 +- lib/libcxxabi/include/cxxabi.h | 2 +- lib/libcxxabi/src/abort_message.cpp | 2 +- lib/libcxxabi/src/abort_message.h | 2 +- lib/libcxxabi/src/cxa_aux_runtime.cpp | 2 +- lib/libcxxabi/src/cxa_default_handlers.cpp | 16 +- lib/libcxxabi/src/cxa_demangle.cpp | 14 +- lib/libcxxabi/src/cxa_exception.cpp | 30 +- lib/libcxxabi/src/cxa_exception.h | 2 +- lib/libcxxabi/src/cxa_exception_storage.cpp | 68 +- lib/libcxxabi/src/cxa_guard.cpp | 2 +- lib/libcxxabi/src/cxa_guard_impl.h | 442 +++--- lib/libcxxabi/src/cxa_handlers.cpp | 16 +- lib/libcxxabi/src/cxa_handlers.h | 2 +- lib/libcxxabi/src/cxa_noexception.cpp | 2 +- lib/libcxxabi/src/cxa_personality.cpp | 20 +- lib/libcxxabi/src/cxa_thread_atexit.cpp | 2 +- lib/libcxxabi/src/cxa_vector.cpp | 2 +- lib/libcxxabi/src/cxa_virtual.cpp | 2 +- lib/libcxxabi/src/demangle/ItaniumDemangle.h | 1450 +++++++++--------- lib/libcxxabi/src/demangle/StringView.h | 17 +- lib/libcxxabi/src/demangle/Utility.h | 65 +- lib/libcxxabi/src/fallback_malloc.cpp | 2 +- lib/libcxxabi/src/fallback_malloc.h | 2 +- lib/libcxxabi/src/include/atomic_support.h | 180 --- lib/libcxxabi/src/private_typeinfo.cpp | 2 +- lib/libcxxabi/src/private_typeinfo.h | 2 +- lib/libcxxabi/src/stdlib_exception.cpp | 2 +- lib/libcxxabi/src/stdlib_new_delete.cpp | 2 +- lib/libcxxabi/src/stdlib_stdexcept.cpp | 6 +- lib/libcxxabi/src/stdlib_typeinfo.cpp | 2 +- 31 files changed, 1174 insertions(+), 1190 deletions(-) delete mode 100644 lib/libcxxabi/src/include/atomic_support.h diff --git a/lib/libcxxabi/include/__cxxabi_config.h b/lib/libcxxabi/include/__cxxabi_config.h index cffedb88df..7bc39ada8d 100644 --- a/lib/libcxxabi/include/__cxxabi_config.h +++ b/lib/libcxxabi/include/__cxxabi_config.h @@ -1,4 +1,4 @@ -//===-------------------------- __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. @@ -93,7 +93,7 @@ # if !__has_feature(cxx_exceptions) # define _LIBCXXABI_NO_EXCEPTIONS # endif -#elif defined(_LIBCXXABI_COMPILER_GCC) && !__EXCEPTIONS +#elif defined(_LIBCXXABI_COMPILER_GCC) && !defined(__EXCEPTIONS) # define _LIBCXXABI_NO_EXCEPTIONS #endif diff --git a/lib/libcxxabi/include/cxxabi.h b/lib/libcxxabi/include/cxxabi.h index 43ce6f5f74..eaa324dc68 100644 --- a/lib/libcxxabi/include/cxxabi.h +++ b/lib/libcxxabi/include/cxxabi.h @@ -1,4 +1,4 @@ -//===--------------------------- 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. diff --git a/lib/libcxxabi/src/abort_message.cpp b/lib/libcxxabi/src/abort_message.cpp index ad44063fac..859a5031b9 100644 --- a/lib/libcxxabi/src/abort_message.cpp +++ b/lib/libcxxabi/src/abort_message.cpp @@ -1,4 +1,4 @@ -//===------------------------- 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. diff --git a/lib/libcxxabi/src/abort_message.h b/lib/libcxxabi/src/abort_message.h index 83f956f74f..f1d5c12e25 100644 --- a/lib/libcxxabi/src/abort_message.h +++ b/lib/libcxxabi/src/abort_message.h @@ -1,4 +1,4 @@ -//===-------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp index 0ed1a72279..a42990c7ef 100644 --- a/lib/libcxxabi/src/cxa_aux_runtime.cpp +++ b/lib/libcxxabi/src/cxa_aux_runtime.cpp @@ -1,4 +1,4 @@ -//===------------------------ 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. diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp index c059a653d4..e0ccbe1195 100644 --- a/lib/libcxxabi/src/cxa_default_handlers.cpp +++ b/lib/libcxxabi/src/cxa_default_handlers.cpp @@ -1,11 +1,12 @@ -//===------------------------- 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. +// This file implements the default terminate_handler, unexpected_handler and +// new_handler. //===----------------------------------------------------------------------===// #include @@ -15,7 +16,7 @@ #include "cxa_handlers.h" #include "cxa_exception.h" #include "private_typeinfo.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ #if !defined(LIBCXXABI_SILENT_TERMINATE) @@ -104,6 +105,9 @@ _LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_ter _LIBCXXABI_DATA_VIS _LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; +_LIBCXXABI_DATA_VIS +_LIBCPP_SAFE_STATIC std::new_handler __cxa_new_handler = 0; + namespace std { @@ -125,4 +129,10 @@ set_terminate(terminate_handler func) noexcept _AO_Acq_Rel); } +new_handler +set_new_handler(new_handler handler) noexcept +{ + return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); +} + } diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp index 3045f6edb3..bee4cfd5a1 100644 --- a/lib/libcxxabi/src/cxa_demangle.cpp +++ b/lib/libcxxabi/src/cxa_demangle.cpp @@ -1,4 +1,4 @@ -//===-------------------------- 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. @@ -342,21 +342,21 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { int InternalStatus = demangle_success; Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; + OutputBuffer O; Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, O, 1024)) InternalStatus = demangle_memory_alloc_failure; else { assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; + AST->print(O); + O += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = O.getCurrentPosition(); + Buf = O.getBuffer(); } if (Status) diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp index 510827a37b..36388d50da 100644 --- a/lib/libcxxabi/src/cxa_exception.cpp +++ b/lib/libcxxabi/src/cxa_exception.cpp @@ -1,4 +1,4 @@ -//===------------------------- 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. @@ -17,7 +17,7 @@ #include "cxa_exception.h" #include "cxa_handlers.h" #include "fallback_malloc.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ #if __has_feature(address_sanitizer) #include @@ -341,8 +341,10 @@ 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. +first argument to _Unwind_Resume(). In addition, we are saving lr in order to +align the stack to 16 bytes and lr will be used to identify the caller and its +frame information. _Unwind_Resume never return and we need to keep the original +lr so just branch to it. */ __attribute__((used)) static _Unwind_Exception * __cxa_end_cleanup_impl() @@ -372,18 +374,24 @@ __cxa_end_cleanup_impl() return &exception_header->unwindHeader; } -asm ( - " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" +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" +#if defined(__ARM_FEATURE_BTI_DEFAULT) + " bti\n" +#endif + " push {r1, r2, r3, lr}\n" " bl __cxa_end_cleanup_impl\n" " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); + " mov lr, r4\n" +#if defined(LIBCXXABI_BAREMETAL) + " ldr r4, =_Unwind_Resume\n" + " bx r4\n" +#else + " b _Unwind_Resume\n" +#endif + " .popsection"); #endif // defined(_LIBCXXABI_ARM_EHABI) /* diff --git a/lib/libcxxabi/src/cxa_exception.h b/lib/libcxxabi/src/cxa_exception.h index 601be4e404..7a32fb653b 100644 --- a/lib/libcxxabi/src/cxa_exception.h +++ b/lib/libcxxabi/src/cxa_exception.h @@ -1,4 +1,4 @@ -//===------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_exception_storage.cpp b/lib/libcxxabi/src/cxa_exception_storage.cpp index 24ff55e39d..3a3233a1b9 100644 --- a/lib/libcxxabi/src/cxa_exception_storage.cpp +++ b/lib/libcxxabi/src/cxa_exception_storage.cpp @@ -1,4 +1,4 @@ -//===--------------------- 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. @@ -21,25 +21,24 @@ 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; } - } -} +} // extern "C" +} // namespace __cxxabiv1 #elif defined(HAS_THREAD_LOCAL) namespace __cxxabiv1 { - namespace { - __cxa_eh_globals * __globals () { + __cxa_eh_globals *__globals() { static thread_local __cxa_eh_globals eh_globals; return &eh_globals; - } } +} // namespace extern "C" { - __cxa_eh_globals * __cxa_get_globals () { return __globals (); } - __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } - } -} + __cxa_eh_globals *__cxa_get_globals() { return __globals(); } + __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } +} // extern "C" +} // namespace __cxxabiv1 #else @@ -59,47 +58,46 @@ 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 ) ) + 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_ ) ) + void construct_() { + if (0 != std::__libcpp_tls_create(&key_, destruct_)) abort_message("cannot create thread specific key for __cxa_get_globals()"); - } -} + } +} // namespace extern "C" { - __cxa_eh_globals * __cxa_get_globals () { - // Try to get the globals for this thread - __cxa_eh_globals* retVal = __cxa_get_globals_fast (); + __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 ) + // 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 ) ) + if (0 != std::__libcpp_tls_set(key_, retVal)) abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); - } - return retVal; } + 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. + __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_)); - } + } +} // extern "C" +} // namespace __cxxabiv1 -} -} #endif diff --git a/lib/libcxxabi/src/cxa_guard.cpp b/lib/libcxxabi/src/cxa_guard.cpp index 5d1cf235cc..fc1fa90511 100644 --- a/lib/libcxxabi/src/cxa_guard.cpp +++ b/lib/libcxxabi/src/cxa_guard.cpp @@ -1,4 +1,4 @@ -//===---------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_guard_impl.h b/lib/libcxxabi/src/cxa_guard_impl.h index 6f873f241f..5a7cbfd5cd 100644 --- a/lib/libcxxabi/src/cxa_guard_impl.h +++ b/lib/libcxxabi/src/cxa_guard_impl.h @@ -23,9 +23,15 @@ * 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 ... | - * ------------------------------------------------------------------------ + * --------------------------------------------------------------------------- + * | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... | + * --------------------------------------------------------------------------- + * + * Note that we don't do what the ABI docs suggest (put a mutex in the guard + * object which we acquire in cxa_guard_acquire and release in + * cxa_guard_release). Instead we use the init byte to imitate that behaviour, + * but without actually holding anything mutex related between aquire and + * release/abort. * * Access Protocol: * For each implementation the guard byte is checked and set before accessing @@ -38,28 +44,31 @@ */ #include "__cxxabi_config.h" -#include "include/atomic_support.h" -#include +#include "include/atomic_support.h" // from libc++ #if defined(__has_include) -# if __has_include() -# include -# endif +# if __has_include() +# include +# endif +# if __has_include() +# include +# endif #endif +#include #include #include <__threading_support> #ifndef _LIBCXXABI_HAS_NO_THREADS -#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) -#pragma comment(lib, "pthread") -#endif +# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) +# pragma comment(lib, "pthread") +# endif #endif #if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtautological-pointer-compare" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wtautological-pointer-compare" #elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Waddress" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Waddress" #endif // To make testing possible, this header is included from both cxa_guard.cpp @@ -74,20 +83,20 @@ // 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__) +# include "abort_message.h" +# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__) #elif defined(TESTING_CXA_GUARD) -# define ABORT_WITH_MESSAGE(...) ::abort() +# define ABORT_WITH_MESSAGE(...) ::abort() #else -# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined" +# 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) +# define __tsan_acquire(addr) ((void)0) +# define __tsan_release(addr) ((void)0) #endif namespace __cxxabiv1 { @@ -99,7 +108,7 @@ namespace { // Misc Utilities //===----------------------------------------------------------------------===// -template +template struct LazyValue { LazyValue() : is_init(false) {} @@ -110,7 +119,8 @@ struct LazyValue { } return value; } - private: + +private: T value; bool is_init = false; }; @@ -120,25 +130,19 @@ class AtomicInt { public: using MemoryOrder = std::__libcpp_atomic_order; - explicit AtomicInt(IntType *b) : b_(b) {} + 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) { + 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_; + IntType* b_; }; //===----------------------------------------------------------------------===// @@ -148,8 +152,7 @@ private: #if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) uint32_t PlatformThreadID() { static_assert(sizeof(mach_port_t) == sizeof(uint32_t), ""); - return static_cast( - pthread_mach_thread_np(std::__libcpp_thread_get_current_id())); + return static_cast(pthread_mach_thread_np(std::__libcpp_thread_get_current_id())); } #elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) uint32_t PlatformThreadID() { @@ -160,99 +163,108 @@ uint32_t PlatformThreadID() { constexpr uint32_t (*PlatformThreadID)() = nullptr; #endif - -constexpr bool PlatformSupportsThreadID() { - return +PlatformThreadID != nullptr; -} - //===----------------------------------------------------------------------===// -// GuardBase +// GuardByte //===----------------------------------------------------------------------===// -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 -struct GuardObject { - GuardObject() = delete; - GuardObject(GuardObject const&) = delete; - GuardObject& operator=(GuardObject const&) = delete; +/// Manages reads and writes to the guard byte. +struct GuardByte { + GuardByte() = delete; + GuardByte(GuardByte const&) = delete; + GuardByte& operator=(GuardByte const&) = delete; - explicit GuardObject(uint32_t* g) - : base_address(g), guard_byte_address(reinterpret_cast(g)), - init_byte_address(reinterpret_cast(g) + 1), - thread_id_address(nullptr) {} - - explicit GuardObject(uint64_t* g) - : base_address(g), guard_byte_address(reinterpret_cast(g)), - init_byte_address(reinterpret_cast(g) + 1), - thread_id_address(reinterpret_cast(g) + 1) {} + explicit GuardByte(uint8_t* const guard_byte_address) : guard_byte(guard_byte_address) {} public: - /// Implements __cxa_guard_acquire - AcquireResult cxa_guard_acquire() { - AtomicInt guard_byte(guard_byte_address); - if (guard_byte.load(std::_AO_Acquire) != UNSET) - return INIT_IS_DONE; - return derived()->acquire_init_byte(); + /// The guard byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { + // if guard_byte is non-zero, we have already completed initialization + // (i.e. release has been called) + return guard_byte.load(std::_AO_Acquire) != UNSET; } - /// Implements __cxa_guard_release - void cxa_guard_release() { - AtomicInt 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(); - } + /// The guard byte portion of cxa_guard_release. + void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); } - /// 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 guard 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; + /// The guard byte portion of cxa_guard_abort. + void abort() {} // Nothing to do private: - Derived* derived() { return static_cast(this); } + AtomicInt guard_byte; }; +//===----------------------------------------------------------------------===// +// InitByte Implementations +//===----------------------------------------------------------------------===// +// +// Each initialization byte implementation supports the following methods: +// +// InitByte(uint8_t* _init_byte_address, uint32_t* _thread_id_address) +// Construct the InitByte object, initializing our member variables +// +// bool acquire() +// Called before we start the initialization. Check if someone else has already started, and if +// not to signal our intent to start it ourselves. We determine the current status from the init +// byte, which is one of 4 possible values: +// COMPLETE: Initialization was finished by somebody else. Return true. +// PENDING: Somebody has started the initialization already, set the WAITING bit, +// then wait for the init byte to get updated with a new value. +// (PENDING|WAITING): Somebody has started the initialization already, and we're not the +// first one waiting. Wait for the init byte to get updated. +// UNSET: Initialization hasn't successfully completed, and nobody is currently +// performing the initialization. Set the PENDING bit to indicate our +// intention to start the initialization, and return false. +// The return value indicates whether initialization has already been completed. +// +// void release() +// Called after successfully completing the initialization. Update the init byte to reflect +// that, then if anybody else is waiting, wake them up. +// +// void abort() +// Called after an error is thrown during the initialization. Reset the init byte to UNSET to +// indicate that we're no longer performing the initialization, then if anybody is waiting, wake +// them up so they can try performing the initialization. +// + //===----------------------------------------------------------------------===// // Single Threaded Implementation //===----------------------------------------------------------------------===// -struct InitByteNoThreads : GuardObject { - using GuardObject::GuardObject; +/// InitByteNoThreads - Doesn't use any inter-thread synchronization when +/// managing reads and writes to the init byte. +struct InitByteNoThreads { + InitByteNoThreads() = delete; + InitByteNoThreads(InitByteNoThreads const&) = delete; + InitByteNoThreads& operator=(InitByteNoThreads const&) = delete; - AcquireResult acquire_init_byte() { + explicit InitByteNoThreads(uint8_t* _init_byte_address, uint32_t*) : init_byte_address(_init_byte_address) {} + + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { if (*init_byte_address == COMPLETE_BIT) - return INIT_IS_DONE; + return true; if (*init_byte_address & PENDING_BIT) ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); *init_byte_address = PENDING_BIT; - return INIT_IS_PENDING; + return false; } - void release_init_byte() { *init_byte_address = COMPLETE_BIT; } - void abort_init_byte() { *init_byte_address = UNSET; } -}; + /// The init byte portion of cxa_guard_release. + void release() { *init_byte_address = COMPLETE_BIT; } + /// The init byte portion of cxa_guard_abort. + void abort() { *init_byte_address = UNSET; } +private: + /// The address of the byte used during initialization. + uint8_t* const init_byte_address; +}; //===----------------------------------------------------------------------===// // Global Mutex Implementation @@ -280,9 +292,7 @@ struct LibcppCondVar { LibcppCondVar(LibcppCondVar const&) = delete; LibcppCondVar& operator=(LibcppCondVar const&) = delete; - bool wait(LibcppMutex& mut) { - return std::__libcpp_condvar_wait(&cond, &mut.mutex); - } + bool wait(LibcppMutex& mut) { return std::__libcpp_condvar_wait(&cond, &mut.mutex); } bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); } private: @@ -293,28 +303,25 @@ struct LibcppMutex {}; struct LibcppCondVar {}; #endif // !defined(_LIBCXXABI_HAS_NO_THREADS) - +/// InitByteGlobalMutex - Uses a global mutex and condition variable (common to +/// all static local variables) to manage reads and writes to the init byte. template -struct InitByteGlobalMutex - : GuardObject> { +struct InitByteGlobalMutex { - 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()) {} + explicit InitByteGlobalMutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address) + : init_byte_address(_init_byte_address), thread_id_address(_thread_id_address), + has_thread_id_support(_thread_id_address != nullptr && GetThreadID != nullptr) {} public: - AcquireResult acquire_init_byte() { + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { 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"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); } // Wait until the pending bit is not set. @@ -324,16 +331,17 @@ public: } if (*init_byte_address == COMPLETE_BIT) - return INIT_IS_DONE; + return true; if (has_thread_id_support) *thread_id_address = current_thread_id.get(); *init_byte_address = PENDING_BIT; - return INIT_IS_PENDING; + return false; } - void release_init_byte() { + /// The init byte portion of cxa_guard_release. + void release() { bool has_waiting; { LockGuard g("__cxa_guard_release"); @@ -347,7 +355,8 @@ public: } } - void abort_init_byte() { + /// The init byte portion of cxa_guard_abort. + void abort() { bool has_waiting; { LockGuard g("__cxa_guard_abort"); @@ -364,8 +373,12 @@ public: } private: - using BaseT::init_byte_address; - using BaseT::thread_id_address; + /// The address of the byte used 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; + const bool has_thread_id_support; LazyValue current_thread_id; @@ -375,8 +388,7 @@ private: LockGuard(LockGuard const&) = delete; LockGuard& operator=(LockGuard const&) = delete; - explicit LockGuard(const char* calling_func) - : calling_func_(calling_func) { + explicit LockGuard(const char* calling_func) : calling_func_(calling_func) { if (global_mutex.lock()) ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func_); } @@ -411,50 +423,40 @@ constexpr void (*PlatformFutexWait)(int*, int) = nullptr; constexpr void (*PlatformFutexWake)(int*) = nullptr; #endif -constexpr bool PlatformSupportsFutex() { - return +PlatformFutexWait != nullptr; -} +constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; } -/// InitByteFutex - Manages initialization using atomics and the futex syscall -/// for waiting and waking. -template -struct InitByteFutex : GuardObject> { - using BaseT = typename InitByteFutex::GuardObject; +struct InitByteFutex { - /// 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) {} + explicit InitByteFutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address) + : init_byte(_init_byte_address), + has_thread_id_support(_thread_id_address != nullptr && GetThreadIDArg != nullptr), + thread_id(_thread_id_address), + base_address(reinterpret_cast(/*_init_byte_address & ~0x3*/ _init_byte_address - 1)) {} public: - AcquireResult acquire_init_byte() { + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { while (true) { uint8_t last_val = UNSET; - if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, - std::_AO_Acquire)) { + 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; + return false; } if (last_val == COMPLETE_BIT) - return INIT_IS_DONE; + return true; 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"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); } if ((last_val & WAITING_BIT) == 0) { @@ -462,11 +464,10 @@ public: // (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)) { + 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; + return true; // (3) someone else, bailed on doing the work, retry from the start! if (last_val == UNSET) @@ -480,30 +481,30 @@ public: } } - void release_init_byte() { + /// The init byte portion of cxa_guard_release. + void release() { uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel); if (old & WAITING_BIT) wake_all(); } - void abort_init_byte() { + /// The init byte portion of cxa_guard_abort. + void abort() { if (has_thread_id_support) thread_id.store(0, std::_AO_Relaxed); - uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel); + uint8_t old = init_byte.exchange(UNSET, 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(this->base_address), - expected_value_for_futex(PENDING_BIT | WAITING_BIT)); - } - void wake_all() { Wake(static_cast(this->base_address)); } + /// 32-bit 4-byte aligned address as the first argument, so we use the 4-byte + /// aligned address that encompasses the init byte (i.e. the address of the + /// raw guard object that was passed to __cxa_guard_acquire/release/abort). + void wait_on_initialization() { Wait(base_address, expected_value_for_futex(PENDING_BIT | WAITING_BIT)); } + void wake_all() { Wake(base_address); } private: AtomicInt init_byte; @@ -513,6 +514,10 @@ private: AtomicInt thread_id; LazyValue current_thread_id; + /// the 4-byte-aligned address that encompasses the init byte (i.e. the + /// address of the raw guard object). + int* const base_address; + /// 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. @@ -525,6 +530,86 @@ private: static_assert(Wait != nullptr && Wake != nullptr, ""); }; +//===----------------------------------------------------------------------===// +// GuardObject +//===----------------------------------------------------------------------===// + +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; + +/// Co-ordinates between GuardByte and InitByte. +template +struct GuardObject { + GuardObject() = delete; + GuardObject(GuardObject const&) = delete; + GuardObject& operator=(GuardObject const&) = delete; + +private: + GuardByte guard_byte; + InitByteT init_byte; + +public: + /// ARM Constructor + explicit GuardObject(uint32_t* raw_guard_object) + : guard_byte(reinterpret_cast(raw_guard_object)), + init_byte(reinterpret_cast(raw_guard_object) + 1, nullptr) {} + + /// Itanium Constructor + explicit GuardObject(uint64_t* raw_guard_object) + : guard_byte(reinterpret_cast(raw_guard_object)), + init_byte(reinterpret_cast(raw_guard_object) + 1, reinterpret_cast(raw_guard_object) + 1) { + } + + /// Implements __cxa_guard_acquire. + AcquireResult cxa_guard_acquire() { + // Use short-circuit evaluation to avoid calling init_byte.acquire when + // guard_byte.acquire returns true. (i.e. don't call it when we know from + // the guard byte that initialization has already been completed) + if (guard_byte.acquire() || init_byte.acquire()) + return INIT_IS_DONE; + return INIT_IS_PENDING; + } + + /// Implements __cxa_guard_release. + void cxa_guard_release() { + // Update guard byte first, so if somebody is woken up by init_byte.release + // and comes all the way back around to __cxa_guard_acquire again, they see + // it as having completed initialization. + guard_byte.release(); + init_byte.release(); + } + + /// Implements __cxa_guard_abort. + void cxa_guard_abort() { + guard_byte.abort(); + init_byte.abort(); + } +}; + +//===----------------------------------------------------------------------===// +// Convenience Classes +//===----------------------------------------------------------------------===// + +/// NoThreadsGuard - Manages initialization without performing any inter-thread +/// synchronization. +using NoThreadsGuard = GuardObject; + +/// GlobalMutexGuard - Manages initialization using a global mutex and +/// condition variable. +template +using GlobalMutexGuard = GuardObject>; + +/// FutexGuard - Manages initialization using atomics and the futex syscall for +/// waiting and waking. +template +using FutexGuard = GuardObject>; + //===----------------------------------------------------------------------===// // //===----------------------------------------------------------------------===// @@ -536,31 +621,25 @@ struct GlobalStatic { template _LIBCPP_SAFE_STATIC T GlobalStatic::instance = {}; -enum class Implementation { - NoThreads, - GlobalLock, - Futex -}; +enum class Implementation { NoThreads, GlobalMutex, Futex }; template struct SelectImplementation; template <> struct SelectImplementation { - using type = InitByteNoThreads; + using type = NoThreadsGuard; }; template <> -struct SelectImplementation { - using type = InitByteGlobalMutex< - LibcppMutex, LibcppCondVar, GlobalStatic::instance, - GlobalStatic::instance, PlatformThreadID>; +struct SelectImplementation { + using type = GlobalMutexGuard::instance, + GlobalStatic::instance, PlatformThreadID>; }; template <> struct SelectImplementation { - using type = - InitByteFutex; + using type = FutexGuard; }; // TODO(EricWF): We should prefer the futex implementation when available. But @@ -571,22 +650,21 @@ constexpr Implementation CurrentImplementation = #elif defined(_LIBCXXABI_USE_FUTEX) Implementation::Futex; #else - Implementation::GlobalLock; + Implementation::GlobalMutex; #endif -static_assert(CurrentImplementation != Implementation::Futex - || PlatformSupportsFutex(), "Futex selected but not supported"); +static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(), + "Futex selected but not supported"); -using SelectedImplementation = - SelectImplementation::type; +using SelectedImplementation = SelectImplementation::type; } // end namespace } // end namespace __cxxabiv1 #if defined(__clang__) -# pragma clang diagnostic pop +# pragma clang diagnostic pop #elif defined(__GNUC__) -# pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp index bcaf4f1f6f..344250dde0 100644 --- a/lib/libcxxabi/src/cxa_handlers.cpp +++ b/lib/libcxxabi/src/cxa_handlers.cpp @@ -1,4 +1,4 @@ -//===------------------------- 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. @@ -6,7 +6,7 @@ // // // This file implements the functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. +// unexpected_handler, and new_handler. //===----------------------------------------------------------------------===// #include @@ -17,7 +17,7 @@ #include "cxa_handlers.h" #include "cxa_exception.h" #include "private_typeinfo.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ namespace std { @@ -92,16 +92,6 @@ terminate() noexcept __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 { diff --git a/lib/libcxxabi/src/cxa_handlers.h b/lib/libcxxabi/src/cxa_handlers.h index da113b82db..3d8dc6b2de 100644 --- a/lib/libcxxabi/src/cxa_handlers.h +++ b/lib/libcxxabi/src/cxa_handlers.h @@ -1,4 +1,4 @@ -//===------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_noexception.cpp b/lib/libcxxabi/src/cxa_noexception.cpp index 73e0b2ae03..4a803f72e1 100644 --- a/lib/libcxxabi/src/cxa_noexception.cpp +++ b/lib/libcxxabi/src/cxa_noexception.cpp @@ -1,4 +1,4 @@ -//===------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp index 91b584eb8c..f6e135f137 100644 --- a/lib/libcxxabi/src/cxa_personality.cpp +++ b/lib/libcxxabi/src/cxa_personality.cpp @@ -1,4 +1,4 @@ -//===------------------------- 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. @@ -1004,9 +1004,14 @@ extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, _Unwind_Context* context) { - if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK) - return _URC_FAILURE; + switch (__gnu_unwind_frame(unwind_exception, context)) { + case _URC_OK: return _URC_CONTINUE_UNWIND; + case _URC_END_OF_STACK: + return _URC_END_OF_STACK; + default: + return _URC_FAILURE; + } } // ARM register names @@ -1109,7 +1114,14 @@ __gxx_personality_v0(_Unwind_State state, // Either we didn't do a phase 1 search (due to forced unwinding), or // phase 1 reported no catching-handlers. // Search for a (non-catching) cleanup - scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context); + if (is_force_unwinding) + scan_eh_tab( + results, + static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND), + native_exception, unwind_exception, context); + else + scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, + unwind_exception, context); if (results.reason == _URC_HANDLER_FOUND) { // Found a non-catching handler diff --git a/lib/libcxxabi/src/cxa_thread_atexit.cpp b/lib/libcxxabi/src/cxa_thread_atexit.cpp index a940eaf2f9..665f9e5569 100644 --- a/lib/libcxxabi/src/cxa_thread_atexit.cpp +++ b/lib/libcxxabi/src/cxa_thread_atexit.cpp @@ -1,4 +1,4 @@ -//===----------------------- 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. diff --git a/lib/libcxxabi/src/cxa_vector.cpp b/lib/libcxxabi/src/cxa_vector.cpp index 325bbf22d2..099f9f0c1e 100644 --- a/lib/libcxxabi/src/cxa_vector.cpp +++ b/lib/libcxxabi/src/cxa_vector.cpp @@ -1,4 +1,4 @@ -//===-------------------------- 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. diff --git a/lib/libcxxabi/src/cxa_virtual.cpp b/lib/libcxxabi/src/cxa_virtual.cpp index 9214c1f3e2..c868672e00 100644 --- a/lib/libcxxabi/src/cxa_virtual.cpp +++ b/lib/libcxxabi/src/cxa_virtual.cpp @@ -1,4 +1,4 @@ -//===-------------------------- 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. diff --git a/lib/libcxxabi/src/demangle/ItaniumDemangle.h b/lib/libcxxabi/src/demangle/ItaniumDemangle.h index 36d5d1adec..db65c60e7e 100644 --- a/lib/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/lib/libcxxabi/src/demangle/ItaniumDemangle.h @@ -6,8 +6,10 @@ // //===----------------------------------------------------------------------===// // -// Generic itanium demangler library. This file has two byte-per-byte identical -// copies in the source tree, one in libcxxabi, and the other in llvm. +// Generic itanium demangler library. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// @@ -21,12 +23,13 @@ #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include #include #include #include #include #include -#include +#include #include #define FOR_EACH_NODE_KIND(X) \ @@ -57,6 +60,7 @@ X(LocalName) \ X(VectorType) \ X(PixelVectorType) \ + X(BinaryFPType) \ X(SyntheticTemplateParamName) \ X(TypeTemplateParamDecl) \ X(NonTypeTemplateParamDecl) \ @@ -109,6 +113,126 @@ DEMANGLE_NAMESPACE_BEGIN +template class PODSmallVector { + static_assert(std::is_pod::value, + "T is required to be a plain old data type"); + + T *First = nullptr; + T *Last = nullptr; + T *Cap = nullptr; + T Inline[N] = {0}; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto *Tmp = static_cast(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector &) = delete; + PODSmallVector &operator=(const PODSmallVector &) = delete; + + PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector &operator=(PODSmallVector &&Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void push_back(const T &Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T *begin() { return First; } + T *end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast(Last - First); } + T &back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T &operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + // Base class of all AST nodes. The AST is built by the parser, then is // traversed by the printLeft/Right functions to produce a demangled string. class Node { @@ -155,50 +279,48 @@ public: // would construct an equivalent node. //template void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } + virtual bool hasArraySlow(OutputBuffer &) const { return false; } + virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } + virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } - void print(OutputStream &S) const { - printLeft(S); + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // Print the "left" side of this Node into OutputBuffer. + virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. - virtual void printRight(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -227,19 +349,19 @@ public: Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + OB += ", "; + size_t AfterComma = OB.getCurrentPosition(); + Elements[Idx]->print(OB); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -254,9 +376,7 @@ struct NodeArrayNode : Node { template void match(Fn F) const { F(Array); } - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } + void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { @@ -269,11 +389,11 @@ public: template void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + void printLeft(OutputBuffer &OB) const override { + Prefix->print(OB); + OB += " ("; + OB += Suffix; + OB += ")"; } }; @@ -288,12 +408,12 @@ public: template void match(Fn F) const { F(Ty, Ext, TA); } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += " "; + OB += Ext; if (TA != nullptr) - TA->print(S); + TA->print(OB); } }; @@ -319,13 +439,13 @@ protected: const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -336,22 +456,22 @@ public: template void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -363,9 +483,9 @@ public: template void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; @@ -379,9 +499,9 @@ public: template void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; @@ -396,7 +516,7 @@ public: StringView getName() const { return Name; } StringView getBaseName() const override { return Name; } - void printLeft(OutputStream &s) const override { s += Name; } + void printLeft(OutputBuffer &OB) const override { OB += Name; } }; class ElaboratedTypeSpefType : public Node { @@ -408,10 +528,10 @@ public: template void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; @@ -426,11 +546,11 @@ struct AbiTagAttr : Node { template void match(Fn F) const { F(Base, Tag); } - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Base->printLeft(OB); + OB += "[abi:"; + OB += Tag; + OB += "]"; } }; @@ -442,10 +562,10 @@ public: template void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; @@ -466,11 +586,11 @@ public: static_cast(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -484,34 +604,34 @@ public: template void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -531,15 +651,30 @@ class ReferenceType : public Node { // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any // other combination collapses to a lvalue ref. - std::pair collapse(OutputStream &S) const { + // + // A combination of a TemplateForwardReference and a back-ref Substitution + // from an ill-formed string may have created a cycle; use cycle detection to + // avoid looping forever. + std::pair collapse(OutputBuffer &OB) const { auto SoFar = std::make_pair(RK, Pointee); + // Track the chain of nodes for the Floyd's 'tortoise and hare' + // cycle-detection algorithm, since getSyntaxNode(S) is impure + PODSmallVector Prev; for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); + const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast(SN); SoFar.second = RT->Pointee; SoFar.first = std::min(SoFar.first, RT->RK); + + // The middle of Prev is the 'slow' pointer moving at half speed + Prev.push_back(SoFar.second); + if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { + // Cycle detected + SoFar.second = nullptr; + break; + } } return SoFar; } @@ -551,31 +686,35 @@ public: template void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + Collapsed.second->printLeft(OB); + if (Collapsed.second->hasArray(OB)) + OB += " "; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -590,24 +729,24 @@ public: template void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; + OB += " "; + ClassType->print(OB); + OB += "::*"; } - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; @@ -624,19 +763,19 @@ public: template void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; if (Dimension) - Dimension->print(S); - S += "]"; - Base->printRight(S); + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -660,8 +799,8 @@ public: F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: @@ -670,32 +809,32 @@ public: // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -707,10 +846,10 @@ public: template void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept("; + E->print(OB); + OB += ")"; } }; @@ -722,10 +861,10 @@ public: template void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw("; + Types.printWithComma(OB); + OB += ')'; } }; @@ -756,41 +895,41 @@ public: NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -803,9 +942,9 @@ public: template void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; @@ -819,9 +958,9 @@ public: template void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -836,11 +975,11 @@ public: template void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -855,10 +994,10 @@ struct NestedName : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qual->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -871,10 +1010,10 @@ struct LocalName : Node { template void match(Fn F) const { F(Encoding, Entity); } - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); + void printLeft(OutputBuffer &OB) const override { + Encoding->print(OB); + OB += "::"; + Entity->print(OB); } }; @@ -891,10 +1030,10 @@ public: StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -909,12 +1048,12 @@ public: template void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; if (Dimension) - Dimension->print(S); - S += "]"; + Dimension->print(OB); + OB += "]"; } }; @@ -927,11 +1066,26 @@ public: template void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - Dimension->print(S); - S += "]"; + OB += "pixel vector["; + Dimension->print(OB); + OB += "]"; + } +}; + +class BinaryFPType final : public Node { + const Node *Dimension; + +public: + BinaryFPType(const Node *Dimension_) + : Node(KBinaryFPType), Dimension(Dimension_) {} + + template void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -953,20 +1107,20 @@ public: template void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -980,13 +1134,9 @@ public: template void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -1000,15 +1150,15 @@ public: template void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1025,15 +1175,13 @@ public: template void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1046,14 +1194,12 @@ public: template void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1067,11 +1213,12 @@ public: class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits::max()) { - S.CurrentPackMax = static_cast(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits::max()) { + OB.CurrentPackMax = static_cast(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1094,38 +1241,38 @@ public: template void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + const Node *getSyntaxNode(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1144,8 +1291,8 @@ public: NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1162,35 +1309,35 @@ public: const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + SwapAndRestore SavePackIdx(OB.CurrentPackIndex, Max); + SwapAndRestore SavePackMax(OB.CurrentPackMax, Max); + size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. - Child->print(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1205,12 +1352,12 @@ public: NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + OB += "<"; + Params.printWithComma(OB); + if (OB.back() == '>') + OB += " "; + OB += ">"; } }; @@ -1252,42 +1399,42 @@ struct ForwardTemplateReference : Node { // special handling. template void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); + Ref->printRight(OB); } }; @@ -1303,9 +1450,9 @@ struct NameWithTemplateArgs : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + TemplateArgs->print(OB); } }; @@ -1320,9 +1467,9 @@ public: StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1335,9 +1482,9 @@ struct StdQualifiedName : Node { StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "std::"; + Child->print(OB); } }; @@ -1377,26 +1524,26 @@ public: DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; + OB += "std::basic_string, " + "std::allocator >"; break; case SpecialSubKind::istream: - S += "std::basic_istream >"; + OB += "std::basic_istream >"; break; case SpecialSubKind::ostream: - S += "std::basic_ostream >"; + OB += "std::basic_ostream >"; break; case SpecialSubKind::iostream: - S += "std::basic_iostream >"; + OB += "std::basic_iostream >"; break; } } @@ -1429,25 +1576,25 @@ public: DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::string"; + OB += "std::string"; break; case SpecialSubKind::istream: - S += "std::istream"; + OB += "std::istream"; break; case SpecialSubKind::ostream: - S += "std::ostream"; + OB += "std::ostream"; break; case SpecialSubKind::iostream: - S += "std::iostream"; + OB += "std::iostream"; break; } } @@ -1465,10 +1612,10 @@ public: template void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1480,9 +1627,9 @@ public: template void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; @@ -1494,10 +1641,10 @@ public: template void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; @@ -1516,22 +1663,22 @@ public: F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB += "("; + Params.printWithComma(OB); + OB += ")"; } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1543,10 +1690,10 @@ public: template void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + Bindings.printWithComma(OB); + OB += ']'; } }; @@ -1564,22 +1711,22 @@ public: template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // might be a template argument expression, then we need to disambiguate // with parens. if (InfixOperator == ">") - S += "("; + OB += "("; - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; + OB += "("; + LHS->print(OB); + OB += ") "; + OB += InfixOperator; + OB += " ("; + RHS->print(OB); + OB += ")"; if (InfixOperator == ">") - S += ")"; + OB += ")"; } }; @@ -1593,12 +1740,12 @@ public: template void match(Fn F) const { F(Op1, Op2); } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Op1->print(OB); + OB += ")["; + Op2->print(OB); + OB += "]"; } }; @@ -1612,11 +1759,11 @@ public: template void match(Fn F) const { F(Child, Operator); } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Child->print(OB); + OB += ")"; + OB += Operator; } }; @@ -1631,14 +1778,14 @@ public: template void match(Fn F) const { F(Cond, Then, Else); } - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Cond->print(OB); + OB += ") ? ("; + Then->print(OB); + OB += ") : ("; + Else->print(OB); + OB += ")"; } }; @@ -1653,10 +1800,10 @@ public: template void match(Fn F) const { F(LHS, Kind, RHS); } - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + void printLeft(OutputBuffer &OB) const override { + LHS->print(OB); + OB += Kind; + RHS->print(OB); } }; @@ -1677,20 +1824,20 @@ public: F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); } - void printLeft(OutputStream &S) const override { - SubExpr->print(S); - S += ".<"; - Type->print(S); - S += " at offset "; + void printLeft(OutputBuffer &OB) const override { + SubExpr->print(OB); + OB += ".<"; + Type->print(OB); + OB += " at offset "; if (Offset.empty()) { - S += "0"; + OB += "0"; } else if (Offset[0] == 'n') { - S += "-"; - S += Offset.dropFront(); + OB += "-"; + OB += Offset.dropFront(); } else { - S += Offset; + OB += Offset; } - S += ">"; + OB += ">"; } }; @@ -1706,10 +1853,10 @@ public: template void match(Fn F) const { F(Prefix, Infix, Postfix); } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Infix->print(OB); + OB += Postfix; } }; @@ -1725,13 +1872,13 @@ public: template void match(Fn F) const { F(CastKind, To, From); } - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + OB += "<"; + To->printLeft(OB); + OB += ">("; + From->printLeft(OB); + OB += ")"; } }; @@ -1744,11 +1891,11 @@ public: template void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof...("; ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB += ")"; } }; @@ -1762,11 +1909,11 @@ public: template void match(Fn F) const { F(Callee, Args); } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB += "("; + Args.printWithComma(OB); + OB += ")"; } }; @@ -1787,25 +1934,24 @@ public: F(ExprList, Type, InitList, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::operator "; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; + OB += ' '; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB += "("; + ExprList.printWithComma(OB); + OB += ")"; } - Type->print(S); + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB += "("; + InitList.printWithComma(OB); + OB += ")"; } - } }; @@ -1820,13 +1966,13 @@ public: template void match(Fn F) const { F(Op, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[] "; + Op->print(OB); } }; @@ -1840,11 +1986,11 @@ public: template void match(Fn F) const { F(Prefix, Child); } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB += "("; + Child->print(OB); + OB += ")"; } }; @@ -1856,9 +2002,9 @@ public: template void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1872,12 +2018,12 @@ public: template void match(Fn F) const { F(Type, Expressions); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + Expressions.printWithComma(OB); + OB += ")"; } }; @@ -1894,12 +2040,12 @@ public: template void match(Fn F) const { F(Type, SubExpr, Offset); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - SubExpr->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + SubExpr->print(OB); + OB += ")"; } }; @@ -1912,12 +2058,12 @@ public: template void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1931,18 +2077,18 @@ public: template void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1956,15 +2102,15 @@ public: template void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1983,43 +2129,43 @@ public: F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB += '('; + ParameterPackExpansion(Pack).print(OB); + OB += ')'; }; - S += '('; + OB += '('; if (IsLeftFold) { // init op ... op pack if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; + Init->print(OB); + OB += ' '; + OB += OperatorName; + OB += ' '; } // ... op pack - S += "... "; - S += OperatorName; - S += ' '; + OB += "... "; + OB += OperatorName; + OB += ' '; PrintPack(); } else { // !IsLeftFold // pack op ... PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; + OB += ' '; + OB += OperatorName; + OB += " ..."; // pack op ... op init if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); + OB += ' '; + OB += OperatorName; + OB += ' '; + Init->print(OB); } } - S += ')'; + OB += ')'; } }; @@ -2031,9 +2177,9 @@ public: template void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2045,8 +2191,8 @@ public: template void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? StringView("true") : StringView("false"); } }; @@ -2058,10 +2204,10 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2073,11 +2219,11 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast(Type)->printDeclarator(S); - S += "{...}"; + static_cast(Type)->printDeclarator(OB); + OB += "{...}"; } }; @@ -2092,15 +2238,15 @@ public: template void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S << "("; - Ty->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB << "("; + Ty->print(OB); + OB << ")"; if (Integer[0] == 'n') - S << "-" << Integer.dropFront(1); + OB << "-" << Integer.dropFront(1); else - S << Integer; + OB << Integer; } }; @@ -2114,21 +2260,21 @@ public: template void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB += "("; + OB += Type; + OB += ")"; } if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); + OB += "-"; + OB += Value.dropFront(1); } else - S += Value; + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2158,7 +2304,7 @@ public: template void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { const char *first = Contents.begin(); const char *last = Contents.end() + 1; @@ -2184,7 +2330,7 @@ public: #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); + OB += StringView(num, num + n); } } }; @@ -2217,125 +2363,6 @@ FOR_EACH_NODE_KIND(SPECIALIZATION) #undef FOR_EACH_NODE_KIND -template -class PODSmallVector { - static_assert(std::is_pod::value, - "T is required to be a plain old data type"); - - T* First = nullptr; - T* Last = nullptr; - T* Cap = nullptr; - T Inline[N] = {0}; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - template struct AbstractManglingParser { const char *First; const char *Last; @@ -2450,7 +2477,7 @@ template struct AbstractManglingParser { char consume() { return First != Last ? *First++ : '\0'; } - char look(unsigned Lookahead = 0) { + char look(unsigned Lookahead = 0) const { if (static_cast(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; @@ -2568,34 +2595,38 @@ Node *AbstractManglingParser::parseName(NameState *State) { if (look() == 'Z') return getDerived().parseLocalName(State); - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; + Node *Result = nullptr; + bool IsSubst = look() == 'S' && look(1) != 't'; + if (IsSubst) { + // A substitution must lead to: + // ::= + Result = getDerived().parseSubstitution(); + } else { + // An unscoped name can be one of: + // ::= + // ::= + Result = getDerived().parseUnscopedName(State); + } + if (Result == nullptr) + return nullptr; + + if (look() == 'I') { + // ::= + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by . + return nullptr; } - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= - if (look() == 'I') { - Subs.push_back(N); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); - } - // ::= - return N; + return Result; } // := Z E [] @@ -2640,13 +2671,17 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make(R); - } - return getDerived().parseUnqualifiedName(State); + bool IsStd = consumeIf("St"); + if (IsStd) + consumeIf('L'); + + Node *Result = getDerived().parseUnqualifiedName(State); + if (Result == nullptr) + return nullptr; + if (IsStd) + Result = make(Result); + + return Result; } // ::= [abi-tags] @@ -3884,6 +3919,16 @@ Node *AbstractManglingParser::parseType() { case 'h': First += 2; return make("half"); + // ::= DF _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(DimensionNumber); + } // ::= Di # char32_t case 'i': First += 2; @@ -4031,9 +4076,9 @@ Node *AbstractManglingParser::parseType() { } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + Result = getDerived().parseSubstitution(); + if (Result == nullptr) return nullptr; // Sub could be either of: @@ -4050,13 +4095,13 @@ Node *AbstractManglingParser::parseType() { Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } @@ -5404,38 +5449,35 @@ Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S')) return nullptr; - if (std::islower(look())) { - Node *SpecialSub; + if (look() >= 'a' && look() <= 'z') { + SpecialSubKind Kind; switch (look()) { case 'a': - ++First; - SpecialSub = make(SpecialSubKind::allocator); + Kind = SpecialSubKind::allocator; break; case 'b': - ++First; - SpecialSub = make(SpecialSubKind::basic_string); - break; - case 's': - ++First; - SpecialSub = make(SpecialSubKind::string); - break; - case 'i': - ++First; - SpecialSub = make(SpecialSubKind::istream); - break; - case 'o': - ++First; - SpecialSub = make(SpecialSubKind::ostream); + Kind = SpecialSubKind::basic_string; break; case 'd': - ++First; - SpecialSub = make(SpecialSubKind::iostream); + Kind = SpecialSubKind::iostream; + break; + case 'i': + Kind = SpecialSubKind::istream; + break; + case 'o': + Kind = SpecialSubKind::ostream; + break; + case 's': + Kind = SpecialSubKind::string; break; default: return nullptr; } + ++First; + auto *SpecialSub = make(Kind); if (!SpecialSub) return nullptr; + // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. diff --git a/lib/libcxxabi/src/demangle/StringView.h b/lib/libcxxabi/src/demangle/StringView.h index 1e4d3803f0..90890e3771 100644 --- a/lib/libcxxabi/src/demangle/StringView.h +++ b/lib/libcxxabi/src/demangle/StringView.h @@ -7,6 +7,9 @@ //===----------------------------------------------------------------------===// // // FIXME: Use std::string_view instead when we support C++17. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// @@ -14,7 +17,6 @@ #define DEMANGLE_STRINGVIEW_H #include "DemangleConfig.h" -#include #include #include @@ -38,15 +40,16 @@ public: StringView substr(size_t Pos, size_t Len = npos) const { assert(Pos <= size()); - return StringView(begin() + Pos, std::min(Len, size() - Pos)); + if (Len > size() - Pos) + Len = size() - Pos; + return StringView(begin() + Pos, Len); } 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()) { + if (From < size()) { // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) + if (const void *P = ::memchr(First + From, C, size() - From)) return size_t(static_cast(P) - First); } return npos; @@ -98,7 +101,7 @@ public: bool startsWith(StringView Str) const { if (Str.size() > size()) return false; - return std::equal(Str.begin(), Str.end(), begin()); + return std::strncmp(Str.begin(), begin(), Str.size()) == 0; } const char &operator[](size_t Idx) const { return *(begin() + Idx); } @@ -111,7 +114,7 @@ public: inline bool operator==(const StringView &LHS, const StringView &RHS) { return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); + std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; } DEMANGLE_NAMESPACE_END diff --git a/lib/libcxxabi/src/demangle/Utility.h b/lib/libcxxabi/src/demangle/Utility.h index 846a5f0818..3b27328522 100644 --- a/lib/libcxxabi/src/demangle/Utility.h +++ b/lib/libcxxabi/src/demangle/Utility.h @@ -6,7 +6,10 @@ // //===----------------------------------------------------------------------===// // -// Provide some utility classes for use in the demangler(s). +// Provide some utility classes for use in the demangler. +// There are two copies of this file in the source tree. The one in libcxxabi +// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update +// the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// @@ -14,17 +17,18 @@ #define DEMANGLE_UTILITY_H #include "StringView.h" +#include #include #include #include -#include +#include #include DEMANGLE_NAMESPACE_BEGIN // Stream that AST nodes write their string representation into after the AST // has been parsed. -class OutputStream { +class OutputBuffer { char *Buffer = nullptr; size_t CurrentPosition = 0; size_t BufferCapacity = 0; @@ -48,8 +52,8 @@ class OutputStream { return; } - char Temp[21]; - char *TempPtr = std::end(Temp); + std::array Temp; + char *TempPtr = Temp.data() + Temp.size(); while (N) { *--TempPtr = char('0' + N % 10); @@ -59,13 +63,13 @@ class OutputStream { // Add negative sign... if (isNeg) *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); + this->operator<<(StringView(TempPtr, Temp.data() + Temp.size())); } public: - OutputStream(char *StartBuf, size_t Size) + OutputBuffer(char *StartBuf, size_t Size) : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; + OutputBuffer() = default; void reset(char *Buffer_, size_t BufferCapacity_) { CurrentPosition = 0; Buffer = Buffer_; @@ -77,7 +81,7 @@ public: unsigned CurrentPackIndex = std::numeric_limits::max(); unsigned CurrentPackMax = std::numeric_limits::max(); - OutputStream &operator+=(StringView R) { + OutputBuffer &operator+=(StringView R) { size_t Size = R.size(); if (Size == 0) return *this; @@ -87,17 +91,28 @@ public: return *this; } - OutputStream &operator+=(char C) { + OutputBuffer &operator+=(char C) { grow(1); Buffer[CurrentPosition++] = C; return *this; } - OutputStream &operator<<(StringView R) { return (*this += R); } + OutputBuffer &operator<<(StringView R) { return (*this += R); } - OutputStream &operator<<(char C) { return (*this += C); } + OutputBuffer prepend(StringView R) { + size_t Size = R.size(); - OutputStream &operator<<(long long N) { + grow(Size); + std::memmove(Buffer + Size, Buffer, CurrentPosition); + std::memcpy(Buffer, R.begin(), Size); + CurrentPosition += Size; + + return *this; + } + + OutputBuffer &operator<<(char C) { return (*this += C); } + + OutputBuffer &operator<<(long long N) { if (N < 0) writeUnsigned(static_cast(-N), true); else @@ -105,27 +120,37 @@ public: return *this; } - OutputStream &operator<<(unsigned long long N) { + OutputBuffer &operator<<(unsigned long long N) { writeUnsigned(N, false); return *this; } - OutputStream &operator<<(long N) { + OutputBuffer &operator<<(long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned long N) { + OutputBuffer &operator<<(unsigned long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(int N) { + OutputBuffer &operator<<(int N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned int N) { + OutputBuffer &operator<<(unsigned int N) { return this->operator<<(static_cast(N)); } + void insert(size_t Pos, const char *S, size_t N) { + assert(Pos <= CurrentPosition); + if (N == 0) + return; + grow(N); + std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); + std::memcpy(Buffer + Pos, S, N); + CurrentPosition += N; + } + size_t getCurrentPosition() const { return CurrentPosition; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } @@ -171,7 +196,7 @@ public: SwapAndRestore &operator=(const SwapAndRestore &) = delete; }; -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, +inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, size_t InitSize) { size_t BufferSize; if (Buf == nullptr) { @@ -182,7 +207,7 @@ inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, } else BufferSize = *N; - S.reset(Buf, BufferSize); + OB.reset(Buf, BufferSize); return true; } diff --git a/lib/libcxxabi/src/fallback_malloc.cpp b/lib/libcxxabi/src/fallback_malloc.cpp index f3d7937793..7e356d9fe4 100644 --- a/lib/libcxxabi/src/fallback_malloc.cpp +++ b/lib/libcxxabi/src/fallback_malloc.cpp @@ -1,4 +1,4 @@ -//===------------------------ 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. diff --git a/lib/libcxxabi/src/fallback_malloc.h b/lib/libcxxabi/src/fallback_malloc.h index 5780854519..816e691ed2 100644 --- a/lib/libcxxabi/src/fallback_malloc.h +++ b/lib/libcxxabi/src/fallback_malloc.h @@ -1,4 +1,4 @@ -//===------------------------- 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. diff --git a/lib/libcxxabi/src/include/atomic_support.h b/lib/libcxxabi/src/include/atomic_support.h deleted file mode 100644 index 6f9dbf4360..0000000000 --- a/lib/libcxxabi/src/include/atomic_support.h +++ /dev/null @@ -1,180 +0,0 @@ -//===----------------------------------------------------------------------===//// -// -// 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 -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int __order = _AO_Seq) -{ - __atomic_store_n(__dest, __val, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - __atomic_store_n(__dest, __val, _AO_Relaxed); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int __order = _AO_Seq) -{ - return __atomic_load_n(__val, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int __order = _AO_Seq) -{ - return __atomic_add_fetch(__val, __a, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int __order = _AO_Seq) -{ - return __atomic_exchange_n(__target, __value, __order); -} - -template -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 -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int = 0) -{ - *__dest = __val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - *__dest = __val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int = 0) -{ - return *__val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int = 0) -{ - return *__val += __a; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int = _AO_Seq) -{ - _ValueType old = *__target; - *__target = __value; - return old; -} - -template -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 diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp index 86e187fecb..e1086661c0 100644 --- a/lib/libcxxabi/src/private_typeinfo.cpp +++ b/lib/libcxxabi/src/private_typeinfo.cpp @@ -1,4 +1,4 @@ -//===----------------------- private_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. diff --git a/lib/libcxxabi/src/private_typeinfo.h b/lib/libcxxabi/src/private_typeinfo.h index b99039cb56..622e09cc24 100644 --- a/lib/libcxxabi/src/private_typeinfo.h +++ b/lib/libcxxabi/src/private_typeinfo.h @@ -1,4 +1,4 @@ -//===------------------------ 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. diff --git a/lib/libcxxabi/src/stdlib_exception.cpp b/lib/libcxxabi/src/stdlib_exception.cpp index 5f9e643548..b1fc21f412 100644 --- a/lib/libcxxabi/src/stdlib_exception.cpp +++ b/lib/libcxxabi/src/stdlib_exception.cpp @@ -1,4 +1,4 @@ -//===---------------------------- 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. diff --git a/lib/libcxxabi/src/stdlib_new_delete.cpp b/lib/libcxxabi/src/stdlib_new_delete.cpp index 1091b82f64..4a664e15a5 100644 --- a/lib/libcxxabi/src/stdlib_new_delete.cpp +++ b/lib/libcxxabi/src/stdlib_new_delete.cpp @@ -1,4 +1,4 @@ -//===--------------------- 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. diff --git a/lib/libcxxabi/src/stdlib_stdexcept.cpp b/lib/libcxxabi/src/stdlib_stdexcept.cpp index d466f69c51..92f7a6e076 100644 --- a/lib/libcxxabi/src/stdlib_stdexcept.cpp +++ b/lib/libcxxabi/src/stdlib_stdexcept.cpp @@ -1,4 +1,4 @@ -//===------------------------ 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. @@ -12,9 +12,7 @@ #include #include #include - -// This includes an implementation file from libc++. -#include "../../libcxx/src/include/refstring.h" +#include "include/refstring.h" // from libc++ static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); diff --git a/lib/libcxxabi/src/stdlib_typeinfo.cpp b/lib/libcxxabi/src/stdlib_typeinfo.cpp index b282cc7c61..6e5499628d 100644 --- a/lib/libcxxabi/src/stdlib_typeinfo.cpp +++ b/lib/libcxxabi/src/stdlib_typeinfo.cpp @@ -1,4 +1,4 @@ -//===----------------------------- 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.