@@ -42,7 +42,47 @@ enum CleanupKind : unsigned {
4242// / A stack of scopes which respond to exceptions, including cleanups
4343// / and catch blocks.
4444class EHScopeStack {
45+ friend class CIRGenFunction ;
46+
4547public:
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.
53+ class stable_iterator {
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+
78+ friend bool operator ==(stable_iterator A, stable_iterator B) {
79+ return A.size == B.size ;
80+ }
81+ friend bool operator !=(stable_iterator A, stable_iterator B) {
82+ return A.size != B.size ;
83+ }
84+ };
85+
4686 // / Information for lazily generating a cleanup. Subclasses must be
4787 // / POD-like: cleanups will not be destructed, and they will be
4888 // / allocated on the cleanup stack and freely copied and moved
@@ -68,30 +108,75 @@ class EHScopeStack {
68108 // /
69109 // \param flags cleanup kind.
70110 virtual void emit (CIRGenFunction &cgf) = 0;
71- };
72111
73- // Classic codegen has a finely tuned custom allocator and a complex stack
74- // management scheme. We'll probably eventually want to find a way to share
75- // that implementation. For now, we will use a very simplified implementation
76- // to get cleanups working.
77- llvm::SmallVector<std::unique_ptr<Cleanup>, 8 > cleanupStack;
112+ // This is a placeholder until EHScope is implemented.
113+ virtual size_t getSize () const = 0;
114+ };
78115
79116private:
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+
80132 // / The CGF this Stack belong to
81133 CIRGenFunction *cgf = nullptr ;
82134
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+
83144public:
84145 EHScopeStack () = default ;
85146 ~EHScopeStack () = default ;
86147
87148 // / Push a lazily-created cleanup on the stack.
88149 template <class T , class ... As> void pushCleanup (CleanupKind kind, As... a) {
89- cleanupStack.push_back (std::make_unique<T>(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...);
90154 }
91155
92156 void setCGF (CIRGenFunction *inCGF) { cgf = inCGF; }
93157
94- size_t getStackDepth () const { return cleanupStack.size (); }
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.
174+ stable_iterator stable_begin () const {
175+ return stable_iterator (endOfBuffer - startOfData);
176+ }
177+
178+ // / Create a stable reference to the bottom of the EH stack.
179+ static stable_iterator stable_end () { return stable_iterator (0 ); }
95180};
96181
97182} // namespace clang::CIRGen
0 commit comments