blob: 80739cd8d73ef55ff03af8070c6eb94e758760e0 [file] [log] [blame]
John McCallf1549f62010-07-06 01:34:17 +00001//===-- CGException.h - Classes for exceptions IR generation ----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These classes support the generation of LLVM IR for exceptions in
11// C++ and Objective C.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef CLANG_CODEGEN_CGEXCEPTION_H
16#define CLANG_CODEGEN_CGEXCEPTION_H
17
18/// EHScopeStack is defined in CodeGenFunction.h, but its
19/// implementation is in this file and in CGException.cpp.
20#include "CodeGenFunction.h"
21
22namespace llvm {
23 class Value;
24 class BasicBlock;
25}
26
27namespace clang {
28namespace CodeGen {
29
30/// A protected scope for zero-cost EH handling.
31class EHScope {
32 llvm::BasicBlock *CachedLandingPad;
33
John McCallda65ea82010-07-13 20:32:21 +000034 unsigned K : 3;
John McCallf1549f62010-07-06 01:34:17 +000035
36protected:
John McCallda65ea82010-07-13 20:32:21 +000037 enum { BitsRemaining = 29 };
John McCallf1549f62010-07-06 01:34:17 +000038
39public:
John McCallda65ea82010-07-13 20:32:21 +000040 enum Kind { Cleanup, LazyCleanup, Catch, Terminate, Filter };
John McCallf1549f62010-07-06 01:34:17 +000041
42 EHScope(Kind K) : CachedLandingPad(0), K(K) {}
43
44 Kind getKind() const { return static_cast<Kind>(K); }
45
46 llvm::BasicBlock *getCachedLandingPad() const {
47 return CachedLandingPad;
48 }
49
50 void setCachedLandingPad(llvm::BasicBlock *Block) {
51 CachedLandingPad = Block;
52 }
53};
54
55/// A scope which attempts to handle some, possibly all, types of
56/// exceptions.
57///
58/// Objective C @finally blocks are represented using a cleanup scope
59/// after the catch scope.
60class EHCatchScope : public EHScope {
61 unsigned NumHandlers : BitsRemaining;
62
63 // In effect, we have a flexible array member
64 // Handler Handlers[0];
65 // But that's only standard in C99, not C++, so we have to do
66 // annoying pointer arithmetic instead.
67
68public:
69 struct Handler {
70 /// A type info value, or null (C++ null, not an LLVM null pointer)
71 /// for a catch-all.
72 llvm::Value *Type;
73
74 /// The catch handler for this type.
75 llvm::BasicBlock *Block;
76
77 static Handler make(llvm::Value *Type, llvm::BasicBlock *Block) {
78 Handler Temp;
79 Temp.Type = Type;
80 Temp.Block = Block;
81 return Temp;
82 }
83 };
84
85private:
86 Handler *getHandlers() {
87 return reinterpret_cast<Handler*>(this+1);
88 }
89
90 const Handler *getHandlers() const {
91 return reinterpret_cast<const Handler*>(this+1);
92 }
93
94public:
95 static size_t getSizeForNumHandlers(unsigned N) {
96 return sizeof(EHCatchScope) + N * sizeof(Handler);
97 }
98
99 EHCatchScope(unsigned NumHandlers)
100 : EHScope(Catch), NumHandlers(NumHandlers) {
101 }
102
103 unsigned getNumHandlers() const {
104 return NumHandlers;
105 }
106
107 void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
108 setHandler(I, /*catchall*/ 0, Block);
109 }
110
111 void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
112 assert(I < getNumHandlers());
113 getHandlers()[I] = Handler::make(Type, Block);
114 }
115
116 const Handler &getHandler(unsigned I) const {
117 assert(I < getNumHandlers());
118 return getHandlers()[I];
119 }
120
121 typedef const Handler *iterator;
122 iterator begin() const { return getHandlers(); }
123 iterator end() const { return getHandlers() + getNumHandlers(); }
124
125 static bool classof(const EHScope *Scope) {
126 return Scope->getKind() == Catch;
127 }
128};
129
John McCallda65ea82010-07-13 20:32:21 +0000130/// A cleanup scope which generates the cleanup blocks lazily.
131class EHLazyCleanupScope : public EHScope {
132 /// Whether this cleanup needs to be run along normal edges.
133 bool IsNormalCleanup : 1;
134
135 /// Whether this cleanup needs to be run along exception edges.
136 bool IsEHCleanup : 1;
137
138 /// The amount of extra storage needed by the LazyCleanup.
139 /// Always a multiple of the scope-stack alignment.
140 unsigned CleanupSize : 12;
141
142 /// The number of fixups required by enclosing scopes (not including
143 /// this one). If this is the top cleanup scope, all the fixups
144 /// from this index onwards belong to this scope.
145 unsigned FixupDepth : BitsRemaining - 14;
146
147 /// The nearest normal cleanup scope enclosing this one.
148 EHScopeStack::stable_iterator EnclosingNormal;
149
150 /// The nearest EH cleanup scope enclosing this one.
151 EHScopeStack::stable_iterator EnclosingEH;
152
153 /// The dual entry/exit block along the normal edge. This is lazily
154 /// created if needed before the cleanup is popped.
155 llvm::BasicBlock *NormalBlock;
156
157 /// The dual entry/exit block along the EH edge. This is lazily
158 /// created if needed before the cleanup is popped.
159 llvm::BasicBlock *EHBlock;
160
161public:
162 /// Gets the size required for a lazy cleanup scope with the given
163 /// cleanup-data requirements.
164 static size_t getSizeForCleanupSize(size_t Size) {
165 return sizeof(EHLazyCleanupScope) + Size;
166 }
167
168 size_t getAllocatedSize() const {
169 return sizeof(EHLazyCleanupScope) + CleanupSize;
170 }
171
172 EHLazyCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize,
173 unsigned FixupDepth,
174 EHScopeStack::stable_iterator EnclosingNormal,
175 EHScopeStack::stable_iterator EnclosingEH)
176 : EHScope(EHScope::LazyCleanup),
177 IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
178 CleanupSize(CleanupSize), FixupDepth(FixupDepth),
179 EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
180 NormalBlock(0), EHBlock(0)
181 {}
182
183 bool isNormalCleanup() const { return IsNormalCleanup; }
184 llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
185 void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
186
187 bool isEHCleanup() const { return IsEHCleanup; }
188 llvm::BasicBlock *getEHBlock() const { return EHBlock; }
189 void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
190
191 unsigned getFixupDepth() const { return FixupDepth; }
192 EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
193 return EnclosingNormal;
194 }
195 EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
196 return EnclosingEH;
197 }
198
199 size_t getCleanupSize() const { return CleanupSize; }
200 void *getCleanupBuffer() { return this + 1; }
201
202 EHScopeStack::LazyCleanup *getCleanup() {
203 return reinterpret_cast<EHScopeStack::LazyCleanup*>(getCleanupBuffer());
204 }
205
206 static bool classof(const EHScope *Scope) {
207 return (Scope->getKind() == LazyCleanup);
208 }
209};
210
John McCallf1549f62010-07-06 01:34:17 +0000211/// A scope which needs to execute some code if we try to unwind ---
212/// either normally, via the EH mechanism, or both --- through it.
213class EHCleanupScope : public EHScope {
214 /// The number of fixups required by enclosing scopes (not including
215 /// this one). If this is the top cleanup scope, all the fixups
216 /// from this index onwards belong to this scope.
217 unsigned FixupDepth : BitsRemaining;
218
219 /// The nearest normal cleanup scope enclosing this one.
220 EHScopeStack::stable_iterator EnclosingNormal;
221
222 /// The nearest EH cleanup scope enclosing this one.
223 EHScopeStack::stable_iterator EnclosingEH;
224
225 llvm::BasicBlock *NormalEntry;
226 llvm::BasicBlock *NormalExit;
227 llvm::BasicBlock *EHEntry;
228 llvm::BasicBlock *EHExit;
229
230public:
231 static size_t getSize() { return sizeof(EHCleanupScope); }
232
233 EHCleanupScope(unsigned FixupDepth,
234 EHScopeStack::stable_iterator EnclosingNormal,
235 EHScopeStack::stable_iterator EnclosingEH,
236 llvm::BasicBlock *NormalEntry, llvm::BasicBlock *NormalExit,
237 llvm::BasicBlock *EHEntry, llvm::BasicBlock *EHExit)
238 : EHScope(Cleanup), FixupDepth(FixupDepth),
239 EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
240 NormalEntry(NormalEntry), NormalExit(NormalExit),
241 EHEntry(EHEntry), EHExit(EHExit) {
242 assert((NormalEntry != 0) == (NormalExit != 0));
243 assert((EHEntry != 0) == (EHExit != 0));
244 }
245
246 bool isNormalCleanup() const { return NormalEntry != 0; }
247 bool isEHCleanup() const { return EHEntry != 0; }
248
249 llvm::BasicBlock *getNormalEntry() const { return NormalEntry; }
250 llvm::BasicBlock *getNormalExit() const { return NormalExit; }
251 llvm::BasicBlock *getEHEntry() const { return EHEntry; }
252 llvm::BasicBlock *getEHExit() const { return EHExit; }
253 unsigned getFixupDepth() const { return FixupDepth; }
254 EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
255 return EnclosingNormal;
256 }
257 EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
258 return EnclosingEH;
259 }
260
261 static bool classof(const EHScope *Scope) {
262 return Scope->getKind() == Cleanup;
263 }
264};
265
266/// An exceptions scope which filters exceptions thrown through it.
267/// Only exceptions matching the filter types will be permitted to be
268/// thrown.
269///
270/// This is used to implement C++ exception specifications.
271class EHFilterScope : public EHScope {
272 unsigned NumFilters : BitsRemaining;
273
274 // Essentially ends in a flexible array member:
275 // llvm::Value *FilterTypes[0];
276
277 llvm::Value **getFilters() {
278 return reinterpret_cast<llvm::Value**>(this+1);
279 }
280
281 llvm::Value * const *getFilters() const {
282 return reinterpret_cast<llvm::Value* const *>(this+1);
283 }
284
285public:
286 EHFilterScope(unsigned NumFilters) :
287 EHScope(Filter), NumFilters(NumFilters) {}
288
289 static size_t getSizeForNumFilters(unsigned NumFilters) {
290 return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
291 }
292
293 unsigned getNumFilters() const { return NumFilters; }
294
295 void setFilter(unsigned I, llvm::Value *FilterValue) {
296 assert(I < getNumFilters());
297 getFilters()[I] = FilterValue;
298 }
299
300 llvm::Value *getFilter(unsigned I) const {
301 assert(I < getNumFilters());
302 return getFilters()[I];
303 }
304
305 static bool classof(const EHScope *Scope) {
306 return Scope->getKind() == Filter;
307 }
308};
309
310/// An exceptions scope which calls std::terminate if any exception
311/// reaches it.
312class EHTerminateScope : public EHScope {
313public:
314 EHTerminateScope() : EHScope(Terminate) {}
315 static size_t getSize() { return sizeof(EHTerminateScope); }
316
317 static bool classof(const EHScope *Scope) {
318 return Scope->getKind() == Terminate;
319 }
320};
321
322/// A non-stable pointer into the scope stack.
323class EHScopeStack::iterator {
324 char *Ptr;
325
326 friend class EHScopeStack;
327 explicit iterator(char *Ptr) : Ptr(Ptr) {}
328
329public:
330 iterator() : Ptr(0) {}
331
332 EHScope *get() const {
333 return reinterpret_cast<EHScope*>(Ptr);
334 }
335
336 EHScope *operator->() const { return get(); }
337 EHScope &operator*() const { return *get(); }
338
339 iterator &operator++() {
340 switch (get()->getKind()) {
341 case EHScope::Catch:
342 Ptr += EHCatchScope::getSizeForNumHandlers(
343 static_cast<const EHCatchScope*>(get())->getNumHandlers());
344 break;
345
346 case EHScope::Filter:
347 Ptr += EHFilterScope::getSizeForNumFilters(
348 static_cast<const EHFilterScope*>(get())->getNumFilters());
349 break;
350
John McCallda65ea82010-07-13 20:32:21 +0000351 case EHScope::LazyCleanup:
352 Ptr += static_cast<const EHLazyCleanupScope*>(get())
353 ->getAllocatedSize();
354 break;
355
John McCallf1549f62010-07-06 01:34:17 +0000356 case EHScope::Cleanup:
357 Ptr += EHCleanupScope::getSize();
358 break;
359
360 case EHScope::Terminate:
361 Ptr += EHTerminateScope::getSize();
362 break;
363 }
364
365 return *this;
366 }
367
368 iterator next() {
369 iterator copy = *this;
370 ++copy;
371 return copy;
372 }
373
374 iterator operator++(int) {
375 iterator copy = *this;
376 operator++();
377 return copy;
378 }
379
380 bool operator==(iterator other) const { return Ptr == other.Ptr; }
381 bool operator!=(iterator other) const { return Ptr != other.Ptr; }
382};
383
384inline EHScopeStack::iterator EHScopeStack::begin() const {
385 return iterator(StartOfData);
386}
387
388inline EHScopeStack::iterator EHScopeStack::end() const {
389 return iterator(EndOfBuffer);
390}
391
392inline void EHScopeStack::popCatch() {
393 assert(!empty() && "popping exception stack when not empty");
394
395 assert(isa<EHCatchScope>(*begin()));
396 StartOfData += EHCatchScope::getSizeForNumHandlers(
397 cast<EHCatchScope>(*begin()).getNumHandlers());
398
399 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
400 CatchDepth--;
401}
402
403inline void EHScopeStack::popTerminate() {
404 assert(!empty() && "popping exception stack when not empty");
405
406 assert(isa<EHTerminateScope>(*begin()));
407 StartOfData += EHTerminateScope::getSize();
408
409 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
410 CatchDepth--;
411}
412
413inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
414 assert(sp.isValid() && "finding invalid savepoint");
415 assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
416 return iterator(EndOfBuffer - sp.Size);
417}
418
419inline EHScopeStack::stable_iterator
420EHScopeStack::stabilize(iterator ir) const {
421 assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
422 return stable_iterator(EndOfBuffer - ir.Ptr);
423}
424
425}
426}
427
428#endif