forked from OSchip/llvm-project
Sketch out a framework for delaying the activation of a cleanup.
Not yet complete or used. llvm-svn: 111044
This commit is contained in:
parent
d1191ee43c
commit
612942d65f
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue