From: Ted Kremenek Date: Mon, 23 Feb 2009 17:45:03 +0000 (+0000) Subject: Add more boilerplate logic to more accurately reason about autorelease pools. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9a8e2e1cf087c1720397e3d6d0c9b77a18787ef;p=clang Add more boilerplate logic to more accurately reason about autorelease pools. This doesn't change the current functionality, but better codifies the autorelease pool stack itself. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65328 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 39edcfd8ad..5a3e9be0cb 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -221,7 +221,8 @@ enum ArgEffect { IncRefMsg, IncRef, DecRefMsg, DecRef, MakeCollectable, DoNothing, DoNothingByRef, - StopTracking, MayEscape, SelfOwn, Autorelease }; + StopTracking, MayEscape, SelfOwn, Autorelease, + NewAutoreleasePool }; /// ArgEffects summarizes the effects of a function/method call on all of /// its arguments. @@ -1132,6 +1133,12 @@ void RetainSummaryManager::InitializeMethodSummaries() { Summ = getPersistentSummary(E, Autorelease); addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); + // Specially handle NSAutoreleasePool. + addInstMethSummary("NSAutoreleasePool", + getPersistentSummary(RetEffect::MakeReceiverAlias(), + NewAutoreleasePool), + "init", NULL); + // For NSWindow, allocated objects are (initially) self-owned. // FIXME: For now we opt for false negatives with NSWindow, as these objects // self-own themselves. However, they only do this once they are displayed. @@ -1354,13 +1361,50 @@ namespace clang { // ARBindings - State used to track objects in autorelease pools. //===----------------------------------------------------------------------===// -typedef llvm::ImmutableSet ARPoolContents; -typedef llvm::ImmutableList< std::pair > ARBindings; + +namespace { +class VISIBILITY_HIDDEN AutoreleasePoolID { + unsigned short PoolLevel; + SymbolRef Sym; + +public: + AutoreleasePoolID() : PoolLevel(0) {} + AutoreleasePoolID(unsigned short poolLevel, SymbolRef sym) + : PoolLevel(poolLevel), Sym(Sym) {} + + bool operator<(const AutoreleasePoolID &X) const { + assert(!(PoolLevel == X.PoolLevel) || Sym == X.Sym); + return PoolLevel < X.PoolLevel; + } + + bool operator==(const AutoreleasePoolID &X) const { + assert(!(PoolLevel == X.PoolLevel) || Sym == X.Sym); + return PoolLevel == X.PoolLevel; + } + + bool matches(SymbolRef sym) { + return Sym.isInitialized() ? Sym == sym : false; + } + + static void Profile(llvm::FoldingSetNodeID& ID, const AutoreleasePoolID& AI) { + ID.AddInteger(AI.PoolLevel); + if (AI.Sym.isInitialized()) ID.Add(AI.Sym); + } +}; +} + +typedef llvm::ImmutableSet AutoreleasePoolContents; +typedef llvm::ImmutableMap + AutoreleaseBindings; + static int AutoRBIndex = 0; +// We can use 'AutoreleaseBindings' directly as the tag class into the GDM sinc +// it is an ImmutableMap based on two types private to this source file. namespace clang { template<> - struct GRStateTrait : public GRStatePartialTrait { + struct GRStateTrait + : public GRStatePartialTrait { static inline void* GDMIndex() { return &AutoRBIndex; } }; } @@ -2040,6 +2084,8 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym, case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break; case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break; case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break; + case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : + NewAutoreleasePool; break; } switch (E) { @@ -2052,6 +2098,8 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym, break; } // Fall-through. + + case NewAutoreleasePool: // FIXME: Implement pushing the pool to the stack. case DoNothingByRef: case DoNothing: if (!isGCEnabled() && V.getKind() == RefVal::Released) {