
Reland https://github.com/llvm/llvm-project/pull/133173 Clang spawns a new thread to avoid running out of stack space. This can make debugging and performance analysis more difficult as how the threads are connected is difficult to recover. This patch introduces `runOnNewStack` and applies it in Clang. On platforms that have good support for it this allocates a new stack and moves to it using assembly. Doing split stacks like this actually runs on most platforms, but many debuggers and unwinders reject the large or backwards stack offsets that occur. Apple platforms and tools are known to support this, so this only enables it there for now.
59 lines
2.0 KiB
C++
59 lines
2.0 KiB
C++
//===--- Stack.cpp - Utilities for dealing with stack space ---------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// Defines utilities for dealing with stack allocation and stack space.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Basic/Stack.h"
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
|
#include "llvm/Support/ProgramStack.h"
|
|
|
|
static LLVM_THREAD_LOCAL uintptr_t BottomOfStack = 0;
|
|
|
|
void clang::noteBottomOfStack(bool ForceSet) {
|
|
if (!BottomOfStack || ForceSet)
|
|
BottomOfStack = llvm::getStackPointer();
|
|
}
|
|
|
|
bool clang::isStackNearlyExhausted() {
|
|
// We consider 256 KiB to be sufficient for any code that runs between checks
|
|
// for stack size.
|
|
constexpr size_t SufficientStack = 256 << 10;
|
|
|
|
// If we don't know where the bottom of the stack is, hope for the best.
|
|
if (!BottomOfStack)
|
|
return false;
|
|
|
|
intptr_t StackDiff =
|
|
(intptr_t)llvm::getStackPointer() - (intptr_t)BottomOfStack;
|
|
size_t StackUsage = (size_t)std::abs(StackDiff);
|
|
|
|
// If the stack pointer has a surprising value, we do not understand this
|
|
// stack usage scheme. (Perhaps the target allocates new stack regions on
|
|
// demand for us.) Don't try to guess what's going on.
|
|
if (StackUsage > DesiredStackSize)
|
|
return false;
|
|
|
|
return StackUsage >= DesiredStackSize - SufficientStack;
|
|
}
|
|
|
|
void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag,
|
|
llvm::function_ref<void()> Fn) {
|
|
llvm::CrashRecoveryContext CRC;
|
|
// Preserve the BottomOfStack in case RunSafelyOnNewStack uses split stacks.
|
|
uintptr_t PrevBottom = BottomOfStack;
|
|
CRC.RunSafelyOnNewStack([&] {
|
|
noteBottomOfStack(true);
|
|
Diag();
|
|
Fn();
|
|
}, DesiredStackSize);
|
|
BottomOfStack = PrevBottom;
|
|
}
|