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