Backout rev 5c7368370ff9 to 980659720b86 (bug 1300118 and bug 1300658) for incorrect bug number in commit message. r=me
authorBen Kelly <ben@wanderview.com>
Mon, 12 Sep 2016 12:29:17 -0700
changeset 354869 f2fd5c60f2b6591314e16faa01f03cd18455d41a
parent 354868 e4471e0566270a408bb4ad201ca32633ace2a293
child 354870 e40df52925d5c9b677d194e225babe9991cf709c
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1300118, 1300658
milestone51.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
Backout rev 5c7368370ff9 to 980659720b86 (bug 1300118 and bug 1300658) for incorrect bug number in commit message. r=me
dom/fetch/Fetch.cpp
dom/media/fmp4/MP4Decoder.cpp
dom/media/mediasource/AutoTaskQueue.h
dom/workers/ServiceWorkerClient.cpp
dom/workers/ServiceWorkerClients.cpp
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/ServiceWorkerWindowClient.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerRunnable.cpp
dom/workers/WorkerScope.cpp
dom/workers/test/test_consoleAndBlobs.html
dom/workers/test/worker_consoleAndBlobs.js
dom/xhr/XMLHttpRequestWorker.cpp
xpcom/tests/gtest/TestStateWatching.cpp
xpcom/threads/AbstractThread.cpp
xpcom/threads/SharedThreadPool.h
xpcom/threads/TaskQueue.cpp
xpcom/threads/TaskQueue.h
xpcom/threads/nsIEventTarget.idl
xpcom/threads/nsThread.cpp
xpcom/threads/nsThreadPool.cpp
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -260,17 +260,17 @@ FetchRequest(nsIGlobalObject* aGlobal, c
     RefPtr<WorkerFetchResolver> resolver = WorkerFetchResolver::Create(worker, p);
     if (!resolver) {
       NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker");
       aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
       return nullptr;
     }
 
     RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(resolver, r);
-    worker->DispatchToMainThread(run.forget());
+    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(run));
   }
 
   return p.forget();
 }
 
 MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise)
   : mPromise(aPromise)
 {
@@ -1027,22 +1027,17 @@ FetchBody<Derived>::BeginConsumeBody()
 
   // The FetchBody is not thread-safe refcounted. We addref it here and release
   // it once the stream read is finished.
   if (!AddRefObject()) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable<Derived>(this);
-  nsresult rv = NS_OK;
-  if (mWorkerPrivate) {
-    rv = mWorkerPrivate->DispatchToMainThread(r.forget());
-  } else {
-    rv = NS_DispatchToMainThread(r.forget());
-  }
+  nsresult rv = NS_DispatchToMainThread(r);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ReleaseObject();
     return rv;
   }
   return NS_OK;
 }
 
 /*
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -8,17 +8,16 @@
 #include "MediaDecoderStateMachine.h"
 #include "MP4Demuxer.h"
 #include "mozilla/Preferences.h"
 #include "nsCharSeparatedTokenizer.h"
 #ifdef MOZ_EME
 #include "mozilla/CDMProxy.h"
 #endif
 #include "mozilla/Logging.h"
-#include "mozilla/SharedThreadPool.h"
 #include "nsMimeTypes.h"
 #include "nsContentTypeParser.h"
 #include "VideoUtils.h"
 
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
 #ifdef MOZ_WIDGET_ANDROID
--- a/dom/media/mediasource/AutoTaskQueue.h
+++ b/dom/media/mediasource/AutoTaskQueue.h
@@ -3,17 +3,16 @@
 /* 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/. */
 
 #ifndef MOZILLA_AUTOTASKQUEUE_H_
 #define MOZILLA_AUTOTASKQUEUE_H_
 
 #include "mozilla/RefPtr.h"
-#include "mozilla/SharedThreadPool.h"
 #include "mozilla/TaskQueue.h"
 
 namespace mozilla {
 
 // A convenience TaskQueue not requiring explicit shutdown.
 class AutoTaskQueue : public AbstractThread
 {
 public:
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -226,14 +226,14 @@ ServiceWorkerClient::PostMessage(JSConte
   RefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
     new ServiceWorkerClientPostMessageRunnable(mWindowId);
 
   runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  aRv = workerPrivate->DispatchToMainThread(runnable.forget());
+  aRv = NS_DispatchToMainThread(runnable);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 }
 
--- a/dom/workers/ServiceWorkerClients.cpp
+++ b/dom/workers/ServiceWorkerClients.cpp
@@ -670,17 +670,17 @@ ServiceWorkerClients::Get(const nsAStrin
     PromiseWorkerProxy::Create(workerPrivate, promise);
   if (!promiseProxy) {
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     return promise.forget();
   }
 
   RefPtr<GetRunnable> r =
     new GetRunnable(promiseProxy, aClientId);
-  MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
                                ErrorResult& aRv)
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
@@ -706,17 +706,17 @@ ServiceWorkerClients::MatchAll(const Cli
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     return promise.forget();
   }
 
   RefPtr<MatchAllRunnable> r =
     new MatchAllRunnable(promiseProxy,
                          NS_ConvertUTF16toUTF8(scope),
                          aOptions.mIncludeUncontrolled);
-  MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
                                  ErrorResult& aRv)
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
@@ -747,17 +747,17 @@ ServiceWorkerClients::OpenWindow(const n
     return nullptr;
   }
 
   nsString scope;
   mWorkerScope->GetScope(scope);
 
   RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy,
                                                           aUrl, scope);
-  MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerClients::Claim(ErrorResult& aRv)
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
@@ -776,11 +776,11 @@ ServiceWorkerClients::Claim(ErrorResult&
   }
 
   nsString scope;
   mWorkerScope->GetScope(scope);
 
   RefPtr<ClaimRunnable> runnable =
     new ClaimRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope));
 
