Backed out 1 changesets (bug 1445883) for Linting opt failures on /MANIFEST.json. a=backout
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Wed, 21 Mar 2018 00:17:34 +0200
changeset 408986 7e5f384e7c8e7bfdaf72c0d5a2aa234b1927e0a4
parent 408985 025426a3e2e780d33bb666c78bfbaf22b3456c19
child 409035 e2e874ceae787faed7bf73dc049e580ee7159f28
push id33670
push usernbeleuzu@mozilla.com
push dateTue, 20 Mar 2018 22:17:13 +0000
treeherdermozilla-central@7e5f384e7c8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1445883
milestone61.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
Backed out 1 changesets (bug 1445883) for Linting opt failures on /MANIFEST.json. a=backout Bug 1445883 - Port XHR to WorkerRef, r=smaug
dom/xhr/XMLHttpRequestWorker.cpp
dom/xhr/XMLHttpRequestWorker.h
testing/web-platform/meta/MANIFEST.json
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/UnionConversions.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/Telemetry.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 
 #include "XMLHttpRequestUpload.h"
@@ -236,19 +237,18 @@ class SendRunnable final
   : public WorkerThreadProxySyncRunnable
   , public StructuredCloneHolder
 {
   nsString mStringBody;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   bool mHasUploadListeners;
 
 public:
-  SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-               const nsAString& aStringBody)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  SendRunnable(Proxy* aProxy, const nsAString& aStringBody)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy)
   , StructuredCloneHolder(CloningSupported, TransferringNotSupported,
                           StructuredCloneScope::SameProcessDifferentThread)
   , mStringBody(aStringBody)
   , mHasUploadListeners(false)
   {
   }
 
   void SetHaveUploadListeners(bool aHasUploadListeners)
@@ -536,18 +536,18 @@ private:
 
   bool PreDispatch(WorkerPrivate* /* unused */) final;
   bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
 };
 
 class SyncTeardownRunnable final : public WorkerThreadProxySyncRunnable
 {
 public:
-  SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  explicit SyncTeardownRunnable(Proxy* aProxy)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy)
   { }
 
 private:
   ~SyncTeardownRunnable()
   { }
 
   virtual void
   RunOnMainThread(ErrorResult& aRv) override
@@ -558,19 +558,18 @@ private:
 };
 
 class SetBackgroundRequestRunnable final :
   public WorkerThreadProxySyncRunnable
 {
   bool mValue;
 
 public:
-  SetBackgroundRequestRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                               bool aValue)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  SetBackgroundRequestRunnable(Proxy* aProxy, bool aValue)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy)
   , mValue(aValue)
   { }
 
 private:
   ~SetBackgroundRequestRunnable()
   { }
 
   virtual void
@@ -581,19 +580,18 @@ private:
 };
 
 class SetWithCredentialsRunnable final :
   public WorkerThreadProxySyncRunnable
 {
   bool mValue;
 
 public:
-  SetWithCredentialsRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                             bool aValue)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  SetWithCredentialsRunnable(Proxy* aProxy, bool aValue)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy)
   , mValue(aValue)
   { }
 
 private:
   ~SetWithCredentialsRunnable()
   { }
 
   virtual void
@@ -603,19 +601,19 @@ private:
   }
 };
 
 class SetResponseTypeRunnable final : public WorkerThreadProxySyncRunnable
 {
   XMLHttpRequestResponseType mResponseType;
 
 public:
-  SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
+  SetResponseTypeRunnable(Proxy* aProxy,
                           XMLHttpRequestResponseType aResponseType)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mResponseType(aResponseType)
   { }
 
   XMLHttpRequestResponseType
   ResponseType()
   {
     return mResponseType;
   }
@@ -634,19 +632,18 @@ private:
   }
 };
 
 class SetTimeoutRunnable final : public WorkerThreadProxySyncRunnable
 {
   uint32_t mTimeout;
 
 public:
-  SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                     uint32_t aTimeout)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  SetTimeoutRunnable(Proxy* aProxy, uint32_t aTimeout)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mTimeout(aTimeout)
   { }
 
 private:
   ~SetTimeoutRunnable()
   { }
 
   virtual void
