Bug 1028588 - Make XPCOM refcounting assert against public destructors (leaving aside _INHERITED macros for now) - r=khuey
authorBenoit Jacob <bjacob@mozilla.com>
Mon, 07 Jul 2014 14:27:32 -0400
changeset 192758 261d818388d28fa95170cf9eddeb43809ee7415b
parent 192757 eac85d5073ef6549df1cc352e666f2c88b294ad8
child 192759 667abb03c12379904e2243b69a777eb2854db377
push id7651
push usercbook@mozilla.com
push dateTue, 08 Jul 2014 13:28:32 +0000
treeherderfx-team@05cfda67b9db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1028588
milestone33.0a1
Bug 1028588 - Make XPCOM refcounting assert against public destructors (leaving aside _INHERITED macros for now) - r=khuey
xpcom/glue/nsISupportsImpl.h
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -25,16 +25,88 @@
 #endif
 #include "mozilla/Attributes.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MacroArgs.h"
 #include "mozilla/MacroForEach.h"
 
+namespace mozilla {
+template <typename T>
+struct HasDangerousPublicDestructor
+{
+  static const bool value = false;
+};
+}
+
+#if defined(__clang__)
+   // bug 1028428 shows that at least in FreeBSD 10.0 with Clang 3.4 and libc++ 3.4,
+   // std::is_destructible is buggy in that it returns false when it should return true
+   // on ipc::SharedMemory. On the other hand, all Clang versions currently in use
+   // seem to handle the fallback just fine.
+#  define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
+#elif defined(__GNUC__)
+   // GCC 4.7 is has buggy std::is_destructible
+#  if MOZ_USING_LIBSTDCXX && MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
+#    define MOZ_HAVE_STD_IS_DESTRUCTIBLE
+   // Some GCC versions have an ICE when using destructors in decltype().
+   // Works for me on GCC 4.8.2 on Fedora 20 x86-64.
+#  elif MOZ_GCC_VERSION_AT_LEAST(4, 8, 2)
+#    define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
+#  endif
+#endif
+
+#ifdef MOZ_HAVE_STD_IS_DESTRUCTIBLE
+#  include <type_traits>
+#  define MOZ_IS_DESTRUCTIBLE(X) (std::is_destructible<X>::value)
+#elif defined MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
+  namespace mozilla {
+    struct IsDestructibleFallbackImpl
+    {
+      template<typename T> static T&& Declval();
+
+      template<typename T, typename = decltype(Declval<T>().~T())>
+      static TrueType Test(int);
+
+      template<typename>
+      static FalseType Test(...);
+
+      template<typename T>
+      struct Selector
+      {
+        typedef decltype(Test<T>(0)) type;
+      };
+    };
+
+    template<typename T>
+    struct IsDestructibleFallback
+      : IsDestructibleFallbackImpl::Selector<T>::type
+    {
+    };
+  }
+#  define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
+#endif
+
+#ifdef MOZ_IS_DESTRUCTIBLE
+#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
+  static_assert(!MOZ_IS_DESTRUCTIBLE(X) || \
+                mozilla::HasDangerousPublicDestructor<X>::value, \
+                "Reference-counted class " #X " should not have a public destructor. " \
+                "Try to make this class's destructor non-public. If that is really " \
+                "not possible, you can whitelist this class by providing a " \
+                "HasDangerousPublicDestructor specialization for it."); \
+  static_assert(!mozilla::HasDangerousPublicDestructor<X>::value || \
+                MOZ_IS_DESTRUCTIBLE(X), \
+                "Class " #X " has no public destructor. That's good! So please " \
+                "remove the HasDangerousPublicDestructor specialization for it.");
+#else
+#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
+#endif
+
 inline nsISupports*
 ToSupports(nsISupports* aSupports)
 {
   return aSupports;
 }
 
 inline nsISupports*
 ToCanonicalSupports(nsISupports* aSupports)
@@ -329,16 +401,17 @@ public:
 ///////////////////////////////////////////////////////////////////////////////
 
 /*
  * Implementation of AddRef and Release for non-nsISupports (ie "native")
  * cycle-collected classes that use the purple buffer to avoid leaks.
  */
 
 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                 \