-  MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(runnable.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
   return promise.forget();
 }
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -389,23 +389,17 @@ void RespondWithCopyComplete(void* aClos
                                       NS_ERROR_INTERCEPTION_FAILED);
   } else {
     event = new FinishResponse(data->mInterceptedChannel,
                                data->mInternalResponse,
                                data->mWorkerChannelInfo,
                                data->mScriptSpec,
                                data->mResponseURLSpec);
   }
-  // In theory this can happen after the worker thread is terminated.
-  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
-  if (worker) {
-    MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(event.forget()));
-  } else {
-    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event.forget()));
-  }
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event));
 }
 
 namespace {
 
 void
 ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
                   nsACString& aSourceSpecOut, uint32_t *aLineOut,
                   uint32_t *aColumnOut, nsString& aMessageOut)
@@ -725,23 +719,17 @@ RespondWithHandler::RejectedCallback(JSC
   CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
 }
 
 void
 RespondWithHandler::CancelRequest(nsresult aStatus)
 {
   nsCOMPtr<nsIRunnable> runnable =
     new CancelChannelRunnable(mInterceptedChannel, mRegistration, aStatus);
-  // Note, this may run off the worker thread during worker termination.
-  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
-  if (worker) {
-    MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(runnable.forget()));
-  } else {
-    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget()));
-  }
+  NS_DispatchToMainThread(runnable);
   mRequestWasHandled = true;
 }
 
 } // namespace
 
 void
 FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
 {
@@ -864,18 +852,18 @@ public:
 
     // only use the extracted location if we found one
     if (!spec.IsEmpty()) {
       mSourceSpec = spec;
       mLine = line;
       mColumn = column;
     }
 
-    MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(
-        NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread)));
+    MOZ_ALWAYS_SUCCEEDS(
+      NS_DispatchToMainThread(NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread)));
   }
 
   void
   ReportOnMainThread()
   {
     AssertIsOnMainThread();
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -207,17 +207,17 @@ public:
 private:
   void
   Done(bool aResult)
   {
 #ifdef DEBUG
     mDone = true;
 #endif
     mCallback->SetResult(aResult);
-    MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mCallback));
+    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback));
   }
 };
 
 } // anonymous namespace
 
 nsresult
 ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback)
 {
@@ -490,17 +490,17 @@ public:
     MOZ_ASSERT(aRegistration);
   }
 
   void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
   {
     nsCOMPtr<nsIRunnable> runnable =
       new RegistrationUpdateRunnable(mRegistration, true /* time check */);
-    aWorkerPrivate->DispatchToMainThread(runnable.forget());
+    NS_DispatchToMainThread(runnable.forget());
 
     ExtendableEventWorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
   }
 };
 
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
@@ -530,17 +530,17 @@ public:
     MOZ_ASSERT(aWorkerPrivate);
     return DispatchLifecycleEvent(aCx, aWorkerPrivate);
   }
 
   nsresult
   Cancel() override
   {
     mCallback->SetResult(false);
-    MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mCallback));
+    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback));
 
     return WorkerRunnable::Cancel();
   }
 
 private:
   bool
   DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
 
@@ -626,17 +626,17 @@ public:
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     if (mDone) {
       return;
     }
     mDone = true;
 
     mCallback->SetResult(aResult);
-    nsresult rv = mWorkerPrivate->DispatchToMainThread(mCallback);
+    nsresult rv = NS_DispatchToMainThread(mCallback);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       NS_RUNTIMEABORT("Failed to dispatch life cycle event handler.");
     }
 
     ReleaseWorker();
   }
 
   void
@@ -757,29 +757,28 @@ public:
 
   void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   {
     Report(nsIPushErrorReporter::DELIVERY_UNHANDLED_REJECTION);
   }
 
   void Report(uint16_t aReason = nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR)
   {
-    WorkerPrivate* workerPrivate = mWorkerPrivate;
     mWorkerPrivate->AssertIsOnWorkerThread();
     mWorkerPrivate = nullptr;
 
     if (NS_WARN_IF(aReason > nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR) ||
         mMessageId.IsEmpty()) {
       return;
     }
     nsCOMPtr<nsIRunnable> runnable =
       NewRunnableMethod<uint16_t>(this,
         &PushErrorReporter::ReportOnMainThread, aReason);
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-      workerPrivate->DispatchToMainThread(runnable.forget())));
+      NS_DispatchToMainThread(runnable.forget())));
   }
 
   void ReportOnMainThread(uint16_t aReason)
   {
     AssertIsOnMainThread();
     nsCOMPtr<nsIPushErrorReporter> reporter =
       do_GetService("@mozilla.org/push/Service;1");
     if (reporter) {
@@ -1416,17 +1415,17 @@ public:
     MOZ_ASSERT(aWorkerPrivate);
     return DispatchFetchEvent(aCx, aWorkerPrivate);
   }
 
   nsresult
   Cancel() override
   {
     nsCOMPtr<nsIRunnable> runnable = new ResumeRequest(mInterceptedChannel);
-    if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable))) {
+    if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       NS_WARNING("Failed to resume channel on FetchEventRunnable::Cancel()!\n");
     }
     WorkerRunnable::Cancel();
     return NS_OK;
   }
 
 private:
   ~FetchEventRunnable() {}
@@ -1530,17 +1529,17 @@ private:
       }
 
       if (!runnable) {
         runnable = new CancelChannelRunnable(mInterceptedChannel,
                                              mRegistration,
                                              NS_ERROR_INTERCEPTION_FAILED);
       }
 
-      MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
+      MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
     }
 
     RefPtr<Promise> waitUntilPromise = event->GetPromise();
     if (waitUntilPromise) {
       KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
                                                  waitUntilPromise);
     }
 
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -1105,17 +1105,17 @@ ServiceWorkerRegistrationWorkerThread::U
 
   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
   if (!proxy) {
     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
     return nullptr;
   }
 
   RefPtr<UpdateRunnable> r = new UpdateRunnable(proxy, mScope);
