update libcxxabi to LLVM 15
release/15.x commit 134fd359a5d884f16662a9edd22ab24feeb1498c
This commit is contained in:
8
lib/libcxxabi/include/__cxxabi_config.h
vendored
8
lib/libcxxabi/include/__cxxabi_config.h
vendored
@@ -10,7 +10,7 @@
|
||||
#define ____CXXABI_CONFIG_H
|
||||
|
||||
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
|
||||
!defined(__ARM_DWARF_EH__)
|
||||
!defined(__ARM_DWARF_EH__) && !defined(__SEH__)
|
||||
#define _LIBCXXABI_ARM_EHABI
|
||||
#endif
|
||||
|
||||
@@ -97,4 +97,10 @@
|
||||
# define _LIBCXXABI_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _LIBCXXABI_DTOR_FUNC __thiscall
|
||||
#else
|
||||
#define _LIBCXXABI_DTOR_FUNC
|
||||
#endif
|
||||
|
||||
#endif // ____CXXABI_CONFIG_H
|
||||
|
||||
4
lib/libcxxabi/include/cxxabi.h
vendored
4
lib/libcxxabi/include/cxxabi.h
vendored
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <__cxxabi_config.h>
|
||||
|
||||
#define _LIBCPPABI_VERSION 1002
|
||||
#define _LIBCPPABI_VERSION 15000
|
||||
#define _LIBCXXABI_NORETURN __attribute__((noreturn))
|
||||
#define _LIBCXXABI_ALWAYS_COLD __attribute__((cold))
|
||||
|
||||
@@ -47,7 +47,7 @@ __cxa_free_exception(void *thrown_exception) throw();
|
||||
// 2.4.3 Throwing the Exception Object
|
||||
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
|
||||
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
|
||||
void (*dest)(void *));
|
||||
void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
|
||||
|
||||
// 2.5.3 Exception Handlers
|
||||
extern _LIBCXXABI_FUNC_VIS void *
|
||||
|
||||
684
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
Normal file
684
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 uint32_t REG_EXCP_OBJ = 14; // Register to pass the address of the exception
|
||||
// object from the personality to xlclang++
|
||||
// compiled code.
|
||||
|
||||
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) {
|
||||
// Jump to the handler.
|
||||
_Unwind_SetGR(context, REG_EXCP_OBJ, reinterpret_cast<uintptr_t>(unwind_exception));
|
||||
_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);
|
||||
}
|
||||
|
||||
// __xlc_exception_handle
|
||||
// This function is for xlclang++. It returns the address of the exception
|
||||
// object set in gpr14 by the personality routine for xlclang++ compiled code.
|
||||
_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
|
||||
uintptr_t exceptionObject;
|
||||
asm("mr %0, 14" : "=r"(exceptionObject));
|
||||
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
|
||||
115
lib/libcxxabi/src/cxa_default_handlers.cpp
vendored
115
lib/libcxxabi/src/cxa_default_handlers.cpp
vendored
@@ -10,6 +10,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdlib.h>
|
||||
#include "abort_message.h"
|
||||
#include "cxxabi.h"
|
||||
@@ -20,67 +21,69 @@
|
||||
|
||||
#if !defined(LIBCXXABI_SILENT_TERMINATE)
|
||||
|
||||
_LIBCPP_SAFE_STATIC
|
||||
static const char* cause = "uncaught";
|
||||
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()
|
||||
{
|
||||
#ifndef _LIBCXXABI_NO_EXCEPTIONS
|
||||
// If there might be an uncaught exception
|
||||
using namespace __cxxabiv1;
|
||||
__cxa_eh_globals* globals = __cxa_get_globals_fast();
|
||||
if (globals)
|
||||
|
||||
// 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))
|
||||
{
|
||||
__cxa_exception* exception_header = globals->caughtExceptions;
|
||||
// If there is an uncaught exception
|
||||
if (exception_header)
|
||||
{
|
||||
_Unwind_Exception* unwind_exception =
|
||||
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
|
||||
if (__isOurExceptionClass(unwind_exception))
|
||||
{
|
||||
void* thrown_object =
|
||||
__getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
|
||||
((__cxa_dependent_exception*)exception_header)->primaryException :
|
||||
exception_header + 1;
|
||||
const __shim_type_info* thrown_type =
|
||||
static_cast<const __shim_type_info*>(exception_header->exceptionType);
|
||||
#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
|
||||
// Try to get demangled name of thrown_type
|
||||
int status;
|
||||
char buf[1024];
|
||||
size_t len = sizeof(buf);
|
||||
const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
|
||||
if (status != 0)
|
||||
name = thrown_type->name();
|
||||
#else
|
||||
const char* name = thrown_type->name();
|
||||
#endif
|
||||
// If the uncaught exception can be caught with std::exception&
|
||||
const __shim_type_info* catch_type =
|
||||
static_cast<const __shim_type_info*>(&typeid(std::exception));
|
||||
if (catch_type->can_catch(thrown_type, thrown_object))
|
||||
{
|
||||
// Include the what() message from the exception
|
||||
const std::exception* e = static_cast<const std::exception*>(thrown_object);
|
||||
abort_message("terminating with %s exception of type %s: %s",
|
||||
cause, name, e->what());
|
||||
}
|
||||
else
|
||||
// Else just note that we're terminating with an exception
|
||||
abort_message("terminating with %s exception of type %s",
|
||||
cause, name);
|
||||
}
|
||||
else
|
||||
// Else we're terminating with a foreign exception
|
||||
abort_message("terminating with %s foreign exception", cause);
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
#endif
|
||||
// Else just note that we're terminating
|
||||
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()
|
||||
@@ -91,22 +94,22 @@ static void demangling_unexpected_handler()
|
||||
|
||||
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
|
||||
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
|
||||
#else
|
||||
#else // !LIBCXXABI_SILENT_TERMINATE
|
||||
static constexpr std::terminate_handler default_terminate_handler = ::abort;
|
||||
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
|
||||
#endif
|
||||
#endif // !LIBCXXABI_SILENT_TERMINATE
|
||||
|
||||
//
|
||||
// Global variables that hold the pointers to the current handler
|
||||
//
|
||||
_LIBCXXABI_DATA_VIS
|
||||
_LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
|
||||
constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
|
||||
|
||||
_LIBCXXABI_DATA_VIS
|
||||
_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
|
||||
constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
|
||||
|
||||
_LIBCXXABI_DATA_VIS
|
||||
_LIBCPP_SAFE_STATIC std::new_handler __cxa_new_handler = 0;
|
||||
constinit std::new_handler __cxa_new_handler = nullptr;
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
44
lib/libcxxabi/src/cxa_demangle.cpp
vendored
44
lib/libcxxabi/src/cxa_demangle.cpp
vendored
@@ -173,6 +173,50 @@ struct DumpVisitor {
|
||||
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");
|
||||
|
||||
31
lib/libcxxabi/src/cxa_exception.cpp
vendored
31
lib/libcxxabi/src/cxa_exception.cpp
vendored
@@ -254,7 +254,7 @@ will call terminate, assuming that there was no handler for the
|
||||
exception.
|
||||
*/
|
||||
void
|
||||
__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) {
|
||||
__cxa_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);
|
||||
|
||||
@@ -341,10 +341,11 @@ unwinding with _Unwind_Resume.
|
||||
According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
|
||||
register, thus we have to write this function in assembly so that we can save
|
||||
{r1, r2, r3}. We don't have to save r0 because it is the return value and the
|
||||
first argument to _Unwind_Resume(). In addition, we are saving lr in order to
|
||||
align the stack to 16 bytes and lr will be used to identify the caller and its
|
||||
frame information. _Unwind_Resume never return and we need to keep the original
|
||||
lr so just branch to it.
|
||||
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()
|
||||
@@ -381,15 +382,19 @@ asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
|
||||
#if defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
" bti\n"
|
||||
#endif
|
||||
" push {r1, r2, r3, lr}\n"
|
||||
" push {r1, r2, r3, r4}\n"
|
||||
" mov r4, lr\n"
|
||||
" bl __cxa_end_cleanup_impl\n"
|
||||
" pop {r1, r2, r3, r4}\n"
|
||||
" mov lr, r4\n"
|
||||
#if defined(LIBCXXABI_BAREMETAL)
|
||||
" ldr r4, =_Unwind_Resume\n"
|
||||
" bx r4\n"
|
||||
" mov ip, r4\n"
|
||||
#endif
|
||||
" pop {r1, r2, r3, r4}\n"
|
||||
#if defined(LIBCXXABI_BAREMETAL)
|
||||
" bx ip\n"
|
||||
#else
|
||||
" b _Unwind_Resume\n"
|
||||
" b _Unwind_Resume\n"
|
||||
#endif
|
||||
" .popsection");
|
||||
#endif // defined(_LIBCXXABI_ARM_EHABI)
|
||||
@@ -439,6 +444,14 @@ __cxa_begin_catch(void* unwind_arg) throw()
|
||||
(
|
||||
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
|
||||
|
||||
10
lib/libcxxabi/src/cxa_exception.h
vendored
10
lib/libcxxabi/src/cxa_exception.h
vendored
@@ -34,7 +34,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
|
||||
// in the beginning of the struct, rather than before unwindHeader.
|
||||
void *reserve;
|
||||
|
||||
// This is a new field to support C++ 0x exception_ptr.
|
||||
// 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.
|
||||
@@ -43,7 +43,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
|
||||
|
||||
// Manage the exception object itself.
|
||||
std::type_info *exceptionType;
|
||||
void (*exceptionDestructor)(void *);
|
||||
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||
std::unexpected_handler unexpectedHandler;
|
||||
std::terminate_handler terminateHandler;
|
||||
|
||||
@@ -63,9 +63,9 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
|
||||
#endif
|
||||
|
||||
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
|
||||
// This is a new field to support C++ 0x exception_ptr.
|
||||
// This is a new field to support C++11 exception_ptr.
|
||||
// For binary compatibility it is placed where the compiler
|
||||
// previously adding padded to 64-bit align unwindHeader.
|
||||
// previously added padding to 64-bit align unwindHeader.
|
||||
size_t referenceCount;
|
||||
#endif
|
||||
_Unwind_Exception unwindHeader;
|
||||
@@ -81,7 +81,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
|
||||
#endif
|
||||
|
||||
std::type_info *exceptionType;
|
||||
void (*exceptionDestructor)(void *);
|
||||
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||
std::unexpected_handler unexpectedHandler;
|
||||
std::terminate_handler terminateHandler;
|
||||
|
||||
|
||||
2
lib/libcxxabi/src/cxa_guard_impl.h
vendored
2
lib/libcxxabi/src/cxa_guard_impl.h
vendored
@@ -619,7 +619,7 @@ struct GlobalStatic {
|
||||
static T instance;
|
||||
};
|
||||
template <class T>
|
||||
_LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
|
||||
_LIBCPP_CONSTINIT T GlobalStatic<T>::instance = {};
|
||||
|
||||
enum class Implementation { NoThreads, GlobalMutex, Futex };
|
||||
|
||||
|
||||
25
lib/libcxxabi/src/cxa_personality.cpp
vendored
25
lib/libcxxabi/src/cxa_personality.cpp
vendored
@@ -22,6 +22,15 @@
|
||||
#include "private_typeinfo.h"
|
||||
#include "unwind.h"
|
||||
|
||||
// TODO: This is a temporary workaround for libc++abi to recognize that it's being
|
||||
// built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
|
||||
// in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove
|
||||
// this workaround, it won't be possible to build libc++abi against libunwind headers
|
||||
// from LLVM 14 and before anymore.
|
||||
#if defined(____LIBUNWIND_CONFIG_H__) && !defined(_LIBUNWIND_VERSION)
|
||||
# define _LIBUNWIND_VERSION
|
||||
#endif
|
||||
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
@@ -613,7 +622,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
return;
|
||||
}
|
||||
// Start scan by getting exception table address
|
||||
// Start scan by getting exception table address.
|
||||
const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);
|
||||
if (lsda == 0)
|
||||
{
|
||||
@@ -903,6 +912,8 @@ static _Unwind_Reason_Code __gxx_personality_imp
|
||||
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
__gxx_personality_sj0
|
||||
#elif defined(__MVS__)
|
||||
__zos_cxx_personality_v2
|
||||
#else
|
||||
__gxx_personality_v0
|
||||
#endif
|
||||
@@ -1015,7 +1026,7 @@ static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
|
||||
}
|
||||
|
||||
// ARM register names
|
||||
#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
|
||||
#if !defined(_LIBUNWIND_VERSION)
|
||||
static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block
|
||||
#endif
|
||||
static const uint32_t REG_SP = 13;
|
||||
@@ -1050,7 +1061,7 @@ __gxx_personality_v0(_Unwind_State state,
|
||||
|
||||
bool native_exception = __isOurExceptionClass(unwind_exception);
|
||||
|
||||
#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
|
||||
#if !defined(_LIBUNWIND_VERSION)
|
||||
// Copy the address of _Unwind_Control_Block to r12 so that
|
||||
// _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can
|
||||
// return correct address.
|
||||
@@ -1112,7 +1123,7 @@ __gxx_personality_v0(_Unwind_State state,
|
||||
}
|
||||
|
||||
// Either we didn't do a phase 1 search (due to forced unwinding), or
|
||||
// phase 1 reported no catching-handlers.
|
||||
// phase 1 reported no catching-handlers.
|
||||
// Search for a (non-catching) cleanup
|
||||
if (is_force_unwinding)
|
||||
scan_eh_tab(
|
||||
@@ -1296,3 +1307,9 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
|
||||
} // extern "C"
|
||||
|
||||
} // __cxxabiv1
|
||||
|
||||
#if defined(_AIX)
|
||||
// Include implementation of the personality and helper functions for the
|
||||
// state table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
|
||||
# include "aix_state_tab_eh.inc"
|
||||
#endif
|
||||
|
||||
2299
lib/libcxxabi/src/demangle/ItaniumDemangle.h
vendored
2299
lib/libcxxabi/src/demangle/ItaniumDemangle.h
vendored
File diff suppressed because it is too large
Load Diff
95
lib/libcxxabi/src/demangle/ItaniumNodes.def
vendored
Normal file
95
lib/libcxxabi/src/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
|
||||
114
lib/libcxxabi/src/demangle/Utility.h
vendored
114
lib/libcxxabi/src/demangle/Utility.h
vendored
@@ -33,43 +33,50 @@ class OutputBuffer {
|
||||
size_t CurrentPosition = 0;
|
||||
size_t BufferCapacity = 0;
|
||||
|
||||
// Ensure there is at least n more positions in buffer.
|
||||
// Ensure there are at least N more positions in the buffer.
|
||||
void grow(size_t N) {
|
||||
if (N + CurrentPosition >= BufferCapacity) {
|
||||
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 < N + CurrentPosition)
|
||||
BufferCapacity = N + CurrentPosition;
|
||||
if (BufferCapacity < Need)
|
||||
BufferCapacity = Need;
|
||||
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
||||
if (Buffer == nullptr)
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void writeUnsigned(uint64_t N, bool isNeg = false) {
|
||||
// Handle special case...
|
||||
if (N == 0) {
|
||||
*this << '0';
|
||||
return;
|
||||
}
|
||||
|
||||
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
|
||||
std::array<char, 21> Temp;
|
||||
char *TempPtr = Temp.data() + Temp.size();
|
||||
|
||||
while (N) {
|
||||
// Output at least one character.
|
||||
do {
|
||||
*--TempPtr = char('0' + N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
} while (N);
|
||||
|
||||
// Add negative sign...
|
||||
// Add negative sign.
|
||||
if (isNeg)
|
||||
*--TempPtr = '-';
|
||||
this->operator<<(StringView(TempPtr, Temp.data() + Temp.size()));
|
||||
|
||||
return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
OutputBuffer(char *StartBuf, size_t Size)
|
||||
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
|
||||
OutputBuffer() = default;
|
||||
// Non-copyable
|
||||
OutputBuffer(const OutputBuffer &) = delete;
|
||||
OutputBuffer &operator=(const OutputBuffer &) = delete;
|
||||
|
||||
operator StringView() const { return StringView(Buffer, CurrentPosition); }
|
||||
|
||||
void reset(char *Buffer_, size_t BufferCapacity_) {
|
||||
CurrentPosition = 0;
|
||||
Buffer = Buffer_;
|
||||
@@ -81,13 +88,27 @@ public:
|
||||
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+=(StringView R) {
|
||||
size_t Size = R.size();
|
||||
if (Size == 0)
|
||||
return *this;
|
||||
grow(Size);
|
||||
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
if (size_t Size = R.size()) {
|
||||
grow(Size);
|
||||
std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -97,9 +118,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(StringView R) { return (*this += R); }
|
||||
|
||||
OutputBuffer prepend(StringView R) {
|
||||
OutputBuffer &prepend(StringView R) {
|
||||
size_t Size = R.size();
|
||||
|
||||
grow(Size);
|
||||
@@ -110,19 +129,16 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(StringView R) { return (*this += R); }
|
||||
|
||||
OutputBuffer &operator<<(char C) { return (*this += C); }
|
||||
|
||||
OutputBuffer &operator<<(long long N) {
|
||||
if (N < 0)
|
||||
writeUnsigned(static_cast<unsigned long long>(-N), true);
|
||||
else
|
||||
writeUnsigned(static_cast<unsigned long long>(N));
|
||||
return *this;
|
||||
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(unsigned long long N) {
|
||||
writeUnsigned(N, false);
|
||||
return *this;
|
||||
return writeUnsigned(N, false);
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(long N) {
|
||||
@@ -155,7 +171,8 @@ public:
|
||||
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||
|
||||
char back() const {
|
||||
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
|
||||
assert(CurrentPosition);
|
||||
return Buffer[CurrentPosition - 1];
|
||||
}
|
||||
|
||||
bool empty() const { return CurrentPosition == 0; }
|
||||
@@ -165,35 +182,20 @@ public:
|
||||
size_t getBufferCapacity() const { return BufferCapacity; }
|
||||
};
|
||||
|
||||
template <class T> class SwapAndRestore {
|
||||
T &Restore;
|
||||
T OriginalValue;
|
||||
bool ShouldRestore = true;
|
||||
template <class T> class ScopedOverride {
|
||||
T &Loc;
|
||||
T Original;
|
||||
|
||||
public:
|
||||
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
|
||||
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
|
||||
|
||||
SwapAndRestore(T &Restore_, T NewVal)
|
||||
: Restore(Restore_), OriginalValue(Restore) {
|
||||
Restore = std::move(NewVal);
|
||||
}
|
||||
~SwapAndRestore() {
|
||||
if (ShouldRestore)
|
||||
Restore = std::move(OriginalValue);
|
||||
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
|
||||
Loc_ = std::move(NewVal);
|
||||
}
|
||||
~ScopedOverride() { Loc = std::move(Original); }
|
||||
|
||||
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
|
||||
|
||||
void restoreNow(bool Force) {
|
||||
if (!Force && !ShouldRestore)
|
||||
return;
|
||||
|
||||
Restore = std::move(OriginalValue);
|
||||
ShouldRestore = false;
|
||||
}
|
||||
|
||||
SwapAndRestore(const SwapAndRestore &) = delete;
|
||||
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
|
||||
ScopedOverride(const ScopedOverride &) = delete;
|
||||
ScopedOverride &operator=(const ScopedOverride &) = delete;
|
||||
};
|
||||
|
||||
inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
|
||||
|
||||
5
lib/libcxxabi/src/fallback_malloc.cpp
vendored
5
lib/libcxxabi/src/fallback_malloc.cpp
vendored
@@ -33,10 +33,9 @@ namespace {
|
||||
|
||||
// When POSIX threads are not available, make the mutex operations a nop
|
||||
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||
_LIBCPP_SAFE_STATIC
|
||||
static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
|
||||
static _LIBCPP_CONSTINIT std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
|
||||
#else
|
||||
static void* heap_mutex = 0;
|
||||
static _LIBCPP_CONSTINIT void* heap_mutex = 0;
|
||||
#endif
|
||||
|
||||
class mutexor {
|
||||
|
||||
Reference in New Issue
Block a user