Bug 1164581 - Adding an overload for NS_ProxyRelease that accepts already_AddRefed, and removing all the others. r?bobbyholley
authorAidin Gharibnavaz <aidin@aidinhut.com>
Sun, 17 Jan 2016 20:26:47 +0330
changeset 675103 7f913ad95de272d0dd1f114e5f78190754903656
parent 672618 531d1f6d1cde1182e9f7f9dff81a4fc5abc0a601
child 675104 7ec76b0aaa5adaa2e80758289ec6465cf3225c2f
push id104889
push useraidin@aidinhut.com
push dateSun, 17 Jan 2016 16:57:30 +0000
treeherdertry@7ec76b0aaa5a [default view] [failures only]
reviewersbobbyholley
bugs1164581
milestone46.0a1
Bug 1164581 - Adding an overload for NS_ProxyRelease that accepts already_AddRefed, and removing all the others. r?bobbyholley
dom/archivereader/ArchiveEvent.cpp
dom/base/Console.cpp
dom/base/WebSocket.cpp
dom/base/nsScriptLoader.cpp
dom/cache/ManagerId.cpp
dom/devicestorage/DeviceStorageStatics.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/media/webspeech/recognition/SpeechStreamListener.cpp
dom/workers/WorkerPrivate.cpp
extensions/gio/nsGIOProtocolHandler.cpp
extensions/spellcheck/src/mozPersonalDictionary.cpp
image/Decoder.cpp
image/decoders/icon/mac/nsIconChannelCocoa.mm
image/decoders/icon/win/nsIconChannel.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
modules/libjar/nsJARChannel.cpp
netwerk/base/TLSServerSocket.cpp
netwerk/base/nsBaseChannel.cpp
netwerk/base/nsProtocolProxyService.cpp
netwerk/base/nsServerSocket.cpp
netwerk/base/nsStreamListenerTee.cpp
netwerk/base/nsTransportUtils.cpp
netwerk/base/nsUDPSocket.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache2/CacheIndex.h
netwerk/cache2/CacheStorageService.h
netwerk/ipc/RemoteOpenFileChild.cpp
netwerk/protocol/file/nsFileChannel.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
netwerk/sctp/datachannel/DataChannel.cpp
security/manager/ssl/nsNSSCallbacks.cpp
storage/StorageBaseStatementInternal.cpp
storage/mozStorageAsyncStatement.cpp
storage/mozStorageConnection.cpp
storage/mozStorageService.cpp
storage/mozStorageStatementData.h
toolkit/components/osfile/NativeOSFileInternals.cpp
toolkit/components/places/AsyncFaviconHelpers.cpp
toolkit/components/places/Database.cpp
toolkit/components/places/Helpers.h
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
widget/gonk/nsScreenManagerGonk.cpp
xpcom/base/nsConsoleService.cpp
xpcom/base/nsInterfaceRequestorAgg.cpp
xpcom/glue/nsProxyRelease.cpp
xpcom/glue/nsProxyRelease.h
xpcom/glue/objs.mozbuild
xpcom/libxpcomrt/moz.build
--- a/dom/archivereader/ArchiveEvent.cpp
+++ b/dom/archivereader/ArchiveEvent.cpp
@@ -44,27 +44,17 @@ ArchiveReaderEvent::ArchiveReaderEvent(A
 : mArchiveReader(aArchiveReader)
 {
   MOZ_COUNT_CTOR(ArchiveReaderEvent);
 }
 
 ArchiveReaderEvent::~ArchiveReaderEvent()
 {
   if (!NS_IsMainThread()) {
-    nsIMIMEService* mimeService;
-    mMimeService.forget(&mimeService);
-
-    if (mimeService) {
-      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-      NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread! Leaking!");
-
-      if (mainThread) {
-        NS_ProxyRelease(mainThread, mimeService);
-      }
-    }
+    NS_ReleaseOnMainThread(mMimeService.forget());
   }
 
   MOZ_COUNT_DTOR(ArchiveReaderEvent);
 }
 
 // From the filename to the mimetype:
 nsresult
 ArchiveReaderEvent::GetType(nsCString& aExt,
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -715,21 +715,21 @@ Console::Console(nsPIDOMWindow* aWindow)
 
   mozilla::HoldJSObjects(this);
 }
 
 Console::~Console()
 {
   if (!NS_IsMainThread()) {
     if (mStorage) {
-      NS_ReleaseOnMainThread(mStorage);
+      NS_ReleaseOnMainThread(mStorage.forget());
     }
 
     if (mSandbox) {
-      NS_ReleaseOnMainThread(mSandbox);
+      NS_ReleaseOnMainThread(mSandbox.forget());
     }
   }
 
   mozilla::DropJSObjects(this);
 }
 
 NS_IMETHODIMP
 Console::Observe(nsISupports* aSubject, const char* aTopic,
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -626,18 +626,18 @@ WebSocketImpl::Disconnect()
     // where to, exactly?
     rv.SuppressException();
   }
 
   // DontKeepAliveAnyMore() can release the object. So hold a reference to this
   // until the end of the method.
   RefPtr<WebSocketImpl> kungfuDeathGrip = this;
 
-  NS_ReleaseOnMainThread(mChannel);
-  NS_ReleaseOnMainThread(static_cast<nsIWebSocketEventService*>(mService.forget().take()));
+  NS_ReleaseOnMainThread(mChannel.forget());
+  NS_ReleaseOnMainThread(dont_AddRef(static_cast<nsIWebSocketEventService*>(mService.forget().take())));
 
   mWebSocket->DontKeepAliveAnyMore();
   mWebSocket->mImpl = nullptr;
 
   if (mWorkerPrivate && mWorkerFeature) {
     UnregisterFeature();
   }
 
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -778,27 +778,18 @@ nsScriptLoader::ProcessOffThreadRequest(
   nsresult rv = ProcessRequest(aRequest);
   mDocument->UnblockOnload(false);
   return rv;
 }
 
 NotifyOffThreadScriptLoadCompletedRunnable::~NotifyOffThreadScriptLoadCompletedRunnable()
 {
   if (MOZ_UNLIKELY(mRequest || mLoader) && !NS_IsMainThread()) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-    if (mainThread) {
-      NS_ProxyRelease(mainThread, mRequest);
-      NS_ProxyRelease(mainThread, mLoader);
-    } else {
-      MOZ_ASSERT(false, "We really shouldn't leak!");
-      // Better to leak than crash.
-      Unused << mRequest.forget();
-      Unused << mLoader.forget();
-    }
+    NS_ReleaseOnMainThread(mRequest.forget());
+    NS_ReleaseOnMainThread(mLoader.forget());
   }
 }
 
 NS_IMETHODIMP
 NotifyOffThreadScriptLoadCompletedRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/cache/ManagerId.cpp
+++ b/dom/cache/ManagerId.cpp
@@ -57,17 +57,14 @@ ManagerId::~ManagerId()
   if (NS_IsMainThread()) {
     return;
   }
 
   // Otherwise we need to proxy to main thread to do the release
 
   // The PBackground worker thread shouldn't be running after the main thread
   // is stopped.  So main thread is guaranteed to exist here.
