imported patch releaseMainThread.patch
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 06 Jul 2017 17:36:26 +0200
changeset 1177729 2ff85311295820a50cba38917d4c4fb4eb5f67a7
parent 1177728 24bc2208e2ac7c6fbb1305b35b9a41d8cc0c8cd2
child 1177730 12cea684d3e08effe42c0722bd664cbec820243b
push id202996
push useramarchesini@mozilla.com
push dateThu, 06 Jul 2017 15:55:19 +0000
treeherdertry@601c281e1b1d [default view] [failures only]
milestone56.0a1
imported patch releaseMainThread.patch
dom/base/WebSocket.cpp
dom/base/nsDOMDataChannel.cpp
dom/base/nsDOMDataChannel.h
dom/cache/ManagerId.cpp
dom/console/Console.cpp
dom/filesystem/GetFilesHelper.cpp
dom/media/MediaStreamGraph.cpp
dom/media/webspeech/recognition/SpeechStreamListener.cpp
dom/script/ScriptLoader.cpp
dom/script/ScriptLoader.h
dom/workers/ServiceWorkerJob.cpp
dom/workers/WorkerPrivate.cpp
extensions/spellcheck/src/mozPersonalDictionary.cpp
image/decoders/icon/mac/nsIconChannelCocoa.mm
image/decoders/icon/win/nsIconChannel.cpp
ipc/mscom/MainThreadHandoff.cpp
ipc/mscom/WeakRef.cpp
js/src/devtools/rootAnalysis/analyzeHeapWrites.js
js/xpconnect/loader/ScriptPreloader.cpp
layout/style/URLExtraData.cpp
layout/style/nsStyleStruct.cpp
media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
modules/libjar/nsJARChannel.cpp
netwerk/base/TLSServerSocket.cpp
netwerk/base/nsBaseChannel.cpp
netwerk/base/nsProtocolProxyService.cpp
netwerk/cache2/CacheIndex.h
netwerk/protocol/gio/nsGIOProtocolHandler.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/mozStorageConnection.cpp
storage/mozStorageService.cpp
storage/mozStorageStatementData.h
toolkit/components/osfile/NativeOSFileInternals.cpp
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
xpcom/base/JSObjectHolder.h
xpcom/base/nsConsoleService.cpp
xpcom/threads/nsProxyRelease.h
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -637,18 +637,20 @@ 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("WebSocketImpl::mChannel", mChannel.forget());
-  NS_ReleaseOnMainThread("WebSocketImpl::mService", mService.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketImpl::mChannel",
+                                    mChannel.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketImpl::mService",
+                                    mService.forget());
 
   mWebSocket->DontKeepAliveAnyMore();
   mWebSocket->mImpl = nullptr;
 
   if (mWorkerPrivate && mWorkerHolder) {
     UnregisterWorkerHolder();
   }
 
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -572,37 +572,51 @@ nsDOMDataChannel::UpdateMustKeepAlive()
 
     case DataChannel::CLOSED:
     {
       shouldKeepAlive = false;
     }
   }
 
   if (mSelfRef && !shouldKeepAlive) {
-    // release our self-reference (safely) by putting it in an event (always)
-    NS_ReleaseOnMainThread("nsDOMDataChannel::mSelfRef", mSelfRef.forget(), true);
+    ReleaseSelf();
   } else if (!mSelfRef && shouldKeepAlive) {
     mSelfRef = this;
   }
 }
 
 void
 nsDOMDataChannel::DontKeepAliveAnyMore()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mSelfRef) {
-    // Since we're on MainThread, force an eventloop trip to avoid deleting ourselves.
-    NS_ReleaseOnMainThread("nsDOMDataChannel::mSelfRef", mSelfRef.forget(), true);
+    // Since we're on MainThread, force an eventloop trip to avoid deleting
+    // ourselves.
+    ReleaseSelf();
   }
 
   mCheckMustKeepAlive = false;
 }
 
 void
+nsDOMDataChannel::ReleaseSelf()
+{
+  // release our self-reference (safely) by putting it in an event (always)
+  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetOwner());
+  nsCOMPtr<nsIEventTarget> eventTarget = window
+      ? window->EventTargetFor(TaskCategory::Other)
+      : SystemGroup::EventTargetFor(TaskCategory::Other);
+
+  // release our self-reference (safely) by putting it in an event (always)
+  NS_ProxyRelease("nsDOMDataChannel::mSelfRef", eventTarget,
+                  mSelfRef.forget(), true);
+}
+
+void
 nsDOMDataChannel::EventListenerAdded(nsIAtom* aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   UpdateMustKeepAlive();
 }
 
 void
 nsDOMDataChannel::EventListenerRemoved(nsIAtom* aType)
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -125,16 +125,18 @@ public:
 
 protected:
   ~nsDOMDataChannel();
 
 private:
   void Send(nsIInputStream* aMsgStream, const nsACString& aMsgString,
             uint32_t aMsgLength, bool aIsBinary, mozilla::ErrorResult& aRv);
 
