clang 22.0.0git
EHScopeStack.h
Go to the documentation of this file.
1//===-- EHScopeStack.h - Stack for cleanup CIR generation -------*- 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// These classes should be the minimum interface required for other parts of
10// CIR CodeGen to emit cleanups. The implementation is in CIRGenCleanup.cpp and
11// other implemenentation details that are not widely needed are in
12// CIRGenCleanup.h.
13//
14// TODO(cir): this header should be shared between LLVM and CIR codegen.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H
19#define CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H
20
21#include "llvm/ADT/SmallVector.h"
22
23namespace clang::CIRGen {
24
25class CIRGenFunction;
26
27enum CleanupKind : unsigned {
28 /// Denotes a cleanup that should run when a scope is exited using exceptional
29 /// control flow (a throw statement leading to stack unwinding, ).
30 EHCleanup = 0x1,
31
32 /// Denotes a cleanup that should run when a scope is exited using normal
33 /// control flow (falling off the end of the scope, return, goto, ...).
35
37
40};
41
42/// A stack of scopes which respond to exceptions, including cleanups
43/// and catch blocks.
45 friend class CIRGenFunction;
46
47public:
48 // TODO(ogcg): Switch to alignof(uint64_t) instead of 8
49 enum { ScopeStackAlignment = 8 };
50
51 /// A saved depth on the scope stack. This is necessary because
52 /// pushing scopes onto the stack invalidates iterators.
54 friend class EHScopeStack;
55
56 /// Offset from startOfData to endOfBuffer.
57 ptrdiff_t size = -1;
58
59 explicit stable_iterator(ptrdiff_t size) : size(size) {}
60
61 public:
62 static stable_iterator invalid() { return stable_iterator(-1); }
63 stable_iterator() = default;
64
65 bool isValid() const { return size >= 0; }
66
67 /// Returns true if this scope encloses I.
68 /// Returns false if I is invalid.
69 /// This scope must be valid.
70 bool encloses(stable_iterator other) const { return size <= other.size; }
71
72 /// Returns true if this scope strictly encloses I: that is,
73 /// if it encloses I and is not I.
74 /// Returns false is I is invalid.
75 /// This scope must be valid.
76 bool strictlyEncloses(stable_iterator I) const { return size < I.size; }
77
79 return A.size == B.size;
80 }
82 return A.size != B.size;
83 }
84 };
85
86 /// Information for lazily generating a cleanup. Subclasses must be
87 /// POD-like: cleanups will not be destructed, and they will be
88 /// allocated on the cleanup stack and freely copied and moved
89 /// around.
90 ///
91 /// Cleanup implementations should generally be declared in an
92 /// anonymous namespace.
93 class Cleanup {
94 // Anchor the construction vtable.
95 virtual void anchor();
96
97 public:
98 Cleanup(const Cleanup &) = default;
100 Cleanup() = default;
101
102 virtual ~Cleanup() = default;
103
104 /// Emit the cleanup. For normal cleanups, this is run in the
105 /// same EH context as when the cleanup was pushed, i.e. the
106 /// immediately-enclosing context of the cleanup scope. For
107 /// EH cleanups, this is run in a terminate context.
108 ///
109 // \param flags cleanup kind.
110 virtual void emit(CIRGenFunction &cgf) = 0;
111
112 // This is a placeholder until EHScope is implemented.
113 virtual size_t getSize() const = 0;
114 };
115
116private:
117 // The implementation for this class is in CIRGenCleanup.h and
118 // CIRGenCleanup.cpp; the definition is here because it's used as a
119 // member of CIRGenFunction.
120
121 /// The start of the scope-stack buffer, i.e. the allocated pointer
122 /// for the buffer. All of these pointers are either simultaneously
123 /// null or simultaneously valid.
124 std::unique_ptr<char[]> startOfBuffer;
125
126 /// The end of the buffer.
127 char *endOfBuffer = nullptr;
128
129 /// The first valid entry in the buffer.
130 char *startOfData = nullptr;
131
132 /// The CGF this Stack belong to
133 CIRGenFunction *cgf = nullptr;
134
135 // This class uses a custom allocator for maximum efficiency because cleanups
136 // are allocated and freed very frequently. It's basically a bump pointer
137 // allocator, but we can't use LLVM's BumpPtrAllocator because we use offsets
138 // into the buffer as stable iterators.
139 char *allocate(size_t size);
140 void deallocate(size_t size);
141
142 void *pushCleanup(CleanupKind kind, size_t dataSize);
143
144public:
145 EHScopeStack() = default;
146 ~EHScopeStack() = default;
147
148 /// Push a lazily-created cleanup on the stack.
149 template <class T, class... As> void pushCleanup(CleanupKind kind, As... a) {
150 static_assert(alignof(T) <= ScopeStackAlignment,
151 "Cleanup's alignment is too large.");
152 void *buffer = pushCleanup(kind, sizeof(T));
153 [[maybe_unused]] Cleanup *obj = new (buffer) T(a...);
154 }
155
156 void setCGF(CIRGenFunction *inCGF) { cgf = inCGF; }
157
158 /// Pops a cleanup scope off the stack. This is private to CIRGenCleanup.cpp.
159 void popCleanup();
160
161 /// Determines whether the exception-scopes stack is empty.
162 bool empty() const { return startOfData == endOfBuffer; }
163
164 /// An unstable reference to a scope-stack depth. Invalidated by
165 /// pushes but not pops.
166 class iterator;
167
168 /// Returns an iterator pointing to the innermost EH scope.
169 iterator begin() const;
170
171 /// Create a stable reference to the top of the EH stack. The
172 /// returned reference is valid until that scope is popped off the
173 /// stack.
175 return stable_iterator(endOfBuffer - startOfData);
176 }
177
178 /// Create a stable reference to the bottom of the EH stack.
180};
181
182} // namespace clang::CIRGen
183
184#endif // CLANG_LIB_CIR_CODEGEN_EHSCOPESTACK_H
__PTRDIFF_TYPE__ ptrdiff_t
Information for lazily generating a cleanup.
Definition: EHScopeStack.h:93
Cleanup(const Cleanup &)=default
virtual size_t getSize() const =0
virtual void emit(CIRGenFunction &cgf)=0
Emit the cleanup.
A saved depth on the scope stack.
Definition: EHScopeStack.h:53
bool strictlyEncloses(stable_iterator I) const
Returns true if this scope strictly encloses I: that is, if it encloses I and is not I.
Definition: EHScopeStack.h:76
bool encloses(stable_iterator other) const
Returns true if this scope encloses I.
Definition: EHScopeStack.h:70
friend bool operator==(stable_iterator A, stable_iterator B)
Definition: EHScopeStack.h:78
friend bool operator!=(stable_iterator A, stable_iterator B)
Definition: EHScopeStack.h:81
A stack of scopes which respond to exceptions, including cleanups and catch blocks.
Definition: EHScopeStack.h:44
void setCGF(CIRGenFunction *inCGF)
Definition: EHScopeStack.h:156
stable_iterator stable_begin() const
Create a stable reference to the top of the EH stack.
Definition: EHScopeStack.h:174
void popCleanup()
Pops a cleanup scope off the stack. This is private to CIRGenCleanup.cpp.
void pushCleanup(CleanupKind kind, As... a)
Push a lazily-created cleanup on the stack.
Definition: EHScopeStack.h:149
bool empty() const
Determines whether the exception-scopes stack is empty.
Definition: EHScopeStack.h:162
static stable_iterator stable_end()
Create a stable reference to the bottom of the EH stack.
Definition: EHScopeStack.h:179
iterator begin() const
Returns an iterator pointing to the innermost EH scope.
@ EHCleanup
Denotes a cleanup that should run when a scope is exited using exceptional control flow (a throw stat...
Definition: EHScopeStack.h:30
@ NormalCleanup
Denotes a cleanup that should run when a scope is exited using normal control flow (falling off the e...
Definition: EHScopeStack.h:34
@ NormalEHLifetimeMarker
Definition: EHScopeStack.h:39
const FunctionProtoType * T