Bug 1164581 - Adding an overload for NS_ProxyRelease that accepts already_AddRefed, and removing all the others. r=bobbyholley
☠☠ backed out by a71b79b9c3ef ☠ ☠
authorAidin Gharibnavaz <aidin@aidinhut.com>
Sun, 07 Feb 2016 10:56:00 +0100
changeset 319814 c18e29c1b369e431a40fd079cdbbc39f0b909423
parent 319813 89670b4ab9f3e2edb1779bd154c7d115c1471b96
child 319815 d6c0d17c38bfef0fa46241001c85e2da6beff730
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobbyholley
bugs1164581
milestone47.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 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
@@ -773,21 +773,21 @@ Console::Console(nsPIDOMWindowInner* aWi
 }
 
 Console::~Console()
 {
   MOZ_ASSERT(mConsoleCallDataArray.IsEmpty());
 
   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
@@ -624,18 +624,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(mService.forget());
 
   mWebSocket->DontKeepAliveAnyMore();
   mWebSocket->mImpl = nullptr;
 
   if (mWorkerPrivate && mWorkerFeature) {
     UnregisterFeature();
   }
 
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -777,27 +777,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
@@ -3711,18 +3711,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
@@ -3621,27 +3621,18 @@ WorkerDebugger::WorkerDebugger(WorkerPri
   AssertIsOnMainThread();
 }
 
 WorkerDebugger::~WorkerDebugger()
 {
   MOZ_ASSERT(!mWorkerPrivate);
 
   if (!NS_IsMainThread()) {
-    nsCOMPtr<nsIThread> mainThread;
-    if (NS_FAILED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
-      NS_WARNING("Failed to proxy release of listeners, leaking instead!");
-    }
-
     for (size_t index = 0; index < mListeners.Length(); ++index) {
-      nsIWorkerDebuggerListener* listener = nullptr;
-      mListeners[index].forget(&listener);
-      if (NS_FAILED(NS_ProxyRelease(mainThread, listener))) {
-        NS_WARNING("Failed to proxy release of listener, leaking instead!");
-      }
+      NS_ReleaseOnMainThread(mListeners[index].forget());
     }
   }
 }
 
 NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger)
 
 NS_IMETHODIMP
 WorkerDebugger::GetIsClosed(bool* aResult)
@@ -4153,21 +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))) {
-        NS_WARNING("Failed to proxy release of channel, leaking instead!");
-      }
+      NS_ReleaseOnMainThread(loadInfo.mChannel.forget());
       return NS_ERROR_FAILURE;
     }
 
     loadInfo.mDomain = aParent->Domain();
     loadInfo.mFromWindow = aParent->IsFromWindow();
     loadInfo.mWindowID = aParent->WindowID();
     loadInfo.mStorageAllowed = aParent->IsStorageAllowed();
     loadInfo.mPrivateBrowsing = aParent->IsInPrivateBrowsing();
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -610,27 +610,20 @@ nsGIOInputStream::Close()
   {
     // Destroy the list of GIOFileInfo objects...
     g_list_foreach(mDirList, (GFunc) g_object_unref, nullptr);
     g_list_free(mDirList);
     mDirList = nullptr;
     mDirListPtr = nullptr;
   }
 