-  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-  MOZ_ASSERT(mainThread);
-
-  NS_ProxyRelease(mainThread, mPrincipal.forget().take());
+  NS_ReleaseOnMainThread(mPrincipal.forget());
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/devicestorage/DeviceStorageStatics.cpp
+++ b/dom/devicestorage/DeviceStorageStatics.cpp
@@ -855,17 +855,17 @@ DeviceStorageStatics::ListenerWrapper::L
   : mListener(do_GetWeakReference(static_cast<DOMEventTargetHelper*>(aListener)))
   , mOwningThread(NS_GetCurrentThread())
 {
 }
 
 DeviceStorageStatics::ListenerWrapper::~ListenerWrapper()
 {
   // Even weak pointers are not thread safe
-  NS_ProxyRelease(mOwningThread, mListener);
+  NS_ProxyRelease(mOwningThread, mListener.forget());
 }
 
 bool
 DeviceStorageStatics::ListenerWrapper::Equals(nsDOMDeviceStorage* aListener)
 {
   bool current = false;
   mOwningThread->IsOnCurrentThread(&current);
   if (current) {
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -3709,18 +3709,17 @@ DeviceStorageRequestManager::~DeviceStor
   DS_LOG_INFO("%p pending %zu", this, mPending.Length());
 
   if (!mPending.IsEmpty()) {
     MOZ_ASSERT_UNREACHABLE("Should not destroy, still has pending requests");
     ListIndex i = mPending.Length();
     while (i > 0) {
       --i;
       DS_LOG_ERROR("terminate %u", mPending[i].mId);
-      NS_ProxyRelease(mOwningThread,
-        NS_ISUPPORTS_CAST(EventTarget*, mPending[i].mRequest.forget().take()));
+      NS_ProxyRelease(mOwningThread, mPending[i].mRequest.forget());
     }
   }
 }
 
 void
 DeviceStorageRequestManager::StorePermission(size_t aAccess, bool aAllow)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/webspeech/recognition/SpeechStreamListener.cpp
+++ b/dom/media/webspeech/recognition/SpeechStreamListener.cpp
@@ -17,20 +17,17 @@ SpeechStreamListener::SpeechStreamListen
 {
 }
 
 SpeechStreamListener::~SpeechStreamListener()
 {
   nsCOMPtr<nsIThread> mainThread;
   NS_GetMainThread(getter_AddRefs(mainThread));
 
-  SpeechRecognition* forgottenRecognition = nullptr;
-  mRecognition.swap(forgottenRecognition);
-  NS_ProxyRelease(mainThread,
-                  static_cast<DOMEventTargetHelper*>(forgottenRecognition));
+  NS_ProxyRelease(mainThread, mRecognition.forget());
 }
 
 void
 SpeechStreamListener::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
                                                TrackID aID,
                                                StreamTime aTrackOffset,
                                                uint32_t aTrackEvents,
                                                const MediaSegment& aQueuedMedia,
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4144,19 +4144,17 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
     // Now that we've spun the loop there's no guarantee that our parent is
     // still alive.  We may have received control messages initiating shutdown.
     {
       MutexAutoLock lock(aParent->mMutex);
       parentStatus = aParent->mStatus;
     }
 
     if (parentStatus > Running) {
-      nsCOMPtr<nsIThread> mainThread;
-      if (NS_FAILED(NS_GetMainThread(getter_AddRefs(mainThread))) ||
-          NS_FAILED(NS_ProxyRelease(mainThread, loadInfo.mChannel))) {
+      if (NS_FAILED(NS_ReleaseOnMainThread(loadInfo.mChannel.forget()))) {
         NS_WARNING("Failed to proxy release of channel, leaking instead!");
       }
       return NS_ERROR_FAILURE;
     }
 
     loadInfo.mDomain = aParent->Domain();
     loadInfo.mFromWindow = aParent->IsFromWindow();
     loadInfo.mWindowID = aParent->WindowID();
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -612,23 +612,19 @@ nsGIOInputStream::Close()
     g_list_foreach(mDirList, (GFunc) g_object_unref, nullptr);
     g_list_free(mDirList);
     mDirList = nullptr;
     mDirListPtr = nullptr;
   }
 
   if (mChannel)
   {
-    nsresult rv = NS_OK;
+    nsresult rv = NS_ReleaseOnMainThread(already_AddRefed<nsIChannel>(mChannel));
 
-    nsCOMPtr<nsIThread> thread = do_GetMainThread();
-    if (thread)
-      rv = NS_ProxyRelease(thread, mChannel);
-
-    NS_ASSERTION(thread && NS_SUCCEEDED(rv), "leaking channel reference");
+    NS_ASSERTION(NS_SUCCEEDED(rv), "leaking channel reference");
     mChannel = nullptr;
     (void) rv;
   }
 
   mSpec.Truncate(); // free memory
 
   // Prevent future reads from re-opening the handle.
   if (NS_SUCCEEDED(mStatus))
--- a/extensions/spellcheck/src/mozPersonalDictionary.cpp
+++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp
@@ -60,26 +60,17 @@ public:
   {
   }
 
   NS_IMETHOD Run() override
   {
     mDict->SyncLoad();
 
     // Release the dictionary on the main thread
-    mozPersonalDictionary *dict;
-    mDict.forget(&dict);
-
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    if (mainThread) {
-      NS_ProxyRelease(mainThread, static_cast<mozIPersonalDictionary *>(dict));
-    } else {
-      // It's better to leak the dictionary than to release it on a wrong thread
-      NS_WARNING("Cannot get main thread, leaking mozPersonalDictionary.");
-    }
+    NS_ReleaseOnMainThread(mDict.forget());
 
     return NS_OK;
   }
 
 private:
   RefPtr<mozPersonalDictionary> mDict;
 };
 
@@ -140,26 +131,18 @@ public:
       mDict->mSavePending = false;
       mon.Notify();
 
       // Leaving the block where 'mon' was declared will call the destructor
       // and unlock.
     }
 
     // Release the dictionary on the main thread.
