1 //===--- ProgramStack.h -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_SUPPORT_PROGRAMSTACK_H
10 #define LLVM_SUPPORT_PROGRAMSTACK_H
11
12 #include "llvm/ADT/STLFunctionalExtras.h"
13 #include "llvm/Support/Compiler.h"
14
15 // LLVM_HAS_SPLIT_STACKS is exposed in the header because CrashRecoveryContext
16 // needs to know if it's running on another thread or not.
17 //
18 // Currently only Apple AArch64 is known to support split stacks in the debugger
19 // and other tooling.
20 #if defined(__APPLE__) && defined(__MACH__) && defined(__aarch64__) && \
21 __has_extension(gnu_asm)
22 # define LLVM_HAS_SPLIT_STACKS
23 # define LLVM_HAS_SPLIT_STACKS_AARCH64
24 #endif
25
26 namespace llvm {
27
28 /// \returns an address close to the current value of the stack pointer.
29 ///
30 /// The value is not guaranteed to point to anything specific. It can be used to
31 /// estimate how much stack space has been used since the previous call.
32 LLVM_ABI uintptr_t getStackPointer();
33
34 /// \returns the default stack size for this platform.
35 ///
36 /// Based on \p RLIMIT_STACK or the equivalent.
37 LLVM_ABI unsigned getDefaultStackSize();
38
39 /// Runs Fn on a new stack of at least the given size.
40 ///
41 /// \param StackSize requested stack size. A size of 0 uses the default stack
42 /// size of the platform.
43 ///
44 /// The preferred implementation is split stacks on platforms that have a good
45 /// debugging experience for them. On other platforms a new thread is used.
46 LLVM_ABI void runOnNewStack(unsigned StackSize, function_ref<void()> Fn);
47
48 template <typename R, typename... Ts>
49 std::enable_if_t<!std::is_same_v<R, void>, R>
runOnNewStack(unsigned StackSize,function_ref<R (Ts...)> Fn,Ts &&...Args)50 runOnNewStack(unsigned StackSize, function_ref<R(Ts...)> Fn, Ts &&...Args) {
51 std::optional<R> Ret;
52 runOnNewStack(StackSize, [&]() { Ret = Fn(std::forward<Ts>(Args)...); });
53 return std::move(*Ret);
54 }
55
56 template <typename... Ts>
runOnNewStack(unsigned StackSize,function_ref<void (Ts...)> Fn,Ts &&...Args)57 void runOnNewStack(unsigned StackSize, function_ref<void(Ts...)> Fn,
58 Ts &&...Args) {
59 runOnNewStack(StackSize, [&]() { Fn(std::forward<Ts>(Args)...); });
60 }
61
62 } // namespace llvm
63
64 #endif // LLVM_SUPPORT_PROGRAMSTACK_H
65