summaryrefslogtreecommitdiff
path: root/lib/libcxxabi
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2016-09-03 18:40:22 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2016-09-03 18:40:22 +0000
commitb22dbf866717862f24c98a76f91d4fd24ef5a6c7 (patch)
treeb0ccb9fcfde981ad8f2542858279e04706c75a0a /lib/libcxxabi
parent6cc4f8fe38a9bd897f43771cda700fe721b06c18 (diff)
Import libc++abi 3.9.0
Diffstat (limited to 'lib/libcxxabi')
-rw-r--r--lib/libcxxabi/CMakeLists.txt404
-rw-r--r--lib/libcxxabi/CREDITS.TXT71
-rw-r--r--lib/libcxxabi/LICENSE.TXT76
-rw-r--r--lib/libcxxabi/cmake/config-ix.cmake49
-rw-r--r--lib/libcxxabi/include/__cxxabi_config.h47
-rw-r--r--lib/libcxxabi/include/cxxabi.h177
-rwxr-xr-xlib/libcxxabi/lib/buildit99
-rw-r--r--lib/libcxxabi/src/CMakeLists.txt139
-rw-r--r--lib/libcxxabi/src/abort_message.cpp81
-rw-r--r--lib/libcxxabi/src/abort_message.h33
-rw-r--r--lib/libcxxabi/src/config.h31
-rw-r--r--lib/libcxxabi/src/cxa_aux_runtime.cpp44
-rw-r--r--lib/libcxxabi/src/cxa_default_handlers.cpp126
-rw-r--r--lib/libcxxabi/src/cxa_demangle.cpp5039
-rw-r--r--lib/libcxxabi/src/cxa_exception.cpp718
-rw-r--r--lib/libcxxabi/src/cxa_exception.hpp125
-rw-r--r--lib/libcxxabi/src/cxa_exception_storage.cpp103
-rw-r--r--lib/libcxxabi/src/cxa_guard.cpp253
-rw-r--r--lib/libcxxabi/src/cxa_handlers.cpp126
-rw-r--r--lib/libcxxabi/src/cxa_handlers.hpp54
-rw-r--r--lib/libcxxabi/src/cxa_new_delete.cpp274
-rw-r--r--lib/libcxxabi/src/cxa_noexception.cpp60
-rw-r--r--lib/libcxxabi/src/cxa_personality.cpp1300
-rw-r--r--lib/libcxxabi/src/cxa_thread_atexit.cpp26
-rw-r--r--lib/libcxxabi/src/cxa_unexpected.cpp27
-rw-r--r--lib/libcxxabi/src/cxa_vector.cpp367
-rw-r--r--lib/libcxxabi/src/cxa_virtual.cpp25
-rw-r--r--lib/libcxxabi/src/exception.cpp41
-rw-r--r--lib/libcxxabi/src/fallback_malloc.ipp188
-rw-r--r--lib/libcxxabi/src/private_typeinfo.cpp1279
-rw-r--r--lib/libcxxabi/src/private_typeinfo.h240
-rw-r--r--lib/libcxxabi/src/stdexcept.cpp48
-rw-r--r--lib/libcxxabi/src/typeinfo.cpp53
33 files changed, 11723 insertions, 0 deletions
diff --git a/lib/libcxxabi/CMakeLists.txt b/lib/libcxxabi/CMakeLists.txt
new file mode 100644
index 00000000000..300d6da2152
--- /dev/null
+++ b/lib/libcxxabi/CMakeLists.txt
@@ -0,0 +1,404 @@
+#===============================================================================
+# Setup Project
+#===============================================================================
+
+cmake_minimum_required(VERSION 3.4.3)
+
+if(POLICY CMP0042)
+ cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default
+endif()
+
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ project(libcxxabi)
+
+ # Rely on llvm-config.
+ set(CONFIG_OUTPUT)
+ find_program(LLVM_CONFIG "llvm-config")
+ if(DEFINED LLVM_PATH)
+ set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include")
+ set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree")
+ set(LLVM_MAIN_SRC_DIR ${LLVM_PATH})
+ set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules")
+ elseif(LLVM_CONFIG)
+ message(STATUS "Found LLVM_CONFIG as ${LLVM_CONFIG}")
+ set(CONFIG_COMMAND ${LLVM_CONFIG}
+ "--includedir"
+ "--prefix"
+ "--src-root")
+ execute_process(
+ COMMAND ${CONFIG_COMMAND}
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT
+ )
+ if(NOT HAD_ERROR)
+ string(REGEX REPLACE
+ "[ \t]*[\r\n]+[ \t]*" ";"
+ CONFIG_OUTPUT ${CONFIG_OUTPUT})
+ else()
+ string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}")
+ message(STATUS "${CONFIG_COMMAND_STR}")
+ message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
+ endif()
+
+ list(GET CONFIG_OUTPUT 0 INCLUDE_DIR)
+ list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT)
+ list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR)
+
+ set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include")
+ set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree")
+ set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+ set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR}/share/llvm/cmake")
+ set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py")
+ else()
+ message(FATAL_ERROR "llvm-config not found and LLVM_MAIN_SRC_DIR not defined. "
+ "Reconfigure with -DLLVM_CONFIG=path/to/llvm-config "
+ "or -DLLVM_PATH=path/to/llvm-source-root.")
+ endif()
+
+ if(EXISTS ${LLVM_CMAKE_PATH})
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
+ include("${LLVM_CMAKE_PATH}/AddLLVM.cmake")
+ include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake")
+ else()
+ message(FATAL_ERROR "Not found: ${LLVM_CMAKE_PATH}")
+ endif()
+
+ set(PACKAGE_NAME libcxxabi)
+ set(PACKAGE_VERSION 3.9.0)
+ set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+ set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org")
+
+ if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ else()
+ # Seek installed Lit.
+ find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit
+ DOC "Path to lit.py")
+ endif()
+
+ if(LLVM_LIT)
+ # Define the default arguments to use with 'lit', and an option for the user
+ # to override.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+
+ # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
+ if( WIN32 AND NOT CYGWIN )
+ set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
+ endif()
+ else()
+ set(LLVM_INCLUDE_TESTS OFF)
+ endif()
+
+ set(LIBCXXABI_LIBDIR_SUFFIX "" CACHE STRING
+ "Define suffix of library directory name (32/64)")
+
+ set(LIBCXXABI_BUILT_STANDALONE 1)
+else()
+ set(LLVM_MAIN_SRC_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "Path to LLVM source tree")
+ set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py")
+ set(LIBCXXABI_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX})
+endif()
+
+#===============================================================================
+# Setup CMake Options
+#===============================================================================
+
+# Define options.
+option(LIBCXXABI_ENABLE_EXCEPTIONS "Use exceptions." ON)
+option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON)
+option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." ON)
+option(LIBCXXABI_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
+option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." OFF)
+option(LIBCXXABI_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
+option(LIBCXXABI_ENABLE_THREADS "Build with threads enabled" ON)
+option(LIBCXXABI_HAS_PTHREAD_API "Ignore auto-detection and force use of pthread API" OFF)
+option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS})
+set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
+set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
+set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.")
+set(LIBCXXABI_LIBCXX_LIBRARY_PATH "" CACHE PATH "The path to libc++ library.")
+
+# Default to building a shared library so that the default options still test
+# the libc++abi that is being built. There are two problems with testing a
+# static libc++abi. In the case of a standalone build, the tests will link the
+# system's libc++, which might not have been built against our libc++abi. In the
+# case of an in tree build, libc++ will prefer a dynamic libc++abi from the
+# system over a static libc++abi from the output directory.
+option(LIBCXXABI_ENABLE_SHARED "Build libc++abi as a shared library." ON)
+option(LIBCXXABI_ENABLE_STATIC "Build libc++abi as a static library." ON)
+
+if (NOT LIBCXXABI_ENABLE_SHARED AND NOT LIBCXXABI_ENABLE_STATIC)
+ message(FATAL_ERROR "libc++abi must be built as either a shared or static library.")
+endif()
+
+find_path(
+ LIBCXXABI_LIBCXX_INCLUDES
+ vector
+ PATHS ${LIBCXXABI_LIBCXX_INCLUDES}
+ ${LIBCXXABI_LIBCXX_PATH}/include
+ ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBCXX_INCLUDES}
+ ${LLVM_MAIN_SRC_DIR}/projects/libcxx/include
+ ${LLVM_INCLUDE_DIR}/c++/v1
+ )
+
+set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXXABI_LIBCXX_INCLUDES}" CACHE PATH
+ "Specify path to libc++ includes." FORCE)
+
+find_path(
+ LIBCXXABI_LIBCXX_PATH
+ test/libcxx/__init__.py
+ PATHS ${LIBCXXABI_LIBCXX_PATH}
+ ${LIBCXXABI_LIBCXX_INCLUDES}/../
+ ${LLVM_MAIN_SRC_DIR}/projects/libcxx/
+ NO_DEFAULT_PATH
+ )
+
+if (LIBCXXABI_LIBCXX_PATH STREQUAL "LIBCXXABI_LIBCXX_PATH-NOTFOUND")
+ message(WARNING "LIBCXXABI_LIBCXX_PATH was not specified and couldn't be infered.")
+ set(LIBCXXABI_LIBCXX_PATH "")
+endif()
+
+set(LIBCXXABI_LIBCXX_PATH "${LIBCXXABI_LIBCXX_PATH}" CACHE PATH
+ "Specify path to libc++ source." FORCE)
+
+#===============================================================================
+# Configure System
+#===============================================================================
+
+# Add path for custom modules
+set(CMAKE_MODULE_PATH
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+ ${CMAKE_MODULE_PATH}
+ )
+
+set(LIBCXXABI_COMPILER ${CMAKE_CXX_COMPILER})
+set(LIBCXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(LIBCXXABI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX})
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR})
+
+# By default, for non-standalone builds, libcxx and libcxxabi share a library
+# directory.
+if (NOT LIBCXXABI_LIBCXX_LIBRARY_PATH)
+ set(LIBCXXABI_LIBCXX_LIBRARY_PATH "${LIBCXXABI_LIBRARY_DIR}" CACHE PATH
+ "The path to libc++ library.")
+endif()
+
+# Check that we can build with 32 bits if requested.
+if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32)
+ if (LIBCXXABI_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM
+ message(STATUS "Building 32 bits executables and libraries.")
+ endif()
+elseif(LIBCXXABI_BUILD_32_BITS)
+ message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.")
+endif()
+
+#===============================================================================
+# Setup Compiler Flags
+#===============================================================================
+
+# Get required flags.
+macro(append_if list condition var)
+ if (${condition})
+ list(APPEND ${list} ${var})
+ endif()
+endmacro()
+
+macro(add_target_flags_if condition var)
+ if (${condition})
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${var}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${var}")
+ list(APPEND LIBCXXABI_LINK_FLAGS ${var})
+ endif()
+endmacro()
+
+set(LIBCXXABI_C_FLAGS "")
+set(LIBCXXABI_CXX_FLAGS "")
+set(LIBCXXABI_COMPILE_FLAGS "")
+set(LIBCXXABI_LINK_FLAGS "")
+
+# Configure target flags
+add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32")
+add_target_flags_if(LIBCXXABI_TARGET_TRIPLE
+ "-target ${LIBCXXABI_TARGET_TRIPLE}")
+add_target_flags_if(LIBCXXABI_GCC_TOOLCHAIN
+ "-gcc-toolchain ${LIBCXXABI_GCC_TOOLCHAIN}")
+add_target_flags_if(LIBCXXABI_SYSROOT
+ "--sysroot=${LIBCXXABI_SYSROOT}")
+
+# Configure compiler. Must happen after setting the target flags.
+include(config-ix)
+
+if (LIBCXXABI_HAS_NOSTDINCXX_FLAG)
+ list(APPEND LIBCXXABI_COMPILE_FLAGS -nostdinc++)
+ # Remove -stdlib flags to prevent them from causing an unused flag warning.
+ string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+endif()
+
+if (LIBCXXABI_USE_COMPILER_RT)
+ list(APPEND LIBCXXABI_LINK_FLAGS "-rtlib=compiler-rt")
+endif()
+
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror=return-type)
+
+# Get warning flags
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_W_FLAG -W)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WALL_FLAG -Wall)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG -Wchar-subscripts)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCONVERSION_FLAG -Wconversion)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG -Wmismatched-tags)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISSING_BRACES_FLAG -Wmissing-braces)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNEWLINE_EOF_FLAG -Wnewline-eof)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_UNUSED_FUNCTION_FLAG -Wno-unused-function)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHADOW_FLAG -Wshadow)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG -Wshorten-64-to-32)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_COMPARE_FLAG -Wsign-compare)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG -Wsign-conversion)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG -Wstrict-aliasing=2)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG -Wstrict-overflow=4)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG -Wunused-parameter)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG -Wunused-variable)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WWRITE_STRINGS_FLAG -Wwrite-strings)
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNDEF_FLAG -Wundef)
+
+if (LIBCXXABI_ENABLE_WERROR)
+ append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror)
+ append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WX_FLAG -WX)
+else()
+ append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_ERROR_FLAG -Wno-error)
+ append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_NO_WX_FLAG -WX-)
+endif()
+if (LIBCXXABI_ENABLE_PEDANTIC)
+ append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_PEDANTIC_FLAG -pedantic)
+endif()
+
+# Get feature flags.
+append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG -fstrict-aliasing)
+
+# Exceptions
+if (LIBCXXABI_ENABLE_EXCEPTIONS)
+ # Catches C++ exceptions only and tells the compiler to assume that extern C
+ # functions never throw a C++ exception.
+ append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_EHSC_FLAG -EHsc)
+ append_if(LIBCXXABI_C_FLAGS LIBCXXABI_HAS_FUNWIND_TABLES -funwind-tables)
+else()
+ add_definitions(-D_LIBCXXABI_NO_EXCEPTIONS)
+ append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG -fno-exceptions)
+ append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHS_FLAG -EHs-)
+ append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHA_FLAG -EHa-)
+endif()
+
+# Assert
+string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
+if (LIBCXXABI_ENABLE_ASSERTIONS)
+ # MSVC doesn't like _DEBUG on release builds. See PR 4379.
+ if (NOT MSVC)
+ list(APPEND LIBCXXABI_COMPILE_FLAGS -D_DEBUG)
+ endif()
+ # On Release builds cmake automatically defines NDEBUG, so we
+ # explicitly undefine it:
+ if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
+ list(APPEND LIBCXXABI_COMPILE_FLAGS -UNDEBUG)
+ endif()
+else()
+ if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
+ list(APPEND LIBCXXABI_COMPILE_FLAGS -DNDEBUG)
+ endif()
+endif()
+# Static library
+if (NOT LIBCXXABI_ENABLE_SHARED)
+ list(APPEND LIBCXXABI_COMPILE_FLAGS -D_LIBCPP_BUILD_STATIC)
+endif()
+
+if (NOT LIBCXXABI_ENABLE_THREADS)
+ if (LIBCXXABI_HAS_PTHREAD_API)
+ message(FATAL_ERROR "LIBCXXABI_HAS_PTHREAD_API can only"
+ " be set to ON when LIBCXXABI_ENABLE_THREADS"
+ " is also set to ON.")
+ endif()
+ add_definitions(-DLIBCXXABI_HAS_NO_THREADS=1)
+endif()
+
+if (LIBCXXABI_HAS_PTHREAD_API)
+ add_definitions(-D_LIBCPP_HAS_THREAD_API_PTHREAD)
+endif()
+
+# This is the _ONLY_ place where add_definitions is called.
+if (MSVC)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# Define LIBCXXABI_USE_LLVM_UNWINDER for conditional compilation.
+if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM)
+ add_definitions(-DLIBCXXABI_USE_LLVM_UNWINDER=1)
+endif()
+
+string(REPLACE ";" " " LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXXABI_CXX_FLAGS}")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBCXXABI_C_FLAGS}")
+
+#===============================================================================
+# Setup Source Code
+#===============================================================================
+
+set(LIBCXXABI_LIBUNWIND_INCLUDES "${LIBCXXABI_LIBUNWIND_INCLUDES}" CACHE PATH
+ "Specify path to libunwind includes." FORCE)
+set(LIBCXXABI_LIBUNWIND_PATH "${LIBCXXABI_LIBUNWIND_PATH}" CACHE PATH
+ "Specify path to libunwind source." FORCE)
+
+include_directories(include)
+if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM)
+ find_path(
+ LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL
+ libunwind.h
+ PATHS ${LIBCXXABI_LIBUNWIND_INCLUDES}
+ ${LIBCXXABI_LIBUNWIND_PATH}/include
+ ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBUNWIND_INCLUDES}
+ ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include
+ NO_DEFAULT_PATH
+ )
+
+ find_path(
+ LIBCXXABI_LIBUNWIND_SOURCES
+ libunwind_ext.h
+ PATHS ${LIBCXXABI_LIBUNWIND_PATH}/src/
+ ${LIBCXXABI_LIBUNWIND_INCLUDES}/../src/
+ ${LLVM_MAIN_SRC_DIR}/projects/libunwind/src/
+ NO_DEFAULT_PATH
+ )
+
+ if (LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "LIBCXXABI_LIBUNWIND_SOURCES-NOTFOUND")
+ message(WARNING "LIBCXXABI_LIBUNWIND_SOURCES was not specified and couldn't be infered.")
+ set(LIBCXXABI_LIBUNWIND_SOURCES "")
+ endif()
+
+ include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}")
+ include_directories("${LIBCXXABI_LIBUNWIND_SOURCES}")
+endif()
+
+# Add source code. This also contains all of the logic for deciding linker flags
+# soname, etc...
+add_subdirectory(src)
+
+if (LIBCXXABI_BUILT_STANDALONE AND NOT LIBCXXABI_ENABLE_SHARED)
+ # We can't reasonably test the system C++ library with a static libc++abi.
+ # We either need to be able to replace libc++abi at run time (with a shared
+ # libc++abi), or we need to be able to replace the C++ runtime (with a non-
+ # standalone build).
+ message(WARNING "The libc++abi tests aren't valid when libc++abi is built "
+ "standalone (i.e. outside of llvm/projects/libcxxabi ) and "
+ "is built without a shared library. Either build a shared "
+ "library, build libc++abi at the same time as you build "
+ "libc++, or do without testing. No check target will be "
+ "available!")
+else()
+ add_subdirectory(test)
+endif()
diff --git a/lib/libcxxabi/CREDITS.TXT b/lib/libcxxabi/CREDITS.TXT
new file mode 100644
index 00000000000..9c910fcfd0c
--- /dev/null
+++ b/lib/libcxxabi/CREDITS.TXT
@@ -0,0 +1,71 @@
+This file is a partial list of people who have contributed to the LLVM/libc++abi
+project. If you have contributed a patch or made some other contribution to
+LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Aaron Ballman
+E: aaron@aaronballman.com
+D: Minor patches
+
+N: Logan Chien
+E: logan.chien@mediatek.com
+D: ARM EHABI Unwind & Exception Handling
+
+N: Marshall Clow
+E: mclow.lists@gmail.com
+E: marshall@idio.com
+D: Architect and primary coauthor of libc++abi
+
+N: Matthew Dempsky
+E: matthew@dempsky.org
+D: Minor patches and bug fixes.
+
+N: Nowar Gu
+E: wenhan.gu@gmail.com
+D: Minor patches and fixes
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary coauthor of libc++abi
+
+N: Dana Jansens
+E: danakj@chromium.org
+D: ARM EHABI Unwind & Exception Handling
+
+N: Nick Kledzik
+E: kledzik@apple.com
+
+N: Antoine Labour
+E: piman@chromium.org
+D: ARM EHABI Unwind & Exception Handling
+
+N: Bruce Mitchener, Jr.
+E: bruce.mitchener@gmail.com
+D: Minor typo fixes
+
+N: Andrew Morrow
+E: andrew.c.morrow@gmail.com
+D: Minor patches and fixes
+
+N: Erik Olofsson
+E: erik.olofsson@hansoft.se
+E: erik@olofsson.info
+D: Minor patches and fixes
+
+N: Jon Roelofs
+E: jonathan@codesourcery.com
+D: ARM EHABI Unwind & Exception Handling, Bare-metal
+
+N: Nico Weber
+E: thakis@chromium.org
+D: ARM EHABI Unwind & Exception Handling
+
+N: Albert J. Wong
+E: ajwong@google.com
+D: ARM EHABI Unwind & Exception Handling
+
diff --git a/lib/libcxxabi/LICENSE.TXT b/lib/libcxxabi/LICENSE.TXT
new file mode 100644
index 00000000000..14fd39a9c4c
--- /dev/null
+++ b/lib/libcxxabi/LICENSE.TXT
@@ -0,0 +1,76 @@
+==============================================================================
+libc++abi License
+==============================================================================
+
+The libc++abi library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/lib/libcxxabi/cmake/config-ix.cmake b/lib/libcxxabi/cmake/config-ix.cmake
new file mode 100644
index 00000000000..baed2db8e41
--- /dev/null
+++ b/lib/libcxxabi/cmake/config-ix.cmake
@@ -0,0 +1,49 @@
+include(CheckLibraryExists)
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+
+# Check compiler flags
+check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES)
+check_cxx_compiler_flag(-fPIC LIBCXXABI_HAS_FPIC_FLAG)
+check_cxx_compiler_flag(-fno-exceptions LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG)
+check_cxx_compiler_flag(-fno-rtti LIBCXXABI_HAS_NO_RTTI_FLAG)
+check_cxx_compiler_flag(-fstrict-aliasing LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG)
+check_cxx_compiler_flag(-nodefaultlibs LIBCXXABI_HAS_NODEFAULTLIBS_FLAG)
+check_cxx_compiler_flag(-nostdinc++ LIBCXXABI_HAS_NOSTDINCXX_FLAG)
+check_cxx_compiler_flag(-Wall LIBCXXABI_HAS_WALL_FLAG)
+check_cxx_compiler_flag(-W LIBCXXABI_HAS_W_FLAG)
+check_cxx_compiler_flag(-Wno-unused-function LIBCXXABI_HAS_WNO_UNUSED_FUNCTION_FLAG)
+check_cxx_compiler_flag(-Wunused-variable LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG)
+check_cxx_compiler_flag(-Wunused-parameter LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG)
+check_cxx_compiler_flag(-Wstrict-aliasing LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG)
+check_cxx_compiler_flag(-Wstrict-overflow LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG)
+check_cxx_compiler_flag(-Wwrite-strings LIBCXXABI_HAS_WWRITE_STRINGS_FLAG)
+check_cxx_compiler_flag(-Wchar-subscripts LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG)
+check_cxx_compiler_flag(-Wmismatched-tags LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG)
+check_cxx_compiler_flag(-Wmissing-braces LIBCXXABI_HAS_WMISSING_BRACES_FLAG)
+check_cxx_compiler_flag(-Wshorten-64-to-32 LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG)
+check_cxx_compiler_flag(-Wsign-conversion LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG)
+check_cxx_compiler_flag(-Wsign-compare LIBCXXABI_HAS_WSIGN_COMPARE_FLAG)
+check_cxx_compiler_flag(-Wshadow LIBCXXABI_HAS_WSHADOW_FLAG)
+check_cxx_compiler_flag(-Wconversion LIBCXXABI_HAS_WCONVERSION_FLAG)
+check_cxx_compiler_flag(-Wnewline-eof LIBCXXABI_HAS_WNEWLINE_EOF_FLAG)
+check_cxx_compiler_flag(-Wundef LIBCXXABI_HAS_WUNDEF_FLAG)
+check_cxx_compiler_flag(-pedantic LIBCXXABI_HAS_PEDANTIC_FLAG)
+check_cxx_compiler_flag(-Werror LIBCXXABI_HAS_WERROR_FLAG)
+check_cxx_compiler_flag(-Wno-error LIBCXXABI_HAS_WNO_ERROR_FLAG)
+check_cxx_compiler_flag(/WX LIBCXXABI_HAS_WX_FLAG)
+check_cxx_compiler_flag(/WX- LIBCXXABI_HAS_NO_WX_FLAG)
+check_cxx_compiler_flag(/EHsc LIBCXXABI_HAS_EHSC_FLAG)
+check_cxx_compiler_flag(/EHs- LIBCXXABI_HAS_NO_EHS_FLAG)
+check_cxx_compiler_flag(/EHa- LIBCXXABI_HAS_NO_EHA_FLAG)
+check_cxx_compiler_flag(/GR- LIBCXXABI_HAS_NO_GR_FLAG)
+
+# Check libraries
+check_library_exists(c fopen "" LIBCXXABI_HAS_C_LIB)
+check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB)
+check_library_exists(pthread pthread_once "" LIBCXXABI_HAS_PTHREAD_LIB)
+if (NOT LIBCXXABI_USE_COMPILER_RT)
+ check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXXABI_HAS_GCC_S_LIB)
+endif ()
+check_library_exists(c __cxa_thread_atexit_impl ""
+ LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL)
diff --git a/lib/libcxxabi/include/__cxxabi_config.h b/lib/libcxxabi/include/__cxxabi_config.h
new file mode 100644
index 00000000000..61555f1a927
--- /dev/null
+++ b/lib/libcxxabi/include/__cxxabi_config.h
@@ -0,0 +1,47 @@
+//===-------------------------- __cxxabi_config.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 ____CXXABI_CONFIG_H
+#define ____CXXABI_CONFIG_H
+
+#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
+ !defined(__ARM_DWARF_EH__)
+#define LIBCXXABI_ARM_EHABI 1
+#else
+#define LIBCXXABI_ARM_EHABI 0
+#endif
+
+#if !defined(__has_attribute)
+#define __has_attribute(_attribute_) 0
+#endif
+
+#if defined(_LIBCXXABI_DLL)
+ #if defined(cxxabi_EXPORTS)
+ #define _LIBCXXABI_HIDDEN
+ #define _LIBCXXABI_DATA_VIS __declspec(dllexport)
+ #define _LIBCXXABI_FUNC_VIS __declspec(dllexport)
+ #define _LIBCXXABI_TYPE_VIS __declspec(dllexport)
+ #else
+ #define _LIBCXXABI_HIDDEN
+ #define _LIBCXXABI_DATA_VIS __declspec(dllimport)
+ #define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
+ #define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
+ #endif
+#else
+ #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
+ #define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default")))
+ #define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default")))
+ #if __has_attribute(__type_visibility__)
+ #define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default")))
+ #else
+ #define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default")))
+ #endif
+#endif
+
+#endif // ____CXXABI_CONFIG_H
diff --git a/lib/libcxxabi/include/cxxabi.h b/lib/libcxxabi/include/cxxabi.h
new file mode 100644
index 00000000000..e4a6797a815
--- /dev/null
+++ b/lib/libcxxabi/include/cxxabi.h
@@ -0,0 +1,177 @@
+//===--------------------------- cxxabi.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 __CXXABI_H
+#define __CXXABI_H
+
+/*
+ * This header provides the interface to the C++ ABI as defined at:
+ * http://www.codesourcery.com/cxx-abi/
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <__cxxabi_config.h>
+
+#define _LIBCPPABI_VERSION 1002
+#define LIBCXXABI_NORETURN __attribute__((noreturn))
+
+#ifdef __cplusplus
+
+namespace std {
+#if defined(_WIN32)
+class _LIBCXXABI_TYPE_VIS type_info; // forward declaration
+#else
+class type_info; // forward declaration
+#endif
+}
+
+
+// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
+namespace __cxxabiv1 {
+extern "C" {
+
+// 2.4.2 Allocating the Exception Object
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_allocate_exception(size_t thrown_size) throw();
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_free_exception(void *thrown_exception) throw();
+
+// 2.4.3 Throwing the Exception Object
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void
+__cxa_throw(void *thrown_exception, std::type_info *tinfo,
+ void (*dest)(void *));
+
+// 2.5.3 Exception Handlers
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_get_exception_ptr(void *exceptionObject) throw();
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_begin_catch(void *exceptionObject) throw();
+extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
+#if LIBCXXABI_ARM_EHABI
+extern _LIBCXXABI_FUNC_VIS bool
+__cxa_begin_cleanup(void *exceptionObject) throw();
+extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup();
+#endif
+extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type();
+
+// 2.5.4 Rethrowing Exceptions
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_rethrow();
+
+// 2.6 Auxiliary Runtime APIs
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_cast(void);
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void
+__cxa_throw_bad_array_new_length(void);
+
+// 3.2.6 Pure Virtual Function API
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
+
+// 3.2.7 Deleted Virtual Function API
+extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
+
+// 3.3.2 One-time Construction API
+#ifdef __arm__
+extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint32_t *);
+extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint32_t *);
+extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint32_t *);
+#else
+extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint64_t *);
+extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint64_t *);
+extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint64_t *);
+#endif
+
+// 3.3.3 Array Construction and Destruction API
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void *), void (*destructor)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void *), void (*destructor)(void *),
+ void *(*alloc)(size_t), void (*dealloc)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void *
+__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void *), void (*destructor)(void *),
+ void *(*alloc)(size_t), void (*dealloc)(void *, size_t));
+
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
+ void (*constructor)(void *), void (*destructor)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
+ size_t element_size,
+ size_t padding_size,
+ void (*destructor)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
+ void (*destructor)(void *), void (*dealloc)(void *));
+
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_vec_delete3(void *__array_address, size_t element_size,
+ size_t padding_size, void (*destructor)(void *),
+ void (*dealloc)(void *, size_t));
+
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count,
+ size_t element_size, void (*constructor)(void *, void *),
+ void (*destructor)(void *));
+
+// 3.3.5.3 Runtime API
+extern _LIBCXXABI_FUNC_VIS int __cxa_atexit(void (*f)(void *), void *p,
+ void *d);
+extern _LIBCXXABI_FUNC_VIS int __cxa_finalize(void *);
+
+// 3.4 Demangler API
+extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
+ char *output_buffer,
+ size_t *length, int *status);
+
+// Apple additions to support C++ 0x exception_ptr class
+// These are primitives to wrap a smart pointer around an exception object
+extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_rethrow_primary_exception(void *primary_exception);
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_increment_exception_refcount(void *primary_exception) throw();
+extern _LIBCXXABI_FUNC_VIS void
+__cxa_decrement_exception_refcount(void *primary_exception) throw();
+
+// Apple extension to support std::uncaught_exception()
+extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
+extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
+
+#ifdef __linux__
+// Linux TLS support. Not yet an official part of the Itanium ABI.
+// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
+extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
+ void *) throw();
+#endif
+
+} // extern "C"
+} // namespace __cxxabiv1
+
+namespace abi = __cxxabiv1;
+
+#endif // __cplusplus
+
+#endif // __CXXABI_H
diff --git a/lib/libcxxabi/lib/buildit b/lib/libcxxabi/lib/buildit
new file mode 100755
index 00000000000..5a4a71090f7
--- /dev/null
+++ b/lib/libcxxabi/lib/buildit
@@ -0,0 +1,99 @@
+#! /bin/sh
+#
+# Set the $TRIPLE environment variable to your system's triple before
+# running this script. If you set $CXX, that will be used to compile
+# the library. Otherwise we'll use clang++.
+
+set -e
+
+if [ `basename $(pwd)` != "lib" ]
+then
+ echo "current directory must be lib"
+ exit 1
+fi
+
+if [ -z "$CXX" ]
+then
+ CXX=clang++
+fi
+
+if [ -z "$CC" ]
+then
+ CC=clang
+fi
+
+if [ -z $RC_ProjectSourceVersion ]
+then
+ RC_ProjectSourceVersion=1
+fi
+
+EXTRA_FLAGS="-std=c++11 -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \
+ -Wsign-conversion -Wshadow -Wconversion -Wunused-variable \
+ -Wmissing-field-initializers -Wchar-subscripts -Wmismatched-tags \
+ -Wmissing-braces -Wshorten-64-to-32 -Wsign-compare \
+ -Wstrict-aliasing=2 -Wstrict-overflow=4 -Wunused-parameter \
+ -Wnewline-eof"
+
+case $TRIPLE in
+ *-apple-*)
+ if [ -z $RC_XBS ]
+ then
+ RC_CFLAGS="-arch i386 -arch x86_64"
+ fi
+ SOEXT=dylib
+ if [ -n "$SDKROOT" ]
+ then
+ EXTRA_FLAGS+="-isysroot ${SDKROOT}"
+ CXX=`xcrun -sdk "${SDKROOT}" -find clang++`
+ CC=`xcrun -sdk "${SDKROOT}" -find clang`
+ fi
+ LDSHARED_FLAGS="-o libc++abi.dylib \
+ -dynamiclib -nodefaultlibs \
+ -current_version ${RC_ProjectSourceVersion} \
+ -compatibility_version 1 \
+ -install_name /usr/lib/libc++abi.dylib \
+ -lSystem"
+ if [ -f "${SDKROOT}/usr/local/lib/libCrashReporterClient.a" ]
+ then
+ LDSHARED_FLAGS+=" -lCrashReporterClient"
+ fi
+ ;;
+ *-*-mingw*)
+ # FIXME: removing libgcc and libsupc++ dependencies means porting libcxxrt and LLVM/compiler-rt
+ SOEXT=dll
+ LDSHARED_FLAGS="-o libc++abi.dll \
+ -shared -nodefaultlibs -Wl,--export-all-symbols -Wl,--allow-multiple-definition -Wl,--out-implib,libc++abi.dll.a \
+ -lsupc++ -lpthread -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcr100 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt"
+ ;;
+ *)
+ RC_CFLAGS="-fPIC"
+ SOEXT=so
+ LDSHARED_FLAGS="-o libc++abi.so.1.0 \
+ -shared -nodefaultlibs -Wl,-soname,libc++abi.so.1 \
+ -lpthread -lrt -lc -lstdc++"
+ ;;
+esac
+
+if [ -z $RC_XBS ]
+then
+ rm -f libc++abi.1.$SOEXT*
+fi
+
+set -x
+
+for FILE in ../src/*.cpp; do
+ $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
+done
+case $TRIPLE in
+ *-*-mingw*)
+ for FILE in ../src/support/win32/*.cpp; do
+ $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
+ done
+ ;;
+esac
+$CC *.o $RC_CFLAGS $LDSHARED_FLAGS $EXTRA_FLAGS
+
+if [ -z $RC_XBS ]
+then
+ rm *.o
+fi
diff --git a/lib/libcxxabi/src/CMakeLists.txt b/lib/libcxxabi/src/CMakeLists.txt
new file mode 100644
index 00000000000..b851b4ac777
--- /dev/null
+++ b/lib/libcxxabi/src/CMakeLists.txt
@@ -0,0 +1,139 @@
+# Get sources
+set(LIBCXXABI_SOURCES
+ abort_message.cpp
+ cxa_aux_runtime.cpp
+ cxa_default_handlers.cpp
+ cxa_demangle.cpp
+ cxa_exception_storage.cpp
+ cxa_guard.cpp
+ cxa_handlers.cpp
+ cxa_new_delete.cpp
+ cxa_unexpected.cpp
+ cxa_vector.cpp
+ cxa_virtual.cpp
+ exception.cpp
+ private_typeinfo.cpp
+ stdexcept.cpp
+ typeinfo.cpp
+)
+
+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 (UNIX 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()
+
+# Generate library list
+set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES})
+
+if (LIBCXXABI_ENABLE_THREADS)
+ append_if(libraries LIBCXXABI_HAS_PTHREAD_LIB pthread)
+endif()
+
+append_if(libraries LIBCXXABI_HAS_C_LIB c)
+
+if (LIBCXXABI_USE_LLVM_UNWINDER)
+ list(APPEND libraries unwind)
+else()
+ append_if(libraries LIBCXXABI_HAS_GCC_S_LIB gcc_s)
+endif()
+
+# Setup flags.
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_FPIC_FLAG -fPIC)
+append_if(LIBCXXABI_LINK_FLAGS LIBCXXABI_HAS_NODEFAULTLIBS_FLAG -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()
+endif()
+
+string(REPLACE ";" " " LIBCXXABI_COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}")
+string(REPLACE ";" " " LIBCXXABI_LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}")
+string(REPLACE ";" " " LIBCXXABI_SHARED_LINK_FLAGS "${LIBCXXABI_SHARED_LINK_FLAGS}")
+
+# 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
+ COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}"
+ )
+
+set(LIBCXXABI_TARGETS)
+
+# Build the shared library.
+if (LIBCXXABI_ENABLE_SHARED)
+ add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>)
+ target_link_libraries(cxxabi_shared ${libraries})
+ set_target_properties(cxxabi_shared
+ PROPERTIES
+ LINK_FLAGS "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}"
+ OUTPUT_NAME "c++abi"
+ VERSION "1.0"
+ SOVERSION "1"
+ )
+ list(APPEND LIBCXXABI_TARGETS "cxxabi_shared")
+endif()
+
+# Build the static library.
+if (LIBCXXABI_ENABLE_STATIC)
+ add_library(cxxabi_static STATIC $<TARGET_OBJECTS:cxxabi_objects>)
+ target_link_libraries(cxxabi_static ${libraries})
+ set_target_properties(cxxabi_static
+ PROPERTIES
+ LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}"
+ OUTPUT_NAME "c++abi"
+ )
+ list(APPEND LIBCXXABI_TARGETS "cxxabi_static")
+endif()
+
+# Add a meta-target for both libraries.
+add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS})
+
+install(TARGETS ${LIBCXXABI_TARGETS}
+ LIBRARY DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT libcxxabi
+ ARCHIVE DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT libcxxabi
+ )
+
+if (NOT CMAKE_CONFIGURATION_TYPES)
+ add_custom_target(install-libcxxabi
+ DEPENDS cxxabi
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=libcxxabi
+ -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake")
+endif()
diff --git a/lib/libcxxabi/src/abort_message.cpp b/lib/libcxxabi/src/abort_message.cpp
new file mode 100644
index 00000000000..5e25c0f3472
--- /dev/null
+++ b/lib/libcxxabi/src/abort_message.cpp
@@ -0,0 +1,81 @@
+//===------------------------- 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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "abort_message.h"
+
+#ifdef __BIONIC__
+#include <android/api-level.h>
+#if __ANDROID_API__ >= 21
+#include <syslog.h>
+extern "C" void android_set_abort_message(const char* msg);
+#else
+#include <assert.h>
+#endif // __ANDROID_API__ >= 21
+#endif // __BIONIC__
+
+#pragma GCC visibility push(hidden)
+
+#ifdef __APPLE__
+# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
+# define HAVE_CRASHREPORTERCLIENT_H
+# include <CrashReporterClient.h>
+# endif
+#endif
+
+__attribute__((visibility("hidden"), noreturn))
+void abort_message(const char* format, ...)
+{
+ // write message to stderr
+#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");
+
+#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();
+}
+
+#pragma GCC visibility pop
diff --git a/lib/libcxxabi/src/abort_message.h b/lib/libcxxabi/src/abort_message.h
new file mode 100644
index 00000000000..2c5cb204664
--- /dev/null
+++ b/lib/libcxxabi/src/abort_message.h
@@ -0,0 +1,33 @@
+//===-------------------------- 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 <stdio.h>
+
+#pragma GCC visibility push(hidden)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__attribute__((visibility("hidden"), noreturn))
+ void abort_message(const char* format, ...)
+ __attribute__((format(printf, 1, 2)));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma GCC visibility pop
+
+#endif
+
diff --git a/lib/libcxxabi/src/config.h b/lib/libcxxabi/src/config.h
new file mode 100644
index 00000000000..ac6d297d113
--- /dev/null
+++ b/lib/libcxxabi/src/config.h
@@ -0,0 +1,31 @@
+//===----------------------------- config.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.
+//
+//
+// Defines macros used within the libc++abi project.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LIBCXXABI_CONFIG_H
+#define LIBCXXABI_CONFIG_H
+
+#include <unistd.h>
+
+// Set this in the CXXFLAGS when you need it
+#if !defined(LIBCXXABI_HAS_NO_THREADS)
+# define LIBCXXABI_HAS_NO_THREADS 0
+#endif
+
+// Set this in the CXXFLAGS when you need it, because otherwise we'd have to
+// #if !defined(__linux__) && !defined(__APPLE__) && ...
+// and so-on for *every* platform.
+#ifndef LIBCXXABI_BAREMETAL
+# define LIBCXXABI_BAREMETAL 0
+#endif
+
+#endif // LIBCXXABI_CONFIG_H
diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp
new file mode 100644
index 00000000000..bb7c9f1255c
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_aux_runtime.cpp
@@ -0,0 +1,44 @@
+//===------------------------ 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 <new>
+#include <typeinfo>
+
+namespace __cxxabiv1 {
+extern "C" {
+_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_cast(void) {
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ throw std::bad_cast();
+#else
+ std::terminate();
+#endif
+}
+
+_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_typeid(void) {
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ throw std::bad_typeid();
+#else
+ std::terminate();
+#endif
+}
+
+_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void
+__cxa_throw_bad_array_new_length(void) {
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ throw std::bad_array_new_length();
+#else
+ std::terminate();
+#endif
+}
+} // extern "C"
+} // abi
diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp
new file mode 100644
index 00000000000..09350e7721a
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_default_handlers.cpp
@@ -0,0 +1,126 @@
+//===------------------------- 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 <stdexcept>
+#include <new>
+#include <exception>
+#include "abort_message.h"
+#include "config.h" // For __sync_swap
+#include "cxxabi.h"
+#include "cxa_handlers.hpp"
+#include "cxa_exception.hpp"
+#include "private_typeinfo.h"
+
+static const char* cause = "uncaught";
+
+__attribute__((noreturn))
+static void default_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;
+ bool native_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ if (native_exception)
+ {
+ void* thrown_object =
+ unwind_exception->exception_class == kOurDependentExceptionClass ?
+ ((__cxa_dependent_exception*)exception_header)->primaryException :
+ exception_header + 1;
+ const __shim_type_info* thrown_type =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ // Try to get demangled name of thrown_type
+ int status;
+ char buf[1024];
+ size_t len = sizeof(buf);
+ const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
+ if (status != 0)
+ name = thrown_type->name();
+ // If the uncaught exception can be caught with std::exception&
+ const __shim_type_info* catch_type =
+ static_cast<const __shim_type_info*>(&typeid(std::exception));
+ if (catch_type->can_catch(thrown_type, thrown_object))
+ {
+ // Include the what() message from the exception
+ const std::exception* e = static_cast<const std::exception*>(thrown_object);
+ abort_message("terminating with %s exception of type %s: %s",
+ cause, name, e->what());
+ }
+ else
+ // Else just note that we're terminating with an exception
+ abort_message("terminating with %s exception of type %s",
+ cause, name);
+ }
+ else
+ // Else we're terminating with a foreign exception
+ abort_message("terminating with %s foreign exception", cause);
+ }
+ }
+ // Else just note that we're terminating
+ abort_message("terminating");
+}
+
+__attribute__((noreturn))
+static void default_unexpected_handler()
+{
+ cause = "unexpected";
+ std::terminate();
+}
+
+
+//
+// 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;
+
+// In the future these will become:
+// std::atomic<std::terminate_handler> __cxa_terminate_handler(default_terminate_handler);
+// std::atomic<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 __atomic_exchange_n(&__cxa_unexpected_handler, func,
+ __ATOMIC_ACQ_REL);
+// Using of C++11 atomics this should be rewritten
+// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel);
+}
+
+terminate_handler
+set_terminate(terminate_handler func) _NOEXCEPT
+{
+ if (func == 0)
+ func = default_terminate_handler;
+ return __atomic_exchange_n(&__cxa_terminate_handler, func,
+ __ATOMIC_ACQ_REL);
+// Using of C++11 atomics this should be rewritten
+// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel);
+}
+
+}
diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp
new file mode 100644
index 00000000000..25aa741299a
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_demangle.cpp
@@ -0,0 +1,5039 @@
+//===-------------------------- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LIBCPP_EXTERN_TEMPLATE(...)
+#define _LIBCPP_NO_EXCEPTIONS
+
+#include "__cxxabi_config.h"
+
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+#ifdef _MSC_VER
+// snprintf is implemented in VS 2015
+#if _MSC_VER < 1900
+#define snprintf _snprintf_s
+#endif
+#endif
+
+namespace __cxxabiv1
+{
+
+namespace
+{
+
+enum
+{
+ unknown_error = -4,
+ invalid_args = -3,
+ invalid_mangled_name,
+ memory_alloc_failure,
+ success
+};
+
+template <class C>
+ const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args = 0);
+template <class C>
+ const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_decltype(const char* first, const char* last, C& db);
+
+template <class C>
+void
+print_stack(const C& db)
+{
+ fprintf(stderr, "---------\n");
+ fprintf(stderr, "names:\n");
+ for (auto& s : db.names)
+ fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str());
+ int i = -1;
+ fprintf(stderr, "subs:\n");
+ for (auto& v : db.subs)
+ {
+ if (i >= 0)
+ fprintf(stderr, "S%i_ = {", i);
+ else
+ fprintf(stderr, "S_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ fprintf(stderr, "template_param:\n");
+ for (auto& t : db.template_param)
+ {
+ fprintf(stderr, "--\n");
+ i = -1;
+ for (auto& v : t)
+ {
+ if (i >= 0)
+ fprintf(stderr, "T%i_ = {", i);
+ else
+ fprintf(stderr, "T_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ }
+ fprintf(stderr, "---------\n\n");
+}
+
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
+{
+ fprintf(stderr, "%s: ", msg);
+ for (; first != last; ++first)
+ fprintf(stderr, "%c", *first);
+ fprintf(stderr, "\n");
+ print_stack(db);
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+parse_number(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ if (*t == 'n')
+ ++t;
+ if (t != last)
+ {
+ if (*t == '0')
+ {
+ first = t+1;
+ }
+ else if ('1' <= *t && *t <= '9')
+ {
+ first = t+1;
+ while (first != last && std::isdigit(*first))
+ ++first;
+ }
+ }
+ }
+ return first;
+}
+
+template <class Float>
+struct float_data;
+
+template <>
+struct float_data<float>
+{
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static constexpr const char* spec = "%af";
+};
+
+constexpr const char* float_data<float>::spec;
+
+template <>
+struct float_data<double>
+{
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static constexpr const char* spec = "%a";
+};
+
+constexpr const char* float_data<double>::spec;
+
+template <>
+struct float_data<long double>
+{
+#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
+ defined(__wasm__)
+ static const size_t mangled_size = 32;
+#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static constexpr const char* spec = "%LaL";
+};
+
+constexpr const char* float_data<long double>::spec;
+
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
+{
+ const size_t N = float_data<Float>::mangled_size;
+ if (static_cast<std::size_t>(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)
+ {
+ if (!isxdigit(*t))
+ return first;
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ *e = static_cast<char>((d1 << 4) + d0);
+ }
+ if (*t == 'E')
+ {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[float_data<Float>::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+ if (static_cast<std::size_t>(n) >= sizeof(num))
+ return first;
+ db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ char c = *first;
+ if (isdigit(c) && first+1 != last)
+ {
+ const char* t = first+1;
+ size_t n = static_cast<size_t>(c - '0');
+ for (c = *t; isdigit(c); c = *t)
+ {
+ n = n * 10 + static_cast<size_t>(c - '0');
+ if (++t == last)
+ return first;
+ }
+ if (static_cast<size_t>(last - t) >= n)
+ {
+ typename C::String r(t, n);
+ if (r.substr(0, 10) == "_GLOBAL__N")
+ db.names.push_back("(anonymous namespace)");
+ else
+ db.names.push_back(std::move(r));
+ first = t + n;
+ }
+ }
+ }
+ return first;
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+
+template <class C>
+const char*
+parse_substitution(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'S')
+ {
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("std::allocator");
+ first += 2;
+ break;
+ case 'b':
+ db.names.push_back("std::basic_string");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("std::string");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("std::istream");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("std::ostream");
+ first += 2;
+ break;
+ case 'd':
+ db.names.push_back("std::iostream");
+ first += 2;
+ break;
+ case '_':
+ if (!db.subs.empty())
+ {
+ for (const auto& n : db.subs.front())
+ db.names.push_back(n);
+ first += 2;
+ }
+ break;
+ default:
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < db.subs.size())
+ {
+ for (const auto& n : db.subs[sub])
+ db.names.push_back(n);
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <builtin-type> ::= v # void
+// ::= w # wchar_t
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= n # __int128
+// ::= o # unsigned __int128
+// ::= f # float
+// ::= d # double
+// ::= e # long double, __float80
+// ::= g # __float128
+// ::= z # ellipsis
+// ::= Dd # IEEE 754r decimal floating point (64 bits)
+// ::= De # IEEE 754r decimal floating point (128 bits)
+// ::= Df # IEEE 754r decimal floating point (32 bits)
+// ::= Dh # IEEE 754r half-precision floating point (16 bits)
+// ::= Di # char32_t
+// ::= Ds # char16_t
+// ::= Da # auto (in dependent new-expressions)
+// ::= Dc # decltype(auto)
+// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+// ::= u <source-name> # vendor extended type
+
+template <class C>
+const char*
+parse_builtin_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'v':
+ db.names.push_back("void");
+ ++first;
+ break;
+ case 'w':
+ db.names.push_back("wchar_t");
+ ++first;
+ break;
+ case 'b':
+ db.names.push_back("bool");
+ ++first;
+ break;
+ case 'c':
+ db.names.push_back("char");
+ ++first;
+ break;
+ case 'a':
+ db.names.push_back("signed char");
+ ++first;
+ break;
+ case 'h':
+ db.names.push_back("unsigned char");
+ ++first;
+ break;
+ case 's':
+ db.names.push_back("short");
+ ++first;
+ break;
+ case 't':
+ db.names.push_back("unsigned short");
+ ++first;
+ break;
+ case 'i':
+ db.names.push_back("int");
+ ++first;
+ break;
+ case 'j':
+ db.names.push_back("unsigned int");
+ ++first;
+ break;
+ case 'l':
+ db.names.push_back("long");
+ ++first;
+ break;
+ case 'm':
+ db.names.push_back("unsigned long");
+ ++first;
+ break;
+ case 'x':
+ db.names.push_back("long long");
+ ++first;
+ break;
+ case 'y':
+ db.names.push_back("unsigned long long");
+ ++first;
+ break;
+ case 'n':
+ db.names.push_back("__int128");
+ ++first;
+ break;
+ case 'o':
+ db.names.push_back("unsigned __int128");
+ ++first;
+ break;
+ case 'f':
+ db.names.push_back("float");
+ ++first;
+ break;
+ case 'd':
+ db.names.push_back("double");
+ ++first;
+ break;
+ case 'e':
+ db.names.push_back("long double");
+ ++first;
+ break;
+ case 'g':
+ db.names.push_back("__float128");
+ ++first;
+ break;
+ case 'z':
+ db.names.push_back("...");
+ ++first;
+ break;
+ case 'u':
+ {
+ const char*t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ first = t;
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'd':
+ db.names.push_back("decimal64");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("decimal128");
+ first += 2;
+ break;
+ case 'f':
+ db.names.push_back("decimal32");
+ first += 2;
+ break;
+ case 'h':
+ db.names.push_back("decimal16");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("char32_t");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("char16_t");
+ first += 2;
+ break;
+ case 'a':
+ db.names.push_back("auto");
+ first += 2;
+ break;
+ case 'c':
+ db.names.push_back("decltype(auto)");
+ first += 2;
+ break;
+ case 'n':
+ db.names.push_back("std::nullptr_t");
+ first += 2;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+
+const char*
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
+{
+ cv = 0;
+ if (first != last)
+ {
+ if (*first == 'r')
+ {
+ cv |= 4;
+ ++first;
+ }
+ if (*first == 'V')
+ {
+ cv |= 2;
+ ++first;
+ }
+ if (*first == 'K')
+ {
+ cv |= 1;
+ ++first;
+ }
+ }
+ return first;
+}
+
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
+template <class C>
+const char*
+parse_template_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'T')
+ {
+ if (first[1] == '_')
+ {
+ if (db.template_param.empty())
+ return first;
+ if (!db.template_param.back().empty())
+ {
+ for (auto& t : db.template_param.back().front())
+ db.names.push_back(t);
+ first += 2;
+ }
+ else
+ {
+ db.names.push_back("T_");
+ first += 2;
+ db.fix_forward_references = true;
+ }
+ }
+ else if (isdigit(first[1]))
+ {
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
+ {
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
+ }
+ if (t == last || *t != '_' || db.template_param.empty())
+ return first;
+ ++sub;
+ if (sub < db.template_param.back().size())
+ {
+ for (auto& temp : db.template_param.back()[sub])
+ db.names.push_back(temp);
+ first = t+1;
+ }
+ else
+ {
+ db.names.push_back(typename C::String(first, t+1));
+ first = t+1;
+ db.fix_forward_references = true;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// cc <type> <expression> # const_cast<type> (expression)
+
+template <class C>
+const char*
+parse_const_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dc <type> <expression> # dynamic_cast<type> (expression)
+
+template <class C>
+const char*
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+
+template <class C>
+const char*
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sc <type> <expression> # static_cast<type> (expression)
+
+template <class C>
+const char*
+parse_static_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sp <expression> # pack expansion
+
+template <class C>
+const char*
+parse_pack_expansion(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ return first;
+}
+
+// st <type> # sizeof (a type)
+
+template <class C>
+const char*
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sz <expr> # sizeof (a expression)
+
+template <class C>
+const char*
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <template-param> # size of a parameter pack
+
+template <class C>
+const char*
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+ {
+ size_t k0 = db.names.size();
+ const char* t = parse_template_param(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ typename C::String tmp("sizeof...(");
+ size_t k = k0;
+ if (k != k1)
+ {
+ tmp += db.names[k].move_full();
+ for (++k; k != k1; ++k)
+ tmp += ", " + db.names[k].move_full();
+ }
+ tmp += ")";
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ db.names.push_back(std::move(tmp));
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+
+template <class C>
+const char*
+parse_function_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && *first == 'f')
+ {
+ if (first[1] == 'p')
+ {
+ unsigned cv;
+ const char* t = parse_cv_qualifiers(first+2, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ else if (first[1] == 'L')
+ {
+ unsigned cv;
+ const char* t0 = parse_number(first+2, last);
+ if (t0 != last && *t0 == 'p')
+ {
+ ++t0;
+ const char* t = parse_cv_qualifiers(t0, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// sZ <function-param> # size of a function parameter pack
+
+template <class C>
+const char*
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ {
+ const char* t = parse_function_param(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+ {
+ const char* t;
+ if (first[1] == 'e')
+ t = parse_expression(first+2, last, db);
+ else
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// tw <expression> # throw expression
+
+template <class C>
+const char*
+parse_throw_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "throw " + db.names.back().move_full();
+ first = t;
+ }
+ }
+ return first;
+}
+
+// ds <expression> <expression> # expr.*expr
+
+template <class C>
+const char*
+parse_dot_star_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += ".*" + expr;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+template <class C>
+const char*
+parse_simple_id(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ first = t1;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_unresolved_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ switch (*first)
+ {
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first && k1 == k0 + 1)
+ {
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ else
+ {
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ }
+ break;
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ break;
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
+ {
+ if (last - first > 2 && first[1] == 't')
+ {
+ t = parse_unqualified_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+
+template <class C>
+const char*
+parse_destructor_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "~");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= on <operator-name> <template-args> # unresolved operator template-id
+// ::= dn <destructor-name> # destructor or pseudo-destructor;
+// # e.g. ~X or ~X<N-1>
+
+template <class C>
+const char*
+parse_base_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+ {
+ if (first[0] == 'o')
+ {
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <unresolved-qualifier-level> ::= <simple-id>
+
+template <class C>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
+{
+ return parse_simple_id(first, last, db);
+}
+
+// <unresolved-name>
+// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ global = true;
+ t += 2;
+ }
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
+ {
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// dt <expression> <unresolved-name> # expr.name
+
+template <class C>
+const char*
+parse_dot_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_unresolved_name(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first += "." + name;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// cl <expression>+ E # call
+
+template <class C>
+const char*
+parse_call_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (t == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += db.names.back().second;
+ db.names.back().second = typename C::String();
+ db.names.back().first.append("(");
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_expr)
+ {
+ db.names.back().first.append(", ");
+ first_expr = false;
+ }
+ db.names.back().first.append(tmp);
+ }
+ t = t1;
+ }
+ ++t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+
+template <class C>
+const char*
+parse_new_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
+ {
+ bool is_array = t[1] == 'a';
+ t += 2;
+ if (t == last)
+ return first;
+ bool has_expr_list = false;
+ bool first_expr = true;
+ while (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ has_expr_list = true;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ ++t;
+ const char* t1 = parse_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ bool has_init = false;
+ if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+ {
+ t += 2;
+ has_init = true;
+ first_expr = true;
+ while (*t != 'E')
+ {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ if (*t != 'E')
+ return first;
+ typename C::String init_list;
+ if (has_init)
+ {
+ if (db.names.empty())
+ return first;
+ init_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ if (db.names.empty())
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ typename C::String expr_list;
+ if (has_expr_list)
+ {
+ if (db.names.empty())
+ return first;
+ expr_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ typename C::String r;
+ if (parsed_gs)
+ r = "::";
+ if (is_array)
+ r += "[] ";
+ else
+ r += " ";
+ if (has_expr_list)
+ r += "(" + expr_list + ") ";
+ r += type;
+ if (has_init)
+ r += " (" + init_list + ")";
+ db.names.push_back(std::move(r));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+
+template <class C>
+const char*
+parse_conversion_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2 && t != last)
+ {
+ if (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ db.names.emplace_back();
+ else
+ {
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ ++t;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pt <expression> <expression> # expr->name
+
+template <class C>
+const char*
+parse_arrow_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "->";
+ db.names.back().first += tmp;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+
+template <class C>
+const char*
+parse_function_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'F')
+ {
+ const char* t = first+1;
+ if (t != last)
+ {
+ if (*t == 'Y')
+ {
+ /* extern "C" */
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ typename C::String sig("(");
+ int ref_qual = 0;
+ while (true)
+ {
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (*t == 'E')
+ {
+ ++t;
+ break;
+ }
+ if (*t == 'v')
+ {
+ ++t;
+ continue;
+ }
+ if (*t == 'R' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 1;
+ ++t;
+ continue;
+ }
+ if (*t == 'O' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 2;
+ ++t;
+ continue;
+ }
+ size_t k0 = db.names.size();
+ t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 == t || t1 == last)
+ return first;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (sig.size() > 1)
+ sig += ", ";
+ sig += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ t = t1;
+ }
+ sig += ")";
+ switch (ref_qual)
+ {
+ case 1:
+ sig += " &";
+ break;
+ case 2:
+ sig += " &&";
+ break;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " ";
+ db.names.back().second.insert(0, sig);
+ first = t;
+ }
+ }
+ }
+ return first;
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+template <class C>
+const char*
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'M')
+ {
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto func = std::move(db.names.back());
+ db.names.pop_back();
+ auto class_type = std::move(db.names.back());
+ if (!func.second.empty() && func.second.front() == '(')
+ {
+ db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+ db.names.back().second = ")" + std::move(func.second);
+ }
+ else
+ {
+ db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+ db.names.back().second = std::move(func.second);
+ }
+ first = t2;
+ }
+ }
+ }
+ return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+
+template <class C>
+const char*
+parse_array_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'A' && first+1 != last)
+ {
+ if (first[1] == '_')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " []");
+ first = t;
+ }
+ }
+ else if ('1' <= first[1] && first[1] <= '9')
+ {
+ const char* t = parse_number(first+1, last);
+ if (t != last && *t == '_')
+ {
+ const char* t2 = parse_type(t+1, last, db);
+ if (t2 != t+1)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_expression(first+1, last, db);
+ if (t != first+1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_type(++t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = std::move(db.names.back());
+ db.names.pop_back();
+ auto expr = std::move(db.names.back());
+ db.names.back().first = std::move(type.first);
+ if (type.second.substr(0, 2) == " [")
+ type.second.erase(0, 1);
+ db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+
+template <class C>
+const char*
+parse_decltype(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'D')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'T':
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+
+template <class C>
+const char*
+parse_vector_type(const char* first, const char* last, C& db)
+{
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+ {
+ if ('1' <= first[2] && first[2] <= '9')
+ {
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
+ const char* num = first + 2;
+ size_t sz = static_cast<size_t>(t - num);
+ if (++t != last)
+ {
+ if (*t != 'p')
+ {
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+ first = t1;
+ }
+ }
+ else
+ {
+ ++t;
+ db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ typename C::String num;
+ const char* t1 = first+2;
+ if (*t1 != '_')
+ {
+ const char* t = parse_expression(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ num = db.names.back().move_full();
+ db.names.pop_back();
+ t1 = t;
+ }
+ }
+ if (t1 != last && *t1 == '_' && ++t1 != last)
+ {
+ const char* t = parse_type(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + num + "]";
+ first = t;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <type> ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= <substitution>
+// ::= <CV-qualifiers> <type>
+// ::= P <type> # pointer-to
+// ::= R <type> # reference-to
+// ::= O <type> # rvalue reference-to (C++0x)
+// ::= C <type> # complex pair (C 2000)
+// ::= G <type> # imaginary (C 2000)
+// ::= Dp <type> # pack expansion (C++0x)
+// ::= U <source-name> <type> # vendor extended type qualifier
+// extension := U <objc-name> <objc-type> # objc-type<identifier>
+// extension := <vector-type> # <vector-type> starts with Dv
+
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+
+template <class C>
+const char*
+parse_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ unsigned cv = 0;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
+ {
+ bool is_function = *t == 'F';
+ size_t k0 = db.names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 != t)
+ {
+ if (is_function)
+ db.subs.pop_back();
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (is_function)
+ {
+ size_t p = db.names[k].second.size();
+ if (db.names[k].second[p-2] == '&')
+ p -= 3;
+ else if (db.names[k].second.back() == '&')
+ p -= 2;
+ if (cv & 1)
+ {
+ db.names[k].second.insert(p, " const");
+ p += 6;
+ }
+ if (cv & 2)
+ {
+ db.names[k].second.insert(p, " volatile");
+ p += 9;
+ }
+ if (cv & 4)
+ db.names[k].second.insert(p, " restrict");
+ }
+ else
+ {
+ if (cv & 1)
+ db.names[k].first.append(" const");
+ if (cv & 2)
+ db.names[k].first.append(" volatile");
+ if (cv & 4)
+ db.names[k].first.append(" restrict");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" complex");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'G':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" imaginary");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'O':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'P':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+ {
+ db.names[k].first.append("*");
+ }
+ else
+ {
+ db.names[k].first.replace(0, 11, "id");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'R':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ if (db.try_to_parse_template_args && k1 == k0+1)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t = t1;
+ }
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'U':
+ if (first+1 != last)
+ {
+ t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.back().first.substr(0, 9) != "objcproto")
+ {
+ db.names.back() = type + " " + db.names.back().move_full();
+ }
+ else
+ {
+ auto proto = db.names.back().move_full();
+ db.names.pop_back();
+ t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+ if (t != proto.data() + 9)
+ {
+ db.names.back() = type + "<" + db.names.back().move_full() + ">";
+ }
+ else
+ {
+ db.names.push_back(type + " " + proto);
+ }
+ }
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t2;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ else
+ {
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = parse_template_args(first, last, db);
+ if (t != first)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto template_args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += template_args;
+ // Need to create substitution for <template-template-param> <template-args>
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ first = t;
+ return first;
+ }
+ break;
+ }
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ switch (first[0])
+ {
+ case 'a':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator&&");
+ first += 2;
+ break;
+ case 'd':
+ case 'n':
+ db.names.push_back("operator&");
+ first += 2;
+ break;
+ case 'N':
+ db.names.push_back("operator&=");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'c':
+ switch (first[1])
+ {
+ case 'l':
+ db.names.push_back("operator()");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator,");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("operator~");
+ first += 2;
+ break;
+ case 'v':
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ db.parsed_ctor_dtor_cv = true;
+ first = t;
+ }
+ }
+ break;
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator delete[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator delete");
+ first += 2;
+ break;
+ case 'v':
+ db.names.push_back("operator/");
+ first += 2;
+ break;
+ case 'V':
+ db.names.push_back("operator/=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'e':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator^");
+ first += 2;
+ break;
+ case 'O':
+ db.names.push_back("operator^=");
+ first += 2;
+ break;
+ case 'q':
+ db.names.push_back("operator==");
+ first += 2;
+ break;
+ }
+ break;
+ case 'g':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator>=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator>");
+ first += 2;
+ break;
+ }
+ break;
+ case 'i':
+ if (first[1] == 'x')
+ {
+ db.names.push_back("operator[]");
+ first += 2;
+ }
+ break;
+ case 'l':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator<=");
+ first += 2;
+ break;
+ case 'i':
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator\"\" ");
+ first = t;
+ }
+ }
+ break;
+ case 's':
+ db.names.push_back("operator<<");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator<<=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator<");
+ first += 2;
+ break;
+ }
+ break;
+ case 'm':
+ switch (first[1])
+ {
+ case 'i':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 'I':
+ db.names.push_back("operator-=");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator*=");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator--");
+ first += 2;
+ break;
+ }
+ break;
+ case 'n':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator new[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator!=");
+ first += 2;
+ break;
+ case 'g':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator!");
+ first += 2;
+ break;
+ case 'w':
+ db.names.push_back("operator new");
+ first += 2;
+ break;
+ }
+ break;
+ case 'o':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator||");
+ first += 2;
+ break;
+ case 'r':
+ db.names.push_back("operator|");
+ first += 2;
+ break;
+ case 'R':
+ db.names.push_back("operator|=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator->*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator+=");
+ first += 2;
+ break;
+ case 'p':
+ db.names.push_back("operator++");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator->");
+ first += 2;
+ break;
+ }
+ break;
+ case 'q':
+ if (first[1] == 'u')
+ {
+ db.names.push_back("operator?");
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator%");
+ first += 2;
+ break;
+ case 'M':
+ db.names.push_back("operator%=");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator>>");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator>>=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+ const char* t = parse_number(first, last);
+ if (t != first && t != last && *t == 'E')
+ {
+ if (lit.size() > 3)
+ db.names.push_back("(" + lit + ")");
+ else
+ db.names.emplace_back();
+ if (*first == 'n')
+ {
+ db.names.back().first += '-';
+ ++first;
+ }
+ db.names.back().first.append(first, t);
+ if (lit.size() <= 3)
+ db.names.back().first += lit;
+ first = t+1;
+ }
+ return first;
+}
+
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
+ {
+ const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
+ {
+ case '0':
+ db.names.push_back("false");
+ first += 4;
+ break;
+ case '1':
+ db.names.push_back("true");
+ first += 4;
+ break;
+ }
+ }
+ break;
+ case 'c':
+ {
+ const char* t = parse_integer_literal(first+2, last, "char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'a':
+ {
+ const char* t = parse_integer_literal(first+2, last, "signed char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'h':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 's':
+ {
+ const char* t = parse_integer_literal(first+2, last, "short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 't':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'i':
+ {
+ const char* t = parse_integer_literal(first+2, last, "", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'j':
+ {
+ const char* t = parse_integer_literal(first+2, last, "u", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'l':
+ {
+ const char* t = parse_integer_literal(first+2, last, "l", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'm':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ul", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'x':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ll", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'y':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ull", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'n':
+ {
+ const char* t = parse_integer_literal(first+2, last, "__int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'o':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'f':
+ {
+ const char* t = parse_floating_number<float>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'd':
+ {
+ const char* t = parse_floating_number<double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'e':
+ {
+ const char* t = parse_floating_number<long double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = parse_encoding(first+3, last, db);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1 && t != last)
+ {
+ if (*t != 'E')
+ {
+ const char* n = t;
+ for (; n != last && isdigit(*n); ++n)
+ ;
+ if (n != t && n != last && *n == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+ first = n+1;
+ break;
+ }
+ }
+ else
+ {
+ first = t+1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+template <class String>
+String
+base_name(String& s)
+{
+ if (s.empty())
+ return s;
+ if (s == "std::string")
+ {
+ s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+ return "basic_string";
+ }
+ if (s == "std::istream")
+ {
+ s = "std::basic_istream<char, std::char_traits<char> >";
+ return "basic_istream";
+ }
+ if (s == "std::ostream")
+ {
+ s = "std::basic_ostream<char, std::char_traits<char> >";
+ return "basic_ostream";
+ }
+ if (s == "std::iostream")
+ {
+ s = "std::basic_iostream<char, std::char_traits<char> >";
+ return "basic_iostream";
+ }
+ const char* const pf = s.data();
+ const char* pe = pf + s.size();
+ if (pe[-1] == '>')
+ {
+ unsigned c = 1;
+ while (true)
+ {
+ if (--pe == pf)
+ return String();
+ if (pe[-1] == '<')
+ {
+ if (--c == 0)
+ {
+ --pe;
+ break;
+ }
+ }
+ else if (pe[-1] == '>')
+ ++c;
+ }
+ }
+ if (pe - pf <= 1)
+ return String();
+ const char* p0 = pe - 1;
+ for (; p0 != pf; --p0)
+ {
+ if (*p0 == ':')
+ {
+ ++p0;
+ break;
+ }
+ }
+ return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= 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 <class C>
+const char*
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
+{
+ if (last-first >= 2 && !db.names.empty())
+ {
+ switch (first[0])
+ {
+ case 'C':
+ switch (first[1])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back(base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ case 'D':
+ switch (first[1])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back("~" + base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+
+template <class C>
+const char*
+parse_unnamed_type_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2 && first[0] == 'U')
+ {
+ char type = first[1];
+ switch (type)
+ {
+ case 't':
+ {
+ db.names.push_back(typename C::String("'unnamed"));
+ const char* t0 = first+2;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.append(t0, t1);
+ t0 = t1;
+ }
+ db.names.back().first.push_back('\'');
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ case 'l':
+ {
+ db.names.push_back(typename C::String("'lambda'("));
+ const char* t0 = first+2;
+ if (first[2] == 'v')
+ {
+ db.names.back().first += ')';
+ ++t0;
+ }
+ else
+ {
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ {
+ if(!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append(tmp);
+ t0 = t1;
+ while (true)
+ {
+ t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ break;
+ if (db.names.size() < 2)
+ return first;
+ tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ }
+ t0 = t1;
+ }
+ if(db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ }
+ if (t0 == last || *t0 != 'E')
+ {
+ if(!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ ++t0;
+ if (t0 == last)
+ {
+ if(!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+ t0 = t1;
+ }
+ if (t0 == last || *t0 != '_')
+ {
+ if(!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+template <class C>
+const char*
+parse_unqualified_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ }
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// az <expression> # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = op + "(" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ auto& nm = db.names.back().first;
+ nm.clear();
+ if (op == ">")
+ nm += '(';
+ nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+ if (op == ">")
+ nm += ')';
+ first = t2;
+ }
+ else if(!db.names.empty())
+ db.names.pop_back();
+ }
+ return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= sz <expression> # sizeof (an expression)
+// ::= at <type> # alignof (a type)
+// ::= az <expression> # alignof (an expression)
+// ::= nx <expression> # noexcept (expression)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= sp <expression> # pack expansion
+// ::= tw <expression> # throw expression
+// ::= tr # throw with no operand (rethrow)
+// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+// # freestanding dependent name (e.g., T::x),
+// # objectless nonstatic member reference
+// ::= <expr-primary>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ switch (*t)
+ {
+ case 'L':
+ first = parse_expr_primary(first, last, db);
+ break;
+ case 'T':
+ first = parse_template_param(first, last, db);
+ break;
+ case 'f':
+ first = parse_function_param(first, last, db);
+ break;
+ case 'a':
+ switch (t[1])
+ {
+ case 'a':
+ t = parse_binary_expression(first+2, last, "&&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'd':
+ t = parse_prefix_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'n':
+ t = parse_binary_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'N':
+ t = parse_binary_expression(first+2, last, "&=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_alignof_type(first, last, db);
+ break;
+ case 'z':
+ first = parse_alignof_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'c':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_const_cast_expr(first, last, db);
+ break;
+ case 'l':
+ first = parse_call_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, ",", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'o':
+ t = parse_prefix_expression(first+2, last, "~", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'v':
+ first = parse_conversion_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'd':
+ switch (t[1])
+ {
+ case 'a':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete[] " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'c':
+ first = parse_dynamic_cast_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_prefix_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 's':
+ first = parse_dot_star_expr(first, last, db);
+ break;
+ case 't':
+ first = parse_dot_expr(first, last, db);
+ break;
+ case 'v':
+ t = parse_binary_expression(first+2, last, "/", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'V':
+ t = parse_binary_expression(first+2, last, "/=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'e':
+ switch (t[1])
+ {
+ case 'o':
+ t = parse_binary_expression(first+2, last, "^", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'O':
+ t = parse_binary_expression(first+2, last, "^=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'q':
+ t = parse_binary_expression(first+2, last, "==", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'g':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, ">=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, ">", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'i':
+ if (t[1] == 'x')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ")[" + op2 + "]";
+ first = t2;
+ }
+ else if (!db.names.empty())
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'l':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, "<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, "<<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "<<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, "<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'm':
+ switch (t[1])
+ {
+ case 'i':
+ t = parse_binary_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'I':
+ t = parse_binary_expression(first+2, last, "-=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "*=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'm':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "--", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")--";
+ first = t1;
+ }
+ }
+ break;
+ }
+ break;
+ case 'n':
+ switch (t[1])
+ {
+ case 'a':
+ case 'w':
+ first = parse_new_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_binary_expression(first+2, last, "!=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'g':
+ t = parse_prefix_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_prefix_expression(first+2, last, "!", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'x':
+ t = parse_noexcept_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'o':
+ switch (t[1])
+ {
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 'o':
+ t = parse_binary_expression(first+2, last, "||", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'r':
+ t = parse_binary_expression(first+2, last, "|", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'R':
+ t = parse_binary_expression(first+2, last, "|=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'p':
+ switch (t[1])
+ {
+ case 'm':
+ t = parse_binary_expression(first+2, last, "->*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "+=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'p':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "++", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")++";
+ first = t1;
+ }
+ }
+ break;
+ case 's':
+ t = parse_prefix_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_arrow_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'q':
+ if (t[1] == 'u')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ const char* t3 = parse_expression(t2, last, db);
+ if (t3 != t2)
+ {
+ if (db.names.size() < 3)
+ return first;
+ auto op3 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+ first = t3;
+ }
+ else
+ {
+ if (db.names.size() < 2)
+ return first;
+ db.names.pop_back();
+ db.names.pop_back();
+ }
+ }
+ else if (!db.names.empty())
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'r':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_reinterpret_cast_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, "%", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'M':
+ t = parse_binary_expression(first+2, last, "%=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, ">>", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, ">>=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 's':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_static_cast_expr(first, last, db);
+ break;
+ case 'p':
+ first = parse_pack_expansion(first, last, db);
+ break;
+ case 'r':
+ return parse_unresolved_name(first, last, db);
+ case 't':
+ first = parse_sizeof_type_expr(first, last, db);
+ break;
+ case 'z':
+ first = parse_sizeof_expr_expr(first, last, db);
+ break;
+ case 'Z':
+ if (last - t >= 3)
+ {
+ switch (t[2])
+ {
+ case 'T':
+ first = parse_sizeof_param_pack_expr(first, last, db);
+ break;
+ case 'f':
+ first = parse_sizeof_function_param_pack_expr(first, last, db);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ first = parse_typeid_expr(first, last, db);
+ break;
+ case 'r':
+ db.names.push_back("throw");
+ first += 2;
+ break;
+ case 'w':
+ first = parse_throw_expr(first, last, db);
+ break;
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parse_unresolved_name(first, last, db);
+ }
+ }
+ return first;
+}
+
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+
+template <class C>
+const char*
+parse_template_arg(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
+ {
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ first = t+1;
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
+ }
+ else
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+
+template <class C>
+const char*
+parse_template_args(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2 && *first == 'I')
+ {
+ if (db.tag_templates)
+ db.template_param.back().clear();
+ const char* t = first+1;
+ typename C::String args("<");
+ while (*t != 'E')
+ {
+ if (db.tag_templates)
+ db.template_param.emplace_back(db.names.get_allocator());
+ size_t k0 = db.names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.names.size();
+ if (db.tag_templates)
+ db.template_param.pop_back();
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.tag_templates)
+ {
+ db.template_param.back().emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.template_param.back().back().push_back(db.names[k]);
+ }
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (args.size() > 1)
+ args += ", ";
+ args += db.names[k].move_full();
+ }
+ for (; k1 > k0; --k1)
+ if (!db.names.empty())
+ db.names.pop_back();
+ t = t1;
+ }
+ first = t + 1;
+ if (args.back() != '>')
+ args += ">";
+ else
+ args += " >";
+ db.names.push_back(std::move(args));
+
+ }
+ return first;
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::= # empty
+// ::= <substitution>
+// ::= <prefix> <data-member-prefix>
+// extension ::= L
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_nested_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'N')
+ {
+ unsigned cv;
+ const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+ if (t0 == last)
+ return first;
+ db.ref = 0;
+ if (*t0 == 'R')
+ {
+ db.ref = 1;
+ ++t0;
+ }
+ else if (*t0 == 'O')
+ {
+ db.ref = 2;
+ ++t0;
+ }
+ db.names.emplace_back();
+ if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+ {
+ t0 += 2;
+ db.names.back().first = "std";
+ }
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ bool pop_subs = false;
+ bool component_ends_with_template_args = false;
+ while (*t0 != 'E')
+ {
+ component_ends_with_template_args = false;
+ const char* t1;
+ switch (*t0)
+ {
+ case 'S':
+ if (t0 + 1 != last && t0[1] == 't')
+ goto do_parse_unqualified_name;
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ if (!db.names.back().first.empty())
+ {
+ db.names.back().first += "::" + name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ else
+ db.names.back().first = name;
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'T':
+ t1 = parse_template_param(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'D':
+ if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+ goto do_parse_unqualified_name;
+ t1 = parse_decltype(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'I':
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first += name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ component_ends_with_template_args = true;
+ }
+ else
+ return first;
+ break;
+ case 'L':
+ if (++t0 == last)
+ return first;
+ break;
+ default:
+ do_parse_unqualified_name:
+ t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ }
+ }
+ first = t0 + 1;
+ db.cv = cv;
+ if (pop_subs && !db.subs.empty())
+ db.subs.pop_back();
+ if (ends_with_template_args)
+ *ends_with_template_args = component_ends_with_template_args;
+ }
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+ # at the end of string
+
+const char*
+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;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = parse_encoding(first+1, last, db);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ switch (*t)
+ {
+ case 's':
+ first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::string literal");
+ break;
+ case 'd':
+ if (++t != last)
+ {
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ t = t1 + 1;
+ t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ first = t1;
+ }
+ else if (!db.names.empty())
+ db.names.pop_back();
+ }
+ }
+ break;
+ default:
+ {
+ const char* t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ }
+ else if (!db.names.empty())
+ db.names.pop_back();
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ switch (*t0)
+ {
+ case 'N':
+ {
+ const char* t1 = parse_nested_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ case 'Z':
+ {
+ const char* t1 = parse_local_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ default:
+ {
+ const char* t1 = parse_unscoped_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ else // <unscoped-name>
+ first = t1;
+ }
+ else
+ { // try <substitution> <template-args>
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+// # non-virtual base override
+//
+// <v-offset> ::= <offset number> _ <virtual offset number>
+// # virtual base override, with vcall offset
+
+const char*
+parse_call_offset(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'h':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ first = t + 1;
+ }
+ break;
+ case 'v':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_number(++t, last);
+ if (t2 != t && t2 != last && *t2 == '_')
+ first = t2 + 1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+
+template <class C>
+const char*
+parse_special_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'T':
+ switch (first[1])
+ {
+ case 'V':
+ // TV <type> # virtual table
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "vtable for ");
+ first = t;
+ }
+ break;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "VTT for ");
+ first = t;
+ }
+ break;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo for ");
+ first = t;
+ }
+ break;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo name for ");
+ first = t;
+ }
+ break;
+ case 'c':
+ // Tc <call-offset> <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+2, last);
+ if (t0 == first+2)
+ break;
+ const char* t1 = parse_call_offset(t0, last);
+ if (t1 == t0)
+ break;
+ t = parse_encoding(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "covariant return thunk to ");
+ first = t;
+ }
+ }
+ break;
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t0 = parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = parse_type(++t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto left = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "construction vtable for " +
+ std::move(left) + "-in-" +
+ db.names.back().move_full();
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ // T <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+1, last);
+ if (t0 == first+1)
+ break;
+ t = parse_encoding(t0, last, db);
+ if (t != t0)
+ {
+ if (db.names.empty())
+ return first;
+ if (first[1] == 'v')
+ {
+ db.names.back().first.insert(0, "virtual thunk to ");
+ first = t;
+ }
+ else
+ {
+ db.names.back().first.insert(0, "non-virtual thunk to ");
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1])
+ {
+ case 'V':
+ // GV <object name> # Guard variable for one-time initialization
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "guard variable for ");
+ first = t;
+ }
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "reference temporary for ");
+ first = t;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+
+template <class C>
+const char*
+parse_encoding(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
+ switch (*first)
+ {
+ case 'G':
+ case 'T':
+ first = parse_special_name(first, last, db);
+ break;
+ default:
+ {
+ bool ends_with_template_args = false;
+ const char* t = parse_name(first, last, db,
+ &ends_with_template_args);
+ unsigned cv = db.cv;
+ unsigned ref = db.ref;
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
+ {
+ save_value<bool> sb2(db.tag_templates);
+ db.tag_templates = false;
+ const char* t2;
+ typename C::String ret2;
+ if (db.names.empty())
+ return first;
+ const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
+ if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
+ {
+ t2 = parse_type(t, last, db);
+ if (t2 == t)
+ return first;
+ if (db.names.size() < 2)
+ return first;
+ auto ret1 = std::move(db.names.back().first);
+ ret2 = std::move(db.names.back().second);
+ if (ret2.empty())
+ ret1 += ' ';
+ db.names.pop_back();
+ if (db.names.empty())
+ return first;
+
+ db.names.back().first.insert(0, ret1);
+ t = t2;
+ }
+ db.names.back().first += '(';
+ if (t != last && *t == 'v')
+ {
+ ++t;
+ }
+ else
+ {
+ bool first_arg = true;
+ while (true)
+ {
+ size_t k0 = db.names.size();
+ t2 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t2 == t)
+ break;
+ if (k1 > k0)
+ {
+ typename C::String tmp;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (!tmp.empty())
+ tmp += ", ";
+ tmp += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k) {
+ if (db.names.empty())
+ return first;
+ db.names.pop_back();
+ }
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_arg)
+ db.names.back().first += ", ";
+ else
+ first_arg = false;
+ db.names.back().first += tmp;
+ }
+ }
+ t = t2;
+ }
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += ')';
+ if (cv & 1)
+ db.names.back().first.append(" const");
+ if (cv & 2)
+ db.names.back().first.append(" volatile");
+ if (cv & 4)
+ db.names.back().first.append(" restrict");
+ if (ref == 1)
+ db.names.back().first.append(" &");
+ else if (ref == 2)
+ db.names.back().first.append(" &&");
+ db.names.back().first += ret2;
+ first = t;
+ }
+ else
+ first = t;
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+
+template <class C>
+const char*
+parse_block_invoke(const char* first, const char* last, C& db)
+{
+ if (last - first >= 13)
+ {
+ const char test[] = "_block_invoke";
+ const char* t = first;
+ for (int i = 0; i < 13; ++i, ++t)
+ {
+ if (*t != test[i])
+ return first;
+ }
+ if (t != last)
+ {
+ if (*t == '_')
+ {
+ // must have at least 1 decimal digit
+ if (++t == last || !std::isdigit(*t))
+ return first;
+ ++t;
+ }
+ // parse zero or more digits
+ while (t != last && isdigit(*t))
+ ++t;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "invocation function for block in ");
+ first = t;
+ }
+ return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+template <class C>
+const char*
+parse_dot_suffix(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == '.')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " (" + typename C::String(first, last) + ")";
+ first = last;
+ }
+ return first;
+}
+
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
+// <mangled-name> ::= _Z<encoding>
+// ::= <type>
+
+template <class C>
+void
+demangle(const char* first, const char* last, C& db, int& status)
+{
+ if (first >= last)
+ {
+ status = invalid_mangled_name;
+ return;
+ }
+ if (*first == '_')
+ {
+ if (last - first >= 4)
+ {
+ if (first[1] == 'Z')
+ {
+ const char* t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == '.')
+ t = parse_dot_suffix(t, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ {
+ const char* t = parse_encoding(first+4, last, db);
+ if (t != first+4 && t != last)
+ {
+ const char* t1 = parse_block_invoke(t, last, db);
+ if (t1 != last)
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ {
+ const char* t = parse_type(first, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ if (status == success && db.names.empty())
+ status = invalid_mangled_name;
+}
+
+template <std::size_t N>
+class arena
+{
+ static const std::size_t alignment = 16;
+ alignas(alignment) char buf_[N];
+ char* ptr_;
+
+ std::size_t
+ align_up(std::size_t n) noexcept
+ {return (n + (alignment-1)) & ~(alignment-1);}
+
+ bool
+ pointer_in_buffer(char* p) noexcept
+ {return buf_ <= p && p <= buf_ + N;}
+
+public:
+ arena() noexcept : ptr_(buf_) {}
+ ~arena() {ptr_ = nullptr;}
+ arena(const arena&) = delete;
+ arena& operator=(const arena&) = delete;
+
+ char* allocate(std::size_t n);
+ void deallocate(char* p, std::size_t n) noexcept;
+
+ static constexpr std::size_t size() {return N;}
+ std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+ void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
+{
+ n = align_up(n);
+ if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+ {
+ char* r = ptr_;
+ ptr_ += n;
+ return r;
+ }
+ return static_cast<char*>(std::malloc(n));
+}
+
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) noexcept
+{
+ if (pointer_in_buffer(p))
+ {
+ n = align_up(n);
+ if (p + n == ptr_)
+ ptr_ = p;
+ }
+ else
+ std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+ arena<N>& a_;
+public:
+ typedef T value_type;
+
+public:
+ template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+ short_alloc(arena<N>& a) noexcept : a_(a) {}
+ template <class U>
+ short_alloc(const short_alloc<U, N>& a) noexcept
+ : a_(a.a_) {}
+ short_alloc(const short_alloc&) = default;
+ short_alloc& operator=(const short_alloc&) = delete;
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t n) noexcept
+ {
+ a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
+ }
+
+ template <class T1, std::size_t N1, class U, std::size_t M>
+ friend
+ bool
+ operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
+
+ template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ malloc_alloc() = default;
+ template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t) noexcept
+ {
+ std::free(p);
+ }
+
+ template <class U> struct rebind { using other = malloc_alloc<U>; };
+ template <class U, class... Args>
+ void construct(U* p, Args&&... args)
+ {
+ ::new ((void*)p) U(std::forward<Args>(args)...);
+ }
+ void destroy(T* p)
+ {
+ p->~T();
+ }
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
+{
+ return true;
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
+{
+ return !(x == y);
+}
+
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+
+template <class StrT>
+struct string_pair
+{
+ StrT first;
+ StrT second;
+
+ string_pair() = default;
+ string_pair(StrT f) : first(std::move(f)) {}
+ string_pair(StrT f, StrT s)
+ : first(std::move(f)), second(std::move(s)) {}
+ template <size_t N>
+ string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+ size_t size() const {return first.size() + second.size();}
+ StrT full() const {return first + second;}
+ StrT move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+ typedef std::basic_string<char, std::char_traits<char>,
+ malloc_alloc<char>> String;
+ typedef Vector<string_pair<String>> sub_type;
+ typedef Vector<sub_type> template_param_type;
+ sub_type names;
+ template_param_type subs;
+ Vector<template_param_type> template_param;
+ unsigned cv;
+ unsigned ref;
+ unsigned encoding_depth;
+ bool parsed_ctor_dtor_cv;
+ bool tag_templates;
+ bool fix_forward_references;
+ bool try_to_parse_template_args;
+
+ template <size_t N>
+ Db(arena<N>& ar) :
+ names(ar),
+ subs(0, names, ar),
+ template_param(0, subs, ar)
+ {}
+};
+
+} // unnamed namespace
+
+extern "C" _LIBCXXABI_FUNC_VIS char *
+__cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) {
+ if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
+ {
+ if (status)
+ *status = invalid_args;
+ return nullptr;
+ }
+ size_t internal_size = buf != nullptr ? *n : 0;
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ size_t len = std::strlen(mangled_name);
+ demangle(mangled_name, mangled_name + len, db,
+ internal_status);
+ if (internal_status == success && db.fix_forward_references &&
+ !db.template_param.empty() && !db.template_param.front().empty())
+ {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(mangled_name, mangled_name + len, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+ if (internal_status == success)
+ {
+ size_t sz = db.names.back().size() + 1;
+ if (sz > internal_size)
+ {
+ char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+ if (newbuf == nullptr)
+ {
+ internal_status = memory_alloc_failure;
+ buf = nullptr;
+ }
+ else
+ {
+ buf = newbuf;
+ if (n != nullptr)
+ *n = sz;
+ }
+ }
+ if (buf != nullptr)
+ {
+ db.names.back().first += db.names.back().second;
+ std::memcpy(buf, db.names.back().first.data(), sz-1);
+ buf[sz-1] = char(0);
+ }
+ }
+ else
+ buf = nullptr;
+ if (status)
+ *status = internal_status;
+ return buf;
+}
+
+} // __cxxabiv1
diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp
new file mode 100644
index 00000000000..50d1a468cea
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_exception.cpp
@@ -0,0 +1,718 @@
+//===------------------------- 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 "config.h"
+#include "cxxabi.h"
+
+#include <exception> // for std::terminate
+#include <cstdlib> // for malloc, free
+#include <cstring> // for memset
+#if !LIBCXXABI_HAS_NO_THREADS
+# include <pthread.h> // for fallback_malloc.ipp's mutexes
+#endif
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+
+// +---------------------------+-----------------------------+---------------+
+// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
+// +---------------------------+-----------------------------+---------------+
+// ^
+// |
+// +-------------------------------------------------------+
+// |
+// +---------------------------+-----------------------------+
+// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
+// +---------------------------+-----------------------------+
+
+namespace __cxxabiv1 {
+
+#pragma GCC visibility push(default)
+
+// Utility routines
+static
+inline
+__cxa_exception*
+cxa_exception_from_thrown_object(void* thrown_object)
+{
+ return static_cast<__cxa_exception*>(thrown_object) - 1;
+}
+
+// Note: This is never called when exception_header is masquerading as a
+// __cxa_dependent_exception.
+static
+inline
+void*
+thrown_object_from_cxa_exception(__cxa_exception* exception_header)
+{
+ return static_cast<void*>(exception_header + 1);
+}
+
+// Get the exception object from the unwind pointer.
+// Relies on the structure layout, where the unwind pointer is right in
+// front of the user's exception object
+static
+inline
+__cxa_exception*
+cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
+{
+ return cxa_exception_from_thrown_object(unwind_exception + 1 );
+}
+
+static
+inline
+size_t
+cxa_exception_size_from_exception_thrown_size(size_t size)
+{
+ return size + sizeof (__cxa_exception);
+}
+
+static void setExceptionClass(_Unwind_Exception* unwind_exception) {
+ unwind_exception->exception_class = kOurExceptionClass;
+}
+
+static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
+ unwind_exception->exception_class = kOurDependentExceptionClass;
+}
+
+// Is it one of ours?
+static bool isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
+ return (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+}
+
+static bool isDependentException(_Unwind_Exception* unwind_exception) {
+ return (unwind_exception->exception_class & 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;
+}
+
+#include "fallback_malloc.ipp"
+
+// Allocate some memory from _somewhere_
+static void *do_malloc(size_t size) {
+ void *ptr = std::malloc(size);
+ if (NULL == ptr) // if malloc fails, fall back to emergency stash
+ ptr = fallback_malloc(size);
+ return ptr;
+}
+
+static void do_free(void *ptr) {
+ is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
+}
+
+/*
+ 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);
+}
+
+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.
+_LIBCXXABI_FUNC_VIS void *__cxa_allocate_exception(size_t thrown_size) throw() {
+ size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
+ __cxa_exception* exception_header = static_cast<__cxa_exception*>(do_malloc(actual_size));
+ if (NULL == exception_header)
+ std::terminate();
+ 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.
+_LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_object) throw() {
+ do_free(cxa_exception_from_thrown_object(thrown_object));
+}
+
+
+// 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 = do_malloc(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) {
+ do_free(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.
+*/
+_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN 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;
+ setExceptionClass(&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;
+#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
+*/
+_LIBCXXABI_FUNC_VIS
+void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
+#if LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(
+ static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
+#else
+ return cxa_exception_from_exception_unwind_exception(
+ static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
+#endif
+}
+
+#if 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.
+*/
+_LIBCXXABI_FUNC_VIS
+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 // 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 LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
+#else
+ return exception_header->adjustedPtr;
+#endif
+ }
+ // Else this is a foreign exception
+ // If the caughtExceptions stack is not empty, terminate
+ if (globals->caughtExceptions != 0)
+ std::terminate();
+ // Push the foreign exception on to the stack
+ globals->caughtExceptions = exception_header;
+ return unwind_exception + 1;
+}
+
+
+/*
+Upon exit for any reason, a handler must call:
+ void __cxa_end_catch ();
+
+This routine can be called for either a native or foreign exception.
+For a native exception:
+* Locates the most recently caught exception and decrements its handler count.
+* Removes the exception from the caught exception stack, if the handler count goes to zero.
+* If the handler count goes down to zero, and the exception was not re-thrown
+ by throw, it locates the primary exception (which may be the same as the one
+ it's handling) and decrements its reference count. If that reference count
+ goes to zero, the function destroys the exception. In any case, if the current
+ exception is a dependent exception, it destroys that.
+
+For a foreign exception:
+* If it has been rethrown, there is nothing to do.
+* Otherwise delete the exception and pop the catch stack to empty.
+*/
+_LIBCXXABI_FUNC_VIS 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.
+_LIBCXXABI_FUNC_VIS 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.
+*/
+_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN 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.
+*/
+_LIBCXXABI_FUNC_VIS void
+__cxa_increment_exception_refcount(void *thrown_object) throw() {
+ if (thrown_object != NULL )
+ {
+ __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
+ __sync_add_and_fetch(&exception_header->referenceCount, 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_FUNC_VIS 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 (__sync_sub_and_fetch(&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.
+*/
+_LIBCXXABI_FUNC_VIS 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"
+
+#pragma GCC visibility pop
+
+} // abi
diff --git a/lib/libcxxabi/src/cxa_exception.hpp b/lib/libcxxabi/src/cxa_exception.hpp
new file mode 100644
index 00000000000..6e68f985389
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_exception.hpp
@@ -0,0 +1,125 @@
+//===------------------------- 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 <exception> // for std::unexpected_handler and std::terminate_handler
+#include <cxxabi.h>
+#include "unwind.h"
+
+namespace __cxxabiv1 {
+
+#pragma GCC visibility push(hidden)
+
+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++
+
+struct __cxa_exception {
+#if defined(__LP64__) || 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 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__) && !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 __cxa_dependent_exception {
+#if defined(__LP64__) || 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 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__) && !LIBCXXABI_ARM_EHABI
+ void* primaryException;
+#endif
+
+ _Unwind_Exception unwindHeader;
+};
+
+struct __cxa_eh_globals {
+ __cxa_exception * caughtExceptions;
+ unsigned int uncaughtExceptions;
+#if LIBCXXABI_ARM_EHABI
+ __cxa_exception* propagatingExceptions;
+#endif
+};
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(default)
+
+extern "C" __cxa_eh_globals * __cxa_get_globals ();
+extern "C" __cxa_eh_globals * __cxa_get_globals_fast ();
+
+extern "C" void * __cxa_allocate_dependent_exception ();
+extern "C" void __cxa_free_dependent_exception (void * dependent_exception);
+
+#pragma GCC visibility pop
+
+} // namespace __cxxabiv1
+
+#endif // _CXA_EXCEPTION_H
diff --git a/lib/libcxxabi/src/cxa_exception_storage.cpp b/lib/libcxxabi/src/cxa_exception_storage.cpp
new file mode 100644
index 00000000000..a39b6db005f
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_exception_storage.cpp
@@ -0,0 +1,103 @@
+//===--------------------- 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 "config.h"
+
+#if 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 <pthread.h>
+#include <cstdlib> // for calloc, free
+#include "abort_message.h"
+
+// In general, we treat all pthread errors as fatal.
+// We cannot call std::terminate() because that will in turn
+// call __cxa_get_globals() and cause infinite recursion.
+
+namespace __cxxabiv1 {
+namespace {
+ pthread_key_t key_;
+ pthread_once_t flag_ = PTHREAD_ONCE_INIT;
+
+ void destruct_ (void *p) {
+ std::free ( p );
+ if ( 0 != ::pthread_setspecific ( key_, NULL ) )
+ abort_message("cannot zero out thread value for __cxa_get_globals()");
+ }
+
+ void construct_ () {
+ if ( 0 != pthread_key_create ( &key_, destruct_ ) )
+ abort_message("cannot create pthread 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*>
+ (std::calloc (1, sizeof (__cxa_eh_globals)));
+ if ( NULL == retVal )
+ abort_message("cannot allocate __cxa_eh_globals");
+ if ( 0 != pthread_setspecific ( key_, retVal ) )
+ abort_message("pthread_setspecific 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 != pthread_once(&flag_, construct_))
+ abort_message("pthread_once failure in __cxa_get_globals_fast()");
+// static int init = construct_();
+ return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_));
+ }
+
+}
+}
+#endif
diff --git a/lib/libcxxabi/src/cxa_guard.cpp b/lib/libcxxabi/src/cxa_guard.cpp
new file mode 100644
index 00000000000..72e868f787e
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_guard.cpp
@@ -0,0 +1,253 @@
+//===---------------------------- 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 "config.h"
+
+#if !LIBCXXABI_HAS_NO_THREADS
+# include <pthread.h>
+#endif
+#include <stdint.h>
+
+/*
+ This implementation must be careful to not call code external to this file
+ which will turn around and try to call __cxa_guard_acquire reentrantly.
+ For this reason, the headers of this file are as restricted as possible.
+ Previous implementations of this code for __APPLE__ have used
+ pthread_mutex_lock and the abort_message utility without problem. This
+ implementation also uses pthread_cond_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;
+
+// Test the lowest bit.
+inline bool is_initialized(guard_type* guard_object) {
+ return (*guard_object) & 1;
+}
+
+inline void set_initialized(guard_type* guard_object) {
+ *guard_object |= 1;
+}
+
+#else
+
+typedef uint64_t guard_type;
+
+bool is_initialized(guard_type* guard_object) {
+ char* initialized = (char*)guard_object;
+ return *initialized;
+}
+
+void set_initialized(guard_type* guard_object) {
+ char* initialized = (char*)guard_object;
+ *initialized = 1;
+}
+
+#endif
+
+#if !LIBCXXABI_HAS_NO_THREADS
+pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t guard_cv = PTHREAD_COND_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<lock_type>(x >> 32);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = static_cast<uint64_t>(y) << 32;
+}
+
+#else // __LITTLE_ENDIAN__
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ return static_cast<lock_type>(x);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = y;
+}
+
+#endif // __LITTLE_ENDIAN__
+
+#else // !__APPLE__ || __arm__
+
+typedef bool lock_type;
+
+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;
+}
+
+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 // __APPLE__
+
+} // unnamed namespace
+
+extern "C"
+{
+
+#if 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;
+}
+
+#else // !LIBCXXABI_HAS_NO_THREADS
+
+_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
+ char* initialized = (char*)guard_object;
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_acquire failed to acquire mutex");
+ int result = *initialized == 0;
+ if (result)
+ {
+#if defined(__APPLE__) && !defined(__arm__)
+ const lock_type id = pthread_mach_thread_np(pthread_self());
+ 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 (pthread_cond_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 (pthread_cond_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 (pthread_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 (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_release failed to acquire mutex");
+ *guard_object = 0;
+ set_initialized(guard_object);
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_release failed to release mutex");
+ if (pthread_cond_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 (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to acquire mutex");
+ *guard_object = 0;
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to release mutex");
+ if (pthread_cond_broadcast(&guard_cv))
+ abort_message("__cxa_guard_abort failed to broadcast condition variable");
+}
+
+#endif // !LIBCXXABI_HAS_NO_THREADS
+
+} // extern "C"
+
+} // __cxxabiv1
diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp
new file mode 100644
index 00000000000..3f781313df8
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_handlers.cpp
@@ -0,0 +1,126 @@
+//===------------------------- 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 <stdexcept>
+#include <new>
+#include <exception>
+#include "abort_message.h"
+#include "config.h"
+#include "cxxabi.h"
+#include "cxa_handlers.hpp"
+#include "cxa_exception.hpp"
+#include "private_typeinfo.h"
+
+namespace std
+{
+
+unexpected_handler
+get_unexpected() _NOEXCEPT
+{
+ return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0);
+// The above is safe but overkill on x86
+// Using of C++11 atomics this should be rewritten
+// return __cxa_unexpected_handler.load(memory_order_acq);
+}
+
+__attribute__((visibility("hidden"), noreturn))
+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 __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0);
+// The above is safe but overkill on x86
+// Using of C++11 atomics this should be rewritten
+// return __cxa_terminate_handler.load(memory_order_acq);
+}
+
+__attribute__((visibility("hidden"), noreturn))
+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;
+ bool native_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ if (native_exception)
+ __terminate(exception_header->terminateHandler);
+ }
+ }
+ __terminate(get_terminate());
+}
+
+// In the future this will become:
+// std::atomic<std::new_handler> __cxa_new_handler(0);
+extern "C" _LIBCXXABI_DATA_VIS new_handler __cxa_new_handler = 0;
+
+new_handler
+set_new_handler(new_handler handler) _NOEXCEPT
+{
+ return __atomic_exchange_n(&__cxa_new_handler, handler, __ATOMIC_ACQ_REL);
+// Using of C++11 atomics this should be rewritten
+// return __cxa_new_handler.exchange(handler, memory_order_acq_rel);
+}
+
+new_handler
+get_new_handler() _NOEXCEPT
+{
+ return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0);
+// The above is safe but overkill on x86
+// Using of C++11 atomics this should be rewritten
+// return __cxa_new_handler.load(memory_order_acq);
+}
+
+} // std
diff --git a/lib/libcxxabi/src/cxa_handlers.hpp b/lib/libcxxabi/src/cxa_handlers.hpp
new file mode 100644
index 00000000000..ce567ec1471
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_handlers.hpp
@@ -0,0 +1,54 @@
+//===------------------------- 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 <exception>
+
+namespace std
+{
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__unexpected(unexpected_handler func);
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__terminate(terminate_handler func) _NOEXCEPT;
+
+} // std
+
+extern "C"
+{
+
+extern void (*__cxa_terminate_handler)();
+extern void (*__cxa_unexpected_handler)();
+extern void (*__cxa_new_handler)();
+
+/*
+
+ At some point in the future these three symbols will become
+ C++11 atomic variables:
+
+ extern std::atomic<std::terminate_handler> __cxa_terminate_handler;
+ extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler;
+ extern std::atomic<std::new_handler> __cxa_new_handler;
+
+ This change will not impact their ABI. But it will allow for a
+ portable performance optimization.
+
+*/
+
+} // extern "C"
+
+#endif // _CXA_HANDLERS_H
diff --git a/lib/libcxxabi/src/cxa_new_delete.cpp b/lib/libcxxabi/src/cxa_new_delete.cpp
new file mode 100644
index 00000000000..7a2c864c311
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_new_delete.cpp
@@ -0,0 +1,274 @@
+//===------------------------ cxa_new_delete.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 new and delete operators.
+//===----------------------------------------------------------------------===//
+
+#define _LIBCPP_BUILDING_NEW
+
+#include <new>
+#include <cstdlib>
+
+/*
+[new.delete.single]
+
+* Executes a loop: Within the loop, the function first attempts to allocate
+ the requested storage. Whether the attempt involves a call to the Standard C
+ library function malloc is unspecified.
+
+* Returns a pointer to the allocated storage if the attempt is successful.
+ Otherwise, if the current new_handler (18.6.2.5) is a null pointer value,
+ throws bad_alloc.
+
+* Otherwise, the function calls the current new_handler function (18.6.2.3).
+ If the called function returns, the loop repeats.
+
+* The loop terminates when an attempt to allocate the requested storage is
+ successful or when a called new_handler function does not return.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void *
+operator new(std::size_t size)
+#if !__has_feature(cxx_noexcept)
+ throw(std::bad_alloc)
+#endif
+{
+ if (size == 0)
+ size = 1;
+ void* p;
+ while ((p = std::malloc(size)) == 0)
+ {
+ std::new_handler nh = std::get_new_handler();
+ if (nh)
+ nh();
+ else
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ throw std::bad_alloc();
+#else
+ break;
+#endif
+ }
+ return p;
+}
+
+/*
+Note: The relationships among these operators is both carefully considered
+and standard in C++11. Please do not change them without fully understanding
+the consequences of doing so. Reference:
+http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2158.html
+*/
+/*
+[new.delete.single]
+
+Calls operator new(size). If the call returns normally, returns the result of
+that call. Otherwise, returns a null pointer.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new(size_t size, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ void* p = 0;
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ try
+ {
+#endif
+ p = ::operator new(size);
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ }
+ catch (...)
+ {
+ }
+#endif
+ return p;
+}
+
+/*
+[new.delete.array]
+
+Returns operator new(size).
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new[](size_t size)
+#if !__has_feature(cxx_noexcept)
+ throw(std::bad_alloc)
+#endif
+{
+ return ::operator new(size);
+}
+
+/*
+[new.delete.array]
+
+Calls operator new[](size). If the call returns normally, returns the result
+of that call. Otherwise, returns a null pointer.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new[](size_t size, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ void* p = 0;
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ try
+ {
+#endif
+ p = ::operator new[](size);
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+ }
+ catch (...)
+ {
+ }
+#endif
+ return p;
+}
+
+/*
+[new.delete.single]
+
+If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the
+earlier call to operator new.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete(void* ptr)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ if (ptr)
+ std::free(ptr);
+}
+
+/*
+[new.delete.single]
+
+calls operator delete(ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete(void* ptr, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete(ptr);
+}
+
+/*
+[new.delete.array]
+
+Calls operator delete(ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete[] (void* ptr)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete(ptr);
+}
+
+/*
+[new.delete.array]
+
+calls operator delete[](ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete[] (void* ptr, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete[](ptr);
+}
+
+namespace std
+{
+
+// bad_alloc
+
+bad_alloc::bad_alloc() _NOEXCEPT
+{
+}
+
+bad_alloc::~bad_alloc() _NOEXCEPT
+{
+}
+
+const char*
+bad_alloc::what() const _NOEXCEPT
+{
+ return "std::bad_alloc";
+}
+
+// bad_array_new_length
+
+bad_array_new_length::bad_array_new_length() _NOEXCEPT
+{
+}
+
+bad_array_new_length::~bad_array_new_length() _NOEXCEPT
+{
+}
+
+const char*
+bad_array_new_length::what() const _NOEXCEPT
+{
+ return "bad_array_new_length";
+}
+
+// bad_array_length
+
+#ifndef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+class _LIBCPP_EXCEPTION_ABI bad_array_length
+ : public bad_alloc
+{
+public:
+ bad_array_length() _NOEXCEPT;
+ virtual ~bad_array_length() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
+};
+
+#endif // _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+bad_array_length::bad_array_length() _NOEXCEPT
+{
+}
+
+bad_array_length::~bad_array_length() _NOEXCEPT
+{
+}
+
+const char*
+bad_array_length::what() const _NOEXCEPT
+{
+ return "bad_array_length";
+}
+
+} // std
diff --git a/lib/libcxxabi/src/cxa_noexception.cpp b/lib/libcxxabi/src/cxa_noexception.cpp
new file mode 100644
index 00000000000..e45ceff0165
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_noexception.cpp
@@ -0,0 +1,60 @@
+//===------------------------- 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 "config.h"
+#include "cxxabi.h"
+
+#include <exception> // for std::terminate
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+
+namespace __cxxabiv1 {
+
+#pragma GCC visibility push(default)
+
+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"
+
+#pragma GCC visibility pop
+
+} // abi
diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp
new file mode 100644
index 00000000000..85b6df2393a
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_personality.cpp
@@ -0,0 +1,1300 @@
+//===------------------------- 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <typeinfo>
+
+#include "__cxxabi_config.h"
+#include "config.h"
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+#include "private_typeinfo.h"
+#include "unwind.h"
+
+/*
+ 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 <class AsType>
+uintptr_t readPointerHelper(const uint8_t*& p) {
+ AsType value;
+ memcpy(&value, p, sizeof(AsType));
+ p += sizeof(AsType);
+ return static_cast<uintptr_t>(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<uintptr_t>(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<uintptr_t>(byte & 0x7F) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
+ result |= static_cast<uintptr_t>(~0) << shift;
+ return static_cast<intptr_t>(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<uintptr_t>(p);
+ break;
+ case DW_EH_PE_uleb128:
+ result = readULEB128(&p);
+ break;
+ case DW_EH_PE_sleb128:
+ result = static_cast<uintptr_t>(readSLEB128(&p));
+ break;
+ case DW_EH_PE_udata2:
+ result = readPointerHelper<uint16_t>(p);
+ break;
+ case DW_EH_PE_udata4:
+ result = readPointerHelper<uint32_t>(p);
+ break;
+ case DW_EH_PE_udata8:
+ result = readPointerHelper<uint64_t>(p);
+ break;
+ case DW_EH_PE_sdata2:
+ result = readPointerHelper<int16_t>(p);
+ break;
+ case DW_EH_PE_sdata4:
+ result = readPointerHelper<int32_t>(p);
+ break;
+ case DW_EH_PE_sdata8:
+ result = readPointerHelper<int64_t>(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 LIBCXXABI_ARM_EHABI
+static const void* read_target2_value(const void* ptr)
+{
+ uintptr_t offset = *reinterpret_cast<const uintptr_t*>(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 LIBCXXABI_BAREMETAL
+ return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(ptr) +
+ offset);
+#else
+ return *reinterpret_cast<const void **>(reinterpret_cast<uintptr_t>(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 && "Unexpected TTypeEncoding");
+ (void)ttypeEncoding;
+
+ const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t);
+ return reinterpret_cast<const __shim_type_info *>(
+ read_target2_value(ttypePtr));
+}
+#else // !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 // !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 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 && "Unexpected TTypeEncoding");
+ (void)ttypeEncoding;
+
+ // specIndex is negative of 1-based byte offset into classInfo;
+ specIndex = -specIndex;
+ --specIndex;
+ const void** temp = reinterpret_cast<const void**>(
+ reinterpret_cast<uintptr_t>(classInfo) +
+ static_cast<uintptr_t>(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<const __shim_type_info*>(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 (unwind_exception->exception_class == 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<uintptr_t>(unwind_exception));
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
+ static_cast<uintptr_t>(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<uint32_t>(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<uint64_t>(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<const __shim_type_info*>(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<const __shim_type_info*>(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 !LIBCXXABI_ARM_EHABI
+_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
+#ifdef __USING_SJLJ_EXCEPTIONS__
+__gxx_personality_sj0
+#else
+__gxx_personality_v0
+#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<int>(results.ttypeIndex);
+ exception_header->actionRecord = results.actionRecord;
+ exception_header->languageSpecificData = results.languageSpecificData;
+ exception_header->catchTemp = reinterpret_cast<void*>(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<uintptr_t>(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;
+}
+#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 !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 = (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+
+#if !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<uint32_t>(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 =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ 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 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 =
+ (new_exception_header->unwindHeader.exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ void* adjustedPtr;
+ if (native_new_exception && (new_exception_header != old_exception_header))
+ {
+ const __shim_type_info* excpType =
+ static_cast<const __shim_type_info*>(new_exception_header->exceptionType);
+ adjustedPtr =
+ new_exception_header->unwindHeader.exception_class == 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<const __shim_type_info*>(&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
new file mode 100644
index 00000000000..7962e28af70
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_thread_atexit.cpp
@@ -0,0 +1,26 @@
+//===----------------------- 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 "cxxabi.h"
+
+namespace __cxxabiv1 {
+extern "C" {
+
+#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
+
+_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*dtor)(void *), void *obj,
+ void *dso_symbol) throw() {
+ extern int __cxa_thread_atexit_impl(void (*)(void *), void *, void *);
+ return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
+}
+
+#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
new file mode 100644
index 00000000000..f6e6b6ab97e
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_unexpected.cpp
@@ -0,0 +1,27 @@
+//===------------------------- 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 <exception>
+#include <cxxabi.h>
+#include "cxa_exception.hpp"
+
+namespace __cxxabiv1
+{
+
+#pragma GCC visibility push(default)
+
+extern "C"
+{
+
+}
+
+#pragma GCC visibility pop
+
+} // namespace __cxxabiv1
+
diff --git a/lib/libcxxabi/src/cxa_vector.cpp b/lib/libcxxabi/src/cxa_vector.cpp
new file mode 100644
index 00000000000..c32a2119756
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_vector.cpp
@@ -0,0 +1,367 @@
+//===-------------------------- 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 <exception> // 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 <size_t *> (p)[-1];
+ }
+
+ inline static void __set_element_count ( void *p, size_t element_count ) {
+ static_cast <size_t *> (p)[-1] = element_count;
+ }
+
+
+// A pair of classes to simplify exception handling and control flow.
+// They get passed a block of memory in the constructor, and unless the
+// 'release' method is called, they deallocate the memory in the destructor.
+// Preferred usage is to allocate some memory, attach it to one of these objects,
+// and then, when all the operations to set up the memory block have succeeded,
+// call 'release'. If any of the setup operations fail, or an exception is
+// thrown, then the block is automatically deallocated.
+//
+// The only difference between these two classes is the signature for the
+// deallocation function (to match new2/new3 and delete2/delete3.
+ class st_heap_block2 {
+ public:
+ typedef void (*dealloc_f)(void *);
+
+ st_heap_block2 ( dealloc_f dealloc, void *ptr )
+ : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
+ ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
+ void release () { enabled_ = false; }
+
+ private:
+ dealloc_f dealloc_;
+ void *ptr_;
+ bool enabled_;
+ };
+
+ class st_heap_block3 {
+ public:
+ typedef void (*dealloc_f)(void *, size_t);
+
+ st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
+ : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
+ ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
+ void release () { enabled_ = false; }
+
+ private:
+ dealloc_f dealloc_;
+ void *ptr_;
+ size_t size_;
+ bool enabled_;
+ };
+
+ class st_cxa_cleanup {
+ public:
+ typedef void (*destruct_f)(void *);
+
+ st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
+ : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
+ destructor_ ( destructor ), enabled_ ( true ) {}
+ ~st_cxa_cleanup () {
+ if ( enabled_ )
+ __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
+ }
+
+ void release () { enabled_ = false; }
+
+ private:
+ void *ptr_;
+ size_t &idx_;
+ size_t element_size_;
+ destruct_f destructor_;
+ bool enabled_;
+ };
+
+ class st_terminate {
+ public:
+ st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
+ ~st_terminate () { if ( enabled_ ) std::terminate (); }
+ void release () { enabled_ = false; }
+ private:
+ bool enabled_ ;
+ };
+}
+
+#if 0
+#pragma mark --Externally visible routines--
+#endif
+
+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<char *> ( alloc ( heap_size ));
+ char *vec_base = heap_block;
+
+ if ( NULL != vec_base ) {
+ st_heap_block2 heap ( dealloc, heap_block );
+
+ // put the padding before the array elements
+ if ( 0 != padding_size ) {
+ vec_base += padding_size;
+ __set_element_count ( vec_base, element_count );
+ }
+
+ // Construct the elements
+ __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
+ heap.release (); // We're good!
+ }
+
+ return vec_base;
+}
+
+
+// Same as __cxa_vec_new2 except that the deallocation function takes both
+// the object address and its size.
+_LIBCXXABI_FUNC_VIS void *
+__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void *), void (*destructor)(void *),
+ void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
+ const size_t heap_size = element_count * element_size + padding_size;
+ char * const heap_block = static_cast<char *> ( alloc ( heap_size ));
+ char *vec_base = heap_block;
+
+ if ( NULL != vec_base ) {
+ st_heap_block3 heap ( dealloc, heap_block, heap_size );
+
+ // put the padding before the array elements
+ if ( 0 != padding_size ) {
+ vec_base += padding_size;
+ __set_element_count ( vec_base, element_count );
+ }
+
+ // Construct the elements
+ __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
+ heap.release (); // We're good!
+ }
+
+ return vec_base;
+}
+
+
+// Given the (data) addresses of a destination and a source array, an
+// element count and an element size, call the given copy constructor to
+// copy each element from the source array to the destination array. The
+// copy constructor's arguments are the destination address and source
+// address, respectively. If an exception occurs, call the given destructor
+// (if non-NULL) on each copied element and rethrow. If the destructor
+// throws an exception, call terminate(). The constructor and or destructor
+// pointers may be NULL. If either is NULL, no action is taken when it
+// would have been called.
+
+_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
+ size_t element_count,
+ size_t element_size,
+ void (*constructor)(void *, void *),
+ void (*destructor)(void *)) {
+ if ( NULL != constructor ) {
+ size_t idx = 0;
+ char *src_ptr = static_cast<char *>(src_array);
+ char *dest_ptr = static_cast<char *>(dest_array);
+ st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
+
+ for ( idx = 0; idx < element_count;
+ ++idx, src_ptr += element_size, dest_ptr += element_size )
+ constructor ( dest_ptr, src_ptr );
+ cleanup.release (); // We're good!
+ }
+}
+
+
+// Given the (data) address of an array, not including any cookie padding,
+// and the number and size of its elements, call the given constructor on
+// each element. If the constructor throws an exception, call the given
+// destructor for any already-constructed elements, and rethrow the
+// exception. If the destructor throws an exception, call terminate(). The
+// constructor and/or destructor pointers may be NULL. If either is NULL,
+// no action is taken when it would have been called.
+_LIBCXXABI_FUNC_VIS void
+__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
+ void (*constructor)(void *), void (*destructor)(void *)) {
+ if ( NULL != constructor ) {
+ size_t idx;
+ char *ptr = static_cast <char *> ( array_address );
+ st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
+
+ // Construct the elements
+ for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
+ constructor ( ptr );
+ cleanup.release (); // We're good!
+ }
+}
+
+// Given the (data) address of an array, the number of elements, and the
+// size of its elements, call the given destructor on each element. If the
+// destructor throws an exception, rethrow after destroying the remaining
+// elements if possible. If the destructor throws a second exception, call
+// terminate(). The destructor pointer may be NULL, in which case this
+// routine does nothing.
+_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void *)) {
+ if ( NULL != destructor ) {
+ char *ptr = static_cast <char *> (array_address);
+ size_t idx = element_count;
+ st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
+ {
+ st_terminate exception_guard (__cxa_uncaught_exception ());
+ ptr += element_count * element_size; // one past the last element
+
+ while ( idx-- > 0 ) {
+ ptr -= element_size;
+ destructor ( ptr );
+ }
+ exception_guard.release (); // We're good !
+ }
+ cleanup.release (); // We're still good!
+ }
+}
+
+// Given the (data) address of an array, the number of elements, and the
+// size of its elements, call the given destructor on each element. If the
+// destructor throws an exception, call terminate(). The destructor pointer
+// may be NULL, in which case this routine does nothing.
+_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void *)) {
+ if ( NULL != destructor ) {
+ char *ptr = static_cast <char *> (array_address);
+ size_t idx = element_count;
+ st_terminate exception_guard;
+
+ ptr += element_count * element_size; // one past the last element
+ while ( idx-- > 0 ) {
+ ptr -= element_size;
+ destructor ( ptr );
+ }
+ exception_guard.release (); // We're done!
+ }
+}
+
+
+// If the array_address is NULL, return immediately. Otherwise, given the
+// (data) address of an array, the non-negative size of prefix padding for
+// the cookie, and the size of its elements, call the given destructor on
+// each element, using the cookie to determine the number of elements, and
+// then delete the space by calling ::operator delete[](void *). If the
+// destructor throws an exception, rethrow after (a) destroying the
+// remaining elements, and (b) deallocating the storage. If the destructor
+// throws a second exception, call terminate(). If padding_size is 0, the
+// destructor pointer must be NULL. If the destructor pointer is NULL, no
+// destructor call is to be made.
+//
+// The intent of this function is to permit an implementation to call this
+// function when confronted with an expression of the form delete[] p in
+// the source code, provided that the default deallocation function can be
+// used. Therefore, the semantics of this function are consistent with
+// those required by the standard. The requirement that the deallocation
+// function be called even if the destructor throws an exception derives
+// from the resolution to DR 353 to the C++ standard, which was adopted in
+// April, 2003.
+_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
+ size_t element_size,
+ size_t padding_size,
+ void (*destructor)(void *)) {
+ __cxa_vec_delete2 ( array_address, element_size, padding_size,
+ destructor, &::operator delete [] );
+}
+
+// Same as __cxa_vec_delete, except that the given function is used for
+// deallocation instead of the default delete function. If dealloc throws
+// an exception, the result is undefined. The dealloc pointer may not be
+// NULL.
+_LIBCXXABI_FUNC_VIS void
+__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
+ void (*destructor)(void *), void (*dealloc)(void *)) {
+ if ( NULL != array_address ) {
+ char *vec_base = static_cast <char *> (array_address);
+ char *heap_block = vec_base - padding_size;
+ st_heap_block2 heap ( dealloc, heap_block );
+
+ if ( 0 != padding_size && NULL != destructor ) // call the destructors
+ __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
+ element_size, destructor );
+ }
+}
+
+
+// Same as __cxa_vec_delete, except that the given function is used for
+// deallocation instead of the default delete function. The deallocation
+// function takes both the object address and its size. If dealloc throws
+// an exception, the result is undefined. The dealloc pointer may not be
+// NULL.
+_LIBCXXABI_FUNC_VIS void
+__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
+ void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
+ if ( NULL != array_address ) {
+ char *vec_base = static_cast <char *> (array_address);
+ char *heap_block = vec_base - padding_size;
+ const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
+ const size_t heap_block_size = element_size * element_count + padding_size;
+ st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
+
+ if ( 0 != padding_size && NULL != destructor ) // call the destructors
+ __cxa_vec_dtor ( array_address, element_count, element_size, destructor );
+ }
+}
+
+
+} // extern "C"
+
+} // abi
diff --git a/lib/libcxxabi/src/cxa_virtual.cpp b/lib/libcxxabi/src/cxa_virtual.cpp
new file mode 100644
index 00000000000..ac81ad39d07
--- /dev/null
+++ b/lib/libcxxabi/src/cxa_virtual.cpp
@@ -0,0 +1,25 @@
+//===-------------------------- 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/exception.cpp b/lib/libcxxabi/src/exception.cpp
new file mode 100644
index 00000000000..c47a9b76266
--- /dev/null
+++ b/lib/libcxxabi/src/exception.cpp
@@ -0,0 +1,41 @@
+//===---------------------------- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+
+#pragma GCC visibility push(default)
+
+namespace std
+{
+
+// exception
+
+exception::~exception() _NOEXCEPT
+{
+}
+
+const char* exception::what() const _NOEXCEPT
+{
+ return "std::exception";
+}
+
+// bad_exception
+
+bad_exception::~bad_exception() _NOEXCEPT
+{
+}
+
+const char* bad_exception::what() const _NOEXCEPT
+{
+ return "std::bad_exception";
+}
+
+} // std
+
+#pragma GCC visibility pop
diff --git a/lib/libcxxabi/src/fallback_malloc.ipp b/lib/libcxxabi/src/fallback_malloc.ipp
new file mode 100644
index 00000000000..71b65bed888
--- /dev/null
+++ b/lib/libcxxabi/src/fallback_malloc.ipp
@@ -0,0 +1,188 @@
+//===------------------------ fallback_malloc.ipp -------------------------===//
+//
+// 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 "config.h"
+
+// A small, simple heap manager based (loosely) on
+// the startup heap manager from FreeBSD, optimized for space.
+//
+// Manages a fixed-size memory pool, supports malloc and free only.
+// No support for realloc.
+//
+// Allocates chunks in multiples of four bytes, with a four byte header
+// for each chunk. The overhead of each chunk is kept low by keeping pointers
+// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
+
+namespace {
+
+// When POSIX threads are not available, make the mutex operations a nop
+#if LIBCXXABI_HAS_NO_THREADS
+static void * heap_mutex = 0;
+#else
+static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+class mutexor {
+public:
+#if LIBCXXABI_HAS_NO_THREADS
+ mutexor ( void * ) {}
+ ~mutexor () {}
+#else
+ mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); }
+ ~mutexor () { pthread_mutex_unlock ( mtx_ ); }
+#endif
+private:
+ mutexor ( const mutexor &rhs );
+ mutexor & operator = ( const mutexor &rhs );
+#if !LIBCXXABI_HAS_NO_THREADS
+ pthread_mutex_t *mtx_;
+#endif
+ };
+
+
+#define HEAP_SIZE 512
+char heap [ HEAP_SIZE ];
+
+typedef unsigned short heap_offset;
+typedef unsigned short heap_size;
+
+struct heap_node {
+ heap_offset next_node; // offset into heap
+ heap_size len; // size in units of "sizeof(heap_node)"
+};
+
+static const heap_node *list_end = (heap_node *) ( &heap [ HEAP_SIZE ] ); // one past the end of the heap
+static heap_node *freelist = NULL;
+
+heap_node *node_from_offset ( const heap_offset offset )
+ { return (heap_node *) ( heap + ( offset * sizeof (heap_node))); }
+
+heap_offset offset_from_node ( const heap_node *ptr )
+ { return static_cast<heap_offset>(static_cast<size_t>(reinterpret_cast<const char *>(ptr) - heap) / sizeof (heap_node)); }
+
+void init_heap () {
+ freelist = (heap_node *) heap;
+ freelist->next_node = offset_from_node ( list_end );
+ freelist->len = HEAP_SIZE / sizeof (heap_node);
+ }
+
+// How big a chunk we allocate
+size_t alloc_size (size_t len)
+ { return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; }
+
+bool is_fallback_ptr ( void *ptr )
+ { return ptr >= heap && ptr < ( heap + HEAP_SIZE ); }
+
+void *fallback_malloc(size_t len) {
+ heap_node *p, *prev;
+ const size_t nelems = alloc_size ( len );
+ mutexor mtx ( &heap_mutex );
+
+ if ( NULL == freelist )
+ init_heap ();
+
+// Walk the free list, looking for a "big enough" chunk
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset ( p->next_node)) {
+
+ if (p->len > nelems) { // chunk is larger, shorten, and return the tail
+ heap_node *q;
+
+ p->len = static_cast<heap_size>(p->len - nelems);
+ q = p + p->len;
+ q->next_node = 0;
+ q->len = static_cast<heap_size>(nelems);
+ return (void *) (q + 1);
+ }
+
+ if (p->len == nelems) { // exact size match
+ if (prev == 0)
+ freelist = node_from_offset(p->next_node);
+ else
+ prev->next_node = p->next_node;
+ p->next_node = 0;
+ return (void *) (p + 1);
+ }
+ }
+ return NULL; // couldn't find a spot big enough
+}
+
+// Return the start of the next block
+heap_node *after ( struct heap_node *p ) { return p + p->len; }
+
+void fallback_free (void *ptr) {
+ struct heap_node *cp = ((struct heap_node *) ptr) - 1; // retrieve the chunk
+ struct heap_node *p, *prev;
+
+ mutexor mtx ( &heap_mutex );
+
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << "Freeing item at " << offset_from_node ( cp ) << " of size " << cp->len << std::endl;
+#endif
+
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset (p->next_node)) {
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " p, cp, after (p), after(cp) "
+ << offset_from_node ( p ) << ' '
+ << offset_from_node ( cp ) << ' '
+ << offset_from_node ( after ( p )) << ' '
+ << offset_from_node ( after ( cp )) << std::endl;
+#endif
+ if ( after ( p ) == cp ) {
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Appending onto chunk at " << offset_from_node ( p ) << std::endl;
+#endif
+ p->len = static_cast<heap_size>(p->len + cp->len); // make the free heap_node larger
+ return;
+ }
+ else if ( after ( cp ) == p ) { // there's a free heap_node right after
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Appending free chunk at " << offset_from_node ( p ) << std::endl;
+#endif
+ cp->len = static_cast<heap_size>(cp->len + p->len);
+ if ( prev == 0 ) {
+ freelist = cp;
+ cp->next_node = p->next_node;
+ }
+ else
+ prev->next_node = offset_from_node(cp);
+ return;
+ }
+ }
+// Nothing to merge with, add it to the start of the free list
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Making new free list entry " << offset_from_node ( cp ) << std::endl;
+#endif
+ cp->next_node = offset_from_node ( freelist );
+ freelist = cp;
+}
+
+#ifdef INSTRUMENT_FALLBACK_MALLOC
+size_t print_free_list () {
+ struct heap_node *p, *prev;
+ heap_size total_free = 0;
+ if ( NULL == freelist )
+ init_heap ();
+
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset (p->next_node)) {
+ std::cout << ( prev == 0 ? "" : " ") << "Offset: " << offset_from_node ( p )
+ << "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
+ total_free += p->len;
+ }
+ std::cout << "Total Free space: " << total_free << std::endl;
+ return total_free;
+ }
+#endif
+} // end unnamed namespace
diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp
new file mode 100644
index 00000000000..df03596e8b6
--- /dev/null
+++ b/lib/libcxxabi/src/private_typeinfo.cpp
@@ -0,0 +1,1279 @@
+//===----------------------- private_typeinfo.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 "private_typeinfo.h"
+
+// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more
+// forgiving when type_info's mistakenly have hidden visibility and thus
+// multiple type_infos can exist for a single type.
+//
+// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where
+// there is a detected inconsistency in the type_info hierarchy during a
+// dynamic_cast, then the equality operation will fall back to using strcmp
+// on type_info names to determine type_info equality.
+//
+// This change happens *only* under dynamic_cast, and only when
+// dynamic_cast is faced with the choice: abort, or possibly give back the
+// wrong answer. If when the dynamic_cast is done with this fallback
+// algorithm and an inconsistency is still detected, dynamic_cast will call
+// abort with an appropriate message.
+//
+// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
+// printf-like function called syslog:
+//
+// void syslog(int facility_priority, const char* format, ...);
+//
+// If you want this functionality but your platform doesn't have syslog,
+// just implement it in terms of fprintf(stderr, ...).
+//
+// _LIBCXX_DYNAMIC_FALLBACK is currently off by default.
+
+
+#include <string.h>
+
+
+#ifdef _LIBCXX_DYNAMIC_FALLBACK
+#include "abort_message.h"
+#include <sys/syslog.h>
+#endif
+
+// On Windows, typeids are different between DLLs and EXEs, so comparing
+// type_info* will work for typeids from the same compiled file but fail
+// for typeids from a DLL and an executable. Among other things, exceptions
+// are not caught by handlers since can_catch() returns false.
+//
+// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls
+// is_equal() with use_strcmp=false so the string names are not compared.
+
+#ifdef _WIN32
+#include <string.h>
+#endif
+
+namespace __cxxabiv1
+{
+
+#pragma GCC visibility push(hidden)
+
+inline
+bool
+is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)
+{
+#ifndef _WIN32
+ if (!use_strcmp)
+ return x == y;
+ return strcmp(x->name(), y->name()) == 0;
+#else
+ return (x == y) || (strcmp(x->name(), y->name()) == 0);
+#endif
+}
+
+
+// __shim_type_info
+
+__shim_type_info::~__shim_type_info()
+{
+}
+
+void __shim_type_info::noop1() const {}
+void __shim_type_info::noop2() const {}
+
+// __fundamental_type_info
+
+// This miraculously (compiler magic) emits the type_info's for:
+// 1. all of the fundamental types
+// 2. pointers to all of the fundamental types
+// 3. pointers to all of the const fundamental types
+__fundamental_type_info::~__fundamental_type_info()
+{
+}
+
+// __array_type_info
+
+__array_type_info::~__array_type_info()
+{
+}
+
+// __function_type_info
+
+__function_type_info::~__function_type_info()
+{
+}
+
+// __enum_type_info
+
+__enum_type_info::~__enum_type_info()
+{
+}
+
+// __class_type_info
+
+__class_type_info::~__class_type_info()
+{
+}
+
+// __si_class_type_info
+
+__si_class_type_info::~__si_class_type_info()
+{
+}
+
+// __vmi_class_type_info
+
+__vmi_class_type_info::~__vmi_class_type_info()
+{
+}
+
+// __pbase_type_info
+
+__pbase_type_info::~__pbase_type_info()
+{
+}
+
+// __pointer_type_info
+
+__pointer_type_info::~__pointer_type_info()
+{
+}
+
+// __pointer_to_member_type_info
+
+__pointer_to_member_type_info::~__pointer_to_member_type_info()
+{
+}
+
+// can_catch
+
+// A handler is a match for an exception object of type E if
+// 1. The handler is of type cv T or cv T& and E and T are the same type
+// (ignoring the top-level cv-qualifiers), or
+// 2. the handler is of type cv T or cv T& and T is an unambiguous public
+// base class of E, or
+// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be
+// converted to the type of the handler by either or both of
+// A. a standard pointer conversion (4.10) not involving conversions to
+// pointers to private or protected or ambiguous classes
+// B. a qualification conversion
+// 4. the handler is a pointer or pointer to member type and E is
+// std::nullptr_t.
+
+// adjustedPtr:
+//
+// catch (A& a) : adjustedPtr == &a
+// catch (A* a) : adjustedPtr == a
+// catch (A** a) : adjustedPtr == a
+//
+// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)
+// catch (D2* d2) : adjustedPtr == d2
+// catch (D2*& d2) : adjustedPtr == d2
+//
+// catch (...) : adjustedPtr == & of the exception
+
+// Handles bullet 1
+bool
+__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ return is_equal(this, thrown_type, false);
+}
+
+bool
+__array_type_info::can_catch(const __shim_type_info*, void*&) const
+{
+ // We can get here if someone tries to catch an array by reference.
+ // However if someone tries to throw an array, it immediately gets
+ // converted to a pointer, which will not convert back to an array
+ // at the catch clause. So this can never catch anything.
+ return false;
+}
+
+bool
+__function_type_info::can_catch(const __shim_type_info*, void*&) const
+{
+ // We can get here if someone tries to catch a function by reference.
+ // However if someone tries to throw a function, it immediately gets
+ // converted to a pointer, which will not convert back to a function
+ // at the catch clause. So this can never catch anything.
+ return false;
+}
+
+// Handles bullet 1
+bool
+__enum_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ return is_equal(this, thrown_type, false);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+// Handles bullets 1 and 2
+bool
+__class_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*& adjustedPtr) const
+{
+ // bullet 1
+ if (is_equal(this, thrown_type, false))
+ return true;
+ const __class_type_info* thrown_class_type =
+ dynamic_cast<const __class_type_info*>(thrown_type);
+ if (thrown_class_type == 0)
+ return false;
+ // bullet 2
+ __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0};
+ info.number_of_dst_type = 1;
+ thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ {
+ adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
+ return true;
+ }
+ return false;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+void
+__class_type_info::process_found_base_class(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (info->dst_ptr_leading_to_static_ptr == 0)
+ {
+ // First time here
+ info->dst_ptr_leading_to_static_ptr = adjustedPtr;
+ info->path_dst_ptr_to_static_ptr = path_below;
+ info->number_to_static_ptr = 1;
+ }
+ else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
+ {
+ // We've been here before. Update path to "most public"
+ if (info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->path_dst_ptr_to_static_ptr = path_below;
+ }
+ else
+ {
+ // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
+ // to a static_type
+ info->number_to_static_ptr += 1;
+ info->path_dst_ptr_to_static_ptr = not_public_path;
+ info->search_done = true;
+ }
+}
+
+void
+__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (is_equal(this, info->static_type, false))
+ process_found_base_class(info, adjustedPtr, path_below);
+}
+
+void
+__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (is_equal(this, info->static_type, false))
+ process_found_base_class(info, adjustedPtr, path_below);
+ else
+ __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
+}
+
+void
+__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ ptrdiff_t offset_to_base = 0;
+ if (adjustedPtr != nullptr)
+ {
+ offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(adjustedPtr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ }
+ __base_type->has_unambiguous_public_base(
+ info,
+ static_cast<char*>(adjustedPtr) + offset_to_base,
+ (__offset_flags & __public_mask) ? path_below : not_public_path);
+}
+
+void
+__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (is_equal(this, info->static_type, false))
+ process_found_base_class(info, adjustedPtr, path_below);
+ else
+ {
+ typedef const __base_class_type_info* Iter;
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ p->has_unambiguous_public_base(info, adjustedPtr, path_below);
+ if (++p < e)
+ {
+ do
+ {
+ p->has_unambiguous_public_base(info, adjustedPtr, path_below);
+ if (info->search_done)
+ break;
+ } while (++p < e);
+ }
+ }
+}
+
+// Handles bullets 1 and 4 for both pointers and member pointers
+bool
+__pbase_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) return true;
+ bool use_strcmp = this->__flags & (__incomplete_class_mask |
+ __incomplete_mask);
+ if (!use_strcmp) {
+ const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>(
+ thrown_type);
+ if (!thrown_pbase) return false;
+ use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask |
+ __incomplete_mask);
+ }
+ return is_equal(this, thrown_type, use_strcmp);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+// Handles bullets 1, 3 and 4
+// NOTE: It might not be safe to adjust the pointer if it is not not a pointer
+// type. Only adjust the pointer after we know it is safe to do so.
+bool
+__pointer_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*& adjustedPtr) const
+{
+ // bullets 1 and 4
+ if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) {
+ if (adjustedPtr != NULL)
+ adjustedPtr = *static_cast<void**>(adjustedPtr);
+ return true;
+ }
+ // bullet 3
+ const __pointer_type_info* thrown_pointer_type =
+ dynamic_cast<const __pointer_type_info*>(thrown_type);
+ if (thrown_pointer_type == 0)
+ return false;
+ // Do the dereference adjustment
+ if (adjustedPtr != NULL)
+ adjustedPtr = *static_cast<void**>(adjustedPtr);
+ // bullet 3B
+ if (thrown_pointer_type->__flags & ~__flags)
+ return false;
+ if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
+ return true;
+ // bullet 3A
+ if (is_equal(__pointee, &typeid(void), false)) {
+ // pointers to functions cannot be converted to void*.
+ // pointers to member functions are not handled here.
+ const __function_type_info* thrown_function =
+ dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee);
+ return (thrown_function == nullptr);
+ }
+ // Handle pointer to pointer
+ const __pointer_type_info* nested_pointer_type =
+ dynamic_cast<const __pointer_type_info*>(__pointee);
+ if (nested_pointer_type) {
+ if (~__flags & __const_mask) return false;
+ return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee);
+ }
+
+ // Handle pointer to pointer to member
+ const __pointer_to_member_type_info* member_ptr_type =
+ dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
+ if (member_ptr_type) {
+ if (~__flags & __const_mask) return false;
+ return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
+ }
+
+ // Handle pointer to class type
+ const __class_type_info* catch_class_type =
+ dynamic_cast<const __class_type_info*>(__pointee);
+ if (catch_class_type == 0)
+ return false;
+ const __class_type_info* thrown_class_type =
+ dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
+ if (thrown_class_type == 0)
+ return false;
+ __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0};
+ info.number_of_dst_type = 1;
+ thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ {
+ if (adjustedPtr != NULL)
+ adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
+ return true;
+ }
+ return false;
+}
+
+bool __pointer_type_info::can_catch_nested(
+ const __shim_type_info* thrown_type) const
+{
+ const __pointer_type_info* thrown_pointer_type =
+ dynamic_cast<const __pointer_type_info*>(thrown_type);
+ if (thrown_pointer_type == 0)
+ return false;
+ // bullet 3B
+ if (thrown_pointer_type->__flags & ~__flags)
+ return false;
+ if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
+ return true;
+ // If the pointed to types differ then the catch type must be const
+ // qualified.
+ if (~__flags & __const_mask)
+ return false;
+
+ // Handle pointer to pointer
+ const __pointer_type_info* nested_pointer_type =
+ dynamic_cast<const __pointer_type_info*>(__pointee);
+ if (nested_pointer_type) {
+ return nested_pointer_type->can_catch_nested(
+ thrown_pointer_type->__pointee);
+ }
+
+ // Handle pointer to pointer to member
+ const __pointer_to_member_type_info* member_ptr_type =
+ dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
+ if (member_ptr_type) {
+ return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
+ }
+
+ return false;
+}
+
+bool __pointer_to_member_type_info::can_catch(
+ const __shim_type_info* thrown_type, void*& adjustedPtr) const {
+ // bullets 1 and 4
+ if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
+ return true;
+
+ const __pointer_to_member_type_info* thrown_pointer_type =
+ dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
+ if (thrown_pointer_type == 0)
+ return false;
+ if (thrown_pointer_type->__flags & ~__flags)
+ return false;
+ if (!is_equal(__pointee, thrown_pointer_type->__pointee, false))
+ return false;
+ if (is_equal(__context, thrown_pointer_type->__context, false))
+ return true;
+
+ // [except.handle] does not allow the pointer-to-member conversions mentioned
+ // in [mem.conv] to take place. For this reason we don't check Derived->Base
+ // for Derived->Base conversions.
+
+ return false;
+}
+
+bool __pointer_to_member_type_info::can_catch_nested(
+ const __shim_type_info* thrown_type) const
+{
+ const __pointer_to_member_type_info* thrown_member_ptr_type =
+ dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
+ if (thrown_member_ptr_type == 0)
+ return false;
+ if (~__flags & thrown_member_ptr_type->__flags)
+ return false;
+ if (!is_equal(__pointee, thrown_member_ptr_type->__pointee, false))
+ return false;
+ if (!is_equal(__context, thrown_member_ptr_type->__context, false))
+ return false;
+ return true;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(default)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+// __dynamic_cast
+
+// static_ptr: pointer to an object of type static_type; nonnull, and since the
+// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
+// static_ptr is &v in the expression dynamic_cast<T>(v).
+// static_type: static type of the object pointed to by static_ptr.
+// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
+// src2dst_offset: a static hint about the location of the
+// source subobject with respect to the complete object;
+// special negative values are:
+// -1: no hint
+// -2: static_type is not a public base of dst_type
+// -3: static_type is a multiple public base type but never a
+// virtual base type
+// otherwise, the static_type type is a unique public nonvirtual
+// base type of dst_type at offset src2dst_offset from the
+// origin of dst_type.
+//
+// (dynamic_ptr, dynamic_type) are the run time type of the complete object
+// referred to by static_ptr and a pointer to it. These can be found from
+// static_ptr for polymorphic types.
+// static_type is guaranteed to be a polymorphic type.
+//
+// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
+// node of the tree represents a base class/object of its parent (or parents) below.
+// Each node is uniquely represented by a pointer to the object, and a pointer
+// to a type_info - its type. Different nodes may have the same pointer and
+// different nodes may have the same type. But only one node has a specific
+// (pointer-value, type) pair. In C++ two objects of the same type can not
+// share the same address.
+//
+// There are two flavors of nodes which have the type dst_type:
+// 1. Those that are derived from (below) (static_ptr, static_type).
+// 2. Those that are not derived from (below) (static_ptr, static_type).
+//
+// Invariants of the DAG:
+//
+// There is at least one path from the root (dynamic_ptr, dynamic_type) to
+// the node (static_ptr, static_type). This path may or may not be public.
+// There may be more than one such path (some public some not). Such a path may
+// or may not go through a node having type dst_type.
+//
+// No node of type T appears above a node of the same type. That means that
+// there is only one node with dynamic_type. And if dynamic_type == dst_type,
+// then there is only one dst_type in the DAG.
+//
+// No node of type dst_type appears above a node of type static_type. Such
+// DAG's are possible in C++, but the compiler computes those dynamic_casts at
+// compile time, and only calls __dynamic_cast when dst_type lies below
+// static_type in the DAG.
+//
+// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
+// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.
+//
+// Returns:
+//
+// If there is exactly one dst_type of flavor 1, and
+// If there is a public path from that dst_type to (static_ptr, static_type), or
+// If there are 0 dst_types of flavor 2, and there is a public path from
+// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
+// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
+// a pointer to that dst_type.
+// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
+// if there is a public path from (dynamic_ptr, dynamic_type) to
+// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
+// to the one dst_type, then return a pointer to that one dst_type.
+// Else return nullptr.
+//
+// If dynamic_type == dst_type, then the above algorithm collapses to the
+// following cheaper algorithm:
+//
+// If there is a public path from (dynamic_ptr, dynamic_type) to
+// (static_ptr, static_type), then return dynamic_ptr.
+// Else return nullptr.
+extern "C"
+void*
+__dynamic_cast(const void* static_ptr,
+ const __class_type_info* static_type,
+ const __class_type_info* dst_type,
+ std::ptrdiff_t src2dst_offset)
+{
+ // Possible future optimization: Take advantage of src2dst_offset
+ // Currently clang always sets src2dst_offset to -1 (no hint).
+
+ // Get (dynamic_ptr, dynamic_type) from static_ptr
+ void **vtable = *static_cast<void ** const *>(static_ptr);
+ ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
+ const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
+ const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
+
+ // Initialize answer to nullptr. This will be changed from the search
+ // results if a non-null answer is found. Regardless, this is what will
+ // be returned.
+ const void* dst_ptr = 0;
+ // Initialize info struct for this search.
+ __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+
+ // Find out if we can use a giant short cut in the search
+ if (is_equal(dynamic_type, dst_type, false))
+ {
+ // Using giant short cut. Add that information to info.
+ info.number_of_dst_type = 1;
+ // Do the search
+ dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
+#ifdef _LIBCXX_DYNAMIC_FALLBACK
+ // The following if should always be false because we should definitely
+ // find (static_ptr, static_type), either on a public or private path
+ if (info.path_dst_ptr_to_static_ptr == unknown)
+ {
+ // We get here only if there is some kind of visibility problem
+ // in client code.
+ syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
+ "should have public visibility. At least one of them is hidden. %s"
+ ", %s.\n", static_type->name(), dynamic_type->name());
+ // Redo the search comparing type_info's using strcmp
+ info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+ info.number_of_dst_type = 1;
+ dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
+ }
+#endif // _LIBCXX_DYNAMIC_FALLBACK
+ // Query the search.
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ dst_ptr = dynamic_ptr;
+ }
+ else
+ {
+ // Not using giant short cut. Do the search
+ dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
+ #ifdef _LIBCXX_DYNAMIC_FALLBACK
+ // The following if should always be false because we should definitely
+ // find (static_ptr, static_type), either on a public or private path
+ if (info.path_dst_ptr_to_static_ptr == unknown &&
+ info.path_dynamic_ptr_to_static_ptr == unknown)
+ {
+ syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
+ " has hidden visibility. They should all have public visibility. "
+ " %s, %s, %s.\n", static_type->name(), dynamic_type->name(),
+ dst_type->name());
+ // Redo the search comparing type_info's using strcmp
+ info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+ dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
+ }
+#endif // _LIBCXX_DYNAMIC_FALLBACK
+ // Query the search.
+ switch (info.number_to_static_ptr)
+ {
+ case 0:
+ if (info.number_to_dst_ptr == 1 &&
+ info.path_dynamic_ptr_to_static_ptr == public_path &&
+ info.path_dynamic_ptr_to_dst_ptr == public_path)
+ dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
+ break;
+ case 1:
+ if (info.path_dst_ptr_to_static_ptr == public_path ||
+ (
+ info.number_to_dst_ptr == 0 &&
+ info.path_dynamic_ptr_to_static_ptr == public_path &&
+ info.path_dynamic_ptr_to_dst_ptr == public_path
+ )
+ )
+ dst_ptr = info.dst_ptr_leading_to_static_ptr;
+ break;
+ }
+ }
+ return const_cast<void*>(dst_ptr);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(hidden)
+
+// Call this function when you hit a static_type which is a base (above) a dst_type.
+// Let caller know you hit a static_type. But only start recording details if
+// this is (static_ptr, static_type) -- the node we are casting from.
+// If this is (static_ptr, static_type)
+// Record the path (public or not) from the dst_type to here. There may be
+// multiple paths from the same dst_type to here, record the "most public" one.
+// Record the dst_ptr as pointing to (static_ptr, static_type).
+// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
+// then mark this dyanmic_cast as ambiguous and stop the search.
+void
+__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ // Record that we found a static_type
+ info->found_any_static_type = true;
+ if (current_ptr == info->static_ptr)
+ {
+ // Record that we found (static_ptr, static_type)
+ info->found_our_static_ptr = true;
+ if (info->dst_ptr_leading_to_static_ptr == 0)
+ {
+ // First time here
+ info->dst_ptr_leading_to_static_ptr = dst_ptr;
+ info->path_dst_ptr_to_static_ptr = path_below;
+ info->number_to_static_ptr = 1;
+ // If there is only one dst_type in the entire tree and the path from
+ // there to here is public then we are done!
+ if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
+ info->search_done = true;
+ }
+ else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)
+ {
+ // We've been here before. Update path to "most public"
+ if (info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->path_dst_ptr_to_static_ptr = path_below;
+ // If there is only one dst_type in the entire tree and the path from
+ // there to here is public then we are done!
+ if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
+ info->search_done = true;
+ }
+ else
+ {
+ // We've detected an ambiguous cast from (static_ptr, static_type)
+ // to a dst_type
+ info->number_to_static_ptr += 1;
+ info->search_done = true;
+ }
+ }
+}
+
+// Call this function when you hit a static_type which is not a base (above) a dst_type.
+// If this is (static_ptr, static_type)
+// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be
+// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.
+void
+__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (current_ptr == info->static_ptr)
+ {
+ // Record the most public path from (dynamic_ptr, dynamic_type) to
+ // (static_ptr, static_type)
+ if (info->path_dynamic_ptr_to_static_ptr != public_path)
+ info->path_dynamic_ptr_to_static_ptr = path_below;
+ }
+}
+
+// Call this function when searching below a dst_type node. This function searches
+// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.
+// If it finds a static_type node, there is no need to further search base classes
+// above.
+// If it finds a dst_type node it should search base classes using search_above_dst
+// to find out if this dst_type points to (static_ptr, static_type) or not.
+// Either way, the dst_type is recorded as one of two "flavors": one that does
+// or does not point to (static_ptr, static_type).
+// If this is neither a static_type nor a dst_type node, continue searching
+// base classes above.
+// All the hoopla surrounding the search code is doing nothing but looking for
+// excuses to stop the search prematurely (break out of the for-loop). That is,
+// the algorithm below is simply an optimization of this:
+// void
+// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
+// const void* current_ptr,
+// int path_below) const
+// {
+// typedef const __base_class_type_info* Iter;
+// if (this == info->static_type)
+// process_static_type_below_dst(info, current_ptr, path_below);
+// else if (this == info->dst_type)
+// {
+// // Record the most public access path that got us here
+// if (info->path_dynamic_ptr_to_dst_ptr != public_path)
+// info->path_dynamic_ptr_to_dst_ptr = path_below;
+// bool does_dst_type_point_to_our_static_type = false;
+// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)
+// {
+// p->search_above_dst(info, current_ptr, current_ptr, public_path);
+// if (info->found_our_static_ptr)
+// does_dst_type_point_to_our_static_type = true;
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// if (!does_dst_type_point_to_our_static_type)
+// {
+// // We found a dst_type that doesn't point to (static_ptr, static_type)
+// // So record the address of this dst_ptr and increment the
+// // count of the number of such dst_types found in the tree.
+// info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+// info->number_to_dst_ptr += 1;
+// }
+// }
+// else
+// {
+// // This is not a static_type and not a dst_type.
+// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+// {
+// p->search_below_dst(info, current_ptr, public_path);
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// }
+// }
+void
+__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ typedef const __base_class_type_info* Iter;
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (is_equal(this, info->dst_type, use_strcmp))
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // Record the access path that got us here
+ // If there is more than one dst_type this path doesn't matter.
+ info->path_dynamic_ptr_to_dst_ptr = path_below;
+ // Only search above here if dst_type derives from static_type, or
+ // if it is unknown if dst_type derives from static_type.
+ if (info->is_dst_type_derived_from_static_type != no)
+ {
+ // Set up flags to record results from all base classes
+ bool is_dst_type_derived_from_static_type = false;
+ bool does_dst_type_point_to_our_static_type = false;
+ // We've found a dst_type with a potentially public path to here.
+ // We have to assume the path is public because it may become
+ // public later (if we get back to here with a public path).
+ // We can stop looking above if:
+ // 1. We've found a public path to (static_ptr, static_type).
+ // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
+ // This is detected at the (static_ptr, static_type).
+ // 3. We can prove that there is no public path to (static_ptr, static_type)
+ // above here.
+ const Iter e = __base_info + __base_count;
+ for (Iter p = __base_info; p < e; ++p)
+ {
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
+ if (info->search_done)
+ break;
+ if (info->found_any_static_type)
+ {
+ is_dst_type_derived_from_static_type = true;
+ if (info->found_our_static_ptr)
+ {
+ does_dst_type_point_to_our_static_type = true;
+ // If we found what we're looking for, stop looking above.
+ if (info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ // We found a private path to (static_ptr, static_type)
+ // If there is no diamond then there is only one path
+ // to (static_ptr, static_type) and we just found it.
+ if (!(__flags & __diamond_shaped_mask))
+ break;
+ }
+ else
+ {
+ // If we found a static_type that isn't the one we're looking
+ // for, and if there are no repeated types above here,
+ // then stop looking.
+ if (!(__flags & __non_diamond_repeat_mask))
+ break;
+ }
+ }
+ }
+ if (!does_dst_type_point_to_our_static_type)
+ {
+ // We found a dst_type that doesn't point to (static_ptr, static_type)
+ // So record the address of this dst_ptr and increment the
+ // count of the number of such dst_types found in the tree.
+ info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+ info->number_to_dst_ptr += 1;
+ // If there exists another dst with a private path to
+ // (static_ptr, static_type), then the cast from
+ // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
+ // so stop search.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->search_done = true;
+ }
+ // If we found no static_type,s then dst_type doesn't derive
+ // from static_type, else it does. Record this result so that
+ // next time we hit a dst_type we will know not to search above
+ // it if it doesn't derive from static_type.
+ if (is_dst_type_derived_from_static_type)
+ info->is_dst_type_derived_from_static_type = yes;
+ else
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+ }
+ else
+ {
+ // This is not a static_type and not a dst_type.
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+ if (++p < e)
+ {
+ if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
+ {
+ // If there are multiple paths to a base above from here, or if
+ // a dst_type pointing to (static_ptr, static_type) has been found,
+ // then there is no way to break out of this loop early unless
+ // something below detects the search is done.
+ do
+ {
+ if (info->search_done)
+ break;
+ p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+ } while (++p < e);
+ }
+ else if (__flags & __non_diamond_repeat_mask)
+ {
+ // There are not multiple paths to any base class from here and a
+ // dst_type pointing to (static_ptr, static_type) has not yet been
+ // found.
+ do
+ {
+ if (info->search_done)
+ break;
+ // If we just found a dst_type with a public path to (static_ptr, static_type),
+ // then the only reason to continue the search is to make sure
+ // no other dst_type points to (static_ptr, static_type).
+ // If !diamond, then we don't need to search here.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+ } while (++p < e);
+ }
+ else
+ {
+ // There are no repeated types above this node.
+ // There are no nodes with multiple parents above this node.
+ // no dst_type has been found to (static_ptr, static_type)
+ do
+ {
+ if (info->search_done)
+ break;
+ // If we just found a dst_type with a public path to (static_ptr, static_type),
+ // then the only reason to continue the search is to make sure sure
+ // no other dst_type points to (static_ptr, static_type).
+ // If !diamond, then we don't need to search here.
+ // if we just found a dst_type with a private path to (static_ptr, static_type),
+ // then we're only looking for a public path to (static_ptr, static_type)
+ // and to check for other dst_types.
+ // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
+ // and not a dst_type under here.
+ if (info->number_to_static_ptr == 1)
+ break;
+ p->search_below_dst(info, current_ptr, path_below, use_strcmp);
+ } while (++p < e);
+ }
+ }
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_below_dst but
+// simplified to the case that there is only a single base class.
+void
+__si_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (is_equal(this, info->dst_type, use_strcmp))
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // Record the access path that got us here
+ // If there is more than one dst_type this path doesn't matter.
+ info->path_dynamic_ptr_to_dst_ptr = path_below;
+ // Only search above here if dst_type derives from static_type, or
+ // if it is unknown if dst_type derives from static_type.
+ if (info->is_dst_type_derived_from_static_type != no)
+ {
+ // Set up flags to record results from all base classes
+ bool is_dst_type_derived_from_static_type = false;
+ bool does_dst_type_point_to_our_static_type = false;
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
+ if (info->found_any_static_type)
+ {
+ is_dst_type_derived_from_static_type = true;
+ if (info->found_our_static_ptr)
+ does_dst_type_point_to_our_static_type = true;
+ }
+ if (!does_dst_type_point_to_our_static_type)
+ {
+ // We found a dst_type that doesn't point to (static_ptr, static_type)
+ // So record the address of this dst_ptr and increment the
+ // count of the number of such dst_types found in the tree.
+ info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+ info->number_to_dst_ptr += 1;
+ // If there exists another dst with a private path to
+ // (static_ptr, static_type), then the cast from
+ // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->search_done = true;
+ }
+ // If we found no static_type,s then dst_type doesn't derive
+ // from static_type, else it does. Record this result so that
+ // next time we hit a dst_type we will know not to search above
+ // it if it doesn't derive from static_type.
+ if (is_dst_type_derived_from_static_type)
+ info->is_dst_type_derived_from_static_type = yes;
+ else
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+ }
+ else
+ {
+ // This is not a static_type and not a dst_type
+ __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_below_dst but
+// simplified to the case that there is no base class.
+void
+__class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (is_equal(this, info->dst_type, use_strcmp))
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // Record the access path that got us here
+ // If there is more than one dst_type this path doesn't matter.
+ info->path_dynamic_ptr_to_dst_ptr = path_below;
+ // We found a dst_type that doesn't point to (static_ptr, static_type)
+ // So record the address of this dst_ptr and increment the
+ // count of the number of such dst_types found in the tree.
+ info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+ info->number_to_dst_ptr += 1;
+ // If there exists another dst with a private path to
+ // (static_ptr, static_type), then the cast from
+ // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->search_done = true;
+ // We found that dst_type does not derive from static_type
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+}
+
+// Call this function when searching above a dst_type node. This function searches
+// for a public path to (static_ptr, static_type).
+// This function is guaranteed not to find a node of type dst_type.
+// Theoretically this is a very simple function which just stops if it finds a
+// static_type node: All the hoopla surrounding the search code is doing
+// nothing but looking for excuses to stop the search prematurely (break out of
+// the for-loop). That is, the algorithm below is simply an optimization of this:
+// void
+// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
+// const void* dst_ptr,
+// const void* current_ptr,
+// int path_below) const
+// {
+// if (this == info->static_type)
+// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+// else
+// {
+// typedef const __base_class_type_info* Iter;
+// // This is not a static_type and not a dst_type
+// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+// {
+// p->search_above_dst(info, dst_ptr, current_ptr, public_path);
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// }
+// }
+void
+__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+ else
+ {
+ typedef const __base_class_type_info* Iter;
+ // This is not a static_type and not a dst_type
+ // Save flags so they can be restored when returning to nodes below.
+ bool found_our_static_ptr = info->found_our_static_ptr;
+ bool found_any_static_type = info->found_any_static_type;
+ // We've found a dst_type below with a path to here. If the path
+ // to here is not public, there may be another path to here that
+ // is public. So we have to assume that the path to here is public.
+ // We can stop looking above if:
+ // 1. We've found a public path to (static_ptr, static_type).
+ // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
+ // This is detected at the (static_ptr, static_type).
+ // 3. We can prove that there is no public path to (static_ptr, static_type)
+ // above here.
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+ if (++p < e)
+ {
+ do
+ {
+ if (info->search_done)
+ break;
+ if (info->found_our_static_ptr)
+ {
+ // If we found what we're looking for, stop looking above.
+ if (info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ // We found a private path to (static_ptr, static_type)
+ // If there is no diamond then there is only one path
+ // to (static_ptr, static_type) from here and we just found it.
+ if (!(__flags & __diamond_shaped_mask))
+ break;
+ }
+ else if (info->found_any_static_type)
+ {
+ // If we found a static_type that isn't the one we're looking
+ // for, and if there are no repeated types above here,
+ // then stop looking.
+ if (!(__flags & __non_diamond_repeat_mask))
+ break;
+ }
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+ } while (++p < e);
+ }
+ // Restore flags
+ info->found_our_static_ptr = found_our_static_ptr;
+ info->found_any_static_type = found_any_static_type;
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_above_dst but
+// simplified to the case that there is only a single base class.
+void
+__si_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+ else
+ __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_above_dst but
+// simplified to the case that there is no base class.
+void
+__class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ if (is_equal(this, info->static_type, use_strcmp))
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+}
+
+// The search functions for __base_class_type_info are simply convenience
+// functions for adjusting the current_ptr and path_below as the search is
+// passed up to the base class node.
+
+void
+__base_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ __base_type->search_above_dst(info, dst_ptr,
+ static_cast<const char*>(current_ptr) + offset_to_base,
+ (__offset_flags & __public_mask) ?
+ path_below :
+ not_public_path,
+ use_strcmp);
+}
+
+void
+__base_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below,
+ bool use_strcmp) const
+{
+ ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ __base_type->search_below_dst(info,
+ static_cast<const char*>(current_ptr) + offset_to_base,
+ (__offset_flags & __public_mask) ?
+ path_below :
+ not_public_path,
+ use_strcmp);
+}
+
+#pragma GCC visibility pop
+
+} // __cxxabiv1
diff --git a/lib/libcxxabi/src/private_typeinfo.h b/lib/libcxxabi/src/private_typeinfo.h
new file mode 100644
index 00000000000..ef98c3ae60b
--- /dev/null
+++ b/lib/libcxxabi/src/private_typeinfo.h
@@ -0,0 +1,240 @@
+//===------------------------ private_typeinfo.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 __PRIVATE_TYPEINFO_H_
+#define __PRIVATE_TYPEINFO_H_
+
+#include "__cxxabi_config.h"
+
+#include <typeinfo>
+#include <cstddef>
+
+namespace __cxxabiv1 {
+#pragma GCC visibility push(hidden)
+
+class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__shim_type_info();
+
+ _LIBCXXABI_HIDDEN virtual void noop1() const;
+ _LIBCXXABI_HIDDEN virtual void noop2() const;
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type,
+ void *&adjustedPtr) const = 0;
+};
+
+class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__fundamental_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__array_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__function_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__enum_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+};
+
+enum
+{
+ unknown = 0,
+ public_path,
+ not_public_path,
+ yes,
+ no
+};
+
+class _LIBCXXABI_TYPE_VIS __class_type_info;
+
+struct __dynamic_cast_info
+{
+// const data supplied to the search:
+
+ const __class_type_info* dst_type;
+ const void* static_ptr;
+ const __class_type_info* static_type;
+ std::ptrdiff_t src2dst_offset;
+
+// Data that represents the answer:
+
+ // pointer to a dst_type which has (static_ptr, static_type) above it
+ const void* dst_ptr_leading_to_static_ptr;
+ // pointer to a dst_type which does not have (static_ptr, static_type) above it
+ const void* dst_ptr_not_leading_to_static_ptr;
+
+ // The following three paths are either unknown, public_path or not_public_path.
+ // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
+ int path_dst_ptr_to_static_ptr;
+ // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
+ // when there is no dst_type along the path
+ int path_dynamic_ptr_to_static_ptr;
+ // access of path from (dynamic_ptr, dynamic_type) to dst_type
+ // (not used if there is a (static_ptr, static_type) above a dst_type).
+ int path_dynamic_ptr_to_dst_ptr;
+
+ // Number of dst_types below (static_ptr, static_type)
+ int number_to_static_ptr;
+ // Number of dst_types not below (static_ptr, static_type)
+ int number_to_dst_ptr;
+
+// Data that helps stop the search before the entire tree is searched:
+
+ // is_dst_type_derived_from_static_type is either unknown, yes or no.
+ int is_dst_type_derived_from_static_type;
+ // Number of dst_type in tree. If 0, then that means unknown.
+ int number_of_dst_type;
+ // communicates to a dst_type node that (static_ptr, static_type) was found
+ // above it.
+ bool found_our_static_ptr;
+ // communicates to a dst_type node that a static_type was found
+ // above it, but it wasn't (static_ptr, static_type)
+ bool found_any_static_type;
+ // Set whenever a search can be stopped
+ bool search_done;
+};
+
+// Has no base class
+class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__class_type_info();
+
+ _LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
+ const void *,
+ const void *, int) const;
+ _LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
+ const void *, int) const;
+ _LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *,
+ int) const;
+ _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
+ const void *, const void *,
+ int, bool) const;
+ _LIBCXXABI_HIDDEN virtual void
+ search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+ _LIBCXXABI_HIDDEN virtual void
+ has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
+};
+
+// Has one non-virtual public base class at offset zero
+class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
+public:
+ const __class_type_info *__base_type;
+
+ _LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
+
+ _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
+ const void *, const void *,
+ int, bool) const;
+ _LIBCXXABI_HIDDEN virtual void
+ search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
+ _LIBCXXABI_HIDDEN virtual void
+ has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
+};
+
+struct __base_class_type_info
+{
+public:
+ const __class_type_info* __base_type;
+ long __offset_flags;
+
+ enum __offset_flags_masks
+ {
+ __virtual_mask = 0x1,
+ __public_mask = 0x2, // base is public
+ __offset_shift = 8
+ };
+
+ void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
+ void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
+ void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
+};
+
+// Has one or more base classes
+class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
+public:
+ unsigned int __flags;
+ unsigned int __base_count;
+ __base_class_type_info __base_info[1];
+
+ enum __flags_masks {
+ __non_diamond_repeat_mask = 0x1, // has two or more distinct base class
+ // objects of the same type
+ __diamond_shaped_mask = 0x2 // has base class object with two or
+ // more derived objects
+ };
+
+ _LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info();
+
+ _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
+ const void *, const void *,
+ int, bool) const;
+ _LIBCXXABI_HIDDEN virtual void
+ search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
+ _LIBCXXABI_HIDDEN virtual void
+ has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
+public:
+ unsigned int __flags;
+ const __shim_type_info *__pointee;
+
+ enum __masks {
+ __const_mask = 0x1,
+ __volatile_mask = 0x2,
+ __restrict_mask = 0x4,
+ __incomplete_mask = 0x8,
+ __incomplete_class_mask = 0x10
+ };
+
+ _LIBCXXABI_HIDDEN virtual ~__pbase_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
+public:
+ _LIBCXXABI_HIDDEN virtual ~__pointer_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+ _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
+};
+
+class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
+ : public __pbase_type_info {
+public:
+ const __class_type_info *__context;
+
+ _LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
+ _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
+ void *&) const;
+ _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
+};
+
+#pragma GCC visibility pop
+
+} // __cxxabiv1
+
+#endif // __PRIVATE_TYPEINFO_H_
diff --git a/lib/libcxxabi/src/stdexcept.cpp b/lib/libcxxabi/src/stdexcept.cpp
new file mode 100644
index 00000000000..bd6789ef227
--- /dev/null
+++ b/lib/libcxxabi/src/stdexcept.cpp
@@ -0,0 +1,48 @@
+//===------------------------ stdexcept.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 "__refstring"
+#include "stdexcept"
+#include "new"
+#include <cstdlib>
+#include <cstring>
+#include <cstdint>
+#include <cstddef>
+
+static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
+
+namespace std // purposefully not using versioning namespace
+{
+
+logic_error::~logic_error() _NOEXCEPT {}
+
+const char*
+logic_error::what() const _NOEXCEPT
+{
+ return __imp_.c_str();
+}
+
+runtime_error::~runtime_error() _NOEXCEPT {}
+
+const char*
+runtime_error::what() const _NOEXCEPT
+{
+ return __imp_.c_str();
+}
+
+domain_error::~domain_error() _NOEXCEPT {}
+invalid_argument::~invalid_argument() _NOEXCEPT {}
+length_error::~length_error() _NOEXCEPT {}
+out_of_range::~out_of_range() _NOEXCEPT {}
+
+range_error::~range_error() _NOEXCEPT {}
+overflow_error::~overflow_error() _NOEXCEPT {}
+underflow_error::~underflow_error() _NOEXCEPT {}
+
+} // std
diff --git a/lib/libcxxabi/src/typeinfo.cpp b/lib/libcxxabi/src/typeinfo.cpp
new file mode 100644
index 00000000000..9313be04a39
--- /dev/null
+++ b/lib/libcxxabi/src/typeinfo.cpp
@@ -0,0 +1,53 @@
+//===----------------------------- typeinfo.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 <typeinfo>
+
+namespace std
+{
+
+// type_info
+
+type_info::~type_info()
+{
+}
+
+// bad_cast
+
+bad_cast::bad_cast() _NOEXCEPT
+{
+}
+
+bad_cast::~bad_cast() _NOEXCEPT
+{
+}
+
+const char*
+bad_cast::what() const _NOEXCEPT
+{
+ return "std::bad_cast";
+}
+
+// bad_typeid
+
+bad_typeid::bad_typeid() _NOEXCEPT
+{
+}
+
+bad_typeid::~bad_typeid() _NOEXCEPT
+{
+}
+
+const char*
+bad_typeid::what() const _NOEXCEPT
+{
+ return "std::bad_typeid";
+}
+
+} // std