+  void ReleaseSelf();
+
   // to keep us alive while we have listeners
   RefPtr<nsDOMDataChannel> mSelfRef;
   // Owning reference
   RefPtr<mozilla::DataChannel> mDataChannel;
   nsString  mOrigin;
   enum DataChannelBinaryType {
     DC_BINARY_TYPE_ARRAYBUFFER,
     DC_BINARY_TYPE_BLOB,
--- a/dom/cache/ManagerId.cpp
+++ b/dom/cache/ManagerId.cpp
@@ -60,15 +60,15 @@ 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.
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "ManagerId::mPrincipal", mPrincipal.forget());
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -879,22 +879,29 @@ Console::Shutdown()
   }
 
   if (NS_IsMainThread()) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, "inner-window-destroyed");
       obs->RemoveObserver(this, "memory-pressure");
     }
+
+    mStorage = nullptr;
+    mSandbox = nullptr;
+  } else {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+
+    NS_ProxyRelease("Console::mStorage", workerPrivate->MainThreadEventTarget(),
+                    mStorage.forget());
+    NS_ProxyRelease("Console::mSandbox", workerPrivate->MainThreadEventTarget(),
+                    mSandbox.forget());
   }
 
-  NS_ReleaseOnMainThread(
-    "Console::mStorage", mStorage.forget());
-  NS_ReleaseOnMainThread(
-    "Console::mSandbox", mSandbox.forget());
 
   mTimerRegistry.Clear();
   mCounterRegistry.Clear();
 
   mCallDataStorage.Clear();
   mCallDataStoragePending.Clear();
 
   mStatus = eShuttingDown;
--- a/dom/filesystem/GetFilesHelper.cpp
+++ b/dom/filesystem/GetFilesHelper.cpp
@@ -613,17 +613,17 @@ GetFilesHelperParent::GetFilesHelperPare
                                            bool aRecursiveFlag)
   : GetFilesHelper(nullptr, aRecursiveFlag)
   , mContentParent(aContentParent)
   , mUUID(aUUID)
 {}
 
 GetFilesHelperParent::~GetFilesHelperParent()
 {
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "GetFilesHelperParent::mContentParent", mContentParent.forget());
 }
 
 /* static */ already_AddRefed<GetFilesHelperParent>
 GetFilesHelperParent::Create(const nsID& aUUID, const nsAString& aDirectoryPath,
                              bool aRecursiveFlag, ContentParent* aContentParent,
                              ErrorResult& aRv)
 {
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1767,17 +1767,17 @@ MediaStreamGraphImpl::RunInStableState(b
              CurrentDriver()->AsAudioCallbackDriver() ? "AudioDriver"
                                                       : "SystemDriver"));
         RefPtr<GraphDriver> driver = CurrentDriver();
         MonitorAutoUnlock unlock(mMonitor);
         driver->Start();
         // It's not safe to Shutdown() a thread from StableState, and
         // releasing this may shutdown a SystemClockDriver thread.
         // Proxy the release to outside of StableState.
