From 16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 11 Jan 2021 15:31:56 +0000 Subject: Remove libc++ and libc++abi 8.0.0 now that we switched to version 10.0.1 in the gnu/ directory. --- lib/libcxxabi/src/CMakeLists.txt | 243 -- lib/libcxxabi/src/abort_message.cpp | 78 - lib/libcxxabi/src/abort_message.h | 27 - lib/libcxxabi/src/cxa_aux_runtime.cpp | 44 - lib/libcxxabi/src/cxa_default_handlers.cpp | 123 - lib/libcxxabi/src/cxa_demangle.cpp | 370 -- lib/libcxxabi/src/cxa_exception.cpp | 757 ---- lib/libcxxabi/src/cxa_exception.hpp | 120 - lib/libcxxabi/src/cxa_exception_storage.cpp | 102 - lib/libcxxabi/src/cxa_guard.cpp | 265 -- lib/libcxxabi/src/cxa_handlers.cpp | 110 - lib/libcxxabi/src/cxa_handlers.hpp | 56 - lib/libcxxabi/src/cxa_noexception.cpp | 60 - lib/libcxxabi/src/cxa_personality.cpp | 1325 ------- lib/libcxxabi/src/cxa_thread_atexit.cpp | 140 - lib/libcxxabi/src/cxa_unexpected.cpp | 23 - lib/libcxxabi/src/cxa_vector.cpp | 367 -- lib/libcxxabi/src/cxa_virtual.cpp | 25 - lib/libcxxabi/src/demangle/Compiler.h | 34 - lib/libcxxabi/src/demangle/ItaniumDemangle.h | 5189 -------------------------- lib/libcxxabi/src/demangle/StringView.h | 98 - lib/libcxxabi/src/demangle/Utility.h | 190 - lib/libcxxabi/src/fallback_malloc.cpp | 255 -- lib/libcxxabi/src/fallback_malloc.h | 29 - lib/libcxxabi/src/include/atomic_support.h | 181 - lib/libcxxabi/src/include/refstring.h | 132 - lib/libcxxabi/src/private_typeinfo.cpp | 1301 ------- lib/libcxxabi/src/private_typeinfo.h | 252 -- lib/libcxxabi/src/stdlib_exception.cpp | 72 - lib/libcxxabi/src/stdlib_new_delete.cpp | 263 -- lib/libcxxabi/src/stdlib_stdexcept.cpp | 48 - lib/libcxxabi/src/stdlib_typeinfo.cpp | 53 - 32 files changed, 12332 deletions(-) delete mode 100644 lib/libcxxabi/src/CMakeLists.txt delete mode 100644 lib/libcxxabi/src/abort_message.cpp delete mode 100644 lib/libcxxabi/src/abort_message.h delete mode 100644 lib/libcxxabi/src/cxa_aux_runtime.cpp delete mode 100644 lib/libcxxabi/src/cxa_default_handlers.cpp delete mode 100644 lib/libcxxabi/src/cxa_demangle.cpp delete mode 100644 lib/libcxxabi/src/cxa_exception.cpp delete mode 100644 lib/libcxxabi/src/cxa_exception.hpp delete mode 100644 lib/libcxxabi/src/cxa_exception_storage.cpp delete mode 100644 lib/libcxxabi/src/cxa_guard.cpp delete mode 100644 lib/libcxxabi/src/cxa_handlers.cpp delete mode 100644 lib/libcxxabi/src/cxa_handlers.hpp delete mode 100644 lib/libcxxabi/src/cxa_noexception.cpp delete mode 100644 lib/libcxxabi/src/cxa_personality.cpp delete mode 100644 lib/libcxxabi/src/cxa_thread_atexit.cpp delete mode 100644 lib/libcxxabi/src/cxa_unexpected.cpp delete mode 100644 lib/libcxxabi/src/cxa_vector.cpp delete mode 100644 lib/libcxxabi/src/cxa_virtual.cpp delete mode 100644 lib/libcxxabi/src/demangle/Compiler.h delete mode 100644 lib/libcxxabi/src/demangle/ItaniumDemangle.h delete mode 100644 lib/libcxxabi/src/demangle/StringView.h delete mode 100644 lib/libcxxabi/src/demangle/Utility.h delete mode 100644 lib/libcxxabi/src/fallback_malloc.cpp delete mode 100644 lib/libcxxabi/src/fallback_malloc.h delete mode 100644 lib/libcxxabi/src/include/atomic_support.h delete mode 100644 lib/libcxxabi/src/include/refstring.h delete mode 100644 lib/libcxxabi/src/private_typeinfo.cpp delete mode 100644 lib/libcxxabi/src/private_typeinfo.h delete mode 100644 lib/libcxxabi/src/stdlib_exception.cpp delete mode 100644 lib/libcxxabi/src/stdlib_new_delete.cpp delete mode 100644 lib/libcxxabi/src/stdlib_stdexcept.cpp delete mode 100644 lib/libcxxabi/src/stdlib_typeinfo.cpp (limited to 'lib/libcxxabi/src') diff --git a/lib/libcxxabi/src/CMakeLists.txt b/lib/libcxxabi/src/CMakeLists.txt deleted file mode 100644 index 7e21fb2d792..00000000000 --- a/lib/libcxxabi/src/CMakeLists.txt +++ /dev/null @@ -1,243 +0,0 @@ -# Get sources -set(LIBCXXABI_SOURCES - # C++ABI files - cxa_aux_runtime.cpp - cxa_default_handlers.cpp - cxa_demangle.cpp - cxa_exception_storage.cpp - cxa_guard.cpp - cxa_handlers.cpp - cxa_unexpected.cpp - cxa_vector.cpp - cxa_virtual.cpp - # C++ STL files - stdlib_exception.cpp - stdlib_stdexcept.cpp - stdlib_typeinfo.cpp - # Internal files - abort_message.cpp - fallback_malloc.cpp - private_typeinfo.cpp -) - -if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) - list(APPEND LIBCXXABI_SOURCES stdlib_new_delete.cpp) -endif() - -if (LIBCXXABI_ENABLE_EXCEPTIONS) - list(APPEND LIBCXXABI_SOURCES cxa_exception.cpp) - list(APPEND LIBCXXABI_SOURCES cxa_personality.cpp) -else() - list(APPEND LIBCXXABI_SOURCES cxa_noexception.cpp) -endif() - -if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)) - list(APPEND LIBCXXABI_SOURCES cxa_thread_atexit.cpp) -endif() - -set(LIBCXXABI_HEADERS ../include/cxxabi.h) - -# Add all the headers to the project for IDEs. -if (MSVC_IDE OR XCODE) - # Force them all into the headers dir on MSVC, otherwise they end up at - # project scope because they don't have extensions. - if (MSVC_IDE) - source_group("Header Files" FILES ${LIBCXXABI_HEADERS}) - endif() -endif() - -include_directories("${LIBCXXABI_LIBCXX_INCLUDES}") - -if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) - add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) -endif() - -if (LIBCXXABI_ENABLE_THREADS) - add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) -endif() - -add_library_flags_if(LIBCXXABI_HAS_C_LIB c) -if (LIBCXXABI_USE_LLVM_UNWINDER) - # Prefer using the in-tree version of libunwind, either shared or static. If - # none are found fall back to using -lunwind. - # FIXME: Is it correct to prefer the static version of libunwind? - if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_static) - else() - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind) - endif() - if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - # We handle this by directly merging libunwind objects into libc++abi. - else() - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind) - endif() -else() - add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) -endif() -if (MINGW) - # MINGW_LIBRARIES is defined in config-ix.cmake - list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) -endif() - -# Setup flags. -add_link_flags_if_supported(-nodefaultlibs) - -set(LIBCXXABI_SHARED_LINK_FLAGS) - -if ( APPLE ) - if ( CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6" ) - list(APPEND LIBCXXABI_COMPILE_FLAGS "-U__STRICT_ANSI__") - list(APPEND LIBCXXABI_SHARED_LINK_FLAGS - "-compatibility_version 1" - "-current_version 1" - "-install_name /usr/lib/libc++abi.1.dylib") - list(APPEND LIBCXXABI_LINK_FLAGS - "/usr/lib/libSystem.B.dylib") - else() - list(APPEND LIBCXXABI_SHARED_LINK_FLAGS - "-compatibility_version 1" - "-install_name /usr/lib/libc++abi.1.dylib") - endif() - - if (LLVM_USE_SANITIZER) - if (("${LLVM_USE_SANITIZER}" STREQUAL "Address") OR - ("${LLVM_USE_SANITIZER}" STREQUAL "Address;Undefined") OR - ("${LLVM_USE_SANITIZER}" STREQUAL "Undefined;Address")) - set(LIBFILE "libclang_rt.asan_osx_dynamic.dylib") - elseif("${LLVM_USE_SANITIZER}" STREQUAL "Undefined") - set(LIBFILE "libclang_rt.ubsan_osx_dynamic.dylib") - elseif("${LLVM_USE_SANITIZER}" STREQUAL "Thread") - set(LIBFILE "libclang_rt.tsan_osx_dynamic.dylib") - else() - message(WARNING "LLVM_USE_SANITIZER=${LLVM_USE_SANITIZER} is not supported on OS X") - endif() - if (LIBFILE) - find_compiler_rt_dir(LIBDIR) - if (NOT IS_DIRECTORY "${LIBDIR}") - message(FATAL_ERROR "Cannot find compiler-rt directory on OS X required for LLVM_USE_SANITIZER") - endif() - set(LIBCXXABI_SANITIZER_LIBRARY "${LIBDIR}/${LIBFILE}") - set(LIBCXXABI_SANITIZER_LIBRARY "${LIBCXXABI_SANITIZER_LIBRARY}" PARENT_SCOPE) - message(STATUS "Manually linking compiler-rt library: ${LIBCXXABI_SANITIZER_LIBRARY}") - add_library_flags("${LIBCXXABI_SANITIZER_LIBRARY}") - add_link_flags("-Wl,-rpath,${LIBDIR}") - endif() - endif() -endif() - -split_list(LIBCXXABI_COMPILE_FLAGS) -split_list(LIBCXXABI_LINK_FLAGS) -split_list(LIBCXXABI_SHARED_LINK_FLAGS) - -# FIXME: libc++abi.so will not link when modules are enabled because it depends -# on symbols defined in libc++.so which has not yet been built. -if (LLVM_ENABLE_MODULES) - string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") -endif() - -# Add a object library that contains the compiled source files. -add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) -set_target_properties(cxxabi_objects - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - COMPILE_FLAGS - "${LIBCXXABI_COMPILE_FLAGS}" - POSITION_INDEPENDENT_CODE - ON) - -# Build the shared library. -if (LIBCXXABI_ENABLE_SHARED) - add_library(cxxabi_shared SHARED $) - if(COMMAND llvm_setup_rpath) - llvm_setup_rpath(cxxabi_shared) - endif() - target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_SHARED_LIBRARIES}) - set_target_properties(cxxabi_shared - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - LINK_FLAGS - "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" - OUTPUT_NAME - "c++abi" - POSITION_INDEPENDENT_CODE - ON - SOVERSION - "1" - VERSION - "1.0") - list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_shared") - if (LIBCXXABI_INSTALL_SHARED_LIBRARY) - list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared") - endif() -endif() - -# Build the static library. -if (LIBCXXABI_ENABLE_STATIC) - set(cxxabi_static_sources $) - if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) - if (TARGET unwind_static OR HAVE_LIBUNWIND) - list(APPEND cxxabi_static_sources $) - endif() - endif() - add_library(cxxabi_static STATIC ${cxxabi_static_sources}) - target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_STATIC_LIBRARIES}) - set_target_properties(cxxabi_static - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - LINK_FLAGS - "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME - "c++abi" - POSITION_INDEPENDENT_CODE - ON) - list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_static") - if (LIBCXXABI_INSTALL_STATIC_LIBRARY) - list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_static") - endif() -endif() - -# Add a meta-target for both libraries. -add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS}) - -if (LIBCXXABI_INSTALL_LIBRARY) - install(TARGETS ${LIBCXXABI_INSTALL_TARGETS} - LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ) -endif() - -if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY) - add_custom_target(install-cxxabi - DEPENDS cxxabi - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=cxxabi - -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") - add_custom_target(install-cxxabi-stripped - DEPENDS cxxabi - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=cxxabi - -DCMAKE_INSTALL_DO_STRIP=1 - -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") - - # TODO: This is a legacy target name and should be removed at some point. - add_custom_target(install-libcxxabi DEPENDS install-cxxabi) -endif() diff --git a/lib/libcxxabi/src/abort_message.cpp b/lib/libcxxabi/src/abort_message.cpp deleted file mode 100644 index 7a2a9f835bd..00000000000 --- a/lib/libcxxabi/src/abort_message.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//===------------------------- abort_message.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include "abort_message.h" - -#ifdef __BIONIC__ -#include -#if __ANDROID_API__ >= 21 -#include -extern "C" void android_set_abort_message(const char* msg); -#else -#include -#endif // __ANDROID_API__ >= 21 -#endif // __BIONIC__ - -#ifdef __APPLE__ -# if defined(__has_include) && __has_include() -# define HAVE_CRASHREPORTERCLIENT_H -# include -# endif -#endif - -void abort_message(const char* format, ...) -{ - // write message to stderr -#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) -#ifdef __APPLE__ - fprintf(stderr, "libc++abi.dylib: "); -#endif - va_list list; - va_start(list, format); - vfprintf(stderr, format, list); - va_end(list); - fprintf(stderr, "\n"); -#endif - -#if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H) - // record message in crash report - char* buffer; - va_list list2; - va_start(list2, format); - vasprintf(&buffer, format, list2); - va_end(list2); - CRSetCrashLogMessage(buffer); -#elif defined(__BIONIC__) - char* buffer; - va_list list2; - va_start(list2, format); - vasprintf(&buffer, format, list2); - va_end(list2); - -#if __ANDROID_API__ >= 21 - // Show error in tombstone. - android_set_abort_message(buffer); - - // Show error in logcat. - openlog("libc++abi", 0, 0); - syslog(LOG_CRIT, "%s", buffer); - closelog(); -#else - // The good error reporting wasn't available in Android until L. Since we're - // about to abort anyway, just call __assert2, which will log _somewhere_ - // (tombstone and/or logcat) in older releases. - __assert2(__FILE__, __LINE__, __func__, buffer); -#endif // __ANDROID_API__ >= 21 -#endif // __BIONIC__ - - abort(); -} diff --git a/lib/libcxxabi/src/abort_message.h b/lib/libcxxabi/src/abort_message.h deleted file mode 100644 index e8f9571cb56..00000000000 --- a/lib/libcxxabi/src/abort_message.h +++ /dev/null @@ -1,27 +0,0 @@ -//===-------------------------- abort_message.h-----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef __ABORT_MESSAGE_H_ -#define __ABORT_MESSAGE_H_ - -#include "cxxabi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void -abort_message(const char *format, ...) __attribute__((format(printf, 1, 2))); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp deleted file mode 100644 index 878d3bd034d..00000000000 --- a/lib/libcxxabi/src/cxa_aux_runtime.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//===------------------------ cxa_aux_runtime.cpp -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Auxiliary Runtime APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-aux -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" -#include -#include - -namespace __cxxabiv1 { -extern "C" { -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_cast(); -#else - std::terminate(); -#endif -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_typeid(); -#else - std::terminate(); -#endif -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void -__cxa_throw_bad_array_new_length(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_array_new_length(); -#else - std::terminate(); -#endif -} -} // extern "C" -} // abi diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp deleted file mode 100644 index f00e95929b9..00000000000 --- a/lib/libcxxabi/src/cxa_default_handlers.cpp +++ /dev/null @@ -1,123 +0,0 @@ -//===------------------------- cxa_default_handlers.cpp -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the default terminate_handler and unexpected_handler. -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include -#include "abort_message.h" -#include "cxxabi.h" -#include "cxa_handlers.hpp" -#include "cxa_exception.hpp" -#include "private_typeinfo.h" -#include "include/atomic_support.h" - -#if !defined(LIBCXXABI_SILENT_TERMINATE) -static const char* cause = "uncaught"; - -__attribute__((noreturn)) -static void demangling_terminate_handler() -{ - // If there might be an uncaught exception - using namespace __cxxabiv1; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals) - { - __cxa_exception* exception_header = globals->caughtExceptions; - // If there is an uncaught exception - if (exception_header) - { - _Unwind_Exception* unwind_exception = - reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; - if (__isOurExceptionClass(unwind_exception)) - { - void* thrown_object = - __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)exception_header)->primaryException : - exception_header + 1; - const __shim_type_info* thrown_type = - static_cast(exception_header->exceptionType); - // Try to get demangled name of thrown_type - int status; - char buf[1024]; - size_t len = sizeof(buf); - const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); - if (status != 0) - name = thrown_type->name(); - // If the uncaught exception can be caught with std::exception& - const __shim_type_info* catch_type = - static_cast(&typeid(std::exception)); - if (catch_type->can_catch(thrown_type, thrown_object)) - { - // Include the what() message from the exception - const std::exception* e = static_cast(thrown_object); - abort_message("terminating with %s exception of type %s: %s", - cause, name, e->what()); - } - else - // Else just note that we're terminating with an exception - abort_message("terminating with %s exception of type %s", - cause, name); - } - else - // Else we're terminating with a foreign exception - abort_message("terminating with %s foreign exception", cause); - } - } - // Else just note that we're terminating - abort_message("terminating"); -} - -__attribute__((noreturn)) -static void demangling_unexpected_handler() -{ - cause = "unexpected"; - std::terminate(); -} - -static std::terminate_handler default_terminate_handler = demangling_terminate_handler; -static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler; -#else -static std::terminate_handler default_terminate_handler = std::abort; -static std::terminate_handler default_unexpected_handler = std::terminate; -#endif - -// -// Global variables that hold the pointers to the current handler -// -_LIBCXXABI_DATA_VIS -std::terminate_handler __cxa_terminate_handler = default_terminate_handler; - -_LIBCXXABI_DATA_VIS -std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; - -namespace std -{ - -unexpected_handler -set_unexpected(unexpected_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_unexpected_handler; - return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func, - _AO_Acq_Rel); -} - -terminate_handler -set_terminate(terminate_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_terminate_handler; - return __libcpp_atomic_exchange(&__cxa_terminate_handler, func, - _AO_Acq_Rel); -} - -} diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp deleted file mode 100644 index f227addbdae..00000000000 --- a/lib/libcxxabi/src/cxa_demangle.cpp +++ /dev/null @@ -1,370 +0,0 @@ -//===-------------------------- cxa_demangle.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - -#define _LIBCPP_NO_EXCEPTIONS - -#include "__cxxabi_config.h" - -#include "demangle/ItaniumDemangle.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace itanium_demangle; - -constexpr const char *itanium_demangle::FloatData::spec; -constexpr const char *itanium_demangle::FloatData::spec; -constexpr const char *itanium_demangle::FloatData::spec; - -// := _ # when number < 10 -// := __ _ # when number >= 10 -// extension := decimal-digit+ # at the end of string -const char *itanium_demangle::parse_discriminator(const char *first, - const char *last) { - // parse but ignore discriminator - if (first != last) { - if (*first == '_') { - const char *t1 = first + 1; - if (t1 != last) { - if (std::isdigit(*t1)) - first = t1 + 1; - else if (*t1 == '_') { - for (++t1; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 != last && *t1 == '_') - first = t1 + 1; - } - } - } else if (std::isdigit(*first)) { - const char *t1 = first + 1; - for (; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 == last) - first = last; - } - } - return first; -} - -#ifndef NDEBUG -namespace { -struct DumpVisitor { - unsigned Depth = 0; - bool PendingNewline = false; - - template static constexpr bool wantsNewline(const NodeT *) { - return true; - } - static bool wantsNewline(NodeArray A) { return !A.empty(); } - static constexpr bool wantsNewline(...) { return false; } - - template static bool anyWantNewline(Ts ...Vs) { - for (bool B : {wantsNewline(Vs)...}) - if (B) - return true; - return false; - } - - void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); - } - void print(const Node *N) { - if (N) - N->visit(std::ref(*this)); - else - printStr(""); - } - void print(NodeOrString NS) { - if (NS.isNode()) - print(NS.asNode()); - else if (NS.isString()) - print(NS.asString()); - else - printStr("NodeOrString()"); - } - void print(NodeArray A) { - ++Depth; - printStr("{"); - bool First = true; - for (const Node *N : A) { - if (First) - print(N); - else - printWithComma(N); - First = false; - } - printStr("}"); - --Depth; - } - - // Overload used when T is exactly 'bool', not merely convertible to 'bool'. - void print(bool B) { printStr(B ? "true" : "false"); } - - template - typename std::enable_if::value>::type print(T N) { - fprintf(stderr, "%llu", (unsigned long long)N); - } - - template - typename std::enable_if::value>::type print(T N) { - fprintf(stderr, "%lld", (long long)N); - } - - void print(ReferenceKind RK) { - switch (RK) { - case ReferenceKind::LValue: - return printStr("ReferenceKind::LValue"); - case ReferenceKind::RValue: - return printStr("ReferenceKind::RValue"); - } - } - void print(FunctionRefQual RQ) { - switch (RQ) { - case FunctionRefQual::FrefQualNone: - return printStr("FunctionRefQual::FrefQualNone"); - case FunctionRefQual::FrefQualLValue: - return printStr("FunctionRefQual::FrefQualLValue"); - case FunctionRefQual::FrefQualRValue: - return printStr("FunctionRefQual::FrefQualRValue"); - } - } - void print(Qualifiers Qs) { - if (!Qs) return printStr("QualNone"); - struct QualName { Qualifiers Q; const char *Name; } Names[] = { - {QualConst, "QualConst"}, - {QualVolatile, "QualVolatile"}, - {QualRestrict, "QualRestrict"}, - }; - for (QualName Name : Names) { - if (Qs & Name.Q) { - printStr(Name.Name); - Qs = Qualifiers(Qs & ~Name.Q); - if (Qs) printStr(" | "); - } - } - } - void print(SpecialSubKind SSK) { - switch (SSK) { - case SpecialSubKind::allocator: - return printStr("SpecialSubKind::allocator"); - case SpecialSubKind::basic_string: - return printStr("SpecialSubKind::basic_string"); - case SpecialSubKind::string: - return printStr("SpecialSubKind::string"); - case SpecialSubKind::istream: - return printStr("SpecialSubKind::istream"); - case SpecialSubKind::ostream: - return printStr("SpecialSubKind::ostream"); - case SpecialSubKind::iostream: - return printStr("SpecialSubKind::iostream"); - } - } - - void newLine() { - printStr("\n"); - for (unsigned I = 0; I != Depth; ++I) - printStr(" "); - PendingNewline = false; - } - - template void printWithPendingNewline(T V) { - print(V); - if (wantsNewline(V)) - PendingNewline = true; - } - - template void printWithComma(T V) { - if (PendingNewline || wantsNewline(V)) { - printStr(","); - newLine(); - } else { - printStr(", "); - } - - printWithPendingNewline(V); - } - - struct CtorArgPrinter { - DumpVisitor &Visitor; - - template void operator()(T V, Rest ...Vs) { - if (Visitor.anyWantNewline(V, Vs...)) - Visitor.newLine(); - Visitor.printWithPendingNewline(V); - int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; - (void)PrintInOrder; - } - }; - - template void operator()(const NodeT *Node) { - Depth += 2; - fprintf(stderr, "%s(", itanium_demangle::NodeKind::name()); - Node->match(CtorArgPrinter{*this}); - fprintf(stderr, ")"); - Depth -= 2; - } - - void operator()(const ForwardTemplateReference *Node) { - Depth += 2; - fprintf(stderr, "ForwardTemplateReference("); - if (Node->Ref && !Node->Printing) { - Node->Printing = true; - CtorArgPrinter{*this}(Node->Ref); - Node->Printing = false; - } else { - CtorArgPrinter{*this}(Node->Index); - } - fprintf(stderr, ")"); - Depth -= 2; - } -}; -} - -void itanium_demangle::Node::dump() const { - DumpVisitor V; - visit(std::ref(V)); - V.newLine(); -} -#endif - -namespace { -class BumpPointerAllocator { - struct BlockMeta { - BlockMeta* Next; - size_t Current; - }; - - static constexpr size_t AllocSize = 4096; - static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); - - alignas(long double) char InitialBuffer[AllocSize]; - BlockMeta* BlockList = nullptr; - - void grow() { - char* NewMeta = static_cast(std::malloc(AllocSize)); - if (NewMeta == nullptr) - std::terminate(); - BlockList = new (NewMeta) BlockMeta{BlockList, 0}; - } - - void* allocateMassive(size_t NBytes) { - NBytes += sizeof(BlockMeta); - BlockMeta* NewMeta = reinterpret_cast(std::malloc(NBytes)); - if (NewMeta == nullptr) - std::terminate(); - BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; - return static_cast(NewMeta + 1); - } - -public: - BumpPointerAllocator() - : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} - - void* allocate(size_t N) { - N = (N + 15u) & ~15u; - if (N + BlockList->Current >= UsableAllocSize) { - if (N > UsableAllocSize) - return allocateMassive(N); - grow(); - } - BlockList->Current += N; - return static_cast(reinterpret_cast(BlockList + 1) + - BlockList->Current - N); - } - - void reset() { - while (BlockList) { - BlockMeta* Tmp = BlockList; - BlockList = BlockList->Next; - if (reinterpret_cast(Tmp) != InitialBuffer) - std::free(Tmp); - } - BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; - } - - ~BumpPointerAllocator() { reset(); } -}; - -class DefaultAllocator { - BumpPointerAllocator Alloc; - -public: - void reset() { Alloc.reset(); } - - template T *makeNode(Args &&...args) { - return new (Alloc.allocate(sizeof(T))) - T(std::forward(args)...); - } - - void *allocateNodeArray(size_t sz) { - return Alloc.allocate(sizeof(Node *) * sz); - } -}; -} // unnamed namespace - -//===----------------------------------------------------------------------===// -// Code beyond this point should not be synchronized with LLVM. -//===----------------------------------------------------------------------===// - -using Demangler = itanium_demangle::ManglingParser; - -namespace { -enum : int { - demangle_invalid_args = -3, - demangle_invalid_mangled_name = -2, - demangle_memory_alloc_failure = -1, - demangle_success = 0, -}; -} - -namespace __cxxabiv1 { -extern "C" _LIBCXXABI_FUNC_VIS char * -__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { - if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status) - *Status = demangle_invalid_args; - return nullptr; - } - - int InternalStatus = demangle_success; - Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; - - Node *AST = Parser.parse(); - - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) - InternalStatus = demangle_memory_alloc_failure; - else { - assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; - if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); - } - - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; -} -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp deleted file mode 100644 index 8d30e5ce429..00000000000 --- a/lib/libcxxabi/src/cxa_exception.cpp +++ /dev/null @@ -1,757 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" - -#include // for std::terminate -#include // for memset -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" -#include "fallback_malloc.h" -#include "include/atomic_support.h" - -#if __has_feature(address_sanitizer) -extern "C" void __asan_handle_no_return(void); -#endif - -// +---------------------------+-----------------------------+---------------+ -// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | -// +---------------------------+-----------------------------+---------------+ -// ^ -// | -// +-------------------------------------------------------+ -// | -// +---------------------------+-----------------------------+ -// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | -// +---------------------------+-----------------------------+ - -namespace __cxxabiv1 { - -// Utility routines -static -inline -__cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) -{ - return static_cast<__cxa_exception*>(thrown_object) - 1; -} - -// Note: This is never called when exception_header is masquerading as a -// __cxa_dependent_exception. -static -inline -void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) -{ - return static_cast(exception_header + 1); -} - -// Get the exception object from the unwind pointer. -// Relies on the structure layout, where the unwind pointer is right in -// front of the user's exception object -static -inline -__cxa_exception* -cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) -{ - return cxa_exception_from_thrown_object(unwind_exception + 1 ); -} - -// Round s up to next multiple of a. -static inline -size_t aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); -} - -static inline -size_t cxa_exception_size_from_exception_thrown_size(size_t size) { - return aligned_allocation_size(size + sizeof (__cxa_exception), - alignof(__cxa_exception)); -} - -void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) { - ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); - } - - -static void setOurExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurExceptionClass); -} - -static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurDependentExceptionClass); -} - -// Is it one of ours? -uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { -// On x86 and some ARM unwinders, unwind_exception->exception_class is -// a uint64_t. On other ARM unwinders, it is a char[8] -// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf -// So we just copy it into a uint64_t to be sure. - uint64_t exClass; - ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); - return exClass; -} - -bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); -} - -static bool isDependentException(_Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; -} - -// This does not need to be atomic -static inline int incrementHandlerCount(__cxa_exception *exception) { - return ++exception->handlerCount; -} - -// This does not need to be atomic -static inline int decrementHandlerCount(__cxa_exception *exception) { - return --exception->handlerCount; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the exceptionDestructor stored in - exc is called, and then the memory for the exception is deallocated. - - This is never called for a __cxa_dependent_exception. -*/ -static -void -exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(exception_header->terminateHandler); - // Just in case there exists a dependent exception that is pointing to this, - // check the reference count and only destroy this if that count goes to zero. - __cxa_decrement_exception_refcount(unwind_exception + 1); -} - -static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { -// Section 2.5.3 says: -// * For purposes of this ABI, several things are considered exception handlers: -// ** A terminate() call due to a throw. -// and -// * Upon entry, Following initialization of the catch parameter, -// a handler must call: -// * void *__cxa_begin_catch(void *exceptionObject ); - (void) __cxa_begin_catch(&exception_header->unwindHeader); - std::__terminate(exception_header->terminateHandler); -} - -// Return the offset of the __cxa_exception header from the start of the -// allocated buffer. If __cxa_exception's alignment is smaller than the maximum -// useful alignment for the target machine, padding has to be inserted before -// the header to ensure the thrown object that follows the header is -// sufficiently aligned. This happens if _Unwind_exception isn't double-word -// aligned (on Darwin, for example). -static size_t get_cxa_exception_offset() { - struct S { - } __attribute__((aligned)); - - // Compute the maximum alignment for the target machine. - constexpr size_t alignment = std::alignment_of::value; - constexpr size_t excp_size = sizeof(__cxa_exception); - constexpr size_t aligned_size = - (excp_size + alignment - 1) / alignment * alignment; - constexpr size_t offset = aligned_size - excp_size; - static_assert((offset == 0 || - std::alignment_of<_Unwind_Exception>::value < alignment), - "offset is non-zero only if _Unwind_Exception isn't aligned"); - return offset; -} - -extern "C" { - -// Allocate a __cxa_exception object, and zero-fill it. -// Reserve "thrown_size" bytes on the end for the user's exception -// object. Zero-fill the object. If memory can't be allocated, call -// std::terminate. Return a pointer to the memory to be used for the -// user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { - size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); - - // Allocate extra space before the __cxa_exception header to ensure the - // start of the thrown object is sufficiently aligned. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - (char *)__aligned_malloc_with_fallback(header_offset + actual_size); - if (NULL == raw_buffer) - std::terminate(); - __cxa_exception *exception_header = - static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); - std::memset(exception_header, 0, actual_size); - return thrown_object_from_cxa_exception(exception_header); -} - - -// Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { - // Compute the size of the padding before the header. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; - __aligned_free_with_fallback((void *)raw_buffer); -} - - -// This function shall allocate a __cxa_dependent_exception and -// return a pointer to it. (Really to the object, not past its' end). -// Otherwise, it will work like __cxa_allocate_exception. -void * __cxa_allocate_dependent_exception () { - size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = __aligned_malloc_with_fallback(actual_size); - if (NULL == ptr) - std::terminate(); - std::memset(ptr, 0, actual_size); - return ptr; -} - - -// This function shall free a dependent_exception. -// It does not affect the reference count of the primary exception. -void __cxa_free_dependent_exception (void * dependent_exception) { - __aligned_free_with_fallback(dependent_exception); -} - - -// 2.4.3 Throwing the Exception Object -/* -After constructing the exception object with the throw argument value, -the generated code calls the __cxa_throw runtime library routine. This -routine never returns. - -The __cxa_throw routine will do the following: - -* Obtain the __cxa_exception header from the thrown exception object address, -which can be computed as follows: - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); -* Save the current unexpected_handler and terminate_handler in the __cxa_exception header. -* Save the tinfo and dest arguments in the __cxa_exception header. -* Set the exception_class field in the unwind header. This is a 64-bit value -representing the ASCII string "XXXXC++\0", where "XXXX" is a -vendor-dependent string. That is, for implementations conforming to this -ABI, the low-order 4 bytes of this 64-bit value will be "C++\0". -* Increment the uncaught_exception flag. -* Call _Unwind_RaiseException in the system unwind library, Its argument is the -pointer to the thrown exception, which __cxa_throw itself received as an argument. -__Unwind_RaiseException begins the process of stack unwinding, described -in Section 2.5. In special cases, such as an inability to find a -handler, _Unwind_RaiseException may return. In that case, __cxa_throw -will call terminate, assuming that there was no handler for the -exception. -*/ -void -__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { - __cxa_eh_globals *globals = __cxa_get_globals(); - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - - exception_header->unexpectedHandler = std::get_unexpected(); - exception_header->terminateHandler = std::get_terminate(); - exception_header->exceptionType = tinfo; - exception_header->exceptionDestructor = dest; - setOurExceptionClass(&exception_header->unwindHeader); - exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. - globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local - - exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; - -#if __has_feature(address_sanitizer) - // Inform the ASan runtime that now might be a good time to clean stuff up. - __asan_handle_no_return(); -#endif - -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - // This only happens when there is no handler, or some unexpected unwinding - // error happens. - failed_throw(exception_header); -} - - -// 2.5.3 Exception Handlers -/* -The adjusted pointer is computed by the personality routine during phase 1 - and saved in the exception header (either __cxa_exception or - __cxa_dependent_exception). - - Requires: exception is native -*/ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast( - static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); -#else - return cxa_exception_from_exception_unwind_exception( - static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; -#endif -} - -#if defined(_LIBCXXABI_ARM_EHABI) -/* -The routine to be called before the cleanup. This will save __cxa_exception in -__cxa_eh_globals, so that __cxa_end_cleanup() can recover later. -*/ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception(unwind_exception); - - if (__isOurExceptionClass(unwind_exception)) - { - if (0 == exception_header->propagationCount) - { - exception_header->nextPropagatingException = globals->propagatingExceptions; - globals->propagatingExceptions = exception_header; - } - ++exception_header->propagationCount; - } - else - { - // If the propagatingExceptions stack is not empty, since we can't - // chain the foreign exception, terminate it. - if (NULL != globals->propagatingExceptions) - std::terminate(); - globals->propagatingExceptions = exception_header; - } - return true; -} - -/* -The routine to be called after the cleanup has been performed. It will get the -propagating __cxa_exception from __cxa_eh_globals, and continue the stack -unwinding with _Unwind_Resume. - -According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any -register, thus we have to write this function in assembly so that we can save -{r1, r2, r3}. We don't have to save r0 because it is the return value and the -first argument to _Unwind_Resume(). In addition, we are saving r4 in order to -align the stack to 16 bytes, even though it is a callee-save register. -*/ -__attribute__((used)) static _Unwind_Exception * -__cxa_end_cleanup_impl() -{ - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->propagatingExceptions; - if (NULL == exception_header) - { - // It seems that __cxa_begin_cleanup() is not called properly. - // We have no choice but terminate the program now. - std::terminate(); - } - - if (__isOurExceptionClass(&exception_header->unwindHeader)) - { - --exception_header->propagationCount; - if (0 == exception_header->propagationCount) - { - globals->propagatingExceptions = exception_header->nextPropagatingException; - exception_header->nextPropagatingException = NULL; - } - } - else - { - globals->propagatingExceptions = NULL; - } - return &exception_header->unwindHeader; -} - -asm ( - " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" - " .globl __cxa_end_cleanup\n" - " .type __cxa_end_cleanup,%function\n" - "__cxa_end_cleanup:\n" - " push {r1, r2, r3, r4}\n" - " bl __cxa_end_cleanup_impl\n" - " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); -#endif // defined(_LIBCXXABI_ARM_EHABI) - -/* -This routine can catch foreign or native exceptions. If native, the exception -can be a primary or dependent variety. This routine may remain blissfully -ignorant of whether the native exception is primary or dependent. - -If the exception is native: -* Increment's the exception's handler count. -* Push the exception on the stack of currently-caught exceptions if it is not - already there (from a rethrow). -* Decrements the uncaught_exception count. -* Returns the adjusted pointer to the exception object, which is stored in - the __cxa_exception by the personality routine. - -If the exception is foreign, this means it did not originate from one of throw -routines. The foreign exception does not necessarily have a __cxa_exception -header. However we can catch it here with a catch (...), or with a call -to terminate or unexpected during unwinding. -* Do not try to increment the exception's handler count, we don't know where - it is. -* Push the exception on the stack of currently-caught exceptions only if the - stack is empty. The foreign exception has no way to link to the current - top of stack. If the stack is not empty, call terminate. Even with an - empty stack, this is hacked in by pushing a pointer to an imaginary - __cxa_exception block in front of the foreign exception. It would be better - if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it - doesn't. It has a stack of __cxa_exception (which has a next* in it). -* Do not decrement the uncaught_exception count because we didn't increment it - in __cxa_throw (or one of our rethrow functions). -* If we haven't terminated, assume the exception object is just past the - _Unwind_Exception and return a pointer to that. -*/ -void* -__cxa_begin_catch(void* unwind_arg) throw() -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - bool native_exception = __isOurExceptionClass(unwind_exception); - __cxa_eh_globals* globals = __cxa_get_globals(); - // exception_header is a hackish offset from a foreign exception, but it - // works as long as we're careful not to try to access any __cxa_exception - // parts. - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception - ( - static_cast<_Unwind_Exception*>(unwind_exception) - ); - if (native_exception) - { - // Increment the handler count, removing the flag about being rethrown - exception_header->handlerCount = exception_header->handlerCount < 0 ? - -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; - // place the exception on the top of the stack if it's not already - // there by a previous rethrow - if (exception_header != globals->caughtExceptions) - { - exception_header->nextException = globals->caughtExceptions; - globals->caughtExceptions = exception_header; - } - globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast(exception_header->unwindHeader.barrier_cache.bitpattern[0]); -#else - return exception_header->adjustedPtr; -#endif - } - // Else this is a foreign exception - // If the caughtExceptions stack is not empty, terminate - if (globals->caughtExceptions != 0) - std::terminate(); - // Push the foreign exception on to the stack - globals->caughtExceptions = exception_header; - return unwind_exception + 1; -} - - -/* -Upon exit for any reason, a handler must call: - void __cxa_end_catch (); - -This routine can be called for either a native or foreign exception. -For a native exception: -* Locates the most recently caught exception and decrements its handler count. -* Removes the exception from the caught exception stack, if the handler count goes to zero. -* If the handler count goes down to zero, and the exception was not re-thrown - by throw, it locates the primary exception (which may be the same as the one - it's handling) and decrements its reference count. If that reference count - goes to zero, the function destroys the exception. In any case, if the current - exception is a dependent exception, it destroys that. - -For a foreign exception: -* If it has been rethrown, there is nothing to do. -* Otherwise delete the exception and pop the catch stack to empty. -*/ -void __cxa_end_catch() { - static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), - "sizeof(__cxa_exception) must be equal to " - "sizeof(__cxa_dependent_exception)"); - static_assert(__builtin_offsetof(__cxa_exception, referenceCount) == - __builtin_offsetof(__cxa_dependent_exception, - primaryException), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - static_assert(__builtin_offsetof(__cxa_exception, handlerCount) == - __builtin_offsetof(__cxa_dependent_exception, handlerCount), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch - __cxa_exception* exception_header = globals->caughtExceptions; - // If we've rethrown a foreign exception, then globals->caughtExceptions - // will have been made an empty stack by __cxa_rethrow() and there is - // nothing more to be done. Do nothing! - if (NULL != exception_header) - { - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // This is a native exception - if (exception_header->handlerCount < 0) - { - // The exception has been rethrown by __cxa_rethrow, so don't delete it - if (0 == incrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // but don't destroy - } - // Keep handlerCount negative in case there are nested catch's - // that need to be told that this exception is rethrown. Don't - // erase this rethrow flag until the exception is recaught. - } - else - { - // The native exception has not been rethrown - if (0 == decrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // Destroy this exception, being careful to distinguish - // between dependent and primary exceptions - if (isDependentException(&exception_header->unwindHeader)) - { - // Reset exception_header to primaryException and deallocate the dependent exception - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = - cxa_exception_from_thrown_object(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); - } - // Destroy the primary exception only if its referenceCount goes to 0 - // (this decrement must be atomic) - __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); - } - } - } - else - { - // The foreign exception has not been rethrown. Pop the stack - // and delete it. If there are nested catch's and they try - // to touch a foreign exception in any way, that is undefined - // behavior. They likely can't since the only way to catch - // a foreign exception is with catch (...)! - _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); - globals->caughtExceptions = 0; - } - } -} - -// Note: exception_header may be masquerading as a __cxa_dependent_exception -// and that's ok. exceptionType is there too. -// However watch out for foreign exceptions. Return null for them. -std::type_info *__cxa_current_exception_type() { -// get the current exception - __cxa_eh_globals *globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there have never been any exceptions, there are none now. - __cxa_exception *exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; - return exception_header->exceptionType; -} - -// 2.5.4 Rethrowing Exceptions -/* This routine can rethrow native or foreign exceptions. -If the exception is native: -* marks the exception object on top of the caughtExceptions stack - (in an implementation-defined way) as being rethrown. -* If the caughtExceptions stack is empty, it calls terminate() - (see [C++FDIS] [except.throw], 15.1.8). -* It then calls _Unwind_RaiseException which should not return - (terminate if it does). - Note: exception_header may be masquerading as a __cxa_dependent_exception - and that's ok. -*/ -void __cxa_rethrow() { - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - std::terminate(); // throw; called outside of a exception handler - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) - exception_header->handlerCount = -exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary - } - else // this is a foreign exception - { - // The only way to communicate to __cxa_end_catch that we've rethrown - // a foreign exception, so don't delete us, is to pop the stack here - // which must be empty afterwards. Then __cxa_end_catch will do - // nothing - globals->caughtExceptions = 0; - } -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - - // If we get here, some kind of unwinding error has occurred. - // There is some weird code generation bug happening with - // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) - // If we call failed_throw here. Turns up with -O2 or higher, and -Os. - __cxa_begin_catch(&exception_header->unwindHeader); - if (native_exception) - std::__terminate(exception_header->terminateHandler); - // Foreign exception: can't get exception_header->terminateHandler - std::terminate(); -} - -/* - If thrown_object is not null, atomically increment the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); - } -} - -/* - If thrown_object is not null, atomically decrement the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. If the referenceCount drops to zero, destroy and - deallocate the exception. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -_LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) - { - if (NULL != exception_header->exceptionDestructor) - exception_header->exceptionDestructor(thrown_object); - __cxa_free_exception(thrown_object); - } - } -} - -/* - Returns a pointer to the thrown object (if any) at the top of the - caughtExceptions stack. Atomically increment the exception's referenceCount. - If there is no such thrown object or if the thrown object is foreign, - returns null. - - We can use __cxa_get_globals_fast here to get the globals because if there have - been no exceptions thrown, ever, on this thread, we can return NULL without - the need to allocate the exception-handling globals. -*/ -void *__cxa_current_primary_exception() throw() { -// get the current exception - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there are no globals, there is no exception - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; // Can't capture a foreign exception (no way to refcount it) - if (isDependentException(&exception_header->unwindHeader)) { - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); - } - void* thrown_object = thrown_object_from_cxa_exception(exception_header); - __cxa_increment_exception_refcount(thrown_object); - return thrown_object; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the referenceCount stored in the - primary exception is decremented, destroying the primary if necessary. - Finally the dependent exception is destroyed. -*/ -static -void -dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(dep_exception_header->terminateHandler); - __cxa_decrement_exception_refcount(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); -} - -/* - If thrown_object is not null, allocate, initialize and throw a dependent - exception. -*/ -void -__cxa_rethrow_primary_exception(void* thrown_object) -{ - if ( thrown_object != NULL ) - { - // thrown_object guaranteed to be native because - // __cxa_current_primary_exception returns NULL for foreign exceptions - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - __cxa_dependent_exception* dep_exception_header = - static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); - dep_exception_header->primaryException = thrown_object; - __cxa_increment_exception_refcount(thrown_object); - dep_exception_header->exceptionType = exception_header->exceptionType; - dep_exception_header->unexpectedHandler = std::get_unexpected(); - dep_exception_header->terminateHandler = std::get_terminate(); - setDependentExceptionClass(&dep_exception_header->unwindHeader); - __cxa_get_globals()->uncaughtExceptions += 1; - dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); -#else - _Unwind_RaiseException(&dep_exception_header->unwindHeader); -#endif - // Some sort of unwinding error. Note that terminate is a handler. - __cxa_begin_catch(&dep_exception_header->unwindHeader); - } - // If we return client will call terminate() -} - -bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } - -unsigned int -__cxa_uncaught_exceptions() throw() -{ - // This does not report foreign exceptions in flight - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals == 0) - return 0; - return globals->uncaughtExceptions; -} - -} // extern "C" - -} // abi diff --git a/lib/libcxxabi/src/cxa_exception.hpp b/lib/libcxxabi/src/cxa_exception.hpp deleted file mode 100644 index 6d98e11a623..00000000000 --- a/lib/libcxxabi/src/cxa_exception.hpp +++ /dev/null @@ -1,120 +0,0 @@ -//===------------------------- cxa_exception.hpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -#ifndef _CXA_EXCEPTION_H -#define _CXA_EXCEPTION_H - -#include // for std::unexpected_handler and std::terminate_handler -#include "cxxabi.h" -#include "unwind.h" - -namespace __cxxabiv1 { - -static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 -static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 -static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ - -uint64_t __getExceptionClass (const _Unwind_Exception*); -void __setExceptionClass ( _Unwind_Exception*, uint64_t); -bool __isOurExceptionClass(const _Unwind_Exception*); - -struct _LIBCXXABI_HIDDEN __cxa_exception { -#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) - // This is a new field to support C++ 0x exception_ptr. - // For binary compatibility it is at the start of this - // struct which is prepended to the object thrown in - // __cxa_allocate_exception. - size_t referenceCount; -#endif - - // Manage the exception object itself. - std::type_info *exceptionType; - void (*exceptionDestructor)(void *); - std::unexpected_handler unexpectedHandler; - std::terminate_handler terminateHandler; - - __cxa_exception *nextException; - - int handlerCount; - -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* nextPropagatingException; - int propagationCount; -#else - int handlerSwitchValue; - const unsigned char *actionRecord; - const unsigned char *languageSpecificData; - void *catchTemp; - void *adjustedPtr; -#endif - -#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) - // This is a new field to support C++ 0x exception_ptr. - // For binary compatibility it is placed where the compiler - // previously adding padded to 64-bit align unwindHeader. - size_t referenceCount; -#endif - _Unwind_Exception unwindHeader; -}; - -// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html -// The layout of this structure MUST match the layout of __cxa_exception, with -// primaryException instead of referenceCount. -struct _LIBCXXABI_HIDDEN __cxa_dependent_exception { -#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) - void* primaryException; -#endif - - std::type_info *exceptionType; - void (*exceptionDestructor)(void *); - std::unexpected_handler unexpectedHandler; - std::terminate_handler terminateHandler; - - __cxa_exception *nextException; - - int handlerCount; - -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* nextPropagatingException; - int propagationCount; -#else - int handlerSwitchValue; - const unsigned char *actionRecord; - const unsigned char *languageSpecificData; - void * catchTemp; - void *adjustedPtr; -#endif - -#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) - void* primaryException; -#endif - _Unwind_Exception unwindHeader; -}; - -struct _LIBCXXABI_HIDDEN __cxa_eh_globals { - __cxa_exception * caughtExceptions; - unsigned int uncaughtExceptions; -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* propagatingExceptions; -#endif -}; - -extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals (); -extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast (); - -extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception (); -extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception); - -} // namespace __cxxabiv1 - -#endif // _CXA_EXCEPTION_H diff --git a/lib/libcxxabi/src/cxa_exception_storage.cpp b/lib/libcxxabi/src/cxa_exception_storage.cpp deleted file mode 100644 index c641e0225f8..00000000000 --- a/lib/libcxxabi/src/cxa_exception_storage.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===--------------------- cxa_exception_storage.cpp ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the storage for the "Caught Exception Stack" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html (section 2.2.2) -// -//===----------------------------------------------------------------------===// - -#include "cxa_exception.hpp" - -#include <__threading_support> - -#if defined(_LIBCXXABI_HAS_NO_THREADS) - -namespace __cxxabiv1 { -extern "C" { - static __cxa_eh_globals eh_globals; - __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } - __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } - } -} - -#elif defined(HAS_THREAD_LOCAL) - -namespace __cxxabiv1 { - -namespace { - __cxa_eh_globals * __globals () { - static thread_local __cxa_eh_globals eh_globals; - return &eh_globals; - } - } - -extern "C" { - __cxa_eh_globals * __cxa_get_globals () { return __globals (); } - __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } - } -} - -#else - -#include "abort_message.h" -#include "fallback_malloc.h" - -// In general, we treat all threading errors as fatal. -// We cannot call std::terminate() because that will in turn -// call __cxa_get_globals() and cause infinite recursion. - -namespace __cxxabiv1 { -namespace { - std::__libcpp_tls_key key_; - std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - - void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { - __free_with_fallback ( p ); - if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) - abort_message("cannot zero out thread value for __cxa_get_globals()"); - } - - void construct_ () { - if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) - abort_message("cannot create thread specific key for __cxa_get_globals()"); - } -} - -extern "C" { - __cxa_eh_globals * __cxa_get_globals () { - // Try to get the globals for this thread - __cxa_eh_globals* retVal = __cxa_get_globals_fast (); - - // If this is the first time we've been asked for these globals, create them - if ( NULL == retVal ) { - retVal = static_cast<__cxa_eh_globals*> - (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); - if ( NULL == retVal ) - abort_message("cannot allocate __cxa_eh_globals"); - if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) - abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); - } - return retVal; - } - - // Note that this implementation will reliably return NULL if not - // preceded by a call to __cxa_get_globals(). This is an extension - // to the Itanium ABI and is taken advantage of in several places in - // libc++abi. - __cxa_eh_globals * __cxa_get_globals_fast () { - // First time through, create the key. - if (0 != std::__libcpp_execute_once(&flag_, construct_)) - abort_message("execute once failure in __cxa_get_globals_fast()"); -// static int init = construct_(); - return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); - } - -} -} -#endif diff --git a/lib/libcxxabi/src/cxa_guard.cpp b/lib/libcxxabi/src/cxa_guard.cpp deleted file mode 100644 index f4c2a184dc5..00000000000 --- a/lib/libcxxabi/src/cxa_guard.cpp +++ /dev/null @@ -1,265 +0,0 @@ -//===---------------------------- cxa_guard.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "__cxxabi_config.h" - -#include "abort_message.h" -#include <__threading_support> - -#include - -/* - This implementation must be careful to not call code external to this file - which will turn around and try to call __cxa_guard_acquire reentrantly. - For this reason, the headers of this file are as restricted as possible. - Previous implementations of this code for __APPLE__ have used - std::__libcpp_mutex_lock and the abort_message utility without problem. This - implementation also uses std::__libcpp_condvar_wait which has tested - to not be a problem. -*/ - -namespace __cxxabiv1 -{ - -namespace -{ - -#ifdef __arm__ -// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must -// be statically initialized to 0. -typedef uint32_t guard_type; - -inline void set_initialized(guard_type* guard_object) { - *guard_object |= 1; -} -#else -typedef uint64_t guard_type; - -void set_initialized(guard_type* guard_object) { - char* initialized = (char*)guard_object; - *initialized = 1; -} -#endif - -#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__)) -#ifdef __arm__ - -// Test the lowest bit. -inline bool is_initialized(guard_type* guard_object) { - return (*guard_object) & 1; -} - -#else - -bool is_initialized(guard_type* guard_object) { - char* initialized = (char*)guard_object; - return *initialized; -} - -#endif -#endif - -#ifndef _LIBCXXABI_HAS_NO_THREADS -std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER; -std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER; -#endif - -#if defined(__APPLE__) && !defined(__arm__) - -typedef uint32_t lock_type; - -#if __LITTLE_ENDIAN__ - -inline -lock_type -get_lock(uint64_t x) -{ - return static_cast(x >> 32); -} - -inline -void -set_lock(uint64_t& x, lock_type y) -{ - x = static_cast(y) << 32; -} - -#else // __LITTLE_ENDIAN__ - -inline -lock_type -get_lock(uint64_t x) -{ - return static_cast(x); -} - -inline -void -set_lock(uint64_t& x, lock_type y) -{ - x = y; -} - -#endif // __LITTLE_ENDIAN__ - -#else // !__APPLE__ || __arm__ - -typedef bool lock_type; - -#if !defined(__arm__) -static_assert(std::is_same::value, ""); - -inline lock_type get_lock(uint64_t x) -{ - union - { - uint64_t guard; - uint8_t lock[2]; - } f = {x}; - return f.lock[1] != 0; -} - -inline void set_lock(uint64_t& x, lock_type y) -{ - union - { - uint64_t guard; - uint8_t lock[2]; - } f = {0}; - f.lock[1] = y; - x = f.guard; -} -#else // defined(__arm__) -static_assert(std::is_same::value, ""); - -inline lock_type get_lock(uint32_t x) -{ - union - { - uint32_t guard; - uint8_t lock[2]; - } f = {x}; - return f.lock[1] != 0; -} - -inline void set_lock(uint32_t& x, lock_type y) -{ - union - { - uint32_t guard; - uint8_t lock[2]; - } f = {0}; - f.lock[1] = y; - x = f.guard; -} - -#endif // !defined(__arm__) - -#endif // __APPLE__ && !__arm__ - -} // unnamed namespace - -extern "C" -{ - -#ifndef _LIBCXXABI_HAS_NO_THREADS -_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { - char* initialized = (char*)guard_object; - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_acquire failed to acquire mutex"); - int result = *initialized == 0; - if (result) - { -#if defined(__APPLE__) && !defined(__arm__) - // This is a special-case pthread dependency for Mac. We can't pull this - // out into libcxx's threading API (__threading_support) because not all - // supported Mac environments provide this function (in pthread.h). To - // make it possible to build/use libcxx in those environments, we have to - // keep this pthread dependency local to libcxxabi. If there is some - // convenient way to detect precisely when pthread_mach_thread_np is - // available in a given Mac environment, it might still be possible to - // bury this dependency in __threading_support. - #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD - const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id()); - #else - #error "How do I pthread_mach_thread_np()?" - #endif - lock_type lock = get_lock(*guard_object); - if (lock) - { - // if this thread set lock for this same guard_object, abort - if (lock == id) - abort_message("__cxa_guard_acquire detected deadlock"); - do - { - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) - abort_message("__cxa_guard_acquire condition variable wait failed"); - lock = get_lock(*guard_object); - } while (lock); - result = !is_initialized(guard_object); - if (result) - set_lock(*guard_object, id); - } - else - set_lock(*guard_object, id); -#else // !__APPLE__ || __arm__ - while (get_lock(*guard_object)) - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) - abort_message("__cxa_guard_acquire condition variable wait failed"); - result = *initialized == 0; - if (result) - set_lock(*guard_object, true); -#endif // !__APPLE__ || __arm__ - } - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_acquire failed to release mutex"); - return result; -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_release failed to acquire mutex"); - *guard_object = 0; - set_initialized(guard_object); - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_release failed to release mutex"); - if (std::__libcpp_condvar_broadcast(&guard_cv)) - abort_message("__cxa_guard_release failed to broadcast condition variable"); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_abort failed to acquire mutex"); - *guard_object = 0; - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_abort failed to release mutex"); - if (std::__libcpp_condvar_broadcast(&guard_cv)) - abort_message("__cxa_guard_abort failed to broadcast condition variable"); -} - -#else // _LIBCXXABI_HAS_NO_THREADS - -_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { - return !is_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - *guard_object = 0; - set_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - *guard_object = 0; -} - -#endif // !_LIBCXXABI_HAS_NO_THREADS - -} // extern "C" - -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp deleted file mode 100644 index 8c26bd0b1a6..00000000000 --- a/lib/libcxxabi/src/cxa_handlers.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//===------------------------- cxa_handlers.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include "abort_message.h" -#include "cxxabi.h" -#include "cxa_handlers.hpp" -#include "cxa_exception.hpp" -#include "private_typeinfo.h" -#include "include/atomic_support.h" - -namespace std -{ - -unexpected_handler -get_unexpected() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire); -} - -void -__unexpected(unexpected_handler func) -{ - func(); - // unexpected handler should not return - abort_message("unexpected_handler unexpectedly returned"); -} - -__attribute__((noreturn)) -void -unexpected() -{ - __unexpected(get_unexpected()); -} - -terminate_handler -get_terminate() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire); -} - -void -__terminate(terminate_handler func) _NOEXCEPT -{ -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - func(); - // handler should not return - abort_message("terminate_handler unexpectedly returned"); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - // handler should not throw exception - abort_message("terminate_handler unexpectedly threw an exception"); - } -#endif // _LIBCXXABI_NO_EXCEPTIONS -} - -__attribute__((noreturn)) -void -terminate() _NOEXCEPT -{ - // If there might be an uncaught exception - using namespace __cxxabiv1; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals) - { - __cxa_exception* exception_header = globals->caughtExceptions; - if (exception_header) - { - _Unwind_Exception* unwind_exception = - reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; - if (__isOurExceptionClass(unwind_exception)) - __terminate(exception_header->terminateHandler); - } - } - __terminate(get_terminate()); -} - -extern "C" { -new_handler __cxa_new_handler = 0; -} - -new_handler -set_new_handler(new_handler handler) _NOEXCEPT -{ - return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); -} - -new_handler -get_new_handler() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire); -} - -} // std diff --git a/lib/libcxxabi/src/cxa_handlers.hpp b/lib/libcxxabi/src/cxa_handlers.hpp deleted file mode 100644 index 14c0e10119d..00000000000 --- a/lib/libcxxabi/src/cxa_handlers.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//===------------------------- cxa_handlers.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. -//===----------------------------------------------------------------------===// - -#ifndef _CXA_HANDLERS_H -#define _CXA_HANDLERS_H - -#include <__cxxabi_config.h> - -#include - -namespace std -{ - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN -void -__unexpected(unexpected_handler func); - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN -void -__terminate(terminate_handler func) _NOEXCEPT; - -} // std - -extern "C" -{ - -_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)(); -_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)(); -_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)(); - -/* - - At some point in the future these three symbols will become - C++11 atomic variables: - - extern std::atomic __cxa_terminate_handler; - extern std::atomic __cxa_unexpected_handler; - extern std::atomic __cxa_new_handler; - - This change will not impact their ABI. But it will allow for a - portable performance optimization. - -*/ - -} // extern "C" - -#endif // _CXA_HANDLERS_H diff --git a/lib/libcxxabi/src/cxa_noexception.cpp b/lib/libcxxabi/src/cxa_noexception.cpp deleted file mode 100644 index 8d5b5f2d00b..00000000000 --- a/lib/libcxxabi/src/cxa_noexception.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -// Support functions for the no-exceptions libc++ library - -#include "cxxabi.h" - -#include // for std::terminate -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" - -namespace __cxxabiv1 { - -extern "C" { - -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != nullptr) - std::terminate(); -} - -void -__cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != nullptr) - std::terminate(); -} - - -void *__cxa_current_primary_exception() throw() { return nullptr; } - -void -__cxa_rethrow_primary_exception(void* thrown_object) { - if (thrown_object != nullptr) - std::terminate(); -} - -bool -__cxa_uncaught_exception() throw() { return false; } - -unsigned int -__cxa_uncaught_exceptions() throw() { return 0; } - -} // extern "C" - -// provide dummy implementations for the 'no exceptions' case. -uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; } -void __setExceptionClass ( _Unwind_Exception*, uint64_t) {} -bool __isOurExceptionClass(const _Unwind_Exception*) { return false; } - -} // abi diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp deleted file mode 100644 index 468461df54a..00000000000 --- a/lib/libcxxabi/src/cxa_personality.cpp +++ /dev/null @@ -1,1325 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// http://www.intel.com/design/itanium/downloads/245358.htm -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include - -#include "__cxxabi_config.h" -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" -#include "private_typeinfo.h" -#include "unwind.h" - -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -#include -#include - -extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, - void *, PCONTEXT, - PDISPATCHER_CONTEXT, - _Unwind_Personality_Fn); -#endif - -/* - Exception Header Layout: - -+---------------------------+-----------------------------+---------------+ -| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | -+---------------------------+-----------------------------+---------------+ - ^ - | - +-------------------------------------------------------+ - | -+---------------------------+-----------------------------+ -| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | -+---------------------------+-----------------------------+ - - Exception Handling Table Layout: - -+-----------------+--------+ -| lpStartEncoding | (char) | -+---------+-------+--------+---------------+-----------------------+ -| lpStart | (encoded with lpStartEncoding) | defaults to funcStart | -+---------+-----+--------+-----------------+---------------+-------+ -| ttypeEncoding | (char) | Encoding of the type_info table | -+---------------+-+------+----+----------------------------+----------------+ -| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null | -+-----------------++--------+-+----------------------------+----------------+ -| callSiteEncoding | (char) | Encoding for Call Site Table | -+------------------+--+-----+-----+------------------------+--------------------------+ -| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | -+---------------------+-----------+---------------------------------------------------+ -#ifndef __USING_SJLJ_EXCEPTIONS__ -+---------------------+-----------+------------------------------------------------+ -| Beginning of Call Site Table The current ip lies within the | -| ... (start, length) range of one of these | -| call sites. There may be action needed. | -| +-------------+---------------------------------+------------------------------+ | -| | start | (encoded with callSiteEncoding) | offset relative to funcStart | | -| | length | (encoded with callSiteEncoding) | length of code fragment | | -| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | | -| | actionEntry | (ULEB128) | Action Table Index 1-based | | -| | | | actionEntry == 0 -> cleanup | | -| +-------------+---------------------------------+------------------------------+ | -| ... | -+----------------------------------------------------------------------------------+ -#else // __USING_SJLJ_EXCEPTIONS__ -+---------------------+-----------+------------------------------------------------+ -| Beginning of Call Site Table The current ip is a 1-based index into | -| ... this table. Or it is -1 meaning no | -| action is needed. Or it is 0 meaning | -| terminate. | -| +-------------+---------------------------------+------------------------------+ | -| | landingPad | (ULEB128) | offset relative to lpStart | | -| | actionEntry | (ULEB128) | Action Table Index 1-based | | -| | | | actionEntry == 0 -> cleanup | | -| +-------------+---------------------------------+------------------------------+ | -| ... | -+----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ -+---------------------------------------------------------------------+ -| Beginning of Action Table ttypeIndex == 0 : cleanup | -| ... ttypeIndex > 0 : catch | -| ttypeIndex < 0 : exception spec | -| +--------------+-----------+--------------------------------------+ | -| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | | -| | actionOffset | (SLEB128) | Offset into next Action Table entry | | -| +--------------+-----------+--------------------------------------+ | -| ... | -+---------------------------------------------------------------------+-----------------+ -| type_info Table, but classInfoOffset does *not* point here! | -| +----------------+------------------------------------------------+-----------------+ | -| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | | -| +----------------+------------------------------------------------+-----------------+ | -| ... | -| +----------------+------------------------------------------------+-----------------+ | -| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | | -| +----------------+------------------------------------------------+-----------------+ | -| +---------------------------------------+-----------+------------------------------+ | -| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | | -| | ... | (ULEB128) | | | -| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | | -| | 0 | (ULEB128) | | | -| +---------------------------------------+------------------------------------------+ | -| ... | -| +---------------------------------------+------------------------------------------+ | -| | 0 | (ULEB128) | throw() | | -| +---------------------------------------+------------------------------------------+ | -| ... | -| +---------------------------------------+------------------------------------------+ | -| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | | -| | ... | (ULEB128) | | | -| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | | -| | 0 | (ULEB128) | | | -| +---------------------------------------+------------------------------------------+ | -+---------------------------------------------------------------------------------------+ - -Notes: - -* ttypeIndex in the Action Table, and in the exception spec table, is an index, - not a byte count, if positive. It is a negative index offset of - classInfoOffset and the sizeof entry depends on ttypeEncoding. - But if ttypeIndex is negative, it is a positive 1-based byte offset into the - type_info Table. - And if ttypeIndex is zero, it refers to a catch (...). - -* landingPad can be 0, this implies there is nothing to be done. - -* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done - @landingPad. - -* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in - the Action Table with ttypeIndex == 0. -*/ - -namespace __cxxabiv1 -{ - -namespace -{ - -template -uintptr_t readPointerHelper(const uint8_t*& p) { - AsType value; - memcpy(&value, p, sizeof(AsType)); - p += sizeof(AsType); - return static_cast(value); -} - -} // end namespace - -extern "C" -{ - -// private API - -// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp - -// DWARF Constants -enum -{ - DW_EH_PE_absptr = 0x00, - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - DW_EH_PE_indirect = 0x80, - DW_EH_PE_omit = 0xFF -}; - -/// Read a uleb128 encoded value and advance pointer -/// See Variable Length Data Appendix C in: -/// @link http://dwarfstd.org/Dwarf4.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @returns decoded value -static -uintptr_t -readULEB128(const uint8_t** data) -{ - uintptr_t result = 0; - uintptr_t shift = 0; - unsigned char byte; - const uint8_t *p = *data; - do - { - byte = *p++; - result |= static_cast(byte & 0x7F) << shift; - shift += 7; - } while (byte & 0x80); - *data = p; - return result; -} - -/// Read a sleb128 encoded value and advance pointer -/// See Variable Length Data Appendix C in: -/// @link http://dwarfstd.org/Dwarf4.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @returns decoded value -static -intptr_t -readSLEB128(const uint8_t** data) -{ - uintptr_t result = 0; - uintptr_t shift = 0; - unsigned char byte; - const uint8_t *p = *data; - do - { - byte = *p++; - result |= static_cast(byte & 0x7F) << shift; - shift += 7; - } while (byte & 0x80); - *data = p; - if ((byte & 0x40) && (shift < (sizeof(result) << 3))) - result |= static_cast(~0) << shift; - return static_cast(result); -} - -/// Read a pointer encoded value and advance pointer -/// See Variable Length Data in: -/// @link http://dwarfstd.org/Dwarf3.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @param encoding dwarf encoding type -/// @returns decoded value -static -uintptr_t -readEncodedPointer(const uint8_t** data, uint8_t encoding) -{ - uintptr_t result = 0; - if (encoding == DW_EH_PE_omit) - return result; - const uint8_t* p = *data; - // first get value - switch (encoding & 0x0F) - { - case DW_EH_PE_absptr: - result = readPointerHelper(p); - break; - case DW_EH_PE_uleb128: - result = readULEB128(&p); - break; - case DW_EH_PE_sleb128: - result = static_cast(readSLEB128(&p)); - break; - case DW_EH_PE_udata2: - result = readPointerHelper(p); - break; - case DW_EH_PE_udata4: - result = readPointerHelper(p); - break; - case DW_EH_PE_udata8: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata2: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata4: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata8: - result = readPointerHelper(p); - break; - default: - // not supported - abort(); - break; - } - // then add relative offset - switch (encoding & 0x70) - { - case DW_EH_PE_absptr: - // do nothing - break; - case DW_EH_PE_pcrel: - if (result) - result += (uintptr_t)(*data); - break; - case DW_EH_PE_textrel: - case DW_EH_PE_datarel: - case DW_EH_PE_funcrel: - case DW_EH_PE_aligned: - default: - // not supported - abort(); - break; - } - // then apply indirection - if (result && (encoding & DW_EH_PE_indirect)) - result = *((uintptr_t*)result); - *data = p; - return result; -} - -static -void -call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) -{ - __cxa_begin_catch(unwind_exception); - if (native_exception) - { - // Use the stored terminate_handler if possible - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - std::__terminate(exception_header->terminateHandler); - } - std::terminate(); -} - -#if defined(_LIBCXXABI_ARM_EHABI) -static const void* read_target2_value(const void* ptr) -{ - uintptr_t offset = *reinterpret_cast(ptr); - if (!offset) - return 0; - // "ARM EABI provides a TARGET2 relocation to describe these typeinfo - // pointers. The reason being it allows their precise semantics to be - // deferred to the linker. For bare-metal they turn into absolute - // relocations. For linux they turn into GOT-REL relocations." - // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html -#if defined(LIBCXXABI_BAREMETAL) - return reinterpret_cast(reinterpret_cast(ptr) + - offset); -#else - return *reinterpret_cast(reinterpret_cast(ptr) + - offset); -#endif -} - -static const __shim_type_info* -get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); - return reinterpret_cast( - read_target2_value(ttypePtr)); -} -#else // !defined(_LIBCXXABI_ARM_EHABI) -static -const __shim_type_info* -get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - switch (ttypeEncoding & 0x0F) - { - case DW_EH_PE_absptr: - ttypeIndex *= sizeof(void*); - break; - case DW_EH_PE_udata2: - case DW_EH_PE_sdata2: - ttypeIndex *= 2; - break; - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - ttypeIndex *= 4; - break; - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - ttypeIndex *= 8; - break; - default: - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - classInfo -= ttypeIndex; - return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); -} -#endif // !defined(_LIBCXXABI_ARM_EHABI) - -/* - This is checking a thrown exception type, excpType, against a possibly empty - list of catchType's which make up an exception spec. - - An exception spec acts like a catch handler, but in reverse. This "catch - handler" will catch an excpType if and only if none of the catchType's in - the list will catch a excpType. If any catchType in the list can catch an - excpType, then this exception spec does not catch the excpType. -*/ -#if defined(_LIBCXXABI_ARM_EHABI) -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const void** temp = reinterpret_cast( - reinterpret_cast(classInfo) + - static_cast(specIndex) * sizeof(uintptr_t)); - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - // ARM EHABI exception specification table (filter table) consists of - // several pointers which will directly point to the type info object - // (instead of ttypeIndex). The table will be terminated with 0. - const void** ttypePtr = temp++; - if (*ttypePtr == 0) - break; - // We can get the __shim_type_info simply by performing a - // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. - const __shim_type_info* catchType = - static_cast(read_target2_value(ttypePtr)); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; -} -#else -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const uint8_t* temp = classInfo + specIndex; - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - uint64_t ttypeIndex = readULEB128(&temp); - if (ttypeIndex == 0) - break; - const __shim_type_info* catchType = get_shim_type_info(ttypeIndex, - classInfo, - ttypeEncoding, - true, - unwind_exception); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; -} -#endif - -static -void* -get_thrown_object_ptr(_Unwind_Exception* unwind_exception) -{ - // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1 - // Regardless, this library is prohibited from touching a foreign exception - void* adjustedPtr = unwind_exception + 1; - if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass) - adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException; - return adjustedPtr; -} - -namespace -{ - -struct scan_results -{ - int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup - const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance. - const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected - uintptr_t landingPad; // null -> nothing found, else something found - void* adjustedPtr; // Used in cxa_exception.cpp - _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR, - // _URC_FATAL_PHASE2_ERROR, - // _URC_CONTINUE_UNWIND, - // _URC_HANDLER_FOUND -}; - -} // unnamed namespace - -static -void -set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, - const scan_results& results) -{ -#if defined(__USING_SJLJ_EXCEPTIONS__) -#define __builtin_eh_return_data_regno(regno) regno -#endif - _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), - reinterpret_cast(unwind_exception)); - _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), - static_cast(results.ttypeIndex)); - _Unwind_SetIP(context, results.landingPad); -} - -/* - There are 3 types of scans needed: - - 1. Scan for handler with native or foreign exception. If handler found, - save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. - May also report an error on invalid input. - May terminate for invalid exception table. - _UA_SEARCH_PHASE - - 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND, - or call terminate. - _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception - - 3. Scan for cleanups. If a handler is found and this isn't forced unwind, - then terminate, otherwise ignore the handler and keep looking for cleanup. - If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. - May also report an error on invalid input. - May terminate for invalid exception table. - _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME -*/ - -static void scan_eh_tab(scan_results &results, _Unwind_Action actions, - bool native_exception, - _Unwind_Exception *unwind_exception, - _Unwind_Context *context) { - // Initialize results to found nothing but an error - results.ttypeIndex = 0; - results.actionRecord = 0; - results.languageSpecificData = 0; - results.landingPad = 0; - results.adjustedPtr = 0; - results.reason = _URC_FATAL_PHASE1_ERROR; - // Check for consistent actions - if (actions & _UA_SEARCH_PHASE) - { - // Do Phase 1 - if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) - { - // None of these flags should be set during Phase 1 - // Client error - results.reason = _URC_FATAL_PHASE1_ERROR; - return; - } - } - else if (actions & _UA_CLEANUP_PHASE) - { - if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) - { - // _UA_HANDLER_FRAME should only be set if phase 1 found a handler. - // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened. - // Client error - results.reason = _URC_FATAL_PHASE2_ERROR; - return; - } - } - else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set - { - // One of these should be set. - // Client error - results.reason = _URC_FATAL_PHASE1_ERROR; - return; - } - // Start scan by getting exception table address - const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); - if (lsda == 0) - { - // There is no exception table - results.reason = _URC_CONTINUE_UNWIND; - return; - } - results.languageSpecificData = lsda; - // Get the current instruction pointer and offset it before next - // instruction in the current frame which threw the exception. - uintptr_t ip = _Unwind_GetIP(context) - 1; - // Get beginning current frame's code (as defined by the - // emitted dwarf code) - uintptr_t funcStart = _Unwind_GetRegionStart(context); -#ifdef __USING_SJLJ_EXCEPTIONS__ - if (ip == uintptr_t(-1)) - { - // no action - results.reason = _URC_CONTINUE_UNWIND; - return; - } - else if (ip == 0) - call_terminate(native_exception, unwind_exception); - // ip is 1-based index into call site table -#else // !__USING_SJLJ_EXCEPTIONS__ - uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) - const uint8_t* classInfo = NULL; - // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding - // dwarf emission - // Parse LSDA header. - uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); - if (lpStart == 0) - lpStart = (const uint8_t*)funcStart; - uint8_t ttypeEncoding = *lsda++; - if (ttypeEncoding != DW_EH_PE_omit) - { - // Calculate type info locations in emitted dwarf code which - // were flagged by type info arguments to llvm.eh.selector - // intrinsic - uintptr_t classInfoOffset = readULEB128(&lsda); - classInfo = lsda + classInfoOffset; - } - // Walk call-site table looking for range that - // includes current PC. - uint8_t callSiteEncoding = *lsda++; -#ifdef __USING_SJLJ_EXCEPTIONS__ - (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used -#endif - uint32_t callSiteTableLength = static_cast(readULEB128(&lsda)); - const uint8_t* callSiteTableStart = lsda; - const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; - const uint8_t* actionTableStart = callSiteTableEnd; - const uint8_t* callSitePtr = callSiteTableStart; - while (callSitePtr < callSiteTableEnd) - { - // There is one entry per call site. -#ifndef __USING_SJLJ_EXCEPTIONS__ - // The call sites are non-overlapping in [start, start+length) - // The call sites are ordered in increasing value of start - uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t actionEntry = readULEB128(&callSitePtr); - if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __USING_SJLJ_EXCEPTIONS__ - // ip is 1-based index into this table - uintptr_t landingPad = readULEB128(&callSitePtr); - uintptr_t actionEntry = readULEB128(&callSitePtr); - if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ - { - // Found the call site containing ip. -#ifndef __USING_SJLJ_EXCEPTIONS__ - if (landingPad == 0) - { - // No handler here - results.reason = _URC_CONTINUE_UNWIND; - return; - } - landingPad = (uintptr_t)lpStart + landingPad; -#else // __USING_SJLJ_EXCEPTIONS__ - ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ - if (actionEntry == 0) - { - // Found a cleanup - // If this is a type 1 or type 2 search, there are no handlers - // If this is a type 3 search, you want to install the cleanup. - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - results.ttypeIndex = 0; // Redundant but clarifying - results.landingPad = landingPad; - results.reason = _URC_HANDLER_FOUND; - return; - } - // No handler here - results.reason = _URC_CONTINUE_UNWIND; - return; - } - // Convert 1-based byte offset into - const uint8_t* action = actionTableStart + (actionEntry - 1); - // Scan action entries until you find a matching handler, cleanup, or the end of action list - while (true) - { - const uint8_t* actionRecord = action; - int64_t ttypeIndex = readSLEB128(&action); - if (ttypeIndex > 0) - { - // Found a catch, does it actually catch? - // First check for catch (...) - const __shim_type_info* catchType = - get_shim_type_info(static_cast(ttypeIndex), - classInfo, ttypeEncoding, - native_exception, unwind_exception); - if (catchType == 0) - { - // Found catch (...) catches everything, including foreign exceptions - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 2 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - // Else this is a catch (T) clause and will never - // catch a foreign exception - else if (native_exception) - { - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - void* adjustedPtr = get_thrown_object_ptr(unwind_exception); - const __shim_type_info* excpType = - static_cast(exception_header->exceptionType); - if (adjustedPtr == 0 || excpType == 0) - { - // Something very bad happened - call_terminate(native_exception, unwind_exception); - } - if (catchType->can_catch(excpType, adjustedPtr)) - { - // Found a matching handler - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - } - // Scan next action ... - } - else if (ttypeIndex < 0) - { - // Found an exception spec. If this is a foreign exception, - // it is always caught. - if (native_exception) - { - // Does the exception spec catch this native exception? - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - void* adjustedPtr = get_thrown_object_ptr(unwind_exception); - const __shim_type_info* excpType = - static_cast(exception_header->exceptionType); - if (adjustedPtr == 0 || excpType == 0) - { - // Something very bad happened - call_terminate(native_exception, unwind_exception); - } - if (exception_spec_can_catch(ttypeIndex, classInfo, - ttypeEncoding, excpType, - adjustedPtr, unwind_exception)) - { - // native exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - } - else - { - // foreign exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 2 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - // Scan next action ... - } - else // ttypeIndex == 0 - { - // Found a cleanup - // If this is a type 1 search, ignore it and continue scan - // If this is a type 2 search, ignore it and continue scan - // If this is a type 3 search, save state and return _URC_HANDLER_FOUND - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - } - const uint8_t* temp = action; - int64_t actionOffset = readSLEB128(&temp); - if (actionOffset == 0) - { - // End of action list, no matching handler or cleanup found - results.reason = _URC_CONTINUE_UNWIND; - return; - } - // Go to next action - action += actionOffset; - } // there is no break out of this loop, only return - } -#ifndef __USING_SJLJ_EXCEPTIONS__ - else if (ipOffset < start) - { - // There is no call site for this ip - // Something bad has happened. We should never get here. - // Possible stack corruption. - call_terminate(native_exception, unwind_exception); - } -#endif // !__USING_SJLJ_EXCEPTIONS__ - } // there might be some tricky cases which break out of this loop - - // It is possible that no eh table entry specify how to handle - // this exception. By spec, terminate it immediately. - call_terminate(native_exception, unwind_exception); -} - -// public API - -/* -The personality function branches on actions like so: - -_UA_SEARCH_PHASE - - If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's - an error from above, return _URC_FATAL_PHASE1_ERROR. - - Scan for anything that could stop unwinding: - - 1. A catch clause that will catch this exception - (will never catch foreign). - 2. A catch (...) (will always catch foreign). - 3. An exception spec that will catch this exception - (will always catch foreign). - If a handler is found - If not foreign - Save state in header - return _URC_HANDLER_FOUND - Else a handler not found - return _URC_CONTINUE_UNWIND - -_UA_CLEANUP_PHASE - - If _UA_HANDLER_FRAME - If _UA_FORCE_UNWIND - How did this happen? return _URC_FATAL_PHASE2_ERROR - If foreign - Do _UA_SEARCH_PHASE to recover state - else - Recover state from header - Transfer control to landing pad. return _URC_INSTALL_CONTEXT - - Else - - This branch handles both normal C++ non-catching handlers (cleanups) - and forced unwinding. - Scan for anything that can not stop unwinding: - - 1. A cleanup. - - If a cleanup is found - transfer control to it. return _URC_INSTALL_CONTEXT - Else a cleanup is not found: return _URC_CONTINUE_UNWIND -*/ - -#if !defined(_LIBCXXABI_ARM_EHABI) -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -static _Unwind_Reason_Code __gxx_personality_imp -#else -_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code -#ifdef __USING_SJLJ_EXCEPTIONS__ -__gxx_personality_sj0 -#else -__gxx_personality_v0 -#endif -#endif - (int version, _Unwind_Action actions, uint64_t exceptionClass, - _Unwind_Exception* unwind_exception, _Unwind_Context* context) -{ - if (version != 1 || unwind_exception == 0 || context == 0) - return _URC_FATAL_PHASE1_ERROR; - - bool native_exception = (exceptionClass & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); - scan_results results; - if (actions & _UA_SEARCH_PHASE) - { - // Phase 1 search: All we're looking for in phase 1 is a handler that - // halts unwinding - scan_eh_tab(results, actions, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - // Found one. Can we cache the results somewhere to optimize phase 2? - if (native_exception) - { - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - exception_header->handlerSwitchValue = static_cast(results.ttypeIndex); - exception_header->actionRecord = results.actionRecord; - exception_header->languageSpecificData = results.languageSpecificData; - exception_header->catchTemp = reinterpret_cast(results.landingPad); - exception_header->adjustedPtr = results.adjustedPtr; - } - return _URC_HANDLER_FOUND; - } - // Did not find a catching-handler. Return the results of the scan - // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR - // if we were called improperly). - return results.reason; - } - if (actions & _UA_CLEANUP_PHASE) - { - // Phase 2 search: - // Did we find a catching handler in phase 1? - if (actions & _UA_HANDLER_FRAME) - { - // Yes, phase 1 said we have a catching handler here. - // Did we cache the results of the scan? - if (native_exception) - { - // Yes, reload the results from the cache. - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - results.ttypeIndex = exception_header->handlerSwitchValue; - results.actionRecord = exception_header->actionRecord; - results.languageSpecificData = exception_header->languageSpecificData; - results.landingPad = reinterpret_cast(exception_header->catchTemp); - results.adjustedPtr = exception_header->adjustedPtr; - } - else - { - // No, do the scan again to reload the results. - scan_eh_tab(results, actions, native_exception, unwind_exception, context); - // Phase 1 told us we would find a handler. Now in Phase 2 we - // didn't find a handler. The eh table should not be changing! - if (results.reason != _URC_HANDLER_FOUND) - call_terminate(native_exception, unwind_exception); - } - // Jump to the handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - // 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, actions, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - // Found a non-catching handler. Jump to it: - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - // Did not find a cleanup. Return the results of the scan - // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR - // if we were called improperly). - return results.reason; - } - // We were called improperly: neither a phase 1 or phase 2 search - return _URC_FATAL_PHASE1_ERROR; -} - -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION -__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame, - PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) -{ - return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp, - __gxx_personality_imp); -} -#endif - -#else - -extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, - _Unwind_Context*); - -// Helper function to unwind one frame. -// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the -// personality routine should update the virtual register set (VRS) according to the -// corresponding frame unwinding instructions (ARM EHABI 9.3.) -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; - return _URC_CONTINUE_UNWIND; -} - -// ARM register names -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) -static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block -#endif -static const uint32_t REG_SP = 13; - -static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception, - const scan_results& results) -{ - unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr; - unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord; - unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData; - unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad; - unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex; -} - -static void load_results_from_barrier_cache(scan_results& results, - const _Unwind_Exception* unwind_exception) -{ - results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0]; - results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1]; - results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; - results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3]; - results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; -} - -extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code -__gxx_personality_v0(_Unwind_State state, - _Unwind_Exception* unwind_exception, - _Unwind_Context* context) -{ - if (unwind_exception == 0 || context == 0) - return _URC_FATAL_PHASE1_ERROR; - - bool native_exception = __isOurExceptionClass(unwind_exception); - -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) - // Copy the address of _Unwind_Control_Block to r12 so that - // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can - // return correct address. - _Unwind_SetGR(context, REG_UCB, reinterpret_cast(unwind_exception)); -#endif - - // Check the undocumented force unwinding behavior - bool is_force_unwinding = state & _US_FORCE_UNWIND; - state &= ~_US_FORCE_UNWIND; - - scan_results results; - switch (state) { - case _US_VIRTUAL_UNWIND_FRAME: - if (is_force_unwinding) - return continue_unwind(unwind_exception, context); - - // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding - scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP); - if (native_exception) - save_results_to_barrier_cache(unwind_exception, results); - return _URC_HANDLER_FOUND; - } - // Did not find the catch handler - if (results.reason == _URC_CONTINUE_UNWIND) - return continue_unwind(unwind_exception, context); - return results.reason; - - case _US_UNWIND_FRAME_STARTING: - // TODO: Support force unwinding in the phase 2 search. - // NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind() - // will call this personality function with (_US_FORCE_UNWIND | - // _US_UNWIND_FRAME_STARTING). - - // Phase 2 search - if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP)) - { - // Found a catching handler in phase 1 - if (native_exception) - { - // Load the result from the native exception barrier cache. - load_results_from_barrier_cache(results, unwind_exception); - results.reason = _URC_HANDLER_FOUND; - } - else - { - // Search for the catching handler again for the foreign exception. - scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME), - native_exception, unwind_exception, context); - if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one - call_terminate(native_exception, unwind_exception); - } - - // Install the context for the catching handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - - // 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 (results.reason == _URC_HANDLER_FOUND) - { - // Found a non-catching handler - - // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some - // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from - // __cxa_get_globals(). - __cxa_begin_cleanup(unwind_exception); - - // Install the context for the cleanup handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - - // Did not find any handler - if (results.reason == _URC_CONTINUE_UNWIND) - return continue_unwind(unwind_exception, context); - return results.reason; - - case _US_UNWIND_FRAME_RESUME: - return continue_unwind(unwind_exception, context); - } - - // We were called improperly: neither a phase 1 or phase 2 search - return _URC_FATAL_PHASE1_ERROR; -} -#endif - - -__attribute__((noreturn)) -_LIBCXXABI_FUNC_VIS void -__cxa_call_unexpected(void* arg) -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); - if (unwind_exception == 0) - call_terminate(false, unwind_exception); - __cxa_begin_catch(unwind_exception); - bool native_old_exception = __isOurExceptionClass(unwind_exception); - std::unexpected_handler u_handler; - std::terminate_handler t_handler; - __cxa_exception* old_exception_header = 0; - int64_t ttypeIndex; - const uint8_t* lsda; - if (native_old_exception) - { - old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - t_handler = old_exception_header->terminateHandler; - u_handler = old_exception_header->unexpectedHandler; - // If std::__unexpected(u_handler) rethrows the same exception, - // these values get overwritten by the rethrow. So save them now: -#if defined(_LIBCXXABI_ARM_EHABI) - ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; - lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; -#else - ttypeIndex = old_exception_header->handlerSwitchValue; - lsda = old_exception_header->languageSpecificData; -#endif - } - else - { - t_handler = std::get_terminate(); - u_handler = std::get_unexpected(); - } - try - { - std::__unexpected(u_handler); - } - catch (...) - { - // If the old exception is foreign, then all we can do is terminate. - // We have no way to recover the needed old exception spec. There's - // no way to pass that information here. And the personality routine - // can't call us directly and do anything but terminate() if we throw - // from here. - if (native_old_exception) - { - // Have: - // old_exception_header->languageSpecificData - // old_exception_header->actionRecord - // Need - // const uint8_t* classInfo - // uint8_t ttypeEncoding - uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); - (void)lpStart; // purposefully unused. Just needed to increment lsda. - uint8_t ttypeEncoding = *lsda++; - if (ttypeEncoding == DW_EH_PE_omit) - std::__terminate(t_handler); - uintptr_t classInfoOffset = readULEB128(&lsda); - const uint8_t* classInfo = lsda + classInfoOffset; - // Is this new exception catchable by the exception spec at ttypeIndex? - // The answer is obviously yes if the new and old exceptions are the same exception - // If no - // throw; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - __cxa_exception* new_exception_header = globals->caughtExceptions; - if (new_exception_header == 0) - // This shouldn't be able to happen! - std::__terminate(t_handler); - bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader); - void* adjustedPtr; - if (native_new_exception && (new_exception_header != old_exception_header)) - { - const __shim_type_info* excpType = - static_cast(new_exception_header->exceptionType); - adjustedPtr = - __getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)new_exception_header)->primaryException : - new_exception_header + 1; - if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch, but for the old exception, - // not the new one. This is a little tricky ... - // Disguise new_exception_header as a rethrown exception, but - // don't actually rethrow it. This means you can temporarily - // end the catch clause enclosing new_exception_header without - // __cxa_end_catch destroying new_exception_header. - new_exception_header->handlerCount = -new_exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Call __cxa_end_catch for old_exception_header - __cxa_end_catch(); - // Renter this catch clause with new_exception_header - __cxa_begin_catch(&new_exception_header->unwindHeader); - // Rethrow new_exception_header - throw; - } - } - // Will a std::bad_exception be catchable by the exception spec at - // ttypeIndex? - // If no - // throw std::bad_exception(); - const __shim_type_info* excpType = - static_cast(&typeid(std::bad_exception)); - std::bad_exception be; - adjustedPtr = &be; - if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch for both the old exception and the - // new exception. Technically we should do it in that order. - // But it is expedient to do it in the opposite order: - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Throw std::bad_exception will __cxa_end_catch for - // old_exception_header - throw be; - } - } - } - std::__terminate(t_handler); -} - -} // extern "C" - -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_thread_atexit.cpp b/lib/libcxxabi/src/cxa_thread_atexit.cpp deleted file mode 100644 index 49d15d6b145..00000000000 --- a/lib/libcxxabi/src/cxa_thread_atexit.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===----------------------- cxa_thread_atexit.cpp ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "abort_message.h" -#include "cxxabi.h" -#include <__threading_support> -#include - -namespace __cxxabiv1 { - - using Dtor = void(*)(void*); - - extern "C" -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL - // A weak symbol is used to detect this function's presence in the C library - // at runtime, even if libc++ is built against an older libc - _LIBCXXABI_WEAK -#endif - int __cxa_thread_atexit_impl(Dtor, void*, void*); - -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL - -namespace { - // This implementation is used if the C library does not provide - // __cxa_thread_atexit_impl() for us. It has a number of limitations that are - // difficult to impossible to address without ..._impl(): - // - // - dso_symbol is ignored. This means that a shared library may be unloaded - // (via dlclose()) before its thread_local destructors have run. - // - // - thread_local destructors for the main thread are run by the destructor of - // a static object. This is later than expected; they should run before the - // destructors of any objects with static storage duration. - // - // - thread_local destructors on non-main threads run on the first iteration - // through the __libccpp_tls_key destructors. - // std::notify_all_at_thread_exit() and similar functions must be careful to - // wait until the second iteration to provide their intended ordering - // guarantees. - // - // Another limitation, though one shared with ..._impl(), is that any - // thread_locals that are first initialized after non-thread_local global - // destructors begin to run will not be destroyed. [basic.start.term] states - // that all thread_local destructors are sequenced before the destruction of - // objects with static storage duration, resulting in a contradiction if a - // thread_local is constructed after that point. Thus we consider such - // programs ill-formed, and don't bother to run those destructors. (If the - // program terminates abnormally after such a thread_local is constructed, - // the destructor is not expected to run and thus there is no contradiction. - // So construction still has to work.) - - struct DtorList { - Dtor dtor; - void* obj; - DtorList* next; - }; - - // The linked list of thread-local destructors to run - __thread DtorList* dtors = nullptr; - // True if the destructors are currently scheduled to run on this thread - __thread bool dtors_alive = false; - // Used to trigger destructors on thread exit; value is ignored - std::__libcpp_tls_key dtors_key; - - void run_dtors(void*) { - while (auto head = dtors) { - dtors = head->next; - head->dtor(head->obj); - std::free(head); - } - - dtors_alive = false; - } - - struct DtorsManager { - DtorsManager() { - // There is intentionally no matching std::__libcpp_tls_delete call, as - // __cxa_thread_atexit() may be called arbitrarily late (for example, from - // global destructors or atexit() handlers). - if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) { - abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()"); - } - } - - ~DtorsManager() { - // std::__libcpp_tls_key destructors do not run on threads that call exit() - // (including when the main thread returns from main()), so we explicitly - // call the destructor here. This runs at exit time (potentially earlier - // if libc++abi is dlclose()'d). Any thread_locals initialized after this - // point will not be destroyed. - run_dtors(nullptr); - } - }; -} // namespace - -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL - -extern "C" { - - _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() { -#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); -#else - if (__cxa_thread_atexit_impl) { - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); - } else { - // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for - // one-time initialization and __cxa_atexit() for destruction) - static DtorsManager manager; - - if (!dtors_alive) { - if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) { - return -1; - } - dtors_alive = true; - } - - auto head = static_cast(std::malloc(sizeof(DtorList))); - if (!head) { - return -1; - } - - head->dtor = dtor; - head->obj = obj; - head->next = dtors; - dtors = head; - - return 0; - } -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL - } - -} // extern "C" -} // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_unexpected.cpp b/lib/libcxxabi/src/cxa_unexpected.cpp deleted file mode 100644 index 7d4ef80c39e..00000000000 --- a/lib/libcxxabi/src/cxa_unexpected.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===------------------------- cxa_unexpected.cpp -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include -#include "cxxabi.h" -#include "cxa_exception.hpp" - -namespace __cxxabiv1 -{ - -extern "C" -{ - -} - -} // namespace __cxxabiv1 - diff --git a/lib/libcxxabi/src/cxa_vector.cpp b/lib/libcxxabi/src/cxa_vector.cpp deleted file mode 100644 index c32a2119756..00000000000 --- a/lib/libcxxabi/src/cxa_vector.cpp +++ /dev/null @@ -1,367 +0,0 @@ -//===-------------------------- cxa_vector.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Array Construction and Destruction APIs" -// http://mentorembedded.github.io/cxx-abi/abi.html#array-ctor -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" - -#include // for std::terminate - -namespace __cxxabiv1 { - -#if 0 -#pragma mark --Helper routines and classes -- -#endif - -namespace { - inline static size_t __get_element_count ( void *p ) { - return static_cast (p)[-1]; - } - - inline static void __set_element_count ( void *p, size_t element_count ) { - static_cast (p)[-1] = element_count; - } - - -// A pair of classes to simplify exception handling and control flow. -// They get passed a block of memory in the constructor, and unless the -// 'release' method is called, they deallocate the memory in the destructor. -// Preferred usage is to allocate some memory, attach it to one of these objects, -// and then, when all the operations to set up the memory block have succeeded, -// call 'release'. If any of the setup operations fail, or an exception is -// thrown, then the block is automatically deallocated. -// -// The only difference between these two classes is the signature for the -// deallocation function (to match new2/new3 and delete2/delete3. - class st_heap_block2 { - public: - typedef void (*dealloc_f)(void *); - - st_heap_block2 ( dealloc_f dealloc, void *ptr ) - : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {} - ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; } - void release () { enabled_ = false; } - - private: - dealloc_f dealloc_; - void *ptr_; - bool enabled_; - }; - - class st_heap_block3 { - public: - typedef void (*dealloc_f)(void *, size_t); - - st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size ) - : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {} - ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; } - void release () { enabled_ = false; } - - private: - dealloc_f dealloc_; - void *ptr_; - size_t size_; - bool enabled_; - }; - - class st_cxa_cleanup { - public: - typedef void (*destruct_f)(void *); - - st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor ) - : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ), - destructor_ ( destructor ), enabled_ ( true ) {} - ~st_cxa_cleanup () { - if ( enabled_ ) - __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ ); - } - - void release () { enabled_ = false; } - - private: - void *ptr_; - size_t &idx_; - size_t element_size_; - destruct_f destructor_; - bool enabled_; - }; - - class st_terminate { - public: - st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {} - ~st_terminate () { if ( enabled_ ) std::terminate (); } - void release () { enabled_ = false; } - private: - bool enabled_ ; - }; -} - -#if 0 -#pragma mark --Externally visible routines-- -#endif - -extern "C" { - -// Equivalent to -// -// __cxa_vec_new2(element_count, element_size, padding_size, constructor, -// destructor, &::operator new[], &::operator delete[]) -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *)) { - return __cxa_vec_new2 ( element_count, element_size, padding_size, - constructor, destructor, &::operator new [], &::operator delete [] ); -} - - - -// Given the number and size of elements for an array and the non-negative -// size of prefix padding for a cookie, allocate space (using alloc) for -// the array preceded by the specified padding, initialize the cookie if -// the padding is non-zero, and call the given constructor on each element. -// Return the address of the array proper, after the padding. -// -// If alloc throws an exception, rethrow the exception. If alloc returns -// NULL, return NULL. If the constructor throws an exception, call -// destructor for any already constructed elements, and rethrow the -// exception. If the destructor throws an exception, call std::terminate. -// -// The constructor may be NULL, in which case it must not be called. If the -// padding_size is zero, the destructor may be NULL; in that case it must -// not be called. -// -// Neither alloc nor dealloc may be NULL. -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *)) { - const size_t heap_size = element_count * element_size + padding_size; - char * const heap_block = static_cast ( alloc ( heap_size )); - char *vec_base = heap_block; - - if ( NULL != vec_base ) { - st_heap_block2 heap ( dealloc, heap_block ); - - // put the padding before the array elements - if ( 0 != padding_size ) { - vec_base += padding_size; - __set_element_count ( vec_base, element_count ); - } - - // Construct the elements - __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); - heap.release (); // We're good! - } - - return vec_base; -} - - -// Same as __cxa_vec_new2 except that the deallocation function takes both -// the object address and its size. -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) { - const size_t heap_size = element_count * element_size + padding_size; - char * const heap_block = static_cast ( alloc ( heap_size )); - char *vec_base = heap_block; - - if ( NULL != vec_base ) { - st_heap_block3 heap ( dealloc, heap_block, heap_size ); - - // put the padding before the array elements - if ( 0 != padding_size ) { - vec_base += padding_size; - __set_element_count ( vec_base, element_count ); - } - - // Construct the elements - __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); - heap.release (); // We're good! - } - - return vec_base; -} - - -// Given the (data) addresses of a destination and a source array, an -// element count and an element size, call the given copy constructor to -// copy each element from the source array to the destination array. The -// copy constructor's arguments are the destination address and source -// address, respectively. If an exception occurs, call the given destructor -// (if non-NULL) on each copied element and rethrow. If the destructor -// throws an exception, call terminate(). The constructor and or destructor -// pointers may be NULL. If either is NULL, no action is taken when it -// would have been called. - -_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array, - size_t element_count, - size_t element_size, - void (*constructor)(void *, void *), - void (*destructor)(void *)) { - if ( NULL != constructor ) { - size_t idx = 0; - char *src_ptr = static_cast(src_array); - char *dest_ptr = static_cast(dest_array); - st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor ); - - for ( idx = 0; idx < element_count; - ++idx, src_ptr += element_size, dest_ptr += element_size ) - constructor ( dest_ptr, src_ptr ); - cleanup.release (); // We're good! - } -} - - -// Given the (data) address of an array, not including any cookie padding, -// and the number and size of its elements, call the given constructor on -// each element. If the constructor throws an exception, call the given -// destructor for any already-constructed elements, and rethrow the -// exception. If the destructor throws an exception, call terminate(). The -// constructor and/or destructor pointers may be NULL. If either is NULL, -// no action is taken when it would have been called. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size, - void (*constructor)(void *), void (*destructor)(void *)) { - if ( NULL != constructor ) { - size_t idx; - char *ptr = static_cast ( array_address ); - st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); - - // Construct the elements - for ( idx = 0; idx < element_count; ++idx, ptr += element_size ) - constructor ( ptr ); - cleanup.release (); // We're good! - } -} - -// Given the (data) address of an array, the number of elements, and the -// size of its elements, call the given destructor on each element. If the -// destructor throws an exception, rethrow after destroying the remaining -// elements if possible. If the destructor throws a second exception, call -// terminate(). The destructor pointer may be NULL, in which case this -// routine does nothing. -_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)) { - if ( NULL != destructor ) { - char *ptr = static_cast (array_address); - size_t idx = element_count; - st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); - { - st_terminate exception_guard (__cxa_uncaught_exception ()); - ptr += element_count * element_size; // one past the last element - - while ( idx-- > 0 ) { - ptr -= element_size; - destructor ( ptr ); - } - exception_guard.release (); // We're good ! - } - cleanup.release (); // We're still good! - } -} - -// Given the (data) address of an array, the number of elements, and the -// size of its elements, call the given destructor on each element. If the -// destructor throws an exception, call terminate(). The destructor pointer -// may be NULL, in which case this routine does nothing. -_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)) { - if ( NULL != destructor ) { - char *ptr = static_cast (array_address); - size_t idx = element_count; - st_terminate exception_guard; - - ptr += element_count * element_size; // one past the last element - while ( idx-- > 0 ) { - ptr -= element_size; - destructor ( ptr ); - } - exception_guard.release (); // We're done! - } -} - - -// If the array_address is NULL, return immediately. Otherwise, given the -// (data) address of an array, the non-negative size of prefix padding for -// the cookie, and the size of its elements, call the given destructor on -// each element, using the cookie to determine the number of elements, and -// then delete the space by calling ::operator delete[](void *). If the -// destructor throws an exception, rethrow after (a) destroying the -// remaining elements, and (b) deallocating the storage. If the destructor -// throws a second exception, call terminate(). If padding_size is 0, the -// destructor pointer must be NULL. If the destructor pointer is NULL, no -// destructor call is to be made. -// -// The intent of this function is to permit an implementation to call this -// function when confronted with an expression of the form delete[] p in -// the source code, provided that the default deallocation function can be -// used. Therefore, the semantics of this function are consistent with -// those required by the standard. The requirement that the deallocation -// function be called even if the destructor throws an exception derives -// from the resolution to DR 353 to the C++ standard, which was adopted in -// April, 2003. -_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address, - size_t element_size, - size_t padding_size, - void (*destructor)(void *)) { - __cxa_vec_delete2 ( array_address, element_size, padding_size, - destructor, &::operator delete [] ); -} - -// Same as __cxa_vec_delete, except that the given function is used for -// deallocation instead of the default delete function. If dealloc throws -// an exception, the result is undefined. The dealloc pointer may not be -// NULL. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size, - void (*destructor)(void *), void (*dealloc)(void *)) { - if ( NULL != array_address ) { - char *vec_base = static_cast (array_address); - char *heap_block = vec_base - padding_size; - st_heap_block2 heap ( dealloc, heap_block ); - - if ( 0 != padding_size && NULL != destructor ) // call the destructors - __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ), - element_size, destructor ); - } -} - - -// Same as __cxa_vec_delete, except that the given function is used for -// deallocation instead of the default delete function. The deallocation -// function takes both the object address and its size. If dealloc throws -// an exception, the result is undefined. The dealloc pointer may not be -// NULL. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size, - void (*destructor)(void *), void (*dealloc)(void *, size_t)) { - if ( NULL != array_address ) { - char *vec_base = static_cast (array_address); - char *heap_block = vec_base - padding_size; - const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0; - const size_t heap_block_size = element_size * element_count + padding_size; - st_heap_block3 heap ( dealloc, heap_block, heap_block_size ); - - if ( 0 != padding_size && NULL != destructor ) // call the destructors - __cxa_vec_dtor ( array_address, element_count, element_size, destructor ); - } -} - - -} // extern "C" - -} // abi diff --git a/lib/libcxxabi/src/cxa_virtual.cpp b/lib/libcxxabi/src/cxa_virtual.cpp deleted file mode 100644 index f59fa7ee2c6..00000000000 --- a/lib/libcxxabi/src/cxa_virtual.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===-------------------------- cxa_virtual.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" -#include "abort_message.h" - -namespace __cxxabiv1 { -extern "C" { -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN -void __cxa_pure_virtual(void) { - abort_message("Pure virtual function called!"); -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN -void __cxa_deleted_virtual(void) { - abort_message("Deleted virtual function called!"); -} -} // extern "C" -} // abi diff --git a/lib/libcxxabi/src/demangle/Compiler.h b/lib/libcxxabi/src/demangle/Compiler.h deleted file mode 100644 index e5f3c72a451..00000000000 --- a/lib/libcxxabi/src/demangle/Compiler.h +++ /dev/null @@ -1,34 +0,0 @@ -//===--- Compiler.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// This file is contains a subset of macros copied from -// llvm/lib/Demangle/Compiler.h. -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_COMPILER_H -#define LIBCXX_DEMANGLE_COMPILER_H - -#ifdef _MSC_VER -// snprintf is implemented in VS 2015 -#if _MSC_VER < 1900 -#define snprintf _snprintf_s -#endif -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#ifndef NDEBUG -#if __has_attribute(noinline) && __has_attribute(used) -#define DUMP_METHOD __attribute__((noinline, used)) -#else -#define DUMP_METHOD -#endif -#endif - -#endif diff --git a/lib/libcxxabi/src/demangle/ItaniumDemangle.h b/lib/libcxxabi/src/demangle/ItaniumDemangle.h deleted file mode 100644 index 9e9d183da7c..00000000000 --- a/lib/libcxxabi/src/demangle/ItaniumDemangle.h +++ /dev/null @@ -1,5189 +0,0 @@ -//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// WARNING: This file defines its contents within an anonymous namespace. It -// should not be included anywhere other than cxa_demangle.h. -// -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H -#define LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - -#include "Compiler.h" -#include "StringView.h" -#include "Utility.h" - -#include -#include -#include -#include -#include -#include -#include - -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(BoolExpr) \ - X(IntegerCastExpr) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - -namespace { -namespace itanium_demangle { -// 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 { -public: - enum Kind : unsigned char { -#define ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR - }; - - /// Three-way bool to track a cached value. Unknown is possible if this node - /// has an unexpanded parameter pack below it that may affect this cache. - enum class Cache : unsigned char { Yes, No, Unknown, }; - -private: - Kind K; - - // FIXME: Make these protected. -public: - /// Tracks if this node has a component on its right side, in which case we - /// need to call printRight. - Cache RHSComponentCache; - - /// Track if this node is a (possibly qualified) array type. This can affect - /// how we format the output string. - Cache ArrayCache; - - /// Track if this node is a (possibly qualified) function type. This can - /// affect how we format the output string. - Cache FunctionCache; - -public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} - - /// Visit the most-derived object corresponding to this object. - template void visit(Fn F) const; - - // The following function is provided by all derived classes: - // - // Call F with arguments that, when passed to the constructor of this node, - // would construct an equivalent node. - //template void match(Fn F) const; - - bool hasRHSComponent(OutputStream &S) const { - if (RHSComponentCache != Cache::Unknown) - return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); - } - - bool hasArray(OutputStream &S) const { - if (ArrayCache != Cache::Unknown) - return ArrayCache == Cache::Yes; - return hasArraySlow(S); - } - - bool hasFunction(OutputStream &S) const { - if (FunctionCache != Cache::Unknown) - return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); - } - - 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; } - - // 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; - } - - void print(OutputStream &S) const { - printLeft(S); - if (RHSComponentCache != Cache::No) - printRight(S); - } - - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) 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 StringView getBaseName() const { return StringView(); } - - // Silence compiler warnings, this dtor will never be called. - virtual ~Node() = default; - -#ifndef NDEBUG - DUMP_METHOD void dump() const; -#endif -}; - -class NodeArray { - Node **Elements; - size_t NumElements; - -public: - NodeArray() : Elements(nullptr), NumElements(0) {} - NodeArray(Node **Elements_, size_t NumElements_) - : Elements(Elements_), NumElements(NumElements_) {} - - bool empty() const { return NumElements == 0; } - size_t size() const { return NumElements; } - - Node **begin() const { return Elements; } - Node **end() const { return Elements + NumElements; } - - Node *operator[](size_t Idx) const { return Elements[Idx]; } - - void printWithComma(OutputStream &S) const { - bool FirstElement = true; - for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); - if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); - - // Elements[Idx] is an empty parameter pack expansion, we should erase the - // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); - continue; - } - - FirstElement = false; - } - } -}; - -struct NodeArrayNode : Node { - NodeArray Array; - NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} - - template void match(Fn F) const { F(Array); } - - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } -}; - -class DotSuffix final : public Node { - const Node *Prefix; - const StringView Suffix; - -public: - DotSuffix(const Node *Prefix_, StringView Suffix_) - : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} - - template void match(Fn F) const { F(Prefix, Suffix); } - - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; - } -}; - -class VendorExtQualType final : public Node { - const Node *Ty; - StringView Ext; - -public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} - - template void match(Fn F) const { F(Ty, Ext); } - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; - } -}; - -enum FunctionRefQual : unsigned char { - FrefQualNone, - FrefQualLValue, - FrefQualRValue, -}; - -enum Qualifiers { - QualNone = 0, - QualConst = 0x1, - QualVolatile = 0x2, - QualRestrict = 0x4, -}; - -inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { - return Q1 = static_cast(Q1 | Q2); -} - -class QualType : public Node { -protected: - const Qualifiers Quals; - const Node *Child; - - void printQuals(OutputStream &S) const { - if (Quals & QualConst) - S += " const"; - if (Quals & QualVolatile) - S += " volatile"; - if (Quals & QualRestrict) - S += " restrict"; - } - -public: - QualType(const Node *Child_, Qualifiers Quals_) - : Node(KQualType, Child_->RHSComponentCache, - Child_->ArrayCache, Child_->FunctionCache), - Quals(Quals_), Child(Child_) {} - - template void match(Fn F) const { F(Child, Quals); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); - } - - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); - } - - void printRight(OutputStream &S) const override { Child->printRight(S); } -}; - -class ConversionOperatorType final : public Node { - const Node *Ty; - -public: - ConversionOperatorType(const Node *Ty_) - : Node(KConversionOperatorType), Ty(Ty_) {} - - template void match(Fn F) const { F(Ty); } - - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); - } -}; - -class PostfixQualifiedType final : public Node { - const Node *Ty; - const StringView Postfix; - -public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) - : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} - - template void match(Fn F) const { F(Ty, Postfix); } - - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; - } -}; - -class NameType final : public Node { - const StringView Name; - -public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} - - template void match(Fn F) const { F(Name); } - - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } - - void printLeft(OutputStream &s) const override { s += Name; } -}; - -class ElaboratedTypeSpefType : public Node { - StringView Kind; - Node *Child; -public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) - : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} - - template void match(Fn F) const { F(Kind, Child); } - - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); - } -}; - -struct AbiTagAttr : Node { - Node *Base; - StringView Tag; - - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), - Base(Base_), Tag(Tag_) {} - - template void match(Fn F) const { F(Base, Tag); } - - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; - } -}; - -class EnableIfAttr : public Node { - NodeArray Conditions; -public: - EnableIfAttr(NodeArray Conditions_) - : Node(KEnableIfAttr), Conditions(Conditions_) {} - - template void match(Fn F) const { F(Conditions); } - - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; - } -}; - -class ObjCProtoName : public Node { - const Node *Ty; - StringView Protocol; - - friend class PointerType; - -public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) - : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} - - template void match(Fn F) const { F(Ty, Protocol); } - - bool isObjCObject() const { - return Ty->getKind() == KNameType && - static_cast(Ty)->getName() == "objc_object"; - } - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; - } -}; - -class PointerType final : public Node { - const Node *Pointee; - -public: - PointerType(const Node *Pointee_) - : Node(KPointerType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} - - template void match(Fn F) const { F(Pointee); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) 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 += "*"; - } else { - const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; - } - } - - void printRight(OutputStream &s) const override { - if (Pointee->getKind() != KObjCProtoName || - !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); - } - } -}; - -enum class ReferenceKind { - LValue, - RValue, -}; - -// Represents either a LValue or an RValue reference type. -class ReferenceType : public Node { - const Node *Pointee; - ReferenceKind RK; - - mutable bool Printing = false; - - // 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 { - auto SoFar = std::make_pair(RK, Pointee); - for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); - if (SN->getKind() != KReferenceType) - break; - auto *RT = static_cast(SN); - SoFar.second = RT->Pointee; - SoFar.first = std::min(SoFar.first, RT->RK); - } - return SoFar; - } - -public: - ReferenceType(const Node *Pointee_, ReferenceKind RK_) - : Node(KReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_), RK(RK_) {} - - template void match(Fn F) const { F(Pointee, RK); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) 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 += "("; - - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); - } - void printRight(OutputStream &s) 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); - } -}; - -class PointerToMemberType final : public Node { - const Node *ClassType; - const Node *MemberType; - -public: - PointerToMemberType(const Node *ClassType_, const Node *MemberType_) - : Node(KPointerToMemberType, MemberType_->RHSComponentCache), - ClassType(ClassType_), MemberType(MemberType_) {} - - template void match(Fn F) const { F(ClassType, MemberType); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; - else - s += " "; - ClassType->print(s); - s += "::*"; - } - - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); - } -}; - -class NodeOrString { - const void *First; - const void *Second; - -public: - /* implicit */ NodeOrString(StringView Str) { - const char *FirstChar = Str.begin(); - const char *SecondChar = Str.end(); - if (SecondChar == nullptr) { - assert(FirstChar == SecondChar); - ++FirstChar, ++SecondChar; - } - First = static_cast(FirstChar); - Second = static_cast(SecondChar); - } - - /* implicit */ NodeOrString(Node *N) - : First(static_cast(N)), Second(nullptr) {} - NodeOrString() : First(nullptr), Second(nullptr) {} - - bool isString() const { return Second && First; } - bool isNode() const { return First && !Second; } - bool isEmpty() const { return !First && !Second; } - - StringView asString() const { - assert(isString()); - return StringView(static_cast(First), - static_cast(Second)); - } - - const Node *asNode() const { - assert(isNode()); - return static_cast(First); - } -}; - -class ArrayType final : public Node { - const Node *Base; - NodeOrString Dimension; - -public: - ArrayType(const Node *Base_, NodeOrString Dimension_) - : Node(KArrayType, - /*RHSComponentCache=*/Cache::Yes, - /*ArrayCache=*/Cache::Yes), - Base(Base_), Dimension(Dimension_) {} - - template void match(Fn F) const { F(Base, Dimension); } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } - - void printLeft(OutputStream &S) const override { Base->printLeft(S); } - - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; - if (Dimension.isString()) - S += Dimension.asString(); - else if (Dimension.isNode()) - Dimension.asNode()->print(S); - S += "]"; - Base->printRight(S); - } -}; - -class FunctionType final : public Node { - const Node *Ret; - NodeArray Params; - Qualifiers CVQuals; - FunctionRefQual RefQual; - const Node *ExceptionSpec; - -public: - FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, - FunctionRefQual RefQual_, const Node *ExceptionSpec_) - : Node(KFunctionType, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), - ExceptionSpec(ExceptionSpec_) {} - - template void match(Fn F) const { - F(Ret, Params, CVQuals, RefQual, ExceptionSpec); - } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } - - // Handle C++'s ... quirky decl grammar by using the left & right - // distinction. Consider: - // int (*f(float))(char) {} - // f is a function that takes a float and returns a pointer to a function - // 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 printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); - } - } -}; - -class NoexceptSpec : public Node { - const Node *E; -public: - NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} - - template void match(Fn F) const { F(E); } - - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; - } -}; - -class DynamicExceptionSpec : public Node { - NodeArray Types; -public: - DynamicExceptionSpec(NodeArray Types_) - : Node(KDynamicExceptionSpec), Types(Types_) {} - - template void match(Fn F) const { F(Types); } - - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; - } -}; - -class FunctionEncoding final : public Node { - const Node *Ret; - const Node *Name; - NodeArray Params; - const Node *Attrs; - Qualifiers CVQuals; - FunctionRefQual RefQual; - -public: - FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, - const Node *Attrs_, Qualifiers CVQuals_, - FunctionRefQual RefQual_) - : Node(KFunctionEncoding, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), - CVQuals(CVQuals_), RefQual(RefQual_) {} - - template void match(Fn F) const { - F(Ret, Name, Params, Attrs, CVQuals, RefQual); - } - - Qualifiers getCVQuals() const { return CVQuals; } - FunctionRefQual getRefQual() const { return RefQual; } - 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; } - - const Node *getName() const { return Name; } - - void printLeft(OutputStream &S) const override { - if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; - } - Name->print(S); - } - - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - if (Ret) - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (Attrs != nullptr) - Attrs->print(S); - } -}; - -class LiteralOperator : public Node { - const Node *OpName; - -public: - LiteralOperator(const Node *OpName_) - : Node(KLiteralOperator), OpName(OpName_) {} - - template void match(Fn F) const { F(OpName); } - - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); - } -}; - -class SpecialName final : public Node { - const StringView Special; - const Node *Child; - -public: - SpecialName(StringView Special_, const Node *Child_) - : Node(KSpecialName), Special(Special_), Child(Child_) {} - - template void match(Fn F) const { F(Special, Child); } - - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); - } -}; - -class CtorVtableSpecialName final : public Node { - const Node *FirstType; - const Node *SecondType; - -public: - CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) - : Node(KCtorVtableSpecialName), - FirstType(FirstType_), SecondType(SecondType_) {} - - 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); - } -}; - -struct NestedName : Node { - Node *Qual; - Node *Name; - - NestedName(Node *Qual_, Node *Name_) - : Node(KNestedName), Qual(Qual_), Name(Name_) {} - - template void match(Fn F) const { F(Qual, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); - } -}; - -struct LocalName : Node { - Node *Encoding; - Node *Entity; - - LocalName(Node *Encoding_, Node *Entity_) - : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} - - template void match(Fn F) const { F(Encoding, Entity); } - - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); - } -}; - -class QualifiedName final : public Node { - // qualifier::name - const Node *Qualifier; - const Node *Name; - -public: - QualifiedName(const Node *Qualifier_, const Node *Name_) - : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} - - template void match(Fn F) const { F(Qualifier, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); - } -}; - -class VectorType final : public Node { - const Node *BaseType; - const NodeOrString Dimension; - -public: - VectorType(const Node *BaseType_, NodeOrString Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} - - template void match(Fn F) const { F(BaseType, Dimension); } - - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; - if (Dimension.isNode()) - Dimension.asNode()->print(S); - else if (Dimension.isString()) - S += Dimension.asString(); - S += "]"; - } -}; - -class PixelVectorType final : public Node { - const NodeOrString Dimension; - -public: - PixelVectorType(NodeOrString Dimension_) - : Node(KPixelVectorType), Dimension(Dimension_) {} - - template void match(Fn F) const { F(Dimension); } - - void printLeft(OutputStream &S) const override { - // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - S += Dimension.asString(); - S += "]"; - } -}; - -/// An unexpanded parameter pack (either in the expression or type context). If -/// this AST is correct, this node will have a ParameterPackExpansion node above -/// it. -/// -/// This node is created when some are found that apply to an -/// , and is stored in the TemplateParams table. In order for this to -/// appear in the final AST, it has to referenced via a (ie, -/// T_). -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; - } - } - -public: - ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { - ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->ArrayCache == Cache::No; - })) - ArrayCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->FunctionCache == Cache::No; - })) - FunctionCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->RHSComponentCache == Cache::No; - })) - RHSComponentCache = Cache::No; - } - - 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 hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; - } - - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printLeft(S); - } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printRight(S); - } -}; - -/// A variadic template argument. This node represents an occurrence of -/// JE in some . It isn't itself unexpanded, unless -/// one of it's Elements is. The parser inserts a ParameterPack into the -/// TemplateParams table if the this pack belongs to apply to an -/// . -class TemplateArgumentPack final : public Node { - NodeArray Elements; -public: - TemplateArgumentPack(NodeArray Elements_) - : Node(KTemplateArgumentPack), Elements(Elements_) {} - - template void match(Fn F) const { F(Elements); } - - NodeArray getElements() const { return Elements; } - - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); - } -}; - -/// A pack expansion. Below this node, there are some unexpanded ParameterPacks -/// which each have Child->ParameterPackSize elements. -class ParameterPackExpansion final : public Node { - const Node *Child; - -public: - ParameterPackExpansion(const Node *Child_) - : Node(KParameterPackExpansion), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - const Node *getChild() const { return Child; } - - void printLeft(OutputStream &S) const override { - constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.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); - - // No ParameterPack was found in Child. This can occur if we've found a pack - // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; - return; - } - - // We found a ParameterPack, but it has no elements. Erase whatever we may - // of printed. - if (S.CurrentPackMax == 0) { - S.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); - } - } -}; - -class TemplateArgs final : public Node { - NodeArray Params; - -public: - TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} - - template void match(Fn F) const { F(Params); } - - NodeArray getParams() { return Params; } - - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; - } -}; - -/// A forward-reference to a template argument that was not known at the point -/// where the template parameter name was parsed in a mangling. -/// -/// This is created when demangling the name of a specialization of a -/// conversion function template: -/// -/// \code -/// struct A { -/// template operator T*(); -/// }; -/// \endcode -/// -/// When demangling a specialization of the conversion function template, we -/// encounter the name of the template (including the \c T) before we reach -/// the template argument list, so we cannot substitute the parameter name -/// for the corresponding argument while parsing. Instead, we create a -/// \c ForwardTemplateReference node that is resolved after we parse the -/// template arguments. -struct ForwardTemplateReference : Node { - size_t Index; - Node *Ref = nullptr; - - // If we're currently printing this node. It is possible (though invalid) for - // a forward template reference to refer to itself via a substitution. This - // creates a cyclic AST, which will stack overflow printing. To fix this, bail - // out if more than one print* function is active. - mutable bool Printing = false; - - ForwardTemplateReference(size_t Index_) - : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, - Cache::Unknown), - Index(Index_) {} - - // We don't provide a matcher for these, because the value of the node is - // not determined by its construction parameters, and it generally needs - // special handling. - template void match(Fn F) const = delete; - - bool hasRHSComponentSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - if (Printing) - return this; - SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); - } - - void printLeft(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); - } - void printRight(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); - } -}; - -struct NameWithTemplateArgs : Node { - // name - Node *Name; - Node *TemplateArgs; - - NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) - : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} - - template void match(Fn F) const { F(Name, TemplateArgs); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); - } -}; - -class GlobalQualifiedName final : public Node { - Node *Child; - -public: - GlobalQualifiedName(Node* Child_) - : Node(KGlobalQualifiedName), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); - } -}; - -enum class SpecialSubKind { - allocator, - basic_string, - string, - istream, - ostream, - iostream, -}; - -class ExpandedSpecialSubstitution final : public Node { - SpecialSubKind SSK; - -public: - ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} - - template void match(Fn F) const { F(SSK); } - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("basic_string"); - case SpecialSubKind::istream: - return StringView("basic_istream"); - case SpecialSubKind::ostream: - return StringView("basic_ostream"); - case SpecialSubKind::iostream: - return StringView("basic_iostream"); - } - _LIBCPP_UNREACHABLE(); - } - - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream >"; - break; - } - } -}; - -class SpecialSubstitution final : public Node { -public: - SpecialSubKind SSK; - - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} - - template void match(Fn F) const { F(SSK); } - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); - } - _LIBCPP_UNREACHABLE(); - } - - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::string"; - break; - case SpecialSubKind::istream: - S += "std::istream"; - break; - case SpecialSubKind::ostream: - S += "std::ostream"; - break; - case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } - } -}; - -class CtorDtorName final : public Node { - const Node *Basename; - const bool IsDtor; - const int Variant; - -public: - CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) - : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), - Variant(Variant_) {} - - template void match(Fn F) const { F(Basename, IsDtor, Variant); } - - void printLeft(OutputStream &S) const override { - if (IsDtor) - S += "~"; - S += Basename->getBaseName(); - } -}; - -class DtorName : public Node { - const Node *Base; - -public: - DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} - - template void match(Fn F) const { F(Base); } - - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); - } -}; - -class UnnamedTypeName : public Node { - const StringView Count; - -public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} - - template void match(Fn F) const { F(Count); } - - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; - } -}; - -class ClosureTypeName : public Node { - NodeArray Params; - StringView Count; - -public: - ClosureTypeName(NodeArray Params_, StringView Count_) - : Node(KClosureTypeName), Params(Params_), Count(Count_) {} - - template void match(Fn F) const { F(Params, Count); } - - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'("; - Params.printWithComma(S); - S += ")"; - } -}; - -class StructuredBindingName : public Node { - NodeArray Bindings; -public: - StructuredBindingName(NodeArray Bindings_) - : Node(KStructuredBindingName), Bindings(Bindings_) {} - - template void match(Fn F) const { F(Bindings); } - - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; - } -}; - -// -- Expression Nodes -- - -class BinaryExpr : public Node { - const Node *LHS; - const StringView InfixOperator; - const Node *RHS; - -public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { - } - - template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; - } -}; - -class ArraySubscriptExpr : public Node { - const Node *Op1; - const Node *Op2; - -public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} - - template void match(Fn F) const { F(Op1, Op2); } - - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; - } -}; - -class PostfixExpr : public Node { - const Node *Child; - const StringView Operator; - -public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} - - template void match(Fn F) const { F(Child, Operator); } - - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; - } -}; - -class ConditionalExpr : public Node { - const Node *Cond; - const Node *Then; - const Node *Else; - -public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} - - 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 += ")"; - } -}; - -class MemberExpr : public Node { - const Node *LHS; - const StringView Kind; - const Node *RHS; - -public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - - template void match(Fn F) const { F(LHS, Kind, RHS); } - - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); - } -}; - -class EnclosingExpr : public Node { - const StringView Prefix; - const Node *Infix; - const StringView Postfix; - -public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} - - template void match(Fn F) const { F(Prefix, Infix, Postfix); } - - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; - } -}; - -class CastExpr : public Node { - // cast_kind(from) - const StringView CastKind; - const Node *To; - const Node *From; - -public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_) - : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} - - 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 += ")"; - } -}; - -class SizeofParamPackExpr : public Node { - const Node *Pack; - -public: - SizeofParamPackExpr(const Node *Pack_) - : Node(KSizeofParamPackExpr), Pack(Pack_) {} - - template void match(Fn F) const { F(Pack); } - - void printLeft(OutputStream &S) const override { - S += "sizeof...("; - ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; - } -}; - -class CallExpr : public Node { - const Node *Callee; - NodeArray Args; - -public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} - - template void match(Fn F) const { F(Callee, Args); } - - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; - } -}; - -class NewExpr : public Node { - // new (expr_list) type(init_list) - NodeArray ExprList; - Node *Type; - NodeArray InitList; - bool IsGlobal; // ::operator new ? - bool IsArray; // new[] ? -public: - NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - template void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); - } - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::operator "; - S += "new"; - if (IsArray) - S += "[]"; - S += ' '; - if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; - } - Type->print(S); - if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; - } - - } -}; - -class DeleteExpr : public Node { - Node *Op; - bool IsGlobal; - bool IsArray; - -public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - template void match(Fn F) const { F(Op, IsGlobal, IsArray); } - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::"; - S += "delete"; - if (IsArray) - S += "[] "; - Op->print(S); - } -}; - -class PrefixExpr : public Node { - StringView Prefix; - Node *Child; - -public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} - - template void match(Fn F) const { F(Prefix, Child); } - - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; - } -}; - -class FunctionParam : public Node { - StringView Number; - -public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} - - template void match(Fn F) const { F(Number); } - - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; - } -}; - -class ConversionExpr : public Node { - const Node *Type; - NodeArray Expressions; - -public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} - - template void match(Fn F) const { F(Type, Expressions); } - - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; - } -}; - -class InitListExpr : public Node { - const Node *Ty; - NodeArray Inits; -public: - InitListExpr(const Node *Ty_, NodeArray Inits_) - : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} - - template void match(Fn F) const { F(Ty, Inits); } - - void printLeft(OutputStream &S) const override { - if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; - } -}; - -class BracedExpr : public Node { - const Node *Elem; - const Node *Init; - bool IsArray; -public: - BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) - : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} - - template void match(Fn F) const { F(Elem, Init, IsArray); } - - void printLeft(OutputStream &S) const override { - if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; - } else { - S += '.'; - Elem->print(S); - } - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); - } -}; - -class BracedRangeExpr : public Node { - const Node *First; - const Node *Last; - const Node *Init; -public: - BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) - : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} - - 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 += ']'; - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); - } -}; - -class FoldExpr : public Node { - const Node *Pack, *Init; - StringView OperatorName; - bool IsLeftFold; - -public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, - const Node *Init_) - : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), - IsLeftFold(IsLeftFold_) {} - - template void match(Fn F) const { - F(IsLeftFold, OperatorName, Pack, Init); - } - - void printLeft(OutputStream &S) const override { - auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; - }; - - S += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } - } - S += ')'; - } -}; - -class ThrowExpr : public Node { - const Node *Op; - -public: - ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} - - template void match(Fn F) const { F(Op); } - - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -class BoolExpr : public Node { - bool Value; - -public: - BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} - - template void match(Fn F) const { F(Value); } - - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); - } -}; - -class IntegerCastExpr : public Node { - // ty(integer) - const Node *Ty; - StringView Integer; - -public: - IntegerCastExpr(const Node *Ty_, StringView Integer_) - : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} - - template void match(Fn F) const { F(Ty, Integer); } - - void printLeft(OutputStream &S) const override { - S += "("; - Ty->print(S); - S += ")"; - S += Integer; - } -}; - -class IntegerLiteral : public Node { - StringView Type; - StringView Value; - -public: - IntegerLiteral(StringView Type_, StringView Value_) - : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} - - template void match(Fn F) const { F(Type, Value); } - - void printLeft(OutputStream &S) const override { - if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; - } - - if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); - } else - S += Value; - - if (Type.size() <= 3) - S += Type; - } -}; - -template struct FloatData; - -namespace float_literal_impl { -constexpr Node::Kind getFloatLiteralKind(float *) { - return Node::KFloatLiteral; -} -constexpr Node::Kind getFloatLiteralKind(double *) { - return Node::KDoubleLiteral; -} -constexpr Node::Kind getFloatLiteralKind(long double *) { - return Node::KLongDoubleLiteral; -} -} - -template class FloatLiteralImpl : public Node { - const StringView Contents; - - static constexpr Kind KindForClass = - float_literal_impl::getFloatLiteralKind((Float *)nullptr); - -public: - FloatLiteralImpl(StringView Contents_) - : Node(KindForClass), Contents(Contents_) {} - - template void match(Fn F) const { F(Contents); } - - void printLeft(OutputStream &s) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - - const size_t N = FloatData::mangled_size; - if (static_cast(last - first) > N) { - last = first + N; - union { - Float value; - char buf[sizeof(Float)]; - }; - const char *t = first; - char *e = buf; - for (; t != last; ++t, ++e) { - unsigned d1 = isdigit(*t) ? static_cast(*t - '0') - : static_cast(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast(*t - '0') - : static_cast(*t - 'a' + 10); - *e = static_cast((d1 << 4) + d0); - } -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[FloatData::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); - } - } -}; - -using FloatLiteral = FloatLiteralImpl; -using DoubleLiteral = FloatLiteralImpl; -using LongDoubleLiteral = FloatLiteralImpl; - -/// Visit the node. Calls \c F(P), where \c P is the node cast to the -/// appropriate derived class. -template -void Node::visit(Fn F) const { - switch (K) { -#define CASE(X) case K ## X: return F(static_cast(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE - } - assert(0 && "unknown mangling node kind"); -} - -/// Determine the kind of a node from its type. -template struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ - }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef 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; - T* Last; - T* Cap; - T Inline[N]; - - 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; - - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser collapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector Names; - - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector Subs; - - // Template parameter table. Like the above, but referenced like "T42_". - // This has a smaller size compared to Subs and Names because it can be - // stored on the stack. - PODSmallVector TemplateParams; - - // Set of unresolved forward references. These can occur in a - // conversion operator's type, and are resolved in the enclosing . - PODSmallVector ForwardTemplateRefs; - - bool TryToParseTemplateArgs = true; - bool PermitForwardTemplateReferences = false; - bool ParsingLambdaParams = false; - - Alloc ASTAllocator; - - AbstractManglingParser(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - - Derived &getDerived() { return static_cast(*this); } - - void reset(const char *First_, const char *Last_) { - First = First_; - Last = Last_; - Names.clear(); - Subs.clear(); - TemplateParams.clear(); - ParsingLambdaParams = false; - TryToParseTemplateArgs = true; - PermitForwardTemplateReferences = false; - ASTAllocator.reset(); - } - - template Node *make(Args &&... args) { - return ASTAllocator.template makeNode(std::forward(args)...); - } - - template NodeArray makeNodeArray(It begin, It end) { - size_t sz = static_cast(end - begin); - void *mem = ASTAllocator.allocateNodeArray(sz); - Node **data = new (mem) Node *[sz]; - std::copy(begin, end, data); - return NodeArray(data, sz); - } - - NodeArray popTrailingNodeArray(size_t FromPosition) { - assert(FromPosition <= Names.size()); - NodeArray res = - makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); - return res; - } - - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { - First += S.size(); - return true; - } - return false; - } - - bool consumeIf(char C) { - if (First != Last && *First == C) { - ++First; - return true; - } - return false; - } - - char consume() { return First != Last ? *First++ : '\0'; } - - char look(unsigned Lookahead = 0) { - if (static_cast(Last - First) <= Lookahead) - return '\0'; - return First[Lookahead]; - } - - size_t numLeft() const { return static_cast(Last - First); } - - StringView parseNumber(bool AllowNegative = false); - Qualifiers parseCVQualifiers(); - bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); - - bool parseSeqId(size_t *Out); - Node *parseSubstitution(); - Node *parseTemplateParam(); - Node *parseTemplateArgs(bool TagTemplates = false); - Node *parseTemplateArg(); - - /// Parse the production. - Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); - Node *parseIntegerLiteral(StringView Lit); - Node *parseExprPrimary(); - template Node *parseFloatingLiteral(); - Node *parseFunctionParam(); - Node *parseNewExpr(); - Node *parseConversionExpr(); - Node *parseBracedExpr(); - Node *parseFoldExpr(); - - /// Parse the production. - Node *parseType(); - Node *parseFunctionType(); - Node *parseVectorType(); - Node *parseDecltype(); - Node *parseArrayType(); - Node *parsePointerToMemberType(); - Node *parseClassEnumType(); - Node *parseQualifiedType(); - - Node *parseEncoding(); - bool parseCallOffset(); - Node *parseSpecialName(); - - /// Holds some extra information about a that is being parsed. This - /// information is only pertinent if the refers to an . - struct NameState { - bool CtorDtorConversion = false; - bool EndsWithTemplateArgs = false; - Qualifiers CVQualifiers = QualNone; - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ForwardTemplateRefsBegin; - - NameState(AbstractManglingParser *Enclosing) - : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} - }; - - bool resolveForwardTemplateRefs(NameState &State) { - size_t I = State.ForwardTemplateRefsBegin; - size_t E = ForwardTemplateRefs.size(); - for (; I < E; ++I) { - size_t Idx = ForwardTemplateRefs[I]->Index; - if (Idx >= TemplateParams.size()) - return true; - ForwardTemplateRefs[I]->Ref = TemplateParams[Idx]; - } - ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); - return false; - } - - /// Parse the production> - Node *parseName(NameState *State = nullptr); - Node *parseLocalName(NameState *State); - Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); - Node *parseUnnamedTypeName(NameState *State); - Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); - Node *parseNestedName(NameState *State); - Node *parseCtorDtorName(Node *&SoFar, NameState *State); - - Node *parseAbiTags(Node *N); - - /// Parse the production. - Node *parseUnresolvedName(); - Node *parseSimpleId(); - Node *parseBaseUnresolvedName(); - Node *parseUnresolvedType(); - Node *parseDestructorName(); - - /// Top-level entry point into the parser. - Node *parse(); -}; - -const char* parse_discriminator(const char* first, const char* last); - -// ::= // N -// ::= # See Scope Encoding below // Z -// ::= -// ::= -// -// ::= -// ::= -template -Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - - if (look() == 'N') - return getDerived().parseNestedName(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 *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); - } - - 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; -} - -// := Z E [] -// := Z E s [] -// := Z Ed [ ] _ -template -Node *AbstractManglingParser::parseLocalName(NameState *State) { - if (!consumeIf('Z')) - return nullptr; - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf('E')) - return nullptr; - - if (consumeIf('s')) { - First = parse_discriminator(First, Last); - auto *StringLitName = make("string literal"); - if (!StringLitName) - return nullptr; - return make(Encoding, StringLitName); - } - - if (consumeIf('d')) { - parseNumber(true); - if (!consumeIf('_')) - return nullptr; - Node *N = getDerived().parseName(State); - if (N == nullptr) - return nullptr; - return make(Encoding, N); - } - - Node *Entity = getDerived().parseName(State); - if (Entity == nullptr) - return nullptr; - First = parse_discriminator(First, Last); - return make(Encoding, Entity); -} - -// ::= -// ::= St # ::std:: -// extension ::= StL -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); -} - -// ::= [abi-tags] -// ::= -// ::= -// ::= -// ::= DC + E # structured binding declaration -template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State) { - // s are special-cased in parseNestedName(). - Node *Result; - if (look() == 'U') - Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') - Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { - size_t BindingsBegin = Names.size(); - do { - Node *Binding = getDerived().parseSourceName(State); - if (Binding == nullptr) - return nullptr; - Names.push_back(Binding); - } while (!consumeIf('E')); - Result = make(popTrailingNodeArray(BindingsBegin)); - } else - Result = getDerived().parseOperatorName(State); - if (Result != nullptr) - Result = getDerived().parseAbiTags(Result); - return Result; -} - -// ::= Ut [] _ -// ::= -// -// ::= Ul E [ ] _ -// -// ::= + # Parameter types or "v" if the lambda has no parameters -template -Node * -AbstractManglingParser::parseUnnamedTypeName(NameState *) { - if (consumeIf("Ut")) { - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make(Count); - } - if (consumeIf("Ul")) { - NodeArray Params; - SwapAndRestore SwapParams(ParsingLambdaParams, true); - if (!consumeIf("vE")) { - size_t ParamsBegin = Names.size(); - do { - Node *P = getDerived().parseType(); - if (P == nullptr) - return nullptr; - Names.push_back(P); - } while (!consumeIf('E')); - Params = popTrailingNodeArray(ParamsBegin); - } - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make(Params, Count); - } - return nullptr; -} - -// ::= -template -Node *AbstractManglingParser::parseSourceName(NameState *) { - size_t Length = 0; - if (parsePositiveInteger(&Length)) - return nullptr; - if (numLeft() < Length || Length == 0) - return nullptr; - StringView Name(First, First + Length); - First += Length; - if (Name.startsWith("_GLOBAL__N")) - return make("(anonymous namespace)"); - return make(Name); -} - -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= li # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v # vendor extended operator -template -Node * -AbstractManglingParser::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make("operator&&"); - case 'd': - case 'n': - First += 2; - return make("operator&"); - case 'N': - First += 2; - return make("operator&="); - case 'S': - First += 2; - return make("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make("operator()"); - case 'm': - First += 2; - return make("operator,"); - case 'o': - First += 2; - return make("operator~"); - // ::= cv # (cast) - case 'v': { - First += 2; - SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); - // If we're parsing an encoding, State != nullptr and the conversion - // operators' could have a that refers to some - // s further ahead in the mangled name. - SwapAndRestore SavePermit(PermitForwardTemplateReferences, - PermitForwardTemplateReferences || - State != nullptr); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (State) State->CtorDtorConversion = true; - return make(Ty); - } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make("operator delete[]"); - case 'e': - First += 2; - return make("operator*"); - case 'l': - First += 2; - return make("operator delete"); - case 'v': - First += 2; - return make("operator/"); - case 'V': - First += 2; - return make("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make("operator^"); - case 'O': - First += 2; - return make("operator^="); - case 'q': - First += 2; - return make("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make("operator>="); - case 't': - First += 2; - return make("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make("operator<="); - // ::= li # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make(SN); - } - case 's': - First += 2; - return make("operator<<"); - case 'S': - First += 2; - return make("operator<<="); - case 't': - First += 2; - return make("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make("operator-"); - case 'I': - First += 2; - return make("operator-="); - case 'l': - First += 2; - return make("operator*"); - case 'L': - First += 2; - return make("operator*="); - case 'm': - First += 2; - return make("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make("operator new[]"); - case 'e': - First += 2; - return make("operator!="); - case 'g': - First += 2; - return make("operator-"); - case 't': - First += 2; - return make("operator!"); - case 'w': - First += 2; - return make("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make("operator||"); - case 'r': - First += 2; - return make("operator|"); - case 'R': - First += 2; - return make("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make("operator->*"); - case 'l': - First += 2; - return make("operator+"); - case 'L': - First += 2; - return make("operator+="); - case 'p': - First += 2; - return make("operator++"); - case 's': - First += 2; - return make("operator+"); - case 't': - First += 2; - return make("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make("operator%"); - case 'M': - First += 2; - return make("operator%="); - case 's': - First += 2; - return make("operator>>"); - case 'S': - First += 2; - return make("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make("operator<=>"); - } - return nullptr; - // ::= v # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make(SN); - } - return nullptr; - } - return nullptr; -} - -// ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// extension ::= C5 # ? -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor -// extension ::= D5 # ? -template -Node * -AbstractManglingParser::parseCtorDtorName(Node *&SoFar, - NameState *State) { - if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } - } - - if (consumeIf('C')) { - bool IsInherited = consumeIf('I'); - if (look() != '1' && look() != '2' && look() != '3' && look() != '5') - return nullptr; - int Variant = look() - '0'; - ++First; - if (State) State->CtorDtorConversion = true; - if (IsInherited) { - if (getDerived().parseName(State) == nullptr) - return nullptr; - } - return make(SoFar, false, Variant); - } - - if (look() == 'D' && - (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) { - int Variant = look(1) - '0'; - First += 2; - if (State) State->CtorDtorConversion = true; - return make(SoFar, true, Variant); - } - - return nullptr; -} - -// ::= N [] [] E -// ::= N [] [] E -// -// ::= -// ::= -// ::= -// ::= -// ::= # empty -// ::= -// ::= -// extension ::= L -// -// := [] M -// -// ::=