1f4a2713aSLionel Sambuc //===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===// 2f4a2713aSLionel Sambuc // 3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure 4f4a2713aSLionel Sambuc // 5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source 6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details. 7f4a2713aSLionel Sambuc // 8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 9f4a2713aSLionel Sambuc // 10f4a2713aSLionel Sambuc // These classes should be the minimum interface required for other parts of 11f4a2713aSLionel Sambuc // CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other 12f4a2713aSLionel Sambuc // implemenentation details that are not widely needed are in CGCleanup.h. 13f4a2713aSLionel Sambuc // 14f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 15f4a2713aSLionel Sambuc 16*0a6a1f1dSLionel Sambuc #ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H 17*0a6a1f1dSLionel Sambuc #define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H 18f4a2713aSLionel Sambuc 19f4a2713aSLionel Sambuc #include "clang/Basic/LLVM.h" 20f4a2713aSLionel Sambuc #include "llvm/ADT/SmallVector.h" 21f4a2713aSLionel Sambuc #include "llvm/IR/BasicBlock.h" 22f4a2713aSLionel Sambuc #include "llvm/IR/Instructions.h" 23*0a6a1f1dSLionel Sambuc #include "llvm/IR/Value.h" 24f4a2713aSLionel Sambuc 25f4a2713aSLionel Sambuc namespace clang { 26f4a2713aSLionel Sambuc namespace CodeGen { 27f4a2713aSLionel Sambuc 28f4a2713aSLionel Sambuc class CodeGenFunction; 29f4a2713aSLionel Sambuc 30f4a2713aSLionel Sambuc /// A branch fixup. These are required when emitting a goto to a 31f4a2713aSLionel Sambuc /// label which hasn't been emitted yet. The goto is optimistically 32f4a2713aSLionel Sambuc /// emitted as a branch to the basic block for the label, and (if it 33f4a2713aSLionel Sambuc /// occurs in a scope with non-trivial cleanups) a fixup is added to 34f4a2713aSLionel Sambuc /// the innermost cleanup. When a (normal) cleanup is popped, any 35f4a2713aSLionel Sambuc /// unresolved fixups in that scope are threaded through the cleanup. 36f4a2713aSLionel Sambuc struct BranchFixup { 37f4a2713aSLionel Sambuc /// The block containing the terminator which needs to be modified 38f4a2713aSLionel Sambuc /// into a switch if this fixup is resolved into the current scope. 39f4a2713aSLionel Sambuc /// If null, LatestBranch points directly to the destination. 40f4a2713aSLionel Sambuc llvm::BasicBlock *OptimisticBranchBlock; 41f4a2713aSLionel Sambuc 42f4a2713aSLionel Sambuc /// The ultimate destination of the branch. 43f4a2713aSLionel Sambuc /// 44f4a2713aSLionel Sambuc /// This can be set to null to indicate that this fixup was 45f4a2713aSLionel Sambuc /// successfully resolved. 46f4a2713aSLionel Sambuc llvm::BasicBlock *Destination; 47f4a2713aSLionel Sambuc 48f4a2713aSLionel Sambuc /// The destination index value. 49f4a2713aSLionel Sambuc unsigned DestinationIndex; 50f4a2713aSLionel Sambuc 51f4a2713aSLionel Sambuc /// The initial branch of the fixup. 52f4a2713aSLionel Sambuc llvm::BranchInst *InitialBranch; 53f4a2713aSLionel Sambuc }; 54f4a2713aSLionel Sambuc 55f4a2713aSLionel Sambuc template <class T> struct InvariantValue { 56f4a2713aSLionel Sambuc typedef T type; 57f4a2713aSLionel Sambuc typedef T saved_type; needsSavingInvariantValue58f4a2713aSLionel Sambuc static bool needsSaving(type value) { return false; } saveInvariantValue59f4a2713aSLionel Sambuc static saved_type save(CodeGenFunction &CGF, type value) { return value; } restoreInvariantValue60f4a2713aSLionel Sambuc static type restore(CodeGenFunction &CGF, saved_type value) { return value; } 61f4a2713aSLionel Sambuc }; 62f4a2713aSLionel Sambuc 63f4a2713aSLionel Sambuc /// A metaprogramming class for ensuring that a value will dominate an 64f4a2713aSLionel Sambuc /// arbitrary position in a function. 65f4a2713aSLionel Sambuc template <class T> struct DominatingValue : InvariantValue<T> {}; 66f4a2713aSLionel Sambuc 67f4a2713aSLionel Sambuc template <class T, bool mightBeInstruction = 68*0a6a1f1dSLionel Sambuc std::is_base_of<llvm::Value, T>::value && 69*0a6a1f1dSLionel Sambuc !std::is_base_of<llvm::Constant, T>::value && 70*0a6a1f1dSLionel Sambuc !std::is_base_of<llvm::BasicBlock, T>::value> 71f4a2713aSLionel Sambuc struct DominatingPointer; 72f4a2713aSLionel Sambuc template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {}; 73f4a2713aSLionel Sambuc // template <class T> struct DominatingPointer<T,true> at end of file 74f4a2713aSLionel Sambuc 75f4a2713aSLionel Sambuc template <class T> struct DominatingValue<T*> : DominatingPointer<T> {}; 76f4a2713aSLionel Sambuc 77*0a6a1f1dSLionel Sambuc enum CleanupKind : unsigned { 78f4a2713aSLionel Sambuc EHCleanup = 0x1, 79f4a2713aSLionel Sambuc NormalCleanup = 0x2, 80f4a2713aSLionel Sambuc NormalAndEHCleanup = EHCleanup | NormalCleanup, 81f4a2713aSLionel Sambuc 82f4a2713aSLionel Sambuc InactiveCleanup = 0x4, 83f4a2713aSLionel Sambuc InactiveEHCleanup = EHCleanup | InactiveCleanup, 84f4a2713aSLionel Sambuc InactiveNormalCleanup = NormalCleanup | InactiveCleanup, 85f4a2713aSLionel Sambuc InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup 86f4a2713aSLionel Sambuc }; 87f4a2713aSLionel Sambuc 88f4a2713aSLionel Sambuc /// A stack of scopes which respond to exceptions, including cleanups 89f4a2713aSLionel Sambuc /// and catch blocks. 90f4a2713aSLionel Sambuc class EHScopeStack { 91f4a2713aSLionel Sambuc public: 92f4a2713aSLionel Sambuc /// A saved depth on the scope stack. This is necessary because 93f4a2713aSLionel Sambuc /// pushing scopes onto the stack invalidates iterators. 94f4a2713aSLionel Sambuc class stable_iterator { 95f4a2713aSLionel Sambuc friend class EHScopeStack; 96f4a2713aSLionel Sambuc 97f4a2713aSLionel Sambuc /// Offset from StartOfData to EndOfBuffer. 98f4a2713aSLionel Sambuc ptrdiff_t Size; 99f4a2713aSLionel Sambuc 100f4a2713aSLionel Sambuc stable_iterator(ptrdiff_t Size) : Size(Size) {} 101f4a2713aSLionel Sambuc 102f4a2713aSLionel Sambuc public: 103f4a2713aSLionel Sambuc static stable_iterator invalid() { return stable_iterator(-1); } 104f4a2713aSLionel Sambuc stable_iterator() : Size(-1) {} 105f4a2713aSLionel Sambuc 106f4a2713aSLionel Sambuc bool isValid() const { return Size >= 0; } 107f4a2713aSLionel Sambuc 108f4a2713aSLionel Sambuc /// Returns true if this scope encloses I. 109f4a2713aSLionel Sambuc /// Returns false if I is invalid. 110f4a2713aSLionel Sambuc /// This scope must be valid. 111f4a2713aSLionel Sambuc bool encloses(stable_iterator I) const { return Size <= I.Size; } 112f4a2713aSLionel Sambuc 113f4a2713aSLionel Sambuc /// Returns true if this scope strictly encloses I: that is, 114f4a2713aSLionel Sambuc /// if it encloses I and is not I. 115f4a2713aSLionel Sambuc /// Returns false is I is invalid. 116f4a2713aSLionel Sambuc /// This scope must be valid. 117f4a2713aSLionel Sambuc bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; } 118f4a2713aSLionel Sambuc 119f4a2713aSLionel Sambuc friend bool operator==(stable_iterator A, stable_iterator B) { 120f4a2713aSLionel Sambuc return A.Size == B.Size; 121f4a2713aSLionel Sambuc } 122f4a2713aSLionel Sambuc friend bool operator!=(stable_iterator A, stable_iterator B) { 123f4a2713aSLionel Sambuc return A.Size != B.Size; 124f4a2713aSLionel Sambuc } 125f4a2713aSLionel Sambuc }; 126f4a2713aSLionel Sambuc 127f4a2713aSLionel Sambuc /// Information for lazily generating a cleanup. Subclasses must be 128f4a2713aSLionel Sambuc /// POD-like: cleanups will not be destructed, and they will be 129f4a2713aSLionel Sambuc /// allocated on the cleanup stack and freely copied and moved 130f4a2713aSLionel Sambuc /// around. 131f4a2713aSLionel Sambuc /// 132f4a2713aSLionel Sambuc /// Cleanup implementations should generally be declared in an 133f4a2713aSLionel Sambuc /// anonymous namespace. 134f4a2713aSLionel Sambuc class Cleanup { 135f4a2713aSLionel Sambuc // Anchor the construction vtable. 136f4a2713aSLionel Sambuc virtual void anchor(); 137f4a2713aSLionel Sambuc public: 138f4a2713aSLionel Sambuc /// Generation flags. 139f4a2713aSLionel Sambuc class Flags { 140f4a2713aSLionel Sambuc enum { 141f4a2713aSLionel Sambuc F_IsForEH = 0x1, 142f4a2713aSLionel Sambuc F_IsNormalCleanupKind = 0x2, 143f4a2713aSLionel Sambuc F_IsEHCleanupKind = 0x4 144f4a2713aSLionel Sambuc }; 145f4a2713aSLionel Sambuc unsigned flags; 146f4a2713aSLionel Sambuc 147f4a2713aSLionel Sambuc public: 148f4a2713aSLionel Sambuc Flags() : flags(0) {} 149f4a2713aSLionel Sambuc 150f4a2713aSLionel Sambuc /// isForEH - true if the current emission is for an EH cleanup. 151f4a2713aSLionel Sambuc bool isForEHCleanup() const { return flags & F_IsForEH; } 152f4a2713aSLionel Sambuc bool isForNormalCleanup() const { return !isForEHCleanup(); } 153f4a2713aSLionel Sambuc void setIsForEHCleanup() { flags |= F_IsForEH; } 154f4a2713aSLionel Sambuc 155f4a2713aSLionel Sambuc bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; } 156f4a2713aSLionel Sambuc void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; } 157f4a2713aSLionel Sambuc 158f4a2713aSLionel Sambuc /// isEHCleanupKind - true if the cleanup was pushed as an EH 159f4a2713aSLionel Sambuc /// cleanup. 160f4a2713aSLionel Sambuc bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } 161f4a2713aSLionel Sambuc void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } 162f4a2713aSLionel Sambuc }; 163f4a2713aSLionel Sambuc 164f4a2713aSLionel Sambuc // Provide a virtual destructor to suppress a very common warning 165f4a2713aSLionel Sambuc // that unfortunately cannot be suppressed without this. Cleanups 166f4a2713aSLionel Sambuc // should not rely on this destructor ever being called. 167f4a2713aSLionel Sambuc virtual ~Cleanup() {} 168f4a2713aSLionel Sambuc 169f4a2713aSLionel Sambuc /// Emit the cleanup. For normal cleanups, this is run in the 170f4a2713aSLionel Sambuc /// same EH context as when the cleanup was pushed, i.e. the 171f4a2713aSLionel Sambuc /// immediately-enclosing context of the cleanup scope. For 172f4a2713aSLionel Sambuc /// EH cleanups, this is run in a terminate context. 173f4a2713aSLionel Sambuc /// 174f4a2713aSLionel Sambuc // \param flags cleanup kind. 175f4a2713aSLionel Sambuc virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; 176f4a2713aSLionel Sambuc }; 177f4a2713aSLionel Sambuc 178f4a2713aSLionel Sambuc /// ConditionalCleanupN stores the saved form of its N parameters, 179f4a2713aSLionel Sambuc /// then restores them and performs the cleanup. 180f4a2713aSLionel Sambuc template <class T, class A0> 181f4a2713aSLionel Sambuc class ConditionalCleanup1 : public Cleanup { 182f4a2713aSLionel Sambuc typedef typename DominatingValue<A0>::saved_type A0_saved; 183f4a2713aSLionel Sambuc A0_saved a0_saved; 184f4a2713aSLionel Sambuc 185*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override { 186f4a2713aSLionel Sambuc A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 187f4a2713aSLionel Sambuc T(a0).Emit(CGF, flags); 188f4a2713aSLionel Sambuc } 189f4a2713aSLionel Sambuc 190f4a2713aSLionel Sambuc public: 191f4a2713aSLionel Sambuc ConditionalCleanup1(A0_saved a0) 192f4a2713aSLionel Sambuc : a0_saved(a0) {} 193f4a2713aSLionel Sambuc }; 194f4a2713aSLionel Sambuc 195f4a2713aSLionel Sambuc template <class T, class A0, class A1> 196f4a2713aSLionel Sambuc class ConditionalCleanup2 : public Cleanup { 197f4a2713aSLionel Sambuc typedef typename DominatingValue<A0>::saved_type A0_saved; 198f4a2713aSLionel Sambuc typedef typename DominatingValue<A1>::saved_type A1_saved; 199f4a2713aSLionel Sambuc A0_saved a0_saved; 200f4a2713aSLionel Sambuc A1_saved a1_saved; 201f4a2713aSLionel Sambuc 202*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override { 203f4a2713aSLionel Sambuc A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 204f4a2713aSLionel Sambuc A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 205f4a2713aSLionel Sambuc T(a0, a1).Emit(CGF, flags); 206f4a2713aSLionel Sambuc } 207f4a2713aSLionel Sambuc 208f4a2713aSLionel Sambuc public: 209f4a2713aSLionel Sambuc ConditionalCleanup2(A0_saved a0, A1_saved a1) 210f4a2713aSLionel Sambuc : a0_saved(a0), a1_saved(a1) {} 211f4a2713aSLionel Sambuc }; 212f4a2713aSLionel Sambuc 213f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2> 214f4a2713aSLionel Sambuc class ConditionalCleanup3 : public Cleanup { 215f4a2713aSLionel Sambuc typedef typename DominatingValue<A0>::saved_type A0_saved; 216f4a2713aSLionel Sambuc typedef typename DominatingValue<A1>::saved_type A1_saved; 217f4a2713aSLionel Sambuc typedef typename DominatingValue<A2>::saved_type A2_saved; 218f4a2713aSLionel Sambuc A0_saved a0_saved; 219f4a2713aSLionel Sambuc A1_saved a1_saved; 220f4a2713aSLionel Sambuc A2_saved a2_saved; 221f4a2713aSLionel Sambuc 222*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override { 223f4a2713aSLionel Sambuc A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 224f4a2713aSLionel Sambuc A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 225f4a2713aSLionel Sambuc A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved); 226f4a2713aSLionel Sambuc T(a0, a1, a2).Emit(CGF, flags); 227f4a2713aSLionel Sambuc } 228f4a2713aSLionel Sambuc 229f4a2713aSLionel Sambuc public: 230f4a2713aSLionel Sambuc ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2) 231f4a2713aSLionel Sambuc : a0_saved(a0), a1_saved(a1), a2_saved(a2) {} 232f4a2713aSLionel Sambuc }; 233f4a2713aSLionel Sambuc 234f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2, class A3> 235f4a2713aSLionel Sambuc class ConditionalCleanup4 : public Cleanup { 236f4a2713aSLionel Sambuc typedef typename DominatingValue<A0>::saved_type A0_saved; 237f4a2713aSLionel Sambuc typedef typename DominatingValue<A1>::saved_type A1_saved; 238f4a2713aSLionel Sambuc typedef typename DominatingValue<A2>::saved_type A2_saved; 239f4a2713aSLionel Sambuc typedef typename DominatingValue<A3>::saved_type A3_saved; 240f4a2713aSLionel Sambuc A0_saved a0_saved; 241f4a2713aSLionel Sambuc A1_saved a1_saved; 242f4a2713aSLionel Sambuc A2_saved a2_saved; 243f4a2713aSLionel Sambuc A3_saved a3_saved; 244f4a2713aSLionel Sambuc 245*0a6a1f1dSLionel Sambuc void Emit(CodeGenFunction &CGF, Flags flags) override { 246f4a2713aSLionel Sambuc A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 247f4a2713aSLionel Sambuc A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 248f4a2713aSLionel Sambuc A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved); 249f4a2713aSLionel Sambuc A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved); 250f4a2713aSLionel Sambuc T(a0, a1, a2, a3).Emit(CGF, flags); 251f4a2713aSLionel Sambuc } 252f4a2713aSLionel Sambuc 253f4a2713aSLionel Sambuc public: 254f4a2713aSLionel Sambuc ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3) 255f4a2713aSLionel Sambuc : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {} 256f4a2713aSLionel Sambuc }; 257f4a2713aSLionel Sambuc 258f4a2713aSLionel Sambuc private: 259f4a2713aSLionel Sambuc // The implementation for this class is in CGException.h and 260f4a2713aSLionel Sambuc // CGException.cpp; the definition is here because it's used as a 261f4a2713aSLionel Sambuc // member of CodeGenFunction. 262f4a2713aSLionel Sambuc 263f4a2713aSLionel Sambuc /// The start of the scope-stack buffer, i.e. the allocated pointer 264f4a2713aSLionel Sambuc /// for the buffer. All of these pointers are either simultaneously 265f4a2713aSLionel Sambuc /// null or simultaneously valid. 266f4a2713aSLionel Sambuc char *StartOfBuffer; 267f4a2713aSLionel Sambuc 268f4a2713aSLionel Sambuc /// The end of the buffer. 269f4a2713aSLionel Sambuc char *EndOfBuffer; 270f4a2713aSLionel Sambuc 271f4a2713aSLionel Sambuc /// The first valid entry in the buffer. 272f4a2713aSLionel Sambuc char *StartOfData; 273f4a2713aSLionel Sambuc 274f4a2713aSLionel Sambuc /// The innermost normal cleanup on the stack. 275f4a2713aSLionel Sambuc stable_iterator InnermostNormalCleanup; 276f4a2713aSLionel Sambuc 277f4a2713aSLionel Sambuc /// The innermost EH scope on the stack. 278f4a2713aSLionel Sambuc stable_iterator InnermostEHScope; 279f4a2713aSLionel Sambuc 280f4a2713aSLionel Sambuc /// The current set of branch fixups. A branch fixup is a jump to 281f4a2713aSLionel Sambuc /// an as-yet unemitted label, i.e. a label for which we don't yet 282f4a2713aSLionel Sambuc /// know the EH stack depth. Whenever we pop a cleanup, we have 283f4a2713aSLionel Sambuc /// to thread all the current branch fixups through it. 284f4a2713aSLionel Sambuc /// 285f4a2713aSLionel Sambuc /// Fixups are recorded as the Use of the respective branch or 286f4a2713aSLionel Sambuc /// switch statement. The use points to the final destination. 287f4a2713aSLionel Sambuc /// When popping out of a cleanup, these uses are threaded through 288f4a2713aSLionel Sambuc /// the cleanup and adjusted to point to the new cleanup. 289f4a2713aSLionel Sambuc /// 290f4a2713aSLionel Sambuc /// Note that branches are allowed to jump into protected scopes 291f4a2713aSLionel Sambuc /// in certain situations; e.g. the following code is legal: 292f4a2713aSLionel Sambuc /// struct A { ~A(); }; // trivial ctor, non-trivial dtor 293f4a2713aSLionel Sambuc /// goto foo; 294f4a2713aSLionel Sambuc /// A a; 295f4a2713aSLionel Sambuc /// foo: 296f4a2713aSLionel Sambuc /// bar(); 297f4a2713aSLionel Sambuc SmallVector<BranchFixup, 8> BranchFixups; 298f4a2713aSLionel Sambuc 299f4a2713aSLionel Sambuc char *allocate(size_t Size); 300f4a2713aSLionel Sambuc 301f4a2713aSLionel Sambuc void *pushCleanup(CleanupKind K, size_t DataSize); 302f4a2713aSLionel Sambuc 303f4a2713aSLionel Sambuc public: 304*0a6a1f1dSLionel Sambuc EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr), 305*0a6a1f1dSLionel Sambuc StartOfData(nullptr), InnermostNormalCleanup(stable_end()), 306f4a2713aSLionel Sambuc InnermostEHScope(stable_end()) {} 307f4a2713aSLionel Sambuc ~EHScopeStack() { delete[] StartOfBuffer; } 308f4a2713aSLionel Sambuc 309f4a2713aSLionel Sambuc // Variadic templates would make this not terrible. 310f4a2713aSLionel Sambuc 311f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 312f4a2713aSLionel Sambuc template <class T> 313f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind) { 314f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 315f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(); 316f4a2713aSLionel Sambuc (void) Obj; 317f4a2713aSLionel Sambuc } 318f4a2713aSLionel Sambuc 319f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 320f4a2713aSLionel Sambuc template <class T, class A0> 321f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind, A0 a0) { 322f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 323f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(a0); 324f4a2713aSLionel Sambuc (void) Obj; 325f4a2713aSLionel Sambuc } 326f4a2713aSLionel Sambuc 327f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 328f4a2713aSLionel Sambuc template <class T, class A0, class A1> 329f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind, A0 a0, A1 a1) { 330f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 331f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(a0, a1); 332f4a2713aSLionel Sambuc (void) Obj; 333f4a2713aSLionel Sambuc } 334f4a2713aSLionel Sambuc 335f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 336f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2> 337f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) { 338f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 339f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(a0, a1, a2); 340f4a2713aSLionel Sambuc (void) Obj; 341f4a2713aSLionel Sambuc } 342f4a2713aSLionel Sambuc 343f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 344f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2, class A3> 345f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { 346f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 347f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3); 348f4a2713aSLionel Sambuc (void) Obj; 349f4a2713aSLionel Sambuc } 350f4a2713aSLionel Sambuc 351f4a2713aSLionel Sambuc /// Push a lazily-created cleanup on the stack. 352f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2, class A3, class A4> 353f4a2713aSLionel Sambuc void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 354f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T)); 355f4a2713aSLionel Sambuc Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3, a4); 356f4a2713aSLionel Sambuc (void) Obj; 357f4a2713aSLionel Sambuc } 358f4a2713aSLionel Sambuc 359f4a2713aSLionel Sambuc // Feel free to add more variants of the following: 360f4a2713aSLionel Sambuc 361f4a2713aSLionel Sambuc /// Push a cleanup with non-constant storage requirements on the 362f4a2713aSLionel Sambuc /// stack. The cleanup type must provide an additional static method: 363f4a2713aSLionel Sambuc /// static size_t getExtraSize(size_t); 364f4a2713aSLionel Sambuc /// The argument to this method will be the value N, which will also 365f4a2713aSLionel Sambuc /// be passed as the first argument to the constructor. 366f4a2713aSLionel Sambuc /// 367f4a2713aSLionel Sambuc /// The data stored in the extra storage must obey the same 368f4a2713aSLionel Sambuc /// restrictions as normal cleanup member data. 369f4a2713aSLionel Sambuc /// 370f4a2713aSLionel Sambuc /// The pointer returned from this method is valid until the cleanup 371f4a2713aSLionel Sambuc /// stack is modified. 372f4a2713aSLionel Sambuc template <class T, class A0, class A1, class A2> 373f4a2713aSLionel Sambuc T *pushCleanupWithExtra(CleanupKind Kind, size_t N, A0 a0, A1 a1, A2 a2) { 374f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); 375f4a2713aSLionel Sambuc return new (Buffer) T(N, a0, a1, a2); 376f4a2713aSLionel Sambuc } 377f4a2713aSLionel Sambuc 378f4a2713aSLionel Sambuc void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) { 379f4a2713aSLionel Sambuc void *Buffer = pushCleanup(Kind, Size); 380f4a2713aSLionel Sambuc std::memcpy(Buffer, Cleanup, Size); 381f4a2713aSLionel Sambuc } 382f4a2713aSLionel Sambuc 383f4a2713aSLionel Sambuc /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. 384f4a2713aSLionel Sambuc void popCleanup(); 385f4a2713aSLionel Sambuc 386f4a2713aSLionel Sambuc /// Push a set of catch handlers on the stack. The catch is 387f4a2713aSLionel Sambuc /// uninitialized and will need to have the given number of handlers 388f4a2713aSLionel Sambuc /// set on it. 389f4a2713aSLionel Sambuc class EHCatchScope *pushCatch(unsigned NumHandlers); 390f4a2713aSLionel Sambuc 391f4a2713aSLionel Sambuc /// Pops a catch scope off the stack. This is private to CGException.cpp. 392f4a2713aSLionel Sambuc void popCatch(); 393f4a2713aSLionel Sambuc 394f4a2713aSLionel Sambuc /// Push an exceptions filter on the stack. 395f4a2713aSLionel Sambuc class EHFilterScope *pushFilter(unsigned NumFilters); 396f4a2713aSLionel Sambuc 397f4a2713aSLionel Sambuc /// Pops an exceptions filter off the stack. 398f4a2713aSLionel Sambuc void popFilter(); 399f4a2713aSLionel Sambuc 400f4a2713aSLionel Sambuc /// Push a terminate handler on the stack. 401f4a2713aSLionel Sambuc void pushTerminate(); 402f4a2713aSLionel Sambuc 403f4a2713aSLionel Sambuc /// Pops a terminate handler off the stack. 404f4a2713aSLionel Sambuc void popTerminate(); 405f4a2713aSLionel Sambuc 406f4a2713aSLionel Sambuc /// Determines whether the exception-scopes stack is empty. 407f4a2713aSLionel Sambuc bool empty() const { return StartOfData == EndOfBuffer; } 408f4a2713aSLionel Sambuc 409f4a2713aSLionel Sambuc bool requiresLandingPad() const { 410f4a2713aSLionel Sambuc return InnermostEHScope != stable_end(); 411f4a2713aSLionel Sambuc } 412f4a2713aSLionel Sambuc 413f4a2713aSLionel Sambuc /// Determines whether there are any normal cleanups on the stack. 414f4a2713aSLionel Sambuc bool hasNormalCleanups() const { 415f4a2713aSLionel Sambuc return InnermostNormalCleanup != stable_end(); 416f4a2713aSLionel Sambuc } 417f4a2713aSLionel Sambuc 418f4a2713aSLionel Sambuc /// Returns the innermost normal cleanup on the stack, or 419f4a2713aSLionel Sambuc /// stable_end() if there are no normal cleanups. 420f4a2713aSLionel Sambuc stable_iterator getInnermostNormalCleanup() const { 421f4a2713aSLionel Sambuc return InnermostNormalCleanup; 422f4a2713aSLionel Sambuc } 423f4a2713aSLionel Sambuc stable_iterator getInnermostActiveNormalCleanup() const; 424f4a2713aSLionel Sambuc 425f4a2713aSLionel Sambuc stable_iterator getInnermostEHScope() const { 426f4a2713aSLionel Sambuc return InnermostEHScope; 427f4a2713aSLionel Sambuc } 428f4a2713aSLionel Sambuc 429f4a2713aSLionel Sambuc stable_iterator getInnermostActiveEHScope() const; 430f4a2713aSLionel Sambuc 431f4a2713aSLionel Sambuc /// An unstable reference to a scope-stack depth. Invalidated by 432f4a2713aSLionel Sambuc /// pushes but not pops. 433f4a2713aSLionel Sambuc class iterator; 434f4a2713aSLionel Sambuc 435f4a2713aSLionel Sambuc /// Returns an iterator pointing to the innermost EH scope. 436f4a2713aSLionel Sambuc iterator begin() const; 437f4a2713aSLionel Sambuc 438f4a2713aSLionel Sambuc /// Returns an iterator pointing to the outermost EH scope. 439f4a2713aSLionel Sambuc iterator end() const; 440f4a2713aSLionel Sambuc 441f4a2713aSLionel Sambuc /// Create a stable reference to the top of the EH stack. The 442f4a2713aSLionel Sambuc /// returned reference is valid until that scope is popped off the 443f4a2713aSLionel Sambuc /// stack. 444f4a2713aSLionel Sambuc stable_iterator stable_begin() const { 445f4a2713aSLionel Sambuc return stable_iterator(EndOfBuffer - StartOfData); 446f4a2713aSLionel Sambuc } 447f4a2713aSLionel Sambuc 448f4a2713aSLionel Sambuc /// Create a stable reference to the bottom of the EH stack. 449f4a2713aSLionel Sambuc static stable_iterator stable_end() { 450f4a2713aSLionel Sambuc return stable_iterator(0); 451f4a2713aSLionel Sambuc } 452f4a2713aSLionel Sambuc 453f4a2713aSLionel Sambuc /// Translates an iterator into a stable_iterator. 454f4a2713aSLionel Sambuc stable_iterator stabilize(iterator it) const; 455f4a2713aSLionel Sambuc 456f4a2713aSLionel Sambuc /// Turn a stable reference to a scope depth into a unstable pointer 457f4a2713aSLionel Sambuc /// to the EH stack. 458f4a2713aSLionel Sambuc iterator find(stable_iterator save) const; 459f4a2713aSLionel Sambuc 460f4a2713aSLionel Sambuc /// Removes the cleanup pointed to by the given stable_iterator. 461f4a2713aSLionel Sambuc void removeCleanup(stable_iterator save); 462f4a2713aSLionel Sambuc 463f4a2713aSLionel Sambuc /// Add a branch fixup to the current cleanup scope. 464f4a2713aSLionel Sambuc BranchFixup &addBranchFixup() { 465f4a2713aSLionel Sambuc assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); 466f4a2713aSLionel Sambuc BranchFixups.push_back(BranchFixup()); 467f4a2713aSLionel Sambuc return BranchFixups.back(); 468f4a2713aSLionel Sambuc } 469f4a2713aSLionel Sambuc 470f4a2713aSLionel Sambuc unsigned getNumBranchFixups() const { return BranchFixups.size(); } 471f4a2713aSLionel Sambuc BranchFixup &getBranchFixup(unsigned I) { 472f4a2713aSLionel Sambuc assert(I < getNumBranchFixups()); 473f4a2713aSLionel Sambuc return BranchFixups[I]; 474f4a2713aSLionel Sambuc } 475f4a2713aSLionel Sambuc 476f4a2713aSLionel Sambuc /// Pops lazily-removed fixups from the end of the list. This 477f4a2713aSLionel Sambuc /// should only be called by procedures which have just popped a 478f4a2713aSLionel Sambuc /// cleanup or resolved one or more fixups. 479f4a2713aSLionel Sambuc void popNullFixups(); 480f4a2713aSLionel Sambuc 481f4a2713aSLionel Sambuc /// Clears the branch-fixups list. This should only be called by 482f4a2713aSLionel Sambuc /// ResolveAllBranchFixups. 483f4a2713aSLionel Sambuc void clearFixups() { BranchFixups.clear(); } 484f4a2713aSLionel Sambuc }; 485f4a2713aSLionel Sambuc 486f4a2713aSLionel Sambuc } // namespace CodeGen 487f4a2713aSLionel Sambuc } // namespace clang 488f4a2713aSLionel Sambuc 489f4a2713aSLionel Sambuc #endif 490