-  if (mChannel)
-  {
-    nsresult rv = NS_OK;
+  if (mChannel) {
+    NS_ReleaseOnMainThread(dont_AddRef(mChannel));
 
-    nsCOMPtr<nsIThread> thread = do_GetMainThread();
-    if (thread)
-      rv = NS_ProxyRelease(thread, mChannel);
-
-    NS_ASSERTION(thread && 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))
     mStatus = NS_BASE_STREAM_CLOSED;
 
--- 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,17 @@ 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");
-    }
+    NS_ReleaseOnMainThread(mImage.forget());
   }
 }
 
 /*
  * 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
@@ -1124,20 +1124,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
@@ -209,17 +209,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
@@ -324,26 +324,24 @@ TLSServerConnectionInfo::TLSServerConnec
 }
 
 TLSServerConnectionInfo::~TLSServerConnectionInfo()
 {
   if (!mSecurityObserver) {
     return;
   }
 
-  nsITLSServerSecurityObserver* observer;
+  RefPtr<nsITLSServerSecurityObserver> observer;
   {
     MutexAutoLock lock(mLock);
-    mSecurityObserver.forget(&observer);
+    observer = mSecurityObserver.forget();
   }
 
   if (observer) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-    NS_ProxyRelease(mainThread, observer);
+    NS_ReleaseOnMainThread(observer.forget());
   }
 }
 
 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,27 @@ nsServerSocket::OnSocketDetached(PRFileD
     mFD = nullptr;
   }
 
   if (mListener)
   {
     mListener->OnStopListening(this, mCondition);
 
     // need to atomically clear mListener.  see our Close() method.
-    nsIServerSocketListener *listener = nullptr;
+    RefPtr<nsIServerSocketListener> listener = nullptr;
     {
       MutexAutoLock lock(mLock);
-      mListener.swap(listener);
+      listener = mListener.forget();
     }
+
     // XXX we need to proxy the release to the listener's target thread to work
     // around bug 337492.
-    if (listener)
-      NS_ProxyRelease(mListenerTarget, listener);
+    if (listener) {
+      NS_ProxyRelease(mListenerTarget, listener.forget());
+    }
   }
 }
 
 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,17 @@ 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;
-        mSink.swap(sink);
-        if (NS_FAILED(NS_ProxyRelease(mEventTarget, sink))) {
-            NS_WARNING("Releasing sink on the current thread!");
-            NS_RELEASE(sink);
-        }
+      NS_ProxyRelease(mEventTarget, mSink.forget());
     }
     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, dont_AddRef(mSink));
     }
 
 public:
     nsITransportEventSink           *mSink;
     nsCOMPtr<nsIEventTarget>         mTarget;
     Mutex                            mLock;
     nsTransportStatusEvent          *mLastEvent;
 };
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -518,26 +518,23 @@ nsUDPSocket::OnSocketDetached(PRFileDesc
     NS_ASSERTION(mFD == fd, "wrong file descriptor");
     CloseSocket();
   }
   SaveNetworkStats(true);
 
   if (mListener)
   {
     // need to atomically clear mListener.  see our Close() method.
-    nsCOMPtr<nsIUDPSocketListener> listener;
+    RefPtr<nsIUDPSocketListener> listener = nullptr;
     {
       MutexAutoLock lock(mLock);
-      mListener.swap(listener);
+      listener = mListener.forget();
     }
 
-    if (listener) {
-      listener->OnStopListening(this, mCondition);
-      NS_ProxyRelease(mListenerTarget, listener);
-    }
+    NS_ProxyRelease(mListenerTarget, listener.forget());
   }
 }
 
 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, dont_AddRef(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
@@ -378,20 +378,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,45 +102,20 @@ RemoteOpenFileChild::RemoteOpenFileChild
 
 RemoteOpenFileChild::~RemoteOpenFileChild()
 {
   if (NS_IsMainThread()) {
     if (mListener) {
       NotifyListener(NS_ERROR_UNEXPECTED);
     }
   } else {
-    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!");
-
-      Unused << mURI.forget();
-      Unused << mAppURI.forget();
-      Unused << mListener.forget();
-      Unused << mTabChild.forget();
-    }
+    NS_ReleaseOnMainThread(mURI.forget(), true);
+    NS_ReleaseOnMainThread(mAppURI.forget(), true);
+    NS_ReleaseOnMainThread(mListener.forget(), true);
+    NS_ReleaseOnMainThread(mTabChild.forget(), true);
   }
 
   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
@@ -122,17 +122,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(mService.forget());
 }
 
 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
@@ -40,20 +40,22 @@ public:
   : mStatement(aStatement)
   , mConnection(aConnection)
   {
   }
 
   NS_IMETHOD Run()
   {
     if (mStatement->mAsyncStatement) {
-      (void)::sqlite3_finalize(mStatement->mAsyncStatement);
+      sqlite3_finalize(mStatement->mAsyncStatement);
       mStatement->mAsyncStatement = nullptr;
     }
-    (void)::NS_ProxyRelease(mConnection->threadOpenedOn, mStatement);
+
+    nsCOMPtr<nsIThread> targetThread(mConnection->threadOpenedOn);
+    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,18 @@ 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);
+    NS_ProxyRelease(targetThread, mDBConnection.forget());
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsISupports
 
 NS_IMPL_ADDREF(AsyncStatement)
 NS_IMPL_RELEASE(AsyncStatement)
--- a/storage/mozStorageConnection.cpp
+++ b/storage/mozStorageConnection.cpp
@@ -377,25 +377,18 @@ public:
       (void)NS_GetMainThread(getter_AddRefs(thread));
       (void)thread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
     }
 
     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_ReleaseOnMainThread(mConnection.forget());
+    NS_ReleaseOnMainThread(mCallbackEvent.forget());
   }
 private:
   RefPtr<Connection> mConnection;
   sqlite3 *mNativeConnection;
   nsCOMPtr<nsIRunnable> mCallbackEvent;
   nsCOMPtr<nsIThread> mAsyncExecutionThread;
 };
 
@@ -447,32 +440,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));
+    NS_ReleaseOnMainThread(mStorageFile.forget());
+    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);
+    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);
+    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
@@ -731,17 +731,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,116 @@
 #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()
+  {
+    NS_IF_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);
+template<class T>
+inline NS_HIDDEN_(void)
+NS_ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed,
+                bool aAlwaysProxy = false)
+{
+  // Auto-managing release of the pointer.
+  RefPtr<T> doomed = aDoomed;
+  nsresult rv;
+
+  if (!doomed || !aTarget) {
+    return;
+  }
 
-/**
- * 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)
-{
-  T* raw = nullptr;
-  aDoomed.swap(raw);
-  return NS_ReleaseOnMainThread(raw, aAlwaysProxy);
+  if (!aAlwaysProxy) {
+    bool onCurrentThread = false;
+    rv = aTarget->IsOnCurrentThread(&onCurrentThread);
+    if (NS_SUCCEEDED(rv) && onCurrentThread) {
+      return;
+    }
+  }
+
+  nsCOMPtr<nsIRunnable> ev = new nsProxyReleaseEvent<T>(doomed.forget());
+
+  rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to post proxy release event, leaking!");
+    // It is better to leak the aDoomed object than risk crashing as
+    // a result of deleting it on the wrong thread.
+  }
 }
 
 /**
- * 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_(void)
+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;
+    }
   }
 
-  return NS_ProxyRelease(mainThread, aDoomed, aAlwaysProxy);
+  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 +173,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(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 += [