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