-    mozPersonalDictionary *dict;
-    mDict.forget(&dict);
+    NS_ReleaseOnMainThread(mDict.forget());
 
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    if (mainThread) {
-      NS_ProxyRelease(mainThread, static_cast<mozIPersonalDictionary *>(dict));
-    } else {
-      // It's better to leak the dictionary than to release it on a wrong thread.
-      NS_WARNING("Cannot get main thread, leaking mozPersonalDictionary.");
-    }
     return NS_OK;
   }
 
 private:
   nsTArray<nsString> mDictWords;
   nsCOMPtr<nsIFile> mFile;
   RefPtr<mozPersonalDictionary> mDict;
 };
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -50,26 +50,18 @@ Decoder::~Decoder()
              "Destroying Decoder without taking all its progress changes");
   MOZ_ASSERT(mInvalidRect.IsEmpty() || !mImage,
              "Destroying Decoder without taking all its invalidations");
   mInitialized = false;
 
   if (mImage && !NS_IsMainThread()) {
     // Dispatch mImage to main thread to prevent it from being destructed by the
     // decode thread.
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
-    if (mainThread) {
-      // Handle ambiguous nsISupports inheritance.
-      RasterImage* rawImg = nullptr;
-      mImage.swap(rawImg);
-      DebugOnly<nsresult> rv =
-        NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
-      MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
-    }
+    DebugOnly<nsresult> rv = NS_ReleaseOnMainThread(mImage.forget());
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
   }
 }
 
 /*
  * Common implementation of the decoder interface.
  */
 
 void
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -33,22 +33,17 @@
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel()
 {
   if (mLoadInfo) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-
-    nsILoadInfo* forgetableLoadInfo;
-    mLoadInfo.forget(&forgetableLoadInfo);
-    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+    NS_ReleaseOnMainThread(mLoadInfo.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsIconChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIRequestObserver,
                   nsIStreamListener)
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -71,22 +71,17 @@ GetStockIconIDForName(const nsACString& 
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel()
 {
   if (mLoadInfo) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-
-    nsILoadInfo* forgetableLoadInfo;
-    mLoadInfo.forget(&forgetableLoadInfo);
-    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+    NS_ReleaseOnMainThread(mLoadInfo.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsIconChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIRequestObserver,
                   nsIStreamListener)
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -1122,20 +1122,17 @@ PeerConnectionMedia::AddTransportFlow(in
     WrapRunnable(this, &PeerConnectionMedia::ConnectDtlsListener_s, aFlow),
     NS_DISPATCH_NORMAL);
 }
 
 void
 PeerConnectionMedia::RemoveTransportFlow(int aIndex, bool aRtcp)
 {
   int index_inner = GetTransportFlowIndex(aIndex, aRtcp);
-  TransportFlow* flow = mTransportFlows[index_inner].forget().take();
-  if (flow) {
-    NS_ProxyRelease(GetSTSThread(), flow);
-  }
+  NS_ProxyRelease(GetSTSThread(), mTransportFlows[index_inner].forget());
 }
 
 void
 PeerConnectionMedia::ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow)
 {
   TransportLayer* dtls = aFlow->GetLayer(TransportLayerDtls::ID());
   if (dtls) {
     dtls->SignalStateChange.connect(this, &PeerConnectionMedia::DtlsConnected_s);
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -212,17 +212,17 @@ nsJARChannel::nsJARChannel()
     mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
 
     // hold an owning reference to the jar handler
     NS_ADDREF(gJarHandler);
 }
 
 nsJARChannel::~nsJARChannel()
 {
-    NS_ReleaseOnMainThread(mLoadInfo);
+    NS_ReleaseOnMainThread(mLoadInfo.forget());
 
     // release owning reference to the jar handler
     nsJARProtocolHandler *handler = gJarHandler;
     NS_RELEASE(handler); // nullptr parameter
 }
 
 NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
                             nsHashPropertyBag,
--- a/netwerk/base/TLSServerSocket.cpp
+++ b/netwerk/base/TLSServerSocket.cpp
@@ -330,20 +330,19 @@ TLSServerConnectionInfo::~TLSServerConne
   }
 
   nsITLSServerSecurityObserver* observer;
   {
     MutexAutoLock lock(mLock);
     mSecurityObserver.forget(&observer);
   }
 
-  if (observer) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-    NS_ProxyRelease(mainThread, observer);
+  if (observer)
+  {
+    NS_ReleaseOnMainThread(dont_AddRef<nsITLSServerSecurityObserver>(observer));
   }
 }
 
 NS_IMETHODIMP
 TLSServerConnectionInfo::SetSecurityObserver(nsITLSServerSecurityObserver* aObserver)
 {
   {
     MutexAutoLock lock(mLock);
--- a/netwerk/base/nsBaseChannel.cpp
+++ b/netwerk/base/nsBaseChannel.cpp
@@ -61,17 +61,17 @@ nsBaseChannel::nsBaseChannel()
   , mContentLength(-1)
   , mWasOpened(false)
 {
   mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
 }
 
 nsBaseChannel::~nsBaseChannel()
 {
-  NS_ReleaseOnMainThread(mLoadInfo);
+  NS_ReleaseOnMainThread(mLoadInfo.forget());
 }
 
 nsresult
 nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
                         bool openNewChannel)
 {
   SUSPEND_PUMP_FOR_SCOPE();
 
--- a/netwerk/base/nsProtocolProxyService.cpp
+++ b/netwerk/base/nsProtocolProxyService.cpp
@@ -123,41 +123,30 @@ public:
 private:
     ~nsAsyncResolveRequest()
     {
         if (!NS_IsMainThread()) {
             // these xpcom pointers might need to be proxied back to the
             // main thread to delete safely, but if this request had its
             // callbacks called normally they will all be null and this is a nop
 
-            nsCOMPtr<nsIThread> mainThread;
-            NS_GetMainThread(getter_AddRefs(mainThread));
-
             if (mChannel) {
-                nsIChannel *forgettable;
-                mChannel.forget(&forgettable);
-                NS_ProxyRelease(mainThread, forgettable, false);
+                NS_ReleaseOnMainThread(mChannel.forget());
             }
 
             if (mCallback) {
-                nsIProtocolProxyCallback *forgettable;
-                mCallback.forget(&forgettable);
-                NS_ProxyRelease(mainThread, forgettable, false);
+                NS_ReleaseOnMainThread(mCallback.forget());
             }
 
             if (mProxyInfo) {
-                nsIProxyInfo *forgettable;
-                mProxyInfo.forget(&forgettable);
-                NS_ProxyRelease(mainThread, forgettable, false);
+                NS_ReleaseOnMainThread(mProxyInfo.forget());
             }
 
             if (mXPComPPS) {
-                nsIProtocolProxyService *forgettable;
-                mXPComPPS.forget(&forgettable);
-                NS_ProxyRelease(mainThread, forgettable, false);
+                NS_ReleaseOnMainThread(mXPComPPS.forget());
             }
         }
     }
 
 public:
     void SetResult(nsresult status, nsIProxyInfo *pi)
     {
         mStatus = status;
--- a/netwerk/base/nsServerSocket.cpp
+++ b/netwerk/base/nsServerSocket.cpp
@@ -228,25 +228,29 @@ nsServerSocket::OnSocketDetached(PRFileD
     mFD = nullptr;
   }
 
   if (mListener)
   {
     mListener->OnStopListening(this, mCondition);
 
     // need to atomically clear mListener.  see our Close() method.
-    nsIServerSocketListener *listener = nullptr;
+    nsIServerSocketListener* listener = nullptr;
     {
       MutexAutoLock lock(mLock);
       mListener.swap(listener);
     }
+
     // XXX we need to proxy the release to the listener's target thread to work
     // around bug 337492.
     if (listener)
-      NS_ProxyRelease(mListenerTarget, listener);
+    {
+      NS_ProxyRelease(mListenerTarget,
+                      dont_AddRef<nsIServerSocketListener>(listener));
+    }
   }
 }
 
 void
 nsServerSocket::IsLocal(bool *aIsLocal)
 {
 #if defined(XP_UNIX)
   // Unix-domain sockets are always local.
--- a/netwerk/base/nsStreamListenerTee.cpp
+++ b/netwerk/base/nsStreamListenerTee.cpp
@@ -34,22 +34,22 @@ nsStreamListenerTee::OnStopRequest(nsIRe
     // it is critical that we close out the input stream tee
     if (mInputTee) {
         mInputTee->SetSink(nullptr);
         mInputTee = 0;
     }
 
     // release sink on the same thread where the data was written (bug 716293)
     if (mEventTarget) {
-        nsIOutputStream *sink = nullptr;
+      if (NS_FAILED(NS_ProxyRelease(mEventTarget, mSink.forget()))) {
+        NS_WARNING("Releasing sink on the current thread!");
+        nsIOutputStream* sink = nullptr;
         mSink.swap(sink);
-        if (NS_FAILED(NS_ProxyRelease(mEventTarget, sink))) {
-            NS_WARNING("Releasing sink on the current thread!");
-            NS_RELEASE(sink);
-        }
+        NS_RELEASE(sink);
+      }
     }
     else {
         mSink = 0;
     }
 
     nsresult rv = mListener->OnStopRequest(request, context, status);
     if (mObserver)
         mObserver->OnStopRequest(request, context, status);
--- a/netwerk/base/nsTransportUtils.cpp
+++ b/netwerk/base/nsTransportUtils.cpp
@@ -32,17 +32,17 @@ public:
         NS_ADDREF(mSink);
     }
 
 private:
     virtual ~nsTransportEventSinkProxy()
     {
         // our reference to mSink could be the last, so be sure to release
         // it on the target thread.  otherwise, we could get into trouble.
-        NS_ProxyRelease(mTarget, mSink);
+        NS_ProxyRelease(mTarget, already_AddRefed<nsITransportEventSink>(mSink));
     }
 
 public:
     nsITransportEventSink           *mSink;
     nsCOMPtr<nsIEventTarget>         mTarget;
     Mutex                            mLock;
     nsTransportStatusEvent          *mLastEvent;
 };
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -519,26 +519,24 @@ nsUDPSocket::OnSocketDetached(PRFileDesc
     PR_Close(mFD);
     mFD = nullptr;
   }
   SaveNetworkStats(true);
 
   if (mListener)
   {
     // need to atomically clear mListener.  see our Close() method.
-    nsCOMPtr<nsIUDPSocketListener> listener;
+    nsIUDPSocketListener* listener;
     {
       MutexAutoLock lock(mLock);
       mListener.swap(listener);
     }
 
-    if (listener) {
-      listener->OnStopListening(this, mCondition);
-      NS_ProxyRelease(mListenerTarget, listener);
-    }
+    NS_ProxyRelease(mListenerTarget,
+                    dont_AddRef<nsIUDPSocketListener>(listener));
   }
 }
 
 void
 nsUDPSocket::IsLocal(bool *aIsLocal)
 {
   // If bound to loopback, this UDP socket only accepts local connections.
   *aIsLocal = mAddr.raw.family == nsINetAddr::FAMILY_LOCAL;
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -2686,17 +2686,17 @@ nsCacheService::ReleaseObject_Locked(nsI
                                      nsIEventTarget * target)
 {
     gService->mLock.AssertCurrentThreadOwns();
 
     bool isCur;
     if (!target || (NS_SUCCEEDED(target->IsOnCurrentThread(&isCur)) && isCur)) {
         gService->mDoomedObjects.AppendElement(obj);
     } else {
-        NS_ProxyRelease(target, obj);
+        NS_ProxyRelease(target, already_AddRefed<nsISupports>(obj));
     }
 }
 
 
 nsresult
 nsCacheService::SetCacheElement(nsCacheEntry * entry, nsISupports * element)
 {
     entry->SetData(element);
--- a/netwerk/cache2/CacheIndex.h
+++ b/netwerk/cache2/CacheIndex.h
@@ -1041,26 +1041,17 @@ private:
       NS_DispatchToMainThread(this);
     }
 
   private:
     explicit DiskConsumptionObserver(nsWeakPtr const &aWeakObserver)
       : mObserver(aWeakObserver) { }
     virtual ~DiskConsumptionObserver() {
       if (mObserver && !NS_IsMainThread()) {
-        nsIWeakReference *obs;
-        mObserver.forget(&obs);
-
-        nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-        if (mainThread) {
-          NS_ProxyRelease(mainThread, obs);
-        } else {
-          NS_WARNING("Cannot get main thread, leaking weak reference to "
-                     "CacheStorageConsumptionObserver.");
-        }
+        NS_ReleaseOnMainThread(mObserver.forget());
       }
     }
 
     NS_IMETHODIMP Run()
     {
       MOZ_ASSERT(NS_IsMainThread());
 
       nsCOMPtr<nsICacheStorageConsumptionObserver> observer =
--- a/netwerk/cache2/CacheStorageService.h
+++ b/netwerk/cache2/CacheStorageService.h
@@ -377,20 +377,17 @@ private:
   };
 
   RefPtr<IOThreadSuspender> mActiveIOSuspender;
 };
 
 template<class T>
 void ProxyRelease(nsCOMPtr<T> &object, nsIThread* thread)
 {
-  T* release;
-  object.forget(&release);
-
-  NS_ProxyRelease(thread, release);
+  NS_ProxyRelease(thread, object.forget());
 }
 
 template<class T>
 void ProxyReleaseMainThread(nsCOMPtr<T> &object)
 {
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   ProxyRelease(object, mainThread);
 }
--- a/netwerk/ipc/RemoteOpenFileChild.cpp
+++ b/netwerk/ipc/RemoteOpenFileChild.cpp
@@ -102,43 +102,40 @@ RemoteOpenFileChild::RemoteOpenFileChild
 
 RemoteOpenFileChild::~RemoteOpenFileChild()
 {
   if (NS_IsMainThread()) {
     if (mListener) {
       NotifyListener(NS_ERROR_UNEXPECTED);
     }
   } else {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ReleaseOnMainThread(mURI.forget(), true)));
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ReleaseOnMainThread(mAppURI.forget(),
+                                                        true)));
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ReleaseOnMainThread(mListener.forget(),
+                                                        true)));
     nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
     if (mainThread) {
-      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread, mURI, true)));
-      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread, mAppURI, true)));
-      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread, mListener,
-                                                   true)));
-
       TabChild* tabChild;
       mTabChild.forget(&tabChild);
 
       if (tabChild) {
         nsCOMPtr<nsIRunnable> runnable =
           NS_NewNonOwningRunnableMethod(tabChild, &TabChild::Release);
         MOZ_ASSERT(runnable);
 
         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(runnable,
                                                           NS_DISPATCH_NORMAL)));
       }
     } else {
       using mozilla::Unused;
 
       NS_WARNING("RemoteOpenFileChild released after thread shutdown, leaking "
-                 "its members!");
+                 "mTabChild!");
 