-  MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv)
 {
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
@@ -1137,17 +1137,17 @@ ServiceWorkerRegistrationWorkerThread::U
 
   RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
   if (!proxy) {
     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
     return nullptr;
   }
 
   RefPtr<StartUnregisterRunnable> r = new StartUnregisterRunnable(proxy, mScope);
-  MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
 
   return promise.forget();
 }
 
 class StartListeningRunnable final : public Runnable
 {
   RefPtr<WorkerListener> mListener;
 public:
@@ -1175,17 +1175,17 @@ ServiceWorkerRegistrationWorkerThread::I
   if (!HoldWorker(worker, Closing)) {
     mListener = nullptr;
     NS_WARNING("Could not add feature");
     return;
   }
 
   RefPtr<StartListeningRunnable> r =
     new StartListeningRunnable(mListener);
-  MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
 }
 
 class AsyncStopListeningRunnable final : public Runnable
 {
   RefPtr<WorkerListener> mListener;
 public:
   explicit AsyncStopListeningRunnable(WorkerListener* aListener)
     : mListener(aListener)
@@ -1233,17 +1233,17 @@ ServiceWorkerRegistrationWorkerThread::R
   mWorkerPrivate->AssertIsOnWorkerThread();
   ReleaseWorker();
 
   mListener->ClearRegistration();
 
   if (aReason == RegistrationIsGoingAway) {
     RefPtr<AsyncStopListeningRunnable> r =
       new AsyncStopListeningRunnable(mListener);
-    MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(r.forget()));
+    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
   } else if (aReason == WorkerIsGoingAway) {
     RefPtr<SyncStopListeningRunnable> r =
       new SyncStopListeningRunnable(mWorkerPrivate, mListener);
     ErrorResult rv;
     r->Dispatch(rv);
     if (rv.Failed()) {
       NS_ERROR("Failed to dispatch stop listening runnable!");
       // And now what?
--- a/dom/workers/ServiceWorkerWindowClient.cpp
+++ b/dom/workers/ServiceWorkerWindowClient.cpp
@@ -178,17 +178,17 @@ ServiceWorkerWindowClient::Focus(ErrorRe
   }
 
   if (workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
     RefPtr<PromiseWorkerProxy> promiseProxy =
       PromiseWorkerProxy::Create(workerPrivate, promise);
     if (promiseProxy) {
       RefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId,
                                                               promiseProxy);
-      MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
+      MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
     } else {
       promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     }
 
   } else {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
   }
 
@@ -511,15 +511,15 @@ ServiceWorkerWindowClient::Navigate(cons
     return promise.forget();
   }
 
   RefPtr<PromiseWorkerProxy> promiseProxy =
     PromiseWorkerProxy::Create(workerPrivate, promise);
   if (promiseProxy) {
     RefPtr<ClientNavigateRunnable> r =
       new ClientNavigateRunnable(mWindowId, aUrl, promiseProxy);
-    MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
+    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
   } else {
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
   }
 
   return promise.forget();
 }
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -65,17 +65,16 @@
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/TaskQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsError.h"
 #include "nsDOMJSUtils.h"
 #include "nsHostObjectProtocolHandler.h"
@@ -397,17 +396,17 @@ private:
     nsCOMPtr<nsILoadGroup> loadGroupToCancel;
     mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
 
     nsTArray<nsCOMPtr<nsISupports>> doomed;
     mFinishedWorker->ForgetMainThreadObjects(doomed);
 
     RefPtr<MainThreadReleaseRunnable> runnable =
       new MainThreadReleaseRunnable(doomed, loadGroupToCancel);
-    if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
+    if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       NS_WARNING("Failed to dispatch, going to leak!");
     }
 
     RuntimeService* runtime = RuntimeService::GetService();
     NS_ASSERTION(runtime, "This should never be null!");
 
     mFinishedWorker->DisableDebugger();
 
@@ -3853,17 +3852,17 @@ WorkerDebugger::Close()
 
 void
 WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   RefPtr<PostDebuggerMessageRunnable> runnable =
     new PostDebuggerMessageRunnable(this, aMessage);
-  if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
+  if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to post message to debugger on main thread!");
   }
 }
 
 void
 WorkerDebugger::PostMessageToDebuggerOnMainThread(const nsAString& aMessage)
 {
   AssertIsOnMainThread();
@@ -3878,17 +3877,17 @@ void
 WorkerDebugger::ReportErrorToDebugger(const nsAString& aFilename,
                                       uint32_t aLineno,
                                       const nsAString& aMessage)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   RefPtr<ReportDebuggerErrorRunnable> runnable =
     new ReportDebuggerErrorRunnable(this, aFilename, aLineno, aMessage);
-  if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
+  if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to report error to debugger on main thread!");
   }
 }
 
 void
 WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
                                                   uint32_t aLineno,
                                                   const nsAString& aMessage)
@@ -3911,17 +3910,16 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
   : WorkerPrivateParent<WorkerPrivate>(aParent, aScriptURL,
                                        aIsChromeWorker, aWorkerType,
                                        aWorkerName, aLoadInfo)
   , mDebuggerRegistered(false)
   , mDebugger(nullptr)
   , mJSContext(nullptr)
   , mPRThread(nullptr)
   , mDebuggerEventLoopLevel(0)
-  , mMainThreadEventTarget(do_GetMainThread())
   , mErrorHandlerRecursionCount(0)
   , mNextTimeoutId(1)
   , mStatus(Pending)
   , mFrozen(false)
   , mTimerRunning(false)
   , mRunningExpiredTimeouts(false)
   , mPendingEventQueueClearing(false)
   , mMemoryReporterRunning(false)
@@ -3940,39 +3938,16 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
     aParent->GetAllPreferences(mPreferences);
     mOnLine = aParent->OnLine();
   }
   else {
     AssertIsOnMainThread();
     RuntimeService::GetDefaultPreferences(mPreferences);
     mOnLine = !NS_IsOffline() && !NS_IsAppOffline(aLoadInfo.mPrincipal);
   }
