[cfe-commits] r142654 - /cfe/trunk/lib/Analysis/ThreadSafety.cpp
DeLesley Hutchins
delesley at google.com
Fri Oct 21 09:14:33 PDT 2011
Author: delesley
Date: Fri Oct 21 11:14:33 2011
New Revision: 142654
URL: http://llvm.org/viewvc/llvm-project?rev=142654&view=rev
Log:
Refactoring and code cleanup.
Modified:
cfe/trunk/lib/Analysis/ThreadSafety.cpp
Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=142654&r1=142653&r2=142654&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Fri Oct 21 11:14:33 2011
@@ -41,6 +41,7 @@
ThreadSafetyHandler::~ThreadSafetyHandler() {}
namespace {
+
/// \brief Implements a set of CFGBlocks using a BitVector.
///
/// This class contains a minimal interface, primarily dictated by the SetType
@@ -83,6 +84,7 @@
}
};
+
/// \brief We create a helper class which we use to iterate through CFGBlocks in
/// the topological order.
class TopologicallySortedCFG {
@@ -116,6 +118,7 @@
}
};
+
/// \brief A MutexID object uniquely identifies a particular mutex, and
/// is built from an Expr* (i.e. calling a lock function).
///
@@ -275,6 +278,7 @@
}
};
+
/// \brief This is a helper class that stores info about the most recent
/// accquire of a Lock.
///
@@ -302,11 +306,12 @@
}
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(AcquireLoc.getRawEncoding());
- ID.AddInteger(LKind);
- }
+ ID.AddInteger(AcquireLoc.getRawEncoding());
+ ID.AddInteger(LKind);
+ }
};
+
/// A Lockset maps each MutexID (defined above) to information about how it has
/// been locked.
typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
@@ -324,25 +329,27 @@
// Helper functions
void removeLock(SourceLocation UnlockLoc, MutexID &Mutex);
void addLock(SourceLocation LockLoc, MutexID &Mutex, LockKind LK);
+
+ template <class AttrType>
+ void addLocksToSet(LockKind LK, AttrType *Attr, CXXMemberCallExpr *Exp,
+ NamedDecl *D);
+
const ValueDecl *getValueDecl(Expr *Exp);
void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
- template <class AttrType>
- void addLocksToSet(LockKind LK, AttrType *Attr, CXXMemberCallExpr *Exp,
- NamedDecl* D);
/// \brief Returns true if the lockset contains a lock, regardless of whether
/// the lock is held exclusively or shared.
- bool locksetContains(MutexID Lock) const {
+ bool locksetContains(const MutexID &Lock) const {
return LSet.lookup(Lock);
}
/// \brief Returns true if the lockset contains a lock with the passed in
/// locktype.
- bool locksetContains(MutexID Lock, LockKind KindRequested) const {
+ bool locksetContains(const MutexID &Lock, LockKind KindRequested) const {
const LockData *LockHeld = LSet.lookup(Lock);
return (LockHeld && KindRequested == LockHeld->LKind);
}
@@ -351,7 +358,8 @@
/// passed in locktype. So for example, if we pass in LK_Shared, this function
/// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
/// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(MutexID Lock, LockKind KindRequested) const {
+ bool locksetContainsAtLeast(const MutexID &Lock,
+ LockKind KindRequested) const {
switch (KindRequested) {
case LK_Shared:
return locksetContains(Lock);
@@ -402,6 +410,36 @@
LSet = NewLSet;
}
+/// \brief This function, parameterized by an attribute type, is used to add a
+/// set of locks specified as attribute arguments to the lockset.
+template <typename AttrType>
+void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
+ CXXMemberCallExpr *Exp,
+ NamedDecl* FunDecl) {
+ typedef typename AttrType::args_iterator iterator_type;
+
+ SourceLocation ExpLocation = Exp->getExprLoc();
+
+ if (Attr->args_size() == 0) {
+ // The mutex held is the "this" object.
+
+ MutexID Mutex(0, Exp, FunDecl);
+ if (!Mutex.isValid())
+ Handler.handleInvalidLockExp(Exp->getExprLoc());
+ else
+ addLock(ExpLocation, Mutex, LK);
+ return;
+ }
+
+ for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
+ MutexID Mutex(*I, Exp, FunDecl);
+ if (!Mutex.isValid())
+ Handler.handleInvalidLockExp(Exp->getExprLoc());
+ else
+ addLock(ExpLocation, Mutex, LK);
+ }
+}
+
/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
@@ -427,7 +465,6 @@
Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc());
}
-
/// \brief This method identifies variable dereferences and checks pt_guarded_by
/// and pt_guarded_var annotations. Note that we only check these annotations
/// at the time a pointer is dereferenced.
@@ -512,36 +549,6 @@
checkDereference(SubExp, AK_Read);
}
-/// \brief This function, parameterized by an attribute type, is used to add a
-/// set of locks specified as attribute arguments to the lockset.
-template <typename AttrType>
-void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
- CXXMemberCallExpr *Exp,
- NamedDecl* FunDecl) {
- typedef typename AttrType::args_iterator iterator_type;
-
- SourceLocation ExpLocation = Exp->getExprLoc();
-
- if (Attr->args_size() == 0) {
- // The mutex held is the "this" object.
-
- MutexID Mutex(0, Exp, FunDecl);
- if (!Mutex.isValid())
- Handler.handleInvalidLockExp(Exp->getExprLoc());
- else
- addLock(ExpLocation, Mutex, LK);
- return;
- }
-
- for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- MutexID Mutex(*I, Exp, FunDecl);
- if (!Mutex.isValid())
- Handler.handleInvalidLockExp(Exp->getExprLoc());
- else
- addLock(ExpLocation, Mutex, LK);
- }
-}
-
/// \brief When visiting CXXMemberCallExprs we need to examine the attributes on
/// the method that is being called and add, remove or check locks in the
/// lockset accordingly.
@@ -647,7 +654,23 @@
}
}
-} // end anonymous namespace
+
+/// \brief Class which implements the core thread safety analysis routines.
+class ThreadSafetyAnalyzer {
+ ThreadSafetyHandler &Handler;
+ Lockset::Factory LocksetFactory;
+
+public:
+ ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
+
+ Lockset intersectAndWarn(const Lockset LSet1, const Lockset LSet2,
+ LockErrorKind LEK);
+
+ Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
+ LockKind LK, SourceLocation Loc);
+
+ void runAnalysis(AnalysisContext &AC);
+};
/// \brief Compute the intersection of two locksets and issue warnings for any
/// locks in the symmetric difference.
@@ -657,9 +680,9 @@
/// A; if () then B; else C; D; we need to check that the lockset after B and C
/// are the same. In the event of a difference, we use the intersection of these
/// two locksets at the start of D.
-static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
- const Lockset LSet1, const Lockset LSet2,
- Lockset::Factory &Fact, LockErrorKind LEK) {
+Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset LSet1,
+ const Lockset LSet2,
+ LockErrorKind LEK) {
Lockset Intersection = LSet1;
for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
const MutexID &LSet2Mutex = I.getKey();
@@ -670,7 +693,8 @@
LSet2LockData.AcquireLoc,
LD->AcquireLoc);
if (LD->LKind != LK_Exclusive)
- Intersection = Fact.add(Intersection, LSet2Mutex, LSet2LockData);
+ Intersection = LocksetFactory.add(Intersection, LSet2Mutex,
+ LSet2LockData);
}
} else {
Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
@@ -684,16 +708,15 @@
const LockData &MissingLock = I.getData();
Handler.handleMutexHeldEndOfScope(Mutex.getName(),
MissingLock.AcquireLoc, LEK);
- Intersection = Fact.remove(Intersection, Mutex);
+ Intersection = LocksetFactory.remove(Intersection, Mutex);
}
}
return Intersection;
}
-static Lockset addLock(ThreadSafetyHandler &Handler,
- Lockset::Factory &LocksetFactory,
- Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
- LockKind LK, SourceLocation Loc) {
+Lockset ThreadSafetyAnalyzer::addLock(Lockset &LSet, Expr *MutexExp,
+ const NamedDecl *D,
+ LockKind LK, SourceLocation Loc) {
MutexID Mutex(MutexExp, 0, D);
if (!Mutex.isValid()) {
Handler.handleInvalidLockExp(MutexExp->getExprLoc());
@@ -703,15 +726,12 @@
return LocksetFactory.add(LSet, Mutex, NewLock);
}
-namespace clang {
-namespace thread_safety {
/// \brief Check a function's CFG for thread-safety violations.
///
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
-void runThreadSafetyAnalysis(AnalysisContext &AC,
- ThreadSafetyHandler &Handler) {
+void ThreadSafetyAnalyzer::runAnalysis(AnalysisContext &AC) {
CFG *CFGraph = AC.getCFG();
if (!CFGraph) return;
const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
@@ -721,9 +741,7 @@
if (D->getAttr<NoThreadSafetyAnalysisAttr>())
return;
- Lockset::Factory LocksetFactory;
-
- // FIXME: Swith to SmallVector? Otherwise improve performance impact?
+ // FIXME: Switch to SmallVector? Otherwise improve performance impact?
std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(),
LocksetFactory.getEmptyMap());
std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(),
@@ -735,6 +753,8 @@
TopologicallySortedCFG SortedGraph(CFGraph);
CFGBlockSet VisitedBlocks(CFGraph);
+ // Add locks from exclusive_locks_required and shared_locks_required
+ // to initial lockset.
if (!SortedGraph.empty() && D->hasAttrs()) {
const CFGBlock *FirstBlock = *SortedGraph.begin();
Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()];
@@ -747,7 +767,7 @@
for (SharedLocksRequiredAttr::args_iterator
SLRIter = SLRAttr->args_begin(),
SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter)
- InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
+ InitialLockset = addLock(InitialLockset,
*SLRIter, D, LK_Shared,
AttrLoc);
} else if (ExclusiveLocksRequiredAttr *ELRAttr
@@ -755,7 +775,7 @@
for (ExclusiveLocksRequiredAttr::args_iterator
ELRIter = ELRAttr->args_begin(),
ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter)
- InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
+ InitialLockset = addLock(InitialLockset,
*ELRIter, D, LK_Exclusive,
AttrLoc);
}
@@ -799,8 +819,7 @@
Entryset = ExitLocksets[PrevBlockID];
LocksetInitialized = true;
} else {
- Entryset = intersectAndWarn(Handler, Entryset,
- ExitLocksets[PrevBlockID], LocksetFactory,
+ Entryset = intersectAndWarn(Entryset, ExitLocksets[PrevBlockID],
LEK_LockedSomePredecessors);
}
}
@@ -827,8 +846,7 @@
CFGBlock *FirstLoopBlock = *SI;
Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
Lockset LoopEnd = ExitLocksets[CurrBlockID];
- intersectAndWarn(Handler, LoopEnd, PreLoop, LocksetFactory,
- LEK_LockedSomeLoopIterations);
+ intersectAndWarn(LoopEnd, PreLoop, LEK_LockedSomeLoopIterations);
}
}
@@ -836,8 +854,24 @@
Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
// FIXME: Should we call this function for all blocks which exit the function?
- intersectAndWarn(Handler, InitialLockset, FinalLockset, LocksetFactory,
- LEK_LockedAtEndOfFunction);
+ intersectAndWarn(InitialLockset, FinalLockset, LEK_LockedAtEndOfFunction);
+}
+
+} // end anonymous namespace
+
+
+namespace clang {
+namespace thread_safety {
+
+/// \brief Check a function's CFG for thread-safety violations.
+///
+/// We traverse the blocks in the CFG, compute the set of mutexes that are held
+/// at the end of each block, and issue warnings for thread safety violations.
+/// Each block in the CFG is traversed exactly once.
+void runThreadSafetyAnalysis(AnalysisContext &AC,
+ ThreadSafetyHandler &Handler) {
+ ThreadSafetyAnalyzer Analyzer(Handler);
+ Analyzer.runAnalysis(AC);
}
/// \brief Helper function that returns a LockKind required for the given level
@@ -851,4 +885,5 @@
}
llvm_unreachable("Unknown AccessKind");
}
+
}} // end namespace clang::thread_safety
More information about the cfe-commits
mailing list