mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Add LLVM libcxxabi (#1063)
* third_party: Add libcxxabi Added libcxxabi from LLVM 17.0.6 The library implements the Itanium C++ exception handling ABI. * third_party/libcxxabi: Enable __cxa_thread_atexit Enable `__cxa_thread_atexit` from libcxxabi. `__cxa_thread_atexit_impl` is still implemented by the cosmo libc. The original `__cxa_thread_atexit` has been removed. * third_party/libcxx: Build with exceptions Build libcxx with exceptions enabled. - Removed `_LIBCPP_NO_EXCEPTIONS` from `__config`. - Switched the exception implementation to `libcxxabi`. These two files are taken from the same `libcxx` version as mentioned in `README.cosmo`. - Removed `new_handler_fallback` in favor of `libcxxabi` implementation. - Enable `-fexceptions` and `-frtti` for `libcxx`. - Removed `THIRD_PARTY_LIBCXX` dependency from `libcxxabi` and `libunwind`. These libraries do not use any runtime `libcxx` functions, just headers. * libc: Remove remaining redundant cxa functions - `__cxa_pure_virtual` in `libcxxabi` is also a stub similar to the existing one. - `__cxa_guard_*` from `libcxxabi` is used instead of the ones from Android. Now there should be no more duplicate implementations. `__cxa_thread_atexit_impl`, `__cxa_atexit`, and related supporting functions, are still left to other libraries as in `libcxxabi`. `libcxxabi` is also now added to `cosmopolitan.a` to make up for the removed functions. Affected in-tree libraries (`third_party/double-conversion`) have been updated.
This commit is contained in:
parent
94bab1618d
commit
8b33204f37
53 changed files with 14606 additions and 372 deletions
6
Makefile
6
Makefile
|
@ -249,7 +249,6 @@ include libc/calls/BUILD.mk #─┐
|
||||||
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
|
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
|
||||||
include third_party/nsync/BUILD.mk # │ You can issue system calls
|
include third_party/nsync/BUILD.mk # │ You can issue system calls
|
||||||
include libc/runtime/BUILD.mk # │
|
include libc/runtime/BUILD.mk # │
|
||||||
include third_party/double-conversion/BUILD.mk # │
|
|
||||||
include libc/crt/BUILD.mk # │
|
include libc/crt/BUILD.mk # │
|
||||||
include third_party/dlmalloc/BUILD.mk #─┘
|
include third_party/dlmalloc/BUILD.mk #─┘
|
||||||
include libc/mem/BUILD.mk #─┐
|
include libc/mem/BUILD.mk #─┐
|
||||||
|
@ -284,7 +283,10 @@ include third_party/stb/BUILD.mk # │
|
||||||
include third_party/mbedtls/BUILD.mk # │
|
include third_party/mbedtls/BUILD.mk # │
|
||||||
include third_party/ncurses/BUILD.mk # │
|
include third_party/ncurses/BUILD.mk # │
|
||||||
include third_party/readline/BUILD.mk # │
|
include third_party/readline/BUILD.mk # │
|
||||||
|
include third_party/libunwind/BUILD.mk # |
|
||||||
|
include third_party/libcxxabi/BUILD.mk # |
|
||||||
include third_party/libcxx/BUILD.mk # │
|
include third_party/libcxx/BUILD.mk # │
|
||||||
|
include third_party/double-conversion/BUILD.mk # │
|
||||||
include third_party/pcre/BUILD.mk # │
|
include third_party/pcre/BUILD.mk # │
|
||||||
include third_party/less/BUILD.mk # │
|
include third_party/less/BUILD.mk # │
|
||||||
include net/https/BUILD.mk # │
|
include net/https/BUILD.mk # │
|
||||||
|
@ -328,7 +330,6 @@ include third_party/python/BUILD.mk
|
||||||
include tool/build/BUILD.mk
|
include tool/build/BUILD.mk
|
||||||
include tool/curl/BUILD.mk
|
include tool/curl/BUILD.mk
|
||||||
include third_party/qemu/BUILD.mk
|
include third_party/qemu/BUILD.mk
|
||||||
include third_party/libunwind/BUILD.mk
|
|
||||||
include examples/BUILD.mk
|
include examples/BUILD.mk
|
||||||
include examples/pyapp/BUILD.mk
|
include examples/pyapp/BUILD.mk
|
||||||
include examples/pylife/BUILD.mk
|
include examples/pylife/BUILD.mk
|
||||||
|
@ -441,6 +442,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||||
LIBC_TIME \
|
LIBC_TIME \
|
||||||
THIRD_PARTY_MUSL \
|
THIRD_PARTY_MUSL \
|
||||||
THIRD_PARTY_ZLIB_GZ \
|
THIRD_PARTY_ZLIB_GZ \
|
||||||
|
THIRD_PARTY_LIBCXXABI \
|
||||||
THIRD_PARTY_LIBUNWIND \
|
THIRD_PARTY_LIBUNWIND \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
THIRD_PARTY_GDTOA \
|
THIRD_PARTY_GDTOA \
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
||||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
|
||||||
│ │
|
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
|
||||||
│ above copyright notice and this permission notice appear in all copies. │
|
|
||||||
│ │
|
|
||||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
||||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
||||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
||||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
||||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
||||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
|
|
||||||
void __cxa_pure_virtual(void) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
kprintf("__cxa_pure_virtual() called\n"
|
|
||||||
"Did you call a virtual method from a destructor?\n");
|
|
||||||
#endif
|
|
||||||
abort();
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2006 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#include "libc/atomic.h"
|
|
||||||
#include "libc/cxxabi.h"
|
|
||||||
#include "libc/intrin/atomic.h"
|
|
||||||
#include "libc/limits.h"
|
|
||||||
#include "third_party/nsync/futex.internal.h"
|
|
||||||
|
|
||||||
// This file contains C++ ABI support functions for one time
|
|
||||||
// constructors as defined in the "Run-time ABI for the ARM Architecture"
|
|
||||||
// section 4.4.2
|
|
||||||
//
|
|
||||||
// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for
|
|
||||||
// one time construction:
|
|
||||||
//
|
|
||||||
// ARM C++ ABI defines the LSB of guard variable should be tested
|
|
||||||
// by compiler-generated code before calling __cxa_guard_acquire et al.
|
|
||||||
//
|
|
||||||
// The Itanium/x86 C++ ABI defines the low-order _byte_ should be
|
|
||||||
// tested instead.
|
|
||||||
//
|
|
||||||
// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit
|
|
||||||
// aligned for x86.
|
|
||||||
//
|
|
||||||
// Reference documentation:
|
|
||||||
//
|
|
||||||
// section 3.2.3 of ARM IHI 0041C (for ARM)
|
|
||||||
// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86).
|
|
||||||
//
|
|
||||||
// There is no C++ ABI available for other ARCH. But the gcc source
|
|
||||||
// shows all other ARCH follow the definition of Itanium/x86 C++ ABI.
|
|
||||||
|
|
||||||
// The Itanium/x86 C++ ABI (used by all architectures that aren't ARM32)
|
|
||||||
// mandates guard variables are 64-bit aligned, 64-bit values. The least
|
|
||||||
// significant byte is tested by the compiler-generated code before it's
|
|
||||||
// calling __cxa_guard_acquire.
|
|
||||||
union CxaGuardValue {
|
|
||||||
atomic_int state;
|
|
||||||
int64_t aligner;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set construction state values according to reference documentation. 0
|
|
||||||
// is the initialization value. Arm requires ((*gv & 1) == 1) after
|
|
||||||
// __cxa_guard_release, ((*gv & 3) == 0) after __cxa_guard_abort. X86
|
|
||||||
// requires first byte not modified by __cxa_guard_acquire, first byte
|
|
||||||
// is non-zero after __cxa_guard_release.
|
|
||||||
#define CONSTRUCTION_NOT_YET_STARTED 0
|
|
||||||
#define CONSTRUCTION_COMPLETE 1
|
|
||||||
#define CONSTRUCTION_UNDERWAY_WITHOUT_WAITER 0x100
|
|
||||||
#define CONSTRUCTION_UNDERWAY_WITH_WAITER 0x200
|
|
||||||
|
|
||||||
int __cxa_guard_acquire(union CxaGuardValue *gv) {
|
|
||||||
int old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
|
|
||||||
while (true) {
|
|
||||||
if (old_value == CONSTRUCTION_COMPLETE) {
|
|
||||||
// A load_acquire operation is needed before exiting with COMPLETE
|
|
||||||
// state, as we must ensure that all the stores performed by the
|
|
||||||
// construction function are observable on this CPU after we exit.
|
|
||||||
atomic_thread_fence(memory_order_acquire);
|
|
||||||
return 0;
|
|
||||||
} else if (old_value == CONSTRUCTION_NOT_YET_STARTED) {
|
|
||||||
if (!atomic_compare_exchange_weak_explicit(
|
|
||||||
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITHOUT_WAITER,
|
|
||||||
memory_order_relaxed, memory_order_relaxed)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// The acquire fence may not be needed. But as described in section 3.3.2
|
|
||||||
// of the Itanium C++ ABI specification, it probably has to behave like
|
|
||||||
// the acquisition of a mutex, which needs an acquire fence.
|
|
||||||
atomic_thread_fence(memory_order_acquire);
|
|
||||||
return 1;
|
|
||||||
} else if (old_value == CONSTRUCTION_UNDERWAY_WITHOUT_WAITER) {
|
|
||||||
if (!atomic_compare_exchange_weak_explicit(
|
|
||||||
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITH_WAITER,
|
|
||||||
memory_order_relaxed, memory_order_relaxed)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nsync_futex_wait_(&gv->state, CONSTRUCTION_UNDERWAY_WITH_WAITER, 0, 0);
|
|
||||||
old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cxa_guard_release(union CxaGuardValue *gv) {
|
|
||||||
// Release fence is used to make all stores performed by the construction
|
|
||||||
// function visible in other threads.
|
|
||||||
int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_COMPLETE,
|
|
||||||
memory_order_release);
|
|
||||||
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
|
|
||||||
nsync_futex_wake_(&gv->state, INT_MAX, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cxa_guard_abort(union CxaGuardValue *gv) {
|
|
||||||
// Release fence is used to make all stores performed by the construction
|
|
||||||
// function visible in other threads.
|
|
||||||
int old_value = atomic_exchange_explicit(
|
|
||||||
&gv->state, CONSTRUCTION_NOT_YET_STARTED, memory_order_release);
|
|
||||||
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
|
|
||||||
nsync_futex_wake_(&gv->state, INT_MAX, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
||||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
|
||||||
│ │
|
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
|
||||||
│ above copyright notice and this permission notice appear in all copies. │
|
|
||||||
│ │
|
|
||||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
||||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
||||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
||||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
||||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
||||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
||||||
#include "libc/intrin/cxaatexit.internal.h"
|
|
||||||
|
|
||||||
int __cxa_thread_atexit(void *fun, void *arg, void *dso_symbol) {
|
|
||||||
return __cxa_thread_atexit_impl(fun, arg, dso_symbol);
|
|
||||||
}
|
|
|
@ -41,6 +41,7 @@ TEST_LIBC_THREAD_DIRECTDEPS = \
|
||||||
LIBC_THREAD \
|
LIBC_THREAD \
|
||||||
LIBC_TIME \
|
LIBC_TIME \
|
||||||
LIBC_X \
|
LIBC_X \
|
||||||
|
THIRD_PARTY_LIBCXXABI \
|
||||||
THIRD_PARTY_NSYNC \
|
THIRD_PARTY_NSYNC \
|
||||||
THIRD_PARTY_NSYNC_MEM
|
THIRD_PARTY_NSYNC_MEM
|
||||||
|
|
||||||
|
|
1
third_party/BUILD.mk
vendored
1
third_party/BUILD.mk
vendored
|
@ -17,6 +17,7 @@ o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/hiredis \
|
o/$(MODE)/third_party/hiredis \
|
||||||
o/$(MODE)/third_party/less \
|
o/$(MODE)/third_party/less \
|
||||||
o/$(MODE)/third_party/libcxx \
|
o/$(MODE)/third_party/libcxx \
|
||||||
|
o/$(MODE)/third_party/libcxxabi \
|
||||||
o/$(MODE)/third_party/libunwind \
|
o/$(MODE)/third_party/libunwind \
|
||||||
o/$(MODE)/third_party/linenoise \
|
o/$(MODE)/third_party/linenoise \
|
||||||
o/$(MODE)/third_party/lua \
|
o/$(MODE)/third_party/lua \
|
||||||
|
|
5
third_party/double-conversion/BUILD.mk
vendored
5
third_party/double-conversion/BUILD.mk
vendored
|
@ -31,10 +31,9 @@ THIRD_PARTY_DOUBLECONVERSION_A_CHECKS = \
|
||||||
|
|
||||||
THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS = \
|
THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS = \
|
||||||
LIBC_INTRIN \
|
LIBC_INTRIN \
|
||||||
LIBC_NEXGEN32E \
|
|
||||||
LIBC_RUNTIME \
|
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_TINYMATH
|
LIBC_TINYMATH \
|
||||||
|
THIRD_PARTY_LIBCXXABI
|
||||||
|
|
||||||
THIRD_PARTY_DOUBLECONVERSION_A_DEPS := \
|
THIRD_PARTY_DOUBLECONVERSION_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
14
third_party/libcxx/BUILD.mk
vendored
14
third_party/libcxx/BUILD.mk
vendored
|
@ -70,8 +70,8 @@ THIRD_PARTY_LIBCXX_A_HDRS = \
|
||||||
third_party/libcxx/deque \
|
third_party/libcxx/deque \
|
||||||
third_party/libcxx/errno.h \
|
third_party/libcxx/errno.h \
|
||||||
third_party/libcxx/exception \
|
third_party/libcxx/exception \
|
||||||
third_party/libcxx/exception_fallback.hh \
|
third_party/libcxx/exception_libcxxabi.hh \
|
||||||
third_party/libcxx/exception_pointer_unimplemented.hh \
|
third_party/libcxx/exception_pointer_cxxabi.hh \
|
||||||
third_party/libcxx/execution \
|
third_party/libcxx/execution \
|
||||||
third_party/libcxx/experimental/__config \
|
third_party/libcxx/experimental/__config \
|
||||||
third_party/libcxx/filesystem \
|
third_party/libcxx/filesystem \
|
||||||
|
@ -99,7 +99,6 @@ THIRD_PARTY_LIBCXX_A_HDRS = \
|
||||||
third_party/libcxx/memory \
|
third_party/libcxx/memory \
|
||||||
third_party/libcxx/mutex \
|
third_party/libcxx/mutex \
|
||||||
third_party/libcxx/new \
|
third_party/libcxx/new \
|
||||||
third_party/libcxx/new_handler_fallback.hh \
|
|
||||||
third_party/libcxx/numeric \
|
third_party/libcxx/numeric \
|
||||||
third_party/libcxx/optional \
|
third_party/libcxx/optional \
|
||||||
third_party/libcxx/ostream \
|
third_party/libcxx/ostream \
|
||||||
|
@ -200,7 +199,9 @@ THIRD_PARTY_LIBCXX_A_DIRECTDEPS = \
|
||||||
LIBC_THREAD \
|
LIBC_THREAD \
|
||||||
LIBC_TINYMATH \
|
LIBC_TINYMATH \
|
||||||
THIRD_PARTY_COMPILER_RT \
|
THIRD_PARTY_COMPILER_RT \
|
||||||
THIRD_PARTY_GDTOA
|
THIRD_PARTY_GDTOA \
|
||||||
|
THIRD_PARTY_LIBCXXABI \
|
||||||
|
THIRD_PARTY_LIBUNWIND
|
||||||
|
|
||||||
THIRD_PARTY_LIBCXX_A_DEPS := \
|
THIRD_PARTY_LIBCXX_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXX_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXX_A_DIRECTDEPS),$($(x))))
|
||||||
|
@ -217,7 +218,10 @@ $(THIRD_PARTY_LIBCXX_A).pkg: \
|
||||||
$(THIRD_PARTY_LIBCXX_A_OBJS): private \
|
$(THIRD_PARTY_LIBCXX_A_OBJS): private \
|
||||||
CXXFLAGS += \
|
CXXFLAGS += \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-fdata-sections
|
-fdata-sections \
|
||||||
|
-fexceptions \
|
||||||
|
-frtti \
|
||||||
|
-DLIBCXX_BUILDING_LIBCXXABI
|
||||||
|
|
||||||
THIRD_PARTY_LIBCXX_LIBS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)))
|
THIRD_PARTY_LIBCXX_LIBS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)))
|
||||||
THIRD_PARTY_LIBCXX_SRCS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)_SRCS))
|
THIRD_PARTY_LIBCXX_SRCS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
|
1
third_party/libcxx/__config
vendored
1
third_party/libcxx/__config
vendored
|
@ -12,7 +12,6 @@
|
||||||
#include "libc/isystem/features.h"
|
#include "libc/isystem/features.h"
|
||||||
|
|
||||||
#define _LIBCPP_ABI_UNSTABLE
|
#define _LIBCPP_ABI_UNSTABLE
|
||||||
#define _LIBCPP_NO_EXCEPTIONS
|
|
||||||
#define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
#define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
||||||
#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS
|
#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS
|
||||||
#define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
|
#define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
|
||||||
|
|
11
third_party/libcxx/exception.cc
vendored
11
third_party/libcxx/exception.cc
vendored
|
@ -11,6 +11,11 @@
|
||||||
#include "third_party/libcxx/new"
|
#include "third_party/libcxx/new"
|
||||||
#include "third_party/libcxx/typeinfo"
|
#include "third_party/libcxx/typeinfo"
|
||||||
|
|
||||||
#include "third_party/libcxx/atomic_support.hh"
|
#if defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
|
||||||
#include "third_party/libcxx/exception_fallback.hh"
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
#include "third_party/libcxx/exception_pointer_unimplemented.hh"
|
using namespace __cxxabiv1;
|
||||||
|
#define HAVE_DEPENDENT_EH_ABI 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception_libcxxabi.hh"
|
||||||
|
#include "third_party/libcxx/exception_pointer_cxxabi.hh"
|
||||||
|
|
111
third_party/libcxx/exception_fallback.hh
vendored
111
third_party/libcxx/exception_fallback.hh
vendored
|
@ -1,111 +0,0 @@
|
||||||
// -*- C++ -*-
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "third_party/libcxx/exception"
|
|
||||||
#include "third_party/libcxx/cstdio"
|
|
||||||
#include "third_party/libcxx/atomic_support.hh"
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
_LIBCPP_SAFE_STATIC static std::terminate_handler __terminate_handler;
|
|
||||||
|
|
||||||
#if _LIBCPP_STD_VER <= 14 || \
|
|
||||||
defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) || \
|
|
||||||
defined(_LIBCPP_BUILDING_LIBRARY)
|
|
||||||
_LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler;
|
|
||||||
// libcxxrt provides implementations of these functions itself.
|
|
||||||
unexpected_handler set_unexpected(unexpected_handler func) _NOEXCEPT {
|
|
||||||
return __libcpp_atomic_exchange(&__unexpected_handler, func);
|
|
||||||
}
|
|
||||||
unexpected_handler get_unexpected() _NOEXCEPT {
|
|
||||||
return __libcpp_atomic_load(&__unexpected_handler);
|
|
||||||
}
|
|
||||||
_LIBCPP_NORETURN
|
|
||||||
void unexpected() {
|
|
||||||
(*get_unexpected())();
|
|
||||||
// unexpected handler should not return
|
|
||||||
terminate();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
terminate_handler set_terminate(terminate_handler func) _NOEXCEPT {
|
|
||||||
return __libcpp_atomic_exchange(&__terminate_handler, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
terminate_handler get_terminate() _NOEXCEPT {
|
|
||||||
return __libcpp_atomic_load(&__terminate_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __EMSCRIPTEN__ // We provide this in JS
|
|
||||||
_LIBCPP_NORETURN
|
|
||||||
void terminate() _NOEXCEPT {
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
||||||
try {
|
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
||||||
(*get_terminate())();
|
|
||||||
// handler should not return
|
|
||||||
fprintf(stderr, "terminate_handler unexpectedly returned\n");
|
|
||||||
::abort();
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
||||||
} catch (...) {
|
|
||||||
// handler should not throw exception
|
|
||||||
fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
||||||
}
|
|
||||||
#endif // !__EMSCRIPTEN__
|
|
||||||
|
|
||||||
#if !defined(__EMSCRIPTEN__)
|
|
||||||
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
|
|
||||||
|
|
||||||
int uncaught_exceptions() _NOEXCEPT {
|
|
||||||
// #warning uncaught_exception not yet implemented
|
|
||||||
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
#endif // !__EMSCRIPTEN__
|
|
||||||
|
|
||||||
exception::~exception() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* exception::what() const _NOEXCEPT { return "std::exception"; }
|
|
||||||
|
|
||||||
bad_exception::~bad_exception() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* bad_exception::what() const _NOEXCEPT {
|
|
||||||
return "std::bad_exception";
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_alloc::bad_alloc() _NOEXCEPT {}
|
|
||||||
|
|
||||||
bad_alloc::~bad_alloc() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* bad_alloc::what() const _NOEXCEPT { return "std::bad_alloc"; }
|
|
||||||
|
|
||||||
bad_array_new_length::bad_array_new_length() _NOEXCEPT {}
|
|
||||||
|
|
||||||
bad_array_new_length::~bad_array_new_length() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* bad_array_new_length::what() const _NOEXCEPT {
|
|
||||||
return "bad_array_new_length";
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_cast::bad_cast() _NOEXCEPT {}
|
|
||||||
|
|
||||||
bad_typeid::bad_typeid() _NOEXCEPT {}
|
|
||||||
|
|
||||||
bad_cast::~bad_cast() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* bad_cast::what() const _NOEXCEPT { return "std::bad_cast"; }
|
|
||||||
|
|
||||||
bad_typeid::~bad_typeid() _NOEXCEPT {}
|
|
||||||
|
|
||||||
const char* bad_typeid::what() const _NOEXCEPT { return "std::bad_typeid"; }
|
|
||||||
|
|
||||||
} // namespace std
|
|
|
@ -7,20 +7,21 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "third_party/libcxx/__config"
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
#include "third_party/libcxx/new"
|
#include "third_party/libcxx/exception"
|
||||||
#include "third_party/libcxx/atomic_support.hh"
|
using namespace __cxxabiv1;
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
_LIBCPP_SAFE_STATIC static std::new_handler __new_handler;
|
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
|
||||||
|
|
||||||
new_handler set_new_handler(new_handler handler) _NOEXCEPT {
|
int uncaught_exceptions() _NOEXCEPT
|
||||||
return __libcpp_atomic_exchange(&__new_handler, handler);
|
{
|
||||||
}
|
# if _LIBCPPABI_VERSION > 1001
|
||||||
|
return __cxa_uncaught_exceptions();
|
||||||
new_handler get_new_handler() _NOEXCEPT {
|
# else
|
||||||
return __libcpp_atomic_load(&__new_handler);
|
return __cxa_uncaught_exception() ? 1 : 0;
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
73
third_party/libcxx/exception_pointer_cxxabi.hh
vendored
Normal file
73
third_party/libcxx/exception_pointer_cxxabi.hh
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
using namespace __cxxabiv1;
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
exception_ptr::~exception_ptr() _NOEXCEPT {
|
||||||
|
__cxa_decrement_exception_refcount(__ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
|
||||||
|
: __ptr_(other.__ptr_)
|
||||||
|
{
|
||||||
|
__cxa_increment_exception_refcount(__ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
|
||||||
|
{
|
||||||
|
if (__ptr_ != other.__ptr_)
|
||||||
|
{
|
||||||
|
__cxa_increment_exception_refcount(other.__ptr_);
|
||||||
|
__cxa_decrement_exception_refcount(__ptr_);
|
||||||
|
__ptr_ = other.__ptr_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_exception::nested_exception() _NOEXCEPT
|
||||||
|
: __ptr_(current_exception())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_exception::~nested_exception() _NOEXCEPT
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_NORETURN
|
||||||
|
void
|
||||||
|
nested_exception::rethrow_nested() const
|
||||||
|
{
|
||||||
|
if (__ptr_ == nullptr)
|
||||||
|
terminate();
|
||||||
|
rethrow_exception(__ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_ptr current_exception() _NOEXCEPT
|
||||||
|
{
|
||||||
|
// be nicer if there was a constructor that took a ptr, then
|
||||||
|
// this whole function would be just:
|
||||||
|
// return exception_ptr(__cxa_current_primary_exception());
|
||||||
|
exception_ptr ptr;
|
||||||
|
ptr.__ptr_ = __cxa_current_primary_exception();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_NORETURN
|
||||||
|
void rethrow_exception(exception_ptr p)
|
||||||
|
{
|
||||||
|
__cxa_rethrow_primary_exception(p.__ptr_);
|
||||||
|
// if p.__ptr_ is NULL, above returns so we terminate
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace std
|
|
@ -1,68 +0,0 @@
|
||||||
// -*- C++ -*-
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "third_party/libcxx/stdio.h"
|
|
||||||
#include "third_party/libcxx/stdlib.h"
|
|
||||||
#include "third_party/libcxx/exception"
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
exception_ptr::~exception_ptr() _NOEXCEPT {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
|
|
||||||
: __ptr_(other.__ptr_) {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
nested_exception::nested_exception() _NOEXCEPT : __ptr_(current_exception()) {}
|
|
||||||
|
|
||||||
#if !defined(__GLIBCXX__)
|
|
||||||
|
|
||||||
nested_exception::~nested_exception() _NOEXCEPT {}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_LIBCPP_NORETURN
|
|
||||||
void nested_exception::rethrow_nested() const {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
#if 0
|
|
||||||
if (__ptr_ == nullptr)
|
|
||||||
terminate();
|
|
||||||
rethrow_exception(__ptr_);
|
|
||||||
#endif // FIXME
|
|
||||||
}
|
|
||||||
|
|
||||||
exception_ptr current_exception() _NOEXCEPT {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_NORETURN
|
|
||||||
void rethrow_exception(exception_ptr p) {
|
|
||||||
// #warning exception_ptr not yet implemented
|
|
||||||
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
||||||
::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace std
|
|
2
third_party/libcxx/new.cc
vendored
2
third_party/libcxx/new.cc
vendored
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#include "third_party/libcxx/new"
|
#include "third_party/libcxx/new"
|
||||||
#include "third_party/libcxx/atomic_support.hh"
|
#include "third_party/libcxx/atomic_support.hh"
|
||||||
#include "third_party/libcxx/new_handler_fallback.hh"
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
|
|
112
third_party/libcxxabi/BUILD.mk
vendored
Normal file
112
third_party/libcxxabi/BUILD.mk
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||||
|
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
|
||||||
|
|
||||||
|
PKGS += THIRD_PARTY_LIBCXXABI
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_ARTIFACTS += THIRD_PARTY_LIBCXXABI_A
|
||||||
|
THIRD_PARTY_LIBCXXABI = $(THIRD_PARTY_LIBCXXABI_A_DEPS) $(THIRD_PARTY_LIBCXXABI_A)
|
||||||
|
THIRD_PARTY_LIBCXXABI_A = o/$(MODE)/third_party/libcxxabi/libcxxabi.a
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_INCS = \
|
||||||
|
third_party/libcxxabi/demangle/ItaniumNodes.def \
|
||||||
|
third_party/libcxxabi/aix_state_tab_eh.inc \
|
||||||
|
third_party/libcxxabi/cxa_exception.h \
|
||||||
|
third_party/libcxxabi/cxa_guard_impl.h \
|
||||||
|
third_party/libcxxabi/cxa_handlers.h
|
||||||
|
|
||||||
|
# TODO: Remove this aligned_alloc header when libcxx is updated
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_HDRS = \
|
||||||
|
third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h \
|
||||||
|
third_party/libcxxabi/include/__cxxabi_config.h \
|
||||||
|
third_party/libcxxabi/include/cxxabi.h \
|
||||||
|
third_party/libcxxabi/demangle/DemangleConfig.h \
|
||||||
|
third_party/libcxxabi/demangle/ItaniumDemangle.h \
|
||||||
|
third_party/libcxxabi/demangle/StringViewExtras.h \
|
||||||
|
third_party/libcxxabi/demangle/Utility.h \
|
||||||
|
third_party/libcxxabi/abort_message.h \
|
||||||
|
third_party/libcxxabi/fallback_malloc.h \
|
||||||
|
third_party/libcxxabi/private_typeinfo.h
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_SRCS_CC = \
|
||||||
|
third_party/libcxxabi/abort_message.cc \
|
||||||
|
third_party/libcxxabi/cxa_aux_runtime.cc \
|
||||||
|
third_party/libcxxabi/cxa_default_handlers.cc \
|
||||||
|
third_party/libcxxabi/cxa_demangle.cc \
|
||||||
|
third_party/libcxxabi/cxa_exception_storage.cc \
|
||||||
|
third_party/libcxxabi/cxa_exception.cc \
|
||||||
|
third_party/libcxxabi/cxa_guard.cc \
|
||||||
|
third_party/libcxxabi/cxa_handlers.cc \
|
||||||
|
third_party/libcxxabi/cxa_personality.cc \
|
||||||
|
third_party/libcxxabi/cxa_thread_atexit.cc \
|
||||||
|
third_party/libcxxabi/cxa_vector.cc \
|
||||||
|
third_party/libcxxabi/cxa_virtual.cc \
|
||||||
|
third_party/libcxxabi/fallback_malloc.cc \
|
||||||
|
third_party/libcxxabi/private_typeinfo.cc \
|
||||||
|
third_party/libcxxabi/stdlib_exception.cc \
|
||||||
|
third_party/libcxxabi/stdlib_new_delete.cc \
|
||||||
|
third_party/libcxxabi/stdlib_stdexcept.cc \
|
||||||
|
third_party/libcxxabi/stdlib_typeinfo.cc
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_SRCS = \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_SRCS_CC)
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_OBJS = \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_SRCS_CC:%.cc=o/$(MODE)/%.o)
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_CHECKS = \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A).pkg \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_HDRS:%=o/$(MODE)/%.okk)
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS = \
|
||||||
|
LIBC_CALLS \
|
||||||
|
LIBC_INTRIN \
|
||||||
|
LIBC_MEM \
|
||||||
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_RUNTIME \
|
||||||
|
LIBC_STDIO \
|
||||||
|
LIBC_STR \
|
||||||
|
LIBC_THREAD \
|
||||||
|
THIRD_PARTY_LIBUNWIND
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_A_DEPS := \
|
||||||
|
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A): \
|
||||||
|
third_party/libcxxabi/ \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A).pkg \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_OBJS)
|
||||||
|
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A).pkg: \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_OBJS) \
|
||||||
|
$(foreach x,$(THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
|
# TODO: Remove constinit hacks when we have C++20
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A_OBJS): private \
|
||||||
|
CXXFLAGS += \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fdata-sections \
|
||||||
|
-fexceptions \
|
||||||
|
-frtti \
|
||||||
|
-D_LIBCXXABI_BUILDING_LIBRARY \
|
||||||
|
-D_LIBCPP_BUILDING_LIBRARY \
|
||||||
|
-DHAVE___CXA_THREAD_ATEXIT_IMPL \
|
||||||
|
-D_LIBCPP_CONSTINIT=__constinit \
|
||||||
|
-Dconstinit=__constinit
|
||||||
|
|
||||||
|
# ttypeIndex is initialized and used only when native_old_exception is true.
|
||||||
|
# GCC does not seem to allow this.
|
||||||
|
o/$(MODE)/third_party/libcxxabi/cxa_personality.o: private \
|
||||||
|
CXXFLAGS += \
|
||||||
|
-Wno-error=maybe-uninitialized
|
||||||
|
|
||||||
|
THIRD_PARTY_LIBCXXABI_LIBS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)))
|
||||||
|
THIRD_PARTY_LIBCXXABI_SRCS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
THIRD_PARTY_LIBCXXABI_HDRS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_HDRS))
|
||||||
|
THIRD_PARTY_LIBCXXABI_INCS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_INCS))
|
||||||
|
THIRD_PARTY_LIBCXXABI_CHECKS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_CHECKS))
|
||||||
|
THIRD_PARTY_LIBCXXABI_OBJS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_OBJS))
|
||||||
|
|
||||||
|
.PHONY: o/$(MODE)/third_party/libcxxabi
|
||||||
|
o/$(MODE)/third_party/libcxxabi: \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_CHECKS) \
|
||||||
|
$(THIRD_PARTY_LIBCXXABI_A)
|
71
third_party/libcxxabi/CREDITS.TXT
vendored
Normal file
71
third_party/libcxxabi/CREDITS.TXT
vendored
Normal file
|
@ -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: jroelofs@jroelofs.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
|
||||||
|
|
311
third_party/libcxxabi/LICENSE.TXT
vendored
Normal file
311
third_party/libcxxabi/LICENSE.TXT
vendored
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
==============================================================================
|
||||||
|
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||||
|
|
||||||
|
As an exception, if, as a result of your compiling your source code, portions
|
||||||
|
of this Software are embedded into an Object form of such source code, you
|
||||||
|
may redistribute such embedded portions in such Object form without complying
|
||||||
|
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||||
|
|
||||||
|
In addition, if you combine or link compiled forms of this Software with
|
||||||
|
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||||
|
court of competent jurisdiction determines that the patent provision (Section
|
||||||
|
3), the indemnity provision (Section 9) or other Section of the License
|
||||||
|
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||||
|
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||||
|
the License, but only in their entirety and only with respect to the Combined
|
||||||
|
Software.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Software from third parties included in the LLVM Project:
|
||||||
|
==============================================================================
|
||||||
|
The LLVM Project contains third party software which is under different license
|
||||||
|
terms. All such code will be identified clearly using at least one of two
|
||||||
|
mechanisms:
|
||||||
|
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||||
|
`LICENSE` file at the top containing the specific license and restrictions
|
||||||
|
which apply to that software, or
|
||||||
|
2) It will contain specific license and restriction terms at the top of every
|
||||||
|
file.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
The libc++abi library is dual licensed under both the University of Illinois
|
||||||
|
"BSD-Like" license and the MIT license. As a user of this code you may choose
|
||||||
|
to use it under either license. As a contributor, you agree to allow your code
|
||||||
|
to be used under both.
|
||||||
|
|
||||||
|
Full text of the relevant licenses is included below.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
University of Illinois/NCSA
|
||||||
|
Open Source License
|
||||||
|
|
||||||
|
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Developed by:
|
||||||
|
|
||||||
|
LLVM Team
|
||||||
|
|
||||||
|
University of Illinois at Urbana-Champaign
|
||||||
|
|
||||||
|
http://llvm.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal with
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimers.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimers in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the names of the LLVM Team, University of Illinois at
|
||||||
|
Urbana-Champaign, nor the names of its contributors may be used to
|
||||||
|
endorse or promote products derived from this Software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
18
third_party/libcxxabi/README.cosmo
vendored
Normal file
18
third_party/libcxxabi/README.cosmo
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
DESCRIPTION
|
||||||
|
|
||||||
|
libcxxabi - C++ Standard Library Support
|
||||||
|
|
||||||
|
ORIGIN
|
||||||
|
|
||||||
|
Obtained from the LLVM monorepo, release 17.0.6.
|
||||||
|
|
||||||
|
https://github.com/llvm/llvm-project/tree/llvmorg-17.0.6/libunwind
|
||||||
|
commit 6009708b4367171ccdbf4b5905cb6a803753fe18
|
||||||
|
Author: Tobias Hieta <tobias@hieta.se>
|
||||||
|
Date: Tue, 28 Nov 2023 09:52:28 +0100
|
||||||
|
|
||||||
|
LOCAL CHANGES
|
||||||
|
|
||||||
|
- Add <__memory/aligned_alloc.h> (contains a few inline functions) from
|
||||||
|
upstream libcxx.
|
||||||
|
- Enable __cxa_thread_atexit for Cosmopolitan.
|
79
third_party/libcxxabi/abort_message.cc
vendored
Normal file
79
third_party/libcxxabi/abort_message.cc
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "libc/isystem/stdlib.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/isystem/stdarg.h"
|
||||||
|
#include "third_party/libcxxabi/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__
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && __has_include(<CrashReporterClient.h>)
|
||||||
|
# include <CrashReporterClient.h>
|
||||||
|
# define _LIBCXXABI_USE_CRASHREPORTER_CLIENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void abort_message(const char* format, ...)
|
||||||
|
{
|
||||||
|
// Write message to stderr. We do this before formatting into a
|
||||||
|
// variable-size buffer so that we still get some information if
|
||||||
|
// formatting into the variable-sized buffer fails.
|
||||||
|
#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "libc++abi: ");
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
vfprintf(stderr, format, list);
|
||||||
|
va_end(list);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Format the arguments into an allocated buffer. We leak the buffer on
|
||||||
|
// purpose, since we're about to abort() anyway.
|
||||||
|
#if defined(_LIBCXXABI_USE_CRASHREPORTER_CLIENT)
|
||||||
|
char* buffer;
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
vasprintf(&buffer, format, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
CRSetCrashLogMessage(buffer);
|
||||||
|
#elif defined(__BIONIC__)
|
||||||
|
char* buffer;
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
vasprintf(&buffer, format, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
# 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();
|
||||||
|
}
|
17
third_party/libcxxabi/abort_message.h
vendored
Normal file
17
third_party/libcxxabi/abort_message.h
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __ABORT_MESSAGE_H_
|
||||||
|
#define __ABORT_MESSAGE_H_
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
|
||||||
|
extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
|
||||||
|
abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||||
|
|
||||||
|
#endif
|
745
third_party/libcxxabi/aix_state_tab_eh.inc
vendored
Normal file
745
third_party/libcxxabi/aix_state_tab_eh.inc
vendored
Normal file
|
@ -0,0 +1,745 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the personality and helper functions for the state
|
||||||
|
// table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/debug.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
The legacy IBM xlC and xlclang++ compilers use the state table for EH
|
||||||
|
instead of the range table. Destructors, or addresses of the possible catch
|
||||||
|
sites or cleanup code are specified in the state table which is a finite
|
||||||
|
state machine (FSM). Each function that has a state table also has an
|
||||||
|
autolocal state variable. The state variable represents the current state
|
||||||
|
of the function for EH and is found through the traceback table of the
|
||||||
|
function during unwinding, which is located at the end of each function.
|
||||||
|
The FSM is an array of state entries. Each state entry has the following
|
||||||
|
fields:
|
||||||
|
|
||||||
|
* offset/address/pointer - the offset used to locate the object, or the
|
||||||
|
address of a global object, or the address of the next state if it is an
|
||||||
|
old conditional state change entry;
|
||||||
|
* dtor/landing pad - address of the destructor function to invoke,
|
||||||
|
or address of the catch block or cleanup code in the user code to branch to;
|
||||||
|
* element count/action flag - the number of elements or the flag for actions;
|
||||||
|
* element size - if the object is an array this is the size of one element
|
||||||
|
of the array;
|
||||||
|
* flags - flags used to control how fields in the entry are interpreted;
|
||||||
|
* next state - the state to execute next after the action for this state is
|
||||||
|
performed. The value of zero indicates the end of the state for this
|
||||||
|
function.
|
||||||
|
|
||||||
|
The following is the description of 'element count/action flag' field.
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
| value | description | action |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
|
||||||
|
| | | each member of the array |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| 1, 0 | object is a scalar | calls dtor for the object |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| -1 | begin catch | branches to the handler which performes |
|
||||||
|
| | | catch-match. If there is no catch that |
|
||||||
|
| | | matches the exception it will be rethrown |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| -2 | end catch | ends current catch block and continues |
|
||||||
|
| | | attempting to catch the exception |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| -3 | delete the object | calls the delete function of the object |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
| -4 | cleanup label | branches to the user code for cleaning up |
|
||||||
|
+-------+------------------------+--------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Macros for debugging the state table parsing.
|
||||||
|
#ifdef NDEBUG
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB(msg, ...)
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB0(msg)
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB1(msg)
|
||||||
|
# define _LIBCXXABI_TRACING_STATETAB 0
|
||||||
|
#else
|
||||||
|
static bool state_tab_dbg() {
|
||||||
|
static bool checked = false;
|
||||||
|
static bool log = false;
|
||||||
|
if (!checked) {
|
||||||
|
log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
|
||||||
|
do { \
|
||||||
|
if (state_tab_dbg()) \
|
||||||
|
fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB0(msg) \
|
||||||
|
do { \
|
||||||
|
if (state_tab_dbg()) \
|
||||||
|
fprintf(stderr, "libcxxabi: " msg); \
|
||||||
|
} while (0)
|
||||||
|
# define _LIBCXXABI_TRACE_STATETAB1(msg) \
|
||||||
|
do { \
|
||||||
|
if (state_tab_dbg()) \
|
||||||
|
fprintf(stderr, msg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
namespace __state_table_eh {
|
||||||
|
|
||||||
|
using destruct_f = void (*)(void*);
|
||||||
|
|
||||||
|
// Definition of flags for the state table entry field 'action flag'.
|
||||||
|
enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
|
||||||
|
|
||||||
|
// Definition of flags for the state table entry field 'flags'.
|
||||||
|
enum FSMEntryFlag : int16_t {
|
||||||
|
indirect = 0x100, // Object was thrown from a function where
|
||||||
|
// the return value optimization was used.
|
||||||
|
oldConditionalStateChange = 0x400, // State table entry is an indirect state
|
||||||
|
// change, dereference the address in
|
||||||
|
// offset as int for the target state.
|
||||||
|
// This is deprecated. This indicates
|
||||||
|
// the address is direct. (static local).
|
||||||
|
conditionalStateChange = 0x800, // State table entry is an indirect state
|
||||||
|
// change, dereference the address in
|
||||||
|
// offset as int for the target state.
|
||||||
|
// The temporary is an automatic. State
|
||||||
|
// change is used in cases such as
|
||||||
|
// (b?(T1(),foo()):(T2(),foo())),throw 42;
|
||||||
|
// which causes a conditional state change
|
||||||
|
// so that we know if T1 or T2 need to be
|
||||||
|
// destroyed.
|
||||||
|
thisFlag = 0x01, // The address of the object for the
|
||||||
|
// cleanup action is based on the
|
||||||
|
// StateVariable::thisValue.
|
||||||
|
vBaseFlag = 0x02, // The object is of a virtual base class.
|
||||||
|
globalObj = 0x04 // FSMEntry::address is the address of
|
||||||
|
// a global object.
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// The finite state machine to be walked.
|
||||||
|
struct FSMEntry {
|
||||||
|
union {
|
||||||
|
// Offset of the object within its stack frame or containing object.
|
||||||
|
intptr_t offset;
|
||||||
|
// Address of a global object.
|
||||||
|
intptr_t address;
|
||||||
|
// Address of the next state if it is an old conditional state change entry.
|
||||||
|
intptr_t nextStatePtr;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
// Address of the destructor function.
|
||||||
|
void (*destructor)(void*, size_t);
|
||||||
|
// The address of the catch block or cleanup code.
|
||||||
|
void* landingPad;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
// The flag for actions (when the value is negative).
|
||||||
|
FSMEntryCount actionFlag;
|
||||||
|
// The element count (when the value is positive or zero).
|
||||||
|
size_t elementCount;
|
||||||
|
};
|
||||||
|
size_t elemSize;
|
||||||
|
FSMEntryFlag flags;
|
||||||
|
uint16_t nextState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSM {
|
||||||
|
uint32_t magic; // Magic number of the state table.
|
||||||
|
int32_t numberOfStates;
|
||||||
|
FSMEntry table[1]; // Actually table[numberOfStates].
|
||||||
|
};
|
||||||
|
|
||||||
|
// The state variable on the stack.
|
||||||
|
struct StateVariable {
|
||||||
|
int32_t state;
|
||||||
|
struct FSM* table;
|
||||||
|
intptr_t thisValue;
|
||||||
|
int32_t ignoreVBasePtrs;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// State table magic number
|
||||||
|
enum FSMMagic : uint32_t {
|
||||||
|
number = 0xbeefdead, // State table generated by xlC compiler.
|
||||||
|
number2 = 0xbeeedead, // State table generated by early version xlC compiler.
|
||||||
|
number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
|
||||||
|
// virtual bases, don't delete object.
|
||||||
|
|
||||||
|
static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
|
||||||
|
try {
|
||||||
|
if (fsmEntry->elementCount == 1) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
|
||||||
|
(*fsmEntry->destructor)(addr, dtorArgument);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
|
||||||
|
} else {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
|
||||||
|
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
|
||||||
|
reinterpret_cast<destruct_f>(fsmEntry->destructor));
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
|
||||||
|
char* objectAddress = *reinterpret_cast<char**>(addr);
|
||||||
|
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
|
||||||
|
reinterpret_cast<void*>(fsmEntry));
|
||||||
|
try {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
|
||||||
|
// 'destructor' holds a function pointer to delete().
|
||||||
|
(*fsmEntry->destructor)(objectAddress, fsmEntry->elemSize);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
|
||||||
|
} catch (...) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the frame address of the current function from its traceback table
|
||||||
|
// which is at the end of each function.
|
||||||
|
static uintptr_t get_frame_addr(_Unwind_Context* context) {
|
||||||
|
int framePointerReg = 1; // default frame pointer == SP.
|
||||||
|
uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
|
||||||
|
|
||||||
|
// Keep looking forward until a word of 0 is found. The traceback
|
||||||
|
// table starts at the following word.
|
||||||
|
while (*p)
|
||||||
|
++p;
|
||||||
|
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
||||||
|
|
||||||
|
p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
|
||||||
|
|
||||||
|
// Skip field parminfo if it exists.
|
||||||
|
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// Skip field tb_offset if it exists.
|
||||||
|
if (TBTable->tb.has_tboff)
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// Skip field hand_mask if it exists.
|
||||||
|
if (TBTable->tb.int_hndl)
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// Skip fields ctl_info and ctl_info_disp if they exist.
|
||||||
|
if (TBTable->tb.has_ctl)
|
||||||
|
p += 1 + *p;
|
||||||
|
|
||||||
|
// Skip fields name_len and name if exist.
|
||||||
|
if (TBTable->tb.name_present) {
|
||||||
|
const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
|
||||||
|
p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TBTable->tb.uses_alloca)
|
||||||
|
framePointerReg = *reinterpret_cast<char*>(p);
|
||||||
|
|
||||||
|
return _Unwind_GetGR(context, framePointerReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the object address from the FSM entry.
|
||||||
|
static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
|
||||||
|
void* addr;
|
||||||
|
if (fsmEntry->flags & FSMEntryFlag::globalObj) {
|
||||||
|
addr = reinterpret_cast<void*>(fsmEntry->address);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
|
||||||
|
} else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
|
||||||
|
addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
|
||||||
|
"state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
|
||||||
|
fsmEntry->offset, state->thisValue, addr);
|
||||||
|
} else if (fsmEntry->flags & FSMEntryFlag::indirect) {
|
||||||
|
addr = reinterpret_cast<void*>(
|
||||||
|
*reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
|
||||||
|
addr, fsmEntry->offset);
|
||||||
|
} else {
|
||||||
|
addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
|
||||||
|
addr);
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scan_state_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.
|
||||||
|
// Client error
|
||||||
|
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_LIBCXXABI_TRACING_STATETAB) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1("\n");
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
|
||||||
|
|
||||||
|
if (_UA_SEARCH_PHASE & actions)
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
|
||||||
|
if (_UA_CLEANUP_PHASE & actions)
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
|
||||||
|
if (_UA_HANDLER_FRAME & actions)
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
|
||||||
|
if (_UA_FORCE_UNWIND & actions)
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
|
||||||
|
_LIBCXXABI_TRACE_STATETAB1(")\n");
|
||||||
|
_LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
|
||||||
|
reinterpret_cast<void*>(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start scan by getting state table address.
|
||||||
|
StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
|
||||||
|
if (state->state <= 0) {
|
||||||
|
// The state is not correct - give up on this routine.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
|
||||||
|
results.reason = _URC_CONTINUE_UNWIND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Parse the state table.
|
||||||
|
FSM* const fsm = state->table;
|
||||||
|
FSMEntry* currFSMEntry;
|
||||||
|
|
||||||
|
if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
|
||||||
|
// Something is wrong with the state table we found.
|
||||||
|
if (_UA_SEARCH_PHASE & actions) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
|
||||||
|
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||||
|
} else if (_UA_CLEANUP_PHASE & actions) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
|
||||||
|
results.reason = _URC_FATAL_PHASE2_ERROR;
|
||||||
|
} else {
|
||||||
|
// We should never get here.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
|
||||||
|
results.reason = _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_LIBCXXABI_TRACING_STATETAB) {
|
||||||
|
// Print the state table for debugging purposes.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
|
||||||
|
// Print out the FSM table.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
|
||||||
|
"count", "el_size", "flags", "next");
|
||||||
|
for (int i = 0; i < fsm->numberOfStates; i++) {
|
||||||
|
currFSMEntry = &fsm->table[i];
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
|
||||||
|
"%7ld %#7x %7d\n",
|
||||||
|
reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
|
||||||
|
reinterpret_cast<void*>(currFSMEntry->destructor),
|
||||||
|
currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
|
||||||
|
currFSMEntry->nextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_UA_SEARCH_PHASE & actions) {
|
||||||
|
// Start walking the state table. Use a local copy of state->state so when
|
||||||
|
// we return from search phase we don't change the state number.
|
||||||
|
int currState = state->state;
|
||||||
|
|
||||||
|
while (currState > 0) {
|
||||||
|
currFSMEntry = &fsm->table[currState - 1];
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
|
||||||
|
|
||||||
|
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
|
||||||
|
// Found a catch handler.
|
||||||
|
if (fsm->magic == FSMMagic::number) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
|
||||||
|
// xlC catch handlers cannot be entered because they use a
|
||||||
|
// proprietary EH runtime that is not interoperable.
|
||||||
|
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// xlclang++ compiled frames use CXA-abi EH calls and any catch
|
||||||
|
// block will include a catch(...) block so it is safe to assume that
|
||||||
|
// the handler is found without checking the catch match. The
|
||||||
|
// catch(...) block will rethrow the exception if there isn't a
|
||||||
|
// match.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
|
||||||
|
results.reason = _URC_HANDLER_FOUND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
|
||||||
|
results.reason = _URC_HANDLER_FOUND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
||||||
|
// Deprecated conditional expression.
|
||||||
|
currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
||||||
|
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
||||||
|
currFSMEntry->nextStatePtr, currState);
|
||||||
|
continue; // We are done this iteration of the loop, since
|
||||||
|
// we changed a state.
|
||||||
|
}
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
||||||
|
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||||
|
currState = *reinterpret_cast<int*>(addr);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
||||||
|
"addr(%p), set state=%d\n", addr, currState);
|
||||||
|
continue; // We are done this iteration of the loop, since we
|
||||||
|
// changed the state.
|
||||||
|
}
|
||||||
|
// Go to the next state.
|
||||||
|
currState = currFSMEntry->nextState;
|
||||||
|
}
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
|
||||||
|
results.reason = _URC_CONTINUE_UNWIND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_UA_CLEANUP_PHASE & actions) {
|
||||||
|
// Start walking the state table.
|
||||||
|
while (state->state > 0) {
|
||||||
|
currFSMEntry = &fsm->table[state->state - 1];
|
||||||
|
|
||||||
|
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
// Perform action according to the currFSMEntry->actionFlag,
|
||||||
|
// except when flag is FSMEntryFlag::conditionalStateChange or
|
||||||
|
// FSMEntryFlag::oldConditionalStateChange.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
||||||
|
state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
||||||
|
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
||||||
|
currFSMEntry->nextStatePtr, state->state);
|
||||||
|
continue; // We are done with this iteration of the loop, since we changed a state.
|
||||||
|
}
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
||||||
|
// A conditional state table entry holds the address of a local
|
||||||
|
// that holds the next state.
|
||||||
|
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||||
|
state->state = *reinterpret_cast<int*>(addr);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
||||||
|
"addr(%p), set state=%d\n", addr, state->state);
|
||||||
|
continue; // We are done with this iteration of the loop, since we changed a state.
|
||||||
|
}
|
||||||
|
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
|
||||||
|
currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
|
||||||
|
|
||||||
|
_LIBCXXABI_TRACE_STATETAB(
|
||||||
|
"FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
|
||||||
|
(currFSMEntry->actionFlag == FSMEntryCount::beginCatch
|
||||||
|
? "beginCatch"
|
||||||
|
: (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
|
||||||
|
currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
|
||||||
|
|
||||||
|
state->state = currFSMEntry->nextState;
|
||||||
|
results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
|
||||||
|
results.reason = _URC_HANDLER_FOUND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currFSMEntry->elementCount > 0) {
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
|
||||||
|
} else {
|
||||||
|
// We need to invoke the virtual base destructor. This must be
|
||||||
|
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
||||||
|
// generates inline cleanup code rather than specifying
|
||||||
|
// the destructor via the state table.
|
||||||
|
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||||
|
|
||||||
|
// An extra indirect to get to the object according to the object
|
||||||
|
// model used by the xlC compiler.
|
||||||
|
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
|
||||||
|
invoke_destructor(currFSMEntry, addr);
|
||||||
|
}
|
||||||
|
} else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
|
||||||
|
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||||
|
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
|
||||||
|
// We need to invoke the virtual base delete function. This must be
|
||||||
|
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
||||||
|
// generates inline cleanup code rather than specifying
|
||||||
|
// the delete function via the state table.
|
||||||
|
|
||||||
|
// An extra indirect to get to the object according to the object
|
||||||
|
// model used by the xlC compiler.
|
||||||
|
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
||||||
|
}
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
|
||||||
|
invoke_delete(currFSMEntry, addr);
|
||||||
|
} else {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
|
||||||
|
currFSMEntry->elementCount);
|
||||||
|
} // End of action switching.
|
||||||
|
|
||||||
|
// Go to next state.
|
||||||
|
state->state = currFSMEntry->nextState;
|
||||||
|
}
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
|
||||||
|
results.reason = _URC_CONTINUE_UNWIND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
|
||||||
|
// It is possible that no state table entry specify how to handle
|
||||||
|
// this exception. By spec, terminate it immediately.
|
||||||
|
call_terminate(native_exception, unwind_exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Personality routine for EH using the state table.
|
||||||
|
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
|
||||||
|
__xlcxx_personality_v0(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;
|
||||||
|
scan_state_tab(results, actions, native_exception, unwind_exception, context);
|
||||||
|
if (actions & _UA_SEARCH_PHASE) {
|
||||||
|
// Phase 1 search: All we're looking for in phase 1 is a handler that
|
||||||
|
// halts unwinding
|
||||||
|
return results.reason;
|
||||||
|
}
|
||||||
|
if (actions & _UA_CLEANUP_PHASE) {
|
||||||
|
// Phase 2 cleanup:
|
||||||
|
if (results.reason == _URC_HANDLER_FOUND) {
|
||||||
|
// Store the address of unwind_exception in the stack field
|
||||||
|
// reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
|
||||||
|
// the caller of the function containing the landing pad (within the link
|
||||||
|
// area for the call to the latter) for __xlc_exception_handle()
|
||||||
|
// to retrieve when it is called by the landing pad.
|
||||||
|
uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
|
||||||
|
uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
|
||||||
|
callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n",
|
||||||
|
reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
|
||||||
|
// Jump to the handler.
|
||||||
|
_Unwind_SetIP(context, results.landingPad);
|
||||||
|
return _URC_INSTALL_CONTEXT;
|
||||||
|
}
|
||||||
|
// Did not find a handler. Return the results of the scan. Normally
|
||||||
|
// _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
|
||||||
|
return results.reason;
|
||||||
|
}
|
||||||
|
// We were called improperly: neither a phase 1 or phase 2 search.
|
||||||
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
} // namespace __state_table_eh
|
||||||
|
|
||||||
|
// The following are EH helper functions for xlclang++ compiled code.
|
||||||
|
|
||||||
|
// __xlc_catch_matchv2
|
||||||
|
// Check whether the thrown object matches the catch handler's exception
|
||||||
|
// declaration. If there is a match, the function returns true with adjusted
|
||||||
|
// address of the thrown object. Otherwise, returns false.
|
||||||
|
_LIBCXXABI_FUNC_VIS bool
|
||||||
|
__xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
|
||||||
|
|
||||||
|
if (!__isOurExceptionClass(exceptionObject)) {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__cxa_exception* exceptionHeader = 0;
|
||||||
|
|
||||||
|
if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
|
||||||
|
// Walk to the __cxa_dependent_exception primary exception for the
|
||||||
|
// exception object and its type_info.
|
||||||
|
__cxa_dependent_exception* dependentExceptionHeader =
|
||||||
|
reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
|
||||||
|
exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
|
||||||
|
reinterpret_cast<void*>(exceptionObject),
|
||||||
|
reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
|
||||||
|
exceptionObject = &exceptionHeader->unwindHeader;
|
||||||
|
} else {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
|
||||||
|
exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
|
||||||
|
std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
|
||||||
|
|
||||||
|
// Get the type info for the thrown type and this catch clause and
|
||||||
|
// see if the catch caluse can catch that type.
|
||||||
|
|
||||||
|
__cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
|
||||||
|
__cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
|
||||||
|
reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
|
||||||
|
throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
|
||||||
|
if (catchType->can_catch(throwType, thrownObject)) {
|
||||||
|
exceptionHeader->adjustedPtr = thrownObject;
|
||||||
|
obj = thrownObject;
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("No match\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// __xlc_throw_badexception
|
||||||
|
// This function is for xlclang++. It allocates and throws a bad_exception.
|
||||||
|
// During unwinding for this bad_exception, the previous exception which is
|
||||||
|
// not matching the throw spec will be cleaned up. Thus having the same
|
||||||
|
// effect as replace the top most exception (which is bad) with a bad_exception.
|
||||||
|
_LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
|
||||||
|
void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
|
||||||
|
__cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip_non_cxx_eh_aware_frames
|
||||||
|
// This function skips non-C++ EH aware stack frames by unwinding from the
|
||||||
|
// stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame
|
||||||
|
// found. 'Pc' is an instruction address inside the function that owns the
|
||||||
|
// stack frame pointed to by 'Sp'.
|
||||||
|
static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) {
|
||||||
|
uint32_t* currentPc = Pc;
|
||||||
|
uintptr_t* currentStack = Sp;
|
||||||
|
|
||||||
|
// Loop until a C++ EH aware frame is found or the return address is 0,
|
||||||
|
// which is the return address of the startup function '__start'.
|
||||||
|
while (currentPc != 0) {
|
||||||
|
uint32_t* p = currentPc;
|
||||||
|
|
||||||
|
// Keep looking forward until a word of 0 is found. The traceback
|
||||||
|
// table starts at the following word.
|
||||||
|
while (*p)
|
||||||
|
++p;
|
||||||
|
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
||||||
|
|
||||||
|
// A stack frame with a C++ state table is C++ EH aware.
|
||||||
|
if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl)
|
||||||
|
return currentStack;
|
||||||
|
|
||||||
|
// Move up one stack frame.
|
||||||
|
currentStack = reinterpret_cast<uintptr_t*>(currentStack[0]);
|
||||||
|
// Get the value of the LR (saved, prior to incrementing the SP, by the
|
||||||
|
// prolog of the function just inspected) from the frame.
|
||||||
|
currentPc = reinterpret_cast<uint32_t*>(currentStack[2]);
|
||||||
|
}
|
||||||
|
// This should not happen.
|
||||||
|
_LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// __xlc_exception_handle
|
||||||
|
// This function is for xlclang++. It returns the address of the exception
|
||||||
|
// object stored in the reserved field in the stack of the caller of the
|
||||||
|
// function that calls __xlc_exception_handle() (within the link area for the
|
||||||
|
// call to the latter). The address is stored by the personality routine for
|
||||||
|
// xlclang++ compiled code. If __xlc_exception_handle() is called by
|
||||||
|
// non-C++ EH aware functions, their frames are skipped until a C++ EH aware
|
||||||
|
// frame is found.
|
||||||
|
// Note: make sure __xlc_excpetion_handle() is a non-leaf function. Currently
|
||||||
|
// it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort().
|
||||||
|
_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
|
||||||
|
// Get the SP of this function, i.e., __xlc_exception_handle().
|
||||||
|
uintptr_t* lastStack = reinterpret_cast<uintptr_t*>(__builtin_frame_address(0));
|
||||||
|
// Move one frame up to the frame of the caller of __xlc_exception_handle().
|
||||||
|
lastStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
|
||||||
|
// Get the return address of this function, i.e., __xlc_exception_handle().
|
||||||
|
uint32_t* returnAddress = reinterpret_cast<uint32_t*>(__builtin_return_address(0));
|
||||||
|
|
||||||
|
// Skip non-C++ EH aware frames and get the first C++ EH aware frame.
|
||||||
|
uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack);
|
||||||
|
|
||||||
|
// Get the SP of the caller of the C++ EH aware caller.
|
||||||
|
callerStack = reinterpret_cast<uintptr_t*>(callerStack[0]);
|
||||||
|
// Retrieve the exception object in the stack slot saved by the personality.
|
||||||
|
uintptr_t exceptionObject = callerStack[3];
|
||||||
|
_LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n",
|
||||||
|
reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack));
|
||||||
|
return exceptionObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xlclang++ may generate calls to __Deleted_Virtual.
|
||||||
|
_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
|
||||||
|
|
||||||
|
// __catchThrownException is called during AIX library initialization and
|
||||||
|
// termination to handle exceptions. An implementation is also provided in
|
||||||
|
// libC.a(shrcore.o). This implementation is provided for applications that
|
||||||
|
// link with -lc++ (the xlclang++ or ibm-clang++ link default.)
|
||||||
|
_LIBCXXABI_FUNC_VIS int
|
||||||
|
__catchThrownException(void (*cdfunc)(void), // function which may fail
|
||||||
|
void (*cleanup)(void*), // cleanup function
|
||||||
|
void* cleanuparg, // parameter to cleanup function
|
||||||
|
int action) { // control exception throwing and termination
|
||||||
|
enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
|
||||||
|
if (!cdfunc)
|
||||||
|
return 0;
|
||||||
|
if (action == Action::Rethrow && !cleanup) {
|
||||||
|
// No cleanup and rethrow is effectively no-op.
|
||||||
|
// Avoid the catch handler when possible to allow exceptions generated
|
||||||
|
// from xlC binaries to flow through.
|
||||||
|
(*cdfunc)();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
(*cdfunc)();
|
||||||
|
} catch (...) {
|
||||||
|
if (action == Action::Terminate)
|
||||||
|
std::terminate();
|
||||||
|
if (cleanup)
|
||||||
|
(*cleanup)(cleanuparg);
|
||||||
|
if (action == Action::Rethrow)
|
||||||
|
throw;
|
||||||
|
assert(action == Action::None);
|
||||||
|
return -1; // FAILED
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
} // __cxxabiv1
|
44
third_party/libcxxabi/cxa_aux_runtime.cc
vendored
Normal file
44
third_party/libcxxabi/cxa_aux_runtime.cc
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the "Auxiliary Runtime APIs"
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-aux
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
#include "third_party/libcxx/new"
|
||||||
|
#include "third_party/libcxx/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
|
141
third_party/libcxxabi/cxa_default_handlers.cc
vendored
Normal file
141
third_party/libcxxabi/cxa_default_handlers.cc
vendored
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the default terminate_handler, unexpected_handler and
|
||||||
|
// new_handler.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
#include "third_party/libcxx/memory"
|
||||||
|
#include "third_party/libcxx/stdlib.h"
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxxabi/cxa_handlers.h"
|
||||||
|
#include "third_party/libcxxabi/cxa_exception.h"
|
||||||
|
#include "third_party/libcxxabi/private_typeinfo.h"
|
||||||
|
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
|
||||||
|
|
||||||
|
#if !defined(LIBCXXABI_SILENT_TERMINATE)
|
||||||
|
|
||||||
|
static constinit const char* cause = "uncaught";
|
||||||
|
|
||||||
|
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
// Demangle the given string, or return the string as-is in case of an error.
|
||||||
|
static std::unique_ptr<char const, void (*)(char const*)> demangle(char const* str)
|
||||||
|
{
|
||||||
|
#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
|
||||||
|
if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
|
||||||
|
return {result, [](char const* p) { std::free(const_cast<char*>(p)); }};
|
||||||
|
#endif
|
||||||
|
return {str, [](char const*) { /* nothing to free */ }};
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
static void demangling_terminate_handler()
|
||||||
|
{
|
||||||
|
using namespace __cxxabiv1;
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||||
|
|
||||||
|
// If there is no uncaught exception, just note that we're terminating
|
||||||
|
if (!globals)
|
||||||
|
abort_message("terminating");
|
||||||
|
|
||||||
|
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||||
|
if (!exception_header)
|
||||||
|
abort_message("terminating");
|
||||||
|
|
||||||
|
_Unwind_Exception* unwind_exception =
|
||||||
|
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
|
||||||
|
|
||||||
|
// If we're terminating due to a foreign exception
|
||||||
|
if (!__isOurExceptionClass(unwind_exception))
|
||||||
|
abort_message("terminating due to %s foreign exception", cause);
|
||||||
|
|
||||||
|
void* thrown_object =
|
||||||
|
__getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
|
||||||
|
((__cxa_dependent_exception*)exception_header)->primaryException :
|
||||||
|
exception_header + 1;
|
||||||
|
const __shim_type_info* thrown_type =
|
||||||
|
static_cast<const __shim_type_info*>(exception_header->exceptionType);
|
||||||
|
auto name = demangle(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 due to %s exception of type %s: %s", cause, name.get(), e->what());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Else just note that we're terminating due to an exception
|
||||||
|
abort_message("terminating due to %s exception of type %s", cause, name.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // !_LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
__attribute__((noreturn))
|
||||||
|
static void demangling_terminate_handler()
|
||||||
|
{
|
||||||
|
abort_message("terminating");
|
||||||
|
}
|
||||||
|
#endif // !_LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
static void demangling_unexpected_handler()
|
||||||
|
{
|
||||||
|
cause = "unexpected";
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
|
||||||
|
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
|
||||||
|
#else // !LIBCXXABI_SILENT_TERMINATE
|
||||||
|
static constexpr std::terminate_handler default_terminate_handler = ::abort;
|
||||||
|
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
|
||||||
|
#endif // !LIBCXXABI_SILENT_TERMINATE
|
||||||
|
|
||||||
|
//
|
||||||
|
// Global variables that hold the pointers to the current handler
|
||||||
|
//
|
||||||
|
_LIBCXXABI_DATA_VIS
|
||||||
|
constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
|
||||||
|
|
||||||
|
_LIBCXXABI_DATA_VIS
|
||||||
|
constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
|
||||||
|
|
||||||
|
_LIBCXXABI_DATA_VIS
|
||||||
|
constinit std::new_handler __cxa_new_handler = nullptr;
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
unexpected_handler
|
||||||
|
set_unexpected(unexpected_handler func) noexcept
|
||||||
|
{
|
||||||
|
if (func == 0)
|
||||||
|
func = default_unexpected_handler;
|
||||||
|
return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
|
||||||
|
_AO_Acq_Rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
terminate_handler
|
||||||
|
set_terminate(terminate_handler func) noexcept
|
||||||
|
{
|
||||||
|
if (func == 0)
|
||||||
|
func = default_terminate_handler;
|
||||||
|
return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
|
||||||
|
_AO_Acq_Rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_handler
|
||||||
|
set_new_handler(new_handler handler) noexcept
|
||||||
|
{
|
||||||
|
return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
409
third_party/libcxxabi/cxa_demangle.cc
vendored
Normal file
409
third_party/libcxxabi/cxa_demangle.cc
vendored
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// FIXME: (possibly) incomplete list of features that clang mangles that this
|
||||||
|
// file does not yet support:
|
||||||
|
// - C++ modules TS
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
|
||||||
|
#include "third_party/libcxxabi/demangle/ItaniumDemangle.h"
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
#include "third_party/libcxx/cassert"
|
||||||
|
#include "third_party/libcxx/cctype"
|
||||||
|
#include "third_party/libcxx/cstdio"
|
||||||
|
#include "third_party/libcxx/cstdlib"
|
||||||
|
#include "third_party/libcxx/cstring"
|
||||||
|
#include "third_party/libcxx/functional"
|
||||||
|
#include "third_party/libcxx/numeric"
|
||||||
|
#include "third_party/libcxx/string_view"
|
||||||
|
#include "third_party/libcxx/utility"
|
||||||
|
|
||||||
|
using namespace itanium_demangle;
|
||||||
|
|
||||||
|
constexpr const char *itanium_demangle::FloatData<float>::spec;
|
||||||
|
constexpr const char *itanium_demangle::FloatData<double>::spec;
|
||||||
|
constexpr const char *itanium_demangle::FloatData<long double>::spec;
|
||||||
|
|
||||||
|
// <discriminator> := _ <non-negative number> # when number < 10
|
||||||
|
// := __ <non-negative number> _ # when number >= 10
|
||||||
|
// extension := decimal-digit+ # at the end of string
|
||||||
|
const char *itanium_demangle::parse_discriminator(const char *first,
|
||||||
|
const char *last) {
|
||||||
|
// parse but ignore discriminator
|
||||||
|
if (first != last) {
|
||||||
|
if (*first == '_') {
|
||||||
|
const char *t1 = first + 1;
|
||||||
|
if (t1 != last) {
|
||||||
|
if (std::isdigit(*t1))
|
||||||
|
first = t1 + 1;
|
||||||
|
else if (*t1 == '_') {
|
||||||
|
for (++t1; t1 != last && std::isdigit(*t1); ++t1)
|
||||||
|
;
|
||||||
|
if (t1 != last && *t1 == '_')
|
||||||
|
first = t1 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (std::isdigit(*first)) {
|
||||||
|
const char *t1 = first + 1;
|
||||||
|
for (; t1 != last && std::isdigit(*t1); ++t1)
|
||||||
|
;
|
||||||
|
if (t1 == last)
|
||||||
|
first = last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
namespace {
|
||||||
|
struct DumpVisitor {
|
||||||
|
unsigned Depth = 0;
|
||||||
|
bool PendingNewline = false;
|
||||||
|
|
||||||
|
template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool wantsNewline(NodeArray A) { return !A.empty(); }
|
||||||
|
static constexpr bool wantsNewline(...) { return false; }
|
||||||
|
|
||||||
|
template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
|
||||||
|
for (bool B : {wantsNewline(Vs)...})
|
||||||
|
if (B)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStr(const char *S) { fprintf(stderr, "%s", S); }
|
||||||
|
void print(std::string_view SV) {
|
||||||
|
fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin());
|
||||||
|
}
|
||||||
|
void print(const Node *N) {
|
||||||
|
if (N)
|
||||||
|
N->visit(std::ref(*this));
|
||||||
|
else
|
||||||
|
printStr("<null>");
|
||||||
|
}
|
||||||
|
void print(NodeArray A) {
|
||||||
|
++Depth;
|
||||||
|
printStr("{");
|
||||||
|
bool First = true;
|
||||||
|
for (const Node *N : A) {
|
||||||
|
if (First)
|
||||||
|
print(N);
|
||||||
|
else
|
||||||
|
printWithComma(N);
|
||||||
|
First = false;
|
||||||
|
}
|
||||||
|
printStr("}");
|
||||||
|
--Depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload used when T is exactly 'bool', not merely convertible to 'bool'.
|
||||||
|
void print(bool B) { printStr(B ? "true" : "false"); }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
|
||||||
|
fprintf(stderr, "%llu", (unsigned long long)N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
|
||||||
|
fprintf(stderr, "%lld", (long long)N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(ReferenceKind RK) {
|
||||||
|
switch (RK) {
|
||||||
|
case ReferenceKind::LValue:
|
||||||
|
return printStr("ReferenceKind::LValue");
|
||||||
|
case ReferenceKind::RValue:
|
||||||
|
return printStr("ReferenceKind::RValue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void print(FunctionRefQual RQ) {
|
||||||
|
switch (RQ) {
|
||||||
|
case FunctionRefQual::FrefQualNone:
|
||||||
|
return printStr("FunctionRefQual::FrefQualNone");
|
||||||
|
case FunctionRefQual::FrefQualLValue:
|
||||||
|
return printStr("FunctionRefQual::FrefQualLValue");
|
||||||
|
case FunctionRefQual::FrefQualRValue:
|
||||||
|
return printStr("FunctionRefQual::FrefQualRValue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void print(Qualifiers Qs) {
|
||||||
|
if (!Qs) return printStr("QualNone");
|
||||||
|
struct QualName { Qualifiers Q; const char *Name; } Names[] = {
|
||||||
|
{QualConst, "QualConst"},
|
||||||
|
{QualVolatile, "QualVolatile"},
|
||||||
|
{QualRestrict, "QualRestrict"},
|
||||||
|
};
|
||||||
|
for (QualName Name : Names) {
|
||||||
|
if (Qs & Name.Q) {
|
||||||
|
printStr(Name.Name);
|
||||||
|
Qs = Qualifiers(Qs & ~Name.Q);
|
||||||
|
if (Qs) printStr(" | ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void print(SpecialSubKind SSK) {
|
||||||
|
switch (SSK) {
|
||||||
|
case SpecialSubKind::allocator:
|
||||||
|
return printStr("SpecialSubKind::allocator");
|
||||||
|
case SpecialSubKind::basic_string:
|
||||||
|
return printStr("SpecialSubKind::basic_string");
|
||||||
|
case SpecialSubKind::string:
|
||||||
|
return printStr("SpecialSubKind::string");
|
||||||
|
case SpecialSubKind::istream:
|
||||||
|
return printStr("SpecialSubKind::istream");
|
||||||
|
case SpecialSubKind::ostream:
|
||||||
|
return printStr("SpecialSubKind::ostream");
|
||||||
|
case SpecialSubKind::iostream:
|
||||||
|
return printStr("SpecialSubKind::iostream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void print(TemplateParamKind TPK) {
|
||||||
|
switch (TPK) {
|
||||||
|
case TemplateParamKind::Type:
|
||||||
|
return printStr("TemplateParamKind::Type");
|
||||||
|
case TemplateParamKind::NonType:
|
||||||
|
return printStr("TemplateParamKind::NonType");
|
||||||
|
case TemplateParamKind::Template:
|
||||||
|
return printStr("TemplateParamKind::Template");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void print(Node::Prec P) {
|
||||||
|
switch (P) {
|
||||||
|
case Node::Prec::Primary:
|
||||||
|
return printStr("Node::Prec::Primary");
|
||||||
|
case Node::Prec::Postfix:
|
||||||
|
return printStr("Node::Prec::Postfix");
|
||||||
|
case Node::Prec::Unary:
|
||||||
|
return printStr("Node::Prec::Unary");
|
||||||
|
case Node::Prec::Cast:
|
||||||
|
return printStr("Node::Prec::Cast");
|
||||||
|
case Node::Prec::PtrMem:
|
||||||
|
return printStr("Node::Prec::PtrMem");
|
||||||
|
case Node::Prec::Multiplicative:
|
||||||
|
return printStr("Node::Prec::Multiplicative");
|
||||||
|
case Node::Prec::Additive:
|
||||||
|
return printStr("Node::Prec::Additive");
|
||||||
|
case Node::Prec::Shift:
|
||||||
|
return printStr("Node::Prec::Shift");
|
||||||
|
case Node::Prec::Spaceship:
|
||||||
|
return printStr("Node::Prec::Spaceship");
|
||||||
|
case Node::Prec::Relational:
|
||||||
|
return printStr("Node::Prec::Relational");
|
||||||
|
case Node::Prec::Equality:
|
||||||
|
return printStr("Node::Prec::Equality");
|
||||||
|
case Node::Prec::And:
|
||||||
|
return printStr("Node::Prec::And");
|
||||||
|
case Node::Prec::Xor:
|
||||||
|
return printStr("Node::Prec::Xor");
|
||||||
|
case Node::Prec::Ior:
|
||||||
|
return printStr("Node::Prec::Ior");
|
||||||
|
case Node::Prec::AndIf:
|
||||||
|
return printStr("Node::Prec::AndIf");
|
||||||
|
case Node::Prec::OrIf:
|
||||||
|
return printStr("Node::Prec::OrIf");
|
||||||
|
case Node::Prec::Conditional:
|
||||||
|
return printStr("Node::Prec::Conditional");
|
||||||
|
case Node::Prec::Assign:
|
||||||
|
return printStr("Node::Prec::Assign");
|
||||||
|
case Node::Prec::Comma:
|
||||||
|
return printStr("Node::Prec::Comma");
|
||||||
|
case Node::Prec::Default:
|
||||||
|
return printStr("Node::Prec::Default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void newLine() {
|
||||||
|
printStr("\n");
|
||||||
|
for (unsigned I = 0; I != Depth; ++I)
|
||||||
|
printStr(" ");
|
||||||
|
PendingNewline = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void printWithPendingNewline(T V) {
|
||||||
|
print(V);
|
||||||
|
if (wantsNewline(V))
|
||||||
|
PendingNewline = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void printWithComma(T V) {
|
||||||
|
if (PendingNewline || wantsNewline(V)) {
|
||||||
|
printStr(",");
|
||||||
|
newLine();
|
||||||
|
} else {
|
||||||
|
printStr(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printWithPendingNewline(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CtorArgPrinter {
|
||||||
|
DumpVisitor &Visitor;
|
||||||
|
|
||||||
|
template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
|
||||||
|
if (Visitor.anyWantNewline(V, Vs...))
|
||||||
|
Visitor.newLine();
|
||||||
|
Visitor.printWithPendingNewline(V);
|
||||||
|
int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
|
||||||
|
(void)PrintInOrder;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename NodeT> void operator()(const NodeT *Node) {
|
||||||
|
Depth += 2;
|
||||||
|
fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
|
||||||
|
Node->match(CtorArgPrinter{*this});
|
||||||
|
fprintf(stderr, ")");
|
||||||
|
Depth -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const ForwardTemplateReference *Node) {
|
||||||
|
Depth += 2;
|
||||||
|
fprintf(stderr, "ForwardTemplateReference(");
|
||||||
|
if (Node->Ref && !Node->Printing) {
|
||||||
|
Node->Printing = true;
|
||||||
|
CtorArgPrinter{*this}(Node->Ref);
|
||||||
|
Node->Printing = false;
|
||||||
|
} else {
|
||||||
|
CtorArgPrinter{*this}(Node->Index);
|
||||||
|
}
|
||||||
|
fprintf(stderr, ")");
|
||||||
|
Depth -= 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void itanium_demangle::Node::dump() const {
|
||||||
|
DumpVisitor V;
|
||||||
|
visit(std::ref(V));
|
||||||
|
V.newLine();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class BumpPointerAllocator {
|
||||||
|
struct BlockMeta {
|
||||||
|
BlockMeta* Next;
|
||||||
|
size_t Current;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr size_t AllocSize = 4096;
|
||||||
|
static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
|
||||||
|
|
||||||
|
alignas(long double) char InitialBuffer[AllocSize];
|
||||||
|
BlockMeta* BlockList = nullptr;
|
||||||
|
|
||||||
|
void grow() {
|
||||||
|
char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
|
||||||
|
if (NewMeta == nullptr)
|
||||||
|
std::terminate();
|
||||||
|
BlockList = new (NewMeta) BlockMeta{BlockList, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocateMassive(size_t NBytes) {
|
||||||
|
NBytes += sizeof(BlockMeta);
|
||||||
|
BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
|
||||||
|
if (NewMeta == nullptr)
|
||||||
|
std::terminate();
|
||||||
|
BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
|
||||||
|
return static_cast<void*>(NewMeta + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
BumpPointerAllocator()
|
||||||
|
: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
|
||||||
|
|
||||||
|
void* allocate(size_t N) {
|
||||||
|
N = (N + 15u) & ~15u;
|
||||||
|
if (N + BlockList->Current >= UsableAllocSize) {
|
||||||
|
if (N > UsableAllocSize)
|
||||||
|
return allocateMassive(N);
|
||||||
|
grow();
|
||||||
|
}
|
||||||
|
BlockList->Current += N;
|
||||||
|
return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
|
||||||
|
BlockList->Current - N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
while (BlockList) {
|
||||||
|
BlockMeta* Tmp = BlockList;
|
||||||
|
BlockList = BlockList->Next;
|
||||||
|
if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
|
||||||
|
std::free(Tmp);
|
||||||
|
}
|
||||||
|
BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
~BumpPointerAllocator() { reset(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultAllocator {
|
||||||
|
BumpPointerAllocator Alloc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset() { Alloc.reset(); }
|
||||||
|
|
||||||
|
template<typename T, typename ...Args> T *makeNode(Args &&...args) {
|
||||||
|
return new (Alloc.allocate(sizeof(T)))
|
||||||
|
T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *allocateNodeArray(size_t sz) {
|
||||||
|
return Alloc.allocate(sizeof(Node *) * sz);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Code beyond this point should not be synchronized with LLVM.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum : int {
|
||||||
|
demangle_invalid_args = -3,
|
||||||
|
demangle_invalid_mangled_name = -2,
|
||||||
|
demangle_memory_alloc_failure = -1,
|
||||||
|
demangle_success = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
extern "C" _LIBCXXABI_FUNC_VIS char *
|
||||||
|
__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
|
||||||
|
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
|
||||||
|
if (Status)
|
||||||
|
*Status = demangle_invalid_args;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int InternalStatus = demangle_success;
|
||||||
|
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
|
||||||
|
Node *AST = Parser.parse();
|
||||||
|
|
||||||
|
if (AST == nullptr)
|
||||||
|
InternalStatus = demangle_invalid_mangled_name;
|
||||||
|
else {
|
||||||
|
OutputBuffer O(Buf, N);
|
||||||
|
assert(Parser.ForwardTemplateRefs.empty());
|
||||||
|
AST->print(O);
|
||||||
|
O += '\0';
|
||||||
|
if (N != nullptr)
|
||||||
|
*N = O.getCurrentPosition();
|
||||||
|
Buf = O.getBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Status)
|
||||||
|
*Status = InternalStatus;
|
||||||
|
return InternalStatus == demangle_success ? Buf : nullptr;
|
||||||
|
}
|
||||||
|
} // __cxxabiv1
|
776
third_party/libcxxabi/cxa_exception.cc
vendored
Normal file
776
third_party/libcxxabi/cxa_exception.cc
vendored
Normal file
|
@ -0,0 +1,776 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the "Exception Handling APIs"
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception" // for std::terminate
|
||||||
|
#include "libc/isystem/string.h" // for memset
|
||||||
|
#include "third_party/libcxxabi/cxa_exception.h"
|
||||||
|
#include "third_party/libcxxabi/cxa_handlers.h"
|
||||||
|
#include "third_party/libcxxabi/fallback_malloc.h"
|
||||||
|
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
|
||||||
|
|
||||||
|
#if __has_feature(address_sanitizer)
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// +---------------------------+-----------------------------+---------------+
|
||||||
|
// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
|
||||||
|
// +---------------------------+-----------------------------+---------------+
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// +-------------------------------------------------------+
|
||||||
|
// |
|
||||||
|
// +---------------------------+-----------------------------+
|
||||||
|
// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
|
||||||
|
// +---------------------------+-----------------------------+
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
// Utility routines
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
__cxa_exception*
|
||||||
|
cxa_exception_from_thrown_object(void* thrown_object)
|
||||||
|
{
|
||||||
|
return static_cast<__cxa_exception*>(thrown_object) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: This is never called when exception_header is masquerading as a
|
||||||
|
// __cxa_dependent_exception.
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
void*
|
||||||
|
thrown_object_from_cxa_exception(__cxa_exception* exception_header)
|
||||||
|
{
|
||||||
|
return static_cast<void*>(exception_header + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the exception object from the unwind pointer.
|
||||||
|
// Relies on the structure layout, where the unwind pointer is right in
|
||||||
|
// front of the user's exception object
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
__cxa_exception*
|
||||||
|
cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
|
||||||
|
{
|
||||||
|
return cxa_exception_from_thrown_object(unwind_exception + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round s up to next multiple of a.
|
||||||
|
static inline
|
||||||
|
size_t aligned_allocation_size(size_t s, size_t a) {
|
||||||
|
return (s + a - 1) & ~(a - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
|
||||||
|
return aligned_allocation_size(size + sizeof (__cxa_exception),
|
||||||
|
alignof(__cxa_exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) {
|
||||||
|
::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setOurExceptionClass(_Unwind_Exception* unwind_exception) {
|
||||||
|
__setExceptionClass(unwind_exception, kOurExceptionClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
|
||||||
|
__setExceptionClass(unwind_exception, kOurDependentExceptionClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it one of ours?
|
||||||
|
uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
|
||||||
|
// On x86 and some ARM unwinders, unwind_exception->exception_class is
|
||||||
|
// a uint64_t. On other ARM unwinders, it is a char[8].
|
||||||
|
// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
|
||||||
|
// So we just copy it into a uint64_t to be sure.
|
||||||
|
uint64_t exClass;
|
||||||
|
::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
|
||||||
|
return exClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
|
||||||
|
return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
|
||||||
|
(kOurExceptionClass & get_vendor_and_language);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isDependentException(_Unwind_Exception* unwind_exception) {
|
||||||
|
return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does not need to be atomic
|
||||||
|
static inline int incrementHandlerCount(__cxa_exception *exception) {
|
||||||
|
return ++exception->handlerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does not need to be atomic
|
||||||
|
static inline int decrementHandlerCount(__cxa_exception *exception) {
|
||||||
|
return --exception->handlerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
|
||||||
|
stored in exc is called. Otherwise the exceptionDestructor stored in
|
||||||
|
exc is called, and then the memory for the exception is deallocated.
|
||||||
|
|
||||||
|
This is never called for a __cxa_dependent_exception.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
|
||||||
|
{
|
||||||
|
__cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
|
||||||
|
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
|
||||||
|
std::__terminate(exception_header->terminateHandler);
|
||||||
|
// Just in case there exists a dependent exception that is pointing to this,
|
||||||
|
// check the reference count and only destroy this if that count goes to zero.
|
||||||
|
__cxa_decrement_exception_refcount(unwind_exception + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
|
||||||
|
// Section 2.5.3 says:
|
||||||
|
// * For purposes of this ABI, several things are considered exception handlers:
|
||||||
|
// ** A terminate() call due to a throw.
|
||||||
|
// and
|
||||||
|
// * Upon entry, Following initialization of the catch parameter,
|
||||||
|
// a handler must call:
|
||||||
|
// * void *__cxa_begin_catch(void *exceptionObject );
|
||||||
|
(void) __cxa_begin_catch(&exception_header->unwindHeader);
|
||||||
|
std::__terminate(exception_header->terminateHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the offset of the __cxa_exception header from the start of the
|
||||||
|
// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
|
||||||
|
// useful alignment for the target machine, padding has to be inserted before
|
||||||
|
// the header to ensure the thrown object that follows the header is
|
||||||
|
// sufficiently aligned. This happens if _Unwind_exception isn't double-word
|
||||||
|
// aligned (on Darwin, for example).
|
||||||
|
static size_t get_cxa_exception_offset() {
|
||||||
|
struct S {
|
||||||
|
} __attribute__((aligned));
|
||||||
|
|
||||||
|
// Compute the maximum alignment for the target machine.
|
||||||
|
constexpr size_t alignment = alignof(S);
|
||||||
|
constexpr size_t excp_size = sizeof(__cxa_exception);
|
||||||
|
constexpr size_t aligned_size =
|
||||||
|
(excp_size + alignment - 1) / alignment * alignment;
|
||||||
|
constexpr size_t offset = aligned_size - excp_size;
|
||||||
|
static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment),
|
||||||
|
"offset is non-zero only if _Unwind_Exception isn't aligned");
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Allocate a __cxa_exception object, and zero-fill it.
|
||||||
|
// Reserve "thrown_size" bytes on the end for the user's exception
|
||||||
|
// object. Zero-fill the object. If memory can't be allocated, call
|
||||||
|
// std::terminate. Return a pointer to the memory to be used for the
|
||||||
|
// user's exception object.
|
||||||
|
void *__cxa_allocate_exception(size_t thrown_size) throw() {
|
||||||
|
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
|
||||||
|
|
||||||
|
// Allocate extra space before the __cxa_exception header to ensure the
|
||||||
|
// start of the thrown object is sufficiently aligned.
|
||||||
|
size_t header_offset = get_cxa_exception_offset();
|
||||||
|
char *raw_buffer =
|
||||||
|
(char *)__aligned_malloc_with_fallback(header_offset + actual_size);
|
||||||
|
if (NULL == raw_buffer)
|
||||||
|
std::terminate();
|
||||||
|
__cxa_exception *exception_header =
|
||||||
|
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
|
||||||
|
::memset(exception_header, 0, actual_size);
|
||||||
|
return thrown_object_from_cxa_exception(exception_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
|
||||||
|
void __cxa_free_exception(void *thrown_object) throw() {
|
||||||
|
// Compute the size of the padding before the header.
|
||||||
|
size_t header_offset = get_cxa_exception_offset();
|
||||||
|
char *raw_buffer =
|
||||||
|
((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
|
||||||
|
__aligned_free_with_fallback((void *)raw_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function shall allocate a __cxa_dependent_exception and
|
||||||
|
// return a pointer to it. (Really to the object, not past its' end).
|
||||||
|
// Otherwise, it will work like __cxa_allocate_exception.
|
||||||
|
void * __cxa_allocate_dependent_exception () {
|
||||||
|
size_t actual_size = sizeof(__cxa_dependent_exception);
|
||||||
|
void *ptr = __aligned_malloc_with_fallback(actual_size);
|
||||||
|
if (NULL == ptr)
|
||||||
|
std::terminate();
|
||||||
|
::memset(ptr, 0, actual_size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function shall free a dependent_exception.
|
||||||
|
// It does not affect the reference count of the primary exception.
|
||||||
|
void __cxa_free_dependent_exception (void * dependent_exception) {
|
||||||
|
__aligned_free_with_fallback(dependent_exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2.4.3 Throwing the Exception Object
|
||||||
|
/*
|
||||||
|
After constructing the exception object with the throw argument value,
|
||||||
|
the generated code calls the __cxa_throw runtime library routine. This
|
||||||
|
routine never returns.
|
||||||
|
|
||||||
|
The __cxa_throw routine will do the following:
|
||||||
|
|
||||||
|
* Obtain the __cxa_exception header from the thrown exception object address,
|
||||||
|
which can be computed as follows:
|
||||||
|
__cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
|
||||||
|
* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
|
||||||
|
* Save the tinfo and dest arguments in the __cxa_exception header.
|
||||||
|
* Set the exception_class field in the unwind header. This is a 64-bit value
|
||||||
|
representing the ASCII string "XXXXC++\0", where "XXXX" is a
|
||||||
|
vendor-dependent string. That is, for implementations conforming to this
|
||||||
|
ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
|
||||||
|
* Increment the uncaught_exception flag.
|
||||||
|
* Call _Unwind_RaiseException in the system unwind library, Its argument is the
|
||||||
|
pointer to the thrown exception, which __cxa_throw itself received as an argument.
|
||||||
|
__Unwind_RaiseException begins the process of stack unwinding, described
|
||||||
|
in Section 2.5. In special cases, such as an inability to find a
|
||||||
|
handler, _Unwind_RaiseException may return. In that case, __cxa_throw
|
||||||
|
will call terminate, assuming that there was no handler for the
|
||||||
|
exception.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
|
||||||
|
__cxa_eh_globals *globals = __cxa_get_globals();
|
||||||
|
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
|
||||||
|
|
||||||
|
exception_header->unexpectedHandler = std::get_unexpected();
|
||||||
|
exception_header->terminateHandler = std::get_terminate();
|
||||||
|
exception_header->exceptionType = tinfo;
|
||||||
|
exception_header->exceptionDestructor = dest;
|
||||||
|
setOurExceptionClass(&exception_header->unwindHeader);
|
||||||
|
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
|
||||||
|
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
|
||||||
|
|
||||||
|
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
|
||||||
|
|
||||||
|
#if __has_feature(address_sanitizer)
|
||||||
|
// Inform the ASan runtime that now might be a good time to clean stuff up.
|
||||||
|
__asan_handle_no_return();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
|
||||||
|
#else
|
||||||
|
_Unwind_RaiseException(&exception_header->unwindHeader);
|
||||||
|
#endif
|
||||||
|
// This only happens when there is no handler, or some unexpected unwinding
|
||||||
|
// error happens.
|
||||||
|
failed_throw(exception_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2.5.3 Exception Handlers
|
||||||
|
/*
|
||||||
|
The adjusted pointer is computed by the personality routine during phase 1
|
||||||
|
and saved in the exception header (either __cxa_exception or
|
||||||
|
__cxa_dependent_exception).
|
||||||
|
|
||||||
|
Requires: exception is native
|
||||||
|
*/
|
||||||
|
void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
return reinterpret_cast<void*>(
|
||||||
|
static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
|
||||||
|
#else
|
||||||
|
return cxa_exception_from_exception_unwind_exception(
|
||||||
|
static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
/*
|
||||||
|
The routine to be called before the cleanup. This will save __cxa_exception in
|
||||||
|
__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
|
||||||
|
*/
|
||||||
|
bool __cxa_begin_cleanup(void *unwind_arg) throw() {
|
||||||
|
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals();
|
||||||
|
__cxa_exception* exception_header =
|
||||||
|
cxa_exception_from_exception_unwind_exception(unwind_exception);
|
||||||
|
|
||||||
|
if (__isOurExceptionClass(unwind_exception))
|
||||||
|
{
|
||||||
|
if (0 == exception_header->propagationCount)
|
||||||
|
{
|
||||||
|
exception_header->nextPropagatingException = globals->propagatingExceptions;
|
||||||
|
globals->propagatingExceptions = exception_header;
|
||||||
|
}
|
||||||
|
++exception_header->propagationCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the propagatingExceptions stack is not empty, since we can't
|
||||||
|
// chain the foreign exception, terminate it.
|
||||||
|
if (NULL != globals->propagatingExceptions)
|
||||||
|
std::terminate();
|
||||||
|
globals->propagatingExceptions = exception_header;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The routine to be called after the cleanup has been performed. It will get the
|
||||||
|
propagating __cxa_exception from __cxa_eh_globals, and continue the stack
|
||||||
|
unwinding with _Unwind_Resume.
|
||||||
|
|
||||||
|
According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
|
||||||
|
register, thus we have to write this function in assembly so that we can save
|
||||||
|
{r1, r2, r3}. We don't have to save r0 because it is the return value and the
|
||||||
|
first argument to _Unwind_Resume(). The function also saves/restores r4 to
|
||||||
|
keep the stack aligned and to provide a temp register. _Unwind_Resume never
|
||||||
|
returns and we need to keep the original lr so just branch to it. When
|
||||||
|
targeting bare metal, the function also clobbers ip/r12 to hold the address of
|
||||||
|
_Unwind_Resume, which may be too far away for an ordinary branch.
|
||||||
|
*/
|
||||||
|
__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"
|
||||||
|
#if defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||||
|
" bti\n"
|
||||||
|
#endif
|
||||||
|
" push {r1, r2, r3, r4}\n"
|
||||||
|
" mov r4, lr\n"
|
||||||
|
" bl __cxa_end_cleanup_impl\n"
|
||||||
|
" mov lr, r4\n"
|
||||||
|
#if defined(LIBCXXABI_BAREMETAL)
|
||||||
|
" ldr r4, =_Unwind_Resume\n"
|
||||||
|
" mov ip, r4\n"
|
||||||
|
#endif
|
||||||
|
" pop {r1, r2, r3, r4}\n"
|
||||||
|
#if defined(LIBCXXABI_BAREMETAL)
|
||||||
|
" bx ip\n"
|
||||||
|
#else
|
||||||
|
" b _Unwind_Resume\n"
|
||||||
|
#endif
|
||||||
|
" .popsection");
|
||||||
|
#endif // defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This routine can catch foreign or native exceptions. If native, the exception
|
||||||
|
can be a primary or dependent variety. This routine may remain blissfully
|
||||||
|
ignorant of whether the native exception is primary or dependent.
|
||||||
|
|
||||||
|
If the exception is native:
|
||||||
|
* Increment's the exception's handler count.
|
||||||
|
* Push the exception on the stack of currently-caught exceptions if it is not
|
||||||
|
already there (from a rethrow).
|
||||||
|
* Decrements the uncaught_exception count.
|
||||||
|
* Returns the adjusted pointer to the exception object, which is stored in
|
||||||
|
the __cxa_exception by the personality routine.
|
||||||
|
|
||||||
|
If the exception is foreign, this means it did not originate from one of throw
|
||||||
|
routines. The foreign exception does not necessarily have a __cxa_exception
|
||||||
|
header. However we can catch it here with a catch (...), or with a call
|
||||||
|
to terminate or unexpected during unwinding.
|
||||||
|
* Do not try to increment the exception's handler count, we don't know where
|
||||||
|
it is.
|
||||||
|
* Push the exception on the stack of currently-caught exceptions only if the
|
||||||
|
stack is empty. The foreign exception has no way to link to the current
|
||||||
|
top of stack. If the stack is not empty, call terminate. Even with an
|
||||||
|
empty stack, this is hacked in by pushing a pointer to an imaginary
|
||||||
|
__cxa_exception block in front of the foreign exception. It would be better
|
||||||
|
if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
|
||||||
|
doesn't. It has a stack of __cxa_exception (which has a next* in it).
|
||||||
|
* Do not decrement the uncaught_exception count because we didn't increment it
|
||||||
|
in __cxa_throw (or one of our rethrow functions).
|
||||||
|
* If we haven't terminated, assume the exception object is just past the
|
||||||
|
_Unwind_Exception and return a pointer to that.
|
||||||
|
*/
|
||||||
|
void*
|
||||||
|
__cxa_begin_catch(void* unwind_arg) throw()
|
||||||
|
{
|
||||||
|
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
|
||||||
|
bool native_exception = __isOurExceptionClass(unwind_exception);
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals();
|
||||||
|
// exception_header is a hackish offset from a foreign exception, but it
|
||||||
|
// works as long as we're careful not to try to access any __cxa_exception
|
||||||
|
// parts.
|
||||||
|
__cxa_exception* exception_header =
|
||||||
|
cxa_exception_from_exception_unwind_exception
|
||||||
|
(
|
||||||
|
static_cast<_Unwind_Exception*>(unwind_exception)
|
||||||
|
);
|
||||||
|
|
||||||
|
#if defined(__MVS__)
|
||||||
|
// Remove the exception object from the linked list of exceptions that the z/OS unwinder
|
||||||
|
// maintains before adding it to the libc++abi list of caught exceptions.
|
||||||
|
// The libc++abi will manage the lifetime of the exception from this point forward.
|
||||||
|
_UnwindZOS_PopException();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (native_exception)
|
||||||
|
{
|
||||||
|
// Increment the handler count, removing the flag about being rethrown
|
||||||
|
exception_header->handlerCount = exception_header->handlerCount < 0 ?
|
||||||
|
-exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
|
||||||
|
// place the exception on the top of the stack if it's not already
|
||||||
|
// there by a previous rethrow
|
||||||
|
if (exception_header != globals->caughtExceptions)
|
||||||
|
{
|
||||||
|
exception_header->nextException = globals->caughtExceptions;
|
||||||
|
globals->caughtExceptions = exception_header;
|
||||||
|
}
|
||||||
|
globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
|
||||||
|
#else
|
||||||
|
return exception_header->adjustedPtr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Else this is a foreign exception
|
||||||
|
// If the caughtExceptions stack is not empty, terminate
|
||||||
|
if (globals->caughtExceptions != 0)
|
||||||
|
std::terminate();
|
||||||
|
// Push the foreign exception on to the stack
|
||||||
|
globals->caughtExceptions = exception_header;
|
||||||
|
return unwind_exception + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Upon exit for any reason, a handler must call:
|
||||||
|
void __cxa_end_catch ();
|
||||||
|
|
||||||
|
This routine can be called for either a native or foreign exception.
|
||||||
|
For a native exception:
|
||||||
|
* Locates the most recently caught exception and decrements its handler count.
|
||||||
|
* Removes the exception from the caught exception stack, if the handler count goes to zero.
|
||||||
|
* If the handler count goes down to zero, and the exception was not re-thrown
|
||||||
|
by throw, it locates the primary exception (which may be the same as the one
|
||||||
|
it's handling) and decrements its reference count. If that reference count
|
||||||
|
goes to zero, the function destroys the exception. In any case, if the current
|
||||||
|
exception is a dependent exception, it destroys that.
|
||||||
|
|
||||||
|
For a foreign exception:
|
||||||
|
* If it has been rethrown, there is nothing to do.
|
||||||
|
* Otherwise delete the exception and pop the catch stack to empty.
|
||||||
|
*/
|
||||||
|
void __cxa_end_catch() {
|
||||||
|
static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
|
||||||
|
"sizeof(__cxa_exception) must be equal to "
|
||||||
|
"sizeof(__cxa_dependent_exception)");
|
||||||
|
static_assert(__builtin_offsetof(__cxa_exception, referenceCount) ==
|
||||||
|
__builtin_offsetof(__cxa_dependent_exception,
|
||||||
|
primaryException),
|
||||||
|
"the layout of __cxa_exception must match the layout of "
|
||||||
|
"__cxa_dependent_exception");
|
||||||
|
static_assert(__builtin_offsetof(__cxa_exception, handlerCount) ==
|
||||||
|
__builtin_offsetof(__cxa_dependent_exception, handlerCount),
|
||||||
|
"the layout of __cxa_exception must match the layout of "
|
||||||
|
"__cxa_dependent_exception");
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
|
||||||
|
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||||
|
// If we've rethrown a foreign exception, then globals->caughtExceptions
|
||||||
|
// will have been made an empty stack by __cxa_rethrow() and there is
|
||||||
|
// nothing more to be done. Do nothing!
|
||||||
|
if (NULL != exception_header)
|
||||||
|
{
|
||||||
|
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
|
||||||
|
if (native_exception)
|
||||||
|
{
|
||||||
|
// This is a native exception
|
||||||
|
if (exception_header->handlerCount < 0)
|
||||||
|
{
|
||||||
|
// The exception has been rethrown by __cxa_rethrow, so don't delete it
|
||||||
|
if (0 == incrementHandlerCount(exception_header))
|
||||||
|
{
|
||||||
|
// Remove from the chain of uncaught exceptions
|
||||||
|
globals->caughtExceptions = exception_header->nextException;
|
||||||
|
// but don't destroy
|
||||||
|
}
|
||||||
|
// Keep handlerCount negative in case there are nested catch's
|
||||||
|
// that need to be told that this exception is rethrown. Don't
|
||||||
|
// erase this rethrow flag until the exception is recaught.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The native exception has not been rethrown
|
||||||
|
if (0 == decrementHandlerCount(exception_header))
|
||||||
|
{
|
||||||
|
// Remove from the chain of uncaught exceptions
|
||||||
|
globals->caughtExceptions = exception_header->nextException;
|
||||||
|
// Destroy this exception, being careful to distinguish
|
||||||
|
// between dependent and primary exceptions
|
||||||
|
if (isDependentException(&exception_header->unwindHeader))
|
||||||
|
{
|
||||||
|
// Reset exception_header to primaryException and deallocate the dependent exception
|
||||||
|
__cxa_dependent_exception* dep_exception_header =
|
||||||
|
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
|
||||||
|
exception_header =
|
||||||
|
cxa_exception_from_thrown_object(dep_exception_header->primaryException);
|
||||||
|
__cxa_free_dependent_exception(dep_exception_header);
|
||||||
|
}
|
||||||
|
// Destroy the primary exception only if its referenceCount goes to 0
|
||||||
|
// (this decrement must be atomic)
|
||||||
|
__cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The foreign exception has not been rethrown. Pop the stack
|
||||||
|
// and delete it. If there are nested catch's and they try
|
||||||
|
// to touch a foreign exception in any way, that is undefined
|
||||||
|
// behavior. They likely can't since the only way to catch
|
||||||
|
// a foreign exception is with catch (...)!
|
||||||
|
_Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
|
||||||
|
globals->caughtExceptions = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: exception_header may be masquerading as a __cxa_dependent_exception
|
||||||
|
// and that's ok. exceptionType is there too.
|
||||||
|
// However watch out for foreign exceptions. Return null for them.
|
||||||
|
std::type_info *__cxa_current_exception_type() {
|
||||||
|
// get the current exception
|
||||||
|
__cxa_eh_globals *globals = __cxa_get_globals_fast();
|
||||||
|
if (NULL == globals)
|
||||||
|
return NULL; // If there have never been any exceptions, there are none now.
|
||||||
|
__cxa_exception *exception_header = globals->caughtExceptions;
|
||||||
|
if (NULL == exception_header)
|
||||||
|
return NULL; // No current exception
|
||||||
|
if (!__isOurExceptionClass(&exception_header->unwindHeader))
|
||||||
|
return NULL;
|
||||||
|
return exception_header->exceptionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.5.4 Rethrowing Exceptions
|
||||||
|
/* This routine can rethrow native or foreign exceptions.
|
||||||
|
If the exception is native:
|
||||||
|
* marks the exception object on top of the caughtExceptions stack
|
||||||
|
(in an implementation-defined way) as being rethrown.
|
||||||
|
* If the caughtExceptions stack is empty, it calls terminate()
|
||||||
|
(see [C++FDIS] [except.throw], 15.1.8).
|
||||||
|
* It then calls _Unwind_RaiseException which should not return
|
||||||
|
(terminate if it does).
|
||||||
|
Note: exception_header may be masquerading as a __cxa_dependent_exception
|
||||||
|
and that's ok.
|
||||||
|
*/
|
||||||
|
void __cxa_rethrow() {
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals();
|
||||||
|
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||||
|
if (NULL == exception_header)
|
||||||
|
std::terminate(); // throw; called outside of a exception handler
|
||||||
|
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
|
||||||
|
if (native_exception)
|
||||||
|
{
|
||||||
|
// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
|
||||||
|
exception_header->handlerCount = -exception_header->handlerCount;
|
||||||
|
globals->uncaughtExceptions += 1;
|
||||||
|
// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
|
||||||
|
}
|
||||||
|
else // this is a foreign exception
|
||||||
|
{
|
||||||
|
// The only way to communicate to __cxa_end_catch that we've rethrown
|
||||||
|
// a foreign exception, so don't delete us, is to pop the stack here
|
||||||
|
// which must be empty afterwards. Then __cxa_end_catch will do
|
||||||
|
// nothing
|
||||||
|
globals->caughtExceptions = 0;
|
||||||
|
}
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
|
||||||
|
#else
|
||||||
|
_Unwind_RaiseException(&exception_header->unwindHeader);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If we get here, some kind of unwinding error has occurred.
|
||||||
|
// There is some weird code generation bug happening with
|
||||||
|
// Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
|
||||||
|
// If we call failed_throw here. Turns up with -O2 or higher, and -Os.
|
||||||
|
__cxa_begin_catch(&exception_header->unwindHeader);
|
||||||
|
if (native_exception)
|
||||||
|
std::__terminate(exception_header->terminateHandler);
|
||||||
|
// Foreign exception: can't get exception_header->terminateHandler
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If thrown_object is not null, atomically increment the referenceCount field
|
||||||
|
of the __cxa_exception header associated with the thrown object referred to
|
||||||
|
by thrown_object.
|
||||||
|
|
||||||
|
Requires: If thrown_object is not NULL, it is a native exception.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__cxa_increment_exception_refcount(void *thrown_object) throw() {
|
||||||
|
if (thrown_object != NULL )
|
||||||
|
{
|
||||||
|
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
|
||||||
|
std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If thrown_object is not null, atomically decrement the referenceCount field
|
||||||
|
of the __cxa_exception header associated with the thrown object referred to
|
||||||
|
by thrown_object. If the referenceCount drops to zero, destroy and
|
||||||
|
deallocate the exception.
|
||||||
|
|
||||||
|
Requires: If thrown_object is not NULL, it is a native exception.
|
||||||
|
*/
|
||||||
|
_LIBCXXABI_NO_CFI
|
||||||
|
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
|
||||||
|
if (thrown_object != NULL )
|
||||||
|
{
|
||||||
|
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
|
||||||
|
if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
|
||||||
|
{
|
||||||
|
if (NULL != exception_header->exceptionDestructor)
|
||||||
|
exception_header->exceptionDestructor(thrown_object);
|
||||||
|
__cxa_free_exception(thrown_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns a pointer to the thrown object (if any) at the top of the
|
||||||
|
caughtExceptions stack. Atomically increment the exception's referenceCount.
|
||||||
|
If there is no such thrown object or if the thrown object is foreign,
|
||||||
|
returns null.
|
||||||
|
|
||||||
|
We can use __cxa_get_globals_fast here to get the globals because if there have
|
||||||
|
been no exceptions thrown, ever, on this thread, we can return NULL without
|
||||||
|
the need to allocate the exception-handling globals.
|
||||||
|
*/
|
||||||
|
void *__cxa_current_primary_exception() throw() {
|
||||||
|
// get the current exception
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||||
|
if (NULL == globals)
|
||||||
|
return NULL; // If there are no globals, there is no exception
|
||||||
|
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||||
|
if (NULL == exception_header)
|
||||||
|
return NULL; // No current exception
|
||||||
|
if (!__isOurExceptionClass(&exception_header->unwindHeader))
|
||||||
|
return NULL; // Can't capture a foreign exception (no way to refcount it)
|
||||||
|
if (isDependentException(&exception_header->unwindHeader)) {
|
||||||
|
__cxa_dependent_exception* dep_exception_header =
|
||||||
|
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
|
||||||
|
exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
|
||||||
|
}
|
||||||
|
void* thrown_object = thrown_object_from_cxa_exception(exception_header);
|
||||||
|
__cxa_increment_exception_refcount(thrown_object);
|
||||||
|
return thrown_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
|
||||||
|
stored in exc is called. Otherwise the referenceCount stored in the
|
||||||
|
primary exception is decremented, destroying the primary if necessary.
|
||||||
|
Finally the dependent exception is destroyed.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
|
||||||
|
{
|
||||||
|
__cxa_dependent_exception* dep_exception_header =
|
||||||
|
reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
|
||||||
|
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
|
||||||
|
std::__terminate(dep_exception_header->terminateHandler);
|
||||||
|
__cxa_decrement_exception_refcount(dep_exception_header->primaryException);
|
||||||
|
__cxa_free_dependent_exception(dep_exception_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If thrown_object is not null, allocate, initialize and throw a dependent
|
||||||
|
exception.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__cxa_rethrow_primary_exception(void* thrown_object)
|
||||||
|
{
|
||||||
|
if ( thrown_object != NULL )
|
||||||
|
{
|
||||||
|
// thrown_object guaranteed to be native because
|
||||||
|
// __cxa_current_primary_exception returns NULL for foreign exceptions
|
||||||
|
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
|
||||||
|
__cxa_dependent_exception* dep_exception_header =
|
||||||
|
static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
|
||||||
|
dep_exception_header->primaryException = thrown_object;
|
||||||
|
__cxa_increment_exception_refcount(thrown_object);
|
||||||
|
dep_exception_header->exceptionType = exception_header->exceptionType;
|
||||||
|
dep_exception_header->unexpectedHandler = std::get_unexpected();
|
||||||
|
dep_exception_header->terminateHandler = std::get_terminate();
|
||||||
|
setDependentExceptionClass(&dep_exception_header->unwindHeader);
|
||||||
|
__cxa_get_globals()->uncaughtExceptions += 1;
|
||||||
|
dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
_Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
|
||||||
|
#else
|
||||||
|
_Unwind_RaiseException(&dep_exception_header->unwindHeader);
|
||||||
|
#endif
|
||||||
|
// Some sort of unwinding error. Note that terminate is a handler.
|
||||||
|
__cxa_begin_catch(&dep_exception_header->unwindHeader);
|
||||||
|
}
|
||||||
|
// If we return client will call terminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
__cxa_uncaught_exceptions() throw()
|
||||||
|
{
|
||||||
|
// This does not report foreign exceptions in flight
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||||
|
if (globals == 0)
|
||||||
|
return 0;
|
||||||
|
return globals->uncaughtExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
} // abi
|
164
third_party/libcxxabi/cxa_exception.h
vendored
Normal file
164
third_party/libcxxabi/cxa_exception.h
vendored
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the "Exception Handling APIs"
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef _CXA_EXCEPTION_H
|
||||||
|
#define _CXA_EXCEPTION_H
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception" // for std::unexpected_handler and std::terminate_handler
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libunwind/include/unwind.h"
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
|
||||||
|
static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
|
||||||
|
static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN uint64_t __getExceptionClass (const _Unwind_Exception*);
|
||||||
|
_LIBCXXABI_HIDDEN void __setExceptionClass ( _Unwind_Exception*, uint64_t);
|
||||||
|
_LIBCXXABI_HIDDEN bool __isOurExceptionClass(const _Unwind_Exception*);
|
||||||
|
|
||||||
|
struct _LIBCXXABI_HIDDEN __cxa_exception {
|
||||||
|
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
// Now _Unwind_Exception is marked with __attribute__((aligned)),
|
||||||
|
// which implies __cxa_exception is also aligned. Insert padding
|
||||||
|
// in the beginning of the struct, rather than before unwindHeader.
|
||||||
|
void *reserve;
|
||||||
|
|
||||||
|
// This is a new field to support C++11 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 (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||||
|
std::unexpected_handler unexpectedHandler;
|
||||||
|
std::terminate_handler terminateHandler;
|
||||||
|
|
||||||
|
__cxa_exception *nextException;
|
||||||
|
|
||||||
|
int handlerCount;
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
__cxa_exception* nextPropagatingException;
|
||||||
|
int propagationCount;
|
||||||
|
#else
|
||||||
|
int handlerSwitchValue;
|
||||||
|
const unsigned char *actionRecord;
|
||||||
|
const unsigned char *languageSpecificData;
|
||||||
|
void *catchTemp;
|
||||||
|
void *adjustedPtr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
// This is a new field to support C++11 exception_ptr.
|
||||||
|
// For binary compatibility it is placed where the compiler
|
||||||
|
// previously added padding to 64-bit align unwindHeader.
|
||||||
|
size_t referenceCount;
|
||||||
|
#endif
|
||||||
|
_Unwind_Exception unwindHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
|
||||||
|
// The layout of this structure MUST match the layout of __cxa_exception, with
|
||||||
|
// primaryException instead of referenceCount.
|
||||||
|
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
|
||||||
|
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
void* reserve; // padding.
|
||||||
|
void* primaryException;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::type_info *exceptionType;
|
||||||
|
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||||
|
std::unexpected_handler unexpectedHandler;
|
||||||
|
std::terminate_handler terminateHandler;
|
||||||
|
|
||||||
|
__cxa_exception *nextException;
|
||||||
|
|
||||||
|
int handlerCount;
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
__cxa_exception* nextPropagatingException;
|
||||||
|
int propagationCount;
|
||||||
|
#else
|
||||||
|
int handlerSwitchValue;
|
||||||
|
const unsigned char *actionRecord;
|
||||||
|
const unsigned char *languageSpecificData;
|
||||||
|
void * catchTemp;
|
||||||
|
void *adjustedPtr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
void* primaryException;
|
||||||
|
#endif
|
||||||
|
_Unwind_Exception unwindHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify the negative offsets of different fields.
|
||||||
|
static_assert(sizeof(_Unwind_Exception) +
|
||||||
|
offsetof(__cxa_exception, unwindHeader) ==
|
||||||
|
sizeof(__cxa_exception),
|
||||||
|
"unwindHeader has wrong negative offsets");
|
||||||
|
static_assert(sizeof(_Unwind_Exception) +
|
||||||
|
offsetof(__cxa_dependent_exception, unwindHeader) ==
|
||||||
|
sizeof(__cxa_dependent_exception),
|
||||||
|
"unwindHeader has wrong negative offsets");
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
static_assert(offsetof(__cxa_exception, propagationCount) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_exception),
|
||||||
|
"propagationCount has wrong negative offset");
|
||||||
|
static_assert(offsetof(__cxa_dependent_exception, propagationCount) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_dependent_exception),
|
||||||
|
"propagationCount has wrong negative offset");
|
||||||
|
#elif defined(__LP64__) || defined(_WIN64)
|
||||||
|
static_assert(offsetof(__cxa_exception, adjustedPtr) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_exception),
|
||||||
|
"adjustedPtr has wrong negative offset");
|
||||||
|
static_assert(offsetof(__cxa_dependent_exception, adjustedPtr) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_dependent_exception),
|
||||||
|
"adjustedPtr has wrong negative offset");
|
||||||
|
#else
|
||||||
|
static_assert(offsetof(__cxa_exception, referenceCount) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_exception),
|
||||||
|
"referenceCount has wrong negative offset");
|
||||||
|
static_assert(offsetof(__cxa_dependent_exception, primaryException) +
|
||||||
|
sizeof(_Unwind_Exception) + sizeof(void*) ==
|
||||||
|
sizeof(__cxa_dependent_exception),
|
||||||
|
"primaryException has wrong negative offset");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _LIBCXXABI_HIDDEN __cxa_eh_globals {
|
||||||
|
__cxa_exception * caughtExceptions;
|
||||||
|
unsigned int uncaughtExceptions;
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
__cxa_exception* propagatingExceptions;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals ();
|
||||||
|
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast ();
|
||||||
|
|
||||||
|
extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
|
||||||
|
extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
|
||||||
|
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
#endif // _CXA_EXCEPTION_H
|
103
third_party/libcxxabi/cxa_exception_storage.cc
vendored
Normal file
103
third_party/libcxxabi/cxa_exception_storage.cc
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the storage for the "Caught Exception Stack"
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/cxa_exception.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/__threading_support"
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_HAS_NO_THREADS)
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
extern "C" {
|
||||||
|
static __cxa_eh_globals eh_globals;
|
||||||
|
__cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
|
||||||
|
__cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
#elif defined(HAS_THREAD_LOCAL)
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
namespace {
|
||||||
|
__cxa_eh_globals *__globals() {
|
||||||
|
static thread_local __cxa_eh_globals eh_globals;
|
||||||
|
return &eh_globals;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
__cxa_eh_globals *__cxa_get_globals() { return __globals(); }
|
||||||
|
__cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); }
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
#include "third_party/libcxxabi/fallback_malloc.h"
|
||||||
|
|
||||||
|
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||||
|
#pragma comment(lib, "pthread")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// In general, we treat all threading errors as fatal.
|
||||||
|
// We cannot call std::terminate() because that will in turn
|
||||||
|
// call __cxa_get_globals() and cause infinite recursion.
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
namespace {
|
||||||
|
std::__libcpp_tls_key key_;
|
||||||
|
std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
|
||||||
|
|
||||||
|
void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) {
|
||||||
|
__free_with_fallback(p);
|
||||||
|
if (0 != std::__libcpp_tls_set(key_, NULL))
|
||||||
|
abort_message("cannot zero out thread value for __cxa_get_globals()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct_() {
|
||||||
|
if (0 != std::__libcpp_tls_create(&key_, destruct_))
|
||||||
|
abort_message("cannot create thread specific key for __cxa_get_globals()");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
__cxa_eh_globals *__cxa_get_globals() {
|
||||||
|
// Try to get the globals for this thread
|
||||||
|
__cxa_eh_globals *retVal = __cxa_get_globals_fast();
|
||||||
|
|
||||||
|
// If this is the first time we've been asked for these globals, create them
|
||||||
|
if (NULL == retVal) {
|
||||||
|
retVal = static_cast<__cxa_eh_globals*>(
|
||||||
|
__calloc_with_fallback(1, sizeof(__cxa_eh_globals)));
|
||||||
|
if (NULL == retVal)
|
||||||
|
abort_message("cannot allocate __cxa_eh_globals");
|
||||||
|
if (0 != std::__libcpp_tls_set(key_, retVal))
|
||||||
|
abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this implementation will reliably return NULL if not
|
||||||
|
// preceded by a call to __cxa_get_globals(). This is an extension
|
||||||
|
// to the Itanium ABI and is taken advantage of in several places in
|
||||||
|
// libc++abi.
|
||||||
|
__cxa_eh_globals *__cxa_get_globals_fast() {
|
||||||
|
// First time through, create the key.
|
||||||
|
if (0 != std::__libcpp_execute_once(&flag_, construct_))
|
||||||
|
abort_message("execute once failure in __cxa_get_globals_fast()");
|
||||||
|
return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
|
||||||
|
}
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
#endif
|
53
third_party/libcxxabi/cxa_guard.cc
vendored
Normal file
53
third_party/libcxxabi/cxa_guard.cc
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
|
||||||
|
// Tell the implementation that we're building the actual implementation
|
||||||
|
// (and not testing it)
|
||||||
|
#define BUILDING_CXA_GUARD
|
||||||
|
#include "third_party/libcxxabi/cxa_guard_impl.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
This implementation must be careful to not call code external to this file
|
||||||
|
which will turn around and try to call __cxa_guard_acquire reentrantly.
|
||||||
|
For this reason, the headers of this file are as restricted as possible.
|
||||||
|
Previous implementations of this code for __APPLE__ have used
|
||||||
|
std::__libcpp_mutex_lock and the abort_message utility without problem. This
|
||||||
|
implementation also uses std::__libcpp_condvar_wait which has tested
|
||||||
|
to not be a problem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
|
||||||
|
using guard_type = uint32_t;
|
||||||
|
#else
|
||||||
|
using guard_type = uint64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) {
|
||||||
|
SelectedImplementation imp(raw_guard_object);
|
||||||
|
return static_cast<int>(imp.cxa_guard_acquire());
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) {
|
||||||
|
SelectedImplementation imp(raw_guard_object);
|
||||||
|
imp.cxa_guard_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
|
||||||
|
SelectedImplementation imp(raw_guard_object);
|
||||||
|
imp.cxa_guard_abort();
|
||||||
|
}
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
} // __cxxabiv1
|
674
third_party/libcxxabi/cxa_guard_impl.h
vendored
Normal file
674
third_party/libcxxabi/cxa_guard_impl.h
vendored
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
|
||||||
|
#define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
|
||||||
|
|
||||||
|
/* cxa_guard_impl.h - Implements the C++ runtime support for function local
|
||||||
|
* static guards.
|
||||||
|
* The layout of the guard object is the same across ARM and Itanium.
|
||||||
|
*
|
||||||
|
* The first "guard byte" (which is checked by the compiler) is set only upon
|
||||||
|
* the completion of cxa release.
|
||||||
|
*
|
||||||
|
* The second "init byte" does the rest of the bookkeeping. It tracks if
|
||||||
|
* initialization is complete or pending, and if there are waiting threads.
|
||||||
|
*
|
||||||
|
* If the guard variable is 64-bits and the platforms supplies a 32-bit thread
|
||||||
|
* identifier, it is used to detect recursive initialization. The thread ID of
|
||||||
|
* the thread currently performing initialization is stored in the second word.
|
||||||
|
*
|
||||||
|
* Guard Object Layout:
|
||||||
|
* ---------------------------------------------------------------------------
|
||||||
|
* | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... |
|
||||||
|
* ---------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Note that we don't do what the ABI docs suggest (put a mutex in the guard
|
||||||
|
* object which we acquire in cxa_guard_acquire and release in
|
||||||
|
* cxa_guard_release). Instead we use the init byte to imitate that behaviour,
|
||||||
|
* but without actually holding anything mutex related between aquire and
|
||||||
|
* release/abort.
|
||||||
|
*
|
||||||
|
* Access Protocol:
|
||||||
|
* For each implementation the guard byte is checked and set before accessing
|
||||||
|
* the init byte.
|
||||||
|
*
|
||||||
|
* Overall Design:
|
||||||
|
* The implementation was designed to allow each implementation to be tested
|
||||||
|
* independent of the C++ runtime or platform support.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
|
||||||
|
#if defined(__has_include)
|
||||||
|
# if __has_include(<sys/syscall.h>)
|
||||||
|
# include <sys/syscall.h>
|
||||||
|
# endif
|
||||||
|
# if __has_include(<unistd.h>)
|
||||||
|
# include <unistd.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "third_party/libcxx/__threading_support"
|
||||||
|
#include "third_party/libcxx/cstdint"
|
||||||
|
#include "third_party/libcxx/cstring"
|
||||||
|
#include "libc/isystem/limits.h"
|
||||||
|
#include "libc/isystem/stdlib.h"
|
||||||
|
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||||
|
# pragma comment(lib, "pthread")
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Waddress"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// To make testing possible, this header is included from both cxa_guard.cpp
|
||||||
|
// and a number of tests.
|
||||||
|
//
|
||||||
|
// For this reason we place everything in an anonymous namespace -- even though
|
||||||
|
// we're in a header. We want the actual implementation and the tests to have
|
||||||
|
// unique definitions of the types in this header (since the tests may depend
|
||||||
|
// on function local statics).
|
||||||
|
//
|
||||||
|
// To enforce this either `BUILDING_CXA_GUARD` or `TESTING_CXA_GUARD` must be
|
||||||
|
// defined when including this file. Only `src/cxa_guard.cpp` should define
|
||||||
|
// the former.
|
||||||
|
#ifdef BUILDING_CXA_GUARD
|
||||||
|
# include "third_party/libcxxabi/abort_message.h"
|
||||||
|
# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
|
||||||
|
#elif defined(TESTING_CXA_GUARD)
|
||||||
|
# define ABORT_WITH_MESSAGE(...) ::abort()
|
||||||
|
#else
|
||||||
|
# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_feature(thread_sanitizer)
|
||||||
|
extern "C" void __tsan_acquire(void*);
|
||||||
|
extern "C" void __tsan_release(void*);
|
||||||
|
#else
|
||||||
|
# define __tsan_acquire(addr) ((void)0)
|
||||||
|
# define __tsan_release(addr) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
// Use an anonymous namespace to ensure that the tests and actual implementation
|
||||||
|
// have unique definitions of these symbols.
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Misc Utilities
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
template <class T, T (*Init)()>
|
||||||
|
struct LazyValue {
|
||||||
|
LazyValue() : is_init(false) {}
|
||||||
|
|
||||||
|
T& get() {
|
||||||
|
if (!is_init) {
|
||||||
|
value = Init();
|
||||||
|
is_init = true;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T value;
|
||||||
|
bool is_init = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class IntType>
|
||||||
|
class AtomicInt {
|
||||||
|
public:
|
||||||
|
using MemoryOrder = std::__libcpp_atomic_order;
|
||||||
|
|
||||||
|
explicit AtomicInt(IntType* b) : b_(b) {}
|
||||||
|
AtomicInt(AtomicInt const&) = delete;
|
||||||
|
AtomicInt& operator=(AtomicInt const&) = delete;
|
||||||
|
|
||||||
|
IntType load(MemoryOrder ord) { return std::__libcpp_atomic_load(b_, ord); }
|
||||||
|
void store(IntType val, MemoryOrder ord) { std::__libcpp_atomic_store(b_, val, ord); }
|
||||||
|
IntType exchange(IntType new_val, MemoryOrder ord) { return std::__libcpp_atomic_exchange(b_, new_val, ord); }
|
||||||
|
bool compare_exchange(IntType* expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
|
||||||
|
return std::__libcpp_atomic_compare_exchange(b_, expected, desired, ord_success, ord_failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IntType* b_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// PlatformGetThreadID
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||||
|
uint32_t PlatformThreadID() {
|
||||||
|
static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
|
||||||
|
return static_cast<uint32_t>(pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
|
||||||
|
}
|
||||||
|
#elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||||
|
uint32_t PlatformThreadID() {
|
||||||
|
static_assert(sizeof(pid_t) == sizeof(uint32_t), "");
|
||||||
|
return static_cast<uint32_t>(syscall(SYS_gettid));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
constexpr uint32_t (*PlatformThreadID)() = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// GuardByte
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static constexpr uint8_t UNSET = 0;
|
||||||
|
static constexpr uint8_t COMPLETE_BIT = (1 << 0);
|
||||||
|
static constexpr uint8_t PENDING_BIT = (1 << 1);
|
||||||
|
static constexpr uint8_t WAITING_BIT = (1 << 2);
|
||||||
|
|
||||||
|
/// Manages reads and writes to the guard byte.
|
||||||
|
struct GuardByte {
|
||||||
|
GuardByte() = delete;
|
||||||
|
GuardByte(GuardByte const&) = delete;
|
||||||
|
GuardByte& operator=(GuardByte const&) = delete;
|
||||||
|
|
||||||
|
explicit GuardByte(uint8_t* const guard_byte_address) : guard_byte(guard_byte_address) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The guard byte portion of cxa_guard_acquire. Returns true if
|
||||||
|
/// initialization has already been completed.
|
||||||
|
bool acquire() {
|
||||||
|
// if guard_byte is non-zero, we have already completed initialization
|
||||||
|
// (i.e. release has been called)
|
||||||
|
return guard_byte.load(std::_AO_Acquire) != UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The guard byte portion of cxa_guard_release.
|
||||||
|
void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); }
|
||||||
|
|
||||||
|
/// The guard byte portion of cxa_guard_abort.
|
||||||
|
void abort() {} // Nothing to do
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtomicInt<uint8_t> guard_byte;
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// InitByte Implementations
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Each initialization byte implementation supports the following methods:
|
||||||
|
//
|
||||||
|
// InitByte(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
|
||||||
|
// Construct the InitByte object, initializing our member variables
|
||||||
|
//
|
||||||
|
// bool acquire()
|
||||||
|
// Called before we start the initialization. Check if someone else has already started, and if
|
||||||
|
// not to signal our intent to start it ourselves. We determine the current status from the init
|
||||||
|
// byte, which is one of 4 possible values:
|
||||||
|
// COMPLETE: Initialization was finished by somebody else. Return true.
|
||||||
|
// PENDING: Somebody has started the initialization already, set the WAITING bit,
|
||||||
|
// then wait for the init byte to get updated with a new value.
|
||||||
|
// (PENDING|WAITING): Somebody has started the initialization already, and we're not the
|
||||||
|
// first one waiting. Wait for the init byte to get updated.
|
||||||
|
// UNSET: Initialization hasn't successfully completed, and nobody is currently
|
||||||
|
// performing the initialization. Set the PENDING bit to indicate our
|
||||||
|
// intention to start the initialization, and return false.
|
||||||
|
// The return value indicates whether initialization has already been completed.
|
||||||
|
//
|
||||||
|
// void release()
|
||||||
|
// Called after successfully completing the initialization. Update the init byte to reflect
|
||||||
|
// that, then if anybody else is waiting, wake them up.
|
||||||
|
//
|
||||||
|
// void abort()
|
||||||
|
// Called after an error is thrown during the initialization. Reset the init byte to UNSET to
|
||||||
|
// indicate that we're no longer performing the initialization, then if anybody is waiting, wake
|
||||||
|
// them up so they can try performing the initialization.
|
||||||
|
//
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Single Threaded Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// InitByteNoThreads - Doesn't use any inter-thread synchronization when
|
||||||
|
/// managing reads and writes to the init byte.
|
||||||
|
struct InitByteNoThreads {
|
||||||
|
InitByteNoThreads() = delete;
|
||||||
|
InitByteNoThreads(InitByteNoThreads const&) = delete;
|
||||||
|
InitByteNoThreads& operator=(InitByteNoThreads const&) = delete;
|
||||||
|
|
||||||
|
explicit InitByteNoThreads(uint8_t* _init_byte_address, uint32_t*) : init_byte_address(_init_byte_address) {}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_acquire. Returns true if
|
||||||
|
/// initialization has already been completed.
|
||||||
|
bool acquire() {
|
||||||
|
if (*init_byte_address == COMPLETE_BIT)
|
||||||
|
return true;
|
||||||
|
if (*init_byte_address & PENDING_BIT)
|
||||||
|
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
|
||||||
|
*init_byte_address = PENDING_BIT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_release.
|
||||||
|
void release() { *init_byte_address = COMPLETE_BIT; }
|
||||||
|
/// The init byte portion of cxa_guard_abort.
|
||||||
|
void abort() { *init_byte_address = UNSET; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The address of the byte used during initialization.
|
||||||
|
uint8_t* const init_byte_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Global Mutex Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
struct LibcppMutex;
|
||||||
|
struct LibcppCondVar;
|
||||||
|
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
struct LibcppMutex {
|
||||||
|
LibcppMutex() = default;
|
||||||
|
LibcppMutex(LibcppMutex const&) = delete;
|
||||||
|
LibcppMutex& operator=(LibcppMutex const&) = delete;
|
||||||
|
|
||||||
|
bool lock() { return std::__libcpp_mutex_lock(&mutex); }
|
||||||
|
bool unlock() { return std::__libcpp_mutex_unlock(&mutex); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct LibcppCondVar;
|
||||||
|
std::__libcpp_mutex_t mutex = _LIBCPP_MUTEX_INITIALIZER;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LibcppCondVar {
|
||||||
|
LibcppCondVar() = default;
|
||||||
|
LibcppCondVar(LibcppCondVar const&) = delete;
|
||||||
|
LibcppCondVar& operator=(LibcppCondVar const&) = delete;
|
||||||
|
|
||||||
|
bool wait(LibcppMutex& mut) { return std::__libcpp_condvar_wait(&cond, &mut.mutex); }
|
||||||
|
bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::__libcpp_condvar_t cond = _LIBCPP_CONDVAR_INITIALIZER;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
struct LibcppMutex {};
|
||||||
|
struct LibcppCondVar {};
|
||||||
|
#endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
|
||||||
|
|
||||||
|
/// InitByteGlobalMutex - Uses a global mutex and condition variable (common to
|
||||||
|
/// all static local variables) to manage reads and writes to the init byte.
|
||||||
|
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
|
||||||
|
uint32_t (*GetThreadID)() = PlatformThreadID>
|
||||||
|
struct InitByteGlobalMutex {
|
||||||
|
|
||||||
|
explicit InitByteGlobalMutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
|
||||||
|
: init_byte_address(_init_byte_address), thread_id_address(_thread_id_address),
|
||||||
|
has_thread_id_support(_thread_id_address != nullptr && GetThreadID != nullptr) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The init byte portion of cxa_guard_acquire. Returns true if
|
||||||
|
/// initialization has already been completed.
|
||||||
|
bool acquire() {
|
||||||
|
LockGuard g("__cxa_guard_acquire");
|
||||||
|
// Check for possible recursive initialization.
|
||||||
|
if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
|
||||||
|
if (*thread_id_address == current_thread_id.get())
|
||||||
|
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the pending bit is not set.
|
||||||
|
while (*init_byte_address & PENDING_BIT) {
|
||||||
|
*init_byte_address |= WAITING_BIT;
|
||||||
|
global_cond.wait(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*init_byte_address == COMPLETE_BIT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (has_thread_id_support)
|
||||||
|
*thread_id_address = current_thread_id.get();
|
||||||
|
|
||||||
|
*init_byte_address = PENDING_BIT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_release.
|
||||||
|
void release() {
|
||||||
|
bool has_waiting;
|
||||||
|
{
|
||||||
|
LockGuard g("__cxa_guard_release");
|
||||||
|
has_waiting = *init_byte_address & WAITING_BIT;
|
||||||
|
*init_byte_address = COMPLETE_BIT;
|
||||||
|
}
|
||||||
|
if (has_waiting) {
|
||||||
|
if (global_cond.broadcast()) {
|
||||||
|
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_release");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_abort.
|
||||||
|
void abort() {
|
||||||
|
bool has_waiting;
|
||||||
|
{
|
||||||
|
LockGuard g("__cxa_guard_abort");
|
||||||
|
if (has_thread_id_support)
|
||||||
|
*thread_id_address = 0;
|
||||||
|
has_waiting = *init_byte_address & WAITING_BIT;
|
||||||
|
*init_byte_address = UNSET;
|
||||||
|
}
|
||||||
|
if (has_waiting) {
|
||||||
|
if (global_cond.broadcast()) {
|
||||||
|
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_abort");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The address of the byte used during initialization.
|
||||||
|
uint8_t* const init_byte_address;
|
||||||
|
/// An optional address storing an identifier for the thread performing initialization.
|
||||||
|
/// It's used to detect recursive initialization.
|
||||||
|
uint32_t* const thread_id_address;
|
||||||
|
|
||||||
|
const bool has_thread_id_support;
|
||||||
|
LazyValue<uint32_t, GetThreadID> current_thread_id;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LockGuard {
|
||||||
|
LockGuard() = delete;
|
||||||
|
LockGuard(LockGuard const&) = delete;
|
||||||
|
LockGuard& operator=(LockGuard const&) = delete;
|
||||||
|
|
||||||
|
explicit LockGuard(const char* calling_func) : calling_func_(calling_func) {
|
||||||
|
if (global_mutex.lock())
|
||||||
|
ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func_);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LockGuard() {
|
||||||
|
if (global_mutex.unlock())
|
||||||
|
ABORT_WITH_MESSAGE("%s failed to release mutex", calling_func_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* const calling_func_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Futex Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if defined(SYS_futex)
|
||||||
|
void PlatformFutexWait(int* addr, int expect) {
|
||||||
|
constexpr int WAIT = 0;
|
||||||
|
syscall(SYS_futex, addr, WAIT, expect, 0);
|
||||||
|
__tsan_acquire(addr);
|
||||||
|
}
|
||||||
|
void PlatformFutexWake(int* addr) {
|
||||||
|
constexpr int WAKE = 1;
|
||||||
|
__tsan_release(addr);
|
||||||
|
syscall(SYS_futex, addr, WAKE, INT_MAX);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
|
||||||
|
constexpr void (*PlatformFutexWake)(int*) = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; }
|
||||||
|
|
||||||
|
/// InitByteFutex - Uses a futex to manage reads and writes to the init byte.
|
||||||
|
template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
|
||||||
|
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
|
||||||
|
struct InitByteFutex {
|
||||||
|
|
||||||
|
explicit InitByteFutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
|
||||||
|
: init_byte(_init_byte_address),
|
||||||
|
has_thread_id_support(_thread_id_address != nullptr && GetThreadIDArg != nullptr),
|
||||||
|
thread_id(_thread_id_address),
|
||||||
|
base_address(reinterpret_cast<int*>(/*_init_byte_address & ~0x3*/ _init_byte_address - 1)) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The init byte portion of cxa_guard_acquire. Returns true if
|
||||||
|
/// initialization has already been completed.
|
||||||
|
bool acquire() {
|
||||||
|
while (true) {
|
||||||
|
uint8_t last_val = UNSET;
|
||||||
|
if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, std::_AO_Acquire)) {
|
||||||
|
if (has_thread_id_support) {
|
||||||
|
thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_val == COMPLETE_BIT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (last_val & PENDING_BIT) {
|
||||||
|
|
||||||
|
// Check for recursive initialization
|
||||||
|
if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
|
||||||
|
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((last_val & WAITING_BIT) == 0) {
|
||||||
|
// This compare exchange can fail for several reasons
|
||||||
|
// (1) another thread finished the whole thing before we got here
|
||||||
|
// (2) another thread set the waiting bit we were trying to thread
|
||||||
|
// (3) another thread had an exception and failed to finish
|
||||||
|
if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT, std::_AO_Acq_Rel, std::_AO_Release)) {
|
||||||
|
// (1) success, via someone else's work!
|
||||||
|
if (last_val == COMPLETE_BIT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// (3) someone else, bailed on doing the work, retry from the start!
|
||||||
|
if (last_val == UNSET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// (2) the waiting bit got set, so we are happy to keep waiting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wait_on_initialization();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_release.
|
||||||
|
void release() {
|
||||||
|
uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
|
||||||
|
if (old & WAITING_BIT)
|
||||||
|
wake_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init byte portion of cxa_guard_abort.
|
||||||
|
void abort() {
|
||||||
|
if (has_thread_id_support)
|
||||||
|
thread_id.store(0, std::_AO_Relaxed);
|
||||||
|
|
||||||
|
uint8_t old = init_byte.exchange(UNSET, std::_AO_Acq_Rel);
|
||||||
|
if (old & WAITING_BIT)
|
||||||
|
wake_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Use the futex to wait on the current guard variable. Futex expects a
|
||||||
|
/// 32-bit 4-byte aligned address as the first argument, so we use the 4-byte
|
||||||
|
/// aligned address that encompasses the init byte (i.e. the address of the
|
||||||
|
/// raw guard object that was passed to __cxa_guard_acquire/release/abort).
|
||||||
|
void wait_on_initialization() { Wait(base_address, expected_value_for_futex(PENDING_BIT | WAITING_BIT)); }
|
||||||
|
void wake_all() { Wake(base_address); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtomicInt<uint8_t> init_byte;
|
||||||
|
|
||||||
|
const bool has_thread_id_support;
|
||||||
|
// Unsafe to use unless has_thread_id_support
|
||||||
|
AtomicInt<uint32_t> thread_id;
|
||||||
|
LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
|
||||||
|
|
||||||
|
/// the 4-byte-aligned address that encompasses the init byte (i.e. the
|
||||||
|
/// address of the raw guard object).
|
||||||
|
int* const base_address;
|
||||||
|
|
||||||
|
/// Create the expected integer value for futex `wait(int* addr, int expected)`.
|
||||||
|
/// We pass the base address as the first argument, So this function creates
|
||||||
|
/// an zero-initialized integer with `b` copied at the correct offset.
|
||||||
|
static int expected_value_for_futex(uint8_t b) {
|
||||||
|
int dest_val = 0;
|
||||||
|
std::memcpy(reinterpret_cast<char*>(&dest_val) + 1, &b, 1);
|
||||||
|
return dest_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(Wait != nullptr && Wake != nullptr, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// GuardObject
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
enum class AcquireResult {
|
||||||
|
INIT_IS_DONE,
|
||||||
|
INIT_IS_PENDING,
|
||||||
|
};
|
||||||
|
constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
|
||||||
|
constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
|
||||||
|
|
||||||
|
/// Co-ordinates between GuardByte and InitByte.
|
||||||
|
template <class InitByteT>
|
||||||
|
struct GuardObject {
|
||||||
|
GuardObject() = delete;
|
||||||
|
GuardObject(GuardObject const&) = delete;
|
||||||
|
GuardObject& operator=(GuardObject const&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GuardByte guard_byte;
|
||||||
|
InitByteT init_byte;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// ARM Constructor
|
||||||
|
explicit GuardObject(uint32_t* raw_guard_object)
|
||||||
|
: guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
|
||||||
|
init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, nullptr) {}
|
||||||
|
|
||||||
|
/// Itanium Constructor
|
||||||
|
explicit GuardObject(uint64_t* raw_guard_object)
|
||||||
|
: guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
|
||||||
|
init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, reinterpret_cast<uint32_t*>(raw_guard_object) + 1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements __cxa_guard_acquire.
|
||||||
|
AcquireResult cxa_guard_acquire() {
|
||||||
|
// Use short-circuit evaluation to avoid calling init_byte.acquire when
|
||||||
|
// guard_byte.acquire returns true. (i.e. don't call it when we know from
|
||||||
|
// the guard byte that initialization has already been completed)
|
||||||
|
if (guard_byte.acquire() || init_byte.acquire())
|
||||||
|
return INIT_IS_DONE;
|
||||||
|
return INIT_IS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements __cxa_guard_release.
|
||||||
|
void cxa_guard_release() {
|
||||||
|
// Update guard byte first, so if somebody is woken up by init_byte.release
|
||||||
|
// and comes all the way back around to __cxa_guard_acquire again, they see
|
||||||
|
// it as having completed initialization.
|
||||||
|
guard_byte.release();
|
||||||
|
init_byte.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements __cxa_guard_abort.
|
||||||
|
void cxa_guard_abort() {
|
||||||
|
guard_byte.abort();
|
||||||
|
init_byte.abort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Convenience Classes
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// NoThreadsGuard - Manages initialization without performing any inter-thread
|
||||||
|
/// synchronization.
|
||||||
|
using NoThreadsGuard = GuardObject<InitByteNoThreads>;
|
||||||
|
|
||||||
|
/// GlobalMutexGuard - Manages initialization using a global mutex and
|
||||||
|
/// condition variable.
|
||||||
|
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
|
||||||
|
uint32_t (*GetThreadID)() = PlatformThreadID>
|
||||||
|
using GlobalMutexGuard = GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond, GetThreadID>>;
|
||||||
|
|
||||||
|
/// FutexGuard - Manages initialization using atomics and the futex syscall for
|
||||||
|
/// waiting and waking.
|
||||||
|
template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
|
||||||
|
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
|
||||||
|
using FutexGuard = GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>>;
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct GlobalStatic {
|
||||||
|
static T instance;
|
||||||
|
};
|
||||||
|
template <class T>
|
||||||
|
_LIBCPP_CONSTINIT T GlobalStatic<T>::instance = {};
|
||||||
|
|
||||||
|
enum class Implementation { NoThreads, GlobalMutex, Futex };
|
||||||
|
|
||||||
|
template <Implementation Impl>
|
||||||
|
struct SelectImplementation;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct SelectImplementation<Implementation::NoThreads> {
|
||||||
|
using type = NoThreadsGuard;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct SelectImplementation<Implementation::GlobalMutex> {
|
||||||
|
using type = GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
|
||||||
|
GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct SelectImplementation<Implementation::Futex> {
|
||||||
|
using type = FutexGuard<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO(EricWF): We should prefer the futex implementation when available. But
|
||||||
|
// it should be done in a separate step from adding the implementation.
|
||||||
|
constexpr Implementation CurrentImplementation =
|
||||||
|
#if defined(_LIBCXXABI_HAS_NO_THREADS)
|
||||||
|
Implementation::NoThreads;
|
||||||
|
#elif defined(_LIBCXXABI_USE_FUTEX)
|
||||||
|
Implementation::Futex;
|
||||||
|
#else
|
||||||
|
Implementation::GlobalMutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(),
|
||||||
|
"Futex selected but not supported");
|
||||||
|
|
||||||
|
using SelectedImplementation = SelectImplementation<CurrentImplementation>::type;
|
||||||
|
|
||||||
|
} // end namespace
|
||||||
|
} // end namespace __cxxabiv1
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
|
101
third_party/libcxxabi/cxa_handlers.cc
vendored
Normal file
101
third_party/libcxxabi/cxa_handlers.cc
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the functionality associated with the terminate_handler,
|
||||||
|
// unexpected_handler, and new_handler.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxx/stdexcept"
|
||||||
|
#include "third_party/libcxx/new"
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxxabi/cxa_handlers.h"
|
||||||
|
#include "third_party/libcxxabi/cxa_exception.h"
|
||||||
|
#include "third_party/libcxxabi/private_typeinfo.h"
|
||||||
|
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
unexpected_handler
|
||||||
|
get_unexpected() noexcept
|
||||||
|
{
|
||||||
|
return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__unexpected(unexpected_handler func)
|
||||||
|
{
|
||||||
|
func();
|
||||||
|
// unexpected handler should not return
|
||||||
|
abort_message("unexpected_handler unexpectedly returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
void
|
||||||
|
unexpected()
|
||||||
|
{
|
||||||
|
__unexpected(get_unexpected());
|
||||||
|
}
|
||||||
|
|
||||||
|
terminate_handler
|
||||||
|
get_terminate() noexcept
|
||||||
|
{
|
||||||
|
return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__terminate(terminate_handler func) noexcept
|
||||||
|
{
|
||||||
|
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif // _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
func();
|
||||||
|
// handler should not return
|
||||||
|
abort_message("terminate_handler unexpectedly returned");
|
||||||
|
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// handler should not throw exception
|
||||||
|
abort_message("terminate_handler unexpectedly threw an exception");
|
||||||
|
}
|
||||||
|
#endif // _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
void
|
||||||
|
terminate() noexcept
|
||||||
|
{
|
||||||
|
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
// If there might be an uncaught exception
|
||||||
|
using namespace __cxxabiv1;
|
||||||
|
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||||
|
if (globals)
|
||||||
|
{
|
||||||
|
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||||
|
if (exception_header)
|
||||||
|
{
|
||||||
|
_Unwind_Exception* unwind_exception =
|
||||||
|
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
|
||||||
|
if (__isOurExceptionClass(unwind_exception))
|
||||||
|
__terminate(exception_header->terminateHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
__terminate(get_terminate());
|
||||||
|
}
|
||||||
|
|
||||||
|
new_handler
|
||||||
|
get_new_handler() noexcept
|
||||||
|
{
|
||||||
|
return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // std
|
55
third_party/libcxxabi/cxa_handlers.h
vendored
Normal file
55
third_party/libcxxabi/cxa_handlers.h
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the functionality associated with the terminate_handler,
|
||||||
|
// unexpected_handler, and new_handler.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef _CXA_HANDLERS_H
|
||||||
|
#define _CXA_HANDLERS_H
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
|
||||||
|
void
|
||||||
|
__unexpected(unexpected_handler func);
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
|
||||||
|
void
|
||||||
|
__terminate(terminate_handler func) noexcept;
|
||||||
|
|
||||||
|
} // std
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)();
|
||||||
|
_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)();
|
||||||
|
_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)();
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
At some point in the future these three symbols will become
|
||||||
|
C++11 atomic variables:
|
||||||
|
|
||||||
|
extern std::atomic<std::terminate_handler> __cxa_terminate_handler;
|
||||||
|
extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler;
|
||||||
|
extern std::atomic<std::new_handler> __cxa_new_handler;
|
||||||
|
|
||||||
|
This change will not impact their ABI. But it will allow for a
|
||||||
|
portable performance optimization.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // _CXA_HANDLERS_H
|
1315
third_party/libcxxabi/cxa_personality.cc
vendored
Normal file
1315
third_party/libcxxabi/cxa_personality.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
145
third_party/libcxxabi/cxa_thread_atexit.cc
vendored
Normal file
145
third_party/libcxxabi/cxa_thread_atexit.cc
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxx/__threading_support"
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||||
|
#pragma comment(lib, "pthread")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "libc/isystem/stdlib.h"
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
using Dtor = void(*)(void*);
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||||
|
// A weak symbol is used to detect this function's presence in the C library
|
||||||
|
// at runtime, even if libc++ is built against an older libc
|
||||||
|
_LIBCXXABI_WEAK
|
||||||
|
#endif
|
||||||
|
int __cxa_thread_atexit_impl(Dtor, void*, void*);
|
||||||
|
|
||||||
|
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// This implementation is used if the C library does not provide
|
||||||
|
// __cxa_thread_atexit_impl() for us. It has a number of limitations that are
|
||||||
|
// difficult to impossible to address without ..._impl():
|
||||||
|
//
|
||||||
|
// - dso_symbol is ignored. This means that a shared library may be unloaded
|
||||||
|
// (via dlclose()) before its thread_local destructors have run.
|
||||||
|
//
|
||||||
|
// - thread_local destructors for the main thread are run by the destructor of
|
||||||
|
// a static object. This is later than expected; they should run before the
|
||||||
|
// destructors of any objects with static storage duration.
|
||||||
|
//
|
||||||
|
// - thread_local destructors on non-main threads run on the first iteration
|
||||||
|
// through the __libccpp_tls_key destructors.
|
||||||
|
// std::notify_all_at_thread_exit() and similar functions must be careful to
|
||||||
|
// wait until the second iteration to provide their intended ordering
|
||||||
|
// guarantees.
|
||||||
|
//
|
||||||
|
// Another limitation, though one shared with ..._impl(), is that any
|
||||||
|
// thread_locals that are first initialized after non-thread_local global
|
||||||
|
// destructors begin to run will not be destroyed. [basic.start.term] states
|
||||||
|
// that all thread_local destructors are sequenced before the destruction of
|
||||||
|
// objects with static storage duration, resulting in a contradiction if a
|
||||||
|
// thread_local is constructed after that point. Thus we consider such
|
||||||
|
// programs ill-formed, and don't bother to run those destructors. (If the
|
||||||
|
// program terminates abnormally after such a thread_local is constructed,
|
||||||
|
// the destructor is not expected to run and thus there is no contradiction.
|
||||||
|
// So construction still has to work.)
|
||||||
|
|
||||||
|
struct DtorList {
|
||||||
|
Dtor dtor;
|
||||||
|
void* obj;
|
||||||
|
DtorList* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The linked list of thread-local destructors to run
|
||||||
|
__thread DtorList* dtors = nullptr;
|
||||||
|
// True if the destructors are currently scheduled to run on this thread
|
||||||
|
__thread bool dtors_alive = false;
|
||||||
|
// Used to trigger destructors on thread exit; value is ignored
|
||||||
|
std::__libcpp_tls_key dtors_key;
|
||||||
|
|
||||||
|
void run_dtors(void*) {
|
||||||
|
while (auto head = dtors) {
|
||||||
|
dtors = head->next;
|
||||||
|
head->dtor(head->obj);
|
||||||
|
::free(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtors_alive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DtorsManager {
|
||||||
|
DtorsManager() {
|
||||||
|
// There is intentionally no matching std::__libcpp_tls_delete call, as
|
||||||
|
// __cxa_thread_atexit() may be called arbitrarily late (for example, from
|
||||||
|
// global destructors or atexit() handlers).
|
||||||
|
if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
|
||||||
|
abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~DtorsManager() {
|
||||||
|
// std::__libcpp_tls_key destructors do not run on threads that call exit()
|
||||||
|
// (including when the main thread returns from main()), so we explicitly
|
||||||
|
// call the destructor here. This runs at exit time (potentially earlier
|
||||||
|
// if libc++abi is dlclose()'d). Any thread_locals initialized after this
|
||||||
|
// point will not be destroyed.
|
||||||
|
run_dtors(nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
|
||||||
|
#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||||
|
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
|
||||||
|
#else
|
||||||
|
if (__cxa_thread_atexit_impl) {
|
||||||
|
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
|
||||||
|
} else {
|
||||||
|
// Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
|
||||||
|
// one-time initialization and __cxa_atexit() for destruction)
|
||||||
|
static DtorsManager manager;
|
||||||
|
|
||||||
|
if (!dtors_alive) {
|
||||||
|
if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dtors_alive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto head = static_cast<DtorList*>(::malloc(sizeof(DtorList)));
|
||||||
|
if (!head) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
head->dtor = dtor;
|
||||||
|
head->obj = obj;
|
||||||
|
head->next = dtors;
|
||||||
|
dtors = head;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace __cxxabiv1
|
421
third_party/libcxxabi/cxa_vector.cc
vendored
Normal file
421
third_party/libcxxabi/cxa_vector.cc
vendored
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This file implements the "Array Construction and Destruction APIs"
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/exception" // for std::terminate
|
||||||
|
#include "third_party/libcxx/new" // for std::bad_array_new_length
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
|
||||||
|
#ifndef __has_builtin
|
||||||
|
#define __has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helper routines and classes
|
||||||
|
//
|
||||||
|
|
||||||
|
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_ ;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Externally visible routines
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
_LIBCXXABI_NORETURN
|
||||||
|
void throw_bad_array_new_length() {
|
||||||
|
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
throw std::bad_array_new_length();
|
||||||
|
#else
|
||||||
|
abort_message("__cxa_vec_new failed to allocate memory");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mul_overflow(size_t x, size_t y, size_t *res) {
|
||||||
|
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
|
||||||
|
|| defined(_LIBCXXABI_COMPILER_GCC)
|
||||||
|
return __builtin_mul_overflow(x, y, res);
|
||||||
|
#else
|
||||||
|
*res = x * y;
|
||||||
|
return x && ((*res / x) != y);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool add_overflow(size_t x, size_t y, size_t *res) {
|
||||||
|
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
|
||||||
|
|| defined(_LIBCXXABI_COMPILER_GCC)
|
||||||
|
return __builtin_add_overflow(x, y, res);
|
||||||
|
#else
|
||||||
|
*res = x + y;
|
||||||
|
return *res < y;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t calculate_allocation_size_or_throw(size_t element_count,
|
||||||
|
size_t element_size,
|
||||||
|
size_t padding_size) {
|
||||||
|
size_t element_heap_size;
|
||||||
|
if (mul_overflow(element_count, element_size, &element_heap_size))
|
||||||
|
throw_bad_array_new_length();
|
||||||
|
|
||||||
|
size_t allocation_size;
|
||||||
|
if (add_overflow(element_heap_size, padding_size, &allocation_size))
|
||||||
|
throw_bad_array_new_length();
|
||||||
|
|
||||||
|
return allocation_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Equivalent to
|
||||||
|
//
|
||||||
|
// __cxa_vec_new2(element_count, element_size, padding_size, constructor,
|
||||||
|
// destructor, &::operator new[], &::operator delete[])
|
||||||
|
_LIBCXXABI_FUNC_VIS void *
|
||||||
|
__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
|
||||||
|
void (*constructor)(void *), void (*destructor)(void *)) {
|
||||||
|
return __cxa_vec_new2 ( element_count, element_size, padding_size,
|
||||||
|
constructor, destructor, &::operator new [], &::operator delete [] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Given the number and size of elements for an array and the non-negative
|
||||||
|
// size of prefix padding for a cookie, allocate space (using alloc) for
|
||||||
|
// the array preceded by the specified padding, initialize the cookie if
|
||||||
|
// the padding is non-zero, and call the given constructor on each element.
|
||||||
|
// Return the address of the array proper, after the padding.
|
||||||
|
//
|
||||||
|
// If alloc throws an exception, rethrow the exception. If alloc returns
|
||||||
|
// NULL, return NULL. If the constructor throws an exception, call
|
||||||
|
// destructor for any already constructed elements, and rethrow the
|
||||||
|
// exception. If the destructor throws an exception, call std::terminate.
|
||||||
|
//
|
||||||
|
// The constructor may be NULL, in which case it must not be called. If the
|
||||||
|
// padding_size is zero, the destructor may be NULL; in that case it must
|
||||||
|
// not be called.
|
||||||
|
//
|
||||||
|
// Neither alloc nor dealloc may be NULL.
|
||||||
|
_LIBCXXABI_FUNC_VIS void *
|
||||||
|
__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
|
||||||
|
void (*constructor)(void *), void (*destructor)(void *),
|
||||||
|
void *(*alloc)(size_t), void (*dealloc)(void *)) {
|
||||||
|
const size_t heap_size = calculate_allocation_size_or_throw(
|
||||||
|
element_count, element_size, padding_size);
|
||||||
|
char* const heap_block = static_cast<char*>(alloc(heap_size));
|
||||||
|
char* vec_base = heap_block;
|
||||||
|
|
||||||
|
if (NULL != vec_base) {
|
||||||
|
st_heap_block2 heap(dealloc, heap_block);
|
||||||
|
|
||||||
|
// put the padding before the array elements
|
||||||
|
if ( 0 != padding_size ) {
|
||||||
|
vec_base += padding_size;
|
||||||
|
__set_element_count ( vec_base, element_count );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the elements
|
||||||
|
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
|
||||||
|
heap.release (); // We're good!
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Same as __cxa_vec_new2 except that the deallocation function takes both
|
||||||
|
// the object address and its size.
|
||||||
|
_LIBCXXABI_FUNC_VIS void *
|
||||||
|
__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
|
||||||
|
void (*constructor)(void *), void (*destructor)(void *),
|
||||||
|
void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
|
||||||
|
const size_t heap_size = calculate_allocation_size_or_throw(
|
||||||
|
element_count, element_size, padding_size);
|
||||||
|
char* const heap_block = static_cast<char*>(alloc(heap_size));
|
||||||
|
char* vec_base = heap_block;
|
||||||
|
|
||||||
|
if (NULL != vec_base) {
|
||||||
|
st_heap_block3 heap(dealloc, heap_block, heap_size);
|
||||||
|
|
||||||
|
// put the padding before the array elements
|
||||||
|
if ( 0 != padding_size ) {
|
||||||
|
vec_base += padding_size;
|
||||||
|
__set_element_count ( vec_base, element_count );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the elements
|
||||||
|
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
|
||||||
|
heap.release (); // We're good!
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Given the (data) addresses of a destination and a source array, an
|
||||||
|
// element count and an element size, call the given copy constructor to
|
||||||
|
// copy each element from the source array to the destination array. The
|
||||||
|
// copy constructor's arguments are the destination address and source
|
||||||
|
// address, respectively. If an exception occurs, call the given destructor
|
||||||
|
// (if non-NULL) on each copied element and rethrow. If the destructor
|
||||||
|
// throws an exception, call terminate(). The constructor and or destructor
|
||||||
|
// pointers may be NULL. If either is NULL, no action is taken when it
|
||||||
|
// would have been called.
|
||||||
|
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
|
||||||
|
size_t element_count,
|
||||||
|
size_t element_size,
|
||||||
|
void (*constructor)(void *, void *),
|
||||||
|
void (*destructor)(void *)) {
|
||||||
|
if ( NULL != constructor ) {
|
||||||
|
size_t idx = 0;
|
||||||
|
char *src_ptr = static_cast<char *>(src_array);
|
||||||
|
char *dest_ptr = static_cast<char *>(dest_array);
|
||||||
|
st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
|
||||||
|
|
||||||
|
for ( idx = 0; idx < element_count;
|
||||||
|
++idx, src_ptr += element_size, dest_ptr += element_size )
|
||||||
|
constructor ( dest_ptr, src_ptr );
|
||||||
|
cleanup.release (); // We're good!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Given the (data) address of an array, not including any cookie padding,
|
||||||
|
// and the number and size of its elements, call the given constructor on
|
||||||
|
// each element. If the constructor throws an exception, call the given
|
||||||
|
// destructor for any already-constructed elements, and rethrow the
|
||||||
|
// exception. If the destructor throws an exception, call terminate(). The
|
||||||
|
// constructor and/or destructor pointers may be NULL. If either is NULL,
|
||||||
|
// no action is taken when it would have been called.
|
||||||
|
_LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
|
||||||
|
void (*constructor)(void *), void (*destructor)(void *)) {
|
||||||
|
if ( NULL != constructor ) {
|
||||||
|
size_t idx;
|
||||||
|
char *ptr = static_cast <char *> ( array_address );
|
||||||
|
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
|
||||||
|
|
||||||
|
// Construct the elements
|
||||||
|
for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
|
||||||
|
constructor ( ptr );
|
||||||
|
cleanup.release (); // We're good!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the (data) address of an array, the number of elements, and the
|
||||||
|
// size of its elements, call the given destructor on each element. If the
|
||||||
|
// destructor throws an exception, rethrow after destroying the remaining
|
||||||
|
// elements if possible. If the destructor throws a second exception, call
|
||||||
|
// terminate(). The destructor pointer may be NULL, in which case this
|
||||||
|
// routine does nothing.
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
|
||||||
|
size_t element_count,
|
||||||
|
size_t element_size,
|
||||||
|
void (*destructor)(void *)) {
|
||||||
|
if ( NULL != destructor ) {
|
||||||
|
char *ptr = static_cast <char *> (array_address);
|
||||||
|
size_t idx = element_count;
|
||||||
|
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
|
||||||
|
{
|
||||||
|
st_terminate exception_guard (__cxa_uncaught_exception ());
|
||||||
|
ptr += element_count * element_size; // one past the last element
|
||||||
|
|
||||||
|
while ( idx-- > 0 ) {
|
||||||
|
ptr -= element_size;
|
||||||
|
destructor ( ptr );
|
||||||
|
}
|
||||||
|
exception_guard.release (); // We're good !
|
||||||
|
}
|
||||||
|
cleanup.release (); // We're still good!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the (data) address of an array, the number of elements, and the
|
||||||
|
// size of its elements, call the given destructor on each element. If the
|
||||||
|
// destructor throws an exception, call terminate(). The destructor pointer
|
||||||
|
// may be NULL, in which case this routine does nothing.
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
|
||||||
|
size_t element_count,
|
||||||
|
size_t element_size,
|
||||||
|
void (*destructor)(void *)) {
|
||||||
|
if ( NULL != destructor ) {
|
||||||
|
char *ptr = static_cast <char *> (array_address);
|
||||||
|
size_t idx = element_count;
|
||||||
|
st_terminate exception_guard;
|
||||||
|
|
||||||
|
ptr += element_count * element_size; // one past the last element
|
||||||
|
while ( idx-- > 0 ) {
|
||||||
|
ptr -= element_size;
|
||||||
|
destructor ( ptr );
|
||||||
|
}
|
||||||
|
exception_guard.release (); // We're done!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the array_address is NULL, return immediately. Otherwise, given the
|
||||||
|
// (data) address of an array, the non-negative size of prefix padding for
|
||||||
|
// the cookie, and the size of its elements, call the given destructor on
|
||||||
|
// each element, using the cookie to determine the number of elements, and
|
||||||
|
// then delete the space by calling ::operator delete[](void *). If the
|
||||||
|
// destructor throws an exception, rethrow after (a) destroying the
|
||||||
|
// remaining elements, and (b) deallocating the storage. If the destructor
|
||||||
|
// throws a second exception, call terminate(). If padding_size is 0, the
|
||||||
|
// destructor pointer must be NULL. If the destructor pointer is NULL, no
|
||||||
|
// destructor call is to be made.
|
||||||
|
//
|
||||||
|
// The intent of this function is to permit an implementation to call this
|
||||||
|
// function when confronted with an expression of the form delete[] p in
|
||||||
|
// the source code, provided that the default deallocation function can be
|
||||||
|
// used. Therefore, the semantics of this function are consistent with
|
||||||
|
// those required by the standard. The requirement that the deallocation
|
||||||
|
// function be called even if the destructor throws an exception derives
|
||||||
|
// from the resolution to DR 353 to the C++ standard, which was adopted in
|
||||||
|
// April, 2003.
|
||||||
|
_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
|
||||||
|
size_t element_size,
|
||||||
|
size_t padding_size,
|
||||||
|
void (*destructor)(void *)) {
|
||||||
|
__cxa_vec_delete2 ( array_address, element_size, padding_size,
|
||||||
|
destructor, &::operator delete [] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as __cxa_vec_delete, except that the given function is used for
|
||||||
|
// deallocation instead of the default delete function. If dealloc throws
|
||||||
|
// an exception, the result is undefined. The dealloc pointer may not be
|
||||||
|
// NULL.
|
||||||
|
_LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
|
||||||
|
void (*destructor)(void *), void (*dealloc)(void *)) {
|
||||||
|
if ( NULL != array_address ) {
|
||||||
|
char *vec_base = static_cast <char *> (array_address);
|
||||||
|
char *heap_block = vec_base - padding_size;
|
||||||
|
st_heap_block2 heap ( dealloc, heap_block );
|
||||||
|
|
||||||
|
if ( 0 != padding_size && NULL != destructor ) // call the destructors
|
||||||
|
__cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
|
||||||
|
element_size, destructor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Same as __cxa_vec_delete, except that the given function is used for
|
||||||
|
// deallocation instead of the default delete function. The deallocation
|
||||||
|
// function takes both the object address and its size. If dealloc throws
|
||||||
|
// an exception, the result is undefined. The dealloc pointer may not be
|
||||||
|
// NULL.
|
||||||
|
_LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
|
||||||
|
void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
|
||||||
|
if ( NULL != array_address ) {
|
||||||
|
char *vec_base = static_cast <char *> (array_address);
|
||||||
|
char *heap_block = vec_base - padding_size;
|
||||||
|
const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
|
||||||
|
const size_t heap_block_size = element_size * element_count + padding_size;
|
||||||
|
st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
|
||||||
|
|
||||||
|
if ( 0 != padding_size && NULL != destructor ) // call the destructors
|
||||||
|
__cxa_vec_dtor ( array_address, element_count, element_size, destructor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
} // abi
|
24
third_party/libcxxabi/cxa_virtual.cc
vendored
Normal file
24
third_party/libcxxabi/cxa_virtual.cc
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/cxxabi.h"
|
||||||
|
#include "third_party/libcxxabi/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
|
105
third_party/libcxxabi/demangle/DemangleConfig.h
vendored
Normal file
105
third_party/libcxxabi/demangle/DemangleConfig.h
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
//===--- DemangleConfig.h --------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
// This file is contains a subset of macros copied from
|
||||||
|
// llvm/include/llvm/Demangle/DemangleConfig.h
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
|
||||||
|
#define LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
|
||||||
|
|
||||||
|
// Must be defined before pulling in headers from libc++. Allow downstream
|
||||||
|
// build systems to override this value.
|
||||||
|
// https://libcxx.llvm.org/UsingLibcxx.html#enabling-the-safe-libc-mode
|
||||||
|
#ifndef _LIBCPP_VERBOSE_ABORT
|
||||||
|
#define _LIBCPP_VERBOSE_ABORT(...) abort_message(__VA_ARGS__)
|
||||||
|
#include "third_party/libcxxabi/abort_message.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "third_party/libcxx/ciso646"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// snprintf is implemented in VS 2015
|
||||||
|
#if _MSC_VER < 1900
|
||||||
|
#define snprintf _snprintf_s
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_cpp_attribute
|
||||||
|
#define __has_cpp_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_attribute
|
||||||
|
#define __has_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_builtin
|
||||||
|
#define __has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEMANGLE_GNUC_PREREQ
|
||||||
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||||
|
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
|
||||||
|
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
||||||
|
((maj) << 20) + ((min) << 10) + (patch))
|
||||||
|
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||||
|
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
|
||||||
|
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
|
||||||
|
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_ATTRIBUTE_USED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
|
||||||
|
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define DEMANGLE_UNREACHABLE __assume(false)
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_UNREACHABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
|
||||||
|
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_ATTRIBUTE_NOINLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
|
||||||
|
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
|
||||||
|
#elif __has_cpp_attribute(gnu::fallthrough)
|
||||||
|
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
|
||||||
|
#elif !__cplusplus
|
||||||
|
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
|
||||||
|
// error when __has_cpp_attribute is given a scoped attribute in C mode.
|
||||||
|
#define DEMANGLE_FALLTHROUGH
|
||||||
|
#elif __has_cpp_attribute(clang::fallthrough)
|
||||||
|
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
|
||||||
|
#else
|
||||||
|
#define DEMANGLE_FALLTHROUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
|
||||||
|
#define DEMANGLE_NAMESPACE_END } }
|
||||||
|
|
||||||
|
#endif // LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
|
5520
third_party/libcxxabi/demangle/ItaniumDemangle.h
vendored
Normal file
5520
third_party/libcxxabi/demangle/ItaniumDemangle.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
95
third_party/libcxxabi/demangle/ItaniumNodes.def
vendored
Normal file
95
third_party/libcxxabi/demangle/ItaniumNodes.def
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
//===------------------------- ItaniumNodes.def ----------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Define the demangler's node names
|
||||||
|
|
||||||
|
#ifndef NODE
|
||||||
|
#error Define NODE to handle nodes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NODE(NodeArrayNode)
|
||||||
|
NODE(DotSuffix)
|
||||||
|
NODE(VendorExtQualType)
|
||||||
|
NODE(QualType)
|
||||||
|
NODE(ConversionOperatorType)
|
||||||
|
NODE(PostfixQualifiedType)
|
||||||
|
NODE(ElaboratedTypeSpefType)
|
||||||
|
NODE(NameType)
|
||||||
|
NODE(AbiTagAttr)
|
||||||
|
NODE(EnableIfAttr)
|
||||||
|
NODE(ObjCProtoName)
|
||||||
|
NODE(PointerType)
|
||||||
|
NODE(ReferenceType)
|
||||||
|
NODE(PointerToMemberType)
|
||||||
|
NODE(ArrayType)
|
||||||
|
NODE(FunctionType)
|
||||||
|
NODE(NoexceptSpec)
|
||||||
|
NODE(DynamicExceptionSpec)
|
||||||
|
NODE(FunctionEncoding)
|
||||||
|
NODE(LiteralOperator)
|
||||||
|
NODE(SpecialName)
|
||||||
|
NODE(CtorVtableSpecialName)
|
||||||
|
NODE(QualifiedName)
|
||||||
|
NODE(NestedName)
|
||||||
|
NODE(LocalName)
|
||||||
|
NODE(ModuleName)
|
||||||
|
NODE(ModuleEntity)
|
||||||
|
NODE(VectorType)
|
||||||
|
NODE(PixelVectorType)
|
||||||
|
NODE(BinaryFPType)
|
||||||
|
NODE(BitIntType)
|
||||||
|
NODE(SyntheticTemplateParamName)
|
||||||
|
NODE(TypeTemplateParamDecl)
|
||||||
|
NODE(NonTypeTemplateParamDecl)
|
||||||
|
NODE(TemplateTemplateParamDecl)
|
||||||
|
NODE(TemplateParamPackDecl)
|
||||||
|
NODE(ParameterPack)
|
||||||
|
NODE(TemplateArgumentPack)
|
||||||
|
NODE(ParameterPackExpansion)
|
||||||
|
NODE(TemplateArgs)
|
||||||
|
NODE(ForwardTemplateReference)
|
||||||
|
NODE(NameWithTemplateArgs)
|
||||||
|
NODE(GlobalQualifiedName)
|
||||||
|
NODE(ExpandedSpecialSubstitution)
|
||||||
|
NODE(SpecialSubstitution)
|
||||||
|
NODE(CtorDtorName)
|
||||||
|
NODE(DtorName)
|
||||||
|
NODE(UnnamedTypeName)
|
||||||
|
NODE(ClosureTypeName)
|
||||||
|
NODE(StructuredBindingName)
|
||||||
|
NODE(BinaryExpr)
|
||||||
|
NODE(ArraySubscriptExpr)
|
||||||
|
NODE(PostfixExpr)
|
||||||
|
NODE(ConditionalExpr)
|
||||||
|
NODE(MemberExpr)
|
||||||
|
NODE(SubobjectExpr)
|
||||||
|
NODE(EnclosingExpr)
|
||||||
|
NODE(CastExpr)
|
||||||
|
NODE(SizeofParamPackExpr)
|
||||||
|
NODE(CallExpr)
|
||||||
|
NODE(NewExpr)
|
||||||
|
NODE(DeleteExpr)
|
||||||
|
NODE(PrefixExpr)
|
||||||
|
NODE(FunctionParam)
|
||||||
|
NODE(ConversionExpr)
|
||||||
|
NODE(PointerToMemberConversionExpr)
|
||||||
|
NODE(InitListExpr)
|
||||||
|
NODE(FoldExpr)
|
||||||
|
NODE(ThrowExpr)
|
||||||
|
NODE(BoolExpr)
|
||||||
|
NODE(StringLiteral)
|
||||||
|
NODE(LambdaExpr)
|
||||||
|
NODE(EnumLiteral)
|
||||||
|
NODE(IntegerLiteral)
|
||||||
|
NODE(FloatLiteral)
|
||||||
|
NODE(DoubleLiteral)
|
||||||
|
NODE(LongDoubleLiteral)
|
||||||
|
NODE(BracedExpr)
|
||||||
|
NODE(BracedRangeExpr)
|
||||||
|
|
||||||
|
#undef NODE
|
38
third_party/libcxxabi/demangle/StringViewExtras.h
vendored
Normal file
38
third_party/libcxxabi/demangle/StringViewExtras.h
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//===--- StringViewExtras.h -------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// There are two copies of this file in the source tree. The one under
|
||||||
|
// libcxxabi is the original and the one under llvm is the copy. Use
|
||||||
|
// cp-to-llvm.sh to update the copy. See README.txt for more details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef DEMANGLE_STRINGVIEW_H
|
||||||
|
#define DEMANGLE_STRINGVIEW_H
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/string_view"
|
||||||
|
|
||||||
|
DEMANGLE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
inline bool starts_with(std::string_view self, char C) noexcept {
|
||||||
|
return !self.empty() && *self.begin() == C;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool starts_with(std::string_view haystack,
|
||||||
|
std::string_view needle) noexcept {
|
||||||
|
if (needle.size() > haystack.size())
|
||||||
|
return false;
|
||||||
|
haystack.remove_suffix(haystack.size() - needle.size());
|
||||||
|
return haystack == needle;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEMANGLE_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
205
third_party/libcxxabi/demangle/Utility.h
vendored
Normal file
205
third_party/libcxxabi/demangle/Utility.h
vendored
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Provide some utility classes for use in the demangler.
|
||||||
|
// There are two copies of this file in the source tree. The one in libcxxabi
|
||||||
|
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
|
||||||
|
// the copy. See README.txt for more details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef DEMANGLE_UTILITY_H
|
||||||
|
#define DEMANGLE_UTILITY_H
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/array"
|
||||||
|
#include "third_party/libcxx/cassert"
|
||||||
|
#include "third_party/libcxx/cstdint"
|
||||||
|
#include "third_party/libcxx/cstdlib"
|
||||||
|
#include "third_party/libcxx/cstring"
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
#include "third_party/libcxx/limits"
|
||||||
|
#include "third_party/libcxx/string_view"
|
||||||
|
|
||||||
|
DEMANGLE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// Stream that AST nodes write their string representation into after the AST
|
||||||
|
// has been parsed.
|
||||||
|
class OutputBuffer {
|
||||||
|
char *Buffer = nullptr;
|
||||||
|
size_t CurrentPosition = 0;
|
||||||
|
size_t BufferCapacity = 0;
|
||||||
|
|
||||||
|
// Ensure there are at least N more positions in the buffer.
|
||||||
|
void grow(size_t N) {
|
||||||
|
size_t Need = N + CurrentPosition;
|
||||||
|
if (Need > BufferCapacity) {
|
||||||
|
// Reduce the number of reallocations, with a bit of hysteresis. The
|
||||||
|
// number here is chosen so the first allocation will more-than-likely not
|
||||||
|
// allocate more than 1K.
|
||||||
|
Need += 1024 - 32;
|
||||||
|
BufferCapacity *= 2;
|
||||||
|
if (BufferCapacity < Need)
|
||||||
|
BufferCapacity = Need;
|
||||||
|
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
||||||
|
if (Buffer == nullptr)
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
|
||||||
|
std::array<char, 21> Temp;
|
||||||
|
char *TempPtr = Temp.data() + Temp.size();
|
||||||
|
|
||||||
|
// Output at least one character.
|
||||||
|
do {
|
||||||
|
*--TempPtr = char('0' + N % 10);
|
||||||
|
N /= 10;
|
||||||
|
} while (N);
|
||||||
|
|
||||||
|
// Add negative sign.
|
||||||
|
if (isNeg)
|
||||||
|
*--TempPtr = '-';
|
||||||
|
|
||||||
|
return operator+=(
|
||||||
|
std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
OutputBuffer(char *StartBuf, size_t Size)
|
||||||
|
: Buffer(StartBuf), BufferCapacity(Size) {}
|
||||||
|
OutputBuffer(char *StartBuf, size_t *SizePtr)
|
||||||
|
: OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
|
||||||
|
OutputBuffer() = default;
|
||||||
|
// Non-copyable
|
||||||
|
OutputBuffer(const OutputBuffer &) = delete;
|
||||||
|
OutputBuffer &operator=(const OutputBuffer &) = delete;
|
||||||
|
|
||||||
|
operator std::string_view() const {
|
||||||
|
return std::string_view(Buffer, CurrentPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
|
||||||
|
/// into the pack that we're currently printing.
|
||||||
|
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
|
||||||
|
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
|
||||||
|
|
||||||
|
/// When zero, we're printing template args and '>' needs to be parenthesized.
|
||||||
|
/// Use a counter so we can simply increment inside parentheses.
|
||||||
|
unsigned GtIsGt = 1;
|
||||||
|
|
||||||
|
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
|
||||||
|
|
||||||
|
void printOpen(char Open = '(') {
|
||||||
|
GtIsGt++;
|
||||||
|
*this += Open;
|
||||||
|
}
|
||||||
|
void printClose(char Close = ')') {
|
||||||
|
GtIsGt--;
|
||||||
|
*this += Close;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator+=(std::string_view R) {
|
||||||
|
if (size_t Size = R.size()) {
|
||||||
|
grow(Size);
|
||||||
|
std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
|
||||||
|
CurrentPosition += Size;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator+=(char C) {
|
||||||
|
grow(1);
|
||||||
|
Buffer[CurrentPosition++] = C;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &prepend(std::string_view R) {
|
||||||
|
size_t Size = R.size();
|
||||||
|
|
||||||
|
grow(Size);
|
||||||
|
std::memmove(Buffer + Size, Buffer, CurrentPosition);
|
||||||
|
std::memcpy(Buffer, &*R.begin(), Size);
|
||||||
|
CurrentPosition += Size;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(char C) { return (*this += C); }
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(long long N) {
|
||||||
|
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(unsigned long long N) {
|
||||||
|
return writeUnsigned(N, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(long N) {
|
||||||
|
return this->operator<<(static_cast<long long>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(unsigned long N) {
|
||||||
|
return this->operator<<(static_cast<unsigned long long>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(int N) {
|
||||||
|
return this->operator<<(static_cast<long long>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer &operator<<(unsigned int N) {
|
||||||
|
return this->operator<<(static_cast<unsigned long long>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(size_t Pos, const char *S, size_t N) {
|
||||||
|
assert(Pos <= CurrentPosition);
|
||||||
|
if (N == 0)
|
||||||
|
return;
|
||||||
|
grow(N);
|
||||||
|
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
|
||||||
|
std::memcpy(Buffer + Pos, S, N);
|
||||||
|
CurrentPosition += N;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getCurrentPosition() const { return CurrentPosition; }
|
||||||
|
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||||
|
|
||||||
|
char back() const {
|
||||||
|
assert(CurrentPosition);
|
||||||
|
return Buffer[CurrentPosition - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return CurrentPosition == 0; }
|
||||||
|
|
||||||
|
char *getBuffer() { return Buffer; }
|
||||||
|
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
|
||||||
|
size_t getBufferCapacity() const { return BufferCapacity; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class ScopedOverride {
|
||||||
|
T &Loc;
|
||||||
|
T Original;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
|
||||||
|
|
||||||
|
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
|
||||||
|
Loc_ = std::move(NewVal);
|
||||||
|
}
|
||||||
|
~ScopedOverride() { Loc = std::move(Original); }
|
||||||
|
|
||||||
|
ScopedOverride(const ScopedOverride &) = delete;
|
||||||
|
ScopedOverride &operator=(const ScopedOverride &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
DEMANGLE_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
303
third_party/libcxxabi/fallback_malloc.cc
vendored
Normal file
303
third_party/libcxxabi/fallback_malloc.cc
vendored
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/fallback_malloc.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/__threading_support"
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||||
|
#pragma comment(lib, "pthread")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h"
|
||||||
|
#include "libc/isystem/assert.h"
|
||||||
|
#include "libc/isystem/stdlib.h" // for malloc, calloc, free
|
||||||
|
#include "libc/isystem/string.h" // for memset
|
||||||
|
|
||||||
|
// A small, simple heap manager based (loosely) on
|
||||||
|
// the startup heap manager from FreeBSD, optimized for space.
|
||||||
|
//
|
||||||
|
// Manages a fixed-size memory pool, supports malloc and free only.
|
||||||
|
// No support for realloc.
|
||||||
|
//
|
||||||
|
// Allocates chunks in multiples of four bytes, with a four byte header
|
||||||
|
// for each chunk. The overhead of each chunk is kept low by keeping pointers
|
||||||
|
// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// When POSIX threads are not available, make the mutex operations a nop
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
static _LIBCPP_CONSTINIT std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
|
||||||
|
#else
|
||||||
|
static _LIBCPP_CONSTINIT void* heap_mutex = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class mutexor {
|
||||||
|
public:
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
mutexor(std::__libcpp_mutex_t* m) : mtx_(m) {
|
||||||
|
std::__libcpp_mutex_lock(mtx_);
|
||||||
|
}
|
||||||
|
~mutexor() { std::__libcpp_mutex_unlock(mtx_); }
|
||||||
|
#else
|
||||||
|
mutexor(void*) {}
|
||||||
|
~mutexor() {}
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
mutexor(const mutexor& rhs);
|
||||||
|
mutexor& operator=(const mutexor& rhs);
|
||||||
|
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||||
|
std::__libcpp_mutex_t* mtx_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t HEAP_SIZE = 512;
|
||||||
|
char heap[HEAP_SIZE] __attribute__((aligned));
|
||||||
|
|
||||||
|
typedef unsigned short heap_offset;
|
||||||
|
typedef unsigned short heap_size;
|
||||||
|
|
||||||
|
// On both 64 and 32 bit targets heap_node should have the following properties
|
||||||
|
// Size: 4
|
||||||
|
// Alignment: 2
|
||||||
|
struct heap_node {
|
||||||
|
heap_offset next_node; // offset into heap
|
||||||
|
heap_size len; // size in units of "sizeof(heap_node)"
|
||||||
|
};
|
||||||
|
|
||||||
|
// All pointers returned by fallback_malloc must be at least aligned
|
||||||
|
// as RequiredAligned. Note that RequiredAlignment can be greater than
|
||||||
|
// alignof(std::max_align_t) on 64 bit systems compiling 32 bit code.
|
||||||
|
struct FallbackMaxAlignType {
|
||||||
|
} __attribute__((aligned));
|
||||||
|
const size_t RequiredAlignment = alignof(FallbackMaxAlignType);
|
||||||
|
|
||||||
|
static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0,
|
||||||
|
"The required alignment must be evenly divisible by the sizeof(heap_node)");
|
||||||
|
|
||||||
|
// The number of heap_node's that can fit in a chunk of memory with the size
|
||||||
|
// of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4.
|
||||||
|
const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a pointer to the first address, 'A', in `heap` that can actually be
|
||||||
|
// used to represent a heap_node. 'A' must be aligned so that
|
||||||
|
// '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this
|
||||||
|
// address should be 12 bytes after the first 16 byte boundary.
|
||||||
|
heap_node* getFirstAlignedNodeInHeap() {
|
||||||
|
heap_node* node = (heap_node*)heap;
|
||||||
|
const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node);
|
||||||
|
size_t boundaryOffset = reinterpret_cast<size_t>(node) % RequiredAlignment;
|
||||||
|
size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset;
|
||||||
|
size_t NElemOffset = requiredOffset / sizeof(heap_node);
|
||||||
|
return node + NElemOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_heap() {
|
||||||
|
freelist = getFirstAlignedNodeInHeap();
|
||||||
|
freelist->next_node = offset_from_node(list_end);
|
||||||
|
freelist->len = static_cast<heap_size>(list_end - freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
|
||||||
|
// Check the invariant that all heap_nodes pointers 'p' are aligned
|
||||||
|
// so that 'p + 1' has an alignment of at least RequiredAlignment
|
||||||
|
assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0);
|
||||||
|
|
||||||
|
// Calculate the number of extra padding elements needed in order
|
||||||
|
// to split 'p' and create a properly aligned heap_node from the tail
|
||||||
|
// of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems'
|
||||||
|
// will be a multiple of NodesPerAlignment.
|
||||||
|
size_t aligned_nelems = nelems;
|
||||||
|
if (p->len > nelems) {
|
||||||
|
heap_size remaining_len = static_cast<heap_size>(p->len - nelems);
|
||||||
|
aligned_nelems += remaining_len % NodesPerAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chunk is larger and we can create a properly aligned heap_node
|
||||||
|
// from the tail. In this case we shorten 'p' and return the tail.
|
||||||
|
if (p->len > aligned_nelems) {
|
||||||
|
heap_node* q;
|
||||||
|
p->len = static_cast<heap_size>(p->len - aligned_nelems);
|
||||||
|
q = p + p->len;
|
||||||
|
q->next_node = 0;
|
||||||
|
q->len = static_cast<heap_size>(aligned_nelems);
|
||||||
|
void* ptr = q + 1;
|
||||||
|
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk is the exact size or the chunk is larger but not large
|
||||||
|
// enough to split due to alignment constraints.
|
||||||
|
if (p->len >= nelems) {
|
||||||
|
if (prev == 0)
|
||||||
|
freelist = node_from_offset(p->next_node);
|
||||||
|
else
|
||||||
|
prev->next_node = p->next_node;
|
||||||
|
p->next_node = 0;
|
||||||
|
void* ptr = p + 1;
|
||||||
|
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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::printf("Freeing item at %d of size %d\n", offset_from_node(cp), cp->len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (p = freelist, prev = 0; p && p != list_end;
|
||||||
|
prev = p, p = node_from_offset(p->next_node)) {
|
||||||
|
#ifdef DEBUG_FALLBACK_MALLOC
|
||||||
|
std::printf(" p=%d, cp=%d, after(p)=%d, after(cp)=%d\n",
|
||||||
|
offset_from_node(p), offset_from_node(cp),
|
||||||
|
offset_from_node(after(p)), offset_from_node(after(cp)));
|
||||||
|
#endif
|
||||||
|
if (after(p) == cp) {
|
||||||
|
#ifdef DEBUG_FALLBACK_MALLOC
|
||||||
|
std::printf(" Appending onto chunk at %d\n", offset_from_node(p));
|
||||||
|
#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::printf(" Appending free chunk at %d\n", offset_from_node(p));
|
||||||
|
#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::printf(" Making new free list entry %d\n", offset_from_node(cp));
|
||||||
|
#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::printf("%sOffset: %d\tsize: %d Next: %d\n",
|
||||||
|
(prev == 0 ? "" : " "), offset_from_node(p), p->len, p->next_node);
|
||||||
|
total_free += p->len;
|
||||||
|
}
|
||||||
|
std::printf("Total Free space: %d\n", total_free);
|
||||||
|
return total_free;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
struct __attribute__((aligned)) __aligned_type {};
|
||||||
|
|
||||||
|
void* __aligned_malloc_with_fallback(size_t size) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (void* dest = std::__libcpp_aligned_alloc(alignof(__aligned_type), size))
|
||||||
|
return dest;
|
||||||
|
#elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
|
||||||
|
if (void* dest = ::malloc(size))
|
||||||
|
return dest;
|
||||||
|
#else
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
if (void* dest = std::__libcpp_aligned_alloc(__alignof(__aligned_type), size))
|
||||||
|
return dest;
|
||||||
|
#endif
|
||||||
|
return fallback_malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* __calloc_with_fallback(size_t count, size_t size) {
|
||||||
|
void* ptr = ::calloc(count, size);
|
||||||
|
if (NULL != ptr)
|
||||||
|
return ptr;
|
||||||
|
// if calloc fails, fall back to emergency stash
|
||||||
|
ptr = fallback_malloc(size * count);
|
||||||
|
if (NULL != ptr)
|
||||||
|
::memset(ptr, 0, size * count);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __aligned_free_with_fallback(void* ptr) {
|
||||||
|
if (is_fallback_ptr(ptr))
|
||||||
|
fallback_free(ptr);
|
||||||
|
else {
|
||||||
|
#if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
|
||||||
|
::free(ptr);
|
||||||
|
#else
|
||||||
|
std::__libcpp_aligned_free(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __free_with_fallback(void* ptr) {
|
||||||
|
if (is_fallback_ptr(ptr))
|
||||||
|
fallback_free(ptr);
|
||||||
|
else
|
||||||
|
::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __cxxabiv1
|
28
third_party/libcxxabi/fallback_malloc.h
vendored
Normal file
28
third_party/libcxxabi/fallback_malloc.h
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef _FALLBACK_MALLOC_H
|
||||||
|
#define _FALLBACK_MALLOC_H
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
#include "libc/isystem/stddef.h" // for size_t
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
// Allocate some memory from _somewhere_
|
||||||
|
_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size);
|
||||||
|
|
||||||
|
// Allocate and zero-initialize memory from _somewhere_
|
||||||
|
_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size);
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr);
|
||||||
|
_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr);
|
||||||
|
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
#endif
|
106
third_party/libcxxabi/include/__cxxabi_config.h
vendored
Normal file
106
third_party/libcxxabi/include/__cxxabi_config.h
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef ____CXXABI_CONFIG_H
|
||||||
|
#define ____CXXABI_CONFIG_H
|
||||||
|
|
||||||
|
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
|
||||||
|
!defined(__ARM_DWARF_EH__) && !defined(__SEH__)
|
||||||
|
#define _LIBCXXABI_ARM_EHABI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__has_attribute)
|
||||||
|
#define __has_attribute(_attribute_) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define _LIBCXXABI_COMPILER_CLANG
|
||||||
|
# ifndef __apple_build_version__
|
||||||
|
# define _LIBCXXABI_CLANG_VER (__clang_major__ * 100 + __clang_minor__)
|
||||||
|
# endif
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define _LIBCXXABI_COMPILER_GCC
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define _LIBCXXABI_COMPILER_MSVC
|
||||||
|
#elif defined(__IBMCPP__)
|
||||||
|
# define _LIBCXXABI_COMPILER_IBM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
|
||||||
|
#define _LIBCXXABI_HIDDEN
|
||||||
|
#define _LIBCXXABI_DATA_VIS
|
||||||
|
#define _LIBCXXABI_FUNC_VIS
|
||||||
|
#define _LIBCXXABI_TYPE_VIS
|
||||||
|
#elif defined(_LIBCXXABI_BUILDING_LIBRARY)
|
||||||
|
#define _LIBCXXABI_HIDDEN
|
||||||
|
#define _LIBCXXABI_DATA_VIS __declspec(dllexport)
|
||||||
|
#define _LIBCXXABI_FUNC_VIS __declspec(dllexport)
|
||||||
|
#define _LIBCXXABI_TYPE_VIS __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_HIDDEN
|
||||||
|
#define _LIBCXXABI_DATA_VIS __declspec(dllimport)
|
||||||
|
#define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
|
||||||
|
#define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||||
|
#define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
|
||||||
|
#define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default")))
|
||||||
|
#define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default")))
|
||||||
|
#if __has_attribute(__type_visibility__)
|
||||||
|
#define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default")))
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default")))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_HIDDEN
|
||||||
|
#define _LIBCXXABI_DATA_VIS
|
||||||
|
#define _LIBCXXABI_FUNC_VIS
|
||||||
|
#define _LIBCXXABI_TYPE_VIS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_COMPILER_MSVC)
|
||||||
|
#define _LIBCXXABI_WEAK
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_WEAK __attribute__((__weak__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define _LIBCXXABI_COMPILER_CLANG
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define _LIBCXXABI_COMPILER_GCC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG)
|
||||||
|
#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi")))
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_NO_CFI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// wasm32 follows the arm32 ABI convention of using 32-bit guard.
|
||||||
|
#if defined(__arm__) || defined(__wasm32__) || defined(__ARM64_ARCH_8_32__)
|
||||||
|
# define _LIBCXXABI_GUARD_ABI_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_COMPILER_CLANG)
|
||||||
|
# if !__has_feature(cxx_exceptions)
|
||||||
|
# define _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
# endif
|
||||||
|
#elif defined(_LIBCXXABI_COMPILER_GCC) && !defined(__EXCEPTIONS)
|
||||||
|
# define _LIBCXXABI_NO_EXCEPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define _LIBCXXABI_DTOR_FUNC __thiscall
|
||||||
|
#else
|
||||||
|
#define _LIBCXXABI_DTOR_FUNC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ____CXXABI_CONFIG_H
|
177
third_party/libcxxabi/include/cxxabi.h
vendored
Normal file
177
third_party/libcxxabi/include/cxxabi.h
vendored
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __CXXABI_H
|
||||||
|
#define __CXXABI_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This header provides the interface to the C++ ABI as defined at:
|
||||||
|
* https://itanium-cxx-abi.github.io/cxx-abi/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libc/isystem/stddef.h"
|
||||||
|
#include "libc/isystem/stdint.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
|
||||||
|
#define _LIBCPPABI_VERSION 15000
|
||||||
|
#define _LIBCXXABI_NORETURN __attribute__((noreturn))
|
||||||
|
#define _LIBCXXABI_ALWAYS_COLD __attribute__((cold))
|
||||||
|
|
||||||
|
#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 (_LIBCXXABI_DTOR_FUNC *dest)(void *));
|
||||||
|
|
||||||
|
// 2.5.3 Exception Handlers
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void *
|
||||||
|
__cxa_get_exception_ptr(void *exceptionObject) throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void *
|
||||||
|
__cxa_begin_catch(void *exceptionObject) throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
|
||||||
|
#if defined(_LIBCXXABI_ARM_EHABI)
|
||||||
|
extern _LIBCXXABI_FUNC_VIS bool
|
||||||
|
__cxa_begin_cleanup(void *exceptionObject) throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup();
|
||||||
|
#endif
|
||||||
|
extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type();
|
||||||
|
|
||||||
|
// 2.5.4 Rethrowing Exceptions
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow();
|
||||||
|
|
||||||
|
// 2.6 Auxiliary Runtime APIs
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
|
||||||
|
__cxa_throw_bad_array_new_length(void);
|
||||||
|
|
||||||
|
// 3.2.6 Pure Virtual Function API
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
|
||||||
|
|
||||||
|
// 3.2.7 Deleted Virtual Function API
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
|
||||||
|
|
||||||
|
// 3.3.2 One-time Construction API
|
||||||
|
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint32_t *);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint32_t *);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint32_t *);
|
||||||
|
#else
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint64_t *);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint64_t *);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD 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
|
||||||
|
// These functions are part of the C++ ABI, but they are not defined in libc++abi:
|
||||||
|
// int __cxa_atexit(void (*)(void *), void *, void *);
|
||||||
|
// void __cxa_finalize(void *);
|
||||||
|
|
||||||
|
// 3.4 Demangler API
|
||||||
|
extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
|
||||||
|
char *output_buffer,
|
||||||
|
size_t *length, int *status);
|
||||||
|
|
||||||
|
// Apple additions to support C++ 0x exception_ptr class
|
||||||
|
// These are primitives to wrap a smart pointer around an exception object
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_rethrow_primary_exception(void *primary_exception);
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_increment_exception_refcount(void *primary_exception) throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS void
|
||||||
|
__cxa_decrement_exception_refcount(void *primary_exception) throw();
|
||||||
|
|
||||||
|
// Apple extension to support std::uncaught_exception()
|
||||||
|
extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
|
||||||
|
extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__Fuchsia__) || defined(__COSMOPOLITAN__)
|
||||||
|
// Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
|
||||||
|
// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
|
||||||
|
extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
|
||||||
|
void *) throw();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace __cxxabiv1
|
||||||
|
|
||||||
|
namespace abi = __cxxabiv1;
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __CXXABI_H
|
66
third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h
vendored
Normal file
66
third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef _LIBCPP___MEMORY_ALIGNED_ALLOC_H
|
||||||
|
#define _LIBCPP___MEMORY_ALIGNED_ALLOC_H
|
||||||
|
|
||||||
|
#include "third_party/libcxx/__config"
|
||||||
|
#include "third_party/libcxx/cstddef"
|
||||||
|
#include "third_party/libcxx/cstdlib"
|
||||||
|
|
||||||
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
|
||||||
|
|
||||||
|
// Low-level helpers to call the aligned allocation and deallocation functions
|
||||||
|
// on the target platform. This is used to implement libc++'s own memory
|
||||||
|
// allocation routines -- if you need to allocate memory inside the library,
|
||||||
|
// chances are that you want to use `__libcpp_allocate` instead.
|
||||||
|
//
|
||||||
|
// Returns the allocated memory, or `nullptr` on failure.
|
||||||
|
inline _LIBCPP_HIDE_FROM_ABI
|
||||||
|
void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
|
||||||
|
# if defined(_LIBCPP_MSVCRT_LIKE)
|
||||||
|
return ::_aligned_malloc(__size, __alignment);
|
||||||
|
# elif _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_C11_ALIGNED_ALLOC)
|
||||||
|
// aligned_alloc() requires that __size is a multiple of __alignment,
|
||||||
|
// but for C++ [new.delete.general], only states "if the value of an
|
||||||
|
// alignment argument passed to any of these functions is not a valid
|
||||||
|
// alignment value, the behavior is undefined".
|
||||||
|
// To handle calls such as ::operator new(1, std::align_val_t(128)), we
|
||||||
|
// round __size up to the next multiple of __alignment.
|
||||||
|
size_t __rounded_size = (__size + __alignment - 1) & ~(__alignment - 1);
|
||||||
|
// Rounding up could have wrapped around to zero, so we have to add another
|
||||||
|
// max() ternary to the actual call site to avoid succeeded in that case.
|
||||||
|
return ::aligned_alloc(__alignment, __size > __rounded_size ? __size : __rounded_size);
|
||||||
|
# else
|
||||||
|
void* __result = nullptr;
|
||||||
|
(void)::posix_memalign(&__result, __alignment, __size);
|
||||||
|
// If posix_memalign fails, __result is unmodified so we still return `nullptr`.
|
||||||
|
return __result;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline _LIBCPP_HIDE_FROM_ABI
|
||||||
|
void __libcpp_aligned_free(void* __ptr) {
|
||||||
|
#if defined(_LIBCPP_MSVCRT_LIKE)
|
||||||
|
::_aligned_free(__ptr);
|
||||||
|
#else
|
||||||
|
::free(__ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP___MEMORY_ALIGNED_ALLOC_H
|
1388
third_party/libcxxabi/private_typeinfo.cc
vendored
Normal file
1388
third_party/libcxxabi/private_typeinfo.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
251
third_party/libcxxabi/private_typeinfo.h
vendored
Normal file
251
third_party/libcxxabi/private_typeinfo.h
vendored
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __PRIVATE_TYPEINFO_H_
|
||||||
|
#define __PRIVATE_TYPEINFO_H_
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
|
||||||
|
#include "third_party/libcxx/typeinfo"
|
||||||
|
#include "libc/isystem/stddef.h"
|
||||||
|
|
||||||
|
namespace __cxxabiv1 {
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__shim_type_info();
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual void noop1() const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void noop2() const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type,
|
||||||
|
void *&adjustedPtr) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__fundamental_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__array_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__function_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__enum_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
unknown = 0,
|
||||||
|
public_path,
|
||||||
|
not_public_path,
|
||||||
|
yes,
|
||||||
|
no
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __class_type_info;
|
||||||
|
|
||||||
|
struct _LIBCXXABI_HIDDEN __dynamic_cast_info
|
||||||
|
{
|
||||||
|
// const data supplied to the search:
|
||||||
|
|
||||||
|
const __class_type_info* dst_type;
|
||||||
|
const void* static_ptr;
|
||||||
|
const __class_type_info* static_type;
|
||||||
|
ptrdiff_t src2dst_offset;
|
||||||
|
|
||||||
|
// Data that represents the answer:
|
||||||
|
|
||||||
|
// pointer to a dst_type which has (static_ptr, static_type) above it
|
||||||
|
const void* dst_ptr_leading_to_static_ptr;
|
||||||
|
// pointer to a dst_type which does not have (static_ptr, static_type) above it
|
||||||
|
const void* dst_ptr_not_leading_to_static_ptr;
|
||||||
|
|
||||||
|
// The following three paths are either unknown, public_path or not_public_path.
|
||||||
|
// access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
|
||||||
|
int path_dst_ptr_to_static_ptr;
|
||||||
|
// access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
|
||||||
|
// when there is no dst_type along the path
|
||||||
|
int path_dynamic_ptr_to_static_ptr;
|
||||||
|
// access of path from (dynamic_ptr, dynamic_type) to dst_type
|
||||||
|
// (not used if there is a (static_ptr, static_type) above a dst_type).
|
||||||
|
int path_dynamic_ptr_to_dst_ptr;
|
||||||
|
|
||||||
|
// Number of dst_types below (static_ptr, static_type)
|
||||||
|
int number_to_static_ptr;
|
||||||
|
// Number of dst_types not below (static_ptr, static_type)
|
||||||
|
int number_to_dst_ptr;
|
||||||
|
|
||||||
|
// Data that helps stop the search before the entire tree is searched:
|
||||||
|
|
||||||
|
// is_dst_type_derived_from_static_type is either unknown, yes or no.
|
||||||
|
int is_dst_type_derived_from_static_type;
|
||||||
|
// Number of dst_type in tree. If 0, then that means unknown.
|
||||||
|
int number_of_dst_type;
|
||||||
|
// communicates to a dst_type node that (static_ptr, static_type) was found
|
||||||
|
// above it.
|
||||||
|
bool found_our_static_ptr;
|
||||||
|
// communicates to a dst_type node that a static_type was found
|
||||||
|
// above it, but it wasn't (static_ptr, static_type)
|
||||||
|
bool found_any_static_type;
|
||||||
|
// Set whenever a search can be stopped
|
||||||
|
bool search_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Has no base class
|
||||||
|
class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__class_type_info();
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
|
||||||
|
const void *,
|
||||||
|
const void *, int) const;
|
||||||
|
_LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
|
||||||
|
const void *, int) const;
|
||||||
|
_LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *,
|
||||||
|
int) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
|
||||||
|
const void *, const void *,
|
||||||
|
int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Has one non-virtual public base class at offset zero
|
||||||
|
class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
|
||||||
|
public:
|
||||||
|
const __class_type_info *__base_type;
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
|
||||||
|
const void *, const void *,
|
||||||
|
int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _LIBCXXABI_HIDDEN __base_class_type_info
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const __class_type_info* __base_type;
|
||||||
|
long __offset_flags;
|
||||||
|
|
||||||
|
enum __offset_flags_masks
|
||||||
|
{
|
||||||
|
__virtual_mask = 0x1,
|
||||||
|
__public_mask = 0x2, // base is public
|
||||||
|
__offset_shift = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
|
||||||
|
void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
|
||||||
|
void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Has one or more base classes
|
||||||
|
class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
|
||||||
|
public:
|
||||||
|
unsigned int __flags;
|
||||||
|
unsigned int __base_count;
|
||||||
|
__base_class_type_info __base_info[1];
|
||||||
|
|
||||||
|
enum __flags_masks {
|
||||||
|
__non_diamond_repeat_mask = 0x1, // has two or more distinct base class
|
||||||
|
// objects of the same type
|
||||||
|
__diamond_shaped_mask = 0x2 // has base class object with two or
|
||||||
|
// more derived objects
|
||||||
|
};
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info();
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
|
||||||
|
const void *, const void *,
|
||||||
|
int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
|
||||||
|
_LIBCXXABI_HIDDEN virtual void
|
||||||
|
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
|
||||||
|
public:
|
||||||
|
unsigned int __flags;
|
||||||
|
const __shim_type_info *__pointee;
|
||||||
|
|
||||||
|
enum __masks {
|
||||||
|
__const_mask = 0x1,
|
||||||
|
__volatile_mask = 0x2,
|
||||||
|
__restrict_mask = 0x4,
|
||||||
|
__incomplete_mask = 0x8,
|
||||||
|
__incomplete_class_mask = 0x10,
|
||||||
|
__transaction_safe_mask = 0x20,
|
||||||
|
// This implements the following proposal from cxx-abi-dev (not yet part of
|
||||||
|
// the ABI document):
|
||||||
|
//
|
||||||
|
// http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html
|
||||||
|
//
|
||||||
|
// This is necessary for support of http://wg21.link/p0012, which permits
|
||||||
|
// throwing noexcept function and member function pointers and catching
|
||||||
|
// them as non-noexcept pointers.
|
||||||
|
__noexcept_mask = 0x40,
|
||||||
|
|
||||||
|
// Flags that cannot be removed by a standard conversion.
|
||||||
|
__no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask,
|
||||||
|
// Flags that cannot be added by a standard conversion.
|
||||||
|
__no_add_flags_mask = __transaction_safe_mask | __noexcept_mask
|
||||||
|
};
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__pbase_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
|
||||||
|
public:
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__pointer_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
|
||||||
|
: public __pbase_type_info {
|
||||||
|
public:
|
||||||
|
const __class_type_info *__context;
|
||||||
|
|
||||||
|
_LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
|
||||||
|
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
|
||||||
|
void *&) const;
|
||||||
|
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // __cxxabiv1
|
||||||
|
|
||||||
|
#endif // __PRIVATE_TYPEINFO_H_
|
70
third_party/libcxxabi/stdlib_exception.cc
vendored
Normal file
70
third_party/libcxxabi/stdlib_exception.cc
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxx/new"
|
||||||
|
#include "third_party/libcxx/exception"
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
// exception
|
||||||
|
|
||||||
|
exception::~exception() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* exception::what() const noexcept
|
||||||
|
{
|
||||||
|
return "std::exception";
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad_exception
|
||||||
|
|
||||||
|
bad_exception::~bad_exception() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* bad_exception::what() const noexcept
|
||||||
|
{
|
||||||
|
return "std::bad_exception";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// bad_alloc
|
||||||
|
|
||||||
|
bad_alloc::bad_alloc() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_alloc::~bad_alloc() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bad_alloc::what() const noexcept
|
||||||
|
{
|
||||||
|
return "std::bad_alloc";
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad_array_new_length
|
||||||
|
|
||||||
|
bad_array_new_length::bad_array_new_length() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_array_new_length::~bad_array_new_length() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bad_array_new_length::what() const noexcept
|
||||||
|
{
|
||||||
|
return "bad_array_new_length";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // std
|
266
third_party/libcxxabi/stdlib_new_delete.cc
vendored
Normal file
266
third_party/libcxxabi/stdlib_new_delete.cc
vendored
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxxabi/include/__cxxabi_config.h"
|
||||||
|
#include "third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h"
|
||||||
|
#include "third_party/libcxx/cstdlib"
|
||||||
|
#include "third_party/libcxx/new"
|
||||||
|
|
||||||
|
// Perform a few sanity checks on libc++ and libc++abi macros to ensure that
|
||||||
|
// the code below can be an exact copy of the code in libcxx/src/new.cpp.
|
||||||
|
#if !defined(_THROW_BAD_ALLOC)
|
||||||
|
# error The _THROW_BAD_ALLOC macro should be already defined by libc++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_WEAK
|
||||||
|
# error The _LIBCPP_WEAK macro should be already defined by libc++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBCXXABI_NO_EXCEPTIONS) != defined(_LIBCPP_HAS_NO_EXCEPTIONS)
|
||||||
|
# error libc++ and libc++abi seem to disagree on whether exceptions are enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------------------ BEGIN COPY ------------------
|
||||||
|
// Implement all new and delete operators as weak definitions
|
||||||
|
// in this shared library, so that they can be overridden by programs
|
||||||
|
// that define non-weak copies of the functions.
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void *
|
||||||
|
operator new(std::size_t size) _THROW_BAD_ALLOC
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
void* p;
|
||||||
|
while ((p = std::malloc(size)) == nullptr)
|
||||||
|
{
|
||||||
|
// If malloc fails and there is a new_handler,
|
||||||
|
// call it to try free up memory.
|
||||||
|
std::new_handler nh = std::get_new_handler();
|
||||||
|
if (nh)
|
||||||
|
nh();
|
||||||
|
else
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
throw std::bad_alloc();
|
||||||
|
#else
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new(size_t size, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
void* p = nullptr;
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
p = ::operator new(size);
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new[](size_t size) _THROW_BAD_ALLOC
|
||||||
|
{
|
||||||
|
return ::operator new(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new[](size_t size, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
void* p = nullptr;
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
p = ::operator new[](size);
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr) noexcept
|
||||||
|
{
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr, size_t) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
::operator delete[](ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr, size_t) noexcept
|
||||||
|
{
|
||||||
|
::operator delete[](ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void *
|
||||||
|
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
if (static_cast<size_t>(alignment) < sizeof(void*))
|
||||||
|
alignment = std::align_val_t(sizeof(void*));
|
||||||
|
|
||||||
|
// Try allocating memory. If allocation fails and there is a new_handler,
|
||||||
|
// call it to try free up memory, and try again until it succeeds, or until
|
||||||
|
// the new_handler decides to terminate.
|
||||||
|
//
|
||||||
|
// If allocation fails and there is no new_handler, we throw bad_alloc
|
||||||
|
// (or return nullptr if exceptions are disabled).
|
||||||
|
void* p;
|
||||||
|
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr)
|
||||||
|
{
|
||||||
|
std::new_handler nh = std::get_new_handler();
|
||||||
|
if (nh)
|
||||||
|
nh();
|
||||||
|
else {
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
throw std::bad_alloc();
|
||||||
|
#else
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
void* p = nullptr;
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
p = ::operator new(size, alignment);
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
|
||||||
|
{
|
||||||
|
return ::operator new(size, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void*
|
||||||
|
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
void* p = nullptr;
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
p = ::operator new[](size, alignment);
|
||||||
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr, std::align_val_t) noexcept
|
||||||
|
{
|
||||||
|
std::__libcpp_aligned_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr, std::align_val_t alignment) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(ptr, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||||
|
{
|
||||||
|
::operator delete[](ptr, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_WEAK
|
||||||
|
void
|
||||||
|
operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept
|
||||||
|
{
|
||||||
|
::operator delete[](ptr, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
|
||||||
|
// ------------------ END COPY ------------------
|
47
third_party/libcxxabi/stdlib_stdexcept.cc
vendored
Normal file
47
third_party/libcxxabi/stdlib_stdexcept.cc
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxx/stdexcept"
|
||||||
|
#include "third_party/libcxx/new"
|
||||||
|
#include "third_party/libcxx/cstdlib"
|
||||||
|
#include "third_party/libcxx/cstring"
|
||||||
|
#include "third_party/libcxx/cstdint"
|
||||||
|
#include "third_party/libcxx/cstddef"
|
||||||
|
#include "third_party/libcxx/refstring.hh" // from libc++
|
||||||
|
|
||||||
|
static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
|
||||||
|
|
||||||
|
namespace std // purposefully not using versioning namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
logic_error::~logic_error() noexcept {}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
logic_error::what() const noexcept
|
||||||
|
{
|
||||||
|
return __imp_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime_error::~runtime_error() noexcept {}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
runtime_error::what() const noexcept
|
||||||
|
{
|
||||||
|
return __imp_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
domain_error::~domain_error() noexcept {}
|
||||||
|
invalid_argument::~invalid_argument() noexcept {}
|
||||||
|
length_error::~length_error() noexcept {}
|
||||||
|
out_of_range::~out_of_range() noexcept {}
|
||||||
|
|
||||||
|
range_error::~range_error() noexcept {}
|
||||||
|
overflow_error::~overflow_error() noexcept {}
|
||||||
|
underflow_error::~underflow_error() noexcept {}
|
||||||
|
|
||||||
|
} // std
|
52
third_party/libcxxabi/stdlib_typeinfo.cc
vendored
Normal file
52
third_party/libcxxabi/stdlib_typeinfo.cc
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "third_party/libcxx/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
|
3
third_party/libunwind/BUILD.mk
vendored
3
third_party/libunwind/BUILD.mk
vendored
|
@ -54,8 +54,7 @@ THIRD_PARTY_LIBUNWIND_A_CHECKS = \
|
||||||
THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS = \
|
THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS = \
|
||||||
LIBC_CALLS \
|
LIBC_CALLS \
|
||||||
LIBC_INTRIN \
|
LIBC_INTRIN \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO
|
||||||
THIRD_PARTY_LIBCXX
|
|
||||||
|
|
||||||
THIRD_PARTY_LIBUNWIND_A_DEPS := \
|
THIRD_PARTY_LIBUNWIND_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
Loading…
Reference in a new issue