-
-  nsCOMPtr<nsIEventTarget> target;
-
-  if (aParent) {
-    target = aParent->MainThreadEventTarget();
-  }
-
-  // TODO: If we have a window, try to use its MainThreadTaskQueue as the
-  //       target for our sub-queue.
-
-  if (!target) {
-    nsCOMPtr<nsIThread> mainThread;
-    NS_GetMainThread(getter_AddRefs(mainThread));
-    MOZ_DIAGNOSTIC_ASSERT(mainThread);
-    target = mainThread;
-  }
-
-  // Throttle events to the main thread using a TaskQueue specific to this
-  // worker thread.
-  mMainThreadTaskQueue = new TaskQueue(target.forget());
-
-  // Expose our task queue as the worker's main thread nsIEventTarget.
-  mMainThreadEventTarget = mMainThreadTaskQueue->WrapAsEventTarget();
 }
 
 WorkerPrivate::~WorkerPrivate()
 {
 }
 
 // static
 already_AddRefed<WorkerPrivate>
@@ -4502,24 +4477,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
 
         {
           MutexAutoLock lock(mMutex);
 
           mStatus = Dead;
           mJSContext = nullptr;
         }
 
-        // Shutdown the main thread TaskQueue and wait for it to drain.  Make
-        // sure to clear our references first, however, so that new runnables
-        // are not dispatched into the closing TaskQueue.
-        mMainThreadEventTarget = do_GetMainThread();
-        RefPtr<TaskQueue> taskQueue = mMainThreadTaskQueue.forget();
-        taskQueue->BeginShutdown();
-        taskQueue->AwaitShutdownAndIdle();
-
         // After mStatus is set to Dead there can be no more
         // WorkerControlRunnables so no need to lock here.
         if (!mControlQueue.IsEmpty()) {
           WorkerControlRunnable* runnable;
           while (mControlQueue.Pop(runnable)) {
             runnable->Cancel();
             runnable->Release();
           }
@@ -4575,24 +4542,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
       }
     }
 
     if (!debuggerRunnablesPending && !normalRunnablesPending) {
       // Both the debugger event queue and the normal event queue has been
       // exhausted, cancel the periodic GC timer and schedule the idle GC timer.
       SetGCTimerMode(IdleTimer);
     }
-
-    // If the worker thread is spamming the main thread faster than it can
-    // process the work, then pause the worker thread until the MT catches
-    // up.
-    if (mMainThreadTaskQueue &&
-        mMainThreadTaskQueue->ImpreciseLengthForHeuristics() > 5000) {
-      mMainThreadTaskQueue->AwaitIdle();
-    }
   }
 
   MOZ_CRASH("Shouldn't get here!");
 }
 
 void
 WorkerPrivate::OnProcessNextEvent()
 {
@@ -4625,37 +4584,17 @@ WorkerPrivate::MaybeDispatchLoadFailedRu
 {
   AssertIsOnWorkerThread();
 
   nsCOMPtr<nsIRunnable> runnable = StealLoadFailedAsyncRunnable();
   if (!runnable) {
     return;
   }
 
-  MOZ_ALWAYS_SUCCEEDS(DispatchToMainThread(runnable.forget()));
-}
-
-nsIEventTarget*
-WorkerPrivate::MainThreadEventTarget()
-{
-  return mMainThreadEventTarget;
-}
-
-nsresult
-WorkerPrivate::DispatchToMainThread(nsIRunnable* aRunnable, uint32_t aFlags)
-{
-  nsCOMPtr<nsIRunnable> r = aRunnable;
-  return DispatchToMainThread(r.forget(), aFlags);
-}
-
-nsresult
-WorkerPrivate::DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
-                                    uint32_t aFlags)
-{
-  return mMainThreadEventTarget->Dispatch(Move(aRunnable), aFlags);
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget()));
 }
 
 void
 WorkerPrivate::InitializeGCTimers()
 {
   AssertIsOnWorkerThread();
 
   // We need a timer for GC. The basic plan is to run a non-shrinking GC
@@ -4846,17 +4785,17 @@ WorkerPrivate::ScheduleDeletion(WorkerRa
       new WorkerFinishedRunnable(parent, this);
     if (!runnable->Dispatch()) {
       NS_WARNING("Failed to dispatch runnable!");
     }
   }
   else {
     RefPtr<TopLevelWorkerFinishedRunnable> runnable =
       new TopLevelWorkerFinishedRunnable(this);
-    if (NS_FAILED(DispatchToMainThread(runnable.forget()))) {
+    if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       NS_WARNING("Failed to dispatch runnable!");
     }
   }
 }
 
 bool
 WorkerPrivate::BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats,
                                            bool aAnonymize)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -54,17 +54,16 @@ class nsITimer;
 class nsIURI;
 template<class T> class nsMainThreadPtrHandle;
 
 namespace JS {
 struct RuntimeStats;
 } // namespace JS
 
 namespace mozilla {
-class TaskQueue;
 namespace dom {
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PromiseNativeHandler;
 class StructuredCloneHolder;
 class WorkerDebuggerGlobalScope;
 class WorkerGlobalScope;
@@ -913,18 +912,16 @@ class WorkerPrivate : public WorkerPriva
 
   // Things touched on worker thread only.
   RefPtr<WorkerGlobalScope> mScope;
   RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
   nsTArray<ParentType*> mChildWorkers;
   nsTObserverArray<WorkerHolder*> mHolders;
   nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
   uint32_t mDebuggerEventLoopLevel;
-  RefPtr<TaskQueue> mMainThreadTaskQueue;
-  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
 
   struct SyncLoopInfo
   {
     explicit SyncLoopInfo(EventTarget* aEventTarget);
 
     RefPtr<EventTarget> mEventTarget;
     bool mCompleted;
     bool mResult;
@@ -1339,30 +1336,16 @@ public:
   {
     AssertIsOnWorkerThread();
     return mWorkerScriptExecutedSuccessfully;
   }
 
   void
   MaybeDispatchLoadFailedRunnable();
 
-  // Get the event target to use when dispatching to the main thread
-  // from this Worker thread.  This may be the main thread itself or
-  // a TaskQueue throttling runnables to the main thread.
-  nsIEventTarget*
-  MainThreadEventTarget();
-
-  nsresult
-  DispatchToMainThread(nsIRunnable* aRunnable,
-                       uint32_t aFlags = NS_DISPATCH_NORMAL);
-
-  nsresult
-  DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
-                       uint32_t aFlags = NS_DISPATCH_NORMAL);
-
 private:
   WorkerPrivate(WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
                 WorkerType aWorkerType, const nsACString& aSharedWorkerName,
                 WorkerLoadInfo& aLoadInfo);
 
   bool
   MayContinueRunning()
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -10,17 +10,16 @@
 #include "nsIEventTarget.h"
 #include "nsIGlobalObject.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/TaskQueue.h"
 #include "mozilla/Telemetry.h"
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerScope.h"
 
@@ -114,17 +113,20 @@ WorkerRunnable::DispatchInternal()
   }
 
   MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
 
   if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
     return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
   }
 
