1218887Sdim//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// These classes support the generation of LLVM IR for cleanups. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14218887Sdim#ifndef CLANG_CODEGEN_CGCLEANUP_H 15218887Sdim#define CLANG_CODEGEN_CGCLEANUP_H 16218887Sdim 17263509Sdim#include "EHScopeStack.h" 18263509Sdim#include "llvm/ADT/SmallPtrSet.h" 19263509Sdim#include "llvm/ADT/SmallVector.h" 20218887Sdim 21218887Sdimnamespace llvm { 22263509Sdimclass BasicBlock; 23263509Sdimclass Value; 24263509Sdimclass ConstantInt; 25263509Sdimclass AllocaInst; 26218887Sdim} 27218887Sdim 28218887Sdimnamespace clang { 29218887Sdimnamespace CodeGen { 30218887Sdim 31218887Sdim/// A protected scope for zero-cost EH handling. 32218887Sdimclass EHScope { 33218887Sdim llvm::BasicBlock *CachedLandingPad; 34226890Sdim llvm::BasicBlock *CachedEHDispatchBlock; 35218887Sdim 36226890Sdim EHScopeStack::stable_iterator EnclosingEHScope; 37218887Sdim 38226890Sdim class CommonBitFields { 39226890Sdim friend class EHScope; 40226890Sdim unsigned Kind : 2; 41226890Sdim }; 42226890Sdim enum { NumCommonBits = 2 }; 43226890Sdim 44218887Sdimprotected: 45226890Sdim class CatchBitFields { 46226890Sdim friend class EHCatchScope; 47226890Sdim unsigned : NumCommonBits; 48218887Sdim 49226890Sdim unsigned NumHandlers : 32 - NumCommonBits; 50226890Sdim }; 51226890Sdim 52226890Sdim class CleanupBitFields { 53226890Sdim friend class EHCleanupScope; 54226890Sdim unsigned : NumCommonBits; 55226890Sdim 56226890Sdim /// Whether this cleanup needs to be run along normal edges. 57226890Sdim unsigned IsNormalCleanup : 1; 58226890Sdim 59226890Sdim /// Whether this cleanup needs to be run along exception edges. 60226890Sdim unsigned IsEHCleanup : 1; 61226890Sdim 62226890Sdim /// Whether this cleanup is currently active. 63226890Sdim unsigned IsActive : 1; 64226890Sdim 65226890Sdim /// Whether the normal cleanup should test the activation flag. 66226890Sdim unsigned TestFlagInNormalCleanup : 1; 67226890Sdim 68226890Sdim /// Whether the EH cleanup should test the activation flag. 69226890Sdim unsigned TestFlagInEHCleanup : 1; 70226890Sdim 71226890Sdim /// The amount of extra storage needed by the Cleanup. 72226890Sdim /// Always a multiple of the scope-stack alignment. 73226890Sdim unsigned CleanupSize : 12; 74226890Sdim 75226890Sdim /// The number of fixups required by enclosing scopes (not including 76226890Sdim /// this one). If this is the top cleanup scope, all the fixups 77226890Sdim /// from this index onwards belong to this scope. 78226890Sdim unsigned FixupDepth : 32 - 17 - NumCommonBits; // currently 13 79226890Sdim }; 80226890Sdim 81226890Sdim class FilterBitFields { 82226890Sdim friend class EHFilterScope; 83226890Sdim unsigned : NumCommonBits; 84226890Sdim 85226890Sdim unsigned NumFilters : 32 - NumCommonBits; 86226890Sdim }; 87226890Sdim 88226890Sdim union { 89226890Sdim CommonBitFields CommonBits; 90226890Sdim CatchBitFields CatchBits; 91226890Sdim CleanupBitFields CleanupBits; 92226890Sdim FilterBitFields FilterBits; 93226890Sdim }; 94226890Sdim 95218887Sdimpublic: 96218887Sdim enum Kind { Cleanup, Catch, Terminate, Filter }; 97218887Sdim 98226890Sdim EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) 99226890Sdim : CachedLandingPad(0), CachedEHDispatchBlock(0), 100226890Sdim EnclosingEHScope(enclosingEHScope) { 101226890Sdim CommonBits.Kind = kind; 102226890Sdim } 103218887Sdim 104226890Sdim Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); } 105218887Sdim 106218887Sdim llvm::BasicBlock *getCachedLandingPad() const { 107218887Sdim return CachedLandingPad; 108218887Sdim } 109218887Sdim 110226890Sdim void setCachedLandingPad(llvm::BasicBlock *block) { 111226890Sdim CachedLandingPad = block; 112218887Sdim } 113226890Sdim 114226890Sdim llvm::BasicBlock *getCachedEHDispatchBlock() const { 115226890Sdim return CachedEHDispatchBlock; 116226890Sdim } 117226890Sdim 118226890Sdim void setCachedEHDispatchBlock(llvm::BasicBlock *block) { 119226890Sdim CachedEHDispatchBlock = block; 120226890Sdim } 121226890Sdim 122226890Sdim bool hasEHBranches() const { 123226890Sdim if (llvm::BasicBlock *block = getCachedEHDispatchBlock()) 124226890Sdim return !block->use_empty(); 125226890Sdim return false; 126226890Sdim } 127226890Sdim 128226890Sdim EHScopeStack::stable_iterator getEnclosingEHScope() const { 129226890Sdim return EnclosingEHScope; 130226890Sdim } 131218887Sdim}; 132218887Sdim 133218887Sdim/// A scope which attempts to handle some, possibly all, types of 134218887Sdim/// exceptions. 135218887Sdim/// 136245431Sdim/// Objective C \@finally blocks are represented using a cleanup scope 137218887Sdim/// after the catch scope. 138218887Sdimclass EHCatchScope : public EHScope { 139218887Sdim // In effect, we have a flexible array member 140218887Sdim // Handler Handlers[0]; 141218887Sdim // But that's only standard in C99, not C++, so we have to do 142218887Sdim // annoying pointer arithmetic instead. 143218887Sdim 144218887Sdimpublic: 145218887Sdim struct Handler { 146218887Sdim /// A type info value, or null (C++ null, not an LLVM null pointer) 147218887Sdim /// for a catch-all. 148218887Sdim llvm::Value *Type; 149218887Sdim 150218887Sdim /// The catch handler for this type. 151218887Sdim llvm::BasicBlock *Block; 152218887Sdim 153226890Sdim bool isCatchAll() const { return Type == 0; } 154218887Sdim }; 155218887Sdim 156218887Sdimprivate: 157218887Sdim friend class EHScopeStack; 158218887Sdim 159218887Sdim Handler *getHandlers() { 160218887Sdim return reinterpret_cast<Handler*>(this+1); 161218887Sdim } 162218887Sdim 163218887Sdim const Handler *getHandlers() const { 164218887Sdim return reinterpret_cast<const Handler*>(this+1); 165218887Sdim } 166218887Sdim 167218887Sdimpublic: 168218887Sdim static size_t getSizeForNumHandlers(unsigned N) { 169218887Sdim return sizeof(EHCatchScope) + N * sizeof(Handler); 170218887Sdim } 171218887Sdim 172226890Sdim EHCatchScope(unsigned numHandlers, 173226890Sdim EHScopeStack::stable_iterator enclosingEHScope) 174226890Sdim : EHScope(Catch, enclosingEHScope) { 175226890Sdim CatchBits.NumHandlers = numHandlers; 176218887Sdim } 177218887Sdim 178218887Sdim unsigned getNumHandlers() const { 179226890Sdim return CatchBits.NumHandlers; 180218887Sdim } 181218887Sdim 182218887Sdim void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) { 183218887Sdim setHandler(I, /*catchall*/ 0, Block); 184218887Sdim } 185218887Sdim 186218887Sdim void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) { 187218887Sdim assert(I < getNumHandlers()); 188218887Sdim getHandlers()[I].Type = Type; 189218887Sdim getHandlers()[I].Block = Block; 190218887Sdim } 191218887Sdim 192218887Sdim const Handler &getHandler(unsigned I) const { 193218887Sdim assert(I < getNumHandlers()); 194218887Sdim return getHandlers()[I]; 195218887Sdim } 196218887Sdim 197218887Sdim typedef const Handler *iterator; 198218887Sdim iterator begin() const { return getHandlers(); } 199218887Sdim iterator end() const { return getHandlers() + getNumHandlers(); } 200218887Sdim 201218887Sdim static bool classof(const EHScope *Scope) { 202218887Sdim return Scope->getKind() == Catch; 203218887Sdim } 204218887Sdim}; 205218887Sdim 206218887Sdim/// A cleanup scope which generates the cleanup blocks lazily. 207218887Sdimclass EHCleanupScope : public EHScope { 208218887Sdim /// The nearest normal cleanup scope enclosing this one. 209218887Sdim EHScopeStack::stable_iterator EnclosingNormal; 210218887Sdim 211226890Sdim /// The nearest EH scope enclosing this one. 212218887Sdim EHScopeStack::stable_iterator EnclosingEH; 213218887Sdim 214218887Sdim /// The dual entry/exit block along the normal edge. This is lazily 215218887Sdim /// created if needed before the cleanup is popped. 216218887Sdim llvm::BasicBlock *NormalBlock; 217218887Sdim 218218887Sdim /// An optional i1 variable indicating whether this cleanup has been 219218887Sdim /// activated yet. 220218887Sdim llvm::AllocaInst *ActiveFlag; 221218887Sdim 222218887Sdim /// Extra information required for cleanups that have resolved 223218887Sdim /// branches through them. This has to be allocated on the side 224218887Sdim /// because everything on the cleanup stack has be trivially 225218887Sdim /// movable. 226218887Sdim struct ExtInfo { 227218887Sdim /// The destinations of normal branch-afters and branch-throughs. 228218887Sdim llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches; 229218887Sdim 230218887Sdim /// Normal branch-afters. 231226890Sdim SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4> 232218887Sdim BranchAfters; 233218887Sdim }; 234218887Sdim mutable struct ExtInfo *ExtInfo; 235218887Sdim 236218887Sdim struct ExtInfo &getExtInfo() { 237218887Sdim if (!ExtInfo) ExtInfo = new struct ExtInfo(); 238218887Sdim return *ExtInfo; 239218887Sdim } 240218887Sdim 241218887Sdim const struct ExtInfo &getExtInfo() const { 242218887Sdim if (!ExtInfo) ExtInfo = new struct ExtInfo(); 243218887Sdim return *ExtInfo; 244218887Sdim } 245218887Sdim 246218887Sdimpublic: 247218887Sdim /// Gets the size required for a lazy cleanup scope with the given 248218887Sdim /// cleanup-data requirements. 249218887Sdim static size_t getSizeForCleanupSize(size_t Size) { 250218887Sdim return sizeof(EHCleanupScope) + Size; 251218887Sdim } 252218887Sdim 253218887Sdim size_t getAllocatedSize() const { 254226890Sdim return sizeof(EHCleanupScope) + CleanupBits.CleanupSize; 255218887Sdim } 256218887Sdim 257226890Sdim EHCleanupScope(bool isNormal, bool isEH, bool isActive, 258226890Sdim unsigned cleanupSize, unsigned fixupDepth, 259226890Sdim EHScopeStack::stable_iterator enclosingNormal, 260226890Sdim EHScopeStack::stable_iterator enclosingEH) 261226890Sdim : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal), 262226890Sdim NormalBlock(0), ActiveFlag(0), ExtInfo(0) { 263226890Sdim CleanupBits.IsNormalCleanup = isNormal; 264226890Sdim CleanupBits.IsEHCleanup = isEH; 265226890Sdim CleanupBits.IsActive = isActive; 266226890Sdim CleanupBits.TestFlagInNormalCleanup = false; 267226890Sdim CleanupBits.TestFlagInEHCleanup = false; 268226890Sdim CleanupBits.CleanupSize = cleanupSize; 269226890Sdim CleanupBits.FixupDepth = fixupDepth; 270226890Sdim 271226890Sdim assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow"); 272218887Sdim } 273218887Sdim 274218887Sdim ~EHCleanupScope() { 275218887Sdim delete ExtInfo; 276218887Sdim } 277218887Sdim 278226890Sdim bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; } 279218887Sdim llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } 280218887Sdim void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; } 281218887Sdim 282226890Sdim bool isEHCleanup() const { return CleanupBits.IsEHCleanup; } 283226890Sdim llvm::BasicBlock *getEHBlock() const { return getCachedEHDispatchBlock(); } 284226890Sdim void setEHBlock(llvm::BasicBlock *BB) { setCachedEHDispatchBlock(BB); } 285218887Sdim 286226890Sdim bool isActive() const { return CleanupBits.IsActive; } 287226890Sdim void setActive(bool A) { CleanupBits.IsActive = A; } 288218887Sdim 289218887Sdim llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; } 290218887Sdim void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; } 291218887Sdim 292226890Sdim void setTestFlagInNormalCleanup() { 293226890Sdim CleanupBits.TestFlagInNormalCleanup = true; 294226890Sdim } 295226890Sdim bool shouldTestFlagInNormalCleanup() const { 296226890Sdim return CleanupBits.TestFlagInNormalCleanup; 297226890Sdim } 298218887Sdim 299226890Sdim void setTestFlagInEHCleanup() { 300226890Sdim CleanupBits.TestFlagInEHCleanup = true; 301226890Sdim } 302226890Sdim bool shouldTestFlagInEHCleanup() const { 303226890Sdim return CleanupBits.TestFlagInEHCleanup; 304226890Sdim } 305218887Sdim 306226890Sdim unsigned getFixupDepth() const { return CleanupBits.FixupDepth; } 307218887Sdim EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { 308218887Sdim return EnclosingNormal; 309218887Sdim } 310218887Sdim 311226890Sdim size_t getCleanupSize() const { return CleanupBits.CleanupSize; } 312218887Sdim void *getCleanupBuffer() { return this + 1; } 313218887Sdim 314218887Sdim EHScopeStack::Cleanup *getCleanup() { 315218887Sdim return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer()); 316218887Sdim } 317218887Sdim 318218887Sdim /// True if this cleanup scope has any branch-afters or branch-throughs. 319218887Sdim bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); } 320218887Sdim 321218887Sdim /// Add a branch-after to this cleanup scope. A branch-after is a 322218887Sdim /// branch from a point protected by this (normal) cleanup to a 323218887Sdim /// point in the normal cleanup scope immediately containing it. 324218887Sdim /// For example, 325218887Sdim /// for (;;) { A a; break; } 326218887Sdim /// contains a branch-after. 327218887Sdim /// 328218887Sdim /// Branch-afters each have their own destination out of the 329218887Sdim /// cleanup, guaranteed distinct from anything else threaded through 330218887Sdim /// it. Therefore branch-afters usually force a switch after the 331218887Sdim /// cleanup. 332218887Sdim void addBranchAfter(llvm::ConstantInt *Index, 333218887Sdim llvm::BasicBlock *Block) { 334218887Sdim struct ExtInfo &ExtInfo = getExtInfo(); 335218887Sdim if (ExtInfo.Branches.insert(Block)) 336218887Sdim ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index)); 337218887Sdim } 338218887Sdim 339218887Sdim /// Return the number of unique branch-afters on this scope. 340218887Sdim unsigned getNumBranchAfters() const { 341218887Sdim return ExtInfo ? ExtInfo->BranchAfters.size() : 0; 342218887Sdim } 343218887Sdim 344218887Sdim llvm::BasicBlock *getBranchAfterBlock(unsigned I) const { 345218887Sdim assert(I < getNumBranchAfters()); 346218887Sdim return ExtInfo->BranchAfters[I].first; 347218887Sdim } 348218887Sdim 349218887Sdim llvm::ConstantInt *getBranchAfterIndex(unsigned I) const { 350218887Sdim assert(I < getNumBranchAfters()); 351218887Sdim return ExtInfo->BranchAfters[I].second; 352218887Sdim } 353218887Sdim 354218887Sdim /// Add a branch-through to this cleanup scope. A branch-through is 355218887Sdim /// a branch from a scope protected by this (normal) cleanup to an 356218887Sdim /// enclosing scope other than the immediately-enclosing normal 357218887Sdim /// cleanup scope. 358218887Sdim /// 359218887Sdim /// In the following example, the branch through B's scope is a 360218887Sdim /// branch-through, while the branch through A's scope is a 361218887Sdim /// branch-after: 362218887Sdim /// for (;;) { A a; B b; break; } 363218887Sdim /// 364218887Sdim /// All branch-throughs have a common destination out of the 365218887Sdim /// cleanup, one possibly shared with the fall-through. Therefore 366218887Sdim /// branch-throughs usually don't force a switch after the cleanup. 367218887Sdim /// 368218887Sdim /// \return true if the branch-through was new to this scope 369218887Sdim bool addBranchThrough(llvm::BasicBlock *Block) { 370218887Sdim return getExtInfo().Branches.insert(Block); 371218887Sdim } 372218887Sdim 373218887Sdim /// Determines if this cleanup scope has any branch throughs. 374218887Sdim bool hasBranchThroughs() const { 375218887Sdim if (!ExtInfo) return false; 376218887Sdim return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); 377218887Sdim } 378218887Sdim 379218887Sdim static bool classof(const EHScope *Scope) { 380218887Sdim return (Scope->getKind() == Cleanup); 381218887Sdim } 382218887Sdim}; 383218887Sdim 384218887Sdim/// An exceptions scope which filters exceptions thrown through it. 385218887Sdim/// Only exceptions matching the filter types will be permitted to be 386218887Sdim/// thrown. 387218887Sdim/// 388218887Sdim/// This is used to implement C++ exception specifications. 389218887Sdimclass EHFilterScope : public EHScope { 390218887Sdim // Essentially ends in a flexible array member: 391218887Sdim // llvm::Value *FilterTypes[0]; 392218887Sdim 393218887Sdim llvm::Value **getFilters() { 394218887Sdim return reinterpret_cast<llvm::Value**>(this+1); 395218887Sdim } 396218887Sdim 397218887Sdim llvm::Value * const *getFilters() const { 398218887Sdim return reinterpret_cast<llvm::Value* const *>(this+1); 399218887Sdim } 400218887Sdim 401218887Sdimpublic: 402226890Sdim EHFilterScope(unsigned numFilters) 403226890Sdim : EHScope(Filter, EHScopeStack::stable_end()) { 404226890Sdim FilterBits.NumFilters = numFilters; 405226890Sdim } 406218887Sdim 407226890Sdim static size_t getSizeForNumFilters(unsigned numFilters) { 408226890Sdim return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*); 409218887Sdim } 410218887Sdim 411226890Sdim unsigned getNumFilters() const { return FilterBits.NumFilters; } 412218887Sdim 413226890Sdim void setFilter(unsigned i, llvm::Value *filterValue) { 414226890Sdim assert(i < getNumFilters()); 415226890Sdim getFilters()[i] = filterValue; 416218887Sdim } 417218887Sdim 418226890Sdim llvm::Value *getFilter(unsigned i) const { 419226890Sdim assert(i < getNumFilters()); 420226890Sdim return getFilters()[i]; 421218887Sdim } 422218887Sdim 423226890Sdim static bool classof(const EHScope *scope) { 424226890Sdim return scope->getKind() == Filter; 425218887Sdim } 426218887Sdim}; 427218887Sdim 428218887Sdim/// An exceptions scope which calls std::terminate if any exception 429218887Sdim/// reaches it. 430218887Sdimclass EHTerminateScope : public EHScope { 431218887Sdimpublic: 432226890Sdim EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope) 433226890Sdim : EHScope(Terminate, enclosingEHScope) {} 434218887Sdim static size_t getSize() { return sizeof(EHTerminateScope); } 435218887Sdim 436226890Sdim static bool classof(const EHScope *scope) { 437226890Sdim return scope->getKind() == Terminate; 438218887Sdim } 439218887Sdim}; 440218887Sdim 441218887Sdim/// A non-stable pointer into the scope stack. 442218887Sdimclass EHScopeStack::iterator { 443218887Sdim char *Ptr; 444218887Sdim 445218887Sdim friend class EHScopeStack; 446218887Sdim explicit iterator(char *Ptr) : Ptr(Ptr) {} 447218887Sdim 448218887Sdimpublic: 449218887Sdim iterator() : Ptr(0) {} 450218887Sdim 451218887Sdim EHScope *get() const { 452218887Sdim return reinterpret_cast<EHScope*>(Ptr); 453218887Sdim } 454218887Sdim 455218887Sdim EHScope *operator->() const { return get(); } 456218887Sdim EHScope &operator*() const { return *get(); } 457218887Sdim 458218887Sdim iterator &operator++() { 459218887Sdim switch (get()->getKind()) { 460218887Sdim case EHScope::Catch: 461218887Sdim Ptr += EHCatchScope::getSizeForNumHandlers( 462218887Sdim static_cast<const EHCatchScope*>(get())->getNumHandlers()); 463218887Sdim break; 464218887Sdim 465218887Sdim case EHScope::Filter: 466218887Sdim Ptr += EHFilterScope::getSizeForNumFilters( 467218887Sdim static_cast<const EHFilterScope*>(get())->getNumFilters()); 468218887Sdim break; 469218887Sdim 470218887Sdim case EHScope::Cleanup: 471218887Sdim Ptr += static_cast<const EHCleanupScope*>(get()) 472218887Sdim ->getAllocatedSize(); 473218887Sdim break; 474218887Sdim 475218887Sdim case EHScope::Terminate: 476218887Sdim Ptr += EHTerminateScope::getSize(); 477218887Sdim break; 478218887Sdim } 479218887Sdim 480218887Sdim return *this; 481218887Sdim } 482218887Sdim 483218887Sdim iterator next() { 484218887Sdim iterator copy = *this; 485218887Sdim ++copy; 486218887Sdim return copy; 487218887Sdim } 488218887Sdim 489218887Sdim iterator operator++(int) { 490218887Sdim iterator copy = *this; 491218887Sdim operator++(); 492218887Sdim return copy; 493218887Sdim } 494218887Sdim 495218887Sdim bool encloses(iterator other) const { return Ptr >= other.Ptr; } 496218887Sdim bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; } 497218887Sdim 498218887Sdim bool operator==(iterator other) const { return Ptr == other.Ptr; } 499218887Sdim bool operator!=(iterator other) const { return Ptr != other.Ptr; } 500218887Sdim}; 501218887Sdim 502218887Sdiminline EHScopeStack::iterator EHScopeStack::begin() const { 503218887Sdim return iterator(StartOfData); 504218887Sdim} 505218887Sdim 506218887Sdiminline EHScopeStack::iterator EHScopeStack::end() const { 507218887Sdim return iterator(EndOfBuffer); 508218887Sdim} 509218887Sdim 510218887Sdiminline void EHScopeStack::popCatch() { 511218887Sdim assert(!empty() && "popping exception stack when not empty"); 512218887Sdim 513226890Sdim EHCatchScope &scope = cast<EHCatchScope>(*begin()); 514226890Sdim InnermostEHScope = scope.getEnclosingEHScope(); 515226890Sdim StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()); 516218887Sdim} 517218887Sdim 518218887Sdiminline void EHScopeStack::popTerminate() { 519218887Sdim assert(!empty() && "popping exception stack when not empty"); 520218887Sdim 521226890Sdim EHTerminateScope &scope = cast<EHTerminateScope>(*begin()); 522226890Sdim InnermostEHScope = scope.getEnclosingEHScope(); 523218887Sdim StartOfData += EHTerminateScope::getSize(); 524218887Sdim} 525218887Sdim 526218887Sdiminline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { 527218887Sdim assert(sp.isValid() && "finding invalid savepoint"); 528218887Sdim assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); 529218887Sdim return iterator(EndOfBuffer - sp.Size); 530218887Sdim} 531218887Sdim 532218887Sdiminline EHScopeStack::stable_iterator 533218887SdimEHScopeStack::stabilize(iterator ir) const { 534218887Sdim assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer); 535218887Sdim return stable_iterator(EndOfBuffer - ir.Ptr); 536218887Sdim} 537218887Sdim 538218887Sdim} 539218887Sdim} 540218887Sdim 541218887Sdim#endif 542