-        NS_ReleaseOnMainThread(
+        NS_ReleaseOnMainThreadSystemGroup(
           "MediaStreamGraphImpl::CurrentDriver", driver.forget(),
           true); // always proxy
       }
     }
 
     if ((mForceShutDown || !mRealtime) &&
         mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
       // Defer calls to RunDuringShutdown() to happen while mMonitor is not held.
--- a/dom/media/webspeech/recognition/SpeechStreamListener.cpp
+++ b/dom/media/webspeech/recognition/SpeechStreamListener.cpp
@@ -14,17 +14,17 @@ namespace dom {
 
 SpeechStreamListener::SpeechStreamListener(SpeechRecognition* aRecognition)
   : mRecognition(aRecognition)
 {
 }
 
 SpeechStreamListener::~SpeechStreamListener()
 {
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "SpeechStreamListener::mRecognition", mRecognition.forget());
 }
 
 void
 SpeechStreamListener::NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
                                             StreamTime aTrackOffset,
                                             const AudioSegment& aQueuedMedia,
                                             MediaStream* aInputStream,
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -1474,28 +1474,37 @@ ScriptLoader::ProcessScriptElement(nsISc
 
 namespace {
 
 class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable
 {
   RefPtr<ScriptLoadRequest> mRequest;
   RefPtr<ScriptLoader> mLoader;
   RefPtr<DocGroup> mDocGroup;
+  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
   void* mToken;
 
 public:
   NotifyOffThreadScriptLoadCompletedRunnable(ScriptLoadRequest* aRequest,
                                              ScriptLoader* aLoader)
     : Runnable("dom::NotifyOffThreadScriptLoadCompletedRunnable")
     , mRequest(aRequest)
     , mLoader(aLoader)
     , mDocGroup(aLoader->GetDocGroup())
     , mToken(nullptr)
   {
     MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsPIDOMWindowInner> window =
+      mLoader->GetDocument()
+        ? mLoader->GetDocument()->GetInnerWindow() : nullptr;
+    mMainThreadEventTarget =
+      window
+        ? window->EventTargetFor(TaskCategory::Other)
+        : SystemGroup::EventTargetFor(TaskCategory::Other);
   }
 
   virtual ~NotifyOffThreadScriptLoadCompletedRunnable();
 
   void SetToken(void* aToken) {
     MOZ_ASSERT(aToken && !mToken);
     mToken = aToken;
   }
@@ -1552,20 +1561,20 @@ ScriptLoader::ProcessOffThreadRequest(Sc
   nsresult rv = ProcessRequest(aRequest);
   mDocument->UnblockOnload(false);
   return rv;
 }
 
 NotifyOffThreadScriptLoadCompletedRunnable::~NotifyOffThreadScriptLoadCompletedRunnable()
 {
   if (MOZ_UNLIKELY(mRequest || mLoader) && !NS_IsMainThread()) {
-    NS_ReleaseOnMainThread(
-      "NotifyOffThreadScriptLoadCompletedRunnable::mRequest", mRequest.forget());
-    NS_ReleaseOnMainThread(
-      "NotifyOffThreadScriptLoadCompletedRunnable::mLoader", mLoader.forget());
+    NS_ProxyRelease("NotifyOffThreadScriptLoadCompletedRunnable::mRequest",
+                    mMainThreadEventTarget, mRequest.forget());
+    NS_ProxyRelease("NotifyOffThreadScriptLoadCompletedRunnable::mLoader",
+                    mMainThreadEventTarget, mLoader.forget());
   }
 }
 
 NS_IMETHODIMP
 NotifyOffThreadScriptLoadCompletedRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -314,16 +314,21 @@ public:
     return mPendingChildLoaders.AppendElement(aChild) != nullptr;
   }
 
   mozilla::dom::DocGroup* GetDocGroup() const
   {
     return mDocument->GetDocGroup();
   }
 
+  nsIDocument* GetDocument() const
+  {
+    return mDocument;
+  }
+
   /**
    * Register the fact that we saw the load event, and that we need to save the
    * bytecode at the next loop cycle unless new scripts are waiting in the
    * pipeline.
    */
   void LoadEventFired();
 
 private:
--- a/dom/workers/ServiceWorkerJob.cpp
+++ b/dom/workers/ServiceWorkerJob.cpp
@@ -227,17 +227,17 @@ ServiceWorkerJob::Finish(ErrorResult& aR
     mFinalCallback = nullptr;
   }
 
   // The callback might not consume the error.
   aRv.SuppressException();
 
   // Async release this object to ensure that our caller methods complete
   // as well.
-  NS_ReleaseOnMainThread("ServiceWorkerJob",
+  NS_ReleaseOnMainThreadSystemGroup("ServiceWorkerJob",
     kungFuDeathGrip.forget(), true /* always proxy */);
 }
 
 void
 ServiceWorkerJob::Finish(nsresult aRv)
 {
   ErrorResult converted(aRv);
   Finish(converted);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4130,17 +4130,17 @@ WorkerDebugger::WorkerDebugger(WorkerPri
 }
 
 WorkerDebugger::~WorkerDebugger()
 {
   MOZ_ASSERT(!mWorkerPrivate);
 
   if (!NS_IsMainThread()) {
     for (size_t index = 0; index < mListeners.Length(); ++index) {
-      NS_ReleaseOnMainThread(
+      NS_ReleaseOnMainThreadSystemGroup(
         "WorkerDebugger::mListeners", mListeners[index].forget());
     }
   }
 }
 
 NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger)
 
 NS_IMETHODIMP
--- a/extensions/spellcheck/src/mozPersonalDictionary.cpp
+++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp
@@ -59,17 +59,17 @@ public:
   {
   }
 
   NS_IMETHOD Run() override
   {
     mDict->SyncLoad();
 
     // Release the dictionary on the main thread
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "mozPersonalDictionaryLoader::mDict",
       mDict.forget().downcast<mozIPersonalDictionary>());
 
     return NS_OK;
   }
 
 private:
   RefPtr<mozPersonalDictionary> mDict;
@@ -133,17 +133,17 @@ 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.
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "mozPersonalDictionarySave::mDict",
       mDict.forget().downcast<mozIPersonalDictionary>());
 
     return NS_OK;
   }
 
 private:
   nsTArray<nsString> mDictWords;
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -34,17 +34,17 @@
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel()
 {
   if (mLoadInfo) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsIconChannel::mLoadInfo", mLoadInfo.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsIconChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIRequestObserver,
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -67,17 +67,17 @@ GetStockIconIDForName(const nsACString& 
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel()
 {
   if (mLoadInfo) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsIconChannel::mLoadInfo", mLoadInfo.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsIconChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIRequestObserver,
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -217,17 +217,17 @@ MainThreadHandoff::Release()
     // If so, we need to dispatch an event to delete ourselves.
     if (NS_IsMainThread()) {
       delete this;
     } else {
       // We need to delete this object on the main thread, but we aren't on the
       // main thread right now, so we send a reference to ourselves to the main
       // thread to be re-released there.
       RefPtr<MainThreadHandoff> self = this;
-      NS_ReleaseOnMainThread(
+      NS_ReleaseOnMainThreadSystemGroup(
         "MainThreadHandoff", self.forget());
     }
   }
   return newRefCnt;
 }
 
 HRESULT
 MainThreadHandoff::FixIServiceProvider(ICallFrame* aFrame)
--- a/ipc/mscom/WeakRef.cpp
+++ b/ipc/mscom/WeakRef.cpp
@@ -163,17 +163,17 @@ WeakReferenceSupport::Release()
   if (newRefCnt == 0) {
     if (mFlags != Flags::eDestroyOnMainThread || NS_IsMainThread()) {
       delete this;
     } else {
       // We need to delete this object on the main thread, but we aren't on the
       // main thread right now, so we send a reference to ourselves to the main
       // thread to be re-released there.
       RefPtr<WeakReferenceSupport> self = this;
-      NS_ReleaseOnMainThread(
+      NS_ReleaseOnMainThreadSystemGroup(
         "WeakReferenceSupport", self.forget());
     }
   }
   return newRefCnt;
 }
 
 HRESULT
 WeakReferenceSupport::GetWeakReference(IWeakReference** aOutWeakRef)
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -366,17 +366,17 @@ function ignoreContents(entry)
         /InvalidArrayIndex_CRASH/,
         /NS_ABORT_OOM/,
 
         // These ought to be threadsafe.
         "NS_DebugBreak",
         /mozalloc_handle_oom/,
         /^NS_Log/, /log_print/, /LazyLogModule::operator/,
         /SprintfLiteral/, "PR_smprintf", "PR_smprintf_free",
-        /NS_DispatchToMainThread/, /NS_ReleaseOnMainThread/,
+        /NS_DispatchToMainThread/, /NS_ReleaseOnMainThreadSystemGroup/,
         /NS_NewRunnableFunction/, /NS_Atomize/,
         /nsCSSValue::BufferFromString/,
         /NS_strdup/,
         /Assert_NoQueryNeeded/,
         /imgRequestProxy::GetProgressTracker/, // Uses an AutoLock
         /Smprintf/,
         "malloc",
         "free",
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -647,17 +647,18 @@ ScriptPreloader::Run()
 
     auto result = WriteCache();
     Unused << NS_WARN_IF(result.isErr());
 
     result = mChildCache->WriteCache();
     Unused << NS_WARN_IF(result.isErr());
 
     mSaveComplete = true;
-    NS_ReleaseOnMainThread("ScriptPreloader::mSaveThread", mSaveThread.forget());
+    NS_ReleaseOnMainThreadSystemGroup("ScriptPreloader::mSaveThread",
+                                      mSaveThread.forget());
 
     mal.NotifyAll();
     return NS_OK;
 }
 
 void
 ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
                             JS::HandleScript jsscript)
--- a/layout/style/URLExtraData.cpp
+++ b/layout/style/URLExtraData.cpp
@@ -27,15 +27,18 @@ URLExtraData::InitDummy()
 URLExtraData::ReleaseDummy()
 {
   sDummy = nullptr;
 }
 
 URLExtraData::~URLExtraData()
 {
   if (!NS_IsMainThread()) {
-    NS_ReleaseOnMainThread("URLExtraData::mBaseURI", mBaseURI.forget());
-    NS_ReleaseOnMainThread("URLExtraData::mReferrer", mReferrer.forget());
-    NS_ReleaseOnMainThread("URLExtraData::mPrincipal", mPrincipal.forget());
+    NS_ReleaseOnMainThreadSystemGroup("URLExtraData::mBaseURI",
+                                      mBaseURI.forget());
+    NS_ReleaseOnMainThreadSystemGroup("URLExtraData::mReferrer",
+                                      mReferrer.forget());
+    NS_ReleaseOnMainThreadSystemGroup("URLExtraData::mPrincipal",
+                                      mPrincipal.forget());
   }
 }
 
 } // namespace mozilla
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3450,29 +3450,29 @@ nsStyleDisplay::nsStyleDisplay(const nsS
 
 nsStyleDisplay::~nsStyleDisplay()
 {
   // We don't allow releasing nsCSSValues with refcounted data in the Servo
   // traversal, since the refcounts aren't threadsafe. Since Servo may trigger
   // the deallocation of style structs during styling, we need to handle it
   // here.
   if (mSpecifiedTransform && ServoStyleSet::IsInServoTraversal()) {
-    // The default behavior of NS_ReleaseOnMainThread is to only proxy the
-    // release if we're not already on the main thread. This is a nice
+    // The default behavior of NS_ReleaseOnMainThreadSystemGroup is to only
+    // proxy the release if we're not already on the main thread. This is a nice
     // optimization for the cases we happen to be doing a sequential traversal
     // (i.e. a single-core machine), but it trips our assertions which check
     // whether we're in a Servo traversal, parallel or not. So we
     // unconditionally proxy in debug builds.
     bool alwaysProxy =
 #ifdef DEBUG
       true;
 #else
       false;
 #endif
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsStyleDisplay::mSpecifiedTransform",
       mSpecifiedTransform.forget(), alwaysProxy);
   }
 
   MOZ_COUNT_DTOR(nsStyleDisplay);
 }
 
 nsChangeHint