-  return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
+  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+  MOZ_ASSERT(mainThread);
+
+  return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
 }
 
 void
 WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
                              bool aDispatchResult)
 {
   MOZ_ASSERT(aWorkerPrivate);
 
@@ -550,17 +552,20 @@ WorkerControlRunnable::DispatchInternal(
   if (mBehavior == WorkerThreadUnchangedBusyCount) {
     return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
   }
 
   if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
     return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
   }
 
-  return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
+  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+  MOZ_ASSERT(mainThread);
+
+  return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
 
 WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
                                                    const nsACString& aTelemetryKey)
 : mWorkerPrivate(aWorkerPrivate)
 , mTelemetryKey(aTelemetryKey)
@@ -573,18 +578,20 @@ WorkerMainThreadRunnable::Dispatch(Error
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   TimeStamp startTime = TimeStamp::NowLoRes();
 
   AutoSyncLoopHolder syncLoop(mWorkerPrivate);
 
   mSyncLoopTarget = syncLoop.EventTarget();
+  RefPtr<WorkerMainThreadRunnable> runnable(this);
 
-  DebugOnly<nsresult> rv = mWorkerPrivate->DispatchToMainThread(this);
+  DebugOnly<nsresult> rv =
+    NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
   MOZ_ASSERT(NS_SUCCEEDED(rv),
              "Should only fail after xpcom-shutdown-threads and we're gone by then");
 
   if (!syncLoop.Run()) {
     aRv.ThrowUncatchableException();
   }
 
   // Telemetry is apparently not threadsafe
@@ -670,17 +677,17 @@ WorkerProxyToMainThreadRunnable::Dispatc
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (NS_WARN_IF(!HoldWorker())) {
     RunBackOnWorkerThread();
     return false;
   }
 
-  if (NS_WARN_IF(NS_FAILED(mWorkerPrivate->DispatchToMainThread(this)))) {
+  if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) {
     ReleaseWorker();
     RunBackOnWorkerThread();
     return false;
   }
 
   return true;
 }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -692,17 +692,17 @@ ServiceWorkerGlobalScope::SkipWaiting(Er
     promise->MaybeResolveWithUndefined();
     return promise.forget();
   }
 
   RefPtr<WorkerScopeSkipWaitingRunnable> runnable =
     new WorkerScopeSkipWaitingRunnable(promiseProxy,
                                        NS_ConvertUTF16toUTF8(mScope));
 
-  MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
+  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
   return promise.forget();
 }
 
 bool
 ServiceWorkerGlobalScope::OpenWindowEnabled(JSContext* aCx, JSObject* aObj)
 {
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
--- a/dom/workers/test/test_consoleAndBlobs.html
+++ b/dom/workers/test/test_consoleAndBlobs.html
@@ -17,24 +17,22 @@
     SpecialPowers.addObserver(this, "console-api-log-event", false);
   }
 
   var order = 0;
   consoleListener.prototype  = {
     observe: function(aSubject, aTopic, aData) {
       ok(true, "Something has been received");
       is(aTopic, "console-api-log-event");
+      SpecialPowers.removeObserver(this, "console-api-log-event");
 
       var obj = aSubject.wrappedJSObject;
-      if (obj.arguments[0] && obj.arguments[0].msg === 'consoleAndBlobs') {
-        SpecialPowers.removeObserver(this, "console-api-log-event");
-        is(obj.arguments[0].blob.size, 3, "The size is correct");
-        is(obj.arguments[0].blob.type, 'foo/bar', "The type is correct");
-        SimpleTest.finish();
-      }
+      is(obj.arguments[0].size, 3, "The size is correct");
+      is(obj.arguments[0].type, 'foo/bar', "The type is correct");
+      SimpleTest.finish();
     }
   }
 
   var cl = new consoleListener();
 
   new Worker('worker_consoleAndBlobs.js');
   SimpleTest.waitForExplicitFinish();
 
--- a/dom/workers/test/worker_consoleAndBlobs.js
+++ b/dom/workers/test/worker_consoleAndBlobs.js
@@ -1,8 +1,8 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 "use strict";
 
 var b = new Blob(['123'], { type: 'foo/bar'});
