update libcxxabi to LLVM 15

release/15.x commit 134fd359a5d884f16662a9edd22ab24feeb1498c
This commit is contained in:
Andrew Kelley
2022-08-04 18:02:01 -07:00
parent 8278eb8837
commit c0d9578a84
14 changed files with 2011 additions and 1427 deletions

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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
{

View File

@@ -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");

View File

@@ -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

View File

@@ -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;

View File

@@ -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 };

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -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,

View File

@@ -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 {