@@ -3768,17 +3768,17 @@ nsStyleVisibility::CalcDifference(const 
   return hint;
 }
 
 nsStyleContentData::~nsStyleContentData()
 {
   MOZ_COUNT_DTOR(nsStyleContentData);
 
   if (mType == eStyleContentType_Image) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsStyleContentData::mContent.mImage", dont_AddRef(mContent.mImage));
     mContent.mImage = nullptr;
   } else if (mType == eStyleContentType_Counter ||
              mType == eStyleContentType_Counters) {
     mContent.mCounters->Release();
   } else if (mContent.mString) {
     free(mContent.mString);
   }
@@ -4360,17 +4360,17 @@ nsStyleUIReset::~nsStyleUIReset()
   // See the nsStyleDisplay destructor for why we're doing this.
   if (mSpecifiedWindowTransform && ServoStyleSet::IsInServoTraversal()) {
     bool alwaysProxy =
 #ifdef DEBUG
       true;
 #else
       false;
 #endif
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsStyleUIReset::mSpecifiedWindowTransform",
       mSpecifiedWindowTransform.forget(), alwaysProxy);
   }
 }
 
 nsChangeHint
 nsStyleUIReset::CalcDifference(const nsStyleUIReset& aNewData) const
 {
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -541,17 +541,17 @@ public:
   }
 
 protected:
   virtual ~AudioProxyThread()
   {
     // Conduits must be released on MainThread, and we might have the last reference
     // We don't need to worry about runnables still trying to access the conduit, since
     // the runnables hold a ref to AudioProxyThread.
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AudioProxyThread::mConduit", mConduit.forget());
     MOZ_COUNT_DTOR(AudioProxyThread);
   }
 
   RefPtr<AudioSessionConduit> mConduit;
   nsCOMPtr<nsIEventTarget> mThread;
   // Only accessed on mThread
   nsAutoPtr<AudioPacketizer<int16_t, int16_t>> packetizer_;
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -204,17 +204,18 @@ 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("nsJARChannel::mLoadInfo", mLoadInfo.forget());
+    NS_ReleaseOnMainThreadSystemGroup("nsJARChannel::mLoadInfo",
+                                      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
@@ -353,17 +353,17 @@ TLSServerConnectionInfo::~TLSServerConne
 
   RefPtr<nsITLSServerSecurityObserver> observer;
   {
     MutexAutoLock lock(mLock);
     observer = mSecurityObserver.forget();
   }
 
   if (observer) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "TLSServerConnectionInfo::mSecurityObserver", observer.forget());
   }
 }
 
 NS_IMETHODIMP
 TLSServerConnectionInfo::SetSecurityObserver(nsITLSServerSecurityObserver* aObserver)
 {
   {
--- a/netwerk/base/nsBaseChannel.cpp
+++ b/netwerk/base/nsBaseChannel.cpp
@@ -64,17 +64,17 @@ nsBaseChannel::nsBaseChannel()
   , mContentLength(-1)
   , mWasOpened(false)
 {
   mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
 }
 
 nsBaseChannel::~nsBaseChannel()
 {
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "nsBaseChannel::mLoadInfo", 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
@@ -124,32 +124,32 @@ 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
 
             if (mChannel) {
-                NS_ReleaseOnMainThread(
+                NS_ReleaseOnMainThreadSystemGroup(
                   "nsAsyncResolveRequest::mChannel", mChannel.forget());
             }
 
             if (mCallback) {
-                NS_ReleaseOnMainThread(
+                NS_ReleaseOnMainThreadSystemGroup(
                   "nsAsyncResolveRequest::mCallback", mCallback.forget());
             }
 
             if (mProxyInfo) {
-                NS_ReleaseOnMainThread(
+                NS_ReleaseOnMainThreadSystemGroup(
                   "nsAsyncResolveRequest::mProxyInfo", mProxyInfo.forget());
             }
 
             if (mXPComPPS) {
-                NS_ReleaseOnMainThread(
+                NS_ReleaseOnMainThreadSystemGroup(
                   "nsAsyncResolveRequest::mXPComPPS", mXPComPPS.forget());
             }
         }
     }
 
 public:
     void SetResult(nsresult status, nsIProxyInfo *pi)
     {
@@ -361,17 +361,17 @@ public:
 
         return NS_DispatchToMainThread(event);
     }
 
 private:
     ~AsyncGetPACURIRequest()
     {
         MOZ_ASSERT(NS_IsMainThread() == mIsMainThreadOnly);
-        NS_ReleaseOnMainThread(
+        NS_ReleaseOnMainThreadSystemGroup(
           "AsyncGetPACURIRequest::mServiceHolder", mServiceHolder.forget());
     }
 
     bool mIsMainThreadOnly;
 
     nsProtocolProxyService* mService; // ref-count is hold by mServiceHolder
     nsCOMPtr<nsIProtocolProxyService2> mServiceHolder;
     CallbackFunc mCallback;
--- a/netwerk/cache2/CacheIndex.h
+++ b/netwerk/cache2/CacheIndex.h
@@ -1207,17 +1207,17 @@ private:
   private:
     explicit DiskConsumptionObserver(nsWeakPtr const& aWeakObserver)
       : Runnable("net::CacheIndex::DiskConsumptionObserver")
       , mObserver(aWeakObserver)
     {
     }
     virtual ~DiskConsumptionObserver() {
       if (mObserver && !NS_IsMainThread()) {
-        NS_ReleaseOnMainThread(
+        NS_ReleaseOnMainThreadSystemGroup(
           "DiskConsumptionObserver::mObserver", mObserver.forget());
       }
     }
 
     NS_IMETHOD Run() override
     {
       MOZ_ASSERT(NS_IsMainThread());
 
--- a/netwerk/protocol/gio/nsGIOProtocolHandler.cpp
+++ b/netwerk/protocol/gio/nsGIOProtocolHandler.cpp
@@ -611,17 +611,17 @@ 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) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsGIOInputStream::mChannel", dont_AddRef(mChannel));
 
     mChannel = nullptr;
   }
 
   mSpec.Truncate(); // free memory
 
   // Prevent future reads from re-opening the handle.
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -368,18 +368,18 @@ BaseWebSocketChannel::ListenerAndContext
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mListener);
 }
 
 BaseWebSocketChannel::ListenerAndContextContainer::~ListenerAndContextContainer()
 {
   MOZ_ASSERT(mListener);
 
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "BaseWebSocketChannel::ListenerAndContextContainer::mListener",
     mListener.forget());
-  NS_ReleaseOnMainThread(
+  NS_ReleaseOnMainThreadSystemGroup(
     "BaseWebSocketChannel::ListenerAndContextContainer::mContext",
     mContext.forget());
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1228,24 +1228,28 @@ 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("WebSocketChannel::mURI", mURI.forget());
-  NS_ReleaseOnMainThread("WebSocketChannel::mOriginalURI", mOriginalURI.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mURI", mURI.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mOriginalURI",
+                                    mOriginalURI.forget());
 
   mListenerMT = nullptr;
 
-  NS_ReleaseOnMainThread("WebSocketChannel::mLoadGroup", mLoadGroup.forget());
-  NS_ReleaseOnMainThread("WebSocketChannel::mLoadInfo", mLoadInfo.forget());
-  NS_ReleaseOnMainThread("WebSocketChannel::mService", mService.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mLoadGroup",
+                                    mLoadGroup.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mLoadInfo",
+                                    mLoadInfo.forget());
+  NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mService",
+                                    mService.forget());
 }
 
 NS_IMETHODIMP
 WebSocketChannel::Observe(nsISupports *subject,
                           const char *topic,
                           const char16_t *data)
 {
   LOG(("WebSocketChannel::Observe [topic=\"%s\"]\n", topic));
@@ -2370,20 +2374,24 @@ WebSocketChannel::StopSession(nsresult r
 
   // normally this should be called on socket thread, but it is ok to call it
   // from OnStartRequest before the socket thread machine has gotten underway
 
   mStopped = 1;
 
   if (!mOpenedHttpChannel) {
     // The HTTP channel information will never be used in this case
-    NS_ReleaseOnMainThread("WebSocketChannel::mChannel", mChannel.forget());
-    NS_ReleaseOnMainThread("WebSocketChannel::mHttpChannel", mHttpChannel.forget());
-    NS_ReleaseOnMainThread("WebSocketChannel::mLoadGroup", mLoadGroup.forget());
-    NS_ReleaseOnMainThread("WebSocketChannel::mCallbacks", mCallbacks.forget());
+    NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mChannel",
+                                      mChannel.forget());
+    NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mHttpChannel",
+                                      mHttpChannel.forget());
+    NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mLoadGroup",
+                                      mLoadGroup.forget());
+    NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mCallbacks",
+                                      mCallbacks.forget());
   }
 
   if (mCloseTimer) {
     mCloseTimer->Cancel();
     mCloseTimer = nullptr;
   }
 
   if (mOpenTimer) {
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -61,17 +61,17 @@ WyciwygChannelChild::WyciwygChannelChild
   // IPDL holds a reference until IPDL channel gets destroyed
   AddIPDLReference();
 }
 
 WyciwygChannelChild::~WyciwygChannelChild()
 {
   LOG(("Destroying WyciwygChannelChild @%p\n", this));
   if (mLoadInfo) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "WyciwygChannelChild::mLoadInfo", mLoadInfo.forget());
   }
 }
 
 void
 WyciwygChannelChild::AddIPDLReference()
 {
   MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -42,17 +42,17 @@ nsWyciwygChannel::nsWyciwygChannel()
     mLoadFlags(LOAD_NORMAL),
     mNeedToSetSecurityInfo(false)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
   if (mLoadInfo) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsWyciwygChannel::mLoadInfo", mLoadInfo.forget(), false);
   }
 }
 
 NS_IMPL_ISUPPORTS(nsWyciwygChannel,
                   nsIChannel,
                   nsIRequest,
                   nsIStreamListener,
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -2414,17 +2414,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_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "DataChannelBlobSendRunnable", runnable.forget());
     return;
   }
   aBlob->Close();
   Dispatch(runnable.forget());
 }
 
 void
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -562,17 +562,18 @@ nsHTTPListener::~nsHTTPListener()
   if (mResponsibleForDoneSignal)
     send_done_signal();
 
   if (mResultData) {
     free(const_cast<uint8_t *>(mResultData));
   }
 
   if (mLoader) {
-    NS_ReleaseOnMainThread("nsHTTPListener::mLoader", mLoader.forget());
+    NS_ReleaseOnMainThreadSystemGroup("nsHTTPListener::mLoader",
+                                      mLoader.forget());
   }
 }
 
 NS_IMPL_ISUPPORTS(nsHTTPListener, nsIStreamLoaderObserver)
 
 void
 nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
 {
--- a/storage/mozStorageConnection.cpp
+++ b/storage/mozStorageConnection.cpp
@@ -404,19 +404,19 @@ public:
       (void)NS_GetMainThread(getter_AddRefs(thread));
       (void)thread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
     }
 
     return NS_OK;
   }
 
   ~AsyncCloseConnection() override {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AsyncCloseConnection::mConnection", mConnection.forget());
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AsyncCloseConnection::mCallbackEvent", mCallbackEvent.forget());
   }
 private:
   RefPtr<Connection> mConnection;
   sqlite3 *mNativeConnection;
   nsCOMPtr<nsIRunnable> mCallbackEvent;
 };
 
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -710,25 +710,25 @@ private:
       new CallbackComplete(aStatus,
                            aValue,
                            mCallback.forget());
     return NS_DispatchToMainThread(event);
   }
 
   ~AsyncInitDatabase()
   {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AsyncInitDatabase::mStorageFile", mStorageFile.forget());
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AsyncInitDatabase::mConnection", 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.
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "AsyncInitDatabase::mCallback", mCallback.forget());
   }
 
   RefPtr<Connection> mConnection;
   nsCOMPtr<nsIFile> mStorageFile;
   int32_t mGrowthIncrement;
   RefPtr<mozIStorageCompletionCallback> mCallback;
 };