-console.log({ msg: 'consoleAndBlobs', blob: b });
+console.log(b);
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -1608,17 +1608,17 @@ XMLHttpRequestWorker::ReleaseProxy(Relea
   if (mProxy) {
     if (aType == XHRIsGoingAway) {
       // We're in a GC finalizer, so we can't do a sync call here (and we don't
       // need to).
       RefPtr<AsyncTeardownRunnable> runnable =
         new AsyncTeardownRunnable(mProxy);
       mProxy = nullptr;
 
-      if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
+      if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
         NS_ERROR("Failed to dispatch teardown runnable!");
       }
     } else {
       // This isn't necessary if the worker is going away or the XHR is going
       // away.
       if (aType == Default) {
         // Don't let any more events run.
         mProxy->mOuterEventStreamId++;
--- a/xpcom/tests/gtest/TestStateWatching.cpp
+++ b/xpcom/tests/gtest/TestStateWatching.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "gtest/gtest.h"
-#include "mozilla/SharedThreadPool.h"
 #include "mozilla/StateWatching.h"
 #include "mozilla/TaskQueue.h"
 #include "nsISupportsImpl.h"
 #include "VideoUtils.h"
 
 namespace TestStateWatching {
 
 using namespace mozilla;
--- a/xpcom/threads/AbstractThread.cpp
+++ b/xpcom/threads/AbstractThread.cpp
@@ -65,16 +65,17 @@ public:
 
   virtual bool IsCurrentThreadIn() override
   {
     // Compare NSPR threads so that this works after shutdown when
     // NS_GetCurrentThread starts returning null.
     PRThread* thread = nullptr;
     mTarget->GetPRThread(&thread);
     bool in = PR_GetCurrentThread() == thread;
+    MOZ_ASSERT(in == (GetCurrent() == this));
     return in;
   }
 
   void FireTailDispatcher()
   {
     MOZ_DIAGNOSTIC_ASSERT(mTailDispatcher.isSome());
     mTailDispatcher.ref().DrainDirectTasks();
     mTailDispatcher.reset();
--- a/xpcom/threads/SharedThreadPool.h
+++ b/xpcom/threads/SharedThreadPool.h
@@ -53,20 +53,17 @@ public:
   NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
 
   // Forward behaviour to wrapped thread pool implementation.
   NS_FORWARD_SAFE_NSITHREADPOOL(mPool);
 
   // Call this when dispatching from an event on the same
   // threadpool that is about to complete. We should not create a new thread
   // in that case since a thread is about to become idle.
-  nsresult DispatchFromEndOfTaskInThisPool(nsIRunnable *event)
-  {
-    return Dispatch(event, NS_DISPATCH_AT_END);
-  }
+  nsresult TailDispatch(nsIRunnable *event) { return Dispatch(event, NS_DISPATCH_TAIL); }
 
   NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override {
       return Dispatch(event, flags);
   }
 
   NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable> event, uint32_t flags) override
     { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(Move(event), flags); }
 
--- a/xpcom/threads/TaskQueue.cpp
+++ b/xpcom/threads/TaskQueue.cpp
@@ -1,76 +1,25 @@
 /* -*- 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 "mozilla/TaskQueue.h"
 
-#include "nsIEventTarget.h"
 #include "nsThreadUtils.h"
+#include "mozilla/SharedThreadPool.h"
 
 namespace mozilla {
 
-class TaskQueue::EventTargetWrapper final : public nsIEventTarget
-{
-  RefPtr<TaskQueue> mTaskQueue;
-
-  ~EventTargetWrapper()
-  {
-  }
-
-public:
-  explicit EventTargetWrapper(TaskQueue* aTaskQueue)
-    : mTaskQueue(aTaskQueue)
-  {
-    MOZ_ASSERT(mTaskQueue);
-  }
-
-  NS_IMETHOD
-  DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) override
-  {
-    nsCOMPtr<nsIRunnable> ref = aEvent;
-    return Dispatch(ref.forget(), aFlags);
-  }
-
-  NS_IMETHOD
-  Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags) override
-  {
-    nsCOMPtr<nsIRunnable> runnable = aEvent;
-    MonitorAutoLock mon(mTaskQueue->mQueueMonitor);
-    return mTaskQueue->DispatchLocked(/* passed by ref */runnable,
-                                      AbortIfFlushing,
-                                      DontAssertDispatchSuccess,
-                                      NormalDispatch);
-  }
-
-  NS_IMETHOD
-  DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t aFlags) override
-  {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-
-  NS_IMETHOD
-  IsOnCurrentThread(bool* aResult) override
-  {
-    *aResult = mTaskQueue->IsCurrentThreadIn();
-    return NS_OK;
-  }
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-};
-
-NS_IMPL_ISUPPORTS(TaskQueue::EventTargetWrapper, nsIEventTarget)
-
-TaskQueue::TaskQueue(already_AddRefed<nsIEventTarget> aTarget,
-                     bool aRequireTailDispatch)
+TaskQueue::TaskQueue(already_AddRefed<SharedThreadPool> aPool,
+                               bool aRequireTailDispatch)
   : AbstractThread(aRequireTailDispatch)
-  , mTarget(aTarget)
+  , mPool(aPool)
   , mQueueMonitor("TaskQueue::Queue")
   , mTailDispatcher(nullptr)
   , mIsRunning(false)
   , mIsShutdown(false)
   , mIsFlushing(false)
 {
   MOZ_COUNT_CTOR(TaskQueue);
 }
@@ -110,17 +59,17 @@ TaskQueue::DispatchLocked(nsCOMPtr<nsIRu
   if (mIsShutdown) {
     return NS_ERROR_FAILURE;
   }
   mTasks.push(aRunnable.forget());
   if (mIsRunning) {
     return NS_OK;
   }
   RefPtr<nsIRunnable> runner(new Runner(this));
-  nsresult rv = mTarget->Dispatch(runner.forget(), NS_DISPATCH_NORMAL);
+  nsresult rv = mPool->Dispatch(runner.forget(), NS_DISPATCH_NORMAL);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to dispatch runnable to run TaskQueue");
     return rv;
   }
   mIsRunning = true;
 
   return NS_OK;
 }
@@ -182,37 +131,24 @@ TaskQueue::BeginShutdown()
 
 bool
 TaskQueue::IsEmpty()
 {
   MonitorAutoLock mon(mQueueMonitor);
   return mTasks.empty();
 }
 
-uint32_t
-TaskQueue::ImpreciseLengthForHeuristics()
-{
-  MonitorAutoLock mon(mQueueMonitor);
-  return mTasks.size();
-}
-
 bool
 TaskQueue::IsCurrentThreadIn()
 {
   bool in = NS_GetCurrentThread() == mRunningThread;
+  MOZ_ASSERT(in == (GetCurrent() == this));
   return in;
 }
 