@@ -654,37 +651,36 @@ private:
   {
     mProxy->mXHR->SetTimeout(mTimeout, aRv);
   }
 };
 
 class AbortRunnable final : public WorkerThreadProxySyncRunnable
 {
 public:
-  AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  explicit AbortRunnable(Proxy* aProxy)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy)
   { }
 
 private:
   ~AbortRunnable()
   { }
 
   virtual void
   RunOnMainThread(ErrorResult& aRv) override;
 };
 
 class GetAllResponseHeadersRunnable final :
   public WorkerThreadProxySyncRunnable
 {
   nsCString& mResponseHeaders;
 
 public:
-  GetAllResponseHeadersRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                                nsCString& aResponseHeaders)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  GetAllResponseHeadersRunnable(Proxy* aProxy, nsCString& aResponseHeaders)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mResponseHeaders(aResponseHeaders)
   { }
 
 private:
   ~GetAllResponseHeadersRunnable()
   { }
 
   virtual void
@@ -695,19 +691,19 @@ private:
 };
 
 class GetResponseHeaderRunnable final : public WorkerThreadProxySyncRunnable
 {
   const nsCString mHeader;
   nsCString& mValue;
 
 public:
-  GetResponseHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                            const nsACString& aHeader, nsCString& aValue)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  GetResponseHeaderRunnable(Proxy* aProxy, const nsACString& aHeader,
+                            nsCString& aValue)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mHeader(aHeader),
     mValue(aValue)
   { }
 
 private:
   ~GetResponseHeaderRunnable()
   { }
 
@@ -774,19 +770,20 @@ private:
 };
 
 class SetRequestHeaderRunnable final : public WorkerThreadProxySyncRunnable
 {
   nsCString mHeader;
   nsCString mValue;
 
 public:
-  SetRequestHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                           const nsACString& aHeader, const nsACString& aValue)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  SetRequestHeaderRunnable(Proxy* aProxy,
+                           const nsACString& aHeader,
+                           const nsACString& aValue)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mHeader(aHeader),
     mValue(aValue)
   { }
 
 private:
   ~SetRequestHeaderRunnable()
   { }
 
@@ -797,19 +794,18 @@ private:
   }
 };
 
 class OverrideMimeTypeRunnable final : public WorkerThreadProxySyncRunnable
 {
   nsString mMimeType;
 
 public:
-  OverrideMimeTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-                           const nsAString& aMimeType)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
+  OverrideMimeTypeRunnable(Proxy* aProxy, const nsAString& aMimeType)
+  : WorkerThreadProxySyncRunnable(GetCurrentThreadWorkerPrivate(), aProxy),
     mMimeType(aMimeType)
   { }
 
 private:
   ~OverrideMimeTypeRunnable()
   { }
 
   virtual void
@@ -1302,17 +1298,17 @@ EventRunnable::WorkerRun(JSContext* aCx,
 
   state->mStatusText = mStatusText;
 
   state->mReadyState = mReadyState;
 
   state->mResponseURL = mResponseURL;
 
   XMLHttpRequestWorker* xhr = mProxy->mXMLHttpRequestPrivate;
-  xhr->UpdateState(*state.get(), mUseCachedArrayBufferResponse);
+  xhr->UpdateState(aCx, *state.get(), mUseCachedArrayBufferResponse);
 
   if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) {
     if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) {
       // We've already dispatched premature abort events.
       return true;
     }
   }
 
@@ -1538,34 +1534,37 @@ SendRunnable::RunOnMainThread(ErrorResul
       if (!mProxy->mUploadEventListenersAttached &&
           !mProxy->AddRemoveEventListeners(true, true)) {
         MOZ_ASSERT(false, "This should never fail!");
       }
     }
   }
 }
 
-XMLHttpRequestWorker::XMLHttpRequestWorker(WorkerPrivate* aWorkerPrivate)
-: WorkerHolder("XMLHttpRequestWorker"), mWorkerPrivate(aWorkerPrivate),
-  mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0),
-  mRooted(false), mBackgroundRequest(false), mWithCredentials(false),
-  mCanceled(false), mMozAnon(false), mMozSystem(false)
+XMLHttpRequestWorker::XMLHttpRequestWorker()
+  : mResponseType(XMLHttpRequestResponseType::Text)
+  , mTimeout(0)
+  , mBackgroundRequest(false)
+  , mWithCredentials(false)
+  , mCanceled(false)
+  , mMozAnon(false)
+  , mMozSystem(false)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(IsCurrentThreadRunningWorker());
 
   mozilla::HoldJSObjects(this);
 }
 
 XMLHttpRequestWorker::~XMLHttpRequestWorker()
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   ReleaseProxy(XHRIsGoingAway);
 
-  MOZ_ASSERT(!mRooted);
+  MOZ_ASSERT(!mWorkerRef);
 
   mozilla::DropJSObjects(this);
 }
 
 NS_IMPL_ADDREF_INHERITED(XMLHttpRequestWorker, XMLHttpRequestEventTarget)
 NS_IMPL_RELEASE_INHERITED(XMLHttpRequestWorker, XMLHttpRequestEventTarget)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XMLHttpRequestWorker)