-      Unused << mURI.forget();
-      Unused << mAppURI.forget();
-      Unused << mListener.forget();
       Unused << mTabChild.forget();
     }
   }
 
   if (mNSPRFileDesc) {
     // PR_Close both closes the file and deallocates the PRFileDesc
     PR_Close(mNSPRFileDesc);
   }
--- a/netwerk/protocol/file/nsFileChannel.cpp
+++ b/netwerk/protocol/file/nsFileChannel.cpp
@@ -124,19 +124,17 @@ nsFileCopyEvent::DoCopy()
   mDest->Close();
 
   // Notify completion
   if (mCallback) {
     mCallbackTarget->Dispatch(mCallback, NS_DISPATCH_NORMAL);
 
     // Release the callback on the target thread to avoid destroying stuff on
     // the wrong thread.
-    nsIRunnable *doomed = nullptr;
-    mCallback.swap(doomed);
-    NS_ProxyRelease(mCallbackTarget, doomed);
+    NS_ProxyRelease(mCallbackTarget, mCallback.forget());
   }
 }
 
 nsresult
 nsFileCopyEvent::Dispatch(nsIRunnable *callback,
                           nsITransportEventSink *sink,
                           nsIEventTarget *target)
 {
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -120,17 +120,17 @@ HttpBaseChannel::HttpBaseChannel()
   mPeerAddr.raw.family = PR_AF_UNSPEC;
   mSchedulingContextID.Clear();
 }
 
 HttpBaseChannel::~HttpBaseChannel()
 {
   LOG(("Destroying HttpBaseChannel @%x\n", this));
 
-  NS_ReleaseOnMainThread(mLoadInfo);
+  NS_ReleaseOnMainThread(mLoadInfo.forget());
 
   // Make sure we don't leak
   CleanRedirectCacheChainIfNecessary();
 }
 
 nsresult
 HttpBaseChannel::Init(nsIURI *aURI,
                       uint32_t aCaps,
--- a/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
@@ -35,23 +35,18 @@ LazyLogModule gRtspLog("nsRtsp");
 void
 RtspControllerParent::Destroy()
 {
   // If we're being destroyed on a non-main thread, we AddRef again and use a
   // proxy to release the RtspControllerParent on the main thread, where the
   // RtspControllerParent is deleted. This ensures we only delete the
   // RtspControllerParent on the main thread.
   if (!NS_IsMainThread()) {
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    NS_ENSURE_TRUE_VOID(mainThread);
     RefPtr<RtspControllerParent> doomed(this);
-    if (NS_FAILED(NS_ProxyRelease(mainThread,
-            static_cast<nsIStreamingProtocolListener*>(doomed), true))) {
-      NS_WARNING("Failed to proxy release to main thread!");
-    }
+    NS_ReleaseOnMainThread(doomed.forget(), true);
   } else {
     delete this;
   }
 }
 
 NS_IMPL_ADDREF(RtspControllerParent)
 NS_IMPL_RELEASE_WITH_DESTROY(RtspControllerParent, Destroy())
 NS_IMPL_QUERY_INTERFACE(RtspControllerParent,
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -355,17 +355,14 @@ BaseWebSocketChannel::ListenerAndContext
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mListener);
 }
 
 BaseWebSocketChannel::ListenerAndContextContainer::~ListenerAndContextContainer()
 {
   MOZ_ASSERT(mListener);
 
-  nsCOMPtr<nsIThread> mainThread;
-  NS_GetMainThread(getter_AddRefs(mainThread));
-
-  NS_ProxyRelease(mainThread, mListener, false);
-  NS_ProxyRelease(mainThread, mContext, false);
+  NS_ReleaseOnMainThread(mListener.forget());
+  NS_ReleaseOnMainThread(mContext.forget());
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1211,24 +1211,24 @@ WebSocketChannel::~WebSocketChannel()
 
   while ((mCurrentOut = (OutboundMessage *) mOutgoingPingMessages.PopFront()))
     delete mCurrentOut;
   while ((mCurrentOut = (OutboundMessage *) mOutgoingPongMessages.PopFront()))
     delete mCurrentOut;
   while ((mCurrentOut = (OutboundMessage *) mOutgoingMessages.PopFront()))
     delete mCurrentOut;
 
-  NS_ReleaseOnMainThread(mURI);
-  NS_ReleaseOnMainThread(mOriginalURI);
+  NS_ReleaseOnMainThread(mURI.forget());
+  NS_ReleaseOnMainThread(mOriginalURI.forget());
 
   mListenerMT = nullptr;
 
-  NS_ReleaseOnMainThread(mLoadGroup);
-  NS_ReleaseOnMainThread(mLoadInfo);
-  NS_ReleaseOnMainThread(static_cast<nsIWebSocketEventService*>(mService.forget().take()));
+  NS_ReleaseOnMainThread(mLoadGroup.forget());
+  NS_ReleaseOnMainThread(mLoadInfo.forget());
+  NS_ReleaseOnMainThread(dont_AddRef(static_cast<nsIWebSocketEventService*>(mService.forget().take())));
 }
 
 NS_IMETHODIMP
 WebSocketChannel::Observe(nsISupports *subject,
                           const char *topic,
                           const char16_t *data)
 {
   LOG(("WebSocketChannel::Observe [topic=\"%s\"]\n", topic));
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -51,22 +51,17 @@ WyciwygChannelChild::WyciwygChannelChild
   LOG(("Creating WyciwygChannelChild @%x\n", this));
   mEventQ = new ChannelEventQueue(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this));
 }
 
 WyciwygChannelChild::~WyciwygChannelChild()
 {
   LOG(("Destroying WyciwygChannelChild @%x\n", this));
   if (mLoadInfo) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-
-    nsILoadInfo *forgetableLoadInfo;
-    mLoadInfo.forget(&forgetableLoadInfo);
-    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+    NS_ReleaseOnMainThread(mLoadInfo.forget());
   }
 }
 
 void
 WyciwygChannelChild::AddIPDLReference()
 {
   MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
   mIPCOpen = true;
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -35,23 +35,17 @@ typedef mozilla::net::LoadContextInfo Lo
 
 // Must release mChannel on the main thread
 class nsWyciwygAsyncEvent : public nsRunnable {
 public:
   explicit nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {}
 
   ~nsWyciwygAsyncEvent()
   {
-    nsCOMPtr<nsIThread> thread = do_GetMainThread();
-    NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!");
-    if (thread) {
-      nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel);
-      mozilla::Unused << mChannel.forget();
-      NS_ProxyRelease(thread, chan);
-    }
+    NS_ReleaseOnMainThread(mChannel.forget());
   }
 protected:
   RefPtr<nsWyciwygChannel> mChannel;
 };
 
 class nsWyciwygSetCharsetandSourceEvent : public nsWyciwygAsyncEvent {
 public:
   explicit nsWyciwygSetCharsetandSourceEvent(nsWyciwygChannel *aChannel)
@@ -104,22 +98,17 @@ nsWyciwygChannel::nsWyciwygChannel()
     mContentLength(-1),
     mLoadFlags(LOAD_NORMAL)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
   if (mLoadInfo) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-
-    nsILoadInfo *forgetableLoadInfo;
-    mLoadInfo.forget(&forgetableLoadInfo);
-    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+    NS_ReleaseOnMainThread(mLoadInfo.forget(), false);
   }
 }
 
 NS_IMPL_ISUPPORTS(nsWyciwygChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIStreamListener,
                   nsIRequestObserver,
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -191,17 +191,17 @@ DataChannelConnection::~DataChannelConne
   MOZ_ASSERT(mPending.GetSize() == 0);
 
   // Already disconnected from sigslot/mTransportFlow
   // TransportFlows must be released from the STS thread
   if (!IsSTSThread()) {
     ASSERT_WEBRTC(NS_IsMainThread());
     if (mTransportFlow) {
       ASSERT_WEBRTC(mSTS);
-      NS_ProxyRelease(mSTS, mTransportFlow);
+      NS_ProxyRelease(mSTS, mTransportFlow.forget());
     }
 
     if (mInternalIOThread) {
       // Avoid spinning the event thread from here (which if we're mainthread
       // is in the event loop already)
       NS_DispatchToMainThread(WrapRunnable(nsCOMPtr<nsIThread>(mInternalIOThread),
                                            &nsIThread::Shutdown),
                               NS_DISPATCH_NORMAL);
@@ -2412,17 +2412,17 @@ DataChannelConnection::ReadBlob(already_
   RefPtr<DataChannelBlobSendRunnable> runnable = new DataChannelBlobSendRunnable(aThis,
                                                                                    aStream);
   // avoid copying the blob data by passing the mData from the runnable
   if (NS_FAILED(aBlob->Available(&len)) ||
       NS_FAILED(NS_ReadInputStreamToString(aBlob, runnable->mData, len))) {
     // Bug 966602:  Doesn't return an error to the caller via onerror.
     // We must release DataChannelConnection on MainThread to avoid issues (bug 876167)
     // aThis is now owned by the runnable; release it there
-    NS_ProxyRelease(mainThread, runnable);
+    NS_ProxyRelease(mainThread, runnable.forget());
     return;
   }
   aBlob->Close();
   NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
 }
 
 void
 DataChannelConnection::GetStreamIds(std::vector<uint16_t>* aStreamList)
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -605,18 +605,17 @@ nsHTTPListener::~nsHTTPListener()
   if (mResponsibleForDoneSignal)
     send_done_signal();
 
   if (mResultData) {
     free(const_cast<uint8_t *>(mResultData));
   }
 
   if (mLoader) {
-    nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
-    NS_ProxyRelease(mainThread, mLoader);
+    NS_ReleaseOnMainThread(mLoader.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsHTTPListener, nsIStreamLoaderObserver)
 
 void
 nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
 {
--- a/storage/StorageBaseStatementInternal.cpp
+++ b/storage/StorageBaseStatementInternal.cpp
@@ -43,17 +43,19 @@ public:
   }
 
   NS_IMETHOD Run()
   {
     if (mStatement->mAsyncStatement) {
       (void)::sqlite3_finalize(mStatement->mAsyncStatement);
       mStatement->mAsyncStatement = nullptr;
     }
-    (void)::NS_ProxyRelease(mConnection->threadOpenedOn, mStatement);
+
+    nsCOMPtr<nsIThread> targetThread(mConnection->threadOpenedOn);
+    (void)::NS_ProxyRelease(targetThread, mStatement.forget());
     return NS_OK;
   }
 private:
   RefPtr<StorageBaseStatementInternal> mStatement;
   RefPtr<Connection> mConnection;
 };
 
 /**
@@ -86,23 +88,18 @@ public:
     NS_PRECONDITION(aConnection, "You must provide a Connection");
   }
 
   NS_IMETHOD Run()
   {
     (void)::sqlite3_finalize(mAsyncStatement);
     mAsyncStatement = nullptr;
 
-    // Because of our ambiguous nsISupports we cannot use the NS_ProxyRelease
-    // template helpers.
-    Connection *rawConnection = nullptr;
-    mConnection.swap(rawConnection);
-    (void)::NS_ProxyRelease(
-      rawConnection->threadOpenedOn,
-      NS_ISUPPORTS_CAST(mozIStorageConnection *, rawConnection));
+    nsCOMPtr<nsIThread> target(mConnection->threadOpenedOn);
+    (void)::NS_ProxyRelease(target, mConnection.forget());
     return NS_OK;
   }
 private:
   RefPtr<Connection> mConnection;
   sqlite3_stmt *mAsyncStatement;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/storage/mozStorageAsyncStatement.cpp
+++ b/storage/mozStorageAsyncStatement.cpp
@@ -215,20 +215,19 @@ AsyncStatement::~AsyncStatement()
 
   // If we are getting destroyed on the wrong thread, proxy the connection
   // release to the right thread.  I'm not sure why we do this.
   bool onCallingThread = false;
   (void)mDBConnection->threadOpenedOn->IsOnCurrentThread(&onCallingThread);
   if (!onCallingThread) {
     // NS_ProxyRelase only magic forgets for us if mDBConnection is an
     // nsCOMPtr.  Which it is not; it's an nsRefPtr.
-    Connection *forgottenConn = nullptr;
-    mDBConnection.swap(forgottenConn);
-    (void)::NS_ProxyRelease(forgottenConn->threadOpenedOn,
-                            static_cast<mozIStorageConnection *>(forgottenConn));
+    nsCOMPtr<nsIThread> targetThread(mDBConnection->threadOpenedOn);
+    (void)::NS_ProxyRelease(targetThread,
+                            mDBConnection.forget());
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsISupports
 
 NS_IMPL_ADDREF(AsyncStatement)
 NS_IMPL_RELEASE(AsyncStatement)
--- a/storage/mozStorageConnection.cpp
+++ b/storage/mozStorageConnection.cpp
@@ -380,22 +380,18 @@ public:
 
     return NS_OK;
   }
 
   ~AsyncCloseConnection() {
     nsCOMPtr<nsIThread> thread;
     (void)NS_GetMainThread(getter_AddRefs(thread));
     // Handle ambiguous nsISupports inheritance.
-    Connection *rawConnection = nullptr;
-    mConnection.swap(rawConnection);
-    (void)NS_ProxyRelease(thread,
-                          NS_ISUPPORTS_CAST(mozIStorageConnection *,
-                                            rawConnection));
-    (void)NS_ProxyRelease(thread, mCallbackEvent);
+    NS_ProxyRelease(thread, mConnection.forget());
+    (void)NS_ReleaseOnMainThread(mCallbackEvent.forget());
   }
 private:
   RefPtr<Connection> mConnection;
   sqlite3 *mNativeConnection;
   nsCOMPtr<nsIRunnable> mCallbackEvent;
   nsCOMPtr<nsIThread> mAsyncExecutionThread;
 };
 
@@ -447,32 +443,23 @@ private:
   }
 
   ~AsyncInitializeClone() {
     nsCOMPtr<nsIThread> thread;
     DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(thread));
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     // Handle ambiguous nsISupports inheritance.
-    Connection *rawConnection = nullptr;
-    mConnection.swap(rawConnection);
-    (void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
-                                                    rawConnection));
-
-    Connection *rawClone = nullptr;
-    mClone.swap(rawClone);
-    (void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
-                                                    rawClone));
+    NS_ProxyRelease(thread, mConnection.forget());
+    NS_ProxyRelease(thread, mClone.forget());
 
     // Generally, the callback will be released by CallbackComplete.
     // However, if for some reason Run() is not executed, we still
     // need to ensure that it is released here.
-    mozIStorageCompletionCallback *rawCallback = nullptr;
-    mCallback.swap(rawCallback);
-    (void)NS_ProxyRelease(thread, rawCallback);
+    NS_ProxyRelease(thread, mCallback.forget());
   }
 
   RefPtr<Connection> mConnection;
   RefPtr<Connection> mClone;
   const bool mReadOnly;
   nsCOMPtr<mozIStorageCompletionCallback> mCallback;
 };
 
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -327,18 +327,17 @@ Service::unregisterConnection(Connection
 
     for (uint32_t i = 0 ; i < mConnections.Length(); ++i) {
       if (mConnections[i] == aConnection) {
         nsCOMPtr<nsIThread> thread = mConnections[i]->threadOpenedOn;
 
         // Ensure the connection is released on its opening thread.  Note, we
         // must use .forget().take() so that we can manually cast to an
         // unambiguous nsISupports type.
-        NS_ProxyRelease(thread,
-          static_cast<mozIStorageConnection*>(mConnections[i].forget().take()));
+        NS_ProxyRelease(thread, mConnections[i].forget());
 
         mConnections.RemoveElementAt(i);
         return;
       }
     }
 
     MOZ_ASSERT_UNREACHABLE("Attempt to unregister unknown storage connection!");
   }
@@ -728,33 +727,23 @@ private:
       new CallbackComplete(aStatus,
                            aValue,
                            mCallback.forget());
     return NS_DispatchToMainThread(event);
   }
 
   ~AsyncInitDatabase()
   {
-    nsCOMPtr<nsIThread> thread;
-    DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(thread));
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
-    (void)NS_ProxyRelease(thread, mStorageFile);
-
-    // Handle ambiguous nsISupports inheritance.
-    Connection *rawConnection = nullptr;
-    mConnection.swap(rawConnection);
-    (void)NS_ProxyRelease(thread, NS_ISUPPORTS_CAST(mozIStorageConnection *,
-                                                    rawConnection));
+    (void)NS_ReleaseOnMainThread(mStorageFile.forget());
+    (void)NS_ReleaseOnMainThread(mConnection.forget());
 
     // Generally, the callback will be released by CallbackComplete.
     // However, if for some reason Run() is not executed, we still
     // need to ensure that it is released here.
-    mozIStorageCompletionCallback *rawCallback = nullptr;
-    mCallback.swap(rawCallback);
-    (void)NS_ProxyRelease(thread, rawCallback);
+    (void)NS_ReleaseOnMainThread(mCallback.forget());
   }
 
   RefPtr<Connection> mConnection;
   nsCOMPtr<nsIFile> mStorageFile;
   int32_t mGrowthIncrement;
   RefPtr<mozIStorageCompletionCallback> mCallback;
 };
 
--- a/storage/mozStorageStatementData.h
+++ b/storage/mozStorageStatementData.h
@@ -47,18 +47,17 @@ public:
   : mStatement(nullptr)
   {
   }
   ~StatementData()
   {
     // We need to ensure that mParamsArray is released on the main thread,
     // as the binding arguments may be XPConnect values, which are safe
     // to release only on the main thread.
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    (void)NS_ProxyRelease(mainThread, mParamsArray);
+    NS_ReleaseOnMainThread(mParamsArray.forget());
   }
 
   /**
    * Return the sqlite statement, fetching it from the storage statement.  In
    * the case of AsyncStatements this may actually create the statement 
    */
   inline int getSqliteStatement(sqlite3_stmt **_stmt)
   {
--- a/toolkit/components/osfile/NativeOSFileInternals.cpp
+++ b/toolkit/components/osfile/NativeOSFileInternals.cpp
@@ -524,36 +524,34 @@ public:
                                                 aDiscardedResult,
                                                 aOperation,
                                                 aOSError);
     nsresult rv = NS_DispatchToMainThread(event);
     if (NS_FAILED(rv)) {
       // Last ditch attempt to release on the main thread - some of
       // the members of event are not thread-safe, so letting the
       // pointer go out of scope would cause a crash.
-      nsCOMPtr<nsIThread> main = do_GetMainThread();
-      NS_ProxyRelease(main, event);
+      NS_ReleaseOnMainThread(event.forget());
     }
   }
 
   /**
    * Succeed, asynchronously.
    */
   void Succeed(already_AddRefed<nsINativeOSFileResult>&& aResult) {
     Resolve();
     RefPtr<SuccessEvent> event = new SuccessEvent(mOnSuccess,
                                                     mOnError,
                                                     aResult);
     nsresult rv = NS_DispatchToMainThread(event);
     if (NS_FAILED(rv)) {
       // Last ditch attempt to release on the main thread - some of
       // the members of event are not thread-safe, so letting the
       // pointer go out of scope would cause a crash.
-      nsCOMPtr<nsIThread> main = do_GetMainThread();
-      NS_ProxyRelease(main, event);
+      NS_ReleaseOnMainThread(event.forget());
     }
 
   }
 
 private:
 
   /**
    * Mark the event as complete, for debugging purposes.
@@ -744,18 +742,17 @@ public:
   { }
 
   ~DoReadToTypedArrayEvent() {
     // If AbstractReadEvent::Run() has bailed out, we may need to cleanup
     // mResult, which is main-thread only data
     if (!mResult) {
       return;
     }
-    nsCOMPtr<nsIThread> main = do_GetMainThread();
-    (void)NS_ProxyRelease(main, mResult);
+    NS_ReleaseOnMainThread(mResult.forget());
   }
 
 protected:
   void AfterRead(TimeStamp aDispatchDate,
                  ScopedArrayBufferContents& aBuffer) override {
     MOZ_ASSERT(!NS_IsMainThread());
     mResult->Init(aDispatchDate, TimeStamp::Now() - aDispatchDate, aBuffer.forget());
     Succeed(mResult.forget());
@@ -782,18 +779,17 @@ public:
   { }
 
   ~DoReadToStringEvent() {
     // If AbstraactReadEvent::Run() has bailed out, we may need to cleanup
     // mResult, which is main-thread only data
     if (!mResult) {
       return;
     }
-    nsCOMPtr<nsIThread> main = do_GetMainThread();
-    (void)NS_ProxyRelease(main, mResult);
+    NS_ReleaseOnMainThread(mResult.forget());
   }
 
 protected:
   nsresult BeforeRead() override {
     // Obtain the decoder. We do this before reading to avoid doing
     // any unnecessary I/O in case the name of the encoding is incorrect.
     MOZ_ASSERT(!NS_IsMainThread());
     nsAutoCString encodingName;
--- a/toolkit/components/places/AsyncFaviconHelpers.cpp
+++ b/toolkit/components/places/AsyncFaviconHelpers.cpp
@@ -352,20 +352,18 @@ AsyncFaviconHelperBase::AsyncFaviconHelp
 )
 {
   // Don't AddRef or Release in runnables for thread-safety.
   mCallback.swap(aCallback);
 }
 
 AsyncFaviconHelperBase::~AsyncFaviconHelperBase()
 {
-  nsCOMPtr<nsIThread> thread;
-  (void)NS_GetMainThread(getter_AddRefs(thread));
   if (mCallback) {
-    (void)NS_ProxyRelease(thread, mCallback, true);
+    NS_ReleaseOnMainThread(mCallback.forget(), true);
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncFetchAndSetIconForPage
 
 // static
 nsresult
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -538,23 +538,19 @@ DatabaseShutdown::Complete(nsresult, nsI
                              nullptr);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
   mState = NOTIFIED_OBSERVERS_PLACES_CONNECTION_CLOSED;
 
   if (NS_WARN_IF(!mBarrier)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  nsCOMPtr<nsIAsyncShutdownBarrier> barrier = mBarrier.forget();
-  nsCOMPtr<nsIAsyncShutdownClient> parentClient = mParentClient.forget();
-  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-  MOZ_ASSERT(mainThread);
 
-  NS_ProxyRelease(mainThread, barrier);
-  NS_ProxyRelease(mainThread, parentClient);
+  NS_ReleaseOnMainThread(mBarrier.forget());
+  NS_ReleaseOnMainThread(mParentClient.forget());
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(
   DatabaseShutdown
 , nsIAsyncShutdownBlocker
 , nsIAsyncShutdownCompletionCallback
--- a/toolkit/components/places/Helpers.h
+++ b/toolkit/components/places/Helpers.h
@@ -191,17 +191,17 @@ public:
   , mCallingThread(do_GetCurrentThread())
   {
   }
 
   NS_IMETHOD Run()
   {
     mStatementCache.FinalizeStatements();
     // Release the owner back on the calling thread.
-    (void)NS_ProxyRelease(mCallingThread, mOwner);
+    (void)NS_ProxyRelease(mCallingThread, mOwner.forget());
     return NS_OK;
   }
 
 protected:
   mozilla::storage::StatementCache<StatementType>& mStatementCache;
   nsCOMPtr<nsISupports> mOwner;
   nsCOMPtr<nsIThread> mCallingThread;
 };
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -793,21 +793,18 @@ private:
 };
 
 NS_IMPL_ISUPPORTS(nsUrlClassifierLookupCallback,
                   nsIUrlClassifierLookupCallback,
                   nsIUrlClassifierHashCompleterCallback)
 
 nsUrlClassifierLookupCallback::~nsUrlClassifierLookupCallback()
 {
-  nsCOMPtr<nsIThread> thread;
-  (void)NS_GetMainThread(getter_AddRefs(thread));
-
   if (mCallback) {
-    (void)NS_ProxyRelease(thread, mCallback, false);
+    NS_ReleaseOnMainThread(mCallback.forget());
   }
 }
 
 NS_IMETHODIMP
 nsUrlClassifierLookupCallback::LookupComplete(nsTArray<LookupResult>* results)
 {
   NS_ASSERTION(mResults == nullptr,
                "Should only get one set of results per nsUrlClassifierLookupCallback!");
--- a/widget/gonk/nsScreenManagerGonk.cpp
+++ b/widget/gonk/nsScreenManagerGonk.cpp
@@ -550,17 +550,17 @@ nsScreenGonk::ClearMirroringScreen(nsScr
 void
 nsScreenGonk::UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow)
 {
     MOZ_ASSERT(CompositorParent::IsInCompositorThread());
     MOZ_ASSERT(IsPrimaryScreen());
 
     if (mMirroringWidget) {
         nsCOMPtr<nsIWidget> widget = mMirroringWidget.forget();
-        NS_ReleaseOnMainThread(widget);
+        NS_ReleaseOnMainThread(widget.forget());
     }
     mMirroringWidget = aWindow;
 }
 
 nsWindow*
 nsScreenGonk::GetMirroringWidget()
 {
     MOZ_ASSERT(CompositorParent::IsInCompositorThread());
--- a/xpcom/base/nsConsoleService.cpp
+++ b/xpcom/base/nsConsoleService.cpp
@@ -309,17 +309,17 @@ nsConsoleService::LogMessageWithMode(nsI
       r = new LogMessageRunnable(aMessage, this);
     }
   }
 
   if (retiredMessage) {
     // Release |retiredMessage| on the main thread in case it is an instance of
     // a mainthread-only class like nsScriptErrorWithStack and we're off the
     // main thread.
-    NS_ReleaseOnMainThread(retiredMessage);
+    NS_ReleaseOnMainThread(retiredMessage.forget());
   }
 
   if (r) {
     // avoid failing in XPCShell tests
     nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
     if (mainThread) {
       NS_DispatchToMainThread(r.forget());
     }
--- a/xpcom/base/nsInterfaceRequestorAgg.cpp
+++ b/xpcom/base/nsInterfaceRequestorAgg.cpp
@@ -49,26 +49,18 @@ nsInterfaceRequestorAgg::GetInterface(co
   if (mSecond && NS_FAILED(rv)) {
     rv = mSecond->GetInterface(aIID, aResult);
   }
   return rv;
 }
 
 nsInterfaceRequestorAgg::~nsInterfaceRequestorAgg()
 {
-  nsIInterfaceRequestor* iir = nullptr;
-  mFirst.swap(iir);
-  if (iir) {
-    NS_ProxyRelease(mConsumerTarget, iir);
-  }
-  iir = nullptr;
-  mSecond.swap(iir);
-  if (iir) {
-    NS_ProxyRelease(mConsumerTarget, iir);
-  }
+  NS_ProxyRelease(mConsumerTarget, mFirst.forget());
+  NS_ProxyRelease(mConsumerTarget, mSecond.forget());
 }
 
 nsresult
 NS_NewInterfaceRequestorAggregation(nsIInterfaceRequestor* aFirst,
                                     nsIInterfaceRequestor* aSecond,
                                     nsIInterfaceRequestor** aResult)
 {
   *aResult = new nsInterfaceRequestorAgg(aFirst, aSecond);
deleted file mode 100644
--- a/xpcom/glue/nsProxyRelease.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- 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"
-#include "nsAutoPtr.h"
-
-class nsProxyReleaseEvent : public nsRunnable
-{
-public:
-  explicit nsProxyReleaseEvent(nsISupports* aDoomed) : mDoomed(aDoomed) {}
-
-  NS_IMETHOD Run()
-  {
-    mDoomed->Release();
-    return NS_OK;
-  }
-
-private:
-  nsISupports* MOZ_OWNING_REF mDoomed;
-};
-
-nsresult
-NS_ProxyRelease(nsIEventTarget* aTarget, nsISupports* aDoomed,
-                bool aAlwaysProxy)
-{
-  nsresult rv;
-
-  if (!aDoomed) {
-    // nothing to do
-    return NS_OK;
-  }
-
-  if (!aTarget) {
-    NS_RELEASE(aDoomed);
-    return NS_OK;
-  }
-
-  if (!aAlwaysProxy) {
-    bool onCurrentThread = false;
-    rv = aTarget->IsOnCurrentThread(&onCurrentThread);
-    if (NS_SUCCEEDED(rv) && onCurrentThread) {
-      NS_RELEASE(aDoomed);
-      return NS_OK;
-    }
-  }
-
-  nsCOMPtr<nsIRunnable> ev = new nsProxyReleaseEvent(aDoomed);
-  if (!ev) {
-    // we do not release aDoomed here since it may cause a delete on the
-    // wrong thread.  better to leak than crash.
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("failed to post proxy release event");
-    // again, it is better to leak the aDoomed object than risk crashing as
-    // a result of deleting it on the wrong thread.
-  }
-  return rv;
-}
--- a/xpcom/glue/nsProxyRelease.h
+++ b/xpcom/glue/nsProxyRelease.h
@@ -7,123 +7,133 @@
 #ifndef nsProxyRelease_h__
 #define nsProxyRelease_h__
 
 #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"
 
 #ifdef XPCOM_GLUE_AVOID_NSPR
 #error NS_ProxyRelease implementation depends on NSPR.
 #endif
 
-/**
- * Ensure that a nsCOMPtr is released on the target thread.
- *
- * @see NS_ProxyRelease(nsIEventTarget*, nsISupports*, bool)
- */
+
 template<class T>
-inline NS_HIDDEN_(nsresult)
-NS_ProxyRelease(nsIEventTarget* aTarget, nsCOMPtr<T>& aDoomed,
-                bool aAlwaysProxy = false)
+class nsProxyReleaseEvent : public nsRunnable
 {
-  T* raw = nullptr;
-  aDoomed.swap(raw);
-  return NS_ProxyRelease(aTarget, raw, aAlwaysProxy);
-}
+public:
+  explicit nsProxyReleaseEvent(already_AddRefed<T> aDoomed)
+  : mDoomed(aDoomed.take()) {}
+
+  NS_IMETHOD Run()
+  {
+    if (mDoomed)
+    {
+      NS_RELEASE(mDoomed);
+    }
+    return NS_OK;
+  }
+
+private:
+  T* MOZ_OWNING_REF mDoomed;
+};
 
 /**
- * Ensure that a nsRefPtr is released on the target thread.
- *
- * @see NS_ProxyRelease(nsIEventTarget*, nsISupports*, bool)
- */
-template<class T>
-inline NS_HIDDEN_(nsresult)
-NS_ProxyRelease(nsIEventTarget* aTarget, RefPtr<T>& aDoomed,
-                bool aAlwaysProxy = false)
-{
-  T* raw = nullptr;
-  aDoomed.swap(raw);
-  return NS_ProxyRelease(aTarget, raw, aAlwaysProxy);
-}
-
-/**
- * Ensures that the delete of a nsISupports object occurs on the target thread.
+ * 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
  *        normally, if NS_ProxyRelease is called on the target thread, then the
  *        doomed object will be released directly. However, if this parameter is
  *        true, then an event will always be posted to the target thread for
  *        asynchronous release.
  */
-nsresult
-NS_ProxyRelease(nsIEventTarget* aTarget, nsISupports* aDoomed,
-                bool aAlwaysProxy = false);
-
-/**
- * Ensure that a nsCOMPtr is released on the main thread.
- *
- * @see NS_ReleaseOnMainThread( nsISupports*, bool)
- */
 template<class T>
 inline NS_HIDDEN_(nsresult)
-NS_ReleaseOnMainThread(nsCOMPtr<T>& aDoomed,
-                       bool aAlwaysProxy = false)
+NS_ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed,
+                bool aAlwaysProxy = false)
 {
-  T* raw = nullptr;
-  aDoomed.swap(raw);
-  return NS_ReleaseOnMainThread(raw, aAlwaysProxy);
+  nsresult rv;
+
+  if (!aTarget)
+  {
+    T* doomedPtr = aDoomed.take();
+    if (doomedPtr)
+    {
+      NS_RELEASE(doomedPtr);
+    }
+    return NS_OK;
+  }
+
+  if (!aAlwaysProxy)
+  {
+    bool onCurrentThread = false;
+    rv = aTarget->IsOnCurrentThread(&onCurrentThread);
+    if (NS_SUCCEEDED(rv) && onCurrentThread)
+    {
+      T* doomedPtr = aDoomed.take();
+      if (doomedPtr)
+      {
+        NS_RELEASE(doomedPtr);
+      }
+      return NS_OK;
+    }
+  }
+
+  nsCOMPtr<nsIRunnable> ev = new nsProxyReleaseEvent<T>(mozilla::Move(aDoomed));
+
+  rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv))
+  {
+    NS_WARNING("failed to post proxy release event");
+    // It is better to leak the aDoomed object than risk crashing as
+    // a result of deleting it on the wrong thread.
+  }
+  return rv;
 }
 
 /**
- * Ensure that a nsRefPtr is released on the main thread.
- *
- * @see NS_ReleaseOnMainThread(nsISupports*, bool)
- */
-template<class T>
-inline NS_HIDDEN_(nsresult)
-NS_ReleaseOnMainThread(RefPtr<T>& aDoomed,
-                       bool aAlwaysProxy = false)
-{
-  T* raw = nullptr;
-  aDoomed.swap(raw);
-  return NS_ReleaseOnMainThread(raw, aAlwaysProxy);
-}
-
-/**
- * Ensures that the delete of a nsISupports object occurs on the main thread.
+ * 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
  *        normally, if NS_ReleaseOnMainThread is called on the main thread,
  *        then the doomed object will be released directly. However, if this
  *        parameter is true, then an event will always be posted to the main
  *        thread for asynchronous release.
  */
