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 &&) {} 15106c3fb27SDimitry Andric 15206c3fb27SDimitry Andric // The copy and move assignment operator is defined as deleted pending 15306c3fb27SDimitry Andric // further motivation. 15406c3fb27SDimitry Andric Cleanup &operator=(const Cleanup &) = delete; 15506c3fb27SDimitry Andric Cleanup &operator=(Cleanup &&) = delete; 15606c3fb27SDimitry Andric 1570b57cec5SDimitry Andric Cleanup() = default; 1580b57cec5SDimitry Andric 159fe6060f1SDimitry Andric virtual bool isRedundantBeforeReturn() { return false; } 160fe6060f1SDimitry Andric 1610b57cec5SDimitry Andric /// Generation flags. 1620b57cec5SDimitry Andric class Flags { 1630b57cec5SDimitry Andric enum { 1640b57cec5SDimitry Andric F_IsForEH = 0x1, 1650b57cec5SDimitry Andric F_IsNormalCleanupKind = 0x2, 1665ffd83dbSDimitry Andric F_IsEHCleanupKind = 0x4, 1675ffd83dbSDimitry Andric F_HasExitSwitch = 0x8, 1680b57cec5SDimitry Andric }; 169*5f757f3fSDimitry Andric unsigned flags = 0; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric public: 172*5f757f3fSDimitry Andric Flags() = default; 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric /// isForEH - true if the current emission is for an EH cleanup. 1750b57cec5SDimitry Andric bool isForEHCleanup() const { return flags & F_IsForEH; } 1760b57cec5SDimitry Andric bool isForNormalCleanup() const { return !isForEHCleanup(); } 1770b57cec5SDimitry Andric void setIsForEHCleanup() { flags |= F_IsForEH; } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; } 1800b57cec5SDimitry Andric void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric /// isEHCleanupKind - true if the cleanup was pushed as an EH 1830b57cec5SDimitry Andric /// cleanup. 1840b57cec5SDimitry Andric bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } 1850b57cec5SDimitry Andric void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } 1860b57cec5SDimitry Andric 1875ffd83dbSDimitry Andric bool hasExitSwitch() const { return flags & F_HasExitSwitch; } 1885ffd83dbSDimitry Andric void setHasExitSwitch() { flags |= F_HasExitSwitch; } 1895ffd83dbSDimitry Andric }; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric /// Emit the cleanup. For normal cleanups, this is run in the 1920b57cec5SDimitry Andric /// same EH context as when the cleanup was pushed, i.e. the 1930b57cec5SDimitry Andric /// immediately-enclosing context of the cleanup scope. For 1940b57cec5SDimitry Andric /// EH cleanups, this is run in a terminate context. 1950b57cec5SDimitry Andric /// 1960b57cec5SDimitry Andric // \param flags cleanup kind. 1970b57cec5SDimitry Andric virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; 1980b57cec5SDimitry Andric }; 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric /// ConditionalCleanup stores the saved form of its parameters, 2010b57cec5SDimitry Andric /// then restores them and performs the cleanup. 2020b57cec5SDimitry Andric template <class T, class... As> 2030b57cec5SDimitry Andric class ConditionalCleanup final : public Cleanup { 2040b57cec5SDimitry Andric typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple; 2050b57cec5SDimitry Andric SavedTuple Saved; 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric template <std::size_t... Is> 208a7dea167SDimitry Andric T restore(CodeGenFunction &CGF, std::index_sequence<Is...>) { 2090b57cec5SDimitry Andric // It's important that the restores are emitted in order. The braced init 2100b57cec5SDimitry Andric // list guarantees that. 2110b57cec5SDimitry Andric return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...}; 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags flags) override { 215a7dea167SDimitry Andric restore(CGF, std::index_sequence_for<As...>()).Emit(CGF, flags); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric public: 2190b57cec5SDimitry Andric ConditionalCleanup(typename DominatingValue<As>::saved_type... A) 2200b57cec5SDimitry Andric : Saved(A...) {} 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {} 2230b57cec5SDimitry Andric }; 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric private: 2260b57cec5SDimitry Andric // The implementation for this class is in CGException.h and 2270b57cec5SDimitry Andric // CGException.cpp; the definition is here because it's used as a 2280b57cec5SDimitry Andric // member of CodeGenFunction. 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric /// The start of the scope-stack buffer, i.e. the allocated pointer 2310b57cec5SDimitry Andric /// for the buffer. All of these pointers are either simultaneously 2320b57cec5SDimitry Andric /// null or simultaneously valid. 2330b57cec5SDimitry Andric char *StartOfBuffer; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric /// The end of the buffer. 2360b57cec5SDimitry Andric char *EndOfBuffer; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric /// The first valid entry in the buffer. 2390b57cec5SDimitry Andric char *StartOfData; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric /// The innermost normal cleanup on the stack. 2420b57cec5SDimitry Andric stable_iterator InnermostNormalCleanup; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric /// The innermost EH scope on the stack. 2450b57cec5SDimitry Andric stable_iterator InnermostEHScope; 2460b57cec5SDimitry Andric 247fe6060f1SDimitry Andric /// The CGF this Stack belong to 248fe6060f1SDimitry Andric CodeGenFunction* CGF; 249fe6060f1SDimitry Andric 2500b57cec5SDimitry Andric /// The current set of branch fixups. A branch fixup is a jump to 2510b57cec5SDimitry Andric /// an as-yet unemitted label, i.e. a label for which we don't yet 2520b57cec5SDimitry Andric /// know the EH stack depth. Whenever we pop a cleanup, we have 2530b57cec5SDimitry Andric /// to thread all the current branch fixups through it. 2540b57cec5SDimitry Andric /// 2550b57cec5SDimitry Andric /// Fixups are recorded as the Use of the respective branch or 2560b57cec5SDimitry Andric /// switch statement. The use points to the final destination. 2570b57cec5SDimitry Andric /// When popping out of a cleanup, these uses are threaded through 2580b57cec5SDimitry Andric /// the cleanup and adjusted to point to the new cleanup. 2590b57cec5SDimitry Andric /// 2600b57cec5SDimitry Andric /// Note that branches are allowed to jump into protected scopes 2610b57cec5SDimitry Andric /// in certain situations; e.g. the following code is legal: 2620b57cec5SDimitry Andric /// struct A { ~A(); }; // trivial ctor, non-trivial dtor 2630b57cec5SDimitry Andric /// goto foo; 2640b57cec5SDimitry Andric /// A a; 2650b57cec5SDimitry Andric /// foo: 2660b57cec5SDimitry Andric /// bar(); 2670b57cec5SDimitry Andric SmallVector<BranchFixup, 8> BranchFixups; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric char *allocate(size_t Size); 2700b57cec5SDimitry Andric void deallocate(size_t Size); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric void *pushCleanup(CleanupKind K, size_t DataSize); 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric public: 275fe6060f1SDimitry Andric EHScopeStack() 276fe6060f1SDimitry Andric : StartOfBuffer(nullptr), EndOfBuffer(nullptr), StartOfData(nullptr), 277fe6060f1SDimitry Andric InnermostNormalCleanup(stable_end()), InnermostEHScope(stable_end()), 278fe6060f1SDimitry Andric CGF(nullptr) {} 2790b57cec5SDimitry Andric ~EHScopeStack() { delete[] StartOfBuffer; } 2800b57cec5SDimitry Andric 28106c3fb27SDimitry Andric EHScopeStack(const EHScopeStack &) = delete; 28206c3fb27SDimitry Andric EHScopeStack &operator=(const EHScopeStack &) = delete; 28306c3fb27SDimitry Andric 2840b57cec5SDimitry Andric /// Push a lazily-created cleanup on the stack. 2850b57cec5SDimitry Andric template <class T, class... As> void pushCleanup(CleanupKind Kind, As... A) { 2860b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 2870b57cec5SDimitry Andric "Cleanup's alignment is too large."); 2880b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T)); 2890b57cec5SDimitry Andric Cleanup *Obj = new (Buffer) T(A...); 2900b57cec5SDimitry Andric (void) Obj; 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric /// Push a lazily-created cleanup on the stack. Tuple version. 2940b57cec5SDimitry Andric template <class T, class... As> 2950b57cec5SDimitry Andric void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) { 2960b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 2970b57cec5SDimitry Andric "Cleanup's alignment is too large."); 2980b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T)); 2990b57cec5SDimitry Andric Cleanup *Obj = new (Buffer) T(std::move(A)); 3000b57cec5SDimitry Andric (void) Obj; 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric // Feel free to add more variants of the following: 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric /// Push a cleanup with non-constant storage requirements on the 3060b57cec5SDimitry Andric /// stack. The cleanup type must provide an additional static method: 3070b57cec5SDimitry Andric /// static size_t getExtraSize(size_t); 3080b57cec5SDimitry Andric /// The argument to this method will be the value N, which will also 3090b57cec5SDimitry Andric /// be passed as the first argument to the constructor. 3100b57cec5SDimitry Andric /// 3110b57cec5SDimitry Andric /// The data stored in the extra storage must obey the same 3120b57cec5SDimitry Andric /// restrictions as normal cleanup member data. 3130b57cec5SDimitry Andric /// 3140b57cec5SDimitry Andric /// The pointer returned from this method is valid until the cleanup 3150b57cec5SDimitry Andric /// stack is modified. 3160b57cec5SDimitry Andric template <class T, class... As> 3170b57cec5SDimitry Andric T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) { 3180b57cec5SDimitry Andric static_assert(alignof(T) <= ScopeStackAlignment, 3190b57cec5SDimitry Andric "Cleanup's alignment is too large."); 3200b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); 3210b57cec5SDimitry Andric return new (Buffer) T(N, A...); 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) { 3250b57cec5SDimitry Andric void *Buffer = pushCleanup(Kind, Size); 3260b57cec5SDimitry Andric std::memcpy(Buffer, Cleanup, Size); 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 329fe6060f1SDimitry Andric void setCGF(CodeGenFunction *inCGF) { CGF = inCGF; } 330fe6060f1SDimitry Andric 3310b57cec5SDimitry Andric /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. 3320b57cec5SDimitry Andric void popCleanup(); 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric /// Push a set of catch handlers on the stack. The catch is 3350b57cec5SDimitry Andric /// uninitialized and will need to have the given number of handlers 3360b57cec5SDimitry Andric /// set on it. 3370b57cec5SDimitry Andric class EHCatchScope *pushCatch(unsigned NumHandlers); 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric /// Pops a catch scope off the stack. This is private to CGException.cpp. 3400b57cec5SDimitry Andric void popCatch(); 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric /// Push an exceptions filter on the stack. 3430b57cec5SDimitry Andric class EHFilterScope *pushFilter(unsigned NumFilters); 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric /// Pops an exceptions filter off the stack. 3460b57cec5SDimitry Andric void popFilter(); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric /// Push a terminate handler on the stack. 3490b57cec5SDimitry Andric void pushTerminate(); 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric /// Pops a terminate handler off the stack. 3520b57cec5SDimitry Andric void popTerminate(); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric // Returns true iff the current scope is either empty or contains only 3550b57cec5SDimitry Andric // lifetime markers, i.e. no real cleanup code 3560b57cec5SDimitry Andric bool containsOnlyLifetimeMarkers(stable_iterator Old) const; 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric /// Determines whether the exception-scopes stack is empty. 3590b57cec5SDimitry Andric bool empty() const { return StartOfData == EndOfBuffer; } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric bool requiresLandingPad() const; 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric /// Determines whether there are any normal cleanups on the stack. 3640b57cec5SDimitry Andric bool hasNormalCleanups() const { 3650b57cec5SDimitry Andric return InnermostNormalCleanup != stable_end(); 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric /// Returns the innermost normal cleanup on the stack, or 3690b57cec5SDimitry Andric /// stable_end() if there are no normal cleanups. 3700b57cec5SDimitry Andric stable_iterator getInnermostNormalCleanup() const { 3710b57cec5SDimitry Andric return InnermostNormalCleanup; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric stable_iterator getInnermostActiveNormalCleanup() const; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric stable_iterator getInnermostEHScope() const { 3760b57cec5SDimitry Andric return InnermostEHScope; 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric /// An unstable reference to a scope-stack depth. Invalidated by 3810b57cec5SDimitry Andric /// pushes but not pops. 3820b57cec5SDimitry Andric class iterator; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric /// Returns an iterator pointing to the innermost EH scope. 3850b57cec5SDimitry Andric iterator begin() const; 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric /// Returns an iterator pointing to the outermost EH scope. 3880b57cec5SDimitry Andric iterator end() const; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric /// Create a stable reference to the top of the EH stack. The 3910b57cec5SDimitry Andric /// returned reference is valid until that scope is popped off the 3920b57cec5SDimitry Andric /// stack. 3930b57cec5SDimitry Andric stable_iterator stable_begin() const { 3940b57cec5SDimitry Andric return stable_iterator(EndOfBuffer - StartOfData); 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric /// Create a stable reference to the bottom of the EH stack. 3980b57cec5SDimitry Andric static stable_iterator stable_end() { 3990b57cec5SDimitry Andric return stable_iterator(0); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric /// Translates an iterator into a stable_iterator. 4030b57cec5SDimitry Andric stable_iterator stabilize(iterator it) const; 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric /// Turn a stable reference to a scope depth into a unstable pointer 4060b57cec5SDimitry Andric /// to the EH stack. 4070b57cec5SDimitry Andric iterator find(stable_iterator save) const; 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric /// Add a branch fixup to the current cleanup scope. 4100b57cec5SDimitry Andric BranchFixup &addBranchFixup() { 4110b57cec5SDimitry Andric assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); 4120b57cec5SDimitry Andric BranchFixups.push_back(BranchFixup()); 4130b57cec5SDimitry Andric return BranchFixups.back(); 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric unsigned getNumBranchFixups() const { return BranchFixups.size(); } 4170b57cec5SDimitry Andric BranchFixup &getBranchFixup(unsigned I) { 4180b57cec5SDimitry Andric assert(I < getNumBranchFixups()); 4190b57cec5SDimitry Andric return BranchFixups[I]; 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric /// Pops lazily-removed fixups from the end of the list. This 4230b57cec5SDimitry Andric /// should only be called by procedures which have just popped a 4240b57cec5SDimitry Andric /// cleanup or resolved one or more fixups. 4250b57cec5SDimitry Andric void popNullFixups(); 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric /// Clears the branch-fixups list. This should only be called by 4280b57cec5SDimitry Andric /// ResolveAllBranchFixups. 4290b57cec5SDimitry Andric void clearFixups() { BranchFixups.clear(); } 4300b57cec5SDimitry Andric }; 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric } // namespace CodeGen 4330b57cec5SDimitry Andric } // namespace clang 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric #endif 436