blob: 01536e35fb935f6dc6efca2d9643467a86b5dcdc [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
John McCallff8e1152010-07-23 21:56:41 +0000103 /// The unwind destination index for this handler.
104 unsigned Index;
John McCallf1549f62010-07-06 01:34:17 +0000105 };
106
107private:
John McCallff8e1152010-07-23 21:56:41 +0000108 friend class EHScopeStack;
109
John McCallf1549f62010-07-06 01:34:17 +0000110 Handler *getHandlers() {
111 return reinterpret_cast<Handler*>(this+1);
112 }
113
114 const Handler *getHandlers() const {
115 return reinterpret_cast<const Handler*>(this+1);
116 }
117
118public:
119 static size_t getSizeForNumHandlers(unsigned N) {
120 return sizeof(EHCatchScope) + N * sizeof(Handler);
121 }
122
123 EHCatchScope(unsigned NumHandlers)
124 : EHScope(Catch), NumHandlers(NumHandlers) {
125 }
126
127 unsigned getNumHandlers() const {
128 return NumHandlers;
129 }
130
131 void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
132 setHandler(I, /*catchall*/ 0, Block);
133 }
134
135 void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
136 assert(I < getNumHandlers());
John McCallff8e1152010-07-23 21:56:41 +0000137 getHandlers()[I].Type = Type;
138 getHandlers()[I].Block = Block;
John McCallf1549f62010-07-06 01:34:17 +0000139 }
140
141 const Handler &getHandler(unsigned I) const {
142 assert(I < getNumHandlers());
143 return getHandlers()[I];
144 }
145
146 typedef const Handler *iterator;
147 iterator begin() const { return getHandlers(); }
148 iterator end() const { return getHandlers() + getNumHandlers(); }
149
150 static bool classof(const EHScope *Scope) {
151 return Scope->getKind() == Catch;
152 }
153};
154
John McCallda65ea82010-07-13 20:32:21 +0000155/// A cleanup scope which generates the cleanup blocks lazily.
John McCall1f0fca52010-07-21 07:22:38 +0000156class EHCleanupScope : public EHScope {
John McCallda65ea82010-07-13 20:32:21 +0000157 /// Whether this cleanup needs to be run along normal edges.
158 bool IsNormalCleanup : 1;
159
160 /// Whether this cleanup needs to be run along exception edges.
161 bool IsEHCleanup : 1;
162
John McCall1f0fca52010-07-21 07:22:38 +0000163 /// The amount of extra storage needed by the Cleanup.
John McCallda65ea82010-07-13 20:32:21 +0000164 /// Always a multiple of the scope-stack alignment.
165 unsigned CleanupSize : 12;
166
167 /// The number of fixups required by enclosing scopes (not including
168 /// this one). If this is the top cleanup scope, all the fixups
169 /// from this index onwards belong to this scope.
170 unsigned FixupDepth : BitsRemaining - 14;
171
172 /// The nearest normal cleanup scope enclosing this one.
173 EHScopeStack::stable_iterator EnclosingNormal;
174
175 /// The nearest EH cleanup scope enclosing this one.
176 EHScopeStack::stable_iterator EnclosingEH;
177
178 /// The dual entry/exit block along the normal edge. This is lazily
179 /// created if needed before the cleanup is popped.
180 llvm::BasicBlock *NormalBlock;
181
182 /// The dual entry/exit block along the EH edge. This is lazily
183 /// created if needed before the cleanup is popped.
184 llvm::BasicBlock *EHBlock;
185
John McCallff8e1152010-07-23 21:56:41 +0000186 /// Extra information required for cleanups that have resolved
187 /// branches through them. This has to be allocated on the side
188 /// because everything on the cleanup stack has be trivially
189 /// movable.
190 struct ExtInfo {
191 /// The destinations of normal branch-afters and branch-throughs.
192 llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
193
194 /// Normal branch-afters.
195 llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
196 BranchAfters;
197
198 /// The destinations of EH branch-afters and branch-throughs.
199 /// TODO: optimize for the extremely common case of a single
200 /// branch-through.
201 llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
202
203 /// EH branch-afters.
204 llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
205 EHBranchAfters;
206 };
207 mutable struct ExtInfo *ExtInfo;
208
209 struct ExtInfo &getExtInfo() {
210 if (!ExtInfo) ExtInfo = new struct ExtInfo();
211 return *ExtInfo;
212 }
213
214 const struct ExtInfo &getExtInfo() const {
215 if (!ExtInfo) ExtInfo = new struct ExtInfo();
216 return *ExtInfo;
217 }
218
John McCallda65ea82010-07-13 20:32:21 +0000219public:
220 /// Gets the size required for a lazy cleanup scope with the given
221 /// cleanup-data requirements.
222 static size_t getSizeForCleanupSize(size_t Size) {
John McCall1f0fca52010-07-21 07:22:38 +0000223 return sizeof(EHCleanupScope) + Size;
John McCallda65ea82010-07-13 20:32:21 +0000224 }
225
226 size_t getAllocatedSize() const {
John McCall1f0fca52010-07-21 07:22:38 +0000227 return sizeof(EHCleanupScope) + CleanupSize;
John McCallda65ea82010-07-13 20:32:21 +0000228 }
229
John McCall1f0fca52010-07-21 07:22:38 +0000230 EHCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize,
231 unsigned FixupDepth,
232 EHScopeStack::stable_iterator EnclosingNormal,
233 EHScopeStack::stable_iterator EnclosingEH)
234 : EHScope(EHScope::Cleanup),
John McCallda65ea82010-07-13 20:32:21 +0000235 IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
236 CleanupSize(CleanupSize), FixupDepth(FixupDepth),
237 EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
John McCallff8e1152010-07-23 21:56:41 +0000238 NormalBlock(0), EHBlock(0), ExtInfo(0)
239 {
240 assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
241 }
242
243 ~EHCleanupScope() {
244 delete ExtInfo;
245 }
John McCallda65ea82010-07-13 20:32:21 +0000246
247 bool isNormalCleanup() const { return IsNormalCleanup; }
248 llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
249 void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
250
251 bool isEHCleanup() const { return IsEHCleanup; }
252 llvm::BasicBlock *getEHBlock() const { return EHBlock; }
253 void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
254
255 unsigned getFixupDepth() const { return FixupDepth; }
256 EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
257 return EnclosingNormal;
258 }
259 EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
260 return EnclosingEH;
261 }
262
263 size_t getCleanupSize() const { return CleanupSize; }
264 void *getCleanupBuffer() { return this + 1; }
265
John McCall1f0fca52010-07-21 07:22:38 +0000266 EHScopeStack::Cleanup *getCleanup() {
267 return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
John McCallda65ea82010-07-13 20:32:21 +0000268 }
269
John McCallff8e1152010-07-23 21:56:41 +0000270 /// True if this cleanup scope has any branch-afters or branch-throughs.
271 bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
272
273 /// Add a branch-after to this cleanup scope. A branch-after is a
274 /// branch from a point protected by this (normal) cleanup to a
275 /// point in the normal cleanup scope immediately containing it.
276 /// For example,
277 /// for (;;) { A a; break; }
278 /// contains a branch-after.
279 ///
280 /// Branch-afters each have their own destination out of the
281 /// cleanup, guaranteed distinct from anything else threaded through
282 /// it. Therefore branch-afters usually force a switch after the
283 /// cleanup.
284 void addBranchAfter(llvm::ConstantInt *Index,
285 llvm::BasicBlock *Block) {
286 struct ExtInfo &ExtInfo = getExtInfo();
287 if (ExtInfo.Branches.insert(Block))
288 ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
289 }
290
291 /// Return the number of unique branch-afters on this scope.
292 unsigned getNumBranchAfters() const {
293 return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
294 }
295
296 llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
297 assert(I < getNumBranchAfters());
298 return ExtInfo->BranchAfters[I].first;
299 }
300
301 llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
302 assert(I < getNumBranchAfters());
303 return ExtInfo->BranchAfters[I].second;
304 }
305
306 /// Add a branch-through to this cleanup scope. A branch-through is
307 /// a branch from a scope protected by this (normal) cleanup to an
308 /// enclosing scope other than the immediately-enclosing normal
309 /// cleanup scope.
310 ///
311 /// In the following example, the branch through B's scope is a
312 /// branch-through, while the branch through A's scope is a
313 /// branch-after:
314 /// for (;;) { A a; B b; break; }
315 ///
316 /// All branch-throughs have a common destination out of the
317 /// cleanup, one possibly shared with the fall-through. Therefore
318 /// branch-throughs usually don't force a switch after the cleanup.
319 ///
320 /// \return true if the branch-through was new to this scope
321 bool addBranchThrough(llvm::BasicBlock *Block) {
322 return getExtInfo().Branches.insert(Block);
323 }
324
325 /// Determines if this cleanup scope has any branch throughs.
326 bool hasBranchThroughs() const {
327 if (!ExtInfo) return false;
328 return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
329 }
330
331 // Same stuff, only for EH branches instead of normal branches.
332 // It's quite possible that we could find a better representation
333 // for this.
334
335 bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
336 void addEHBranchAfter(llvm::ConstantInt *Index,
337 llvm::BasicBlock *Block) {
338 struct ExtInfo &ExtInfo = getExtInfo();
339 if (ExtInfo.EHBranches.insert(Block))
340 ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
341 }
342
343 unsigned getNumEHBranchAfters() const {
344 return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
345 }
346
347 llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
348 assert(I < getNumEHBranchAfters());
349 return ExtInfo->EHBranchAfters[I].first;
350 }
351
352 llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
353 assert(I < getNumEHBranchAfters());
354 return ExtInfo->EHBranchAfters[I].second;
355 }
356
357 bool addEHBranchThrough(llvm::BasicBlock *Block) {
358 return getExtInfo().EHBranches.insert(Block);
359 }
360
361 bool hasEHBranchThroughs() const {
362 if (!ExtInfo) return false;
363 return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
364 }
365
John McCallda65ea82010-07-13 20:32:21 +0000366 static bool classof(const EHScope *Scope) {
John McCall1f0fca52010-07-21 07:22:38 +0000367 return (Scope->getKind() == Cleanup);
John McCallda65ea82010-07-13 20:32:21 +0000368 }
369};
370
John McCallf1549f62010-07-06 01:34:17 +0000371/// An exceptions scope which filters exceptions thrown through it.
372/// Only exceptions matching the filter types will be permitted to be
373/// thrown.
374///
375/// This is used to implement C++ exception specifications.
376class EHFilterScope : public EHScope {
377 unsigned NumFilters : BitsRemaining;
378
379 // Essentially ends in a flexible array member:
380 // llvm::Value *FilterTypes[0];
381
382 llvm::Value **getFilters() {
383 return reinterpret_cast<llvm::Value**>(this+1);
384 }
385
386 llvm::Value * const *getFilters() const {
387 return reinterpret_cast<llvm::Value* const *>(this+1);
388 }
389
390public:
391 EHFilterScope(unsigned NumFilters) :
392 EHScope(Filter), NumFilters(NumFilters) {}
393
394 static size_t getSizeForNumFilters(unsigned NumFilters) {
395 return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
396 }
397
398 unsigned getNumFilters() const { return NumFilters; }
399
400 void setFilter(unsigned I, llvm::Value *FilterValue) {
401 assert(I < getNumFilters());
402 getFilters()[I] = FilterValue;
403 }
404
405 llvm::Value *getFilter(unsigned I) const {
406 assert(I < getNumFilters());
407 return getFilters()[I];
408 }
409
410 static bool classof(const EHScope *Scope) {
411 return Scope->getKind() == Filter;
412 }
413};
414
415/// An exceptions scope which calls std::terminate if any exception
416/// reaches it.
417class EHTerminateScope : public EHScope {
John McCallff8e1152010-07-23 21:56:41 +0000418 unsigned DestIndex : BitsRemaining;
John McCallf1549f62010-07-06 01:34:17 +0000419public:
John McCallff8e1152010-07-23 21:56:41 +0000420 EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
John McCallf1549f62010-07-06 01:34:17 +0000421 static size_t getSize() { return sizeof(EHTerminateScope); }
422
John McCallff8e1152010-07-23 21:56:41 +0000423 unsigned getDestIndex() const { return DestIndex; }
424
John McCallf1549f62010-07-06 01:34:17 +0000425 static bool classof(const EHScope *Scope) {
426 return Scope->getKind() == Terminate;
427 }
428};
429
430/// A non-stable pointer into the scope stack.
431class EHScopeStack::iterator {
432 char *Ptr;
433
434 friend class EHScopeStack;
435 explicit iterator(char *Ptr) : Ptr(Ptr) {}
436
437public:
438 iterator() : Ptr(0) {}
439
440 EHScope *get() const {
441 return reinterpret_cast<EHScope*>(Ptr);
442 }
443
444 EHScope *operator->() const { return get(); }
445 EHScope &operator*() const { return *get(); }
446
447 iterator &operator++() {
448 switch (get()->getKind()) {
449 case EHScope::Catch:
450 Ptr += EHCatchScope::getSizeForNumHandlers(
451 static_cast<const EHCatchScope*>(get())->getNumHandlers());
452 break;
453
454 case EHScope::Filter:
455 Ptr += EHFilterScope::getSizeForNumFilters(
456 static_cast<const EHFilterScope*>(get())->getNumFilters());
457 break;
458
John McCall1f0fca52010-07-21 07:22:38 +0000459 case EHScope::Cleanup:
460 Ptr += static_cast<const EHCleanupScope*>(get())
John McCallda65ea82010-07-13 20:32:21 +0000461 ->getAllocatedSize();
462 break;
463
John McCallf1549f62010-07-06 01:34:17 +0000464 case EHScope::Terminate:
465 Ptr += EHTerminateScope::getSize();
466 break;
467 }
468
469 return *this;
470 }
471
472 iterator next() {
473 iterator copy = *this;
474 ++copy;
475 return copy;
476 }
477
478 iterator operator++(int) {
479 iterator copy = *this;
480 operator++();
481 return copy;
482 }
483
John McCallff8e1152010-07-23 21:56:41 +0000484 bool encloses(iterator other) const { return Ptr >= other.Ptr; }
485 bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
486
John McCallf1549f62010-07-06 01:34:17 +0000487 bool operator==(iterator other) const { return Ptr == other.Ptr; }
488 bool operator!=(iterator other) const { return Ptr != other.Ptr; }
489};
490
491inline EHScopeStack::iterator EHScopeStack::begin() const {
492 return iterator(StartOfData);
493}
494
495inline EHScopeStack::iterator EHScopeStack::end() const {
496 return iterator(EndOfBuffer);
497}
498
499inline void EHScopeStack::popCatch() {
500 assert(!empty() && "popping exception stack when not empty");
501
502 assert(isa<EHCatchScope>(*begin()));
503 StartOfData += EHCatchScope::getSizeForNumHandlers(
504 cast<EHCatchScope>(*begin()).getNumHandlers());
505
John McCallff8e1152010-07-23 21:56:41 +0000506 if (empty()) NextEHDestIndex = FirstEHDestIndex;
507
John McCallf1549f62010-07-06 01:34:17 +0000508 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
509 CatchDepth--;
510}
511
512inline void EHScopeStack::popTerminate() {
513 assert(!empty() && "popping exception stack when not empty");
514
515 assert(isa<EHTerminateScope>(*begin()));
516 StartOfData += EHTerminateScope::getSize();
517
John McCallff8e1152010-07-23 21:56:41 +0000518 if (empty()) NextEHDestIndex = FirstEHDestIndex;
519
John McCallf1549f62010-07-06 01:34:17 +0000520 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
521 CatchDepth--;
522}
523
524inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
525 assert(sp.isValid() && "finding invalid savepoint");
526 assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
527 return iterator(EndOfBuffer - sp.Size);
528}
529
530inline EHScopeStack::stable_iterator
531EHScopeStack::stabilize(iterator ir) const {
532 assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
533 return stable_iterator(EndOfBuffer - ir.Ptr);
534}
535
536}
537}
538
539#endif