Bug 1547218 - Part 2: Stop special casing pointer types in ParamTraits specialization, r=froydnj
authorNika Layzell <nika@thelayzells.com>
Tue, 21 May 2019 17:04:39 +0000
changeset 474788 a50b68e0deb2cd736a83d3bd3d40ca18675f908e
parent 474787 15b4b7f9d97a77a19b94d64e257bbb6c28cfa134
child 474789 ba0de671a6c4ef10b211d2a684b29f0ebdc3eadb
push id36046
push useraiakab@mozilla.com
push dateTue, 21 May 2019 21:45:52 +0000
treeherdermozilla-central@257f2c96cef5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1547218
milestone69.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 1547218 - Part 2: Stop special casing pointer types in ParamTraits specialization, r=froydnj Differential Revision: https://phabricator.services.mozilla.com/D29779
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
dom/file/ipc/IPCBlobUtils.cpp
dom/file/ipc/IPCBlobUtils.h
dom/geolocation/nsGeoPositionIPCSerialiser.h
dom/ipc/CSPMessageUtils.cpp
dom/ipc/CSPMessageUtils.h
dom/ipc/DocShellMessageUtils.cpp
dom/ipc/DocShellMessageUtils.h
dom/ipc/PermissionMessageUtils.cpp
dom/ipc/PermissionMessageUtils.h
dom/ipc/ReferrerInfoUtils.cpp
dom/ipc/ReferrerInfoUtils.h
dom/plugins/ipc/PluginMessageUtils.h
ipc/chromium/src/chrome/common/ipc_message_utils.h
ipc/glue/IPCStreamUtils.cpp
ipc/glue/IPCStreamUtils.h
ipc/glue/IPDLParamTraits.h
ipc/glue/URIUtils.h
ipc/ipdl/ipdl/lower.py
toolkit/components/alerts/AlertNotificationIPCSerializer.h
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -884,30 +884,30 @@ void BrowsingContext::DidSetIsActivatedB
       mIsActivatedByUserGesture, XRE_IsParentProcess() ? "Parent" : "Child",
       Id());
 }
 
 }  // namespace dom
 
 namespace ipc {
 
-void IPDLParamTraits<dom::BrowsingContext>::Write(
+void IPDLParamTraits<dom::BrowsingContext*>::Write(
     IPC::Message* aMsg, IProtocol* aActor, dom::BrowsingContext* aParam) {
   uint64_t id = aParam ? aParam->Id() : 0;
   WriteIPDLParam(aMsg, aActor, id);
 
   // If his is an in-process send. We want to make sure that our BrowsingContext
   // object lives long enough to make it to the other side, so we take an extra
   // reference. This reference is freed in ::Read().
   if (!aActor->GetIPCChannel()->IsCrossProcess()) {
     NS_IF_ADDREF(aParam);
   }
 }
 
-bool IPDLParamTraits<dom::BrowsingContext>::Read(
+bool IPDLParamTraits<dom::BrowsingContext*>::Read(
     const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
     RefPtr<dom::BrowsingContext>* aResult) {
   uint64_t id = 0;
   if (!ReadIPDLParam(aMsg, aIter, aActor, &id)) {
     return false;
   }
 
   if (id == 0) {
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -476,17 +476,17 @@ typedef BrowsingContext::FieldEpochs Bro
 typedef BrowsingContext::IPCInitializer BrowsingContextInitializer;
 typedef BrowsingContext::Children BrowsingContextChildren;
 
 }  // namespace dom
 
 // Allow sending BrowsingContext objects over IPC.
 namespace ipc {
 template <>
-struct IPDLParamTraits<dom::BrowsingContext> {
+struct IPDLParamTraits<dom::BrowsingContext*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     dom::BrowsingContext* aParam);
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<dom::BrowsingContext>* aResult);
 };
 
 template <>
 struct IPDLParamTraits<dom::BrowsingContext::Transaction> {
--- a/dom/file/ipc/IPCBlobUtils.cpp
+++ b/dom/file/ipc/IPCBlobUtils.cpp
@@ -282,32 +282,32 @@ nsresult SerializeUntyped(BlobImpl* aBlo
       MOZ_CRASH("Unsupported protocol passed to BlobImpl serialize");
   }
 }
 
 }  // namespace IPCBlobUtils
 }  // namespace dom
 
 namespace ipc {
-void IPDLParamTraits<mozilla::dom::BlobImpl>::Write(
+void IPDLParamTraits<mozilla::dom::BlobImpl*>::Write(
     IPC::Message* aMsg, IProtocol* aActor, mozilla::dom::BlobImpl* aParam) {
   nsresult rv;
   mozilla::dom::IPCBlob ipcblob;
   if (aParam) {
     rv = mozilla::dom::IPCBlobUtils::SerializeUntyped(aParam, aActor, ipcblob);
   }
   if (!aParam || NS_WARN_IF(NS_FAILED(rv))) {
     WriteIPDLParam(aMsg, aActor, false);
   } else {
     WriteIPDLParam(aMsg, aActor, true);
     WriteIPDLParam(aMsg, aActor, ipcblob);
   }
 }
 
-bool IPDLParamTraits<mozilla::dom::BlobImpl>::Read(
+bool IPDLParamTraits<mozilla::dom::BlobImpl*>::Read(
     const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
     RefPtr<mozilla::dom::BlobImpl>* aResult) {
   *aResult = nullptr;
 
   bool notnull = false;
   if (!ReadIPDLParam(aMsg, aIter, aActor, &notnull)) {
     return false;
   }
--- a/dom/file/ipc/IPCBlobUtils.h
+++ b/dom/file/ipc/IPCBlobUtils.h
@@ -253,17 +253,17 @@ nsresult SerializeUntyped(BlobImpl* aBlo
 }  // namespace dom
 
 namespace ipc {
 // ParamTraits implementation for BlobImpl. N.B: If the original BlobImpl cannot
 // be successfully serialized, a warning will be produced and a nullptr will be
 // sent over the wire. When Read()-ing a BlobImpl,
 // __always make sure to handle null!__
 template <>
-struct IPDLParamTraits<mozilla::dom::BlobImpl> {
+struct IPDLParamTraits<mozilla::dom::BlobImpl*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     mozilla::dom::BlobImpl* aParam);
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<mozilla::dom::BlobImpl>* aResult);
 };
 }  // namespace ipc
 }  // namespace mozilla
 
--- a/dom/geolocation/nsGeoPositionIPCSerialiser.h
+++ b/dom/geolocation/nsGeoPositionIPCSerialiser.h
@@ -9,17 +9,17 @@
 
 #include "ipc/IPCMessageUtils.h"
 #include "nsGeoPosition.h"
 #include "nsIDOMGeoPosition.h"
 
 namespace IPC {
 
 template <>
-struct ParamTraits<nsIDOMGeoPositionCoords> {
+struct ParamTraits<nsIDOMGeoPositionCoords*> {
   // Function to serialize a geoposition
   static void Write(Message* aMsg, nsIDOMGeoPositionCoords* aParam) {
     bool isNull = !aParam;
     WriteParam(aMsg, isNull);
     // If it is a null object, then we are done
     if (isNull) return;
 
     double coordData;
@@ -84,17 +84,17 @@ struct ParamTraits<nsIDOMGeoPositionCoor
                                        heading,          /* aHeading */
                                        speed             /* aSpeed   */
     );
     return true;
   }
 };
 
 template <>
-struct ParamTraits<nsIDOMGeoPosition> {
+struct ParamTraits<nsIDOMGeoPosition*> {
   // Function to serialize a geoposition
   static void Write(Message* aMsg, nsIDOMGeoPosition* aParam) {
     bool isNull = !aParam;
     WriteParam(aMsg, isNull);
     // If it is a null object, then we are done
     if (isNull) return;
 
     DOMTimeStamp timeStamp;
--- a/dom/ipc/CSPMessageUtils.cpp
+++ b/dom/ipc/CSPMessageUtils.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/CSPMessageUtils.h"
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
 
 namespace IPC {
 
-void ParamTraits<nsIContentSecurityPolicy>::Write(
+void ParamTraits<nsIContentSecurityPolicy*>::Write(
     Message* aMsg, nsIContentSecurityPolicy* aParam) {
   bool isNull = !aParam;
   WriteParam(aMsg, isNull);
   if (isNull) {
     return;
   }
 
   nsCString cspString;
@@ -23,17 +23,17 @@ void ParamTraits<nsIContentSecurityPolic
   if (NS_FAILED(rv)) {
     MOZ_CRASH("Unable to serialize csp.");
     return;
   }
 
   WriteParam(aMsg, cspString);
 }
 
-bool ParamTraits<nsIContentSecurityPolicy>::Read(
+bool ParamTraits<nsIContentSecurityPolicy*>::Read(
     const Message* aMsg, PickleIterator* aIter,
     RefPtr<nsIContentSecurityPolicy>* aResult) {
   bool isNull;
   if (!ReadParam(aMsg, aIter, &isNull)) {
     return false;
   }
 
   if (isNull) {
--- a/dom/ipc/CSPMessageUtils.h
+++ b/dom/ipc/CSPMessageUtils.h
@@ -9,17 +9,17 @@
 
 #include "ipc/IPCMessageUtils.h"
 #include "nsCOMPtr.h"
 #include "nsIContentSecurityPolicy.h"
 
 namespace IPC {
 
 template <>
-struct ParamTraits<nsIContentSecurityPolicy> {
+struct ParamTraits<nsIContentSecurityPolicy*> {
   static void Write(Message* aMsg, nsIContentSecurityPolicy* aParam);
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    RefPtr<nsIContentSecurityPolicy>* aResult);
 };
 
 }  // namespace IPC
 
 #endif  // mozilla_dom_csp_message_utils_h__
--- a/dom/ipc/DocShellMessageUtils.cpp
+++ b/dom/ipc/DocShellMessageUtils.cpp
@@ -6,24 +6,24 @@
 
 #include "mozilla/dom/DocShellMessageUtils.h"
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
 
 namespace mozilla {
 namespace ipc {
 
-void IPDLParamTraits<nsDocShellLoadState>::Write(IPC::Message* aMsg,
-                                                 IProtocol* aActor,
-                                                 nsDocShellLoadState* aParam) {
+void IPDLParamTraits<nsDocShellLoadState*>::Write(IPC::Message* aMsg,
+                                                  IProtocol* aActor,
+                                                  nsDocShellLoadState* aParam) {
   MOZ_RELEASE_ASSERT(aParam);
   WriteIPDLParam(aMsg, aActor, aParam->Serialize());
 }
 
-bool IPDLParamTraits<nsDocShellLoadState>::Read(
+bool IPDLParamTraits<nsDocShellLoadState*>::Read(
     const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
     RefPtr<nsDocShellLoadState>* aResult) {
   DocShellLoadStateInit loadState;
   if (!ReadIPDLParam(aMsg, aIter, aActor, &loadState)) {
     return false;
   }
 
   // Assert if we somehow don't have a URI in our IPDL type, because we can't
--- a/dom/ipc/DocShellMessageUtils.h
+++ b/dom/ipc/DocShellMessageUtils.h
@@ -10,17 +10,17 @@
 #include "ipc/IPCMessageUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDocShellLoadState.h"
 
 namespace mozilla {
 namespace ipc {
 
 template <>
-struct IPDLParamTraits<nsDocShellLoadState> {
+struct IPDLParamTraits<nsDocShellLoadState*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     nsDocShellLoadState* aParam);
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<nsDocShellLoadState>* aResult);
 };
 
 }  // namespace ipc
 }  // namespace mozilla
--- a/dom/ipc/PermissionMessageUtils.cpp
+++ b/dom/ipc/PermissionMessageUtils.cpp
@@ -6,34 +6,35 @@
 
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 
 namespace mozilla {
 namespace ipc {
 
-void IPDLParamTraits<nsIPrincipal>::Write(IPC::Message* aMsg, IProtocol* aActor,
-                                          nsIPrincipal* aParam) {
+void IPDLParamTraits<nsIPrincipal*>::Write(IPC::Message* aMsg,
+                                           IProtocol* aActor,
+                                           nsIPrincipal* aParam) {
   MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
 
   Maybe<PrincipalInfo> info;
   if (aParam) {
     info.emplace();
     nsresult rv = PrincipalToPrincipalInfo(aParam, info.ptr());
     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   }
 
   WriteIPDLParam(aMsg, aActor, info);
 }
 
-bool IPDLParamTraits<nsIPrincipal>::Read(const IPC::Message* aMsg,
-                                         PickleIterator* aIter,
-                                         IProtocol* aActor,
-                                         RefPtr<nsIPrincipal>* aResult) {
+bool IPDLParamTraits<nsIPrincipal*>::Read(const IPC::Message* aMsg,
+                                          PickleIterator* aIter,
+                                          IProtocol* aActor,
+                                          RefPtr<nsIPrincipal>* aResult) {
   Maybe<PrincipalInfo> info;
   if (!ReadIPDLParam(aMsg, aIter, aActor, &info)) {
     return false;
   }
 
   nsresult rv = NS_OK;
   *aResult = info ? PrincipalInfoToPrincipal(info.ref(), &rv) : nullptr;
   return NS_SUCCEEDED(rv);
--- a/dom/ipc/PermissionMessageUtils.h
+++ b/dom/ipc/PermissionMessageUtils.h
@@ -37,17 +37,17 @@ class Principal {
 };
 
 }  // namespace IPC
 
 namespace mozilla {
 namespace ipc {
 
 template <>
-struct IPDLParamTraits<nsIPrincipal> {
+struct IPDLParamTraits<nsIPrincipal*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     nsIPrincipal* aParam);
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<nsIPrincipal>* aResult);
 
   // Overload to support deserializing nsCOMPtr<nsIPrincipal> directly.
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, nsCOMPtr<nsIPrincipal>* aResult) {
--- a/dom/ipc/ReferrerInfoUtils.cpp
+++ b/dom/ipc/ReferrerInfoUtils.cpp
@@ -5,35 +5,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ReferrerInfoUtils.h"
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
 
 namespace IPC {
 
-void ParamTraits<nsIReferrerInfo>::Write(Message* aMsg,
-                                         nsIReferrerInfo* aParam) {
+void ParamTraits<nsIReferrerInfo*>::Write(Message* aMsg,
+                                          nsIReferrerInfo* aParam) {
   bool isNull = !aParam;
   WriteParam(aMsg, isNull);
   if (isNull) {
     return;
   }
   nsAutoCString infoString;
   nsresult rv = NS_SerializeToString(aParam, infoString);
   if (NS_FAILED(rv)) {
     MOZ_CRASH("Unable to serialize referrer info.");
     return;
   }
   WriteParam(aMsg, infoString);
 }
 
-bool ParamTraits<nsIReferrerInfo>::Read(const Message* aMsg,
-                                        PickleIterator* aIter,
-                                        RefPtr<nsIReferrerInfo>* aResult) {
+bool ParamTraits<nsIReferrerInfo*>::Read(const Message* aMsg,
+                                         PickleIterator* aIter,
+                                         RefPtr<nsIReferrerInfo>* aResult) {
   bool isNull;
   if (!ReadParam(aMsg, aIter, &isNull)) {
     return false;
   }
   if (isNull) {
     *aResult = nullptr;
     return true;
   }
--- a/dom/ipc/ReferrerInfoUtils.h
+++ b/dom/ipc/ReferrerInfoUtils.h
@@ -9,17 +9,17 @@
 
 #include "ipc/IPCMessageUtils.h"
 #include "nsCOMPtr.h"
 #include "nsIReferrerInfo.h"
 
 namespace IPC {
 
 template <>
-struct ParamTraits<nsIReferrerInfo> {
+struct ParamTraits<nsIReferrerInfo*> {
   static void Write(Message* aMsg, nsIReferrerInfo* aParam);
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    RefPtr<nsIReferrerInfo>* aResult);
 };
 
 }  // namespace IPC
 
 #endif  // mozilla_dom_referrer_info_utils_h__
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -379,17 +379,17 @@ struct ParamTraits<mozilla::plugins::NPR
     aLog->append(StringPrintf(L"[%u, %d, %d, %u, %u, %d",
                               (unsigned long)aParam.window, aParam.x, aParam.y,
                               aParam.width, aParam.height, (long)aParam.type));
   }
 };
 
 #ifdef XP_MACOSX
 template <>
-struct ParamTraits<NPNSString> {
+struct ParamTraits<NPNSString*> {
   // Empty string writes a length of 0 and no buffer.
   // We don't write a nullptr terminating character in buffers.
   static void Write(Message* aMsg, NPNSString* aParam) {
     CFStringRef cfString = (CFStringRef)aParam;
 
     // Write true if we have a string, false represents nullptr.
     aMsg->WriteBool(!!cfString);
     if (!cfString) {
--- a/ipc/chromium/src/chrome/common/ipc_message_utils.h
+++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h
@@ -105,58 +105,30 @@ class MessageIterator {
 // The scheme we follow below names the various classes according to the types
 // in them, and the number of ParamTraits levels is larger, but otherwise it's
 // exactly the above idea.
 //
 
 template <class P>
 struct ParamTraits;
 
-// When WriteParam or ReadParam is passed a pointer type like RefPtr<T> or T*,
-// we want to invoke Write() on ParamTraits<T>, as the intype is often T*, while
-// the ReadParam type may be RefPtr<T>.
-namespace detail {
-template <typename T>
-struct StripPointers {
-  typedef T Type;
-};
-template <typename T>
-struct StripPointers<T*> {
-  typedef T Type;
-};
-template <typename T>
-struct StripPointers<RefPtr<T>> {
-  typedef T Type;
-};
-template <typename T>
-struct StripPointers<nsCOMPtr<T>> {
-  typedef T Type;
-};
-}  // namespace detail
-
-// NOTE: This helper is also used in IPDLParamTraits.h
-template <typename T>
-struct ParamTraitsSelector
-    : public detail::StripPointers<typename mozilla::Decay<T>::Type> {};
-
 template <typename P>
 static inline void WriteParam(Message* m, P&& p) {
-  ParamTraits<typename ParamTraitsSelector<P>::Type>::Write(m,
-                                                            std::forward<P>(p));
+  ParamTraits<typename mozilla::Decay<P>::Type>::Write(m, std::forward<P>(p));
 }
 
 template <typename P>
 static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m,
                                                 PickleIterator* iter, P* p) {
-  return ParamTraits<typename ParamTraitsSelector<P>::Type>::Read(m, iter, p);
+  return ParamTraits<P>::Read(m, iter, p);
 }
 
 template <typename P>
 static inline void LogParam(const P& p, std::wstring* l) {
-  ParamTraits<typename ParamTraitsSelector<P>::Type>::Log(p, l);
+  ParamTraits<P>::Log(p, l);
 }
 
 // Fundamental types.
 
 template <class P>
 struct ParamTraitsFundamental {};
 
 template <>
@@ -369,37 +341,33 @@ struct ParamTraitsStd<std::map<K, V>> {
 };
 
 // Windows-specific types.
 
 template <class P>
 struct ParamTraitsWindows : ParamTraitsStd<P> {};
 
 #if defined(OS_WIN)
-// NOTE: HANDLE is a pointer, which we need to strip off, otherwise we won't
-// find this specialization.
 template <>
-struct ParamTraitsWindows<detail::StripPointers<HANDLE>::Type> {
+struct ParamTraitsWindows<HANDLE> {
   static_assert(sizeof(HANDLE) == sizeof(intptr_t), "Wrong size for HANDLE?");
 
   static void Write(Message* m, HANDLE p) {
     m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
   }
   static bool Read(const Message* m, PickleIterator* iter, HANDLE* r) {
     return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
   }
   static void Log(const HANDLE& p, std::wstring* l) {
     l->append(StringPrintf(L"0x%X", p));
   }
 };
 
-// NOTE: HWND is a pointer, which we need to strip off, otherwise we won't find
-// this specialization.
 template <>
-struct ParamTraitsWindows<detail::StripPointers<HWND>::Type> {
+struct ParamTraitsWindows<HWND> {
   static_assert(sizeof(HWND) == sizeof(intptr_t), "Wrong size for HWND?");
 
   static void Write(Message* m, HWND p) {
     m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
   }
   static bool Read(const Message* m, PickleIterator* iter, HWND* r) {
     return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
   }
@@ -479,16 +447,45 @@ struct ParamTraitsMozilla<nsresult> {
   static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
     return m->ReadUInt32(iter, reinterpret_cast<uint32_t*>(r));
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"%u", static_cast<uint32_t>(p)));
   }
 };
 
+// See comments for the IPDLParamTraits specializations for RefPtr<T> and
+// nsCOMPtr<T> for more details.
+template <class T>
+struct ParamTraitsMozilla<RefPtr<T>> {
+  static void Write(Message* m, const RefPtr<T>& p) {
+    ParamTraits<T*>::Write(m, p.get());
+  }
+
+  static bool Read(const Message* m, PickleIterator* iter, RefPtr<T>* r) {
+    return ParamTraits<T*>::Read(m, iter, r);
+  }
+};
+
+template <class T>
+struct ParamTraitsMozilla<nsCOMPtr<T>> {
+  static void Write(Message* m, const nsCOMPtr<T>& p) {
+    ParamTraits<T*>::Write(m, p.get());
+  }
+
+  static bool Read(const Message* m, PickleIterator* iter, nsCOMPtr<T>* r) {
+    RefPtr<T> refptr;
+    if (!ParamTraits<T*>::Read(m, iter, &refptr)) {
+      return false;
+    }
+    *r = refptr.forget();
+    return true;
+  }
+};
+
 // Finally, ParamTraits itself.
 
 template <class P>
 struct ParamTraits : ParamTraitsMozilla<P> {};
 
 }  // namespace IPC
 
 #endif  // CHROME_COMMON_IPC_MESSAGE_UTILS_H_
--- a/ipc/glue/IPCStreamUtils.cpp
+++ b/ipc/glue/IPCStreamUtils.cpp
@@ -442,19 +442,19 @@ IPCStream& AutoIPCStream::TakeValue() {
 Maybe<IPCStream>& AutoIPCStream::TakeOptionalValue() {
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!mValue);
   MOZ_ASSERT(mOptionalValue);
   mTaken = true;
   return *mOptionalValue;
 }
 
-void IPDLParamTraits<nsIInputStream>::Write(IPC::Message* aMsg,
-                                            IProtocol* aActor,
-                                            nsIInputStream* aParam) {
+void IPDLParamTraits<nsIInputStream*>::Write(IPC::Message* aMsg,
+                                             IProtocol* aActor,
+                                             nsIInputStream* aParam) {
   mozilla::ipc::AutoIPCStream autoStream;
   bool ok = false;
   bool found = false;
 
   // We can only serialize our nsIInputStream if it's going to be sent over one
   // of the protocols we support, or a protocol which is managed by one of the
   // protocols we support.
   IProtocol* actor = aActor;
@@ -492,20 +492,20 @@ void IPDLParamTraits<nsIInputStream>::Wr
     aActor->FatalError(
         "Attempt to send nsIInputStream over an unsupported ipdl protocol");
   }
   MOZ_RELEASE_ASSERT(ok, "Failed to serialize nsIInputStream");
 
   WriteIPDLParam(aMsg, aActor, autoStream.TakeOptionalValue());
 }
 
-bool IPDLParamTraits<nsIInputStream>::Read(const IPC::Message* aMsg,
-                                           PickleIterator* aIter,
-                                           IProtocol* aActor,
-                                           RefPtr<nsIInputStream>* aResult) {
+bool IPDLParamTraits<nsIInputStream*>::Read(const IPC::Message* aMsg,
+                                            PickleIterator* aIter,
+                                            IProtocol* aActor,
+                                            RefPtr<nsIInputStream>* aResult) {
   mozilla::Maybe<mozilla::ipc::IPCStream> ipcStream;
   if (!ReadIPDLParam(aMsg, aIter, aActor, &ipcStream)) {
     return false;
   }
 
   *aResult = mozilla::ipc::DeserializeIPCStream(ipcStream);
   return true;
 }
--- a/ipc/glue/IPCStreamUtils.h
+++ b/ipc/glue/IPCStreamUtils.h
@@ -176,17 +176,17 @@ class AutoIPCStream final {
 
  private:
   AutoIPCStream(const AutoIPCStream& aOther) = delete;
   AutoIPCStream& operator=(const AutoIPCStream& aOther) = delete;
   AutoIPCStream& operator=(const AutoIPCStream&& aOther) = delete;
 };
 
 template <>
-struct IPDLParamTraits<nsIInputStream> {
+struct IPDLParamTraits<nsIInputStream*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     nsIInputStream* aParam);
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<nsIInputStream>* aResult);
 };
 
 }  // namespace ipc
 }  // namespace mozilla
--- a/ipc/glue/IPDLParamTraits.h
+++ b/ipc/glue/IPDLParamTraits.h
@@ -22,30 +22,22 @@ class IProtocol;
 //
 template <typename P>
 struct IPDLParamTraits {
   // This is the default impl which discards the actor parameter and calls into
   // ParamTraits. Types which want to use the actor parameter must specialize
   // IPDLParamTraits.
   template <typename R>
   static inline void Write(IPC::Message* aMsg, IProtocol*, R&& aParam) {
-    static_assert(
-        IsSame<P, typename IPC::ParamTraitsSelector<R>::Type>::value,
-        "IPDLParamTraits::Write only forwards calls which work via WriteParam");
-
     IPC::ParamTraits<P>::Write(aMsg, std::forward<R>(aParam));
   }
 
   template <typename R>
   static inline bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                           IProtocol*, R* aResult) {
-    static_assert(
-        IsSame<P, typename IPC::ParamTraitsSelector<R>::Type>::value,
-        "IPDLParamTraits::Read only forwards calls which work via ReadParam");
-
     return IPC::ParamTraits<P>::Read(aMsg, aIter, aResult);
   }
 };
 
 //
 // WriteIPDLParam and ReadIPDLParam are like IPC::WriteParam and IPC::ReadParam,
 // however, they also accept an extra actor argument, and use IPDLParamTraits
 // rather than ParamTraits.
@@ -53,26 +45,25 @@ struct IPDLParamTraits {
 // NOTE: WriteIPDLParam takes a universal reference, so that it can support
 // whatever reference type is supported by the underlying IPDLParamTraits::Write
 // implementation. See the comment on IPDLParamTraits<nsTArray<T>>::Write for
 // more information.
 //
 template <typename P>
 static MOZ_NEVER_INLINE void WriteIPDLParam(IPC::Message* aMsg,
                                             IProtocol* aActor, P&& aParam) {
-  IPDLParamTraits<typename IPC::ParamTraitsSelector<P>::Type>::Write(
-      aMsg, aActor, std::forward<P>(aParam));
+  IPDLParamTraits<typename Decay<P>::Type>::Write(aMsg, aActor,
+                                                  std::forward<P>(aParam));
 }
 
 template <typename P>
 static MOZ_NEVER_INLINE bool ReadIPDLParam(const IPC::Message* aMsg,
                                            PickleIterator* aIter,
                                            IProtocol* aActor, P* aResult) {
-  return IPDLParamTraits<typename IPC::ParamTraitsSelector<P>::Type>::Read(
-      aMsg, aIter, aActor, aResult);
+  return IPDLParamTraits<P>::Read(aMsg, aIter, aActor, aResult);
 }
 
 constexpr void WriteIPDLParamList(IPC::Message*, IProtocol*) {}
 
 template <typename P, typename... Ps>
 static void WriteIPDLParamList(IPC::Message* aMsg, IProtocol* aActor,
                                P&& aParam, Ps&&... aParams) {
   WriteIPDLParam(aMsg, aActor, std::forward<P>(aParam));
@@ -86,16 +77,54 @@ constexpr bool ReadIPDLParamList(const I
 
 template <typename P, typename... Ps>
 static bool ReadIPDLParamList(const IPC::Message* aMsg, PickleIterator* aIter,
                               IProtocol* aActor, P* aResult, Ps*... aResults) {
   return ReadIPDLParam(aMsg, aIter, aActor, aResult) &&
          ReadIPDLParamList(aMsg, aIter, aActor, aResults...);
 }
 
+// When being passed `RefPtr<T>` or `nsCOMPtr<T>`, forward to a specialization
+// for the underlying target type. The parameter type will be passed as `T*`,
+// and result as `RefPtr<T>*`.
+//
+// This is done explicitly to ensure that the deleted `&&` overload for
+// `operator T*` is not selected in generic contexts, and to support
+// deserializing into `nsCOMPtr<T>`.
+template <typename T>
+struct IPDLParamTraits<RefPtr<T>> {
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    const RefPtr<T>& aParam) {
+    IPDLParamTraits<T*>::Write(aMsg, aActor, aParam.get());
+  }
+
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, RefPtr<T>* aResult) {
+    return IPDLParamTraits<T*>::Read(aMsg, aIter, aActor, aResult);
+  }
+};
+
+template <typename T>
+struct IPDLParamTraits<nsCOMPtr<T>> {
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    const nsCOMPtr<T>& aParam) {
+    IPDLParamTraits<T*>::Write(aMsg, aActor, aParam.get());
+  }
+
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, nsCOMPtr<T>* aResult) {
+    RefPtr<T> refptr;
+    if (!IPDLParamTraits<T*>::Read(aMsg, aIter, aActor, &refptr)) {
+      return false;
+    }
+    *aResult = refptr.forget();
+    return true;
+  }
+};
+
 // nsTArray support for IPDLParamTraits
 template <typename T>
 struct IPDLParamTraits<nsTArray<T>> {
   // Some serializers need to take a mutable reference to their backing object,
   // such as Shmem segments and Byte Buffers. These serializers take the
   // backing data and move it into the IPC layer for efficiency. `Write` uses a
   // forwarding reference as occasionally these types appear inside of IPDL
   // arrays.
--- a/ipc/glue/URIUtils.h
+++ b/ipc/glue/URIUtils.h
@@ -19,17 +19,17 @@ void SerializeURI(nsIURI* aURI, URIParam
 
 void SerializeURI(nsIURI* aURI, Maybe<URIParams>& aParams);
 
 already_AddRefed<nsIURI> DeserializeURI(const URIParams& aParams);
 
 already_AddRefed<nsIURI> DeserializeURI(const Maybe<URIParams>& aParams);
 
 template <>
-struct IPDLParamTraits<nsIURI> {
+struct IPDLParamTraits<nsIURI*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor, nsIURI* aParam) {
     Maybe<URIParams> params;
     SerializeURI(aParam, params);
     WriteIPDLParam(aMsg, aActor, params);
   }
 
   static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                    IProtocol* aActor, RefPtr<nsIURI>* aResult) {
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1970,22 +1970,22 @@ class _ParamTraits():
             errfn=errfn,
             paramtype=what,
             sentinelKey=sentinelKey,
             errfnSentinel=errfnSentinel(),
             actor=cls.actor)
 
     @classmethod
     def generateDecl(cls, fortype, write, read, constin=True):
-        # IPDLParamTraits impls are selected ignoring constness, references,
-        # and pointers.
+        # IPDLParamTraits impls are selected ignoring constness, and references.
         pt = Class('IPDLParamTraits',
                    specializes=Type(fortype.name,
                                     T=fortype.T,
-                                    inner=fortype.inner),
+                                    inner=fortype.inner,
+                                    ptr=fortype.ptr),
                    struct=True)
 
         # typedef T paramType;
         pt.addstmt(Typedef(fortype, 'paramType'))
 
         iprotocoltype = Type('mozilla::ipc::IProtocol', ptr=True)
 
         # static void Write(Message*, const T&);
--- a/toolkit/components/alerts/AlertNotificationIPCSerializer.h
+++ b/toolkit/components/alerts/AlertNotificationIPCSerializer.h
@@ -14,17 +14,17 @@
 #include "ipc/IPCMessageUtils.h"
 
 #include "mozilla/dom/PermissionMessageUtils.h"
 
 namespace mozilla {
 namespace ipc {
 
 template <>
-struct IPDLParamTraits<nsIAlertNotification> {
+struct IPDLParamTraits<nsIAlertNotification*> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
                     nsIAlertNotification* aParam) {
     bool isNull = !aParam;
     if (isNull) {
       WriteIPDLParam(aMsg, aActor, isNull);
       return;
     }