-inline nsresult
-NS_ReleaseOnMainThread(nsISupports* aDoomed,
+template<class T>
+inline NS_HIDDEN_(nsresult)
+NS_ReleaseOnMainThread(already_AddRefed<T> aDoomed,
                        bool aAlwaysProxy = false)
 {
   // NS_ProxyRelease treats a null event target as "the current thread".  So a
   // handle on the main thread is only necessary when we're not already on the
   // main thread or the release must happen asynchronously.
   nsCOMPtr<nsIThread> mainThread;
   if (!NS_IsMainThread() || aAlwaysProxy) {
-    NS_GetMainThread(getter_AddRefs(mainThread));
+    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
+
+    if (NS_FAILED(rv))
+    {
+      NS_WARNING("Could not get main thread! Leaking.");
+      return rv;
+    }
   }
 
-  return NS_ProxyRelease(mainThread, aDoomed, aAlwaysProxy);
+  return NS_ProxyRelease(mainThread, mozilla::Move(aDoomed), aAlwaysProxy);
 }
 
 /**
  * Class to safely handle main-thread-only pointers off the main thread.
  *
  * Classes like XPCWrappedJS are main-thread-only, which means that it is
  * forbidden to call methods on instances of these classes off the main thread.
  * For various reasons (see bug 771074), this restriction recently began to
@@ -180,23 +190,17 @@ public:
 
 private:
   // We can be released on any thread.
   ~nsMainThreadPtrHolder()
   {
     if (NS_IsMainThread()) {
       NS_IF_RELEASE(mRawPtr);
     } else if (mRawPtr) {
-      nsCOMPtr<nsIThread> mainThread;
-      NS_GetMainThread(getter_AddRefs(mainThread));
-      if (!mainThread) {
-        NS_WARNING("Couldn't get main thread! Leaking pointer.");
-        return;
-      }
-      NS_ProxyRelease(mainThread, mRawPtr);
+      NS_ReleaseOnMainThread(dont_AddRef<T>(mRawPtr));
     }
   }
 
 public:
   T* get()
   {
     // Nobody should be touching the raw pointer off-main-thread.
     if (mStrict && MOZ_UNLIKELY(!NS_IsMainThread())) {
--- a/xpcom/glue/objs.mozbuild
+++ b/xpcom/glue/objs.mozbuild
@@ -34,15 +34,14 @@ 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
 ]
--- a/xpcom/libxpcomrt/moz.build
+++ b/xpcom/libxpcomrt/moz.build
@@ -56,17 +56,16 @@ xpcom_glue_src = [
     'nsCOMPtr.cpp',
     'nsCRTGlue.cpp',
     'nsComponentManagerUtils.cpp',
     'nsEnumeratorUtils.cpp',
     'GenericFactory.cpp',
     'nsID.cpp',
     'nsISupportsImpl.cpp',
     'nsMemory.cpp',
-    'nsProxyRelease.cpp',
     'nsQuickSort.cpp',
     'nsTArray.cpp',
     'nsTObserverArray.cpp',
     'nsThreadUtils.cpp',
     'nsWeakReference.cpp',
     'PLDHashTable.cpp',
 ]
 src_list += [