Bug 1329319 - Allow NewRunnableMethod to method of a non-refcounted base class - r?froydnj draft
authorGerald Squelart <gsquelart@mozilla.com>
Tue, 10 Jan 2017 10:49:08 +1100
changeset 457799 aa2cac47036d0d1d7a36c8c0137fe21f21b4961b
parent 457793 4db25092c64d87f34e9691f1e80617c9a0bf3662
child 457800 1ea285ab81ac52ccffc4d765b7f495b76faebf77
push id40901
push usergsquelart@mozilla.com
push dateMon, 09 Jan 2017 23:50:28 +0000
reviewersfroydnj
bugs1329319
milestone53.0a1
Bug 1329319 - Allow NewRunnableMethod to method of a non-refcounted base class - r?froydnj This is done by storing the object pointer based on the exact pointee type, instead of as hinted by the method-pointer, which could be a non-refcounted base class. The stored pointer type is statically-checked to be derived from (or the same as) the class type from the method-pointer, to prevent misuses. One change had to be done in TrackBuffersManager, as it was passing another type and relying on implicit pointer conversions. A simple `.get()` to pass the raw pointer type (to be stored in a RefPtr) fixed that one issue. MozReview-Commit-ID: 4kH0XdjB5Rk
dom/media/mediasource/TrackBuffersManager.cpp
xpcom/glue/nsThreadUtils.h
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -955,17 +955,17 @@ TrackBuffersManager::OnDemuxerInitDone(n
 
   int64_t videoDuration = numVideos ? info.mVideo.mDuration : 0;
   int64_t audioDuration = numAudios ? info.mAudio.mDuration : 0;
 
   int64_t duration = std::max(videoDuration, audioDuration);
   // 1. Update the duration attribute if it currently equals NaN.
   // Those steps are performed by the MediaSourceDecoder::SetInitialDuration
   AbstractThread::MainThread()->Dispatch(NewRunnableMethod<int64_t>
-                                         (mParentDecoder,
+                                         (mParentDecoder.get(),
                                           &MediaSourceDecoder::SetInitialDuration,
                                           duration ? duration : -1));
 
   // 2. If the initialization segment has no audio, video, or text tracks, then
   // run the append error algorithm with the decode error parameter set to true
   // and abort these steps.
   if (!numVideos && !numAudios) {
     RejectAppend(NS_ERROR_FAILURE, __func__);
--- a/xpcom/glue/nsThreadUtils.h
+++ b/xpcom/glue/nsThreadUtils.h
@@ -458,67 +458,80 @@ template<class ClassType>
 struct nsRunnableMethodReceiver<ClassType, false>
 {
   ClassType* MOZ_NON_OWNING_REF mObj;
   explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
   ClassType* Get() const { return mObj; }
   void Revoke() { mObj = nullptr; }
 };
 
-template<typename Method, bool Owning, bool Cancelable> struct nsRunnableMethodTraits;
+template<typename PtrType, typename Method, bool Owning, bool Cancelable>
+struct nsRunnableMethodTraits;
 
-template<class C, typename R, bool Owning, bool Cancelable, typename... As>
-struct nsRunnableMethodTraits<R(C::*)(As...), Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable, typename... As>
+struct nsRunnableMethodTraits<PtrType, R(C::*)(As...), Owning, Cancelable>
 {
-  typedef C class_type;
+  typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
 
-template<class C, typename R, bool Owning, bool Cancelable, typename... As>
-struct nsRunnableMethodTraits<R(C::*)(As...) const, Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable, typename... As>
+struct nsRunnableMethodTraits<PtrType, R(C::*)(As...) const, Owning, Cancelable>
 {
-  typedef const C class_type;
+  typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
 
 #ifdef NS_HAVE_STDCALL
-template<class C, typename R, bool Owning, bool Cancelable, typename... As>
-struct nsRunnableMethodTraits<R(__stdcall C::*)(As...), Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable, typename... As>
+struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...), Owning, Cancelable>
 {
-  typedef C class_type;
+  typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
 
-template<class C, typename R, bool Owning, bool Cancelable>
-struct nsRunnableMethodTraits<R(NS_STDCALL C::*)(), Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable>
+struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)(), Owning, Cancelable>
 {
-  typedef C class_type;
+  typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
-template<class C, typename R, bool Owning, bool Cancelable, typename... As>
-struct nsRunnableMethodTraits<R(__stdcall C::*)(As...) const, Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable, typename... As>
+struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...) const, Owning, Cancelable>
 {
-  typedef const C class_type;
+  typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
 
-template<class C, typename R, bool Owning, bool Cancelable>
-struct nsRunnableMethodTraits<R(NS_STDCALL C::*)() const, Owning, Cancelable>
+template<typename PtrType, class C, typename R, bool Owning, bool Cancelable>
+struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)() const, Owning, Cancelable>
 {
-  typedef const C class_type;
+  typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
+  static_assert(mozilla::IsBaseOf<C, class_type>::value,
+                "Stored class must inherit from method's class");
   typedef R return_type;
   typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
   static const bool can_cancel = Cancelable;
 };
 #endif
 
 
 // IsParameterStorageClass<T>::value is true if T is a parameter-storage class
@@ -815,32 +828,32 @@ struct RunnableMethodArguments final
       -> decltype(applyImpl(o, m, mArguments,
                   typename IndexSequenceFor<Ts...>::Type()))
   {
     return applyImpl(o, m, mArguments,
         typename IndexSequenceFor<Ts...>::Type());
   }
 };
 
-template<typename Method, bool Owning, bool Cancelable, typename... Storages>
+template<typename PtrType, typename Method, bool Owning, bool Cancelable, typename... Storages>
 class RunnableMethodImpl final
-  : public ::nsRunnableMethodTraits<Method, Owning, Cancelable>::base_type
+  : public ::nsRunnableMethodTraits<PtrType, Method, Owning, Cancelable>::base_type
 {
-  typedef typename ::nsRunnableMethodTraits<Method, Owning, Cancelable>::class_type
+  typedef typename ::nsRunnableMethodTraits<PtrType, Method, Owning, Cancelable>::class_type
       ClassType;
   ::nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
   Method mMethod;
   RunnableMethodArguments<Storages...> mArgs;
 private:
   virtual ~RunnableMethodImpl() { Revoke(); };
 public:
-  template<typename... Args>
-  explicit RunnableMethodImpl(ClassType* aObj, Method aMethod,
+  template<typename ForwardedPtrType, typename... Args>
+  explicit RunnableMethodImpl(ForwardedPtrType&& aObj, Method aMethod,
                               Args&&... aArgs)
-    : mReceiver(aObj)
+    : mReceiver(Forward<ForwardedPtrType>(aObj))
     , mMethod(aMethod)
     , mArgs(Forward<Args>(aArgs)...)
   {
     static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
   }
   NS_IMETHOD Run()
   {
     if (MOZ_LIKELY(mReceiver.Get())) {
@@ -865,86 +878,122 @@ public:
 //   NS_DispatchToCurrentThread(event);
 //
 // Statically enforced constraints:
 //  - myObject must be of (or implicitly convertible to) type MyClass
 //  - MyClass must define AddRef and Release methods
 //
 
 template<typename PtrType, typename Method>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, false>::base_type>
-NewRunnableMethod(PtrType aPtr, Method aMethod)
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, true, false>::base_type>
+NewRunnableMethod(PtrType&& aPtr, Method aMethod)
 {
-  return do_AddRef(new detail::RunnableMethodImpl<Method, true, false>(aPtr, aMethod));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, true, false>
+      (Forward<PtrType>(aPtr), aMethod));
 }
 
 template<typename PtrType, typename Method>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, true>::base_type>
-NewCancelableRunnableMethod(PtrType aPtr, Method aMethod)
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, true, true>::base_type>
+NewCancelableRunnableMethod(PtrType&& aPtr, Method aMethod)
 {
-  return do_AddRef(new detail::RunnableMethodImpl<Method, true, true>(aPtr, aMethod));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, true, true>
+      (Forward<PtrType>(aPtr), aMethod));
 }
 
 template<typename PtrType, typename Method>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, false>::base_type>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, false, false>::base_type>
 NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod)
 {
-  return do_AddRef(new detail::RunnableMethodImpl<Method, false, false>(aPtr, aMethod));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, false, false>
+      (Forward<PtrType>(aPtr), aMethod));
 }
 
 template<typename PtrType, typename Method>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, true>::base_type>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, false, true>::base_type>
 NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod)
 {
-  return do_AddRef(new detail::RunnableMethodImpl<Method, false, true>(aPtr, aMethod));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, false, true>
+      (Forward<PtrType>(aPtr), aMethod));
 }
 
 // Similar to NewRunnableMethod. Call like so:
 // nsCOMPtr<nsIRunnable> event =
 //   NewRunnableMethod<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
 // 'Types' are the stored type for each argument, see ParameterStorage for details.
-template<typename... Storages, typename Method, typename PtrType, typename... Args>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, false>::base_type>
+template<typename... Storages, typename PtrType, typename Method, typename... Args>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, true, false>::base_type>
 NewRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
 {
   static_assert(sizeof...(Storages) == sizeof...(Args),
                 "<Storages...> size should be equal to number of arguments");
-  return do_AddRef(new detail::RunnableMethodImpl<Method, true, false, Storages...>(
-      aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, true, false, Storages...>
+      (Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
 }
 
-template<typename... Storages, typename Method, typename PtrType, typename... Args>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, false>::base_type>
+template<typename... Storages, typename PtrType, typename Method, typename... Args>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, false, false>::base_type>
 NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
 {
   static_assert(sizeof...(Storages) == sizeof...(Args),
                 "<Storages...> size should be equal to number of arguments");
-  return do_AddRef(new detail::RunnableMethodImpl<Method, false, false, Storages...>(
-      aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, false, false, Storages...>
+      (Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
 }
 
-template<typename... Storages, typename Method, typename PtrType, typename... Args>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, true>::base_type>
+template<typename... Storages, typename PtrType, typename Method, typename... Args>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, true, true>::base_type>
 NewCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
 {
   static_assert(sizeof...(Storages) == sizeof...(Args),
                 "<Storages...> size should be equal to number of arguments");
-  return do_AddRef(new detail::RunnableMethodImpl<Method, true, true, Storages...>(
-      aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, true, true, Storages...>
+      (Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
 }
 
-template<typename... Storages, typename Method, typename PtrType, typename... Args>
-already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, true>::base_type>
+template<typename... Storages, typename PtrType, typename Method, typename... Args>
+already_AddRefed<
+  typename ::nsRunnableMethodTraits<
+    typename RemoveReference<PtrType>::Type, Method, false, true>::base_type>
 NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod,
                                                 Args&&... aArgs)
 {
   static_assert(sizeof...(Storages) == sizeof...(Args),
                 "<Storages...> size should be equal to number of arguments");
-  return do_AddRef(new detail::RunnableMethodImpl<Method, false, true, Storages...>(
-      aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
+  return do_AddRef(
+    new detail::RunnableMethodImpl
+      <typename RemoveReference<PtrType>::Type, Method, false, true, Storages...>
+      (Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
 }
 
 } // namespace mozilla
 
 #endif  // XPCOM_GLUE_AVOID_NSPR
 
 // This class is designed to be used when you have an event class E that has a
 // pointer back to resource class R.  If R goes away while E is still pending,