Bug 1247972 - specialize NS_ProxyRelease for nsISupports to be out-of-line; r=erahm
authorAidin Gharibnavaz <aidin@aidinhut.com>
Wed, 29 Jun 2016 18:56:41 -0400
changeset 345263 a5a8beff2575044d0d8beb0e283d7f27bce13b67
parent 345262 b7188125e7317d13c22c3973478d57b866c1662d
child 345264 1cee0d296a34a96468ed6b1f2a6947616d04be26
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1247972
milestone50.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 1247972 - specialize NS_ProxyRelease for nsISupports to be out-of-line; r=erahm NS_ProxyRelease's current implementation requires a lot of code. We can reduce the impact of this by providing an out-of-line implementation for classes based on nsISupports. This change reduces codesize by ~60K on a Linux x86-64 build.
image/RasterImage.h
netwerk/protocol/websocket/WebSocketEventService.h
netwerk/protocol/wyciwyg/nsWyciwygChannel.h
storage/mozStorageConnection.h
xpcom/glue/nsProxyRelease.cpp
xpcom/glue/nsProxyRelease.h
xpcom/glue/objs.mozbuild
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -453,9 +453,18 @@ protected:
 inline NS_IMETHODIMP
 RasterImage::GetAnimationMode(uint16_t* aAnimationMode) {
   return GetAnimationModeInternal(aAnimationMode);
 }
 
 } // namespace image
 } // namespace mozilla
 
+/**
+ * Casting RasterImage to nsISupports is ambiguous. This method handles that.
+ */
+inline nsISupports*
+ToSupports(mozilla::image::RasterImage* p)
+{
+  return NS_ISUPPORTS_CAST(mozilla::image::ImageResource*, p);
+}
+
 #endif /* mozilla_image_RasterImage_h */
--- a/netwerk/protocol/websocket/WebSocketEventService.h
+++ b/netwerk/protocol/websocket/WebSocketEventService.h
@@ -106,9 +106,19 @@ private:
   nsClassHashtable<nsUint64HashKey, WindowListener> mWindows;
 
   Atomic<uint64_t> mCountListeners;
 };
 
 } // net namespace
 } // mozilla namespace
 
+/**
+ * Casting WebSocketEventService to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports*
+ToSupports(mozilla::net::WebSocketEventService* p)
+{
+  return NS_ISUPPORTS_CAST(nsIWebSocketEventService*, p);
+}
+
 #endif // mozilla_net_WebSocketEventService_h
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -105,9 +105,19 @@ protected:
     nsCOMPtr<nsICacheEntry>             mCacheEntry;
     nsCOMPtr<nsIOutputStream>           mCacheOutputStream;
     nsCOMPtr<nsIInputStream>            mCacheInputStream;
     nsCOMPtr<nsIEventTarget>            mCacheIOTarget;
 
     nsCOMPtr<nsISupports>               mSecurityInfo;
 };
 
+/**
+ * Casting nsWyciwygChannel to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports*
+ToSupports(nsWyciwygChannel* p)
+{
+  return NS_ISUPPORTS_CAST(nsIStreamListener*, p);
+}
+
 #endif /* nsWyciwygChannel_h___ */
--- a/storage/mozStorageConnection.h
+++ b/storage/mozStorageConnection.h
@@ -408,9 +408,19 @@ private:
   // nsCOMP<T> would cause an off-main thread QI, which
   // is not a good idea (and crashes XPConnect).
   RefPtr<mozIStorageCompletionCallback> mCallback;
 };
 
 } // namespace storage
 } // namespace mozilla
 
+/**
+ * Casting Connection to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports*
+ToSupports(mozilla::storage::Connection* p)
+{
+  return NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, p);
+}
+
 #endif // mozilla_storage_Connection_h
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsProxyRelease.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsProxyRelease.h"
+#include "nsThreadUtils.h"
+
+namespace detail {
+
+/* static */ void
+ProxyReleaseChooser<true>::ProxyReleaseISupports(nsIEventTarget* aTarget,
+                                                 nsISupports* aDoomed,
+                                                 bool aAlwaysProxy)
+{
+  ::detail::ProxyRelease<nsISupports>(aTarget, dont_AddRef(aDoomed),
+                                      aAlwaysProxy);
+}
+
+} // namespace detail
--- a/xpcom/glue/nsProxyRelease.h
+++ b/xpcom/glue/nsProxyRelease.h
@@ -10,39 +10,103 @@
 #include "nsIEventTarget.h"
 #include "nsIThread.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "MainThreadUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Move.h"
+#include "mozilla/TypeTraits.h"
 
 #ifdef XPCOM_GLUE_AVOID_NSPR
 #error NS_ProxyRelease implementation depends on NSPR.
 #endif
 
