Bug 935778 - Part 3: Add trace-refcount logging for AddRef and Release in RefCounted objects; r=dbaron
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 09 Mar 2014 14:36:36 -0400
changeset 189867 6ece485bb7223d6a6b48e117669e9f6cb0e8e603
parent 189866 f16600ef3313325bc7cc419d750b1d25d9664d2f
child 189868 9cfebec86c16c1f84cc3667bde8dd87eec0fd71f
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs935778
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 935778 - Part 3: Add trace-refcount logging for AddRef and Release in RefCounted objects; r=dbaron
mfbt/RefPtr.h
mfbt/WeakPtr.h
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -9,16 +9,23 @@
 #ifndef mozilla_RefPtr_h
 #define mozilla_RefPtr_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/RefCountType.h"
 #include "mozilla/TypeTraits.h"
+#if defined(MOZILLA_INTERNAL_API)
+#include "nsXPCOM.h"
+#endif
+
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+#define MOZ_REFCOUNTED_LEAK_CHECKING
+#endif
 
 namespace mozilla {
 
 template<typename T> class RefCounted;
 template<typename T> class RefPtr;
 template<typename T> class TemporaryRef;
 template<typename T> class OutParamRef;
 template<typename T> OutParamRef<T> byRef(RefPtr<T>&);
@@ -48,16 +55,38 @@ template<typename T> OutParamRef<T> byRe
  * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public
  * section of your class, where ClassName is the name of your class.
  */
 namespace detail {
 #ifdef DEBUG
 const MozRefCountType DEAD = 0xffffdead;
 #endif
 
+// When building code that gets compiled into Gecko, try to use the
+// trace-refcount leak logging facilities.
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+class RefCountLogger
+{
+  public:
+    static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
+                          const char* aTypeName, uint32_t aInstanceSize)
+    {
+      MOZ_ASSERT(aRefCount != DEAD);
+      NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName, aInstanceSize);
+    }
+
+    static void logRelease(const void* aPointer, MozRefCountType aRefCount,
+                           const char* aTypeName)
+    {
+      MOZ_ASSERT(aRefCount != DEAD);
+      NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
+    }
+};
+#endif
+
 // This is used WeakPtr.h as well as this file.
 enum RefCountAtomicity
 {
   AtomicRefCount,
   NonAtomicRefCount
 };
 
 template<typename T, RefCountAtomicity Atomicity>
@@ -71,21 +100,31 @@ class RefCounted
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     // Compatibility with nsRefPtr.
     void AddRef() const {
       MOZ_ASSERT(int32_t(refCnt) >= 0);
       ++refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logAddRef(static_cast<const T*>(this), refCnt,
+                                        static_cast<const T*>(this)->typeName(),
+                                        static_cast<const T*>(this)->typeSize());
+#endif
     }
 
     void Release() const {
       MOZ_ASSERT(int32_t(refCnt) > 0);
-      if (0 == --refCnt) {
+      --refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logRelease(static_cast<const T*>(this), refCnt,
+                                         static_cast<const T*>(this)->typeName());
+#endif
+      if (0 == refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
         delete static_cast<const T*>(this);
       }
     }
 
     // Compatibility with wtf::RefPtr.
@@ -96,17 +135,17 @@ class RefCounted
       MOZ_ASSERT(refCnt > 0);
       return refCnt == 1;
     }
 
   private:
     mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
 };
 
-#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
 #define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
   const char* typeName() const { return #T; } \
   size_t typeSize() const { return sizeof(*this); }
 
 #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \
   virtual const char* typeName() const { return #T; } \
   virtual size_t typeSize() const { return sizeof(*this); }
 #else
--- a/mfbt/WeakPtr.h
+++ b/mfbt/WeakPtr.h
@@ -59,21 +59,24 @@
  *
  * The API was loosely inspired by Chromium's weak_ptr.h:
  * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
  */
 
 #ifndef mozilla_WeakPtr_h
 #define mozilla_WeakPtr_h
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/NullPtr.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TypeTraits.h"
 
+#include <string.h>
+
 namespace mozilla {
 
 template <typename T, class WeakReference> class WeakPtrBase;
 template <typename T, class WeakReference> class SupportsWeakPtrBase;
 
 namespace detail {
 
 // This can live beyond the lifetime of the class derived from SupportsWeakPtrBase.
@@ -81,16 +84,39 @@ template<class T>
 class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
 {
   public:
     explicit WeakReference(T* p) : ptr(p) {}
     T* get() const {
       return ptr;
     }
 
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+#ifdef XP_WIN
+#define snprintf _snprintf
+#endif
+    const char* typeName() const {
+      static char nameBuffer[1024];
+      const char* innerType = ptr->typeName();
+      // We could do fancier length checks at runtime, but innerType is
+      // controlled by us so we can ensure that this never causes a buffer
+      // overflow by this assertion.
+      MOZ_ASSERT(strlen(innerType) + sizeof("WeakReference<>") < ArrayLength(nameBuffer),
+                 "Exceedingly large type name");
+      snprintf(nameBuffer, ArrayLength(nameBuffer), "WeakReference<%s>", innerType);
+      // This is usually not OK, but here we are returning a pointer to a static
+      // buffer which will immediately be used by the caller.
+      return nameBuffer;
+    }
+    size_t typeSize() const {
+      return sizeof(*this);
+    }
+#undef snprintf
+#endif
+
   private:
     friend class WeakPtrBase<T, WeakReference<T> >;
     friend class SupportsWeakPtrBase<T, WeakReference<T> >;
     void detach() {
       ptr = nullptr;
     }
     T* ptr;
 };