-already_AddRefed<nsIEventTarget>
-TaskQueue::WrapAsEventTarget()
-{
-  nsCOMPtr<nsIEventTarget> ref = new EventTargetWrapper(this);
-  return ref.forget();
-}
-
 nsresult
 TaskQueue::Runner::Run()
 {
   RefPtr<nsIRunnable> event;
   {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
     MOZ_ASSERT(mQueue->mIsRunning);
     if (mQueue->mTasks.size() == 0) {
@@ -250,21 +186,21 @@ TaskQueue::Runner::Run()
       mQueue->mIsRunning = false;
       mQueue->MaybeResolveShutdown();
       mon.NotifyAll();
       return NS_OK;
     }
   }
 
   // There's at least one more event that we can run. Dispatch this Runner
-  // to the target again to ensure it runs again. Note that we don't just
-  // run in a loop here so that we don't hog the target. This means we may
+  // to the thread pool again to ensure it runs again. Note that we don't just
+  // run in a loop here so that we don't hog the thread pool. This means we may
   // run on another thread next time, but we rely on the memory fences from
   // mQueueMonitor for thread safety of non-threadsafe tasks.
-  nsresult rv = mQueue->mTarget->Dispatch(this, NS_DISPATCH_AT_END);
+  nsresult rv = mQueue->mPool->TailDispatch(this);
   if (NS_FAILED(rv)) {
     // Failed to dispatch, shutdown!
     MonitorAutoLock mon(mQueue->mQueueMonitor);
     mQueue->mIsRunning = false;
     mQueue->mIsShutdown = true;
     mQueue->MaybeResolveShutdown();
     mon.NotifyAll();
   }
--- a/xpcom/threads/TaskQueue.h
+++ b/xpcom/threads/TaskQueue.h
@@ -10,53 +10,35 @@
 #include "mozilla/Monitor.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TaskDispatcher.h"
 #include "mozilla/Unused.h"
 
 #include <queue>
 
+#include "mozilla/SharedThreadPool.h"
 #include "nsThreadUtils.h"
 
-class nsIEventTarget;
 class nsIRunnable;
 
 namespace mozilla {
 
+class SharedThreadPool;
+
 typedef MozPromise<bool, bool, false> ShutdownPromise;
 
-// Abstracts executing runnables in order on an arbitrary event target. The
-// runnables dispatched to the TaskQueue will be executed in the order in which
+// Abstracts executing runnables in order in a thread pool. The runnables
+// dispatched to the TaskQueue will be executed in the order in which
 // they're received, and are guaranteed to not be executed concurrently.
 // They may be executed on different threads, and a memory barrier is used
 // to make this threadsafe for objects that aren't already threadsafe.
-//
-// Note, since a TaskQueue can also be converted to an nsIEventTarget using
-// WrapAsEventTarget() its possible to construct a hierarchy of TaskQueues.
-// Consider these three TaskQueues:
-//
-//  TQ1 dispatches to the main thread
-//  TQ2 dispatches to TQ1
-//  TQ3 dispatches to TQ1
-//
-// This ensures there is only ever a single runnable from the entire chain on
-// the main thread.  It also ensures that TQ2 and TQ3 only have a single runnable
-// in TQ1 at any time.
-//
-// This arrangement lets you prioritize work by dispatching runnables directly
-// to TQ1.  You can issue many runnables for important work.  Meanwhile the TQ2
-// and TQ3 work will always execute at most one runnable and then yield.
-class TaskQueue : public AbstractThread
-{
-  class EventTargetWrapper;
-
+class TaskQueue : public AbstractThread {
 public:
-  explicit TaskQueue(already_AddRefed<nsIEventTarget> aTarget,
-                     bool aSupportsTailDispatch = false);
+  explicit TaskQueue(already_AddRefed<SharedThreadPool> aPool, bool aSupportsTailDispatch = false);
 
   TaskDispatcher& TailDispatcher() override;
 
   TaskQueue* AsTaskQueue() override { return this; }
 
   void Dispatch(already_AddRefed<nsIRunnable> aRunnable,
                 DispatchFailureHandling aFailureHandling = AssertDispatchSuccess,
                 DispatchReason aReason = NormalDispatch) override
@@ -72,39 +54,34 @@ public:
     // dispatch failure, it will be deleted here outside the lock. We do so
     // since the destructor of the runnable might access TaskQueue and result
     // in deadlocks.
   }
 
   // Puts the queue in a shutdown state and returns immediately. The queue will
   // remain alive at least until all the events are drained, because the Runners
   // hold a strong reference to the task queue, and one of them is always held
-  // by the target event queue when the task queue is non-empty.
+  // by the threadpool event queue when the task queue is non-empty.
   //
   // The returned promise is resolved when the queue goes empty.
   RefPtr<ShutdownPromise> BeginShutdown();
 
   // Blocks until all task finish executing.
   void AwaitIdle();
 
   // Blocks until the queue is flagged for shutdown and all tasks have finished
   // executing.
   void AwaitShutdownAndIdle();
 
   bool IsEmpty();
-  uint32_t ImpreciseLengthForHeuristics();
 
   // Returns true if the current thread is currently running a Runnable in
   // the task queue.
   bool IsCurrentThreadIn() override;
 
-  // Create a new nsIEventTarget wrapper object that dispatches to this
-  // TaskQueue.
-  already_AddRefed<nsIEventTarget> WrapAsEventTarget();
-
 protected:
   virtual ~TaskQueue();
 
 
   // Blocks until all task finish executing. Called internally by methods
   // that need to wait until the task queue is idle.
   // mQueueMonitor must be held.
   void AwaitIdleLocked();
@@ -116,21 +93,21 @@ protected:
                           DispatchFailureHandling aFailureHandling,
                           DispatchReason aReason = NormalDispatch);
 
   void MaybeResolveShutdown()
   {
     mQueueMonitor.AssertCurrentThreadOwns();
     if (mIsShutdown && !mIsRunning) {
       mShutdownPromise.ResolveIfExists(true, __func__);
-      mTarget = nullptr;
+      mPool = nullptr;
     }
   }
 
-  nsCOMPtr<nsIEventTarget> mTarget;
+  RefPtr<SharedThreadPool> mPool;
 
   // Monitor that protects the queue and mIsRunning;
   Monitor mQueueMonitor;
 
   // Queue of tasks to run.
   std::queue<nsCOMPtr<nsIRunnable>> mTasks;
 
   // The thread currently running the task queue. We store a reference
@@ -144,49 +121,47 @@ protected:
   Atomic<nsIThread*> mRunningThread;
 
   // RAII class that gets instantiated for each dispatched task.
   class AutoTaskGuard : public AutoTaskDispatcher
   {
   public:
     explicit AutoTaskGuard(TaskQueue* aQueue)
       : AutoTaskDispatcher(/* aIsTailDispatcher = */ true), mQueue(aQueue)
-      , mLastCurrentThread(nullptr)
     {
       // NB: We don't hold the lock to aQueue here. Don't do anything that
       // might require it.
       MOZ_ASSERT(!mQueue->mTailDispatcher);
       mQueue->mTailDispatcher = this;
 
-      mLastCurrentThread = sCurrentThreadTLS.get();
+      MOZ_ASSERT(sCurrentThreadTLS.get() == nullptr);
       sCurrentThreadTLS.set(aQueue);
 
       MOZ_ASSERT(mQueue->mRunningThread == nullptr);
       mQueue->mRunningThread = NS_GetCurrentThread();
     }
 
     ~AutoTaskGuard()
     {
       DrainDirectTasks();
 
       MOZ_ASSERT(mQueue->mRunningThread == NS_GetCurrentThread());
       mQueue->mRunningThread = nullptr;
 
-      sCurrentThreadTLS.set(mLastCurrentThread);
+      sCurrentThreadTLS.set(nullptr);
       mQueue->mTailDispatcher = nullptr;
     }
 
   private:
   TaskQueue* mQueue;
-  AbstractThread* mLastCurrentThread;
   };
 
   TaskDispatcher* mTailDispatcher;
 
-  // True if we've dispatched an event to the target to execute events from
+  // True if we've dispatched an event to the pool to execute events from
   // the queue.
   bool mIsRunning;
 
   // True if we've started our shutdown process.
   bool mIsShutdown;
   MozPromiseHolder<ShutdownPromise> mShutdownPromise;
 
   // True if we're flushing; we reject new tasks if we're flushing.
--- a/xpcom/threads/nsIEventTarget.idl
+++ b/xpcom/threads/nsIEventTarget.idl
@@ -45,17 +45,17 @@ interface nsIEventTarget : nsISupports
    * that was dispatched to the same event target, and that event is about to
    * finish.
    *
    * A thread pool can use this as an optimization hint to not spin up
    * another thread, since the current thread is about to become idle.
    *
    * These events are always async.
    */
-  const unsigned long DISPATCH_AT_END = 2;
+  const unsigned long DISPATCH_TAIL = 2;
 
   /**
    * Check to see if this event target is associated with the current thread.
    *
    * @returns
    *   A boolean value that if "true" indicates that events dispatched to this
    *   event target will run on the current thread (i.e., the thread calling
    *   this method).
@@ -118,10 +118,10 @@ interface nsIEventTarget : nsISupports
    */
   [noscript] void delayedDispatch(in alreadyAddRefed_nsIRunnable event, in unsigned long delay);
 };
 
 %{C++
 // convenient aliases:
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC
-#define NS_DISPATCH_AT_END nsIEventTarget::DISPATCH_AT_END
+#define NS_DISPATCH_TAIL   nsIEventTarget::DISPATCH_TAIL
 %}
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -743,18 +743,17 @@ nsThread::DispatchInternal(already_AddRe
 
     // Allows waiting; ensure no locks are held that would deadlock us!
     while (wrapper->IsPending()) {
       NS_ProcessNextEvent(thread, true);
     }
     return NS_OK;
   }
 
-  NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL ||
-               aFlags == NS_DISPATCH_AT_END, "unexpected dispatch flags");
+  NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
   return PutEvent(event.take(), aTarget);
 }
 
 //-----------------------------------------------------------------------------
 // nsIEventTarget
 
 NS_IMETHODIMP
 nsThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -81,17 +81,17 @@ nsThreadPool::PutEvent(already_AddRefed<
       return NS_ERROR_NOT_AVAILABLE;
     }
     LOG(("THRD-P(%p) put [%d %d %d]\n", this, mIdleCount, mThreads.Count(),
          mThreadLimit));
     MOZ_ASSERT(mIdleCount <= (uint32_t)mThreads.Count(), "oops");
 
     // Make sure we have a thread to service this event.
     if (mThreads.Count() < (int32_t)mThreadLimit &&
-        !(aFlags & NS_DISPATCH_AT_END) &&
+        !(aFlags & NS_DISPATCH_TAIL) &&
         // Spawn a new thread if we don't have enough idle threads to serve
         // pending events immediately.
         mEvents.Count(lock) >= mIdleCount) {
       spawnThread = true;
     }
 
     mEvents.PutEvent(Move(aEvent), lock);
     stackSize = mStackSize;
@@ -265,17 +265,17 @@ nsThreadPool::Dispatch(already_AddRefed<
       new nsThreadSyncDispatch(thread, Move(aEvent));
     PutEvent(wrapper);
 
     while (wrapper->IsPending()) {
       NS_ProcessNextEvent(thread);
     }
   } else {
     NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL ||
-                 aFlags == NS_DISPATCH_AT_END, "unexpected dispatch flags");
+                 aFlags == NS_DISPATCH_TAIL, "unexpected dispatch flags");
     PutEvent(Move(aEvent), aFlags);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThreadPool::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
 {