+namespace detail {
 
-template<class T>
-class nsProxyReleaseEvent : public mozilla::Runnable
+template<typename T>
+class ProxyReleaseEvent : public mozilla::Runnable
 {
 public:
-  explicit nsProxyReleaseEvent(already_AddRefed<T> aDoomed)
+  explicit ProxyReleaseEvent(already_AddRefed<T> aDoomed)
   : mDoomed(aDoomed.take()) {}
 
   NS_IMETHOD Run()
   {
     NS_IF_RELEASE(mDoomed);
     return NS_OK;
   }
 
 private:
   T* MOZ_OWNING_REF mDoomed;
 };
 
+template<typename T>
+void
+ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed, bool aAlwaysProxy)
+{
+  // Auto-managing release of the pointer.
+  RefPtr<T> doomed = aDoomed;
+  nsresult rv;
+
+  if (!doomed || !aTarget) {
+    return;
+  }
+
+  if (!aAlwaysProxy) {
+    bool onCurrentThread = false;
+    rv = aTarget->IsOnCurrentThread(&onCurrentThread);
+    if (NS_SUCCEEDED(rv) && onCurrentThread) {
+      return;
+    }
+  }
+
+  nsCOMPtr<nsIRunnable> ev = new ProxyReleaseEvent<T>(doomed.forget());
+
+  rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to post proxy release event, leaking!");
+    // It is better to leak the aDoomed object than risk crashing as
+    // a result of deleting it on the wrong thread.
+  }
+}
+
+template<bool nsISupportsBased>
+struct ProxyReleaseChooser
+{
+  template<typename T>
+  static void ProxyRelease(nsIEventTarget* aTarget,
+                           already_AddRefed<T> aDoomed,
+                           bool aAlwaysProxy)
+  {
+    ::detail::ProxyRelease(aTarget, mozilla::Move(aDoomed), aAlwaysProxy);
+  }
+};
+
+template<>
+struct ProxyReleaseChooser<true>
+{
+  // We need an intermediate step for handling classes with ambiguous
+  // inheritance to nsISupports.
+  template<typename T>
+  static void ProxyRelease(nsIEventTarget* aTarget,
+                           already_AddRefed<T> aDoomed,
+                           bool aAlwaysProxy)
+  {
+    ProxyReleaseISupports(aTarget, ToSupports(aDoomed.take()), aAlwaysProxy);
+  }
+
+  static void ProxyReleaseISupports(nsIEventTarget* aTarget,
+                                    nsISupports* aDoomed,
+                                    bool aAlwaysProxy);
+};
+
+} // namespace detail
+
 /**
  * Ensures that the delete of a smart pointer occurs on the target thread.
  *
  * @param aTarget
  *        the target thread where the doomed object should be released.
  * @param aDoomed
  *        the doomed object; the object to be released on the target thread.
  * @param aAlwaysProxy
@@ -51,40 +115,18 @@ private:
  *        true, then an event will always be posted to the target thread for
  *        asynchronous release.
  */
 template<class T>
 inline NS_HIDDEN_(void)
 NS_ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed,
                 bool aAlwaysProxy = false)
 {
-  // Auto-managing release of the pointer.
-  RefPtr<T> doomed = aDoomed;
-  nsresult rv;
-
-  if (!doomed || !aTarget) {
-    return;
-  }
-
-  if (!aAlwaysProxy) {
-    bool onCurrentThread = false;
-    rv = aTarget->IsOnCurrentThread(&onCurrentThread);
-    if (NS_SUCCEEDED(rv) && onCurrentThread) {
-      return;
-    }
-  }
-
-  nsCOMPtr<nsIRunnable> ev = new nsProxyReleaseEvent<T>(doomed.forget());
-
-  rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("failed to post proxy release event, leaking!");
-    // It is better to leak the aDoomed object than risk crashing as
-    // a result of deleting it on the wrong thread.
-  }
+  ::detail::ProxyReleaseChooser<mozilla::IsBaseOf<nsISupports, T>::value>
+    ::ProxyRelease(aTarget, mozilla::Move(aDoomed), aAlwaysProxy);
 }
 
 /**
  * Ensures that the delete of a smart pointer occurs on the main thread.
  *
  * @param aDoomed
  *        the doomed object; the object to be released on the main thread.
  * @param aAlwaysProxy
--- a/xpcom/glue/objs.mozbuild
+++ b/xpcom/glue/objs.mozbuild
@@ -34,14 +34,15 @@ xpcom_glue_src_lcppsrcs = [
 
 xpcom_glue_src_cppsrcs = [
     '/xpcom/glue/%s' % s for s in xpcom_glue_src_lcppsrcs
 ]
 
 xpcom_gluens_src_lcppsrcs = [
     'BlockingResourceBase.cpp',
     'GenericFactory.cpp',
+    'nsProxyRelease.cpp',
     'nsTextFormatter.cpp',
 ]
 
 xpcom_gluens_src_cppsrcs = [
     '/xpcom/glue/%s' % s for s in xpcom_gluens_src_lcppsrcs
 ]