Bug 1390568 - manually de-virtualize do_QueryReferent; r=ehsan
authorNathan Froyd <froydnj@mozilla.com>
Thu, 24 Aug 2017 20:04:31 -0400
changeset 428741 20e6ab8c91bcd00d480607715d59b48ed99fe0f9
parent 428740 aa18594d4f60287f20ca6d08670a1b1d98901df8
child 428742 adb2d85aa19a2db3c7dc3a33013e622fdfcd767a
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1390568
milestone57.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 1390568 - manually de-virtualize do_QueryReferent; r=ehsan nsQueryReferent is defined as an nsCOMPtr_helper, which implies that calling its operator() method requires a virtual call. While nsQueryReferent is marked `final`, compiler inlining decisions make it impossible to de-virtualize the call to operator(). However, we have many other classes returned by do_* functions that nsCOMPtr handles directly, requiring no extra virtual calls, and we can give nsQueryReferent the same treatment.
mfbt/RefPtr.h
xpcom/base/nsCOMPtr.cpp
xpcom/base/nsCOMPtr.h
xpcom/base/nsIWeakReferenceUtils.h
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -10,16 +10,17 @@
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 /*****************************************************************************/
 
 // template <class T> class RefPtrGetterAddRefs;
 
+class nsQueryReferent;
 class nsCOMPtr_helper;
 
 namespace mozilla {
 template<class T> class OwningNonNull;
 template<class T> class StaticRefPtr;
 
 // Traditionally, RefPtr supports automatic refcounting of any pointer type
 // with AddRef() and Release() methods that follow the traditional semantics.
@@ -143,16 +144,17 @@ public:
 
   template <typename I>
   MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
     : mRawPtr(aSmartPtr.forget().take())
     // construct from |Move(RefPtr<SomeSubclassOfT>)|.
   {
   }
 
+  MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
   MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
 
   // Defined in OwningNonNull.h
   template<class U>
   MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
 
   // Defined in StaticPtr.h
   template<class U>
@@ -205,16 +207,17 @@ public:
   RefPtr<T>&
   operator=(already_AddRefed<I> && aRhs)
   // assign from |otherRefPtr.forget()|
   {
     assign_assuming_AddRef(aRhs.take());
     return *this;
   }
 
+  RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
   RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
 
   RefPtr<T>&
   operator=(RefPtr<T> && aRefPtr)
   {
     assign_assuming_AddRef(aRefPtr.mRawPtr);
     aRefPtr.mRawPtr = nullptr;
     return *this;
--- a/xpcom/base/nsCOMPtr.cpp
+++ b/xpcom/base/nsCOMPtr.cpp
@@ -105,16 +105,27 @@ nsCOMPtr_base::assign_from_gs_contractid
   void* newRawPtr;
   if (NS_FAILED(aGS(aIID, &newRawPtr))) {
     newRawPtr = nullptr;
   }
   assign_assuming_AddRef(static_cast<nsISupports*>(newRawPtr));
 }
 
 void
+nsCOMPtr_base::assign_from_query_referent(
+    const nsQueryReferent& aQueryReferent, const nsIID& aIID)
+{
+  void* newRawPtr;
+  if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
+    newRawPtr = nullptr;
+  }
+  assign_assuming_AddRef(static_cast<nsISupports*>(newRawPtr));
+}
+
+void
 nsCOMPtr_base::assign_from_helper(const nsCOMPtr_helper& aHelper,
                                   const nsIID& aIID)
 {
   void* newRawPtr;
   if (NS_FAILED(aHelper(aIID, &newRawPtr))) {
     newRawPtr = nullptr;
   }
   assign_assuming_AddRef(static_cast<nsISupports*>(newRawPtr));
--- a/xpcom/base/nsCOMPtr.h
+++ b/xpcom/base/nsCOMPtr.h
@@ -268,16 +268,35 @@ public:
 
   nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
 
 private:
   const char* mContractID;
   nsresult* mErrorPtr;
 };
 