+    MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                \
     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
     NS_ASSERT_OWNINGTHREAD(_class);                                           \
     nsrefcnt count =                                                          \
       mRefCnt.incr(static_cast<void*>(this),                                  \
                    _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
     NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
     return count;
 
@@ -406,88 +479,16 @@ public:
 
 /**
  * Previously used to initialize the reference count, but no longer needed.
  *
  * DEPRECATED.
  */
 #define NS_INIT_ISUPPORTS() ((void)0)
 
-namespace mozilla {
-template<typename T>
-struct HasDangerousPublicDestructor
-{
-  static const bool value = false;
-};
-}
-
-#if defined(__clang__)
-   // bug 1028428 shows that at least in FreeBSD 10.0 with Clang 3.4 and libc++ 3.4,
-   // std::is_destructible is buggy in that it returns false when it should return true
-   // on ipc::SharedMemory. On the other hand, all Clang versions currently in use
-   // seem to handle the fallback just fine.
-#  define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
-#elif defined(__GNUC__)
-   // GCC 4.7 is has buggy std::is_destructible
-#  if MOZ_USING_LIBSTDCXX && MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
-#    define MOZ_HAVE_STD_IS_DESTRUCTIBLE
-   // Some GCC versions have an ICE when using destructors in decltype().
-   // Works for me on GCC 4.8.2 on Fedora 20 x86-64.
-#  elif MOZ_GCC_VERSION_AT_LEAST(4, 8, 2)
-#    define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
-#  endif
-#endif
-
-#ifdef MOZ_HAVE_STD_IS_DESTRUCTIBLE
-#  include <type_traits>
-#  define MOZ_IS_DESTRUCTIBLE(X) (std::is_destructible<X>::value)
-#elif defined MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
-  namespace mozilla {
-    struct IsDestructibleFallbackImpl
-    {
-      template<typename T> static T&& Declval();
-
-      template<typename T, typename = decltype(Declval<T>().~T())>
-      static TrueType Test(int);
-
-      template<typename>
-      static FalseType Test(...);
-
-      template<typename T>
-      struct Selector
-      {
-        typedef decltype(Test<T>(0)) type;
-      };
-    };
-
-    template<typename T>
-    struct IsDestructibleFallback
-      : IsDestructibleFallbackImpl::Selector<T>::type
-    {
-    };
-  }
-#  define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
-#endif
-
-#ifdef MOZ_IS_DESTRUCTIBLE
-#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
-  static_assert(!MOZ_IS_DESTRUCTIBLE(X) || \
-                mozilla::HasDangerousPublicDestructor<X>::value, \
-                "Reference-counted classes should not have a public destructor. " \
-                "Try to make this class's destructor non-public. If that is really " \
-                "not possible, you can whitelist this class by providing a " \
-                "HasDangerousPublicDestructor specialization for it."); \
-  static_assert(!mozilla::HasDangerousPublicDestructor<X>::value || \
-                MOZ_IS_DESTRUCTIBLE(X), \
-                "This class has no public destructor. That's good! So please " \
-                "remove the HasDangerousPublicDestructor specialization for it.");
-#else
-#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
-#endif
-
 /**
  * Use this macro to declare and implement the AddRef & Release methods for a
  * given non-XPCOM <i>_class</i>.
  *
  * @param _class The name of the class implementing the method
  */
 #define NS_INLINE_DECL_REFCOUNTING(_class)                                    \
 public:                                                                       \
@@ -550,16 +551,17 @@ public:
 
 /**
  * Use this macro to implement the AddRef method for a given <i>_class</i>
  * @param _class The name of the class implementing the method
  */
 #define NS_IMPL_ADDREF(_class)                                                \
 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void)                  \
 {                                                                             \
+  MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                  \
   MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                        \
   if (!mRefCnt.isThreadSafe)                                                  \
     NS_ASSERT_OWNINGTHREAD(_class);                                           \
   nsrefcnt count = ++mRefCnt;                                                 \
   NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                         \
   return count;                                                               \
 }
 
@@ -568,16 +570,17 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
  * implemented as a wholly owned aggregated object intended to implement
  * interface(s) for its owner
  * @param _class The name of the class implementing the method
  * @param _aggregator the owning/containing object
  */
 #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator)                  \
 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void)                  \
 {                                                                             \
+  MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                  \
   NS_PRECONDITION(_aggregator, "null aggregator");                            \
   return (_aggregator)->AddRef();                                             \
 }
 
 /**
  * Use this macro to implement the Release method for a given
  * <i>_class</i>.
  * @param _class The name of the class implementing the method
@@ -643,16 +646,17 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
   NS_PRECONDITION(_aggregator, "null aggregator");                            \
   return (_aggregator)->Release();                                            \
 }
 
 
 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class)                               \
 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void)                  \
 {                                                                             \
+  MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                  \
   MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                        \
   NS_ASSERT_OWNINGTHREAD(_class);                                             \
   nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
   nsrefcnt count = mRefCnt.incr(base);                                        \
   NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                         \
   return count;                                                               \
 }