@@ -1590,179 +1589,195 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INH
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStateData.mResponse)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 /* static */ already_AddRefed<XMLHttpRequest>
 XMLHttpRequestWorker::Construct(const GlobalObject& aGlobal,
                                 const MozXMLHttpRequestParameters& aParams,
                                 ErrorResult& aRv)
 {
+  RefPtr<XMLHttpRequestWorker> xhr = new XMLHttpRequestWorker();
+
   JSContext* cx = aGlobal.Context();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
   MOZ_ASSERT(workerPrivate);
 
-  RefPtr<XMLHttpRequestWorker> xhr = new XMLHttpRequestWorker(workerPrivate);
-
   if (workerPrivate->XHRParamsAllowed()) {
     if (aParams.mMozSystem)
       xhr->mMozAnon = true;
     else
       xhr->mMozAnon = aParams.mMozAnon;
     xhr->mMozSystem = aParams.mMozSystem;
   }
 
   return xhr.forget();
 }
 
 void
 XMLHttpRequestWorker::ReleaseProxy(ReleaseType aType)
 {
-  // Can't assert that we're on the worker thread here because mWorkerPrivate
-  // may be gone.
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   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()))) {
+      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+      MOZ_ASSERT(workerPrivate);
+
+      if (NS_FAILED(workerPrivate->DispatchToMainThread(runnable.forget()))) {
         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++;
       }
 
       // We need to make a sync call here.
-      RefPtr<SyncTeardownRunnable> runnable =
-        new SyncTeardownRunnable(mWorkerPrivate, mProxy);
+      RefPtr<SyncTeardownRunnable> runnable = new SyncTeardownRunnable(mProxy);
       mProxy = nullptr;
 
       IgnoredErrorResult forAssertionsOnly;
       // This runnable _must_ be executed.
       runnable->Dispatch(Dead, forAssertionsOnly);
       MOZ_DIAGNOSTIC_ASSERT(!forAssertionsOnly.Failed());
     }
   }
 }
 
