diff options
-rw-r--r-- | lib/CodeGen/CGException.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGException.h | 40 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 67 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 13 |
4 files changed, 119 insertions, 7 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index dd518cf5ef..d4a702a255 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -73,11 +73,13 @@ EHScopeStack::getEnclosingEHCleanup(iterator it) const { void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); - bool IsNormalCleanup = Kind != EHCleanup; - bool IsEHCleanup = Kind != NormalCleanup; + bool IsNormalCleanup = Kind & NormalCleanup; + bool IsEHCleanup = Kind & EHCleanup; + bool IsActive = !(Kind & InactiveCleanup); EHCleanupScope *Scope = new (Buffer) EHCleanupScope(IsNormalCleanup, IsEHCleanup, + IsActive, Size, BranchFixups.size(), InnermostNormalCleanup, diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h index 01536e35fb..f40e3e32c2 100644 --- a/lib/CodeGen/CGException.h +++ b/lib/CodeGen/CGException.h @@ -160,6 +160,12 @@ class EHCleanupScope : public EHScope { /// Whether this cleanup needs to be run along exception edges. bool IsEHCleanup : 1; + /// Whether this cleanup was activated before all normal uses. + bool ActivatedBeforeNormalUse : 1; + + /// Whether this cleanup was activated before all EH uses. + bool ActivatedBeforeEHUse : 1; + /// The amount of extra storage needed by the Cleanup. /// Always a multiple of the scope-stack alignment. unsigned CleanupSize : 12; @@ -167,7 +173,7 @@ class EHCleanupScope : public EHScope { /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. - unsigned FixupDepth : BitsRemaining - 14; + unsigned FixupDepth : BitsRemaining - 16; /// The nearest normal cleanup scope enclosing this one. EHScopeStack::stable_iterator EnclosingNormal; @@ -183,6 +189,14 @@ class EHCleanupScope : public EHScope { /// created if needed before the cleanup is popped. llvm::BasicBlock *EHBlock; + /// An optional i1 variable indicating whether this cleanup has been + /// activated yet. This has one of three states: + /// - it is null if the cleanup is inactive + /// - it is activeSentinel() if the cleanup is active and was not + /// required before activation + /// - it points to a valid variable + llvm::AllocaInst *ActiveVar; + /// Extra information required for cleanups that have resolved /// branches through them. This has to be allocated on the side /// because everything on the cleanup stack has be trivially @@ -227,15 +241,19 @@ public: return sizeof(EHCleanupScope) + CleanupSize; } - EHCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize, - unsigned FixupDepth, + EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive, + unsigned CleanupSize, unsigned FixupDepth, EHScopeStack::stable_iterator EnclosingNormal, EHScopeStack::stable_iterator EnclosingEH) : EHScope(EHScope::Cleanup), IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), + ActivatedBeforeNormalUse(IsActive), + ActivatedBeforeEHUse(IsActive), CleanupSize(CleanupSize), FixupDepth(FixupDepth), EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), - NormalBlock(0), EHBlock(0), ExtInfo(0) + NormalBlock(0), EHBlock(0), + ActiveVar(IsActive ? activeSentinel() : 0), + ExtInfo(0) { assert(this->CleanupSize == CleanupSize && "cleanup size overflow"); } @@ -252,6 +270,20 @@ public: llvm::BasicBlock *getEHBlock() const { return EHBlock; } void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; } + static llvm::AllocaInst *activeSentinel() { + return reinterpret_cast<llvm::AllocaInst*>(1); + } + + bool isActive() const { return ActiveVar != 0; } + llvm::AllocaInst *getActiveVar() const { return ActiveVar; } + void setActiveVar(llvm::AllocaInst *Var) { ActiveVar = Var; } + + bool wasActivatedBeforeNormalUse() const { return ActivatedBeforeNormalUse; } + void setActivatedBeforeNormalUse(bool B) { ActivatedBeforeNormalUse = B; } + + bool wasActivatedBeforeEHUse() const { return ActivatedBeforeEHUse; } + void setActivatedBeforeEHUse(bool B) { ActivatedBeforeEHUse = B; } + unsigned getFixupDepth() const { return FixupDepth; } EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { return EnclosingNormal; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index e5cfa624b2..b3ac8f1ddb 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -1275,6 +1275,73 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { EHStack.popNullFixups(); } +/// Activate a cleanup that was created in an inactivated state. +void CodeGenFunction::ActivateCleanup(EHScopeStack::stable_iterator C) { + assert(C != EHStack.stable_end() && "activating bottom of stack?"); + EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C)); + assert(!Scope.isActive() && "double activation"); + + // Calculate whether the cleanup was used: + bool Used = false; + + // - as a normal cleanup + if (Scope.isNormalCleanup()) { + bool NormalUsed = false; + if (Scope.getNormalBlock()) { + NormalUsed = true; + } else { + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostNormalCleanup(); I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); + if (S.getNormalBlock()) { + NormalUsed = true; + break; + } + I = S.getEnclosingNormalCleanup(); + } + } + + if (NormalUsed) + Used = true; + else + Scope.setActivatedBeforeNormalUse(true); + } + + // - as an EH cleanup + if (Scope.isEHCleanup()) { + bool EHUsed = false; + if (Scope.getEHBlock()) { + EHUsed = true; + } else { + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostEHCleanup(); I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); + if (S.getEHBlock()) { + EHUsed = true; + break; + } + I = S.getEnclosingEHCleanup(); + } + } + + if (EHUsed) + Used = true; + else + Scope.setActivatedBeforeEHUse(true); + } + + llvm::AllocaInst *Var = EHCleanupScope::activeSentinel(); + if (Used) { + Var = CreateTempAlloca(Builder.getInt1Ty()); + InitTempAlloca(Var, Builder.getFalse()); + } + Scope.setActiveVar(Var); +} + llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() { if (!NormalCleanupDest) NormalCleanupDest = diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 325940d245..3d212b5f78 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -96,7 +96,16 @@ struct BranchFixup { llvm::BranchInst *InitialBranch; }; -enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup }; +enum CleanupKind { + EHCleanup = 0x1, + NormalCleanup = 0x2, + NormalAndEHCleanup = EHCleanup | NormalCleanup, + + InactiveCleanup = 0x4, + InactiveEHCleanup = EHCleanup | InactiveCleanup, + InactiveNormalCleanup = NormalCleanup | InactiveCleanup, + InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup +}; /// A stack of scopes which respond to exceptions, including cleanups /// and catch blocks. @@ -520,6 +529,8 @@ public: /// process all branch fixups. void PopCleanupBlock(bool FallThroughIsBranchThrough = false); + void ActivateCleanup(EHScopeStack::stable_iterator Cleanup); + /// \brief Enters a new scope for capturing cleanups, all of which /// will be executed once the scope is exited. class RunCleanupsScope { |