Bug 1571530 - Cleanup confusing lifetime of SheetLoadData. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 16 Aug 2019 10:56:09 +0000
changeset 488486 aec66f88bfd05871e1b03067ba70608f6b320979
parent 488485 1f4c64e73cfc266d25c595a1e943737f577c5e0a
child 488487 a28efee19e9ceda71182874e51e19ee5e3ea72cb
push id36444
push userccoroiu@mozilla.com
push dateFri, 16 Aug 2019 16:24:18 +0000
treeherdermozilla-central@8a9e9189cd98 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1571530
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1571530 - Cleanup confusing lifetime of SheetLoadData. r=heycam Saving a refcount bump is not worth the churn. Use a proper RefPtr<> everywhere instead of manual refcounting, and don't make DoSheetComplete call NS_RELEASE unconditionally. Also, make clear by using references where null is expected or not. Also, properly use a RefPtr in mPendingDatas, since they are strong pointers, in fact. Finally, remove some unused macros from nsCSSValue of which this code was the last consumer. Differential Revision: https://phabricator.services.mozilla.com/D41090
layout/style/GeckoBindings.cpp
layout/style/Loader.cpp
layout/style/Loader.h
layout/style/SheetLoadData.h
layout/style/StreamLoader.cpp
layout/style/StreamLoader.h
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
layout/style/nsCSSValue.h
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1742,17 +1742,17 @@ static already_AddRefed<StyleSheet> Load
   MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
 
   RefPtr<MediaList> media = new MediaList(std::move(aMediaList));
   nsCOMPtr<nsIURI> uri = aURL.GetURI();
   nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
 
   StyleSheet* previousFirstChild = aParent->GetFirstChild();
   if (NS_SUCCEEDED(rv)) {
-    rv = aLoader->LoadChildSheet(aParent, aParentLoadData, uri, media,
+    rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
                                  aReusableSheets);
   }
 
   if (NS_FAILED(rv) || !aParent->GetFirstChild() ||
       aParent->GetFirstChild() == previousFirstChild) {
     // Servo and Gecko have different ideas of what a valid URL is, so we might
     // get in here with a URL string that NS_NewURI can't handle.  We may also
     // reach here via an import cycle.  For the import cycle case, we need some
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -160,17 +160,17 @@ class SheetLoadDataHashKey : public nsUR
       : nsURIHashKey(std::move(toMove)),
         mPrincipal(std::move(toMove.mPrincipal)),
         mReferrerInfo(std::move(toMove.mReferrerInfo)),
         mCORSMode(std::move(toMove.mCORSMode)),
         mParsingMode(std::move(toMove.mParsingMode)) {
     MOZ_COUNT_CTOR(SheetLoadDataHashKey);
   }
 
-  explicit SheetLoadDataHashKey(css::SheetLoadData* aLoadData);
+  explicit SheetLoadDataHashKey(css::SheetLoadData&);
 
   ~SheetLoadDataHashKey() { MOZ_COUNT_DTOR(SheetLoadDataHashKey); }
 
   SheetLoadDataHashKey* GetKey() const {
     return const_cast<SheetLoadDataHashKey*>(this);
   }
   const SheetLoadDataHashKey* GetKeyPointer() const { return this; }
 
@@ -219,22 +219,22 @@ class SheetLoadDataHashKey : public nsUR
 
  protected:
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
   CORSMode mCORSMode;
   css::SheetParsingMode mParsingMode;
 };
 