+class nsIWeakReference;
+
+// Weak references
+class MOZ_STACK_CLASS nsQueryReferent final
+{
+public:
+  nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
+    : mWeakPtr(aWeakPtr)
+    , mErrorPtr(aError)
+  {
+  }
+
+  nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
+
+private:
+  nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
+  nsresult*          mErrorPtr;
+};
+
 /**
  * Factors implementation for all template versions of nsCOMPtr.
  *
  * Here's the way people normally do things like this:
  *
  *   template<class T> class Foo { ... };
  *   template<> class Foo<void*> { ... };
  *   template<class T> class Foo<T*> : private Foo<void*> { ... };
@@ -306,16 +325,18 @@ public:
   void NS_FASTCALL
   assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&, const nsIID&);
   void NS_FASTCALL
   assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
   void NS_FASTCALL
   assign_from_gs_contractid_with_error(const nsGetServiceByContractIDWithError&,
                                        const nsIID&);
   void NS_FASTCALL
+  assign_from_query_referent(const nsQueryReferent&, const nsIID&);
+  void NS_FASTCALL
   assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
   void** NS_FASTCALL
   begin_assignment();
 
 protected:
   NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
 
   void assign_assuming_AddRef(nsISupports* aNewPtr)
@@ -361,16 +382,17 @@ private:
   void assign_from_qi(const nsQueryInterface, const nsIID&);
   void assign_from_qi_with_error(const nsQueryInterfaceWithError&, const nsIID&);
   void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
   void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
                                      const nsIID&);
   void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
   void assign_from_gs_contractid_with_error(
     const nsGetServiceByContractIDWithError&, const nsIID&);
+  void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
   void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
   void** begin_assignment();
 
   void assign_assuming_AddRef(T* aNewPtr)
   {
     T* oldPtr = mRawPtr;
     mRawPtr = aNewPtr;
     NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
@@ -559,16 +581,25 @@ public:
   MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
     : NSCAP_CTOR_BASE(nullptr)
   {
     assert_validity();
     NSCAP_LOG_ASSIGNMENT(this, nullptr);
     assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
   }
 
+  // Construct from |do_QueryReferent(ptr)|
+  MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
+    : NSCAP_CTOR_BASE(nullptr)
+  {
+    assert_validity();
+    NSCAP_LOG_ASSIGNMENT(this, nullptr);
+    assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
+  }
+
   // And finally, anything else we might need to construct from can exploit the
   // nsCOMPtr_helper facility.
   MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
     : NSCAP_CTOR_BASE(nullptr)
   {
     assert_validity();
     NSCAP_LOG_ASSIGNMENT(this, nullptr);
     assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
@@ -662,16 +693,23 @@ public:
 
   // Assign from |do_GetService(contractid_expr, &rv)|.
   nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs)
   {
     assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
     return *this;
   }
 
+  // Assign from |do_QueryReferent(ptr)|.
+  nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs)
+  {
+    assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
+    return *this;
+  }
+
   // And finally, anything else we might need to assign from can exploit the
   // nsCOMPtr_helper facility.
   nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs)
   {
     assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
     NSCAP_ASSERT_NO_QUERY_NEEDED();
     return *this;
   }
@@ -893,16 +931,24 @@ public:
   // Construct from |do_GetService(contractid_expr, &rv)|.
   MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
     : nsCOMPtr_base(nullptr)
   {
     NSCAP_LOG_ASSIGNMENT(this, nullptr);
     assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
   }
 
+  // Construct from |do_QueryReferent(ptr)|
+  MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
+    : nsCOMPtr_base(nullptr)
+  {
+    NSCAP_LOG_ASSIGNMENT(this, nullptr);
+    assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(nsISupports));
+  }
+
   // And finally, anything else we might need to construct from can exploit
   // the |nsCOMPtr_helper| facility
   MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
     : nsCOMPtr_base(nullptr)
   {
     NSCAP_LOG_ASSIGNMENT(this, nullptr);
     assign_from_helper(aHelper, NS_GET_IID(nsISupports));
   }
@@ -979,16 +1025,23 @@ public:
 
   // Assign from |do_GetService(contractid_expr, &rv)|.
   nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractIDWithError& aRhs)
   {
     assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
     return *this;
   }
 
+  // Assign from |do_QueryReferent(ptr)|.
+  nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs)
+  {
+    assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
+    return *this;
+  }
+
   // And finally, anything else we might need to assign from can exploit the
   // nsCOMPtr_helper facility
   nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs)
   {
     assign_from_helper(aRhs, NS_GET_IID(nsISupports));
     return *this;
   }
 
@@ -1174,16 +1227,28 @@ nsCOMPtr<T>::assign_from_gs_contractid_w
   if (NS_FAILED(aGS(aIID, &newRawPtr))) {
     newRawPtr = nullptr;
   }
   assign_assuming_AddRef(static_cast<T*>(newRawPtr));
 }
 
 template<class T>
 void
+nsCOMPtr<T>::assign_from_query_referent(
+    const nsQueryReferent& aQueryReferent, const nsIID& aIID)
+{
+  void* newRawPtr;
+  if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
+    newRawPtr = nullptr;
+  }
+  assign_assuming_AddRef(static_cast<T*>(newRawPtr));
+}
+
+template<class T>
+void
 nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper, const nsIID& aIID)
 {
   void* newRawPtr;
   if (NS_FAILED(helper(aIID, &newRawPtr))) {
     newRawPtr = nullptr;
   }
   assign_assuming_AddRef(static_cast<T*>(newRawPtr));
 }
@@ -1436,27 +1501,49 @@ SameCOMIdentity(nsISupports* aLhs, nsISu
 template<class SourceType, class DestinationType>
 inline nsresult
 CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr, DestinationType** aDestPtr)
 {
   return CallQueryInterface(aSourcePtr.get(), aDestPtr);
 }
 
 template <class T>
+RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent)
+{
+  void* newRawPtr;
+  if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
+    newRawPtr = nullptr;
+  }
+  mRawPtr = static_cast<T*>(newRawPtr);
+}
+
+template <class T>
 RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper)
 {
   void* newRawPtr;
   if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
     newRawPtr = nullptr;
   }
   mRawPtr = static_cast<T*>(newRawPtr);
 }
 
 template <class T>
 RefPtr<T>&
+RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent)
+{
+  void* newRawPtr;
+  if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
+    newRawPtr = nullptr;
+  }
+  assign_assuming_AddRef(static_cast<T*>(newRawPtr));
+  return *this;
+}
+
+template <class T>
+RefPtr<T>&
 RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper)
 {
   void* newRawPtr;
   if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
     newRawPtr = nullptr;
   }
   assign_assuming_AddRef(static_cast<T*>(newRawPtr));
   return *this;
--- a/xpcom/base/nsIWeakReferenceUtils.h
+++ b/xpcom/base/nsIWeakReferenceUtils.h
@@ -25,33 +25,16 @@ CallQueryReferent(T* aSource, Destinatio
   NS_PRECONDITION(aSource, "null parameter");
   NS_PRECONDITION(aDestination, "null parameter");
 
   return aSource->QueryReferent(NS_GET_TEMPLATE_IID(DestinationType),
                                 reinterpret_cast<void**>(aDestination));
 }
 
 
-class MOZ_STACK_CLASS nsQueryReferent final : public nsCOMPtr_helper
-{
-public:
-  nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
-    : mWeakPtr(aWeakPtr)
-    , mErrorPtr(aError)
-  {
-  }
-
-  virtual nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const
-    override;
-
-private:
-  nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
-  nsresult*          mErrorPtr;
-};
-
 inline const nsQueryReferent
 do_QueryReferent(nsIWeakReference* aRawPtr, nsresult* aError = 0)
 {
   return nsQueryReferent(aRawPtr, aError);
 }
 
 
 /**