10b57cec5SDimitry Andric //===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // These classes should be the minimum interface required for other parts of 100b57cec5SDimitry Andric // CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other 110b57cec5SDimitry Andric // implemenentation details that are not widely needed are in CGCleanup.h. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H 160b57cec5SDimitry Andric #define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 210b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 220b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 230b57cec5SDimitry Andric #include "llvm/IR/Value.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace clang { 260b57cec5SDimitry Andric namespace CodeGen { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric class CodeGenFunction; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric /// A branch fixup. These are required when emitting a goto to a 310b57cec5SDimitry Andric /// label which hasn't been emitted yet. The goto is optimistically 320b57cec5SDimitry Andric /// emitted as a branch to the basic block for the label, and (if it 330b57cec5SDimitry Andric /// occurs in a scope with non-trivial cleanups) a fixup is added to 340b57cec5SDimitry Andric /// the innermost cleanup. When a (normal) cleanup is popped, any 350b57cec5SDimitry Andric /// unresolved fixups in that scope are threaded through the cleanup. 360b57cec5SDimitry Andric struct BranchFixup { 370b57cec5SDimitry Andric /// The block containing the terminator which needs to be modified 380b57cec5SDimitry Andric /// into a switch if this fixup is resolved into the current scope. 390b57cec5SDimitry Andric /// If null, LatestBranch points directly to the destination. 400b57cec5SDimitry Andric llvm::BasicBlock *OptimisticBranchBlock; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// The ultimate destination of the branch. 430b57cec5SDimitry Andric /// 440b57cec5SDimitry Andric /// This can be set to null to indicate that this fixup was 450b57cec5SDimitry Andric /// successfully resolved. 460b57cec5SDimitry Andric llvm::BasicBlock *Destination; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric /// The destination index value. 490b57cec5SDimitry Andric unsigned DestinationIndex; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric /// The initial branch of the fixup. 520b57cec5SDimitry Andric llvm::BranchInst *InitialBranch; 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric template <class T> struct InvariantValue { 560b57cec5SDimitry Andric typedef T type; 570b57cec5SDimitry Andric typedef T saved_type; 580b57cec5SDimitry Andric static bool needsSaving(type value) { return false; } 590b57cec5SDimitry Andric static saved_type save(CodeGenFunction &CGF, type value) { return value; } 600b57cec5SDimitry Andric static type restore(CodeGenFunction &CGF, saved_type value) { return value; } 610b57cec5SDimitry Andric }; 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric /// A metaprogramming class for ensuring that a value will dominate an 640b57cec5SDimitry Andric /// arbitrary position in a function. 650b57cec5SDimitry Andric template <class T> struct DominatingValue : InvariantValue<T> {}; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric template <class T, bool mightBeInstruction = 680b57cec5SDimitry Andric std::is_base_of<llvm::Value, T>::value && 690b57cec5SDimitry Andric !std::is_base_of<llvm::Constant, T>::value && 700b57cec5SDimitry Andric !std::is_base_of<llvm::BasicBlock, T>::value> 710b57cec5SDimitry Andric struct DominatingPointer; 720b57cec5SDimitry Andric template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {}; 730b57cec5SDimitry Andric // template <class T> struct DominatingPointer<T,true> at end of file 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric template <class T> struct DominatingValue<T*> : DominatingPointer<T> {}; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric enum CleanupKind : unsigned { 780b57cec5SDimitry Andric /// Denotes a cleanup that should run when a scope is exited using exceptional 790b57cec5SDimitry Andric /// control flow (a throw statement leading to stack unwinding, ). 800b57cec5SDimitry Andric EHCleanup = 0x1, 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// Denotes a cleanup that should run when a scope is exited using normal 830b57cec5SDimitry Andric /// control flow (falling off the end of the scope, return, goto, ...). 840b57cec5SDimitry Andric NormalCleanup = 0x2, 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric NormalAndEHCleanup = EHCleanup | NormalCleanup, 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric LifetimeMarker = 0x8, 890b57cec5SDimitry Andric NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup, 900b57cec5SDimitry Andric }; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric /// A stack of scopes which respond to exceptions, including cleanups 930b57cec5SDimitry Andric /// and catch blocks. 940b57cec5SDimitry Andric class EHScopeStack { 950b57cec5SDimitry Andric public: 960b57cec5SDimitry Andric /* Should switch to alignof(uint64_t) instead of 8, when EHCleanupScope can */ 970b57cec5SDimitry Andric enum { ScopeStackAlignment = 8 }; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric /// A saved depth on the scope stack. This is necessary because 1000b57cec5SDimitry Andric /// pushing scopes onto the stack invalidates iterators. 1010b57cec5SDimitry Andric class stable_iterator { 1020b57cec5SDimitry Andric friend class EHScopeStack; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric /// Offset from StartOfData to EndOfBuffer. 1050b57cec5SDimitry Andric ptrdiff_t Size; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric stable_iterator(ptrdiff_t Size) : Size(Size) {} 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric public: 1100b57cec5SDimitry Andric static stable_iterator invalid() { return stable_iterator(-1); } 1110b57cec5SDimitry Andric stable_iterator() : Size(-1) {} 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric bool isValid() const { return Size >= 0; } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric /// Returns true if this scope encloses I. 1160b57cec5SDimitry Andric /// Returns false if I is invalid. 1170b57cec5SDimitry Andric /// This scope must be valid. 1180b57cec5SDimitry Andric bool encloses(stable_iterator I) const { return Size <= I.Size; } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Returns true if this scope strictly encloses I: that is, 1210b57cec5SDimitry Andric /// if it encloses I and is not I. 1220b57cec5SDimitry Andric /// Returns false is I is invalid. 1230b57cec5SDimitry Andric /// This scope must be valid. 1240b57cec5SDimitry Andric bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric friend bool operator==(stable_iterator A, stable_iterator B) { 1270b57cec5SDimitry Andric return A.Size == B.Size; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric friend bool operator!=(stable_iterator A, stable_iterator B) { 1300b57cec5SDimitry Andric return A.Size != B.Size; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric }; 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric /// Information for lazily generating a cleanup. Subclasses must be 1350b57cec5SDimitry Andric /// POD-like: cleanups will not be destructed, and they will be 1360b57cec5SDimitry Andric /// allocated on the cleanup stack and freely copied and moved 1370b57cec5SDimitry Andric /// around. 1380b57cec5SDimitry Andric /// 1390b57cec5SDimitry Andric /// Cleanup implementations should generally be declared in an 1400b57cec5SDimitry Andric /// anonymous namespace. 1410b57cec5SDimitry Andric class Cleanup { 1420b57cec5SDimitry Andric // Anchor the construction vtable. 1430b57cec5SDimitry Andric virtual void anchor(); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric protected: 1460b57cec5SDimitry Andric ~Cleanup() = default; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric public: 1490b57cec5SDimitry Andric Cleanup(const Cleanup &) = default; 1500b57cec5SDimitry Andric Cleanup(Cleanup &&) {} 1510b57cec5SDimitry Andric Cleanup() = default; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric /// Generation flags. 1540b57cec5SDimitry Andric class Flags { 1550b57cec5SDimitry Andric enum { 1560b57cec5SDimitry Andric F_IsForEH = 0x1, 1570b57cec5SDimitry Andric F_IsNormalCleanupKind = 0x2, 158*5ffd83dbSDimitry Andric F_IsEHCleanupKind = 0x4, 159*5ffd83dbSDimitry Andric F_HasExitSwitch = 0x8, 1600b57cec5SDimitry Andric }; 1610b57cec5SDimitry Andric unsigned flags; 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric public: 1640b57cec5SDimitry Andric Flags() : flags(0) {} 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric /// isForEH - true if the current emission is for an EH cleanup. 1670b57cec5SDimitry Andric bool isForEHCleanup() const { return flags & F_IsForEH; } 1680b57cec5SDimitry Andric bool isForNormalCleanup() const { return !isForEHCleanup(); } 1690b57cec5SDimitry Andric void setIsForEHCleanup() { flags |= F_IsForEH; } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; } 1720b57cec5SDimitry Andric void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric /// isEHCleanupKind - true if the cleanup was pushed as an EH 1750b57cec5SDimitry Andric /// cleanup. 1760b57cec5SDimitry Andric bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } 1770b57cec5SDimitry Andric void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } 1780b57cec5SDimitry Andric 179*5ffd83dbSDimitry Andric bool hasExitSwitch() const { return flags & F_HasExitSwitch; } 180*5ffd83dbSDimitry Andric void setHasExitSwitch() { flags |= F_HasExitSwitch; } 181*5ffd83dbSDimitry Andric }; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /// Emit the cleanup. For normal cleanups, this is run in the 1840b57cec5SDimitry Andric /// same EH context as when the cleanup was pushed, i.e. the 1850b57cec5SDimitry Andric /// immediately-enclosing context of the cleanup scope. For 1860b57cec5SDimitry Andric /// EH cleanups, this is run in a terminate context. 1870b57cec5SDimitry Andric /// 1880b57cec5SDimitry Andric // \param flags cleanup kind. 1890b57cec5SDimitry Andric virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; 1900b57cec5SDimitry Andric }; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric /// ConditionalCleanup stores the saved form of its parameters, 1930b57cec5SDimitry Andric /// then restores them and performs the cleanup. 1940b57cec5SDimitry Andric template <class T, class... As> 1950b57cec5SDimitry Andric class ConditionalCleanup final : public Cleanup { 1960b57cec5SDimitry Andric typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple; 1970b57cec5SDimitry Andric SavedTuple Saved; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric template <std::size_t... Is> 200a7dea167SDimitry Andric T restore(CodeGenFunction &CGF, std::index_sequence<Is...>) { 2010b57cec5SDimitry Andric // It's important that the restores are emitted in order. The braced init 2020b57cec5SDimitry Andric // list guarantees that. 2030b57cec5SDimitry Andric return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...}; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags flags) override { 207a7dea167SDimitry Andric restore(CGF, std::index_sequence_for<As...>()).Emit(CGF, flags); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric public: 2110b57cec5SDimitry Andric ConditionalCleanup(typename DominatingValue<As>::saved_type... A) 2120b57cec5SDimitry Andric : Saved(A...) {} 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {} 2150b57cec5SDimitry Andric }; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric private: 2180b57cec5SDimitry Andric // The implementation for this class is in CGException.h and 2190b57cec5SDimitry Andric // CGException.cpp; the definition is here because it's used as a 2200b57cec5SDimitry Andric // member of CodeGenFunction. 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric /// The start of the scope-stack buffer, i.e. the allocated pointer 2230b57cec5SDimitry Andric /// for the buffer. All of these pointers are either simultaneously 2240b57cec5SDimitry Andric /// null or simultaneously valid. 2250b57cec5SDimitry Andric char *StartOfBuffer; 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric /// The end of the buffer. 2280b57cec5SDimitry Andric char *EndOfBuffer; 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric /// The first valid entry in the buffer. 2310b57cec5SDimitry Andric char *StartOfData; 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric /// The innermost normal cleanup on the stack. 2340b57cec5SDimitry Andric stable_iterator InnermostNormalCleanup; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric /// The innermost EH scope on the stack. 2370b57cec5SDimitry Andric stable_iterator InnermostEHScope; 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric /// The current set of branch fixups. A branch fixup is a jump to 2400b57cec5SDimitry Andric /// an as-yet unemitted label, i.e. a label for which we don't yet 2410b57cec5SDimitry Andric /// know the EH stack depth. Whenever we pop a cleanup, we have 2420b57cec5SDimitry Andric /// to thread all the current branch fixups through it. 2430b57cec5SDimitry Andric /// 2440b57cec5SDimitry Andric /// Fixups are recorded as the Use of the respective branch or 2450b57cec5SDimitry Andric /// switch statement. The use points to the final destination. 2460b57cec5SDimitry Andric /// When popping out of a cleanup, these uses are threaded through 2470b57cec5SDimitry Andric /// the cleanup and adjusted to point to the new cleanup. 2480b57cec5SDimitry Andric /// 2490b57cec5SDimitry Andric /// Note that branches are allowed to jump into protected scopes 2500b57cec5SDimitry Andric /// in certain situations; e.g. the following code is legal: 2510b57cec5SDimitry Andric /// struct A { ~A(); }; // trivial ctor, non-trivial dtor 2520b57cec5SDimitry Andric /// goto foo; 2530b57cec5SDimitry Andric /// A a; 2540b57cec5SDimitry Andric /// foo: 2550b57cec5SDimitry Andric /// bar(); 2560b57cec5SDimitry Andric SmallVector<BranchFixup, 8> BranchFixups; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric char *allocate(size_t Size); 2590b57cec5SDimitry Andric void deallocate(size_t Size); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric void *pushCleanup(CleanupKind K, size_t DataSize); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric public: 2640b57cec5SDimitry Andric EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr), 2650b57cec5SDimitry Andric StartOfData(nullptr), InnermostNormalCleanup(stable_end()), 2660b57cec5SDimitry Andric InnermostEHScope(stable_end()) {} 2670b57cec5SDimitry Andric ~EHScopeStack() { delete[] StartOfBuffer; } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric /// Push a lazily-created cleanup on the stack. 2700b57cec5SDimitry Andric template <class T, class... As> void pushCleanup(CleanupKind Kind, As... A) { 2710b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 2720b57cec5SDimitry Andric "Cleanup's alignment is too large."); 2730b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T)); 2740b57cec5SDimitry Andric Cleanup *Obj = new (Buffer) T(A...); 2750b57cec5SDimitry Andric (void) Obj; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric /// Push a lazily-created cleanup on the stack. Tuple version. 2790b57cec5SDimitry Andric template <class T, class... As> 2800b57cec5SDimitry Andric void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) { 2810b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 2820b57cec5SDimitry Andric "Cleanup's alignment is too large."); 2830b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T)); 2840b57cec5SDimitry Andric Cleanup *Obj = new (Buffer) T(std::move(A)); 2850b57cec5SDimitry Andric (void) Obj; 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // Feel free to add more variants of the following: 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric /// Push a cleanup with non-constant storage requirements on the 2910b57cec5SDimitry Andric /// stack. The cleanup type must provide an additional static method: 2920b57cec5SDimitry Andric /// static size_t getExtraSize(size_t); 2930b57cec5SDimitry Andric /// The argument to this method will be the value N, which will also 2940b57cec5SDimitry Andric /// be passed as the first argument to the constructor. 2950b57cec5SDimitry Andric /// 2960b57cec5SDimitry Andric /// The data stored in the extra storage must obey the same 2970b57cec5SDimitry Andric /// restrictions as normal cleanup member data. 2980b57cec5SDimitry Andric /// 2990b57cec5SDimitry Andric /// The pointer returned from this method is valid until the cleanup 3000b57cec5SDimitry Andric /// stack is modified. 3010b57cec5SDimitry Andric template <class T, class... As> 3020b57cec5SDimitry Andric T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) { 3030b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 3040b57cec5SDimitry Andric "Cleanup's alignment is too large."); 3050b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); 3060b57cec5SDimitry Andric return new (Buffer) T(N, A...); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) { 3100b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, Size); 3110b57cec5SDimitry Andric std::memcpy(Buffer, Cleanup, Size); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. 3150b57cec5SDimitry Andric void popCleanup(); 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric /// Push a set of catch handlers on the stack. The catch is 3180b57cec5SDimitry Andric /// uninitialized and will need to have the given number of handlers 3190b57cec5SDimitry Andric /// set on it. 3200b57cec5SDimitry Andric class EHCatchScope *pushCatch(unsigned NumHandlers); 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric /// Pops a catch scope off the stack. This is private to CGException.cpp. 3230b57cec5SDimitry Andric void popCatch(); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric /// Push an exceptions filter on the stack. 3260b57cec5SDimitry Andric class EHFilterScope *pushFilter(unsigned NumFilters); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric /// Pops an exceptions filter off the stack. 3290b57cec5SDimitry Andric void popFilter(); 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric /// Push a terminate handler on the stack. 3320b57cec5SDimitry Andric void pushTerminate(); 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric /// Pops a terminate handler off the stack. 3350b57cec5SDimitry Andric void popTerminate(); 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // Returns true iff the current scope is either empty or contains only 3380b57cec5SDimitry Andric // lifetime markers, i.e. no real cleanup code 3390b57cec5SDimitry Andric bool containsOnlyLifetimeMarkers(stable_iterator Old) const; 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric /// Determines whether the exception-scopes stack is empty. 3420b57cec5SDimitry Andric bool empty() const { return StartOfData == EndOfBuffer; } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric bool requiresLandingPad() const; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric /// Determines whether there are any normal cleanups on the stack. 3470b57cec5SDimitry Andric bool hasNormalCleanups() const { 3480b57cec5SDimitry Andric return InnermostNormalCleanup != stable_end(); 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric /// Returns the innermost normal cleanup on the stack, or 3520b57cec5SDimitry Andric /// stable_end() if there are no normal cleanups. 3530b57cec5SDimitry Andric stable_iterator getInnermostNormalCleanup() const { 3540b57cec5SDimitry Andric return InnermostNormalCleanup; 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric stable_iterator getInnermostActiveNormalCleanup() const; 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric stable_iterator getInnermostEHScope() const { 3590b57cec5SDimitry Andric return InnermostEHScope; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric /// An unstable reference to a scope-stack depth. Invalidated by 3640b57cec5SDimitry Andric /// pushes but not pops. 3650b57cec5SDimitry Andric class iterator; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric /// Returns an iterator pointing to the innermost EH scope. 3680b57cec5SDimitry Andric iterator begin() const; 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric /// Returns an iterator pointing to the outermost EH scope. 3710b57cec5SDimitry Andric iterator end() const; 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric /// Create a stable reference to the top of the EH stack. The 3740b57cec5SDimitry Andric /// returned reference is valid until that scope is popped off the 3750b57cec5SDimitry Andric /// stack. 3760b57cec5SDimitry Andric stable_iterator stable_begin() const { 3770b57cec5SDimitry Andric return stable_iterator(EndOfBuffer - StartOfData); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric /// Create a stable reference to the bottom of the EH stack. 3810b57cec5SDimitry Andric static stable_iterator stable_end() { 3820b57cec5SDimitry Andric return stable_iterator(0); 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric /// Translates an iterator into a stable_iterator. 3860b57cec5SDimitry Andric stable_iterator stabilize(iterator it) const; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric /// Turn a stable reference to a scope depth into a unstable pointer 3890b57cec5SDimitry Andric /// to the EH stack. 3900b57cec5SDimitry Andric iterator find(stable_iterator save) const; 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric /// Add a branch fixup to the current cleanup scope. 3930b57cec5SDimitry Andric BranchFixup &addBranchFixup() { 3940b57cec5SDimitry Andric assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); 3950b57cec5SDimitry Andric BranchFixups.push_back(BranchFixup()); 3960b57cec5SDimitry Andric return BranchFixups.back(); 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric unsigned getNumBranchFixups() const { return BranchFixups.size(); } 4000b57cec5SDimitry Andric BranchFixup &getBranchFixup(unsigned I) { 4010b57cec5SDimitry Andric assert(I < getNumBranchFixups()); 4020b57cec5SDimitry Andric return BranchFixups[I]; 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric /// Pops lazily-removed fixups from the end of the list. This 4060b57cec5SDimitry Andric /// should only be called by procedures which have just popped a 4070b57cec5SDimitry Andric /// cleanup or resolved one or more fixups. 4080b57cec5SDimitry Andric void popNullFixups(); 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric /// Clears the branch-fixups list. This should only be called by 4110b57cec5SDimitry Andric /// ResolveAllBranchFixups. 4120b57cec5SDimitry Andric void clearFixups() { BranchFixups.clear(); } 4130b57cec5SDimitry Andric }; 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric } // namespace CodeGen 4160b57cec5SDimitry Andric } // namespace clang 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric #endif 419