[cfe-commits] r160983 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h lib/StaticAnalyzer/Core/ProgramState.cpp

Jordan Rose jordan_rose at apple.com
Mon Jul 30 13:21:55 PDT 2012


Author: jrose
Date: Mon Jul 30 15:21:55 2012
New Revision: 160983

URL: http://llvm.org/viewvc/llvm-project?rev=160983&view=rev
Log:
[analyzer] Introduce a CallEventManager to keep a pool of CallEvents.

This allows us to get around the C++ "virtual constructor" problem
when we'd like to create a CallEvent from an ExplodedNode, an inlined
StackFrameContext, or another CallEvent. The solution has three parts:

- CallEventManager uses a BumpPtrAllocator to allocate CallEvent-sized
  memory blocks. It also keeps a cache of freed CallEvents for reuse.
- CallEvents all have protected copy constructors, along with cloneTo()
  methods that use placement new to copy into CallEventManager-managed
  memory, vtables intact.
- CallEvents owned by CallEventManager are now wrapped in an
  IntrusiveRefCntPtr. Going forwards, it's probably a good idea to create
  ALL CallEvents through the CallEventManager, so that we don't accidentally
  try to reclaim a stack-allocated CallEvent.

All of this machinery is currently unused but will be put into use shortly.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
    cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=160983&r1=160982&r2=160983&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Mon Jul 30 15:21:55 2012
@@ -47,9 +47,19 @@
   CE_ObjCMessage
 };
 
+class CallEvent;
+typedef IntrusiveRefCntPtr<CallEvent> CallEventRef;
+
 
 /// \brief Represents an abstract call to a function or method along a
 /// particular path.