-void
-XMLHttpRequestWorker::MaybePin(ErrorResult& aRv)
+bool
+XMLHttpRequestWorker::MaybePin()
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
-
-  if (mRooted) {
-    return;
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
+
+  if (mWorkerRef) {
+    return true;
   }
 
-  if (!HoldWorker(mWorkerPrivate, Canceling)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  RefPtr<XMLHttpRequestWorker> self = this;
+  mWorkerRef =
+    StrongWorkerRef::Create(workerPrivate, "XMLHttpRequestWorker", [self] {
+      self->mCanceled = true;
+      self->ReleaseProxy(WorkerIsGoingAway);
+    });
+
+  if (NS_WARN_IF(!mWorkerRef)) {
+    return false;
   }
 
   NS_ADDREF_THIS();
-
-  mRooted = true;
+  return true;
 }
 
 void
 XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
   MOZ_ASSERT(mProxy);
 
+  // The worker can be closed during the dispatching of the following events.
+  // Let's keep the proxy alive.
+  RefPtr<Proxy> proxy = mProxy;
+
   // Only send readystatechange event when state changed.
   bool isStateChanged = false;
   if ((mStateData.mReadyState == 1 && mStateData.mFlagSend) ||
       mStateData.mReadyState == 2 ||
       mStateData.mReadyState == 3) {
     isStateChanged = true;
     mStateData.mReadyState = 4;
   }
 
-  if (mProxy->mSeenUploadLoadStart) {
+  if (proxy->mSeenUploadLoadStart) {
     MOZ_ASSERT(mUpload);
 
-    DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true,
-                                aRv);
+    DispatchPrematureAbortEvent(mUpload, proxy, NS_LITERAL_STRING("abort"),
+                                true, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
+
+    DispatchPrematureAbortEvent(mUpload, proxy, NS_LITERAL_STRING("loadend"),
+                                true, aRv);
     if (aRv.Failed()) {
       return;
     }
 
-    DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("loadend"), true,
+    proxy->mSeenUploadLoadStart = false;
+  }
+
+  if (proxy->mSeenLoadStart) {
+    if (isStateChanged) {
+      DispatchPrematureAbortEvent(this, proxy,
+                                  NS_LITERAL_STRING("readystatechange"), false,
+                                  aRv);
+      if (aRv.Failed()) {
+        return;
+      }
+    }
+
+    DispatchPrematureAbortEvent(this, proxy, NS_LITERAL_STRING("abort"), false,
                                 aRv);
     if (aRv.Failed()) {
       return;
     }
 
-    mProxy->mSeenUploadLoadStart = false;
-  }
-
-  if (mProxy->mSeenLoadStart) {
-    if (isStateChanged) {
-      DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("readystatechange"),
-                                  false, aRv);
-      if (aRv.Failed()) {
-        return;
-      }
-    }
-
-    DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("abort"), false, aRv);
+    DispatchPrematureAbortEvent(this, proxy, NS_LITERAL_STRING("loadend"),
+                                false, aRv);
     if (aRv.Failed()) {
       return;
     }
 
-    DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("loadend"), false,
-                                aRv);
-    if (aRv.Failed()) {
-      return;
-    }
-
-    mProxy->mSeenLoadStart = false;
+    proxy->mSeenLoadStart = false;
   }
 }
 
 void
 XMLHttpRequestWorker::DispatchPrematureAbortEvent(EventTarget* aTarget,
+                                                  Proxy* aProxy,
                                                   const nsAString& aEventType,
                                                   bool aUploadTarget,
                                                   ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
   MOZ_ASSERT(aTarget);
 
-  if (!mProxy) {
+  if (!aProxy) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   RefPtr<Event> event;
   if (aEventType.EqualsLiteral("readystatechange")) {
     event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
     event->InitEvent(aEventType, false, false);
   }
   else {
     ProgressEventInit init;
     init.mBubbles = false;
     init.mCancelable = false;
     if (aUploadTarget) {
-      init.mLengthComputable = mProxy->mLastUploadLengthComputable;
-      init.mLoaded = mProxy->mLastUploadLoaded;
-      init.mTotal = mProxy->mLastUploadTotal;
+      init.mLengthComputable = aProxy->mLastUploadLengthComputable;
+      init.mLoaded = aProxy->mLastUploadLoaded;
+      init.mTotal = aProxy->mLastUploadTotal;
     }
     else {
-      init.mLengthComputable = mProxy->mLastLengthComputable;
-      init.mLoaded = mProxy->mLastLoaded;
-      init.mTotal = mProxy->mLastTotal;
+      init.mLengthComputable = aProxy->mLastLengthComputable;
+      init.mLoaded = aProxy->mLastLoaded;
+      init.mTotal = aProxy->mLastTotal;
     }
     event = ProgressEvent::Constructor(aTarget, aEventType, init);
   }
 
   if (!event) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
@@ -1771,54 +1786,55 @@ XMLHttpRequestWorker::DispatchPrematureA
 
   bool dummy;
   aTarget->DispatchEvent(event, &dummy);
 }
 
 void
 XMLHttpRequestWorker::Unpin()
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
-
-  MOZ_ASSERT(mRooted, "Mismatched calls to Unpin!");
-
-  ReleaseWorker();
-
-  mRooted = false;
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
+
+  MOZ_ASSERT(mWorkerRef, "Mismatched calls to Unpin!");
+
+  mWorkerRef = nullptr;
 
   NS_RELEASE_THIS();
 }
 
 void
 XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
                                    ErrorResult& aRv)
 {
   MOZ_ASSERT(aRunnable);
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   // No send() calls when open is running.
   if (mProxy->mOpenCount) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   bool hasUploadListeners = mUpload ? mUpload->HasListeners() : false;
 
-  MaybePin(aRv);
-  if (aRv.Failed()) {
+  if (NS_WARN_IF(!MaybePin())) {
+    // Worker is shutting down. Let's ignore this send request.
     return;
   }
 
   AutoUnpinXHR autoUnpin(this);
   Maybe<AutoSyncLoopHolder> autoSyncLoop;
 
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
   nsCOMPtr<nsIEventTarget> syncLoopTarget;
   bool isSyncXHR = mProxy->mIsSyncXHR;
   if (isSyncXHR) {
-    autoSyncLoop.emplace(mWorkerPrivate, Terminating);
+    autoSyncLoop.emplace(workerPrivate, Terminating);
     syncLoopTarget = autoSyncLoop->GetEventTarget();
     if (!syncLoopTarget) {
       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
   }
 
   mProxy->mOuterChannelId++;
@@ -1827,17 +1843,17 @@ XMLHttpRequestWorker::SendInternal(SendR
   aRunnable->SetHaveUploadListeners(hasUploadListeners);
 
   mStateData.mFlagSend = true;
 
   aRunnable->Dispatch(Terminating, aRv);
   if (aRv.Failed()) {
     // Dispatch() may have spun the event loop and we may have already unrooted.
     // If so we don't want autoUnpin to try again.
-    if (!mRooted) {
+    if (!mWorkerRef) {
       autoUnpin.Clear();
     }
     return;
   }
 
   if (!isSyncXHR)  {
     autoUnpin.Clear();
     MOZ_ASSERT(!autoSyncLoop);
@@ -1854,58 +1870,48 @@ XMLHttpRequestWorker::SendInternal(SendR
   // that this autoSyncLoop->Run() can never fail, since the StopSyncLoop call
   // for it will come from ProxyCompleteRunnable and that always passes true for
   // the second arg.
   if (!succeeded && !aRv.Failed()) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
 }
 
-bool
-XMLHttpRequestWorker::Notify(WorkerStatus aStatus)
-{
-  mWorkerPrivate->AssertIsOnWorkerThread();
-
-  if (aStatus >= Canceling && !mCanceled) {
-    mCanceled = true;
-    ReleaseProxy(WorkerIsGoingAway);
-  }
-
-  return true;
-}
-
 void
 XMLHttpRequestWorker::Open(const nsACString& aMethod,
                            const nsAString& aUrl, bool aAsync,
                            const Optional<nsAString>& aUser,
                            const Optional<nsAString>& aPassword,
                            ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
+
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (mProxy) {
     MaybeDispatchPrematureAbortEvents(aRv);
-    if (aRv.Failed()) {
+    if (aRv.Failed() || !mProxy) {
       return;
     }
   }
   else {
-    mProxy = new Proxy(this, mWorkerPrivate->GetClientInfo(),
-                       mWorkerPrivate->GetController(), mMozAnon, mMozSystem);
+    mProxy = new Proxy(this, workerPrivate->GetClientInfo(),
+                       workerPrivate->GetController(), mMozAnon, mMozSystem);
   }
 
   mProxy->mOuterEventStreamId++;
 
   RefPtr<OpenRunnable> runnable =
-    new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword,
+    new OpenRunnable(workerPrivate, mProxy, aMethod, aUrl, aUser, aPassword,
                      mBackgroundRequest, mWithCredentials,
                      mTimeout, mResponseType);
 
   ++mProxy->mOpenCount;
   runnable->Dispatch(Terminating, aRv);
   if (aRv.Failed()) {
     if (mProxy && !--mProxy->mOpenCount) {
       ReleaseProxy();
@@ -1923,108 +1929,107 @@ XMLHttpRequestWorker::Open(const nsACStr
   --mProxy->mOpenCount;
   mProxy->mIsSyncXHR = !aAsync;
 }
 
 void
 XMLHttpRequestWorker::SetRequestHeader(const nsACString& aHeader,
                                        const nsACString& aValue, ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (!mProxy) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   RefPtr<SetRequestHeaderRunnable> runnable =
-    new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue);
+    new SetRequestHeaderRunnable(mProxy, aHeader, aValue);
   runnable->Dispatch(Terminating, aRv);
 }
 
 void
 XMLHttpRequestWorker::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   mTimeout = aTimeout;
 
   if (!mProxy) {
     // Open may not have been called yet, in which case we'll handle the
     // timeout in OpenRunnable.
     return;
   }
 
   RefPtr<SetTimeoutRunnable> runnable =
-    new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout);
+    new SetTimeoutRunnable(mProxy, aTimeout);
   runnable->Dispatch(Terminating, aRv);
 }
 
 void
 XMLHttpRequestWorker::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   mWithCredentials = aWithCredentials;
 
   if (!mProxy) {
     // Open may not have been called yet, in which case we'll handle the
     // credentials in OpenRunnable.
     return;
   }
 
   RefPtr<SetWithCredentialsRunnable> runnable =
-    new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials);
+    new SetWithCredentialsRunnable(mProxy, aWithCredentials);
   runnable->Dispatch(Terminating, aRv);
 }
 
 void
 XMLHttpRequestWorker::SetMozBackgroundRequest(bool aBackgroundRequest,
                                               ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   mBackgroundRequest = aBackgroundRequest;
 
   if (!mProxy) {
     // Open may not have been called yet, in which case we'll handle the
     // background request in OpenRunnable.
     return;
   }
 
   RefPtr<SetBackgroundRequestRunnable> runnable =
-    new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy,
-                                     aBackgroundRequest);
+    new SetBackgroundRequestRunnable(mProxy, aBackgroundRequest);
   runnable->Dispatch(Terminating, aRv);
 }
 
 XMLHttpRequestUpload*
 XMLHttpRequestWorker::GetUpload(ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return nullptr;
   }
 
   if (!mUpload) {
     mUpload = new XMLHttpRequestUpload();
@@ -2038,32 +2043,32 @@ XMLHttpRequestWorker::GetUpload(ErrorRes
   return mUpload;
 }
 
 void
 XMLHttpRequestWorker::Send(JSContext* aCx,
                            const Nullable<DocumentOrBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString>& aData,
                            ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (!mProxy) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   RefPtr<SendRunnable> sendRunnable;
 
   if (aData.IsNull()) {
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, VoidString());
+    sendRunnable = new SendRunnable(mProxy, VoidString());
     // Nothing to clone.
   }
 
   else if (aData.Value().IsDocument()) {
     MOZ_CRASH("Documents are not exposed to workers.");
   }
 
   else if (aData.Value().IsBlob()) {
@@ -2079,26 +2084,26 @@ XMLHttpRequestWorker::Send(JSContext* aC
     }
 
     JS::Rooted<JS::Value> value(aCx);
     if (!GetOrCreateDOMReflector(aCx, blob, &value)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+    sendRunnable = new SendRunnable(mProxy, EmptyString());
 
     sendRunnable->Write(aCx, value, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
   else if (aData.Value().IsArrayBuffer()) {
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+    sendRunnable = new SendRunnable(mProxy, EmptyString());
 
     JS::Rooted<JS::Value> value(aCx);
     value.setObject(*aData.Value().GetAsArrayBuffer().Obj());
 
     sendRunnable->Write(aCx, value, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
@@ -2109,17 +2114,17 @@ XMLHttpRequestWorker::Send(JSContext* aC
 
     if (JS_IsTypedArrayObject(body.Obj()) &&
         JS_GetTypedArraySharedness(body.Obj())) {
       // Throw if the object is mapping shared memory (must opt in).
       aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of XMLHttpRequest.send"));
       return;
     }
 
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+    sendRunnable = new SendRunnable(mProxy, EmptyString());
 
     JS::Rooted<JS::Value> value(aCx);
     value.setObject(*body.Obj());
 
     sendRunnable->Write(aCx, value, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
@@ -2128,54 +2133,53 @@ XMLHttpRequestWorker::Send(JSContext* aC
   else if (aData.Value().IsFormData()) {
     JS::Rooted<JS::Value> value(aCx);
     if (!GetOrCreateDOMReflector(aCx, &aData.Value().GetAsFormData(),
                                  &value)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+    sendRunnable = new SendRunnable(mProxy, EmptyString());
 
     sendRunnable->Write(aCx, value, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
   else if (aData.Value().IsURLSearchParams()) {
     JS::Rooted<JS::Value> value(aCx);
     if (!GetOrCreateDOMReflector(aCx, &aData.Value().GetAsURLSearchParams(),
                                  &value)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+    sendRunnable = new SendRunnable(mProxy, EmptyString());
 
     sendRunnable->Write(aCx, value, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
   else if (aData.Value().IsUSVString()) {
-    sendRunnable = new SendRunnable(mWorkerPrivate, mProxy,
-                                    aData.Value().GetAsUSVString());
+    sendRunnable = new SendRunnable(mProxy, aData.Value().GetAsUSVString());
     // Nothing to clone.
   }
 
   MOZ_ASSERT(sendRunnable);
   SendInternal(sendRunnable, aRv);
 }
 
 void
 XMLHttpRequestWorker::Abort(ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (!mProxy) {
     return;
@@ -2198,80 +2202,83 @@ XMLHttpRequestWorker::Abort(ErrorResult&
   }
 
   if (mStateData.mReadyState == 4) {
     // No one did anything to us while we fired abort events, so reset our state
     // to "unsent"
     mStateData.mReadyState = 0;
   }
 
+  if (!mProxy) {
+    return;
+  }
+
   mProxy->mOuterEventStreamId++;
 
-  RefPtr<AbortRunnable> runnable = new AbortRunnable(mWorkerPrivate, mProxy);
+  RefPtr<AbortRunnable> runnable = new AbortRunnable(mProxy);
   runnable->Dispatch(Terminating, aRv);
 }
 
 void
 XMLHttpRequestWorker::GetResponseHeader(const nsACString& aHeader,
                                         nsACString& aResponseHeader, ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (!mProxy) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCString responseHeader;
   RefPtr<GetResponseHeaderRunnable> runnable =
-    new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader,
-                                  responseHeader);
+    new GetResponseHeaderRunnable(mProxy, aHeader, responseHeader);
   runnable->Dispatch(Terminating, aRv);
   if (aRv.Failed()) {
     return;
   }
   aResponseHeader = responseHeader;
 }
 
 void
 XMLHttpRequestWorker::GetAllResponseHeaders(nsACString& aResponseHeaders,
                                             ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   if (!mProxy) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCString responseHeaders;
   RefPtr<GetAllResponseHeadersRunnable> runnable =
-    new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders);
+    new GetAllResponseHeadersRunnable(mProxy, responseHeaders);
   runnable->Dispatch(Terminating, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   aResponseHeaders = responseHeaders;
 }
 
 void
 XMLHttpRequestWorker::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   // We're supposed to throw if the state is not OPENED or HEADERS_RECEIVED. We
   // can detect OPENED really easily but we can't detect HEADERS_RECEIVED in a
@@ -2281,25 +2288,25 @@ XMLHttpRequestWorker::OverrideMimeType(c
   if (!mProxy || (SendInProgress() &&
                   (mProxy->mSeenLoadStart ||
                    mStateData.mReadyState > 1))) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   RefPtr<OverrideMimeTypeRunnable> runnable =
-    new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType);
+    new OverrideMimeTypeRunnable(mProxy, aMimeType);
   runnable->Dispatch(Terminating, aRv);
 }
 
 void
 XMLHttpRequestWorker::SetResponseType(XMLHttpRequestResponseType aResponseType,
                                       ErrorResult& aRv)
 {
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
 
   // "document" is fine for the main thread but not for a worker. Short-circuit
   // that here.
@@ -2317,43 +2324,43 @@ XMLHttpRequestWorker::SetResponseType(XM
   if (SendInProgress() &&
       (mProxy->mSeenLoadStart ||
        mStateData.mReadyState > 1)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   RefPtr<SetResponseTypeRunnable> runnable =
-    new SetResponseTypeRunnable(mWorkerPrivate, mProxy, aResponseType);
+    new SetResponseTypeRunnable(mProxy, aResponseType);
   runnable->Dispatch(Terminating, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   mResponseType = runnable->ResponseType();
 }
 
 void
-XMLHttpRequestWorker::GetResponse(JSContext* /* unused */,
+XMLHttpRequestWorker::GetResponse(JSContext* aCx,
                                   JS::MutableHandle<JS::Value> aResponse,
                                   ErrorResult& aRv)
 {
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
+
   if (NS_SUCCEEDED(mStateData.mResponseTextResult) &&
       mStateData.mResponse.isUndefined()) {
     MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult));
 
     if (mStateData.mResponseText.IsEmpty()) {
-      mStateData.mResponse =
-        JS_GetEmptyStringValue(mWorkerPrivate->GetJSContext());
+      mStateData.mResponse = JS_GetEmptyStringValue(aCx);
     } else {
       XMLHttpRequestStringSnapshotReaderHelper helper(mStateData.mResponseText);
 
       JSString* str =
-        JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
-                            helper.Buffer(), helper.Length());
+        JS_NewUCStringCopyN(aCx, helper.Buffer(), helper.Length());
 
       if (!str) {
         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
         return;
       }
 
       mStateData.mResponse.setString(str);
     }
@@ -2373,25 +2380,27 @@ XMLHttpRequestWorker::GetResponseText(DO
 
   if (!mStateData.mResponseText.GetAsString(aResponseText)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 }
 
 void
-XMLHttpRequestWorker::UpdateState(const StateData& aStateData,
+XMLHttpRequestWorker::UpdateState(JSContext* aCx,
+                                  const StateData& aStateData,
                                   bool aUseCachedArrayBufferResponse)
 {
+  NS_ASSERT_OWNINGTHREAD(XMLHttpRequestWorker);
+
   if (aUseCachedArrayBufferResponse) {
     MOZ_ASSERT(mStateData.mResponse.isObject() &&
                JS_IsArrayBufferObject(&mStateData.mResponse.toObject()));
 
-    JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
-                                   mStateData.mResponse);
+    JS::Rooted<JS::Value> response(aCx, mStateData.mResponse);
     mStateData = aStateData;
     mStateData.mResponse = response;
   }
   else {
     mStateData = aStateData;
   }
 
   XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
--- a/dom/xhr/XMLHttpRequestWorker.h
+++ b/dom/xhr/XMLHttpRequestWorker.h
@@ -5,28 +5,26 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_XMLHttpRequestWorker_h
 #define mozilla_dom_XMLHttpRequestWorker_h
 
 #include "XMLHttpRequest.h"
 #include "XMLHttpRequestString.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/dom/WorkerHolder.h"
 
 namespace mozilla {
 namespace dom {
 
 class Proxy;
 class SendRunnable;
 class DOMString;
-class WorkerPrivate;
+class StrongWorkerRef;
 
-class XMLHttpRequestWorker final : public XMLHttpRequest,
-                                   public WorkerHolder
+class XMLHttpRequestWorker final : public XMLHttpRequest
 {
 public:
   struct StateData
   {
     XMLHttpRequestStringSnapshot mResponseText;
     nsString mResponseURL;
     uint32_t mStatus;
     nsCString mStatusText;
@@ -43,24 +41,23 @@ public:
       mStatusResult(NS_OK), mResponseResult(NS_OK)
     { }
 
     void trace(JSTracer* trc);
   };
 
 private:
   RefPtr<XMLHttpRequestUpload> mUpload;
-  WorkerPrivate* mWorkerPrivate;
+  RefPtr<StrongWorkerRef> mWorkerRef;
   RefPtr<Proxy> mProxy;
   XMLHttpRequestResponseType mResponseType;
   StateData mStateData;
 
   uint32_t mTimeout;
 
-  bool mRooted;
   bool mBackgroundRequest;
   bool mWithCredentials;
   bool mCanceled;
 
   bool mMozAnon;
   bool mMozSystem;
 
 public:
@@ -72,19 +69,16 @@ public:
   static already_AddRefed<XMLHttpRequest>
   Construct(const GlobalObject& aGlobal,
             const MozXMLHttpRequestParameters& aParams,
             ErrorResult& aRv);
 
   void
   Unpin();
 
-  bool
-  Notify(WorkerStatus aStatus) override;
-
   virtual uint16_t
   ReadyState() const override
   {
     return mStateData.mReadyState;
   }
 
   virtual void
   Open(const nsACString& aMethod, const nsAString& aUrl,
@@ -246,17 +240,18 @@ public:
 
   XMLHttpRequestUpload*
   GetUploadObjectNoCreate() const
   {
     return mUpload;
   }
 
   void
-  UpdateState(const StateData& aStateData, bool aUseCachedArrayBufferResponse);
+  UpdateState(JSContext* aCx, const StateData& aStateData,
+              bool aUseCachedArrayBufferResponse);
 
   void
   NullResponseText()
   {
     mStateData.mResponseText.SetVoid();
     mStateData.mResponse.setNull();
   }
 
@@ -273,36 +268,36 @@ public:
   virtual bool MozSystem() const override
   {
     return mMozSystem;
   }
 
   bool
   SendInProgress() const
   {
-    return mRooted;
+    return !!mWorkerRef;
   }
 
 private:
-  explicit XMLHttpRequestWorker(WorkerPrivate* aWorkerPrivate);
+  XMLHttpRequestWorker();
   ~XMLHttpRequestWorker();
 
   enum ReleaseType { Default, XHRIsGoingAway, WorkerIsGoingAway };
 
   void
   ReleaseProxy(ReleaseType aType = Default);
 
-  void
-  MaybePin(ErrorResult& aRv);
+  bool
+  MaybePin();
 
   void
   MaybeDispatchPrematureAbortEvents(ErrorResult& aRv);
 
   void
-  DispatchPrematureAbortEvent(EventTarget* aTarget,
+  DispatchPrematureAbortEvent(EventTarget* aTarget, Proxy* aProxy,
                               const nsAString& aEventType, bool aUploadTarget,
                               ErrorResult& aRv);
 
   void
   Send(JSContext* aCx, JS::Handle<JSObject*> aBody, ErrorResult& aRv);
 
   void
   SendInternal(SendRunnable* aRunnable,
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -366455,16 +366455,22 @@
     ]
    ],
    "xhr/xmlhttprequest-basic.htm": [
     [
      "/xhr/xmlhttprequest-basic.htm",
      {}
     ]
    ],
+   "xhr/xmlhttprequest-closing-worker.html": [
+    [
+     "/xhr/xmlhttprequest-closing-worker.html",
+     {}
+    ]
+   ],
    "xhr/xmlhttprequest-eventtarget.htm": [
     [
      "/xhr/xmlhttprequest-eventtarget.htm",
      {}
     ]
    ],
    "xhr/xmlhttprequest-network-error-sync.htm": [
     [
@@ -601504,16 +601510,20 @@
   "xhr/timeout-sync.htm": [
    "aefabb6eedc02aae1a46e860c12e104de251efa1",
    "testharness"
   ],
   "xhr/xmlhttprequest-basic.htm": [
    "a67d1876d6245fb94d60a937b633c87c51a04d21",
    "testharness"
   ],
+  "xhr/xmlhttprequest-closing-worker.html": [
+   "2e12b49aca2dc3908837b6b419c92cb890e60e3f",
+   "testharness"
+  ],
   "xhr/xmlhttprequest-eventtarget.htm": [
    "40c886f79399108db3ded8a23848905dcf9e0862",
    "testharness"
   ],
   "xhr/xmlhttprequest-network-error-sync.htm": [
    "ae354ecee8e774f2005daca9084d3e6422f829be",
    "testharness"
   ],