--- a/storage/mozStorageStatementData.h
+++ b/storage/mozStorageStatementData.h
@@ -47,17 +47,18 @@ 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.
-    NS_ReleaseOnMainThread("StatementData::mParamsArray", mParamsArray.forget());
+    NS_ReleaseOnMainThreadSystemGroup("StatementData::mParamsArray",
+                                      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
@@ -525,34 +525,36 @@ 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.
-      NS_ReleaseOnMainThread("AbstractDoEvent::ErrorEvent", event.forget());
+      NS_ReleaseOnMainThreadSystemGroup("AbstractDoEvent::ErrorEvent",
+                                        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.
-      NS_ReleaseOnMainThread("AbstractDoEvent::SuccessEvent", event.forget());
+      NS_ReleaseOnMainThreadSystemGroup("AbstractDoEvent::SuccessEvent",
+                                        event.forget());
     }
 
   }
 
 private:
 
   /**
    * Mark the event as complete, for debugging purposes.
@@ -743,17 +745,18 @@ public:
   { }
 
   ~DoReadToTypedArrayEvent() override {
     // If AbstractReadEvent::Run() has bailed out, we may need to cleanup
     // mResult, which is main-thread only data
     if (!mResult) {
       return;
     }
-    NS_ReleaseOnMainThread("DoReadToTypedArrayEvent::mResult", mResult.forget());
+    NS_ReleaseOnMainThreadSystemGroup("DoReadToTypedArrayEvent::mResult",
+                                      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());
@@ -780,17 +783,18 @@ public:
   { }
 
   ~DoReadToStringEvent() override {
     // If AbstraactReadEvent::Run() has bailed out, we may need to cleanup
     // mResult, which is main-thread only data
     if (!mResult) {
       return;
     }
-    NS_ReleaseOnMainThread("DoReadToStringEvent::mResult", mResult.forget());
+    NS_ReleaseOnMainThreadSystemGroup("DoReadToStringEvent::mResult",
+                                      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());
     const Encoding* encoding = Encoding::ForLabel(mEncoding);
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -1047,17 +1047,17 @@ private:
 
 NS_IMPL_ISUPPORTS(nsUrlClassifierLookupCallback,
                   nsIUrlClassifierLookupCallback,
                   nsIUrlClassifierHashCompleterCallback)
 
 nsUrlClassifierLookupCallback::~nsUrlClassifierLookupCallback()
 {
   if (mCallback) {
-    NS_ReleaseOnMainThread(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsUrlClassifierLookupCallback::mCallback", mCallback.forget());
   }
 }
 
 NS_IMETHODIMP
 nsUrlClassifierLookupCallback::LookupComplete(nsTArray<LookupResult>* results)
 {
   NS_ASSERTION(mResults == nullptr,
--- a/xpcom/base/JSObjectHolder.h
+++ b/xpcom/base/JSObjectHolder.h
@@ -16,17 +16,18 @@ namespace mozilla {
 // a JS Object from another thread. If they are both on the same thread, the
 // owning class should instead be made a cycle collected SCRIPT_HOLDER class.
 // This object should only be AddRefed and Released on the same thread as
 // mJSObject.
 //
 // Note that this keeps alive the JS object until it goes away, so be sure not to
 // create cycles that keep alive the holder.
 //
-// JSObjectHolder is ISupports to make it usable with NS_ReleaseOnMainThread.
+// JSObjectHolder is ISupports to make it usable with
+// NS_ReleaseOnMainThreadSystemGroup.
 class JSObjectHolder final : public nsISupports
 {
 public:
   JSObjectHolder(JSContext* aCx, JSObject* aObject) : mJSObject(aCx, aObject) {}
 
   NS_DECL_ISUPPORTS
 
   JSObject* GetJSObject() { return mJSObject; }
--- a/xpcom/base/nsConsoleService.cpp
+++ b/xpcom/base/nsConsoleService.cpp
@@ -318,17 +318,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(
+    NS_ReleaseOnMainThreadSystemGroup(
       "nsConsoleService::retiredMessage", retiredMessage.forget());
   }
 
   if (!r) {
     return NS_OK;
   }
 
   if (NS_IsMainThread()) {
--- a/xpcom/threads/nsProxyRelease.h
+++ b/xpcom/threads/nsProxyRelease.h
@@ -121,16 +121,18 @@ struct ProxyReleaseChooser<true>
                                     bool aAlwaysProxy);
 };
 
 } // namespace detail
 
 /**
  * Ensures that the delete of a smart pointer occurs on the target thread.
  *
+ * @param aName
+ *        the labelling name of the runnable involved in the releasing
  * @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
@@ -143,72 +145,57 @@ NS_ProxyRelease(const char* aName, nsIEv
 {
   ::detail::ProxyReleaseChooser<mozilla::IsBaseOf<nsISupports, T>::value>
     ::ProxyRelease(aName, aTarget, mozilla::Move(aDoomed), aAlwaysProxy);
 }
 
 /**
  * Ensures that the delete of a smart pointer occurs on the main thread.
  *
+ * @param aName
+ *        the labelling name of the runnable involved in the releasing
  * @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.
+ *        normally, if NS_ReleaseOnMainThreadSystemGroup 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.
  */
 template<class T>
 inline NS_HIDDEN_(void)