+///
+/// CallEvents are created through the factory methods of CallEventManager.
+///
+/// CallEvents should always be cheap to create and destroy. In order for
+/// CallEventManager to be able to re-use CallEvent-sized memory blocks,
+/// subclasses of CallEvent may not add any data members to the base class.
+/// Use the "Data" and "Location" fields instead.
 class CallEvent {
 public:
   typedef CallEventKind Kind;
@@ -59,20 +69,36 @@
   const LocationContext *LCtx;
   llvm::PointerUnion<const Expr *, const Decl *> Origin;
 
-  // DO NOT IMPLEMENT! CallEvents should not be copied.
-  CallEvent(const CallEvent &);
+  // DO NOT IMPLEMENT
   CallEvent &operator=(const CallEvent &);
 
 protected:
   // This is user data for subclasses.
   const void *Data;
+
+  // This is user data for subclasses.
+  // This should come right before RefCount, so that the two fields can be
+  // packed together on LP64 platforms.
   SourceLocation Location;
 
+private:
+  mutable unsigned RefCount;
+
+  template <typename T> friend struct llvm::IntrusiveRefCntPtrInfo;
+  void Retain() const { ++RefCount; }
+  void Release() const;
+
+protected:
   CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
-    : State(state), LCtx(lctx), Origin(E) {}
+    : State(state), LCtx(lctx), Origin(E), RefCount(0) {}
 
   CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
-    : State(state), LCtx(lctx), Origin(D) {}
+    : State(state), LCtx(lctx), Origin(D), RefCount(0) {}
+
+  // DO NOT MAKE PUBLIC
+  CallEvent(const CallEvent &Original)
+    : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
+      Data(Original.Data), Location(Original.Location), RefCount(0) {}
 
   ProgramStateRef getState() const {
     return State;
@@ -83,11 +109,15 @@
   }
 
 
+  /// Copies this CallEvent, with vtable intact, into a new block of memory.
+  virtual void cloneTo(void *Dest) const = 0;
+
   /// \brief Get the value of arbitrary expressions at this point in the path.
   SVal getSVal(const Stmt *S) const {
     return getState()->getSVal(S, getLocationContext());
   }
 
+
   typedef SmallVectorImpl<const MemRegion *> RegionList;
 
   /// \brief Used to specify non-argument regions that will be invalidated as a
@@ -197,6 +227,15 @@
   ProgramStateRef invalidateRegions(unsigned BlockCount,
                                     ProgramStateRef Orig = 0) const;
 
+  /// Returns a copy of this CallEvent, but using the given state.
+  template <typename T>
+  IntrusiveRefCntPtr<T> cloneWithState(ProgramStateRef NewState) const;
+
+  /// Returns a copy of this CallEvent, but using the given state.
+  CallEventRef cloneWithState(ProgramStateRef NewState) const {
+    return cloneWithState<CallEvent>(NewState);
+  }
+
   /// \brief Returns true if this is a statement that can be considered for
   /// inlining.
   ///
@@ -264,6 +303,7 @@
   AnyFunctionCall(const Decl *D, ProgramStateRef St,
                   const LocationContext *LCtx)
     : CallEvent(D, St, LCtx) {}
+  AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {}
 
   virtual QualType getDeclaredResultType() const;
 
@@ -298,8 +338,8 @@
 protected:
   SimpleCall(const CallExpr *CE, ProgramStateRef St,
              const LocationContext *LCtx)
-    : AnyFunctionCall(CE, St, LCtx) {
-  }
+    : AnyFunctionCall(CE, St, LCtx) {}
+  SimpleCall(const SimpleCall &Other) : AnyFunctionCall(Other) {}
 
 public:
   virtual const CallExpr *getOriginExpr() const {
@@ -324,6 +364,10 @@
 ///
 /// Example: \c fun()
 class FunctionCall : public SimpleCall {
+protected:
+  FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+
 public:
   FunctionCall(const CallExpr *CE, ProgramStateRef St,
                const LocationContext *LCtx)
@@ -346,6 +390,8 @@
                   const LocationContext *LCtx)
     : SimpleCall(CE, St, LCtx) {}
 
+  CXXInstanceCall(const CXXInstanceCall &Other) : SimpleCall(Other) {}
+
 public:
   virtual const Decl *getRuntimeDefinition() const;
 
@@ -359,6 +405,10 @@
 ///
 /// Example: \c obj.fun()
 class CXXMemberCall : public CXXInstanceCall {
+protected:
+  CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+
 public:
   CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
                 const LocationContext *LCtx)
@@ -382,6 +432,13 @@
 ///
 /// Example: <tt>iter + 1</tt>
 class CXXMemberOperatorCall : public CXXInstanceCall {
+protected:
+  CXXMemberOperatorCall(const CXXMemberOperatorCall &Other)
+    : CXXInstanceCall(Other) {}
+  virtual void cloneTo(void *Dest) const {
+    new (Dest) CXXMemberOperatorCall(*this);
+  }
+
 public:
   CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
                         const LocationContext *LCtx)
@@ -412,6 +469,9 @@
 /// Example: <tt>^{ /* ... */ }()</tt>
 class BlockCall : public SimpleCall {
 protected:
+  BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
+
   virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
 
   virtual QualType getDeclaredResultType() const;
@@ -456,6 +516,9 @@
 /// Example: \c T(1)
 class CXXConstructorCall : public AnyFunctionCall {
 protected:
+  CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
+
   virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
 
 public:
@@ -502,6 +565,9 @@
 /// of a full-expression (for temporaries), or as part of a delete.
 class CXXDestructorCall : public AnyFunctionCall {
 protected:
+  CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
+
   virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
 
 public:
@@ -537,6 +603,10 @@
 ///
 /// This is a call to "operator new".
 class CXXAllocatorCall : public AnyFunctionCall {
+protected:
+  CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+
 public:
   CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
                    const LocationContext *LCtx)
@@ -585,6 +655,9 @@
   const PseudoObjectExpr *getContainingPseudoObjectExpr() const;
 
 protected:
+  ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); }
+
   virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
 
   virtual QualType getDeclaredResultType() const;
@@ -678,6 +751,64 @@
   }
 };
 
+
+/// \brief Manages the lifetime of CallEvent objects.
+///
+/// CallEventManager provides a way to create arbitrary CallEvents "on the
+/// stack" as if they were value objects by keeping a cache of CallEvent-sized
+/// memory blocks. The CallEvents created by CallEventManager are only valid
+/// for the lifetime of the OwnedCallEvent that holds them; right now these
+/// objects cannot be copied and ownership cannot be transferred.
+class CallEventManager {
+  friend class CallEvent;
+
+  llvm::BumpPtrAllocator &Alloc;
+  SmallVector<void *, 4> Cache;
+
+  void reclaim(const void *Memory) {
+    Cache.push_back(const_cast<void *>(Memory));
+  }
+
+  /// Returns memory that can be initialized as a CallEvent.
+  void *allocate() {
+    if (Cache.empty())
+      return Alloc.Allocate<FunctionCall>();
+    else
+      return Cache.pop_back_val();
+  }
+
+public:
+  CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+};
+
+
+template <typename T>
+IntrusiveRefCntPtr<T> CallEvent::cloneWithState(ProgramStateRef NewState) const{
+  assert(isa<T>(*this) && "Cloning to unrelated type");
+  assert(sizeof(T) == sizeof(CallEvent) && "Subclasses may not add fields");
+
+  CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+  T *Copy = static_cast<T *>(Mgr.allocate());
+  cloneTo(Copy);
+  assert(Copy->getKind() == this->getKind() && "Bad copy");
+
+  Copy->State = NewState;
+  return Copy;
+}
+
+inline void CallEvent::Release() const {
+  assert(RefCount > 0 && "Reference count is already zero.");
+  --RefCount;
+
+  if (RefCount > 0)
+    return;
+
+  CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+  Mgr.reclaim(this);
+
+  this->~CallEvent();
+}
+
 } // end namespace ento
 } // end namespace clang
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=160983&r1=160982&r2=160983&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon Jul 30 15:21:55 2012
@@ -36,6 +36,7 @@
 namespace ento {
 
 class CallEvent;
+class CallEventManager;
 
 typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
                                                        SubEngine&);