-SheetLoadDataHashKey::SheetLoadDataHashKey(css::SheetLoadData* aLoadData)
-    : nsURIHashKey(aLoadData->mURI),
-      mPrincipal(aLoadData->mLoaderPrincipal),
-      mReferrerInfo(aLoadData->ReferrerInfo()),
-      mCORSMode(aLoadData->mSheet->GetCORSMode()),
-      mParsingMode(aLoadData->mSheet->ParsingMode()) {
+SheetLoadDataHashKey::SheetLoadDataHashKey(css::SheetLoadData& aLoadData)
+    : nsURIHashKey(aLoadData.mURI),
+      mPrincipal(aLoadData.mLoaderPrincipal),
+      mReferrerInfo(aLoadData.ReferrerInfo()),
+      mCORSMode(aLoadData.mSheet->GetCORSMode()),
+      mParsingMode(aLoadData.mSheet->ParsingMode()) {
   MOZ_COUNT_CTOR(SheetLoadDataHashKey);
 }
 }  // namespace mozilla
 
 namespace mozilla {
 namespace css {
 
 /********************************
@@ -357,22 +357,26 @@ SheetLoadData::SheetLoadData(Loader* aLo
       mRequestingNode(aRequestingNode),
       mPreloadEncoding(aPreloadEncoding) {
   MOZ_ASSERT(mLoader, "Must have a loader!");
   MOZ_ASSERT(!mUseSystemPrincipal || mSyncLoad,
              "Shouldn't use system principal for async loads");
 }
 
 SheetLoadData::~SheetLoadData() {
-  NS_CSS_NS_RELEASE_LIST_MEMBER(SheetLoadData, this, mNext);
+  // Do this iteratively to avoid blowing up the stack.
+  RefPtr<SheetLoadData> next = mNext.forget();
+  while (next) {
+    next = next->mNext.forget();
+  }
 }
 
 NS_IMETHODIMP
 SheetLoadData::Run() {
-  mLoader->HandleLoadEvent(this);
+  mLoader->HandleLoadEvent(*this);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SheetLoadData::OnDispatchedEvent() { return NS_OK; }
 
 NS_IMETHODIMP
 SheetLoadData::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
@@ -446,19 +450,21 @@ bool LoaderReusableStyleSheets::FindReus
   }
   return false;
 }
 
 // A struct keeping alive various records of sheets that are loading, deferred,
 // or already loaded (the later one for caching purposes).
 struct Loader::Sheets {
   nsRefPtrHashtable<SheetLoadDataHashKey, StyleSheet> mCompleteSheets;
-  // The SheetLoadData pointers below are weak references.
+
+  nsRefPtrHashtable<SheetLoadDataHashKey, SheetLoadData> mPendingDatas;
+
+  // The SheetLoadData pointers in mLoadingDatas below are weak references.
   nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*> mLoadingDatas;
-  nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*> mPendingDatas;
 
   // A cache hit or miss. It is a miss if the `StyleSheet` is null.
   using CacheResult = Tuple<RefPtr<StyleSheet>, SheetState>;
   CacheResult Lookup(SheetLoadDataHashKey&, bool aSyncLoad);
 };
 
 static void AssertComplete(const StyleSheet& aSheet) {
   // This sheet came from the XUL cache or our per-document hashtable; it
@@ -536,17 +542,17 @@ auto Loader::Sheets::Lookup(SheetLoadDat
   }
 
   if (SheetLoadData* data = mLoadingDatas.Get(&aKey)) {
     LOG(("  From loading: %p", data->mSheet.get()));
     AssertIncompleteSheetMatches(*data, aKey);
     return MakeTuple(CloneSheet(*data->mSheet), SheetState::Loading);
   }
 
-  if (SheetLoadData* data = mPendingDatas.Get(&aKey)) {
+  if (SheetLoadData* data = mPendingDatas.GetWeak(&aKey)) {
     LOG(("  From pending: %p", data->mSheet.get()));
     AssertIncompleteSheetMatches(*data, aKey);
     return MakeTuple(CloneSheet(*data->mSheet), SheetState::Pending);
   }
 
   return {};
 }
 
@@ -594,32 +600,32 @@ void Loader::DocumentStyleSheetSetChange
 
   // start any pending alternates that aren't alternates anymore
   if (!mSheets) {
     return;
   }
 
   LoadDataArray arr(mSheets->mPendingDatas.Count());
   for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
-    SheetLoadData* data = iter.Data();
+    RefPtr<SheetLoadData>& data = iter.Data();
     MOZ_ASSERT(data, "Must have a data");
 
     // Note that we don't want to affect what the selected style set is, so
     // use true for aHasAlternateRel.
     auto isAlternate = data->mLoader->IsAlternateSheet(data->mTitle, true);
     if (isAlternate == IsAlternate::No) {
-      arr.AppendElement(data);
+      arr.AppendElement(std::move(data));
       iter.Remove();
     }
   }
 
   mDatasToNotifyOn += arr.Length();
-  for (uint32_t i = 0; i < arr.Length(); ++i) {
+  for (RefPtr<SheetLoadData>& data : arr) {
     --mDatasToNotifyOn;
-    LoadSheet(arr[i], SheetState::NeedsParser, IsPreload::No);
+    LoadSheet(*data, SheetState::NeedsParser, IsPreload::No);
   }
 }
 
 static const char kCharsetSym[] = "@charset \"";
 
 static bool GetCharsetFromData(const char* aStyleSheetData,
                                uint32_t aDataLength, nsACString& aCharset) {
   aCharset.Truncate();
@@ -758,17 +764,17 @@ nsresult SheetLoadData::VerifySheetReady
     // called and calling it again will lead to an extra NS_RELEASE on
     // this data and a likely crash.
     return NS_OK;
   }
 
   if (!mLoader->mDocument && !mIsNonDocumentSheet) {
     // Sorry, we don't care about this load anymore
     LOG_WARN(("  No document and not non-document sheet; dropping load"));
-    mLoader->SheetComplete(this, NS_BINDING_ABORTED);
+    mLoader->SheetComplete(*this, NS_BINDING_ABORTED);
     return NS_OK;
   }
 
   if (NS_FAILED(aStatus)) {
     LOG_WARN(
         ("  Load failed: status 0x%" PRIx32, static_cast<uint32_t>(aStatus)));
     // Handle sheet not loading error because source was a tracking URL (or
     // fingerprinting, cryptomining, etc).
@@ -783,22 +789,22 @@ nsresult SheetLoadData::VerifySheetReady
         for (SheetLoadData* data = this; data; data = data->mNext) {
           // mOwningElement may be null but AddBlockTrackingNode can cope
           nsCOMPtr<nsIContent> content =
               do_QueryInterface(data->mOwningElement);
           doc->AddBlockedNodeByClassifier(content);
         }
       }
     }
-    mLoader->SheetComplete(this, aStatus);
+    mLoader->SheetComplete(*this, aStatus);
     return NS_OK;
   }
 
   if (!aChannel) {
-    mLoader->SheetComplete(this, NS_OK);
+    mLoader->SheetComplete(*this, NS_OK);
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> originalURI;
   aChannel->GetOriginalURI(getter_AddRefs(originalURI));
 
   // If the channel's original URI is "chrome:", we want that, since
   // the observer code in nsXULPrototypeCache depends on chrome stylesheets
@@ -806,17 +812,17 @@ nsresult SheetLoadData::VerifySheetReady
   // this codepath seems nondeterministic.)
   // Otherwise we want the potentially-HTTP-redirected URI.
   nsCOMPtr<nsIURI> channelURI;
   NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
 
   if (!channelURI || !originalURI) {
     NS_ERROR("Someone just violated the nsIRequest contract");
     LOG_WARN(("  Channel without a URI.  Bad!"));
-    mLoader->SheetComplete(this, NS_ERROR_UNEXPECTED);
+    mLoader->SheetComplete(*this, NS_ERROR_UNEXPECTED);
     return NS_OK;
   }
 
   nsCOMPtr<nsIPrincipal> principal;
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   nsresult result = NS_ERROR_NOT_AVAILABLE;
   if (secMan) {  // Could be null if we already shut down
     if (mUseSystemPrincipal) {
@@ -824,17 +830,17 @@ nsresult SheetLoadData::VerifySheetReady
     } else {
       result = secMan->GetChannelResultPrincipal(aChannel,
                                                  getter_AddRefs(principal));
     }
   }
 
   if (NS_FAILED(result)) {
     LOG_WARN(("  Couldn't get principal"));
-    mLoader->SheetComplete(this, result);
+    mLoader->SheetComplete(*this, result);
     return NS_OK;
   }
 
   mSheet->SetPrincipal(principal);
 
   if (mLoaderPrincipal && mSheet->GetCORSMode() == CORS_NONE) {
     bool subsumed;
     result = mLoaderPrincipal->Subsumes(principal, &subsumed);
@@ -846,17 +852,17 @@ nsresult SheetLoadData::VerifySheetReady
   // If it's an HTTP channel, we want to make sure this is not an
   // error document we got.
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
   if (httpChannel) {
     bool requestSucceeded;
     result = httpChannel->GetRequestSucceeded(&requestSucceeded);
     if (NS_SUCCEEDED(result) && !requestSucceeded) {
       LOG(("  Load returned an error page"));
-      mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
+      mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE);
       return NS_OK;
     }
 
     nsAutoCString sourceMapURL;
     if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
       mSheet->SetSourceMapURL(NS_ConvertUTF8toUTF16(sourceMapURL));
     }
   }
@@ -901,17 +907,17 @@ nsresult SheetLoadData::VerifySheetReady
     nsCOMPtr<nsIURI> referrer = ReferrerInfo()->GetOriginalReferrer();
     nsContentUtils::ReportToConsole(
         errorFlag, NS_LITERAL_CSTRING("CSS Loader"), mLoader->mDocument,
         nsContentUtils::eCSS_PROPERTIES, errorMessage, strings, referrer);
 
     if (errorFlag == nsIScriptError::errorFlag) {
       LOG_WARN(
           ("  Ignoring sheet with improper MIME type %s", contentType.get()));
-      mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
+      mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE);
       return NS_OK;
     }
   }
 
   SRIMetadata sriMetadata;
   mSheet->GetIntegrity(sriMetadata);
   if (!sriMetadata.IsEmpty()) {
     nsAutoCString sourceUri;
@@ -928,17 +934,17 @@ nsresult SheetLoadData::VerifySheetReady
     } else {
       mLoader->mReporter->FlushConsoleReports(mLoader->mDocument);
     }
 
     if (NS_FAILED(rv)) {
       LOG(("  Load was blocked by SRI"));
       MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
               ("css::Loader::OnStreamComplete, bad metadata"));
-      mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
+      mLoader->SheetComplete(*this, NS_ERROR_SRI_CORRUPT);
       return NS_OK;
     }
   }
 
   // Enough to set the URIs on mSheet, since any sibling datas we have share
   // the same mInner as mSheet and will thus get the same URI.
   mSheet->SetURIs(channelURI, originalURI, channelURI);
 
@@ -1227,54 +1233,53 @@ void Loader::InsertChildSheet(StyleSheet
 /**
  * LoadSheet handles the actual load of a sheet.  If the load is
  * supposed to be synchronous it just opens a channel synchronously
  * using the given uri, wraps the resulting stream in a converter
  * stream and calls ParseSheet.  Otherwise it tries to look for an
  * existing load for this URI and piggyback on it.  Failing all that,
  * a new load is kicked off asynchronously.
  */
-nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
+nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState,
                            IsPreload aIsPreload) {
   LOG(("css::Loader::LoadSheet"));
-  MOZ_ASSERT(aLoadData, "Need a load data");
-  MOZ_ASSERT(aLoadData->mURI, "Need a URI to load");
-  MOZ_ASSERT(aLoadData->mSheet, "Need a sheet to load into");
+  MOZ_ASSERT(aLoadData.mURI, "Need a URI to load");
+  MOZ_ASSERT(aLoadData.mSheet, "Need a sheet to load into");
   MOZ_ASSERT(aSheetState != SheetState::Complete, "Why bother?");
-  MOZ_ASSERT(!aLoadData->mUseSystemPrincipal || aLoadData->mSyncLoad,
+  MOZ_ASSERT(!aLoadData.mUseSystemPrincipal || aLoadData.mSyncLoad,
              "Shouldn't use system principal for async loads");
   NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
 
-  LOG_URI("  Load from: '%s'", aLoadData->mURI);
+  LOG_URI("  Load from: '%s'", aLoadData.mURI);
 
   nsresult rv = NS_OK;
 
-  if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
+  if (!mDocument && !aLoadData.mIsNonDocumentSheet) {
     // No point starting the load; just release all the data and such.
     LOG_WARN(("  No document and not non-document sheet; pre-dropping load"));
     SheetComplete(aLoadData, NS_BINDING_ABORTED);
     return NS_BINDING_ABORTED;
   }
 
   SRIMetadata sriMetadata;
-  aLoadData->mSheet->GetIntegrity(sriMetadata);
+  aLoadData.mSheet->GetIntegrity(sriMetadata);
 
-  if (aLoadData->mSyncLoad) {
+  if (aLoadData.mSyncLoad) {
     LOG(("  Synchronous load"));
-    NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
+    NS_ASSERTION(!aLoadData.mObserver, "Observer for a sync load?");
     NS_ASSERTION(aSheetState == SheetState::NeedsParser,
                  "Sync loads can't reuse existing async loads");
 
     // Create a StreamLoader instance to which we will feed
     // the data from the sync load.  Do this before creating the
     // channel to make error recovery simpler.
     nsCOMPtr<nsIStreamListener> streamLoader = new StreamLoader(aLoadData);
 
     if (mDocument) {
-      mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
+      mozilla::net::PredictorLearn(aLoadData.mURI, mDocument->GetDocumentURI(),
                                    nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
                                    mDocument);
     }
 
     nsSecurityFlags securityFlags =
         nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
         nsILoadInfo::SEC_ALLOW_CHROME;
 
@@ -1285,50 +1290,50 @@ nsresult Loader::LoadSheet(SheetLoadData
 
     // Just load it
     nsCOMPtr<nsIChannel> channel;
     // Note that we are calling NS_NewChannelWithTriggeringPrincipal() with both
     // a node and a principal.
     // This is because of a case where the node is the document being styled and
     // the principal is the stylesheet (perhaps from a different origin) that is
     // applying the styles.
-    if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
+    if (aLoadData.mRequestingNode && aLoadData.mLoaderPrincipal) {
       rv = NS_NewChannelWithTriggeringPrincipal(
-          getter_AddRefs(channel), aLoadData->mURI, aLoadData->mRequestingNode,
-          aLoadData->mLoaderPrincipal, securityFlags, contentPolicyType);
+          getter_AddRefs(channel), aLoadData.mURI, aLoadData.mRequestingNode,
+          aLoadData.mLoaderPrincipal, securityFlags, contentPolicyType);
     } else {
       // either we are loading something inside a document, in which case
       // we should always have a requestingNode, or we are loading something
       // outside a document, in which case the loadingPrincipal and the
       // triggeringPrincipal should always be the systemPrincipal.
-      auto result = URLPreloader::ReadURI(aLoadData->mURI);
+      auto result = URLPreloader::ReadURI(aLoadData.mURI);
       if (result.isOk()) {
         nsCOMPtr<nsIInputStream> stream;
         MOZ_TRY(
             NS_NewCStringInputStream(getter_AddRefs(stream), result.unwrap()));
 
-        rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aLoadData->mURI,
+        rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aLoadData.mURI,
                                       stream.forget(),
                                       nsContentUtils::GetSystemPrincipal(),
                                       securityFlags, contentPolicyType);
       } else {
-        rv = NS_NewChannel(getter_AddRefs(channel), aLoadData->mURI,
+        rv = NS_NewChannel(getter_AddRefs(channel), aLoadData.mURI,
                            nsContentUtils::GetSystemPrincipal(), securityFlags,
                            contentPolicyType);
       }
     }
     if (NS_FAILED(rv)) {
       LOG_ERROR(("  Failed to create channel"));
       SheetComplete(aLoadData, rv);
       return rv;
     }
 
     // snapshot the nonce at load start time for performing CSP checks
     if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
-      nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
+      nsCOMPtr<Element> element = do_QueryInterface(aLoadData.mRequestingNode);
       if (element && element->IsHTMLElement()) {
         nsAutoString cspNonce;
         element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
         nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
         loadInfo->SetCspNonce(cspNonce);
       }
     }
 
@@ -1354,44 +1359,38 @@ nsresult Loader::LoadSheet(SheetLoadData
                                                        streamLoader, channel);
   }
 
   SheetLoadData* existingData = nullptr;
 
   SheetLoadDataHashKey key(aLoadData);
 
   if (aSheetState == SheetState::Loading) {
-    mSheets->mLoadingDatas.Get(&key, &existingData);
+    existingData = mSheets->mLoadingDatas.Get(&key);
     NS_ASSERTION(existingData, "CreateSheet lied about the state");
   } else if (aSheetState == SheetState::Pending) {
-    mSheets->mPendingDatas.Get(&key, &existingData);
+    existingData = mSheets->mPendingDatas.GetWeak(&key);
     NS_ASSERTION(existingData, "CreateSheet lied about the state");
   }
 
   if (existingData) {
     LOG(("  Glomming on to existing load"));
     SheetLoadData* data = existingData;
     while (data->mNext) {
       data = data->mNext;
     }
-    data->mNext = aLoadData;  // transfer ownership
-    if (aSheetState == SheetState::Pending && !aLoadData->ShouldDefer()) {
+    data->mNext = &aLoadData;
+    if (aSheetState == SheetState::Pending && !aLoadData.ShouldDefer()) {
       // Kick the load off; someone cares about it right away
-
-#ifdef DEBUG
-      SheetLoadData* removedData;
-      NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
-                       removedData == existingData,
-                   "Bad pending table.");
-#endif
-
-      mSheets->mPendingDatas.Remove(&key);
+      RefPtr<SheetLoadData> removedData;
+      mSheets->mPendingDatas.Remove(&key, getter_AddRefs(removedData));
+      MOZ_ASSERT(removedData == existingData, "Bad loading table");
 
       LOG(("  Forcing load of pending data"));
-      return LoadSheet(existingData, SheetState::NeedsParser, aIsPreload);
+      return LoadSheet(*removedData, SheetState::NeedsParser, aIsPreload);
     }
     // All done here; once the load completes we'll be marked complete
     // automatically
     return NS_OK;
   }
 
   nsCOMPtr<nsILoadGroup> loadGroup;
   nsCOMPtr<nsICookieSettings> cookieSettings;
@@ -1408,17 +1407,17 @@ nsresult Loader::LoadSheet(SheetLoadData
     cookieSettings = mDocument->CookieSettings();
   }
 
 #ifdef DEBUG
   AutoRestore<bool> syncCallbackGuard(mSyncCallback);
   mSyncCallback = true;
 #endif
 
-  CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
+  CORSMode ourCORSMode = aLoadData.mSheet->GetCORSMode();
   nsSecurityFlags securityFlags =
       ourCORSMode == CORS_NONE
           ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
           : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
   if (ourCORSMode == CORS_ANONYMOUS) {
     securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
   } else if (ourCORSMode == CORS_USE_CREDENTIALS) {
     securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
@@ -1430,78 +1429,73 @@ nsresult Loader::LoadSheet(SheetLoadData
           ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
           : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
 
   nsCOMPtr<nsIChannel> channel;
   // Note we are calling NS_NewChannelWithTriggeringPrincipal here with a node
   // and a principal. This is because of a case where the node is the document
   // being styled and the principal is the stylesheet (perhaps from a different
   // origin)  that is applying the styles.
-  if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
+  if (aLoadData.mRequestingNode && aLoadData.mLoaderPrincipal) {
     rv = NS_NewChannelWithTriggeringPrincipal(
-        getter_AddRefs(channel), aLoadData->mURI, aLoadData->mRequestingNode,
-        aLoadData->mLoaderPrincipal, securityFlags, contentPolicyType,
-        nullptr,  // Performancestorage
-        loadGroup);
+        getter_AddRefs(channel), aLoadData.mURI, aLoadData.mRequestingNode,
+        aLoadData.mLoaderPrincipal, securityFlags, contentPolicyType,
+        /* PerformanceStorage */ nullptr, loadGroup);
   } else {
     // either we are loading something inside a document, in which case
     // we should always have a requestingNode, or we are loading something
     // outside a document, in which case the loadingPrincipal and the
     // triggeringPrincipal should always be the systemPrincipal.
-    rv = NS_NewChannel(getter_AddRefs(channel), aLoadData->mURI,
+    rv = NS_NewChannel(getter_AddRefs(channel), aLoadData.mURI,
                        nsContentUtils::GetSystemPrincipal(), securityFlags,
                        contentPolicyType, cookieSettings,
-                       nullptr,  // aPerformanceStorage
-                       loadGroup);
+                       /* aPerformanceStorage */ nullptr, loadGroup);
   }
 
   if (NS_FAILED(rv)) {
     LOG_ERROR(("  Failed to create channel"));
     SheetComplete(aLoadData, rv);
     return rv;
   }
 
   // snapshot the nonce at load start time for performing CSP checks
   if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
-    nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
+    nsCOMPtr<Element> element = do_QueryInterface(aLoadData.mRequestingNode);
     if (element && element->IsHTMLElement()) {
       nsAutoString cspNonce;
       element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
       nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
       loadInfo->SetCspNonce(cspNonce);
     }
   }
 
-  if (!aLoadData->ShouldDefer()) {
-    nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
-    if (cos) {
+  if (!aLoadData.ShouldDefer()) {
+    if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(channel)) {
       cos->AddClassFlags(nsIClassOfService::Leader);
     }
   }
 
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
-  if (httpChannel) {
-    nsCOMPtr<nsIReferrerInfo> referrerInfo = aLoadData->ReferrerInfo();
-    if (referrerInfo) {
+  if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
+    if (nsCOMPtr<nsIReferrerInfo> referrerInfo = aLoadData.ReferrerInfo()) {
       rv = httpChannel->SetReferrerInfo(referrerInfo);
       Unused << NS_WARN_IF(NS_FAILED(rv));
     }
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel =
         do_QueryInterface(httpChannel);
     if (internalChannel) {
       rv = internalChannel->SetIntegrityMetadata(
           sriMetadata.GetIntegrityString());
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Set the initiator type
-    nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
-    if (timedChannel) {
-      if (aLoadData->mParentData) {
+    if (nsCOMPtr<nsITimedChannel> timedChannel =
+            do_QueryInterface(httpChannel)) {
+      if (aLoadData.mParentData) {
         timedChannel->SetInitiatorType(NS_LITERAL_STRING("css"));
 
         // This is a child sheet load.
         //
         // The resource timing of the sub-resources that a document loads
         // should normally be reported to the document.  One exception is any
         // sub-resources of any cross-origin resources that are loaded.  We
         // don't mind reporting timing data for a direct child cross-origin
@@ -1515,21 +1509,21 @@ nsresult Loader::LoadSheet(SheetLoadData
         // In addition to checking whether we're an immediate child resource of
         // a cross-origin resource (by checking if mIsCrossOriginNoCORS is set
         // to true on our parent), we also check our parent to see whether it
         // itself is a sub-resource of a cross-origin resource by checking
         // mBlockResourceTiming.  If that is set then we too are such a
         // sub-resource and so we set the flag on ourself too to propagate it
         // on down.
         //
-        if (aLoadData->mParentData->mIsCrossOriginNoCORS ||
-            aLoadData->mParentData->mBlockResourceTiming) {
+        if (aLoadData.mParentData->mIsCrossOriginNoCORS ||
+            aLoadData.mParentData->mBlockResourceTiming) {
           // Set a flag so any other stylesheet triggered by this one will
           // not be reported
-          aLoadData->mBlockResourceTiming = true;
+          aLoadData.mBlockResourceTiming = true;
 
           // Mark the channel so PerformanceMainThread::AddEntry will not
           // report the resource.
           timedChannel->SetReportResourceTiming(false);
         }
 
       } else {
         timedChannel->SetInitiatorType(NS_LITERAL_STRING("link"));
@@ -1542,107 +1536,105 @@ nsresult Loader::LoadSheet(SheetLoadData
   channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
 
   // We don't have to hold on to the stream loader.  The ownership
   // model is: Necko owns the stream loader, which owns the load data,
   // which owns us
   nsCOMPtr<nsIStreamListener> streamLoader = new StreamLoader(aLoadData);
 
   if (mDocument) {
-    mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
+    mozilla::net::PredictorLearn(aLoadData.mURI, mDocument->GetDocumentURI(),
                                  nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
                                  mDocument);
   }
 
   rv = channel->AsyncOpen(streamLoader);
 
   if (NS_FAILED(rv)) {
     LOG_ERROR(("  Failed to create stream loader"));
     SheetComplete(aLoadData, rv);
     return rv;
   }
 
-  mSheets->mLoadingDatas.Put(&key, aLoadData);
-  aLoadData->mIsLoading = true;
+  mSheets->mLoadingDatas.Put(&key, &aLoadData);
+  aLoadData.mIsLoading = true;
 
   return NS_OK;
 }
 
 /**
  * ParseSheet handles parsing the data stream.
  */
 Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
-                                     SheetLoadData* aLoadData,
+                                     SheetLoadData& aLoadData,
                                      AllowAsyncParse aAllowAsync) {
   LOG(("css::Loader::ParseSheet"));
   AUTO_PROFILER_LABEL("css::Loader::ParseSheet", LAYOUT_CSSParsing);
-  MOZ_ASSERT(aLoadData);
-  aLoadData->mIsBeingParsed = true;
+  aLoadData.mIsBeingParsed = true;
 
   // Tell the record/replay system about any sheets that are being parsed,
   // so that devtools code can find them later.
-  if (recordreplay::IsRecordingOrReplaying() && aLoadData->mURI) {
+  if (recordreplay::IsRecordingOrReplaying() && aLoadData.mURI) {
     recordreplay::NoteContentParse(
-        aLoadData, aLoadData->mURI->GetSpecOrDefault().get(), "text/css",
+        &aLoadData, aLoadData.mURI->GetSpecOrDefault().get(), "text/css",
         reinterpret_cast<const Utf8Unit*>(aBytes.BeginReading()),
         aBytes.Length());
   }
 
-  StyleSheet* sheet = aLoadData->mSheet;
+  StyleSheet* sheet = aLoadData.mSheet;
   MOZ_ASSERT(sheet);
 
   // Some cases, like inline style and UA stylesheets, need to be parsed
   // synchronously. The former may trigger child loads, the latter must not.
-  if (aLoadData->mSyncLoad || aAllowAsync == AllowAsyncParse::No) {
-    sheet->ParseSheetSync(this, aBytes, aLoadData, aLoadData->mLineNumber);
-    aLoadData->mIsBeingParsed = false;
+  if (aLoadData.mSyncLoad || aAllowAsync == AllowAsyncParse::No) {
+    sheet->ParseSheetSync(this, aBytes, &aLoadData, aLoadData.mLineNumber);
+    aLoadData.mIsBeingParsed = false;
 
-    bool noPendingChildren = aLoadData->mPendingChildren == 0;
-    MOZ_ASSERT_IF(aLoadData->mSyncLoad, noPendingChildren);
+    bool noPendingChildren = aLoadData.mPendingChildren == 0;
+    MOZ_ASSERT_IF(aLoadData.mSyncLoad, noPendingChildren);
     if (noPendingChildren) {
       SheetComplete(aLoadData, NS_OK);
       return Completed::Yes;
     }
     return Completed::No;
   }
 
   // This parse does not need to be synchronous. \o/
   //
   // Note that we need to block onload because there may be no network requests
   // pending.
   BlockOnload();
-  RefPtr<SheetLoadData> loadData = aLoadData;
   nsCOMPtr<nsISerialEventTarget> target = DispatchTarget();
-  sheet->ParseSheet(this, aBytes, aLoadData)
+  sheet->ParseSheet(*this, aBytes, aLoadData)
       ->Then(
           target, __func__,
-          [loadData = std::move(loadData)](bool aDummy) {
+          [loadData = RefPtr<SheetLoadData>(&aLoadData)](bool aDummy) {
             MOZ_ASSERT(NS_IsMainThread());
             loadData->mIsBeingParsed = false;
             loadData->mLoader->UnblockOnload(/* aFireSync = */ false);
             // If there are no child sheets outstanding, mark us as complete.
             // Otherwise, the children are holding strong refs to the data
             // and will call SheetComplete() on it when they complete.
             if (loadData->mPendingChildren == 0) {
-              loadData->mLoader->SheetComplete(loadData, NS_OK);
+              loadData->mLoader->SheetComplete(*loadData, NS_OK);
             }
           },
           [] { MOZ_CRASH("rejected parse promise"); });
   return Completed::No;
 }
 
 /**
  * SheetComplete is the do-it-all cleanup function.  It removes the
  * load data from the "loading" hashtable, adds the sheet to the
  * "completed" hashtable, massages the XUL cache, handles siblings of
  * the load data (other loads for the same URI), handles unblocking
  * blocked parent loads as needed, and most importantly calls
  * NS_RELEASE on the load data to destroy the whole mess.
  */
-void Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) {
+void Loader::SheetComplete(SheetLoadData& aLoadData, nsresult aStatus) {
   LOG(("css::Loader::SheetComplete, status: 0x%" PRIx32,
        static_cast<uint32_t>(aStatus)));
 
   // If aStatus is a failure we need to mark this data failed.  We also need to
   // mark any ancestors of a failing data as failed and any sibling of a
   // failing data as failed.  Note that SheetComplete is never called on a
   // SheetLoadData that is the mNext of some other SheetLoadData.
   if (NS_FAILED(aStatus)) {
@@ -1684,45 +1676,44 @@ void Loader::SheetComplete(SheetLoadData
   if (mSheets &&
       mSheets->mLoadingDatas.Count() == 0 &&
       mSheets->mPendingDatas.Count() > 0) {
     LOG(("  No more loading sheets; starting deferred loads"));
     StartDeferredLoads();
   }
 }
 
-void Loader::DoSheetComplete(SheetLoadData* aLoadData,
+void Loader::DoSheetComplete(SheetLoadData& aLoadData,
                              LoadDataArray& aDatasToNotify) {
   LOG(("css::Loader::DoSheetComplete"));
-  MOZ_ASSERT(aLoadData, "Must have a load data!");
-  MOZ_ASSERT(aLoadData->mSheet, "Must have a sheet");
-  NS_ASSERTION(mSheets || !aLoadData->mURI,
+  MOZ_ASSERT(aLoadData.mSheet, "Must have a sheet");
+  NS_ASSERTION(mSheets || !aLoadData.mURI,
                "mLoadingDatas should be initialized by now.");
 
   // Twiddle the hashtables
-  if (aLoadData->mURI) {
-    LOG_URI("  Finished loading: '%s'", aLoadData->mURI);
+  if (aLoadData.mURI) {
+    LOG_URI("  Finished loading: '%s'", aLoadData.mURI);
     // Remove the data from the list of loading datas
-    if (aLoadData->mIsLoading) {
+    if (aLoadData.mIsLoading) {
       SheetLoadDataHashKey key(aLoadData);
 #ifdef DEBUG
       SheetLoadData* loadingData;
       NS_ASSERTION(mSheets->mLoadingDatas.Get(&key, &loadingData) &&
-                       loadingData == aLoadData,
+                       loadingData == &aLoadData,
                    "Bad loading table");
 #endif
 
       mSheets->mLoadingDatas.Remove(&key);
-      aLoadData->mIsLoading = false;
+      aLoadData.mIsLoading = false;
     }
   }
 
   // Go through and deal with the whole linked list.
-  SheetLoadData* data = aLoadData;
-  while (data) {
+  SheetLoadData* data = &aLoadData;
+  do {
     if (!data->mSheetAlreadyComplete) {
       // If mSheetAlreadyComplete, then the sheet could well be modified between
       // when we posted the async call to SheetComplete and now, since the sheet
       // was page-accessible during that whole time.
       MOZ_ASSERT(!data->mSheet->HasForcedUniqueInner(),
                  "should not get a forced unique inner during parsing");
       data->mSheet->SetComplete();
       data->ScheduleLoadEventIfNeeded();
@@ -1741,79 +1732,79 @@ void Loader::DoSheetComplete(SheetLoadDa
 
     // If we have a parent, our parent is no longer being parsed, and
     // we are the last pending child, then our load completion
     // completes the parent too.  Note that the parent _can_ still be
     // being parsed (eg if the child (us) failed to open the channel
     // or some such).
     if (data->mParentData && --(data->mParentData->mPendingChildren) == 0 &&
         !data->mParentData->mIsBeingParsed) {
-      DoSheetComplete(data->mParentData, aDatasToNotify);
+      DoSheetComplete(*data->mParentData, aDatasToNotify);
     }
 
     data = data->mNext;
-  }
+  } while (data);
 
   // Now that it's marked complete, put the sheet in our cache.
   // If we ever start doing this for failed loads, we'll need to
   // adjust the PostLoadEvent code that thinks anything already
   // complete must have loaded succesfully.
-  if (!aLoadData->mLoadFailed && aLoadData->mURI) {
+  if (!aLoadData.mLoadFailed && aLoadData.mURI) {
     // Pick our sheet to cache carefully.  Ideally, we want to cache
     // one of the sheets that will be kept alive by a document or
     // parent sheet anyway, so that if someone then accesses it via
     // CSSOM we won't have extra clones of the inner lying around.
-    data = aLoadData;
-    StyleSheet* sheet = aLoadData->mSheet;
-    while (data) {
+    data = &aLoadData;
+    StyleSheet* sheet = aLoadData.mSheet;
+    do {
       if (data->mSheet->GetParentSheet() || data->mSheet->GetOwnerNode()) {
         sheet = data->mSheet;
         break;
       }
       data = data->mNext;
-    }
+    } while (data);
+
 #ifdef MOZ_XUL
-    if (IsChromeURI(aLoadData->mURI)) {
+    if (IsChromeURI(aLoadData.mURI)) {
       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
       if (cache && cache->IsEnabled()) {
-        if (!cache->GetStyleSheet(aLoadData->mURI)) {
+        if (!cache->GetStyleSheet(aLoadData.mURI)) {
           LOG(("  Putting sheet in XUL prototype cache"));
           NS_ASSERTION(sheet->IsComplete(),
                        "Should only be caching complete sheets");
           cache->PutStyleSheet(sheet);
         }
       }
     } else {
 #endif
       SheetLoadDataHashKey key(aLoadData);
       NS_ASSERTION(sheet->IsComplete(),
                    "Should only be caching complete sheets");
       mSheets->mCompleteSheets.Put(&key, sheet);
 #ifdef MOZ_XUL
     }
 #endif
   }
-
-  NS_RELEASE(aLoadData);  // this will release parents and siblings and all that
 }
 
-void Loader::MarkLoadTreeFailed(SheetLoadData* aLoadData) {
-  if (aLoadData->mURI) {
-    LOG_URI("  Load failed: '%s'", aLoadData->mURI);
+void Loader::MarkLoadTreeFailed(SheetLoadData& aLoadData) {
+  if (aLoadData.mURI) {
+    LOG_URI("  Load failed: '%s'", aLoadData.mURI);
   }
 
+  SheetLoadData* data = &aLoadData;
   do {
-    aLoadData->mLoadFailed = true;
+    data->mLoadFailed = true;
 
-    if (aLoadData->mParentData) {
-      MarkLoadTreeFailed(aLoadData->mParentData);
+    if (data->mParentData) {
+      MarkLoadTreeFailed(*data->mParentData);
     }
 
-    aLoadData = aLoadData->mNext;
-  } while (aLoadData);
+    data = data->mNext;
+  } while (data);
 }
 
 Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
     const SheetInfo& aInfo, const nsAString& aBuffer, uint32_t aLineNumber,
     nsICSSLoaderObserver* aObserver) {
   LOG(("css::Loader::LoadInlineStyle"));
 
   if (!mEnabled) {
@@ -1861,34 +1852,31 @@ Result<Loader::LoadSheetResult, nsresult
     // The triggering principal may be an expanded principal, which is safe to
     // use for URL security checks, but not as the loader principal for a
     // stylesheet. So treat this as principal inheritance, and downgrade if
     // necessary.
     principal =
         BasePrincipal::Cast(aInfo.mTriggeringPrincipal)->PrincipalToInherit();
   }
 
-  SheetLoadData* data = new SheetLoadData(
+  auto data = MakeRefPtr<SheetLoadData>(
       this, aInfo.mTitle, nullptr, sheet, false, owningElement, isAlternate,
       matched, aObserver, nullptr, aInfo.mReferrerInfo, aInfo.mContent);
 
   // We never actually load this, so just set its principal directly
   sheet->SetPrincipal(principal);
-
-  NS_ADDREF(data);
   data->mLineNumber = aLineNumber;
   // Parse completion releases the load data.
   //
   // Note that we need to parse synchronously, since the web expects that the
   // effects of inline stylesheets are visible immediately (aside from
   // @imports).
   NS_ConvertUTF16toUTF8 utf8(aBuffer);
-  Completed completed = ParseSheet(utf8, data, AllowAsyncParse::No);
+  Completed completed = ParseSheet(utf8, *data, AllowAsyncParse::No);
 
-  // If the sheet is complete already, |data| may well be deleted by now.
   if (completed == Completed::No) {
     data->mMustNotify = true;
   }
   return LoadSheetResult{completed, isAlternate, matched};
 }
 
 Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
     const SheetInfo& aInfo, nsICSSLoaderObserver* aObserver) {
@@ -1974,183 +1962,180 @@ Result<Loader::LoadSheetResult, nsresult
       }
     }
 
     // The load hasn't been completed yet, will be done in PostLoadEvent.
     return LoadSheetResult{Completed::No, isAlternate, matched};
   }
 
   // Now we need to actually load it.
-  SheetLoadData* data = new SheetLoadData(
+  auto data = MakeRefPtr<SheetLoadData>(
       this, aInfo.mTitle, aInfo.mURI, sheet, syncLoad, owningElement,
       isAlternate, matched, aObserver, principal, aInfo.mReferrerInfo, context);
-  NS_ADDREF(data);
 
   auto result = LoadSheetResult{Completed::No, isAlternate, matched};
 
   MOZ_ASSERT(result.ShouldBlock() == !data->ShouldDefer(),
              "These should better match!");
 
   // If we have to parse and it's a non-blocking non-inline sheet, defer it.
   if (!syncLoad && state == SheetState::NeedsParser &&
       mSheets->mLoadingDatas.Count() != 0 && !result.ShouldBlock()) {
     LOG(("  Deferring sheet load"));
-    SheetLoadDataHashKey key(data);
+    SheetLoadDataHashKey key(*data);
     mSheets->mPendingDatas.Put(&key, data);
     data->mMustNotify = true;
     return result;
   }
 
   // Load completion will free the data
-  rv = LoadSheet(data, state, IsPreload::No);
+  rv = LoadSheet(*data, state, IsPreload::No);
   if (NS_FAILED(rv)) {
     return Err(rv);
   }
 
   if (!syncLoad) {
     data->mMustNotify = true;
   }
   return result;
 }
 
-static bool HaveAncestorDataWithURI(SheetLoadData* aData, nsIURI* aURI) {
-  if (!aData->mURI) {
+static bool HaveAncestorDataWithURI(SheetLoadData& aData, nsIURI* aURI) {
+  if (!aData.mURI) {
     // Inline style; this won't have any ancestors
-    MOZ_ASSERT(!aData->mParentData, "How does inline style have a parent?");
+    MOZ_ASSERT(!aData.mParentData, "How does inline style have a parent?");
     return false;
   }
 
   bool equal;
-  if (NS_FAILED(aData->mURI->Equals(aURI, &equal)) || equal) {
+  if (NS_FAILED(aData.mURI->Equals(aURI, &equal)) || equal) {
     return true;
   }
 
   // Datas down the mNext chain have the same URI as aData, so we
   // don't have to compare to them.  But they might have different
   // parents, and we have to check all of those.
-  while (aData) {
-    if (aData->mParentData &&
-        HaveAncestorDataWithURI(aData->mParentData, aURI)) {
+  SheetLoadData* data = &aData;
+  do {
+    if (data->mParentData &&
+        HaveAncestorDataWithURI(*data->mParentData, aURI)) {
       return true;
     }
 
-    aData = aData->mNext;
-  }
+    data = data->mNext;
+  } while (data);
 
   return false;
 }
 
-nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
+nsresult Loader::LoadChildSheet(StyleSheet& aParentSheet,
                                 SheetLoadData* aParentData, nsIURI* aURL,
                                 dom::MediaList* aMedia,
                                 LoaderReusableStyleSheets* aReusableSheets) {
   LOG(("css::Loader::LoadChildSheet"));
   MOZ_ASSERT(aURL, "Must have a URI to load");
-  MOZ_ASSERT(aParentSheet, "Must have a parent sheet");
 
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   LOG_URI("  Child uri: '%s'", aURL);
 
   nsCOMPtr<nsINode> owningNode;
 
   // Check for an associated document or shadow root: if none, don't bother
   // walking up the parent sheets.
-  if (aParentSheet->GetAssociatedDocumentOrShadowRoot()) {
-    StyleSheet* topSheet = aParentSheet;
+  if (aParentSheet.GetAssociatedDocumentOrShadowRoot()) {
+    StyleSheet* topSheet = &aParentSheet;
     while (StyleSheet* parent = topSheet->GetParentSheet()) {
       topSheet = parent;
     }
     owningNode = topSheet->GetOwnerNode();
   }
 
   nsINode* context = nullptr;
   nsIPrincipal* loadingPrincipal = nullptr;
   if (owningNode) {
     context = owningNode;
     loadingPrincipal = owningNode->NodePrincipal();
   } else if (mDocument) {
     context = mDocument;
     loadingPrincipal = mDocument->NodePrincipal();
   }
 
-  nsIPrincipal* principal = aParentSheet->Principal();
+  nsIPrincipal* principal = aParentSheet.Principal();
   nsresult rv = CheckContentPolicy(loadingPrincipal, principal, aURL, context,
                                    IsPreload::No);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     if (aParentData) {
-      MarkLoadTreeFailed(aParentData);
+      MarkLoadTreeFailed(*aParentData);
     }
     return rv;
   }
 
   nsCOMPtr<nsICSSLoaderObserver> observer;
 
   if (aParentData) {
     LOG(("  Have a parent load"));
     // Check for cycles
-    if (HaveAncestorDataWithURI(aParentData, aURL)) {
+    if (HaveAncestorDataWithURI(*aParentData, aURL)) {
       // Houston, we have a loop, blow off this child and pretend this never
       // happened
       LOG_ERROR(("  @import cycle detected, dropping load"));
       return NS_OK;
     }
 
-    NS_ASSERTION(aParentData->mSheet == aParentSheet,
+    NS_ASSERTION(aParentData->mSheet == &aParentSheet,
                  "Unexpected call to LoadChildSheet");
   } else {
     LOG(("  No parent load; must be CSSOM"));
     // No parent load data, so the sheet will need to be notified when
     // we finish, if it can be, if we do the load asynchronously.
-    observer = aParentSheet;
+    observer = &aParentSheet;
   }
 
   // Now that we know it's safe to load this (passes security check and not a
   // loop) do so.
   RefPtr<StyleSheet> sheet;
   SheetState state;
   if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
     state = SheetState::Complete;
   } else {
     // For now, use CORS_NONE for child sheets
     Tie(sheet, state) =
-        CreateSheet(aURL, nullptr, principal, aParentSheet->ParsingMode(),
-                    CORS_NONE, aParentSheet->GetReferrerInfo(),
+        CreateSheet(aURL, nullptr, principal, aParentSheet.ParsingMode(),
+                    CORS_NONE, aParentSheet.GetReferrerInfo(),
                     EmptyString(),  // integrity is only checked on main sheet
                     aParentData ? aParentData->mSyncLoad : false);
     PrepareSheet(sheet, EmptyString(), EmptyString(), aMedia, IsAlternate::No,
                  IsExplicitlyEnabled::No);
   }
 
   MOZ_ASSERT(sheet);
-  InsertChildSheet(*sheet, *aParentSheet);
+  InsertChildSheet(*sheet, aParentSheet);
 
   if (state == SheetState::Complete) {
     LOG(("  Sheet already complete"));
     // We're completely done.  No need to notify, even, since the
     // @import rule addition/modification will trigger the right style
     // changes automatically.
     return NS_OK;
   }
 
-  SheetLoadData* data =
-      new SheetLoadData(this, aURL, sheet, aParentData, observer, principal,
-                        aParentSheet->GetReferrerInfo(), context);
+  auto data = MakeRefPtr<SheetLoadData>(
+      this, aURL, sheet, aParentData, observer, principal,
+      aParentSheet.GetReferrerInfo(), context);
 
-  NS_ADDREF(data);
   bool syncLoad = data->mSyncLoad;
 
   // Load completion will release the data
-  rv = LoadSheet(data, state, IsPreload::No);
+  rv = LoadSheet(*data, state, IsPreload::No);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // If syncLoad is true, |data| will be deleted by now.
   if (!syncLoad) {
     data->mMustNotify = true;
   }
   return rv;
 }
 
 Result<RefPtr<StyleSheet>, nsresult> Loader::LoadSheetSync(
     nsIURI* aURL, SheetParsingMode aParsingMode,
@@ -2227,23 +2212,21 @@ Result<RefPtr<StyleSheet>, nsresult> Loa
                          MediaMatched::Yes, aReferrerInfo, nullptr);
       if (NS_FAILED(rv)) {
         return Err(rv);
       }
     }
     return sheet;
   }
 
-  SheetLoadData* data = new SheetLoadData(
+  auto data = MakeRefPtr<SheetLoadData>(
       this, aURL, sheet, syncLoad,
       aUseSystemPrincipal == UseSystemPrincipal::Yes, aPreloadEncoding,
       aObserver, aOriginPrincipal, aReferrerInfo, mDocument);
-
-  NS_ADDREF(data);
-  rv = LoadSheet(data, state, aIsPreload);
+  rv = LoadSheet(*data, state, aIsPreload);
   if (NS_FAILED(rv)) {
     return Err(rv);
   }
   if (aObserver) {
     data->mMustNotify = true;
   }
   return sheet;
 }
@@ -2295,78 +2278,69 @@ nsresult Loader::PostLoadEvent(nsIURI* a
     // event async.
     MOZ_ASSERT(!evt->mLoadFailed, "Why are we marked as failed?");
     evt->ScheduleLoadEventIfNeeded();
   }
 
   return rv;
 }
 
-void Loader::HandleLoadEvent(SheetLoadData* aEvent) {
+void Loader::HandleLoadEvent(SheetLoadData& aEvent) {
   // XXXbz can't assert this yet.... May not have an observer because
   // we're unblocking the parser
   // NS_ASSERTION(aEvent->mObserver, "Must have observer");
-  NS_ASSERTION(aEvent->mSheet, "Must have sheet");
+  NS_ASSERTION(aEvent.mSheet, "Must have sheet");
 
   // Very important: this needs to come before the SheetComplete call
   // below, so that HasPendingLoads() will test true as needed under
   // notifications we send from that SheetComplete call.
-  mPostedEvents.RemoveElement(aEvent);
+  mPostedEvents.RemoveElement(&aEvent);
 
-  if (!aEvent->mIsCancelled) {
-    // SheetComplete will call Release(), so give it a reference to do
-    // that with.
-    NS_ADDREF(aEvent);
+  if (!aEvent.mIsCancelled) {
     SheetComplete(aEvent, NS_OK);
   }
 
   UnblockOnload(true);
 }
 
-static void StopLoadingSheets(
-    nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*>& aDatas,
-    Loader::LoadDataArray& aArr) {
-  for (auto iter = aDatas.Iter(); !iter.Done(); iter.Next()) {
-    SheetLoadData* data = iter.Data();
-    MOZ_ASSERT(data, "Must have a data!");
-
-    data->mIsLoading = false;  // we will handle the removal right here
-    data->mIsCancelled = true;
-
-    aArr.AppendElement(data);
-
-    iter.Remove();
-  }
-}
-
 void Loader::Stop() {
   uint32_t pendingCount = mSheets ? mSheets->mPendingDatas.Count() : 0;
   uint32_t loadingCount = mSheets ? mSheets->mLoadingDatas.Count() : 0;
   LoadDataArray arr(pendingCount + loadingCount + mPostedEvents.Length());
 
   if (pendingCount) {
-    StopLoadingSheets(mSheets->mPendingDatas, arr);
+    for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
+      RefPtr<SheetLoadData>& data = iter.Data();
+      data->mIsLoading = false;  // we will handle the removal right here
+      data->mIsCancelled = true;
+      arr.AppendElement(std::move(data));
+    }
+    mSheets->mPendingDatas.Clear();
   }
   if (loadingCount) {
-    StopLoadingSheets(mSheets->mLoadingDatas, arr);
+    for (auto iter = mSheets->mLoadingDatas.Iter(); !iter.Done(); iter.Next()) {
+      SheetLoadData* data = iter.Data();
+      data->mIsLoading = false;  // we will handle the removal right here
+      data->mIsCancelled = true;
+      arr.AppendElement(data);
+    }
+    mSheets->mLoadingDatas.Clear();
   }
 
   for (RefPtr<SheetLoadData>& data : mPostedEvents) {
     data->mIsCancelled = true;
-    // SheetComplete() calls Release(), so give this an extra ref.
-    NS_ADDREF(data.get());
     // Move since we're about to get rid of the array below.
     arr.AppendElement(std::move(data));
   }
   mPostedEvents.Clear();
 
   mDatasToNotifyOn += arr.Length();
   for (RefPtr<SheetLoadData>& data : arr) {
     --mDatasToNotifyOn;
-    SheetComplete(data, NS_BINDING_ABORTED);
+    SheetComplete(*data, NS_BINDING_ABORTED);
   }
 }
 
 bool Loader::HasPendingLoads() {
   return (mSheets && mSheets->mLoadingDatas.Count() != 0) ||
          (mSheets && mSheets->mPendingDatas.Count() != 0) ||
          mPostedEvents.Length() != 0 || mDatasToNotifyOn != 0;
 }
@@ -2384,19 +2358,19 @@ void Loader::StartDeferredLoads() {
   MOZ_ASSERT(mSheets, "Don't call me!");
   LoadDataArray arr(mSheets->mPendingDatas.Count());
   for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
     arr.AppendElement(iter.Data());
     iter.Remove();
   }
 
   mDatasToNotifyOn += arr.Length();
-  for (uint32_t i = 0; i < arr.Length(); ++i) {
+  for (RefPtr<SheetLoadData>& data : arr) {
     --mDatasToNotifyOn;
-    LoadSheet(arr[i], SheetState::NeedsParser, IsPreload::No);
+    LoadSheet(*data, SheetState::NeedsParser, IsPreload::No);
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Loader)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Loader)
   if (tmp->mSheets) {
     for (auto iter = tmp->mSheets->mCompleteSheets.Iter(); !iter.Done();
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -163,23 +163,24 @@ class Loader final {
    * complete when this method returns, then when the child sheet becomes
    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
    * asynchronously notified, just like for LoadStyleLink.  Note that if the
    * child sheet is already complete when this method returns, no
    * nsICSSLoaderObserver notification will be sent.
    *
    * @param aParentSheet the parent of this child sheet
    * @param aParentData the SheetLoadData corresponding to the load of the
-   *                    parent sheet.
+   *                    parent sheet. May be null for @import rules inserted via
+   *                    CSSOM.
    * @param aURL the URL of the child sheet
    * @param aMedia the already-parsed media list for the child sheet
    * @param aSavedSheets any saved style sheets which could be reused
    *              for this load
    */
-  nsresult LoadChildSheet(StyleSheet* aParentSheet, SheetLoadData* aParentData,
+  nsresult LoadChildSheet(StyleSheet& aParentSheet, SheetLoadData* aParentData,
                           nsIURI* aURL, dom::MediaList* aMedia,
                           LoaderReusableStyleSheets* aSavedSheets);
 
   enum class UseSystemPrincipal { No, Yes };
 
   /**
    * Synchronously load and return the stylesheet at aURL.  Any child sheets
    * will also be loaded synchronously.  Note that synchronous loads over some
@@ -380,51 +381,49 @@ class Loader final {
                          nsICSSLoaderObserver* aObserver,
                          IsAlternate aWasAlternate, MediaMatched aMediaMatched,
                          nsIReferrerInfo* aReferrerInfo,
                          nsIStyleSheetLinkingElement* aElement);
 
   // Start the loads of all the sheets in mPendingDatas
   void StartDeferredLoads();
 
-  // Handle an event posted by PostLoadEvent
-  void HandleLoadEvent(SheetLoadData* aEvent);
+  void HandleLoadEvent(SheetLoadData&);
 
-  // Note: LoadSheet is responsible for releasing the load data and setting the
-  // sheet to complete on failure.
-  nsresult LoadSheet(SheetLoadData*, SheetState, IsPreload);
+  // Note: LoadSheet is responsible for setting the sheet to complete on
+  // failure.
+  nsresult LoadSheet(SheetLoadData&, SheetState, IsPreload);
 
   enum class AllowAsyncParse {
     Yes,
     No,
   };
 
   // Parse the stylesheet in the load data.
   //
   // Returns whether the parse finished. It may not finish e.g. if the sheet had
   // an @import.
   //
   // If this function returns Completed::Yes, then ParseSheet also called
   // SheetComplete on aLoadData.
-  Completed ParseSheet(const nsACString& aBytes, SheetLoadData*,
-                       AllowAsyncParse);
+  Completed ParseSheet(const nsACString&, SheetLoadData&, AllowAsyncParse);
 
-  // The load of the sheet in aLoadData is done, one way or another.  Do final
-  // cleanup, including releasing aLoadData.
-  void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
+  // The load of the sheet in the load data is done, one way or another.
+  // Do final cleanup.
+  void SheetComplete(SheetLoadData&, nsresult aStatus);
 
   // The guts of SheetComplete.  This may be called recursively on parent datas
   // or datas that had glommed on to a single load.  The array is there so load
   // datas whose observers need to be notified can be added to it.
-  void DoSheetComplete(SheetLoadData* aLoadData, LoadDataArray& aDatasToNotify);
+  void DoSheetComplete(SheetLoadData&, LoadDataArray& aDatasToNotify);
 
   // Mark the given SheetLoadData, as well as any of its siblings, parents, etc
   // transitively, as failed.  The idea is to mark as failed any load that was
   // directly or indirectly @importing the sheet this SheetLoadData represents.
-  void MarkLoadTreeFailed(SheetLoadData* aLoadData);
+  void MarkLoadTreeFailed(SheetLoadData&);
 
   struct Sheets;
   UniquePtr<Sheets> mSheets;
 
   // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
   // Note that these are rare.
   LoadDataArray mPostedEvents;
 
--- a/layout/style/SheetLoadData.h
+++ b/layout/style/SheetLoadData.h
@@ -96,18 +96,18 @@ class SheetLoadData final : public nsIRu
   nsCOMPtr<nsIURI> mURI;
 
   // Should be 1 for non-inline sheets.
   uint32_t mLineNumber;
 
   // The sheet we're loading data for
   RefPtr<StyleSheet> mSheet;
 
-  // Linked list of datas for the same URI as us
-  SheetLoadData* mNext;  // strong ref
+  // Linked list of datas for the same URI as us.
+  RefPtr<SheetLoadData> mNext;
 
   // Load data for the sheet that @import-ed us if we were @import-ed
   // during the parse
   RefPtr<SheetLoadData> mParentData;
 
   // Number of sheets we @import-ed that are still loading
   uint32_t mPendingChildren;
 
--- a/layout/style/StreamLoader.cpp
+++ b/layout/style/StreamLoader.cpp
@@ -11,18 +11,18 @@
 #include "nsIChannel.h"
 #include "nsIInputStream.h"
 
 using namespace mozilla;
 
 namespace mozilla {
 namespace css {
 
-StreamLoader::StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData)
-    : mSheetLoadData(aSheetLoadData), mStatus(NS_OK) {}
+StreamLoader::StreamLoader(SheetLoadData& aSheetLoadData)
+    : mSheetLoadData(&aSheetLoadData), mStatus(NS_OK) {}
 
 StreamLoader::~StreamLoader() {}
 
 NS_IMPL_ISUPPORTS(StreamLoader, nsIStreamListener)
 
 /* nsIRequestObserver implementation */
 NS_IMETHODIMP
 StreamLoader::OnStartRequest(nsIRequest* aRequest) {
@@ -101,17 +101,17 @@ StreamLoader::OnStopRequest(nsIRequest* 
       rv = encoding->DecodeWithoutBOMHandling(bytes, utf8String, validated);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }  // run destructor for `bytes`
 
   // For reasons I don't understand, factoring the below lines into
   // a method on SheetLoadData resulted in a linker error. Hence,
   // accessing fields of mSheetLoadData from here.
-  mSheetLoadData->mLoader->ParseSheet(utf8String, mSheetLoadData,
+  mSheetLoadData->mLoader->ParseSheet(utf8String, *mSheetLoadData,
                                       Loader::AllowAsyncParse::Yes);
   return NS_OK;
 }
 
 /* nsIStreamListener implementation */
 NS_IMETHODIMP
 StreamLoader::OnDataAvailable(nsIRequest*, nsIInputStream* aInputStream,
                               uint64_t, uint32_t aCount) {
--- a/layout/style/StreamLoader.h
+++ b/layout/style/StreamLoader.h
@@ -17,30 +17,30 @@ namespace mozilla {
 namespace css {
 
 class StreamLoader : public nsIStreamListener {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
-  explicit StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData);
+  explicit StreamLoader(SheetLoadData&);
 
  private:
   virtual ~StreamLoader();
 
   /**
    * callback method used for ReadSegments
    */
   static nsresult WriteSegmentFun(nsIInputStream*, void*, const char*, uint32_t,
                                   uint32_t, uint32_t*);
 
   void HandleBOM();
 
-  RefPtr<mozilla::css::SheetLoadData> mSheetLoadData;
+  RefPtr<SheetLoadData> mSheetLoadData;
   nsresult mStatus;
   Maybe<const Encoding*> mEncodingFromBOM;
 
   // We store the initial three bytes of the stream into mBOMBytes, and then
   // use that buffer to detect a BOM. We then shift any non-BOM bytes into
   // mBytes, and store all subsequent data in that buffer.
   nsCString mBytes;
   nsAutoCStringN<3> mBOMBytes;
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -913,25 +913,25 @@ already_AddRefed<StyleSheet> StyleSheet:
 // conditions hold:
 //
 // (1) The pref is off.
 // (2) The browser is recording CSS errors (which parallel parsing can't
 //     handle).
 // (3) The stylesheet is a chrome stylesheet, since those can use
 //     -moz-bool-pref, which needs to access the pref service, which is not
 //     threadsafe.
-static bool AllowParallelParse(css::Loader* aLoader, nsIURI* aSheetURI) {
+static bool AllowParallelParse(css::Loader& aLoader, nsIURI* aSheetURI) {
   // Check the pref.
   if (!StaticPrefs::layout_css_parsing_parallel()) {
     return false;
   }
 
   // If the browser is recording CSS errors, we need to use the sequential path
   // because the parallel path doesn't support that.
-  Document* doc = aLoader->GetDocument();
+  Document* doc = aLoader.GetDocument();
   if (doc && css::ErrorReporter::ShouldReportErrors(*doc)) {
     return false;
   }
 
   // If this is a chrome stylesheet, it might use -moz-bool-pref, which needs to
   // access the pref service, which is not thread-safe. We could probably expose
   // the relevant booleans as thread-safe var caches if we needed to, but
   // parsing chrome stylesheets in parallel is unlikely to be a win anyway.
@@ -941,42 +941,39 @@ static bool AllowParallelParse(css::Load
   if (dom::IsChromeURI(aSheetURI)) {
     return false;
   }
 
   return true;
 }
 
 RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet(
-    css::Loader* aLoader, const nsACString& aBytes,
-    css::SheetLoadData* aLoadData) {
-  MOZ_ASSERT(aLoader);
-  MOZ_ASSERT(aLoadData);
+    css::Loader& aLoader, const nsACString& aBytes,
+    css::SheetLoadData& aLoadData) {
   MOZ_ASSERT(mParsePromise.IsEmpty());
   RefPtr<StyleSheetParsePromise> p = mParsePromise.Ensure(__func__);
   SetURLExtraData();
 
   const StyleUseCounters* useCounters =
-      aLoader->GetDocument() ? aLoader->GetDocument()->GetStyleUseCounters()
-                             : nullptr;
+      aLoader.GetDocument() ? aLoader.GetDocument()->GetStyleUseCounters()
+                            : nullptr;
 
   if (!AllowParallelParse(aLoader, GetSheetURI())) {
     RefPtr<RawServoStyleSheetContents> contents =
         Servo_StyleSheet_FromUTF8Bytes(
-            aLoader, this, aLoadData, &aBytes, mParsingMode, Inner().mURLData,
-            aLoadData->mLineNumber, aLoader->GetCompatibilityMode(),
+            &aLoader, this, &aLoadData, &aBytes, mParsingMode, Inner().mURLData,
+            aLoadData.mLineNumber, aLoader.GetCompatibilityMode(),
             /* reusable_sheets = */ nullptr, useCounters)
             .Consume();
     FinishAsyncParse(contents.forget());
   } else {
-    RefPtr<css::SheetLoadDataHolder> loadDataHolder =
-        new css::SheetLoadDataHolder(__func__, aLoadData);
+    auto holder = MakeRefPtr<css::SheetLoadDataHolder>(__func__, &aLoadData);
     Servo_StyleSheet_FromUTF8BytesAsync(
-        loadDataHolder, Inner().mURLData, &aBytes, mParsingMode,
-        aLoadData->mLineNumber, aLoader->GetCompatibilityMode(),
+        holder, Inner().mURLData, &aBytes, mParsingMode, aLoadData.mLineNumber,
+        aLoader.GetCompatibilityMode(),
         /* should_record_counters = */ !!useCounters);
   }
 
   return p;
 }
 
 void StyleSheet::FinishAsyncParse(
     already_AddRefed<RawServoStyleSheetContents> aSheetContents) {
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -95,29 +95,31 @@ class StyleSheet final : public nsICSSLo
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
 
   already_AddRefed<StyleSheet> CreateEmptyChildSheet(
       already_AddRefed<dom::MediaList> aMediaList) const;
 
   bool HasRules() const;
 
-  // Parses a stylesheet. The aLoadData argument corresponds to the
-  // SheetLoadData for this stylesheet. It may be null in some cases.
-  RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader* aLoader,
+  // Parses a stylesheet. The load data argument corresponds to the
+  // SheetLoadData for this stylesheet.
+  RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader&,
                                             const nsACString& aBytes,
-                                            css::SheetLoadData* aLoadData);
+                                            css::SheetLoadData&);
 
   // Common code that needs to be called after servo finishes parsing. This is
   // shared between the parallel and sequential paths.
   void FinishAsyncParse(
       already_AddRefed<RawServoStyleSheetContents> aSheetContents);
 
   // Similar to the above, but guarantees that parsing will be performed
   // synchronously.
+  //
+  // The load data may be null sometimes.
   void ParseSheetSync(
       css::Loader* aLoader, const nsACString& aBytes,
       css::SheetLoadData* aLoadData, uint32_t aLineNumber,
       css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
 
   nsresult ReparseSheet(const nsAString& aInput);
 
   const RawServoStyleSheetContents* RawContents() const {
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -41,59 +41,16 @@ class nsPresContext;
 template <class T>
 class nsPtrHashKey;
 struct RawServoCssUrlData;
 
 namespace mozilla {
 class CSSStyleSheet;
 }  // namespace mozilla
 
-// Deletes a linked list iteratively to avoid blowing up the stack (bug 456196).
-#define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \
-  {                                                     \
-    type_* cur = (ptr_)->member_;                       \
-    (ptr_)->member_ = nullptr;                          \
-    while (cur) {                                       \
-      type_* dlm_next = cur->member_;                   \
-      cur->member_ = nullptr;                           \
-      delete cur;                                       \
-      cur = dlm_next;                                   \
-    }                                                   \
-  }
-// Ditto, but use NS_RELEASE instead of 'delete' (bug 1221902).
-#define NS_CSS_NS_RELEASE_LIST_MEMBER(type_, ptr_, member_) \
-  {                                                         \
-    type_* cur = (ptr_)->member_;                           \
-    (ptr_)->member_ = nullptr;                              \
-    while (cur) {                                           \
-      type_* dlm_next = cur->member_;                       \
-      cur->member_ = nullptr;                               \
-      NS_RELEASE(cur);                                      \
-      cur = dlm_next;                                       \
-    }                                                       \
-  }
-
-// Clones a linked list iteratively to avoid blowing up the stack.
-// If it fails to clone the entire list then 'to_' is deleted and
-// we return null.
-#define NS_CSS_CLONE_LIST_MEMBER(type_, from_, member_, to_, args_)      \
-  {                                                                      \
-    type_* dest = (to_);                                                 \
-    (to_)->member_ = nullptr;                                            \
-    for (const type_* src = (from_)->member_; src; src = src->member_) { \
-      type_* clm_clone = src->Clone args_;                               \
-      if (!clm_clone) {                                                  \
-        delete (to_);                                                    \
-        return nullptr;                                                  \
-      }                                                                  \
-      dest->member_ = clm_clone;                                         \
-      dest = clm_clone;                                                  \
-    }                                                                    \
-  }
-
 // Forward declaration copied here since ServoBindings.h #includes nsCSSValue.h.
 extern "C" {
 mozilla::URLExtraData* Servo_CssUrlData_GetExtraData(const RawServoCssUrlData*);
 bool Servo_CssUrlData_IsLocalRef(const RawServoCssUrlData* url);
 }
 
 enum nsCSSUnit : uint32_t {
   eCSSUnit_Null = 0,  // (n/a) null unit, value is not specified