-NS_ReleaseOnMainThread(const char* aName,
-                       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) {
-    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
-
-    if (NS_FAILED(rv)) {
-      MOZ_ASSERT_UNREACHABLE("Could not get main thread; leaking an object!");
-      mozilla::Unused << aDoomed.take();
-      return;
-    }
-  }
-
-  NS_ProxyRelease(aName, mainThread, mozilla::Move(aDoomed), aAlwaysProxy);
-}
-
-/**
- * This is the same as NS_ReleaseOnMainThread, except that the
- * runnable for the deletion will be dispatched to the system group.
- */
-template<class T>
-inline NS_HIDDEN_(void)
-NS_ReleaseOnMainThreadSystemGroup(already_AddRefed<T> aDoomed,
+NS_ReleaseOnMainThreadSystemGroup(const char* aName,
+                                  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<nsIEventTarget> systemGroupEventTarget;
   if (!NS_IsMainThread() || aAlwaysProxy) {
     systemGroupEventTarget = mozilla::SystemGroup::EventTargetFor(mozilla::TaskCategory::Other);
 
     if (!systemGroupEventTarget) {
       MOZ_ASSERT_UNREACHABLE("Could not get main thread; leaking an object!");
       mozilla::Unused << aDoomed.take();
       return;
     }
   }
 
-  NS_ProxyRelease("NS_ReleaseOnMainThreadSystemGroup", systemGroupEventTarget,
-                  mozilla::Move(aDoomed), aAlwaysProxy);
+  NS_ProxyRelease(aName, systemGroupEventTarget, mozilla::Move(aDoomed),
+                  aAlwaysProxy);
+}
+
+template<class T>
+inline NS_HIDDEN_(void)
+NS_ReleaseOnMainThreadSystemGroup(already_AddRefed<T> aDoomed,
+                                  bool aAlwaysProxy = false)
+{
+  NS_ReleaseOnMainThreadSystemGroup("NS_ReleaseOnMainThreadSystemGroup",
+                                    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