blob: 3c6e1a5528afddef8ea57b4fcddf1da8dfa43957 [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 McCall7495f222010-07-21 07:11:21 +000060 unsigned K : 2;
John McCallf1549f62010-07-06 01:34:17 +000061
62protected:
John McCall7495f222010-07-21 07:11:21 +000063 enum { BitsRemaining = 30 };
John McCallf1549f62010-07-06 01:34:17 +000064
65public:
John McCall1f0fca52010-07-21 07:22:38 +000066 enum Kind { Cleanup, 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.
John McCall1f0fca52010-07-21 07:22:38 +0000157class EHCleanupScope : public EHScope {
John McCallda65ea82010-07-13 20:32:21 +0000158 /// 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
John McCall1f0fca52010-07-21 07:22:38 +0000164 /// The amount of extra storage needed by the Cleanup.
John McCallda65ea82010-07-13 20:32:21 +0000165 /// 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) {
John McCall1f0fca52010-07-21 07:22:38 +0000191 return sizeof(EHCleanupScope) + Size;
John McCallda65ea82010-07-13 20:32:21 +0000192 }
193
194 size_t getAllocatedSize() const {
John McCall1f0fca52010-07-21 07:22:38 +0000195 return sizeof(EHCleanupScope) + CleanupSize;
John McCallda65ea82010-07-13 20:32:21 +0000196 }
197
John McCall1f0fca52010-07-21 07:22:38 +0000198 EHCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize,
199 unsigned FixupDepth,
200 EHScopeStack::stable_iterator EnclosingNormal,
201 EHScopeStack::stable_iterator EnclosingEH)
202 : EHScope(EHScope::Cleanup),
John McCallda65ea82010-07-13 20:32:21 +0000203 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
John McCall1f0fca52010-07-21 07:22:38 +0000228 EHScopeStack::Cleanup *getCleanup() {
229 return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
John McCallda65ea82010-07-13 20:32:21 +0000230 }
231
232 static bool classof(const EHScope *Scope) {
John McCall1f0fca52010-07-21 07:22:38 +0000233 return (Scope->getKind() == Cleanup);
John McCallda65ea82010-07-13 20:32:21 +0000234 }
235};
236
John McCallf1549f62010-07-06 01:34:17 +0000237/// An exceptions scope which filters exceptions thrown through it.
238/// Only exceptions matching the filter types will be permitted to be
239/// thrown.
240///
241/// This is used to implement C++ exception specifications.
242class EHFilterScope : public EHScope {
243 unsigned NumFilters : BitsRemaining;
244
245 // Essentially ends in a flexible array member:
246 // llvm::Value *FilterTypes[0];
247
248 llvm::Value **getFilters() {
249 return reinterpret_cast<llvm::Value**>(this+1);
250 }
251
252 llvm::Value * const *getFilters() const {
253 return reinterpret_cast<llvm::Value* const *>(this+1);
254 }
255
256public:
257 EHFilterScope(unsigned NumFilters) :
258 EHScope(Filter), NumFilters(NumFilters) {}
259
260 static size_t getSizeForNumFilters(unsigned NumFilters) {
261 return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
262 }
263
264 unsigned getNumFilters() const { return NumFilters; }
265
266 void setFilter(unsigned I, llvm::Value *FilterValue) {
267 assert(I < getNumFilters());
268 getFilters()[I] = FilterValue;
269 }
270
271 llvm::Value *getFilter(unsigned I) const {
272 assert(I < getNumFilters());
273 return getFilters()[I];
274 }
275
276 static bool classof(const EHScope *Scope) {
277 return Scope->getKind() == Filter;
278 }
279};
280
281/// An exceptions scope which calls std::terminate if any exception
282/// reaches it.
283class EHTerminateScope : public EHScope {
284public:
285 EHTerminateScope() : EHScope(Terminate) {}
286 static size_t getSize() { return sizeof(EHTerminateScope); }
287
288 static bool classof(const EHScope *Scope) {
289 return Scope->getKind() == Terminate;
290 }
291};
292
293/// A non-stable pointer into the scope stack.
294class EHScopeStack::iterator {
295 char *Ptr;
296
297 friend class EHScopeStack;
298 explicit iterator(char *Ptr) : Ptr(Ptr) {}
299
300public:
301 iterator() : Ptr(0) {}
302
303 EHScope *get() const {
304 return reinterpret_cast<EHScope*>(Ptr);
305 }
306
307 EHScope *operator->() const { return get(); }
308 EHScope &operator*() const { return *get(); }
309
310 iterator &operator++() {
311 switch (get()->getKind()) {
312 case EHScope::Catch:
313 Ptr += EHCatchScope::getSizeForNumHandlers(
314 static_cast<const EHCatchScope*>(get())->getNumHandlers());
315 break;
316
317 case EHScope::Filter:
318 Ptr += EHFilterScope::getSizeForNumFilters(
319 static_cast<const EHFilterScope*>(get())->getNumFilters());
320 break;
321
John McCall1f0fca52010-07-21 07:22:38 +0000322 case EHScope::Cleanup:
323 Ptr += static_cast<const EHCleanupScope*>(get())
John McCallda65ea82010-07-13 20:32:21 +0000324 ->getAllocatedSize();
325 break;
326
John McCallf1549f62010-07-06 01:34:17 +0000327 case EHScope::Terminate:
328 Ptr += EHTerminateScope::getSize();
329 break;
330 }
331
332 return *this;
333 }
334
335 iterator next() {
336 iterator copy = *this;
337 ++copy;
338 return copy;
339 }
340
341 iterator operator++(int) {
342 iterator copy = *this;
343 operator++();
344 return copy;
345 }
346
347 bool operator==(iterator other) const { return Ptr == other.Ptr; }
348 bool operator!=(iterator other) const { return Ptr != other.Ptr; }
349};
350
351inline EHScopeStack::iterator EHScopeStack::begin() const {
352 return iterator(StartOfData);
353}
354
355inline EHScopeStack::iterator EHScopeStack::end() const {
356 return iterator(EndOfBuffer);
357}
358
359inline void EHScopeStack::popCatch() {
360 assert(!empty() && "popping exception stack when not empty");
361
362 assert(isa<EHCatchScope>(*begin()));
363 StartOfData += EHCatchScope::getSizeForNumHandlers(
364 cast<EHCatchScope>(*begin()).getNumHandlers());
365
366 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
367 CatchDepth--;
368}
369
370inline void EHScopeStack::popTerminate() {
371 assert(!empty() && "popping exception stack when not empty");
372
373 assert(isa<EHTerminateScope>(*begin()));
374 StartOfData += EHTerminateScope::getSize();
375
376 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
377 CatchDepth--;
378}
379
380inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
381 assert(sp.isValid() && "finding invalid savepoint");
382 assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
383 return iterator(EndOfBuffer - sp.Size);
384}
385
386inline EHScopeStack::stable_iterator
387EHScopeStack::stabilize(iterator ir) const {
388 assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
389 return stable_iterator(EndOfBuffer - ir.Ptr);
390}
391
392}
393}
394
395#endif