@@ -414,6 +415,9 @@
   /// Object that manages the data for all created SVals.
   OwningPtr<SValBuilder> svalBuilder;
 
+  /// Manages memory for created CallEvents.
+  OwningPtr<CallEventManager> CallEventMgr;
+
   /// A BumpPtrAllocator to allocate states.
   llvm::BumpPtrAllocator &Alloc;
   
@@ -425,28 +429,7 @@
                  StoreManagerCreator CreateStoreManager,
                  ConstraintManagerCreator CreateConstraintManager,
                  llvm::BumpPtrAllocator& alloc,
-                 SubEngine &subeng)
-    : Eng(&subeng),
-      EnvMgr(alloc),
-      GDMFactory(alloc),
-      svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
-      Alloc(alloc) {
-    StoreMgr.reset((*CreateStoreManager)(*this));
-    ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
-  }
-
-  ProgramStateManager(ASTContext &Ctx,
-                 StoreManagerCreator CreateStoreManager,
-                 ConstraintManager* ConstraintManagerPtr,
-                 llvm::BumpPtrAllocator& alloc)
-    : Eng(0),
-      EnvMgr(alloc),
-      GDMFactory(alloc),
-      svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
-      Alloc(alloc) {
-    StoreMgr.reset((*CreateStoreManager)(*this));
-    ConstraintMgr.reset(ConstraintManagerPtr);
-  }
+                 SubEngine &subeng);
 
   ~ProgramStateManager();
 
@@ -482,6 +465,8 @@
     return svalBuilder->getRegionManager();
   }
 
+  CallEventManager &getCallEventManager() { return *CallEventMgr; }
+
   StoreManager& getStoreManager() { return *StoreMgr; }
   ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
   SubEngine* getOwningEngine() { return Eng; }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=160983&r1=160982&r2=160983&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Mon Jul 30 15:21:55 2012
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
@@ -70,6 +71,19 @@
     stateMgr->getStoreManager().decrementReferenceCount(store);
 }
 
+ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
+                                         StoreManagerCreator CreateSMgr,
+                                         ConstraintManagerCreator CreateCMgr,
+                                         llvm::BumpPtrAllocator &alloc,
+                                         SubEngine &SubEng)
+  : Eng(&SubEng), EnvMgr(alloc), GDMFactory(alloc),
+    svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
+    CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
+  StoreMgr.reset((*CreateSMgr)(*this));
+  ConstraintMgr.reset((*CreateCMgr)(*this, SubEng));
+}
+
+
 ProgramStateManager::~ProgramStateManager() {
   for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
        I!=E; ++I)





More information about the cfe-commits mailing list