Merge mozilla-inbound to mozilla-central a=merge
authorRazvan Maries <rmaries@mozilla.com>
Mon, 21 Jan 2019 19:50:56 +0200
changeset 514735 44369796f148630ff496be99f77a5eeea41c7d23
parent 514734 4977d02e11915a93c6c80a51f3e7bdc99d5e2f08 (current diff)
parent 514714 b1f8fe42b1a80800368724ebbff8e5097e632511 (diff)
child 514736 f851b150476a2259413390d4510f27ed62a1d1c2
child 514771 19db0edfbc10ad8f540a0a3482bd78c0baf7246d
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
44369796f148 / 66.0a1 / 20190121175139 / files
nightly linux64
44369796f148 / 66.0a1 / 20190121175139 / files
nightly mac
44369796f148 / 66.0a1 / 20190121175139 / files
nightly win32
44369796f148 / 66.0a1 / 20190121175139 / files
nightly win64
44369796f148 / 66.0a1 / 20190121175139 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central a=merge
dom/base/nsGlobalWindowOuter.cpp
dom/script/ScriptLoader.cpp
dom/smil/nsSMILInterval.cpp
dom/smil/nsSMILInterval.h
dom/smil/nsSMILRepeatCount.cpp
dom/smil/nsSMILRepeatCount.h
js/src/gc/GC.cpp
js/src/gc/Statistics.cpp
js/src/gc/Statistics.h
js/src/jit/arm/AtomicOperations-arm.h
js/src/jit/arm64/AtomicOperations-arm64-gcc.h
js/src/jit/arm64/AtomicOperations-arm64-msvc.h
js/src/jit/none/AtomicOperations-feeling-lucky.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-gcc.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
js/src/jsapi.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10376,17 +10376,17 @@ nsresult nsDocShell::DoChannelLoad(nsICh
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aURILoader->OpenURI(aChannel, openFlags, this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We're about to load a new page and it may take time before necko
   // gives back any data, so main thread might have a chance to process a
   // collector slice
-  nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL);
+  nsJSContext::MaybeRunNextCollectorSlice(this, JS::GCReason::DOCSHELL);
 
   // Success.  Keep the initial ClientSource if it exists.
   cleanupInitialClient.release();
 
   return NS_OK;
 }
 
 nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
--- a/dom/base/FuzzingFunctions.cpp
+++ b/dom/base/FuzzingFunctions.cpp
@@ -17,17 +17,17 @@
 #include "nsIAccessibilityService.h"
 #include "nsPIDOMWindow.h"
 #include "xpcAccessibilityService.h"
 
 namespace mozilla {
 namespace dom {
 
 /* static */ void FuzzingFunctions::GarbageCollect(const GlobalObject&) {
-  nsJSContext::GarbageCollectNow(JS::gcreason::COMPONENT_UTILS,
+  nsJSContext::GarbageCollectNow(JS::GCReason::COMPONENT_UTILS,
                                  nsJSContext::NonIncrementalGC,
                                  nsJSContext::NonShrinkingGC);
 }
 
 /* static */ void FuzzingFunctions::CycleCollect(const GlobalObject&) {
   nsJSContext::CycleCollectNow();
 }
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1032,31 +1032,31 @@ nsIWidget* nsDOMWindowUtils::GetWidgetFo
 
   return nullptr;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
   AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
 
-  nsJSContext::GarbageCollectNow(JS::gcreason::DOM_UTILS);
+  nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
   nsJSContext::CycleCollectNow(aListener);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
   nsJSContext::CycleCollectNow(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::RunNextCollectorTimer() {
-  nsJSContext::RunNextCollectorTimer(JS::gcreason::DOM_WINDOW_UTILS);
+  nsJSContext::RunNextCollectorTimer(JS::GCReason::DOM_WINDOW_UTILS);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType, float aX,
                                          float aY, uint32_t aDirection,
                                          double aDelta, int32_t aModifiers,
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -6001,20 +6001,21 @@ bool nsGlobalWindowInner::RunTimeoutHand
       options.setFileAndLine(filename, lineNo);
       options.setNoScriptRval(true);
       JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
       nsresult rv;
       {
         nsJSUtils::ExecutionContext exec(aes.cx(), global);
         rv = exec.Compile(options, handler->GetHandlerText());
 
-        if (rv == NS_OK) {
+        JS::Rooted<JSScript*> script(aes.cx(), exec.MaybeGetScript());
+        if (script) {
           LoadedScript* initiatingScript = handler->GetInitiatingScript();
           if (initiatingScript) {
-            initiatingScript->AssociateWithScript(exec.GetScript());
+            initiatingScript->AssociateWithScript(script);
           }
 
           rv = exec.ExecScript();
         }
       }
 
       if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
         abortIntervalHandler = true;
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2490,17 +2490,17 @@ void nsGlobalWindowOuter::DetachFromDocS
   ClearControllers();
 
   mChromeEventHandler = nullptr;  // force release now
 
   if (mContext) {
     // When we're about to destroy a top level content window
     // (for example a tab), we trigger a full GC by passing null as the last
     // param. We also trigger a full GC for chrome windows.
-    nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL,
+    nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
                         (mTopLevelOuterContentWindow || mIsChrome)
                             ? nullptr
                             : GetWrapperPreserveColor());
     mContext = nullptr;
   }
 
   mDocShell = nullptr;  // Weak Reference
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -319,22 +319,22 @@ nsJSEnvironmentObserver::Observe(nsISupp
   if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
     if (StaticPrefs::javascript_options_gc_on_memory_pressure()) {
       if (StringBeginsWith(nsDependentString(aData),
                            NS_LITERAL_STRING("low-memory-ongoing"))) {
         // Don't GC/CC if we are in an ongoing low-memory state since its very
         // slow and it likely won't help us anyway.
         return NS_OK;
       }
-      nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
+      nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
                                      nsJSContext::NonIncrementalGC,
                                      nsJSContext::ShrinkingGC);
       nsJSContext::CycleCollectNow();
       if (NeedsGCAfterCC()) {
-        nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
+        nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
                                        nsJSContext::NonIncrementalGC,
                                        nsJSContext::ShrinkingGC);
       }
     }
   } else if (!nsCRT::strcmp(aTopic, "user-interaction-inactive")) {
     if (StaticPrefs::javascript_options_compact_on_user_inactive()) {
       nsJSContext::PokeShrinkingGC();
     }
@@ -572,17 +572,17 @@ nsJSContext::nsJSContext(bool aGCOnDestr
 nsJSContext::~nsJSContext() {
   mGlobalObjectRef = nullptr;
 
   Destroy();
 }
 
 void nsJSContext::Destroy() {
   if (mGCOnDestruction) {
-    PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY, mWindowProxy);
+    PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy);
   }
 
   DropJSObjects(this);
 }
 
 // QueryInterface implementation for nsJSContext
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext)
 
@@ -1074,27 +1074,27 @@ bool nsJSContext::GetProcessingScriptTag
 
 void nsJSContext::SetProcessingScriptTag(bool aFlag) {
   mProcessingScriptTag = aFlag;
 }
 
 void FullGCTimerFired(nsITimer* aTimer, void* aClosure) {
   nsJSContext::KillFullGCTimer();
   MOZ_ASSERT(!aClosure, "Don't pass a closure to FullGCTimerFired");
-  nsJSContext::GarbageCollectNow(JS::gcreason::FULL_GC_TIMER,
+  nsJSContext::GarbageCollectNow(JS::GCReason::FULL_GC_TIMER,
                                  nsJSContext::IncrementalGC);
 }
 
 // static
-void nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
+void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
                                     IsIncremental aIncremental,
                                     IsShrinking aShrinking,
                                     int64_t aSliceMillis) {
   AUTO_PROFILER_LABEL_DYNAMIC_CSTR("nsJSContext::GarbageCollectNow", GCCC,
-                                   JS::gcreason::ExplainReason(aReason));
+                                   JS::ExplainGCReason(aReason));
 
   MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
 
   KillGCTimer();
 
   // We use danger::GetJSContext() since AutoJSAPI will assert if the current
   // thread's context is null (such as during shutdown).
   JSContext* cx = danger::GetJSContext();
@@ -1108,17 +1108,17 @@ void nsJSContext::GarbageCollectNow(JS::
     JS::PrepareForIncrementalGC(cx);
     JS::IncrementalGCSlice(cx, aReason, aSliceMillis);
     return;
   }
 
   JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
 
   if (aIncremental == NonIncrementalGC ||
-      aReason == JS::gcreason::FULL_GC_TIMER) {
+      aReason == JS::GCReason::FULL_GC_TIMER) {
     sNeedsFullGC = true;
   }
 
   if (sNeedsFullGC) {
     JS::PrepareForFullGC(cx);
   } else {
     CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
   }
@@ -1134,17 +1134,17 @@ static void FinishAnyIncrementalGC() {
   AUTO_PROFILER_LABEL("FinishAnyIncrementalGC", GCCC);
 
   if (sCCLockedOut) {
     AutoJSAPI jsapi;
     jsapi.Init();
 
     // We're in the middle of an incremental GC, so finish it.
     JS::PrepareForIncrementalGC(jsapi.cx());
-    JS::FinishIncrementalGC(jsapi.cx(), JS::gcreason::CC_FORCED);
+    JS::FinishIncrementalGC(jsapi.cx(), JS::GCReason::CC_FORCED);
   }
 }
 
 static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
                                 TimeStamp aDeadline) {
   AUTO_PROFILER_TRACING(
       "CC", aDeadline.IsNull() ? "ForgetSkippable" : "IdleForgetSkippable",
       GCCC);
@@ -1568,17 +1568,17 @@ void nsJSContext::EndCycleCollectionCall
 
   sCCollectedWaitingForGC += aResults.mFreedGCed;
   sCCollectedZonesWaitingForGC += aResults.mFreedJSZones;
 
   TimeStamp endCCTimeStamp = TimeStamp::Now();
   uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp);
 
   if (NeedsGCAfterCC()) {
-    PokeGC(JS::gcreason::CC_WAITING, nullptr,
+    PokeGC(JS::GCReason::CC_WAITING, nullptr,
            NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration));
   }
 
   // Log information about the CC via telemetry, JSON and the console.
   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC,
                         gCCStats.mAnyLockedOut);
   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE,
                         gCCStats.mRanSyncForgetSkippable);
@@ -1725,18 +1725,17 @@ bool InterSliceGCRunnerFired(TimeStamp a
     budget = static_cast<int64_t>(
         std::max((double)budget, percentOfLockedTime * maxSliceGCBudget));
   }
 
   TimeStamp startTimeStamp = TimeStamp::Now();
   TimeDuration duration = sGCUnnotifiedTotalTime;
   uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
   nsJSContext::GarbageCollectNow(
-      aData ? static_cast<JS::gcreason::Reason>(reason)
-            : JS::gcreason::INTER_SLICE_GC,
+      aData ? static_cast<JS::GCReason>(reason) : JS::GCReason::INTER_SLICE_GC,
       nsJSContext::IncrementalGC, nsJSContext::NonShrinkingGC, budget);
 
   sGCUnnotifiedTotalTime = TimeDuration();
   TimeStamp now = TimeStamp::Now();
   TimeDuration sliceDuration = now - startTimeStamp;
   duration += sliceDuration;
   if (duration.ToSeconds()) {
     TimeDuration idleDuration;
@@ -1775,17 +1774,17 @@ void GCTimerFired(nsITimer* aTimer, void
       sActiveIntersliceGCBudget, false, [] { return sShuttingDown; },
       TaskCategory::GarbageCollection);
 }
 
 // static
 void ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure) {
   nsJSContext::KillShrinkingGCTimer();
   sIsCompactingOnUserInactive = true;
-  nsJSContext::GarbageCollectNow(JS::gcreason::USER_INACTIVE,
+  nsJSContext::GarbageCollectNow(JS::GCReason::USER_INACTIVE,
                                  nsJSContext::IncrementalGC,
                                  nsJSContext::ShrinkingGC);
 }
 
 static bool ShouldTriggerCC(uint32_t aSuspected) {
   return sNeedsFullCC || aSuspected > NS_CC_PURPLE_LIMIT ||
          (aSuspected > NS_CC_FORCED_PURPLE_LIMIT &&
           TimeUntilNow(sLastCCEndTime) > NS_CC_FORCED);
@@ -1881,17 +1880,17 @@ static bool CCRunnerFired(TimeStamp aDea
 // static
 uint32_t nsJSContext::CleanupsSinceLastGC() { return sCleanupsSinceLastGC; }
 
 // Check all of the various collector timers/runners and see if they are waiting
 // to fire. This does not check sFullGCTimer, as that's a more expensive
 // collection we run on a long timer.
 
 // static
-void nsJSContext::RunNextCollectorTimer(JS::gcreason::Reason aReason,
+void nsJSContext::RunNextCollectorTimer(JS::GCReason aReason,
                                         mozilla::TimeStamp aDeadline) {
   if (sShuttingDown) {
     return;
   }
 
   if (sGCTimer) {
     GCTimerFired(nullptr, reinterpret_cast<void*>(aReason));
     return;
@@ -1920,17 +1919,17 @@ void nsJSContext::RunNextCollectorTimer(
 
   if (runnable) {
     runnable->Run();
   }
 }
 
 // static
 void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
-                                             JS::gcreason::Reason aReason) {
+                                             JS::GCReason aReason) {
   if (!aDocShell || !XRE_IsContentProcess()) {
     return;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> root;
   aDocShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
   if (root == aDocShell) {
     // We don't want to run collectors when loading the top level page.
@@ -1967,26 +1966,25 @@ void nsJSContext::MaybeRunNextCollectorS
     // deadline for collectors.
     if (next.isSome()) {
       nsJSContext::RunNextCollectorTimer(aReason, next.value());
     }
   }
 }
 
 // static
-void nsJSContext::PokeGC(JS::gcreason::Reason aReason, JSObject* aObj,
-                         int aDelay) {
+void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj, int aDelay) {
   if (sShuttingDown) {
     return;
   }
 
   if (aObj) {
     JS::Zone* zone = JS::GetObjectZone(aObj);
     CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone);
-  } else if (aReason != JS::gcreason::CC_WAITING) {
+  } else if (aReason != JS::GCReason::CC_WAITING) {
     sNeedsFullGC = true;
   }
 
   if (sGCTimer || sInterSliceGCRunner) {
     // There's already a timer for GC'ing, just return
     return;
   }
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -67,17 +67,17 @@ class nsJSContext : public nsIScriptCont
 
   enum IsShrinking { ShrinkingGC, NonShrinkingGC };
 
   enum IsIncremental { IncrementalGC, NonIncrementalGC };
 
   // Setup all the statics etc - safe to call multiple times after Startup().
   static void EnsureStatics();
 
-  static void GarbageCollectNow(JS::gcreason::Reason reason,
+  static void GarbageCollectNow(JS::GCReason reason,
                                 IsIncremental aIncremental = NonIncrementalGC,
                                 IsShrinking aShrinking = NonShrinkingGC,
                                 int64_t aSliceMillis = 0);
 
   static void CycleCollectNow(nsICycleCollectorListener *aListener = nullptr);
 
   // Run a cycle collector slice, using a heuristic to decide how long to run
   // it.
@@ -92,27 +92,26 @@ class nsJSContext : public nsIScriptCont
 
   // Return the longest CC slice time since ClearMaxCCSliceTime() was last
   // called.
   static uint32_t GetMaxCCSliceTimeSinceClear();
   static void ClearMaxCCSliceTime();
 
   // If there is some pending CC or GC timer/runner, this will run it.
   static void RunNextCollectorTimer(
-      JS::gcreason::Reason aReason,
+      JS::GCReason aReason,
       mozilla::TimeStamp aDeadline = mozilla::TimeStamp());
   // If user has been idle and aDocShell is for an iframe being loaded in an
   // already loaded top level docshell, this will run a CC or GC
   // timer/runner if there is such pending.
   static void MaybeRunNextCollectorSlice(nsIDocShell *aDocShell,
-                                         JS::gcreason::Reason aReason);
+                                         JS::GCReason aReason);
 
   // The GC should probably run soon, in the zone of object aObj (if given).
-  static void PokeGC(JS::gcreason::Reason aReason, JSObject *aObj,
-                     int aDelay = 0);
+  static void PokeGC(JS::GCReason aReason, JSObject *aObj, int aDelay = 0);
   static void KillGCTimer();
 
   static void PokeShrinkingGC();
   static void KillShrinkingGCTimer();
 
   static void MaybePokeCC();
   static void KillCCRunner();
   static void KillICCRunner();
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -369,16 +369,20 @@ nsresult nsJSUtils::ExecutionContext::De
 
 JSScript* nsJSUtils::ExecutionContext::GetScript() {
 #ifdef DEBUG
   MOZ_ASSERT(!mSkip);
   MOZ_ASSERT(mScript);
   mScriptUsed = true;
 #endif
 
+  return MaybeGetScript();
+}
+
+JSScript* nsJSUtils::ExecutionContext::MaybeGetScript() {
   return mScript;
 }
 
 nsresult nsJSUtils::ExecutionContext::ExecScript() {
   if (mSkip) {
     return mRv;
   }
 
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -170,16 +170,19 @@ class nsJSUtils {
 
     // Decode a BinAST encoded script contained in a buffer.
     nsresult DecodeBinAST(JS::CompileOptions& aCompileOptions,
                           const uint8_t* aBuf, size_t aLength);
 
     // Get a successfully compiled script.
     JSScript* GetScript();
 
+    // Get the compiled script if present, or nullptr.
+    JSScript* MaybeGetScript();
+
     // Execute the compiled script and ignore the return value.
     MOZ_MUST_USE nsresult ExecScript();
 
     // Execute the compiled script a get the return value.
     //
     // Copy the returned value into the mutable handle argument. In case of a
     // evaluation failure either during the execution or the conversion of the
     // result to a string, the nsresult is be set to the corresponding result
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -124,17 +124,17 @@ void MaybeCollectGarbageOnIPCMessage() {
   if (!NS_IsMainThread()) {
     if (!haveWarnedAboutNonMainThread) {
       haveWarnedAboutNonMainThread = true;
       NS_WARNING("Don't know how to GC on a non-main thread yet.");
     }
     return;
   }
 
-  nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
+  nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
   nsJSContext::CycleCollectNow();
 #endif  // BUILD_GC_ON_IPC_MESSAGES
 }
 
 class MOZ_STACK_CLASS AutoSetCurrentTransaction final {
   typedef mozilla::ipc::BackgroundChildImpl BackgroundChildImpl;
 
   IDBTransaction* const mTransaction;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2467,17 +2467,17 @@ mozilla::ipc::IPCResult ContentChild::Re
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvGarbageCollect() {
   // Rebroadcast the "child-gc-request" so that workers will GC.
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
   }
-  nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
+  nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvCycleCollect() {
   // Rebroadcast the "child-cc-request" so that workers will CC.
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -2439,17 +2439,17 @@ class MOZ_RAII AutoSetProcessingScriptTa
   }
 
   ~AutoSetProcessingScriptTag() { mContext->SetProcessingScriptTag(mOldTag); }
 };
 
 static nsresult ExecuteCompiledScript(JSContext* aCx,
                                       ScriptLoadRequest* aRequest,
                                       nsJSUtils::ExecutionContext& aExec) {
-  JS::Rooted<JSScript*> script(aCx, aExec.GetScript());
+  JS::Rooted<JSScript*> script(aCx, aExec.MaybeGetScript());
   if (!script) {
     // Compilation succeeds without producing a script if scripting is
     // disabled for the global.
     return NS_OK;
   }
 
   // Create a ClassicScript object and associate it with the JSScript.
   RefPtr<ClassicScript> classicScript =
rename from dom/smil/nsSMILInterval.cpp
rename to dom/smil/SMILInterval.cpp
--- a/dom/smil/nsSMILInterval.cpp
+++ b/dom/smil/SMILInterval.cpp
@@ -1,42 +1,44 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsSMILInterval.h"
+#include "SMILInterval.h"
+
+namespace mozilla {
 
-nsSMILInterval::nsSMILInterval() : mBeginFixed(false), mEndFixed(false) {}
+SMILInterval::SMILInterval() : mBeginFixed(false), mEndFixed(false) {}
 
-nsSMILInterval::nsSMILInterval(const nsSMILInterval& aOther)
+SMILInterval::SMILInterval(const SMILInterval& aOther)
     : mBegin(aOther.mBegin),
       mEnd(aOther.mEnd),
       mBeginFixed(false),
       mEndFixed(false) {
   MOZ_ASSERT(aOther.mDependentTimes.IsEmpty(),
              "Attempt to copy-construct an interval with dependent times; this "
              "will lead to instance times being shared between intervals.");
 
   // For the time being we don't allow intervals with fixed endpoints to be
   // copied since we only ever copy-construct to establish a new current
   // interval. If we ever need to copy historical intervals we may need to move
   // the ReleaseFixedEndpoint calls from Unlink to the dtor.
   MOZ_ASSERT(!aOther.mBeginFixed && !aOther.mEndFixed,
              "Attempt to copy-construct an interval with fixed endpoints");
 }
 
-nsSMILInterval::~nsSMILInterval() {
+SMILInterval::~SMILInterval() {
   MOZ_ASSERT(mDependentTimes.IsEmpty(),
              "Destroying interval without disassociating dependent instance "
              "times. Unlink was not called");
 }
 
-void nsSMILInterval::Unlink(bool aFiltered) {
+void SMILInterval::Unlink(bool aFiltered) {
   for (int32_t i = mDependentTimes.Length() - 1; i >= 0; --i) {
     if (aFiltered) {
       mDependentTimes[i]->HandleFilteredInterval();
     } else {
       mDependentTimes[i]->HandleDeletedInterval();
     }
   }
   mDependentTimes.Clear();
@@ -45,90 +47,92 @@ void nsSMILInterval::Unlink(bool aFilter
   }
   mBegin = nullptr;
   if (mEnd && mEndFixed) {
     mEnd->ReleaseFixedEndpoint();
   }
   mEnd = nullptr;
 }
 
-nsSMILInstanceTime* nsSMILInterval::Begin() {
+nsSMILInstanceTime* SMILInterval::Begin() {
   MOZ_ASSERT(mBegin && mEnd, "Requesting Begin() on un-initialized interval.");
   return mBegin;
 }
 
-nsSMILInstanceTime* nsSMILInterval::End() {
+nsSMILInstanceTime* SMILInterval::End() {
   MOZ_ASSERT(mBegin && mEnd, "Requesting End() on un-initialized interval.");
   return mEnd;
 }
 
-void nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
+void SMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
   MOZ_ASSERT(aBegin.Time().IsDefinite(),
              "Attempt to set unresolved or indefinite begin time on interval");
   MOZ_ASSERT(!mBeginFixed,
              "Attempt to set begin time but the begin point is fixed");
   // Check that we're not making an instance time dependent on itself. Such an
   // arrangement does not make intuitive sense and should be detected when
   // creating or updating intervals.
   MOZ_ASSERT(!mBegin || aBegin.GetBaseTime() != mBegin,
              "Attempt to make self-dependent instance time");
 
   mBegin = &aBegin;
 }
 
-void nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
+void SMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
   MOZ_ASSERT(!mEndFixed, "Attempt to set end time but the end point is fixed");
   // As with SetBegin, check we're not making an instance time dependent on
   // itself.
   MOZ_ASSERT(!mEnd || aEnd.GetBaseTime() != mEnd,
              "Attempting to make self-dependent instance time");
 
   mEnd = &aEnd;
 }
 
-void nsSMILInterval::FixBegin() {
+void SMILInterval::FixBegin() {
   MOZ_ASSERT(mBegin && mEnd, "Fixing begin point on un-initialized interval");
   MOZ_ASSERT(!mBeginFixed, "Duplicate calls to FixBegin()");
   mBeginFixed = true;
   mBegin->AddRefFixedEndpoint();
 }
 
-void nsSMILInterval::FixEnd() {
+void SMILInterval::FixEnd() {
   MOZ_ASSERT(mBegin && mEnd, "Fixing end point on un-initialized interval");
   MOZ_ASSERT(mBeginFixed,
              "Fixing the end of an interval without a fixed begin");
   MOZ_ASSERT(!mEndFixed, "Duplicate calls to FixEnd()");
   mEndFixed = true;
   mEnd->AddRefFixedEndpoint();
 }
 
-void nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
+void SMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
   RefPtr<nsSMILInstanceTime>* inserted =
       mDependentTimes.InsertElementSorted(&aTime);
   if (!inserted) {
     NS_WARNING("Insufficient memory to insert instance time.");
   }
 }
 
-void nsSMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
+void SMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
 #ifdef DEBUG
   bool found =
 #endif
       mDependentTimes.RemoveElementSorted(&aTime);
   MOZ_ASSERT(found, "Couldn't find instance time to delete.");
 }
 
-void nsSMILInterval::GetDependentTimes(InstanceTimeList& aTimes) {
+void SMILInterval::GetDependentTimes(InstanceTimeList& aTimes) {
   aTimes = mDependentTimes;
 }
 
-bool nsSMILInterval::IsDependencyChainLink() const {
+bool SMILInterval::IsDependencyChainLink() const {
   if (!mBegin || !mEnd)
     return false;  // Not yet initialised so it can't be part of a chain
 
   if (mDependentTimes.IsEmpty()) return false;  // No dependents, chain end
 
   // So we have dependents, but we're still only a link in the chain (as opposed
   // to the end of the chain) if one of our endpoints is dependent on an
   // interval other than ourselves.
   return (mBegin->IsDependent() && mBegin->GetBaseInterval() != this) ||
          (mEnd->IsDependent() && mEnd->GetBaseInterval() != this);
 }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILInterval.h
rename to dom/smil/SMILInterval.h
--- a/dom/smil/nsSMILInterval.h
+++ b/dom/smil/SMILInterval.h
@@ -5,30 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILINTERVAL_H_
 #define NS_SMILINTERVAL_H_
 
 #include "nsSMILInstanceTime.h"
 #include "nsTArray.h"
 
+namespace mozilla {
+
 //----------------------------------------------------------------------
-// nsSMILInterval class
+// SMILInterval class
 //
 // A structure consisting of a begin and end time. The begin time must be
 // resolved (i.e. not indefinite or unresolved).
 //
 // For an overview of how this class is related to other SMIL time classes see
 // the documentation in nsSMILTimeValue.h
 
-class nsSMILInterval {
+class SMILInterval {
  public:
-  nsSMILInterval();
-  nsSMILInterval(const nsSMILInterval& aOther);
-  ~nsSMILInterval();
+  SMILInterval();
+  SMILInterval(const SMILInterval& aOther);
+  ~SMILInterval();
   void Unlink(bool aFiltered = false);
 
   const nsSMILInstanceTime* Begin() const {
     MOZ_ASSERT(mBegin && mEnd,
                "Requesting Begin() on un-initialized instance time");
     return mBegin;
   }
   nsSMILInstanceTime* Begin();
@@ -74,9 +76,11 @@ class nsSMILInterval {
   // end point to refer to a different nsSMILInstanceTime object.
   //
   // However, if mBegin/EndFixed is true, then BOTH the nsSMILInstanceTime
   // OBJECT returned for that end point and its TIME value will not change.
   bool mBeginFixed;
   bool mEndFixed;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILINTERVAL_H_
--- a/dom/smil/SMILParserUtils.cpp
+++ b/dom/smil/SMILParserUtils.cpp
@@ -1,24 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SMILParserUtils.h"
+
+#include "mozilla/SMILKeySpline.h"
+#include "mozilla/SMILRepeatCount.h"
 #include "mozilla/SVGContentUtils.h"
 #include "mozilla/TextUtils.h"
-#include "SMILKeySpline.h"
 #include "nsISMILAttr.h"
 #include "nsSMILValue.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILTimeValueSpecParams.h"
 #include "nsSMILTypes.h"
-#include "nsSMILRepeatCount.h"
 #include "nsContentUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 
 using namespace mozilla::dom;
 //------------------------------------------------------------------------------
 // Helper functions and Constants
 
 namespace {
@@ -546,17 +547,17 @@ bool SMILParserUtils::ParseValuesGeneric
       return false;
     }
   }
 
   return true;
 }
 
 bool SMILParserUtils::ParseRepeatCount(const nsAString& aSpec,
-                                       nsSMILRepeatCount& aResult) {
+                                       SMILRepeatCount& aResult) {
   const nsAString& spec = SMILParserUtils::TrimWhitespace(aSpec);
 
   if (spec.EqualsLiteral("indefinite")) {
     aResult.SetIndefinite();
     return true;
   }
 
   double value;
--- a/dom/smil/SMILParserUtils.h
+++ b/dom/smil/SMILParserUtils.h
@@ -6,23 +6,23 @@
 
 #ifndef NS_SMILPARSERUTILS_H_
 #define NS_SMILPARSERUTILS_H_
 
 #include "nsTArray.h"
 #include "nsStringFwd.h"
 
 class nsISMILAttr;
-class SMILKeySpline;
 class nsSMILTimeValue;
 class nsSMILValue;
-class nsSMILRepeatCount;
 class nsSMILTimeValueSpecParams;
 
 namespace mozilla {
+class SMILKeySpline;
+class SMILRepeatCount;
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 
 /**
  * Common parsing utilities for the SMIL module. There is little re-use here; it
  * simply serves to simplify other classes by moving parsing outside and to aid
  * unit testing.
@@ -52,17 +52,17 @@ class SMILParserUtils {
                           bool& aPreventCachingOfSandwich);
 
   // Generic method that will run some code on each sub-section of an animation
   // element's "values" list.
   static bool ParseValuesGeneric(const nsAString& aSpec,
                                  GenericValueParser& aParser);
 
   static bool ParseRepeatCount(const nsAString& aSpec,
-                               nsSMILRepeatCount& aResult);
+                               SMILRepeatCount& aResult);
 
   static bool ParseTimeValueSpecParams(const nsAString& aSpec,
                                        nsSMILTimeValueSpecParams& aResult);
 
   /*
    * Parses a clock value as defined in the SMIL Animation specification.
    * If parsing succeeds the returned value will be a non-negative, definite
    * time value i.e. IsDefinite will return true.
rename from dom/smil/nsSMILRepeatCount.cpp
rename to dom/smil/SMILRepeatCount.cpp
--- a/dom/smil/nsSMILRepeatCount.cpp
+++ b/dom/smil/SMILRepeatCount.cpp
@@ -1,10 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsSMILRepeatCount.h"
+#include "SMILRepeatCount.h"
+
+namespace mozilla {
 
-/*static*/ const double nsSMILRepeatCount::kNotSet = -1.0;
-/*static*/ const double nsSMILRepeatCount::kIndefinite = -2.0;
+/*static*/ const double SMILRepeatCount::kNotSet = -1.0;
+/*static*/ const double SMILRepeatCount::kIndefinite = -2.0;
+
+}  // namespace mozilla
+
rename from dom/smil/nsSMILRepeatCount.h
rename to dom/smil/SMILRepeatCount.h
--- a/dom/smil/nsSMILRepeatCount.h
+++ b/dom/smil/SMILRepeatCount.h
@@ -1,48 +1,50 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsSMILRepeatCount_h
-#define nsSMILRepeatCount_h
+#ifndef SMILRepeatCount_h
+#define SMILRepeatCount_h
 
 #include "nsDebug.h"
 #include <math.h>
 
+namespace mozilla {
+
 //----------------------------------------------------------------------
-// nsSMILRepeatCount
+// SMILRepeatCount
 //
 // A tri-state non-negative floating point number for representing the number of
 // times an animation repeat, i.e. the SMIL repeatCount attribute.
 //
 // The three states are:
 //  1. not-set
 //  2. set (with non-negative, non-zero count value)
 //  3. indefinite
 //
-class nsSMILRepeatCount {
+class SMILRepeatCount {
  public:
-  nsSMILRepeatCount() : mCount(kNotSet) {}
-  explicit nsSMILRepeatCount(double aCount) : mCount(kNotSet) {
+  SMILRepeatCount() : mCount(kNotSet) {}
+  explicit SMILRepeatCount(double aCount) : mCount(kNotSet) {
     SetCount(aCount);
   }
 
   operator double() const {
     MOZ_ASSERT(IsDefinite(),
                "Converting indefinite or unset repeat count to double");
     return mCount;
   }
   bool IsDefinite() const { return mCount != kNotSet && mCount != kIndefinite; }
   bool IsIndefinite() const { return mCount == kIndefinite; }
   bool IsSet() const { return mCount != kNotSet; }
 
-  nsSMILRepeatCount& operator=(double aCount) {
+  SMILRepeatCount& operator=(double aCount) {
     SetCount(aCount);
     return *this;
   }
   void SetCount(double aCount) {
     NS_ASSERTION(aCount > 0.0, "Negative or zero repeat count");
     mCount = aCount > 0.0 ? aCount : kNotSet;
   }
   void SetIndefinite() { mCount = kIndefinite; }
@@ -50,9 +52,11 @@ class nsSMILRepeatCount {
 
  private:
   static const double kNotSet;
   static const double kIndefinite;
 
   double mCount;
 };
 
+}  // namespace mozilla
+
 #endif
--- a/dom/smil/SMILTimedElement.cpp
+++ b/dom/smil/SMILTimedElement.cpp
@@ -543,24 +543,24 @@ void SMILTimedElement::DoSampleAt(nsSMIL
                  "Should have current interval in waiting and active states");
     }
 #endif
 
     stateChanged = false;
 
     switch (mElementState) {
       case STATE_STARTUP: {
-        nsSMILInterval firstInterval;
+        SMILInterval firstInterval;
         mElementState =
             GetNextInterval(nullptr, nullptr, nullptr, firstInterval)
                 ? STATE_WAITING
                 : STATE_POSTACTIVE;
         stateChanged = true;
         if (mElementState == STATE_WAITING) {
-          mCurrentInterval = MakeUnique<nsSMILInterval>(firstInterval);
+          mCurrentInterval = MakeUnique<SMILInterval>(firstInterval);
           NotifyNewInterval();
         }
       } break;
 
       case STATE_WAITING: {
         if (mCurrentInterval->Begin()->Time() <= sampleTime) {
           mElementState = STATE_ACTIVE;
           mCurrentInterval->FixBegin();
@@ -587,33 +587,33 @@ void SMILTimedElement::DoSampleAt(nsSMIL
 
       case STATE_ACTIVE: {
         // Ending early will change the interval but we don't notify dependents
         // of the change until we have closed off the current interval (since we
         // don't want dependencies to un-end our early end).
         bool didApplyEarlyEnd = ApplyEarlyEnd(sampleTime);
 
         if (mCurrentInterval->End()->Time() <= sampleTime) {
-          nsSMILInterval newInterval;
+          SMILInterval newInterval;
           mElementState = GetNextInterval(mCurrentInterval.get(), nullptr,
                                           nullptr, newInterval)
                               ? STATE_WAITING
                               : STATE_POSTACTIVE;
           if (mClient) {
             mClient->Inactivate(mFillMode == FILL_FREEZE);
           }
           mCurrentInterval->FixEnd();
           if (mSeekState == SEEK_NOT_SEEKING) {
             FireTimeEventAsync(eSMILEndEvent, 0);
           }
           mCurrentRepeatIteration = 0;
           mOldIntervals.AppendElement(std::move(mCurrentInterval));
           SampleFillValue();
           if (mElementState == STATE_WAITING) {
-            mCurrentInterval = MakeUnique<nsSMILInterval>(newInterval);
+            mCurrentInterval = MakeUnique<SMILInterval>(newInterval);
           }
           // We are now in a consistent state to dispatch notifications
           if (didApplyEarlyEnd) {
             NotifyChangedInterval(
                 mOldIntervals[mOldIntervals.Length() - 1].get(), false, true);
           }
           if (mElementState == STATE_WAITING) {
             NotifyNewInterval();
@@ -945,17 +945,17 @@ void SMILTimedElement::UnsetRestart() {
   mRestartMode = RESTART_ALWAYS;
   UpdateCurrentInterval();
 }
 
 nsresult SMILTimedElement::SetRepeatCount(const nsAString& aRepeatCountSpec) {
   // Update the current interval before returning
   AutoIntervalUpdater updater(*this);
 
-  nsSMILRepeatCount newRepeatCount;
+  SMILRepeatCount newRepeatCount;
 
   if (SMILParserUtils::ParseRepeatCount(aRepeatCountSpec, newRepeatCount)) {
     mRepeatCount = newRepeatCount;
     return NS_OK;
   }
   mRepeatCount.Unset();
   return NS_ERROR_FAILURE;
 }
@@ -1349,17 +1349,17 @@ void SMILTimedElement::DoPostSeek() {
       /* Do nothing */
       break;
   }
 
   mSeekState = SEEK_NOT_SEEKING;
 }
 
 void SMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList) {
-  const nsSMILInterval* prevInterval = GetPreviousInterval();
+  const SMILInterval* prevInterval = GetPreviousInterval();
   const nsSMILInstanceTime* cutoff =
       mCurrentInterval ? mCurrentInterval->Begin()
                        : prevInterval ? prevInterval->Begin() : nullptr;
   uint32_t count = aList.Length();
   for (uint32_t i = 0; i < count; ++i) {
     nsSMILInstanceTime* instance = aList[i].get();
     if (!cutoff || cutoff->Time().CompareTo(instance->Time()) < 0) {
       instance->UnmarkShouldPreserve();
@@ -1404,17 +1404,17 @@ void SMILTimedElement::FilterIntervals()
   // that generate intervals indefinitely. In such a case we simply set
   // a maximum number of intervals and drop any intervals beyond that threshold.
 
   uint32_t threshold = mOldIntervals.Length() > sMaxNumIntervals
                            ? mOldIntervals.Length() - sMaxNumIntervals
                            : 0;
   IntervalList filteredList;
   for (uint32_t i = 0; i < mOldIntervals.Length(); ++i) {
-    nsSMILInterval* interval = mOldIntervals[i].get();
+    SMILInterval* interval = mOldIntervals[i].get();
     if (i != 0 &&                         /*skip first interval*/
         i + 1 < mOldIntervals.Length() && /*skip previous interval*/
         (i < threshold || !interval->IsDependencyChainLink())) {
       interval->Unlink(true /*filtered, not deleted*/);
     } else {
       filteredList.AppendElement(std::move(mOldIntervals[i]));
     }
   }
@@ -1472,17 +1472,17 @@ void SMILTimedElement::FilterInstanceTim
     // There are a few instance times we should keep though, notably:
     // - the current interval begin time,
     // - the previous interval end time (see note in RemoveInstanceTimes)
     // - the first interval begin time (see note in FilterIntervals)
     nsTArray<const nsSMILInstanceTime*> timesToKeep;
     if (mCurrentInterval) {
       timesToKeep.AppendElement(mCurrentInterval->Begin());
     }
-    const nsSMILInterval* prevInterval = GetPreviousInterval();
+    const SMILInterval* prevInterval = GetPreviousInterval();
     if (prevInterval) {
       timesToKeep.AppendElement(prevInterval->End());
     }
     if (!mOldIntervals.IsEmpty()) {
       timesToKeep.AppendElement(mOldIntervals[0]->Begin());
     }
     RemoveBelowThreshold removeBelowThreshold(threshold, timesToKeep);
     RemoveInstanceTimes(aList, removeBelowThreshold);
@@ -1491,19 +1491,18 @@ void SMILTimedElement::FilterInstanceTim
 
 //
 // This method is based on the pseudocode given in the SMILANIM spec.
 //
 // See:
 // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
 //
 bool SMILTimedElement::GetNextInterval(
-    const nsSMILInterval* aPrevInterval,
-    const nsSMILInterval* aReplacedInterval,
-    const nsSMILInstanceTime* aFixedBeginTime, nsSMILInterval& aResult) const {
+    const SMILInterval* aPrevInterval, const SMILInterval* aReplacedInterval,
+    const nsSMILInstanceTime* aFixedBeginTime, SMILInterval& aResult) const {
   MOZ_ASSERT(!aFixedBeginTime || aFixedBeginTime->Time().IsDefinite(),
              "Unresolved or indefinite begin time given for interval start");
   static const nsSMILTimeValue zeroTime(0L);
 
   if (mRestartMode == RESTART_NEVER && aPrevInterval) return false;
 
   // Calc starting point
   nsSMILTimeValue beginAfter;
@@ -1855,23 +1854,23 @@ void SMILTimedElement::UpdateCurrentInte
     MOZ_ASSERT(false,
                "Update current interval recursion depth exceeded threshold");
     return;
   }
 
   // If the interval is active the begin time is fixed.
   const nsSMILInstanceTime* beginTime =
       mElementState == STATE_ACTIVE ? mCurrentInterval->Begin() : nullptr;
-  nsSMILInterval updatedInterval;
+  SMILInterval updatedInterval;
   if (GetNextInterval(GetPreviousInterval(), mCurrentInterval.get(), beginTime,
                       updatedInterval)) {
     if (mElementState == STATE_POSTACTIVE) {
       MOZ_ASSERT(!mCurrentInterval,
                  "In postactive state but the interval has been set");
-      mCurrentInterval = MakeUnique<nsSMILInterval>(updatedInterval);
+      mCurrentInterval = MakeUnique<SMILInterval>(updatedInterval);
       mElementState = STATE_WAITING;
       NotifyNewInterval();
 
     } else {
       bool beginChanged = false;
       bool endChanged = false;
 
       if (mElementState != STATE_ACTIVE &&
@@ -1925,17 +1924,17 @@ void SMILTimedElement::SampleSimpleTime(
 }
 
 void SMILTimedElement::SampleFillValue() {
   if (mFillMode != FILL_FREEZE || !mClient) return;
 
   nsSMILTime activeTime;
 
   if (mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE) {
-    const nsSMILInterval* prevInterval = GetPreviousInterval();
+    const SMILInterval* prevInterval = GetPreviousInterval();
     MOZ_ASSERT(prevInterval,
                "Attempting to sample fill value but there is no previous "
                "interval");
     MOZ_ASSERT(prevInterval->End()->Time().IsDefinite() &&
                    prevInterval->End()->IsFixedTime(),
                "Attempting to sample fill value but the endpoint of the "
                "previous interval is not resolved and fixed");
 
@@ -2086,30 +2085,30 @@ void SMILTimedElement::NotifyNewInterval
              "interval is not set");
 
   SMILTimeContainer* container = GetTimeContainer();
   if (container) {
     container->SyncPauseTime();
   }
 
   for (auto iter = mTimeDependents.Iter(); !iter.Done(); iter.Next()) {
-    nsSMILInterval* interval = mCurrentInterval.get();
+    SMILInterval* interval = mCurrentInterval.get();
     // It's possible that in notifying one new time dependent of a new interval
     // that a chain reaction is triggered which results in the original
     // interval disappearing. If that's the case we can skip sending further
     // notifications.
     if (!interval) {
       break;
     }
     nsSMILTimeValueSpec* spec = iter.Get()->GetKey();
     spec->HandleNewInterval(*interval, container);
   }
 }
 
-void SMILTimedElement::NotifyChangedInterval(nsSMILInterval* aInterval,
+void SMILTimedElement::NotifyChangedInterval(SMILInterval* aInterval,
                                              bool aBeginObjectChanged,
                                              bool aEndObjectChanged) {
   MOZ_ASSERT(aInterval, "Null interval for change notification");
 
   SMILTimeContainer* container = GetTimeContainer();
   if (container) {
     container->SyncPauseTime();
   }
@@ -2139,24 +2138,24 @@ const nsSMILInstanceTime* SMILTimedEleme
     case STATE_STARTUP:
       return nullptr;
 
     case STATE_ACTIVE:
       return mCurrentInterval->Begin();
 
     case STATE_WAITING:
     case STATE_POSTACTIVE: {
-      const nsSMILInterval* prevInterval = GetPreviousInterval();
+      const SMILInterval* prevInterval = GetPreviousInterval();
       return prevInterval ? prevInterval->Begin() : nullptr;
     }
   }
   MOZ_CRASH("Invalid element state");
 }
 
-const nsSMILInterval* SMILTimedElement::GetPreviousInterval() const {
+const SMILInterval* SMILTimedElement::GetPreviousInterval() const {
   return mOldIntervals.IsEmpty()
              ? nullptr
              : mOldIntervals[mOldIntervals.Length() - 1].get();
 }
 
 bool SMILTimedElement::HasClientInFillRange() const {
   // Returns true if we have a client that is in the range where it will fill
   return mClient && ((mElementState != STATE_ACTIVE && HasPlayed()) ||
--- a/dom/smil/SMILTimedElement.h
+++ b/dom/smil/SMILTimedElement.h
@@ -5,21 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILTIMEDELEMENT_H_
 #define NS_SMILTIMEDELEMENT_H_
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/Move.h"
 #include "mozilla/SMILMilestone.h"
+#include "mozilla/SMILInterval.h"
+#include "mozilla/SMILRepeatCount.h"
 #include "mozilla/UniquePtr.h"
-#include "nsSMILInterval.h"
 #include "nsSMILInstanceTime.h"
 #include "nsSMILTimeValueSpec.h"
-#include "nsSMILRepeatCount.h"
 #include "nsSMILTypes.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsAutoPtr.h"
 #include "nsAttrValue.h"
 
 class nsSMILTimeValue;
@@ -343,17 +343,17 @@ class SMILTimedElement {
   void Unlink();
 
   typedef bool (*RemovalTestFunction)(nsSMILInstanceTime* aInstance);
 
  protected:
   // Typedefs
   typedef nsTArray<UniquePtr<nsSMILTimeValueSpec>> TimeValueSpecList;
   typedef nsTArray<RefPtr<nsSMILInstanceTime>> InstanceTimeList;
-  typedef nsTArray<UniquePtr<nsSMILInterval>> IntervalList;
+  typedef nsTArray<UniquePtr<SMILInterval>> IntervalList;
   typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
   typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
 
   // Helper classes
   class InstanceTimeComparator {
    public:
     bool Equals(const nsSMILInstanceTime* aElem1,
                 const nsSMILInstanceTime* aElem2) const;
@@ -454,23 +454,23 @@ class SMILTimedElement {
    * Unmarks instance times that were previously preserved because they were
    * considered important historical milestones but are no longer such because
    * a backwards seek has been performed.
    */
   void UnpreserveInstanceTimes(InstanceTimeList& aList);
 
   /**
    * Helper function to iterate through this element's accumulated timing
-   * information (specifically old nsSMILIntervals and nsSMILTimeInstanceTimes)
+   * information (specifically old SMILIntervals and nsSMILTimeInstanceTimes)
    * and discard items that are no longer needed or exceed some threshold of
    * accumulated state.
    */
   void FilterHistory();
 
-  // Helper functions for FilterHistory to clear old nsSMILIntervals and
+  // Helper functions for FilterHistory to clear old SMILIntervals and
   // nsSMILInstanceTimes respectively.
   void FilterIntervals();
   void FilterInstanceTimes(InstanceTimeList& aList);
 
   /**
    * Calculates the next acceptable interval for this element after the
    * specified interval, or, if no previous interval is specified, it will be
    * the first interval with an end time after t=0.
@@ -487,20 +487,20 @@ class SMILTimedElement {
    *                        is used when only the endpoint of the interval
    *                        should be updated such as when the animation is in
    *                        the ACTIVE state. May be nullptr.
    * @param[out] aResult    The next interval. Will be unchanged if no suitable
    *                        interval was found (in which case false will be
    *                        returned).
    * @return  true if a suitable interval was found, false otherwise.
    */
-  bool GetNextInterval(const nsSMILInterval* aPrevInterval,
-                       const nsSMILInterval* aReplacedInterval,
+  bool GetNextInterval(const SMILInterval* aPrevInterval,
+                       const SMILInterval* aReplacedInterval,
                        const nsSMILInstanceTime* aFixedBeginTime,
-                       nsSMILInterval& aResult) const;
+                       SMILInterval& aResult) const;
   nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
                                      const nsSMILTimeValue& aBase,
                                      int32_t& aPosition) const;
   nsSMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList,
                                             const nsSMILTimeValue& aBase,
                                             int32_t& aPosition) const;
   nsSMILTimeValue CalcActiveEnd(const nsSMILTimeValue& aBegin,
                                 const nsSMILTimeValue& aEnd) const;
@@ -520,22 +520,22 @@ class SMILTimedElement {
 
   // Notification methods. Note that these notifications can result in nested
   // calls to this same object. Therefore,
   // (i)  we should not perform notification until this object is in
   //      a consistent state to receive callbacks, and
   // (ii) after calling these methods we must assume that the state of the
   //      element may have changed.
   void NotifyNewInterval();
-  void NotifyChangedInterval(nsSMILInterval* aInterval,
-                             bool aBeginObjectChanged, bool aEndObjectChanged);
+  void NotifyChangedInterval(SMILInterval* aInterval, bool aBeginObjectChanged,
+                             bool aEndObjectChanged);
 
   void FireTimeEventAsync(EventMessage aMsg, int32_t aDetail);
   const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
-  const nsSMILInterval* GetPreviousInterval() const;
+  const SMILInterval* GetPreviousInterval() const;
   bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
   bool HasClientInFillRange() const;
   bool EndHasEventConditions() const;
   bool AreEndTimesDependentOn(const nsSMILInstanceTime* aBase) const;
 
   // Reset the current interval by first passing ownership to a temporary
   // variable so that if Unlink() results in us receiving a callback,
   // mCurrentInterval will be nullptr and we will be in a consistent state.
@@ -552,17 +552,17 @@ class SMILTimedElement {
   //
   mozilla::dom::SVGAnimationElement* mAnimationElement;  // [weak] won't outlive
                                                          // owner
   TimeValueSpecList mBeginSpecs;                         // [strong]
   TimeValueSpecList mEndSpecs;                           // [strong]
 
   nsSMILTimeValue mSimpleDur;
 
-  nsSMILRepeatCount mRepeatCount;
+  SMILRepeatCount mRepeatCount;
   nsSMILTimeValue mRepeatDur;
 
   nsSMILTimeValue mMin;
   nsSMILTimeValue mMax;
 
   enum nsSMILFillMode : uint8_t { FILL_REMOVE, FILL_FREEZE };
   nsSMILFillMode mFillMode;
   static const nsAttrValue::EnumTable sFillModeTable[];
@@ -575,17 +575,17 @@ class SMILTimedElement {
   nsSMILRestartMode mRestartMode;
   static const nsAttrValue::EnumTable sRestartModeTable[];
 
   InstanceTimeList mBeginInstances;
   InstanceTimeList mEndInstances;
   uint32_t mInstanceSerialIndex;
 
   SMILAnimationFunction* mClient;
-  UniquePtr<nsSMILInterval> mCurrentInterval;
+  UniquePtr<SMILInterval> mCurrentInterval;
   IntervalList mOldIntervals;
   uint32_t mCurrentRepeatIteration;
   SMILMilestone mPrevRegisteredMilestone;
   static const SMILMilestone sMaxMilestone;
   static const uint8_t sMaxNumIntervals;
   static const uint8_t sMaxNumInstanceTimes;
 
   // Set of dependent time value specs to be notified when establishing a new
--- a/dom/smil/moz.build
+++ b/dom/smil/moz.build
@@ -7,64 +7,64 @@
 with Files("**"):
     BUG_COMPONENT = ("Core", "SVG")
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsISMILAttr.h',
     'nsSMILInstanceTime.h',
-    'nsSMILInterval.h',
-    'nsSMILRepeatCount.h',
     'nsSMILTimeValue.h',
     'nsSMILTimeValueSpec.h',
     'nsSMILTimeValueSpecParams.h',
     'nsSMILTypes.h',
     'nsSMILValue.h',
 ]
 
 EXPORTS.mozilla += [
     'SMILAnimationController.h',
     'SMILAnimationFunction.h',
     'SMILCompositorTable.h',
     'SMILCSSValueType.h',
+    'SMILInterval.h',
     'SMILKeySpline.h',
     'SMILMilestone.h',
     'SMILNullType.h',
     'SMILParserUtils.h',
+    'SMILRepeatCount.h',
     'SMILSetAnimationFunction.h',
     'SMILTargetIdentifier.h',
     'SMILTimeContainer.h',
     'SMILTimedElement.h',
     'SMILType.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'TimeEvent.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsSMILInstanceTime.cpp',
-    'nsSMILInterval.cpp',
-    'nsSMILRepeatCount.cpp',
     'nsSMILTimeValue.cpp',
     'nsSMILTimeValueSpec.cpp',
     'nsSMILValue.cpp',
     'SMILAnimationController.cpp',
     'SMILAnimationFunction.cpp',
     'SMILBoolType.cpp',
     'SMILCompositor.cpp',
     'SMILCSSProperty.cpp',
     'SMILCSSValueType.cpp',
     'SMILEnumType.cpp',
     'SMILFloatType.cpp',
     'SMILIntegerType.cpp',
+    'SMILInterval.cpp',
     'SMILKeySpline.cpp',
     'SMILNullType.cpp',
     'SMILParserUtils.cpp',
+    'SMILRepeatCount.cpp',
     'SMILSetAnimationFunction.cpp',
     'SMILStringType.cpp',
     'SMILTimeContainer.cpp',
     'SMILTimedElement.cpp',
     'TimeEvent.cpp',
 ]
 
 LOCAL_INCLUDES += [
--- a/dom/smil/nsSMILInstanceTime.cpp
+++ b/dom/smil/nsSMILInstanceTime.cpp
@@ -1,26 +1,27 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSMILInstanceTime.h"
-#include "nsSMILInterval.h"
+
+#include "mozilla/AutoRestore.h"
+#include "mozilla/SMILInterval.h"
 #include "nsSMILTimeValueSpec.h"
-#include "mozilla/AutoRestore.h"
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
                                        nsSMILInstanceTimeSource aSource,
                                        nsSMILTimeValueSpec* aCreator,
-                                       nsSMILInterval* aBaseInterval)
+                                       SMILInterval* aBaseInterval)
     : mTime(aTime),
       mFlags(0),
       mVisited(false),
       mFixedEndpointRefCnt(0),
       mSerial(0),
       mCreator(aCreator),
       mBaseInterval(nullptr)  // This will get set to aBaseInterval in a call to
                               // SetBaseInterval() at end of constructor
@@ -160,17 +161,17 @@ const nsSMILInstanceTime* nsSMILInstance
   if (!mCreator) {
     return nullptr;
   }
 
   return mCreator->DependsOnBegin() ? mBaseInterval->Begin()
                                     : mBaseInterval->End();
 }
 
-void nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval) {
+void nsSMILInstanceTime::SetBaseInterval(SMILInterval* aBaseInterval) {
   MOZ_ASSERT(!mBaseInterval,
              "Attempting to reassociate an instance time with a different "
              "interval.");
 
   if (aBaseInterval) {
     MOZ_ASSERT(mCreator,
                "Attempting to create a dependent instance time without "
                "reference to the creating nsSMILTimeValueSpec object.");
--- a/dom/smil/nsSMILInstanceTime.h
+++ b/dom/smil/nsSMILInstanceTime.h
@@ -5,44 +5,47 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILINSTANCETIME_H_
 #define NS_SMILINSTANCETIME_H_
 
 #include "nsISupportsImpl.h"
 #include "nsSMILTimeValue.h"
 
-class nsSMILInterval;
 class nsSMILTimeValueSpec;
 
 namespace mozilla {
+class SMILInterval;
 class SMILTimeContainer;
 }
 
 //----------------------------------------------------------------------
 // nsSMILInstanceTime
 //
 // An instant in document simple time that may be used in creating a new
 // interval.
 //
 // For an overview of how this class is related to other SMIL time classes see
 // the documentation in nsSMILTimeValue.h
 //
 // These objects are owned by an SMILTimedElement but MAY also be referenced
 // by:
 //
-// a) nsSMILIntervals that belong to the same SMILTimedElement and which refer
+// a) SMILIntervals that belong to the same SMILTimedElement and which refer
 //    to the nsSMILInstanceTimes which form the interval endpoints; and/or
-// b) nsSMILIntervals that belong to other SMILTimedElements but which need to
+// b) SMILIntervals that belong to other SMILTimedElements but which need to
 //    update dependent instance times when they change or are deleted.
 //    E.g. for begin='a.begin', 'a' needs to inform dependent
 //    nsSMILInstanceTimes if its begin time changes. This notification is
-//    performed by the nsSMILInterval.
+//    performed by the SMILInterval.
 
 class nsSMILInstanceTime final {
+  typedef mozilla::SMILInterval SMILInterval;
+  typedef mozilla::SMILTimeContainer SMILTimeContainer;
+
  public:
   // Instance time source. Times generated by events, syncbase relationships,
   // and DOM calls behave differently in some circumstances such as when a timed
   // element is reset.
   enum nsSMILInstanceTimeSource {
     // No particularly significant source, e.g. offset time, 'indefinite'
     SOURCE_NONE,
     // Generated by a DOM call such as beginElement
@@ -51,20 +54,20 @@ class nsSMILInstanceTime final {
     SOURCE_SYNCBASE,
     // Generated by an event
     SOURCE_EVENT
   };
 
   explicit nsSMILInstanceTime(const nsSMILTimeValue& aTime,
                               nsSMILInstanceTimeSource aSource = SOURCE_NONE,
                               nsSMILTimeValueSpec* aCreator = nullptr,
-                              nsSMILInterval* aBaseInterval = nullptr);
+                              SMILInterval* aBaseInterval = nullptr);
 
   void Unlink();
-  void HandleChangedInterval(const mozilla::SMILTimeContainer* aSrcContainer,
+  void HandleChangedInterval(const SMILTimeContainer* aSrcContainer,
                              bool aBeginObjectChanged, bool aEndObjectChanged);
   void HandleDeletedInterval();
   void HandleFilteredInterval();
 
   const nsSMILTimeValue& Time() const { return mTime; }
   const nsSMILTimeValueSpec* GetCreator() const { return mCreator; }
 
   bool IsDynamic() const { return !!(mFlags & kDynamic); }
@@ -80,17 +83,17 @@ class nsSMILInstanceTime final {
   void DependentUpdate(const nsSMILTimeValue& aNewTime) {
     MOZ_ASSERT(!IsFixedTime(),
                "Updating an instance time that is not expected to be updated");
     mTime = aNewTime;
   }
 
   bool IsDependent() const { return !!mBaseInterval; }
   bool IsDependentOn(const nsSMILInstanceTime& aOther) const;
-  const nsSMILInterval* GetBaseInterval() const { return mBaseInterval; }
+  const SMILInterval* GetBaseInterval() const { return mBaseInterval; }
   const nsSMILInstanceTime* GetBaseTime() const;
 
   bool SameTimeAndBase(const nsSMILInstanceTime& aOther) const {
     return mTime == aOther.mTime && GetBaseTime() == aOther.GetBaseTime();
   }
 
   // Get and set a serial number which may be used by a containing class to
   // control the sort order of otherwise similar instance times.
@@ -98,17 +101,17 @@ class nsSMILInstanceTime final {
   void SetSerial(uint32_t aIndex) { mSerial = aIndex; }
 
   NS_INLINE_DECL_REFCOUNTING(nsSMILInstanceTime)
 
  private:
   // Private destructor, to discourage deletion outside of Release():
   ~nsSMILInstanceTime();
 
-  void SetBaseInterval(nsSMILInterval* aBaseInterval);
+  void SetBaseInterval(SMILInterval* aBaseInterval);
 
   nsSMILTimeValue mTime;
 
   // Internal flags used to represent the behaviour of different instance times
   enum {
     // Indicates that this instance time was generated by an event or a DOM
     // call. Such instance times require special handling when (i) the owning
     // element is reset, (ii) when they are to be added as a new end instance
@@ -154,13 +157,13 @@ class nsSMILInstanceTime final {
 
   uint32_t mSerial;  // A serial number used by the containing class to
                      // specify the sort order for instance times with the
                      // same mTime.
 
   nsSMILTimeValueSpec* mCreator;  // The nsSMILTimeValueSpec object that created
                                   // us. (currently only needed for syncbase
                                   // instance times.)
-  nsSMILInterval* mBaseInterval;  // Interval from which this time is derived
+  SMILInterval* mBaseInterval;    // Interval from which this time is derived
                                   // (only used for syncbase instance times)
 };
 
 #endif  // NS_SMILINSTANCETIME_H_
--- a/dom/smil/nsSMILTimeValue.h
+++ b/dom/smil/nsSMILTimeValue.h
@@ -18,17 +18,17 @@
  * First a quick overview of the SMIL time data types:
  *
  * nsSMILTime          -- a timestamp in milliseconds.
  * nsSMILTimeValue     -- (this class) a timestamp that can take the additional
  *                        states 'indefinite' and 'unresolved'
  * nsSMILInstanceTime  -- an nsSMILTimeValue used for constructing intervals. It
  *                        contains additional fields to govern reset behavior
  *                        and track timing dependencies (e.g. syncbase timing).
- * nsSMILInterval      -- a pair of nsSMILInstanceTimes that defines a begin and
+ * SMILInterval        -- a pair of nsSMILInstanceTimes that defines a begin and
  *                        an end time for animation.
  * nsSMILTimeValueSpec -- a component of a begin or end attribute, such as the
  *                        '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
  *                        a broker between an SMILTimedElement and its
  *                        nsSMILInstanceTimes by generating new instance times
  *                        and handling changes to existing times.
  *
  * Objects of this class may be in one of three states:
--- a/dom/smil/nsSMILTimeValueSpec.cpp
+++ b/dom/smil/nsSMILTimeValueSpec.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/EventListenerManager.h"
+#include "mozilla/SMILInterval.h"
 #include "mozilla/SMILParserUtils.h"
 #include "mozilla/SMILTimeContainer.h"
 #include "mozilla/SMILTimedElement.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/dom/TimeEvent.h"
 #include "nsSMILTimeValueSpec.h"
-#include "nsSMILInterval.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILInstanceTime.h"
 #include "nsString.h"
 #include <limits>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -103,17 +103,17 @@ void nsSMILTimeValueSpec::ResolveReferen
 }
 
 bool nsSMILTimeValueSpec::IsEventBased() const {
   return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
          mParams.mType == nsSMILTimeValueSpecParams::REPEAT;
 }
 
 void nsSMILTimeValueSpec::HandleNewInterval(
-    nsSMILInterval& aInterval, const SMILTimeContainer* aSrcContainer) {
+    SMILInterval& aInterval, const SMILTimeContainer* aSrcContainer) {
   const nsSMILInstanceTime& baseInstance =
       mParams.mSyncBegin ? *aInterval.Begin() : *aInterval.End();
   nsSMILTimeValue newTime =
       ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
 
   // Apply offset
   if (!ApplyOffset(newTime)) {
     NS_WARNING("New time overflows nsSMILTime, ignoring");
--- a/dom/smil/nsSMILTimeValueSpec.h
+++ b/dom/smil/nsSMILTimeValueSpec.h
@@ -10,19 +10,19 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/IDTracker.h"
 #include "nsSMILTimeValueSpecParams.h"
 #include "nsStringFwd.h"
 #include "nsIDOMEventListener.h"
 
 class nsSMILTimeValue;
 class nsSMILInstanceTime;
-class nsSMILInterval;
 
 namespace mozilla {
+class SMILInterval;
 class SMILTimeContainer;
 class SMILTimedElement;
 namespace dom {
 class Event;
 }  // namespace dom
 
 class EventListenerManager;
 }  // namespace mozilla
@@ -35,30 +35,31 @@ class EventListenerManager;
 // necessary event handling (for event and repeat specifications)
 // and synchronisation (for syncbase specifications).
 //
 // For an overview of how this class is related to other SMIL time classes see
 // the documentation in nsSMILTimeValue.h
 
 class nsSMILTimeValueSpec {
  public:
+  typedef mozilla::SMILInterval SMILInterval;
   typedef mozilla::SMILTimeContainer SMILTimeContainer;
   typedef mozilla::SMILTimedElement SMILTimedElement;
   typedef mozilla::dom::Element Element;
   typedef mozilla::dom::Event Event;
   typedef mozilla::dom::IDTracker IDTracker;
 
   nsSMILTimeValueSpec(SMILTimedElement& aOwner, bool aIsBegin);
   ~nsSMILTimeValueSpec();
 
   nsresult SetSpec(const nsAString& aStringSpec, Element& aContextElement);
   void ResolveReferences(Element& aContextElement);
   bool IsEventBased() const;
 
-  void HandleNewInterval(nsSMILInterval& aInterval,
+  void HandleNewInterval(SMILInterval& aInterval,
                          const SMILTimeContainer* aSrcContainer);
   void HandleTargetElementChange(Element* aNewTarget);
 
   // For created nsSMILInstanceTime objects
   bool DependsOnBegin() const;
   void HandleChangedInstanceTime(const nsSMILInstanceTime& aBaseTime,
                                  const SMILTimeContainer* aSrcContainer,
                                  nsSMILInstanceTime& aInstanceTimeToUpdate,
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4385,23 +4385,23 @@ void WorkerPrivate::GarbageCollectIntern
     // We haven't compiled anything yet. Just bail out.
     return;
   }
 
   if (aShrinking || aCollectChildren) {
     JS::PrepareForFullGC(aCx);
 
     if (aShrinking) {
-      JS::NonIncrementalGC(aCx, GC_SHRINK, JS::gcreason::DOM_WORKER);
+      JS::NonIncrementalGC(aCx, GC_SHRINK, JS::GCReason::DOM_WORKER);
 
       if (!aCollectChildren) {
         LOG(WorkerLog(), ("Worker %p collected idle garbage\n", this));
       }
     } else {
-      JS::NonIncrementalGC(aCx, GC_NORMAL, JS::gcreason::DOM_WORKER);
+      JS::NonIncrementalGC(aCx, GC_NORMAL, JS::GCReason::DOM_WORKER);
       LOG(WorkerLog(), ("Worker %p collected garbage\n", this));
     }
   } else {
     JS_MaybeGC(aCx);
     LOG(WorkerLog(), ("Worker %p collected periodic garbage\n", this));
   }
 
   if (aCollectChildren) {
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -34,17 +34,17 @@ static void MaybeForceDebugGC() {
 
   if (!sEnvVarInitialized) {
     sDebugGCs = !!PR_GetEnv("MOZ_DEBUG_DEAD_CPOWS");
   }
 
   if (sDebugGCs) {
     JSContext* cx = XPCJSContext::Get()->Context();
     PrepareForFullGC(cx);
-    NonIncrementalGC(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
+    NonIncrementalGC(cx, GC_NORMAL, GCReason::COMPONENT_UTILS);
   }
 }
 
 bool WrapperAnswer::fail(AutoJSAPI& jsapi, ReturnStatus* rs) {
   // By default, we set |undefined| unless we can get a more meaningful
   // exception.
   *rs = ReturnStatus(ReturnException(JSVariant(UndefinedVariant())));
 
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -401,41 +401,35 @@ namespace JS {
   D(FULL_GC_TIMER, 49)                     \
   D(SHUTDOWN_CC, 50)                       \
   D(UNUSED2, 51)                           \
   D(USER_INACTIVE, 52)                     \
   D(XPCONNECT_SHUTDOWN, 53)                \
   D(DOCSHELL, 54)                          \
   D(HTML_PARSER, 55)
 
-namespace gcreason {
-
-/* GCReasons will end up looking like JSGC_MAYBEGC */
-enum Reason {
+enum class GCReason {
 #define MAKE_REASON(name, val) name = val,
   GCREASONS(MAKE_REASON)
 #undef MAKE_REASON
       NO_REASON,
   NUM_REASONS,
 
   /*
    * For telemetry, we want to keep a fixed max bucket size over time so we
-   * don't have to switch histograms. 100 is conservative; as of this writing
-   * there are 52. But the cost of extra buckets seems to be low while the
-   * cost of switching histograms is high.
+   * don't have to switch histograms. 100 is conservative; but the cost of extra
+   * buckets seems to be low while the cost of switching histograms is high.
    */
   NUM_TELEMETRY_REASONS = 100
 };
 
 /**
  * Get a statically allocated C string explaining the given GC reason.
  */
-extern JS_PUBLIC_API const char* ExplainReason(JS::gcreason::Reason reason);
-
-} /* namespace gcreason */
+extern JS_PUBLIC_API const char* ExplainGCReason(JS::GCReason reason);
 
 /*
  * Zone GC:
  *
  * SpiderMonkey's GC is capable of performing a collection on an arbitrary
  * subset of the zones in the system. This allows an embedding to minimize
  * collection time by only collecting zones that have run code recently,
  * ignoring the parts of the heap that are unlikely to have changed.
@@ -487,17 +481,17 @@ extern JS_PUBLIC_API void SkipZoneForGC(
  * If the gckind argument is GC_NORMAL, then some objects that are unreachable
  * from the program may still be alive afterwards because of internal
  * references; if GC_SHRINK is passed then caches and other temporary references
  * to objects will be cleared and all unreferenced objects will be removed from
  * the system.
  */
 extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx,
                                            JSGCInvocationKind gckind,
-                                           gcreason::Reason reason);
+                                           GCReason reason);
 
 /*
  * Incremental GC:
  *
  * Incremental GC divides the full mark-and-sweep collection into multiple
  * slices, allowing client JavaScript code to run between each slice. This
  * allows interactive apps to avoid long collection pauses. Incremental GC does
  * not make collection take less time, it merely spreads that time out so that
@@ -520,39 +514,37 @@ extern JS_PUBLIC_API void NonIncremental
  * IncrementalGCSlice() must be called repeatedly until
  * !IsIncrementalGCInProgress(cx).
  *
  * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
  *       shorter than the requested interval.
  */
 extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
                                              JSGCInvocationKind gckind,
-                                             gcreason::Reason reason,
+                                             GCReason reason,
                                              int64_t millis = 0);
 
 /**
  * Perform a slice of an ongoing incremental collection. When this function
  * returns, the collection may not be complete. It must be called repeatedly
  * until !IsIncrementalGCInProgress(cx).
  *
  * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
  *       shorter than the requested interval.
  */
-extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx,
-                                             gcreason::Reason reason,
+extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason,
                                              int64_t millis = 0);
 
 /**
  * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
  * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
  * this is equivalent to NonIncrementalGC. When this function returns,
  * IsIncrementalGCInProgress(cx) will always be false.
  */
-extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx,
-                                              gcreason::Reason reason);
+extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, GCReason reason);
 
 /**
  * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
  * performs whatever work needs to be done to return the collector to its idle
  * state. This may take an arbitrarily long time. When this function returns,
  * IsIncrementalGCInProgress(cx) will always be false.
  */
 extern JS_PUBLIC_API void AbortIncrementalGC(JSContext* cx);
@@ -618,20 +610,20 @@ enum GCProgress {
   GC_SLICE_END,
   GC_CYCLE_END
 };
 
 struct JS_PUBLIC_API GCDescription {
   bool isZone_;
   bool isComplete_;
   JSGCInvocationKind invocationKind_;
-  gcreason::Reason reason_;
+  GCReason reason_;
 
   GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind,
-                gcreason::Reason reason)
+                GCReason reason)
       : isZone_(isZone),
         isComplete_(isComplete),
         invocationKind_(kind),
         reason_(reason) {}
 
   char16_t* formatSliceMessage(JSContext* cx) const;
   char16_t* formatSummaryMessage(JSContext* cx) const;
 
@@ -676,17 +668,17 @@ enum class GCNurseryProgress {
 };
 
 /**
  * A nursery collection callback receives the progress of the nursery collection
  * and the reason for the collection.
  */
 using GCNurseryCollectionCallback = void (*)(JSContext* cx,
                                              GCNurseryProgress progress,
-                                             gcreason::Reason reason);
+                                             GCReason reason);
 
 /**
  * Set the nursery collection callback for the given runtime. When set, it will
  * be called at the start and end of every nursery collection.
  */
 extern JS_PUBLIC_API GCNurseryCollectionCallback SetGCNurseryCollectionCallback(
     JSContext* cx, GCNurseryCollectionCallback callback);
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -423,34 +423,34 @@ static bool GC(JSContext* cx, unsigned a
 
   if (zone) {
     PrepareForDebugGC(cx->runtime());
   } else {
     JS::PrepareForFullGC(cx);
   }
 
   JSGCInvocationKind gckind = shrinking ? GC_SHRINK : GC_NORMAL;
-  JS::NonIncrementalGC(cx, gckind, JS::gcreason::API);
+  JS::NonIncrementalGC(cx, gckind, JS::GCReason::API);
 
   char buf[256] = {'\0'};
 #ifndef JS_MORE_DETERMINISTIC
   SprintfLiteral(buf, "before %zu, after %zu\n", preBytes,
                  cx->runtime()->gc.heapSize.gcBytes());
 #endif
   return ReturnStringCopy(cx, args, buf);
 }
 
 static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.get(0) == BooleanValue(true)) {
     cx->runtime()->gc.storeBuffer().setAboutToOverflow(
-        JS::gcreason::FULL_GENERIC_BUFFER);
-  }
-
-  cx->minorGC(JS::gcreason::API);
+        JS::GCReason::FULL_GENERIC_BUFFER);
+  }
+
+  cx->minorGC(JS::GCReason::API);
   args.rval().setUndefined();
   return true;
 }
 
 #define FOR_EACH_GC_PARAM(_)                                                 \
   _("maxBytes", JSGC_MAX_BYTES, true)                                        \
   _("maxMallocBytes", JSGC_MAX_MALLOC_BYTES, true)                           \
   _("maxNurseryBytes", JSGC_MAX_NURSERY_BYTES, true)                         \
@@ -586,17 +586,17 @@ static bool RelazifyFunctions(JSContext*
   // Relazifying functions on GC is usually only done for compartments that are
   // not active. To aid fuzzing, this testing function allows us to relazify
   // even if the compartment is active.
 
   CallArgs args = CallArgsFromVp(argc, vp);
   SetAllowRelazification(cx, true);
 
   JS::PrepareForFullGC(cx);
-  JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::API);
+  JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
 
   SetAllowRelazification(cx, false);
   args.rval().setUndefined();
   return true;
 }
 
 static bool IsProxy(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
@@ -4181,17 +4181,17 @@ static void majorGC(JSContext* cx, JSGCS
   auto info = static_cast<MajorGC*>(data);
   if (!(info->phases & (1 << status))) {
     return;
   }
 
   if (info->depth > 0) {
     info->depth--;
     JS::PrepareForFullGC(cx);
-    JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
+    JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
     info->depth++;
   }
 }
 
 struct MinorGC {
   int32_t phases;
   bool active;
 };
@@ -4200,17 +4200,17 @@ static void minorGC(JSContext* cx, JSGCS
   auto info = static_cast<MinorGC*>(data);
   if (!(info->phases & (1 << status))) {
     return;
   }
 
   if (info->active) {
     info->active = false;
     if (cx->zone() && !cx->zone()->isAtomsZone()) {
-      cx->runtime()->gc.evictNursery(JS::gcreason::DEBUG_GC);
+      cx->runtime()->gc.evictNursery(JS::GCReason::DEBUG_GC);
     }
     info->active = true;
   }
 }
 
 // Process global, should really be runtime-local. Also, the final one of these
 // is currently leaked, since they are only deleted when changing.
 MajorGC* prevMajorGC = nullptr;
--- a/js/src/fuzz-tests/testBinASTReader.cpp
+++ b/js/src/fuzz-tests/testBinASTReader.cpp
@@ -30,17 +30,17 @@ extern JSContext* gCx;
 
 static int testBinASTReaderInit(int* argc, char*** argv) { return 0; }
 
 static int testBinASTReaderFuzz(const uint8_t* buf, size_t size) {
   using namespace js::frontend;
 
   auto gcGuard = mozilla::MakeScopeExit([&] {
     JS::PrepareForFullGC(gCx);
-    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
+    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
   });
 
   if (!size) return 0;
 
   CompileOptions options(gCx);
   options.setIntroductionType("fuzzing parse").setFileAndLine("<string>", 1);
 
   js::Vector<uint8_t> binSource(gCx);
--- a/js/src/fuzz-tests/testExample.cpp
+++ b/js/src/fuzz-tests/testExample.cpp
@@ -32,17 +32,17 @@ static int testExampleFuzz(const uint8_t
   /* If your code directly or indirectly allocates GC memory, then it makes
      sense to attempt and collect that after every iteration. This should detect
      GC issues as soon as possible (right after your iteration), rather than
      later when your code happens to trigger GC coincidentially. You can of
      course disable this code
      if it is not required in your use case, which will speed up fuzzing. */
   auto gcGuard = mozilla::MakeScopeExit([&] {
     JS::PrepareForFullGC(gCx);
-    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
+    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
   });
 
   /* Add code here that processes the given buffer.
      While doing so, you need to follow these rules:
 
      1. Do not modify or free the buffer. Make a copy if necessary.
      2. This function must always return 0.
      3. Do not crash or abort unless the condition constitutes a bug.
--- a/js/src/fuzz-tests/testStructuredCloneReader.cpp
+++ b/js/src/fuzz-tests/testStructuredCloneReader.cpp
@@ -21,17 +21,17 @@ using namespace js;
 extern JS::PersistentRootedObject gGlobal;
 extern JSContext* gCx;
 
 static int testStructuredCloneReaderInit(int* argc, char*** argv) { return 0; }
 
 static int testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
   auto gcGuard = mozilla::MakeScopeExit([&] {
     JS::PrepareForFullGC(gCx);
-    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
+    JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
   });
 
   if (!size) return 0;
 
   // Make sure to pad the buffer to a multiple of kSegmentAlignment
   const size_t kSegmentAlignment = 8;
   size_t buf_size = JS_ROUNDUP(size, kSegmentAlignment);
 
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -103,17 +103,17 @@ JSObject* GCRuntime::tryNewNurseryObject
 
   JSObject* obj =
       cx->nursery().allocateObject(cx, thingSize, nDynamicSlots, clasp);
   if (obj) {
     return obj;
   }
 
   if (allowGC && !cx->suppressGC) {
-    cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
+    cx->runtime()->gc.minorGC(JS::GCReason::OUT_OF_NURSERY);
 
     // Exceeding gcMaxBytes while tenuring can disable the Nursery.
     if (cx->nursery().isEnabled()) {
       return cx->nursery().allocateObject(cx, thingSize, nDynamicSlots, clasp);
     }
   }
   return nullptr;
 }
@@ -159,17 +159,17 @@ JSString* GCRuntime::tryNewNurseryString
   MOZ_ASSERT(!cx->zone()->isAtomsZone());
 
   Cell* cell = cx->nursery().allocateString(cx->zone(), thingSize, kind);
   if (cell) {
     return static_cast<JSString*>(cell);
   }
 
   if (allowGC && !cx->suppressGC) {
-    cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
+    cx->runtime()->gc.minorGC(JS::GCReason::OUT_OF_NURSERY);
 
     // Exceeding gcMaxBytes while tenuring can disable the Nursery, and
     // other heuristics can disable nursery strings for this zone.
     if (cx->nursery().isEnabled() && cx->zone()->allocNurseryStrings) {
       return static_cast<JSString*>(
           cx->nursery().allocateString(cx->zone(), thingSize, kind));
     }
   }
@@ -271,17 +271,17 @@ template <typename T, AllowGC allowGC>
     t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
 
     if (MOZ_UNLIKELY(!t && allowGC)) {
       if (!cx->helperThread()) {
         // We have no memory available for a new chunk; perform an
         // all-compartments, non-incremental, shrinking GC and wait for
         // sweeping to finish.
         JS::PrepareForFullGC(cx);
-        cx->runtime()->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
+        cx->runtime()->gc.gc(GC_SHRINK, JS::GCReason::LAST_DITCH);
         cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
 
         t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
       }
       if (!t) {
         ReportOutOfMemory(cx);
       }
     }
@@ -346,17 +346,17 @@ bool GCRuntime::gcIfNeededAtAllocation(J
   }
 
   // If we have grown past our GC heap threshold while in the middle of
   // an incremental GC, we're growing faster than we're GCing, so stop
   // the world and do a full, non-incremental GC right now, if possible.
   if (isIncrementalGCInProgress() &&
       cx->zone()->zoneSize.gcBytes() > cx->zone()->threshold.gcTriggerBytes()) {
     PrepareZoneForGC(cx->zone());
-    gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
+    gc(GC_NORMAL, JS::GCReason::INCREMENTAL_TOO_SLOW);
   }
 
   return true;
 }
 
 template <typename T>
 /* static */ void GCRuntime::checkIncrementalZoneState(JSContext* cx, T* t) {
 #ifdef DEBUG
--- a/js/src/gc/ArenaList.h
+++ b/js/src/gc/ArenaList.h
@@ -330,17 +330,17 @@ class ArenaLists {
   void adoptArenas(ArenaLists* fromArenaLists, bool targetZoneIsCollecting);
 
   inline void checkEmptyFreeLists();
   inline bool checkEmptyArenaLists();
   inline void checkEmptyFreeList(AllocKind kind);
 
   bool checkEmptyArenaList(AllocKind kind);
 
-  bool relocateArenas(Arena*& relocatedListOut, JS::gcreason::Reason reason,
+  bool relocateArenas(Arena*& relocatedListOut, JS::GCReason reason,
                       js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
 
   void queueForegroundObjectsForSweep(FreeOp* fop);
   void queueForegroundThingsForSweep();
 
   void releaseForegroundSweptEmptyArenas();
 
   bool foregroundFinalize(FreeOp* fop, AllocKind thingKind,
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -910,17 +910,17 @@ GCRuntime::GCRuntime(JSRuntime* rt)
       verifyPreData(nullptr),
       chunkAllocationSinceLastGC(false),
       lastGCTime(ReallyNow()),
       mode(TuningDefaults::Mode),
       numActiveZoneIters(0),
       cleanUpEverything(false),
       grayBufferState(GCRuntime::GrayBufferState::Unused),
       grayBitsValid(false),
-      majorGCTriggerReason(JS::gcreason::NO_REASON),
+      majorGCTriggerReason(JS::GCReason::NO_REASON),
       fullGCForAtomsRequested_(false),
       minorGCNumber(0),
       majorGCNumber(0),
       number(0),
       isFull(false),
       incrementalState(gc::State::NotActive),
       initialState(gc::State::NotActive),
 #ifdef JS_GC_ZEAL
@@ -1048,22 +1048,22 @@ void GCRuntime::setZeal(uint8_t zeal, ui
   MOZ_ASSERT(zeal <= unsigned(ZealMode::Limit));
 
   if (verifyPreData) {
     VerifyBarriers(rt, PreBarrierVerifier);
   }
 
   if (zeal == 0) {
     if (hasZealMode(ZealMode::GenerationalGC)) {
-      evictNursery(JS::gcreason::DEBUG_GC);
+      evictNursery(JS::GCReason::DEBUG_GC);
       nursery().leaveZealMode();
     }
 
     if (isIncrementalGCInProgress()) {
-      finishGC(JS::gcreason::DEBUG_GC);
+      finishGC(JS::GCReason::DEBUG_GC);
     }
   }
 
   ZealMode zealMode = ZealMode(zeal);
   if (zealMode == ZealMode::GenerationalGC) {
     nursery().enterZealMode();
   }
 
@@ -1093,25 +1093,25 @@ void GCRuntime::unsetZeal(uint8_t zeal) 
     return;
   }
 
   if (verifyPreData) {
     VerifyBarriers(rt, PreBarrierVerifier);
   }
 
   if (zealMode == ZealMode::GenerationalGC) {
-    evictNursery(JS::gcreason::DEBUG_GC);
+    evictNursery(JS::GCReason::DEBUG_GC);
     nursery().leaveZealMode();
   }
 
   clearZealMode(zealMode);
 
   if (zealModeBits == 0) {
     if (isIncrementalGCInProgress()) {
-      finishGC(JS::gcreason::DEBUG_GC);
+      finishGC(JS::GCReason::DEBUG_GC);
     }
 
     zealFrequency = 0;
     nextScheduled = 0;
   }
 }
 
 void GCRuntime::setNextScheduled(uint32_t count) { nextScheduled = count; }
@@ -2070,18 +2070,18 @@ bool GCRuntime::shouldCompact() {
   // responding to memory pressure.
 
   static const auto oneSecond = TimeDuration::FromSeconds(1);
 
   if (invocationKind != GC_SHRINK || !isCompactingGCEnabled()) {
     return false;
   }
 
-  if (initialReason == JS::gcreason::USER_INACTIVE ||
-      initialReason == JS::gcreason::MEM_PRESSURE) {
+  if (initialReason == JS::GCReason::USER_INACTIVE ||
+      initialReason == JS::GCReason::MEM_PRESSURE) {
     return true;
   }
 
   const auto& lastAnimationTime = rt->lastAnimationTime.ref();
   return !isIncremental || lastAnimationTime.IsNull() ||
          lastAnimationTime + oneSecond < TimeStamp::Now();
 }
 
@@ -2117,18 +2117,18 @@ Arena* ArenaList::removeRemainingArenas(
   }
 #endif
   Arena* remainingArenas = *arenap;
   *arenap = nullptr;
   check();
   return remainingArenas;
 }
 
-static bool ShouldRelocateAllArenas(JS::gcreason::Reason reason) {
-  return reason == JS::gcreason::DEBUG_GC;
+static bool ShouldRelocateAllArenas(JS::GCReason reason) {
+  return reason == JS::GCReason::DEBUG_GC;
 }
 
 /*
  * Choose which arenas to relocate all cells from. Return an arena cursor that
  * can be passed to removeRemainingArenas().
  */
 Arena** ArenaList::pickArenasToRelocate(size_t& arenaTotalOut,
                                         size_t& relocTotalOut) {
@@ -2292,22 +2292,22 @@ static void RelocateArena(Arena* arena, 
 }
 
 static inline bool CanProtectArenas() {
   // On some systems the page size is larger than the size of an arena so we
   // can't change the mapping permissions per arena.
   return SystemPageSize() <= ArenaSize;
 }
 
-static inline bool ShouldProtectRelocatedArenas(JS::gcreason::Reason reason) {
+static inline bool ShouldProtectRelocatedArenas(JS::GCReason reason) {
   // For zeal mode collections we don't release the relocated arenas
   // immediately. Instead we protect them and keep them around until the next
   // collection so we can catch any stray accesses to them.
 #ifdef DEBUG
-  return reason == JS::gcreason::DEBUG_GC && CanProtectArenas();
+  return reason == JS::GCReason::DEBUG_GC && CanProtectArenas();
 #else
   return false;
 #endif
 }
 
 /*
  * Relocate all arenas identified by pickArenasToRelocate: for each arena,
  * relocate each cell within it, then add it to a list of relocated arenas.
@@ -2331,17 +2331,17 @@ Arena* ArenaList::relocateArenas(Arena* 
   return relocated;
 }
 
 // Skip compacting zones unless we can free a certain proportion of their GC
 // heap memory.
 static const float MIN_ZONE_RECLAIM_PERCENT = 2.0;
 
 static bool ShouldRelocateZone(size_t arenaCount, size_t relocCount,
-                               JS::gcreason::Reason reason) {
+                               JS::GCReason reason) {
   if (relocCount == 0) {
     return false;
   }
 
   if (IsOOMReason(reason)) {
     return true;
   }
 
@@ -2353,18 +2353,17 @@ static AllocKinds CompactingAllocKinds()
   for (AllocKind kind : AllAllocKinds()) {
     if (IsCompactingKind(kind)) {
       result += kind;
     }
   }
   return result;
 }
 
-bool ArenaLists::relocateArenas(Arena*& relocatedListOut,
-                                JS::gcreason::Reason reason,
+bool ArenaLists::relocateArenas(Arena*& relocatedListOut, JS::GCReason reason,
                                 SliceBudget& sliceBudget,
                                 gcstats::Statistics& stats) {
   // This is only called from the main thread while we are doing a GC, so
   // there is no need to lock.
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
   MOZ_ASSERT(runtime()->gc.isHeapCompacting());
   MOZ_ASSERT(!runtime()->gc.isBackgroundSweeping());
 
@@ -2406,17 +2405,17 @@ bool ArenaLists::relocateArenas(Arena*& 
             al.relocateArenas(arenas, relocatedListOut, sliceBudget, stats);
       }
     }
   }
 
   return true;
 }
 
-bool GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason,
+bool GCRuntime::relocateArenas(Zone* zone, JS::GCReason reason,
                                Arena*& relocatedListOut,
                                SliceBudget& sliceBudget) {
   gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_MOVE);
 
   MOZ_ASSERT(!zone->isPreservingCode());
   MOZ_ASSERT(CanRelocateZone(zone));
 
   js::CancelOffThreadIonCompile(rt, JS::Zone::Compact);
@@ -3185,28 +3184,28 @@ bool SliceBudget::checkOverBudget() {
 
   bool over = ReallyNow() >= deadline;
   if (!over) {
     counter = CounterReset;
   }
   return over;
 }
 
-void GCRuntime::requestMajorGC(JS::gcreason::Reason reason) {
+void GCRuntime::requestMajorGC(JS::GCReason reason) {
   MOZ_ASSERT(!CurrentThreadIsPerformingGC());
 
   if (majorGCRequested()) {
     return;
   }
 
   majorGCTriggerReason = reason;
   rt->mainContextFromOwnThread()->requestInterrupt(InterruptReason::GC);
 }
 
-void Nursery::requestMinorGC(JS::gcreason::Reason reason) const {
+void Nursery::requestMinorGC(JS::GCReason reason) const {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
   MOZ_ASSERT(!CurrentThreadIsPerformingGC());
 
   if (minorGCRequested()) {
     return;
   }
 
   minorGCTriggerReason_ = reason;
@@ -3217,42 +3216,42 @@ void Nursery::requestMinorGC(JS::gcreaso
 // replaying. GCs must occur at the same points when replaying as they did
 // while recording, so any trigger reasons whose behavior is non-deterministic
 // between recording and replaying are excluded here.
 //
 // Non-deterministic behaviors here are very narrow: the amount of malloc'ed
 // memory or memory used by GC things may vary between recording or replaying,
 // but other behaviors that would normally be non-deterministic (timers and so
 // forth) are captured in the recording and replayed exactly.
-static bool RecordReplayCheckCanGC(JS::gcreason::Reason reason) {
+static bool RecordReplayCheckCanGC(JS::GCReason reason) {
   if (!mozilla::recordreplay::IsRecordingOrReplaying()) {
     return true;
   }
 
   switch (reason) {
-    case JS::gcreason::EAGER_ALLOC_TRIGGER:
-    case JS::gcreason::LAST_DITCH:
-    case JS::gcreason::TOO_MUCH_MALLOC:
-    case JS::gcreason::ALLOC_TRIGGER:
-    case JS::gcreason::DELAYED_ATOMS_GC:
-    case JS::gcreason::TOO_MUCH_WASM_MEMORY:
+    case JS::GCReason::EAGER_ALLOC_TRIGGER:
+    case JS::GCReason::LAST_DITCH:
+    case JS::GCReason::TOO_MUCH_MALLOC:
+    case JS::GCReason::ALLOC_TRIGGER:
+    case JS::GCReason::DELAYED_ATOMS_GC:
+    case JS::GCReason::TOO_MUCH_WASM_MEMORY:
       return false;
 
     default:
       break;
   }
 
   // If the above filter misses a non-deterministically triggered GC, this
   // assertion will fail.
   mozilla::recordreplay::RecordReplayAssert("RecordReplayCheckCanGC %d",
                                             (int)reason);
   return true;
 }
 
-bool GCRuntime::triggerGC(JS::gcreason::Reason reason) {
+bool GCRuntime::triggerGC(JS::GCReason reason) {
   /*
    * Don't trigger GCs if this is being called off the main thread from
    * onTooMuchMalloc().
    */
   if (!CurrentThreadCanAccessRuntime(rt)) {
     return false;
   }
 
@@ -3281,17 +3280,17 @@ void GCRuntime::maybeAllocTriggerZoneGC(
   MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
 
   size_t usedBytes = zone->zoneSize.gcBytes();
   size_t thresholdBytes = zone->threshold.gcTriggerBytes();
 
   if (usedBytes >= thresholdBytes) {
     // The threshold has been surpassed, immediately trigger a GC, which
     // will be done non-incrementally.
-    triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
+    triggerZoneGC(zone, JS::GCReason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
     return;
   }
 
   bool wouldInterruptCollection =
       isIncrementalGCInProgress() && !zone->isCollecting();
   float zoneGCThresholdFactor =
       wouldInterruptCollection ? tunables.allocThresholdFactorAvoidInterrupt()
                                : tunables.allocThresholdFactor();
@@ -3306,29 +3305,29 @@ void GCRuntime::maybeAllocTriggerZoneGC(
       zone->gcDelayBytes -= ArenaSize;
     }
 
     if (!zone->gcDelayBytes) {
       // Start or continue an in progress incremental GC. We do this
       // to try to avoid performing non-incremental GCs on zones
       // which allocate a lot of data, even when incremental slices
       // can't be triggered via scheduling in the event loop.
-      triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes,
+      triggerZoneGC(zone, JS::GCReason::ALLOC_TRIGGER, usedBytes,
                     igcThresholdBytes);
 
       // Delay the next slice until a certain amount of allocation
       // has been performed.
       zone->gcDelayBytes = tunables.zoneAllocDelayBytes();
       return;
     }
   }
 }
 
-bool GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason,
-                              size_t used, size_t threshold) {
+bool GCRuntime::triggerZoneGC(Zone* zone, JS::GCReason reason, size_t used,
+                              size_t threshold) {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
   /* GC is already running. */
   if (JS::RuntimeHeapIsBusy()) {
     return false;
   }
 
   // GCs can only be triggered in certain ways when recording/replaying.
@@ -3362,43 +3361,43 @@ bool GCRuntime::triggerZoneGC(Zone* zone
 }
 
 void GCRuntime::maybeGC(Zone* zone) {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
 #ifdef JS_GC_ZEAL
   if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
     JS::PrepareForFullGC(rt->mainContextFromOwnThread());
-    gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
+    gc(GC_NORMAL, JS::GCReason::DEBUG_GC);
     return;
   }
 #endif
 
   if (gcIfRequested()) {
     return;
   }
 
   float threshold = zone->threshold.eagerAllocTrigger(
       schedulingState.inHighFrequencyGCMode());
   float usedBytes = zone->zoneSize.gcBytes();
   if (usedBytes > 1024 * 1024 && usedBytes >= threshold &&
       !isIncrementalGCInProgress() && !isBackgroundSweeping()) {
     stats().recordTrigger(usedBytes, threshold);
     PrepareZoneForGC(zone);
-    startGC(GC_NORMAL, JS::gcreason::EAGER_ALLOC_TRIGGER);
+    startGC(GC_NORMAL, JS::GCReason::EAGER_ALLOC_TRIGGER);
   }
 }
 
 void GCRuntime::triggerFullGCForAtoms(JSContext* cx) {
   MOZ_ASSERT(fullGCForAtomsRequested_);
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
   MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
   MOZ_ASSERT(cx->canCollectAtoms());
   fullGCForAtomsRequested_ = false;
-  MOZ_RELEASE_ASSERT(triggerGC(JS::gcreason::DELAYED_ATOMS_GC));
+  MOZ_RELEASE_ASSERT(triggerGC(JS::GCReason::DELAYED_ATOMS_GC));
 }
 
 // Do all possible decommit immediately from the current thread without
 // releasing the GC lock or allocating any memory.
 void GCRuntime::decommitAllWithoutUnlocking(const AutoLockGC& lock) {
   MOZ_ASSERT(emptyChunks(lock).count() == 0);
   for (ChunkPool::Iter chunk(availableChunks(lock)); !chunk.done();
        chunk.next()) {
@@ -3957,17 +3956,17 @@ void GCRuntime::purgeRuntime() {
   // memory when they are next idle.
   if (!rt->parentRuntime) {
     HelperThreadState().triggerFreeUnusedMemory();
   }
 }
 
 bool GCRuntime::shouldPreserveJITCode(Realm* realm,
                                       const TimeStamp& currentTime,
-                                      JS::gcreason::Reason reason,
+                                      JS::GCReason reason,
                                       bool canAllocateMoreCode) {
   static const auto oneSecond = TimeDuration::FromSeconds(1);
 
   if (cleanUpEverything) {
     return false;
   }
   if (!canAllocateMoreCode) {
     return false;
@@ -3981,17 +3980,17 @@ bool GCRuntime::shouldPreserveJITCode(Re
   }
 
   const auto& lastAnimationTime = realm->lastAnimationTime.ref();
   if (!lastAnimationTime.IsNull() &&
       lastAnimationTime + oneSecond >= currentTime) {
     return true;
   }
 
-  if (reason == JS::gcreason::DEBUG_GC) {
+  if (reason == JS::GCReason::DEBUG_GC) {
     return true;
   }
 
   return false;
 }
 
 #ifdef DEBUG
 class CompartmentCheckTracer : public JS::CallbackTracer {
@@ -4102,20 +4101,20 @@ static void RelazifyFunctions(Zone* zone
   for (auto i = zone->cellIter<JSObject>(kind, empty); !i.done(); i.next()) {
     JSFunction* fun = &i->as<JSFunction>();
     if (fun->hasScript()) {
       fun->maybeRelazify(rt);
     }
   }
 }
 
-static bool ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) {
+static bool ShouldCollectZone(Zone* zone, JS::GCReason reason) {
   // If we are repeating a GC because we noticed dead compartments haven't
   // been collected, then only collect zones containing those compartments.
-  if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
+  if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
       if (comp->gcState.scheduledForDestruction) {
         return true;
       }
     }
 
     return false;
   }
@@ -4142,17 +4141,17 @@ static bool ShouldCollectZone(Zone* zone
   // set of atoms in use by the other collected zones at the end of the GC.
   if (zone->isAtomsZone()) {
     return TlsContext.get()->canCollectAtoms();
   }
 
   return zone->canCollect();
 }
 
-bool GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason,
+bool GCRuntime::prepareZonesForCollection(JS::GCReason reason,
                                           bool* isFullOut) {
 #ifdef DEBUG
   /* Assert that zone state is as we expect */
   for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
     MOZ_ASSERT(!zone->isCollecting());
     MOZ_ASSERT_IF(!zone->isAtomsZone(), !zone->compartments().empty());
     for (auto i : AllAllocKinds()) {
       MOZ_ASSERT(!zone->arenas.arenaListsToSweep(i));
@@ -4206,17 +4205,17 @@ bool GCRuntime::prepareZonesForCollectio
       activation->compartment()->zone()->setPreservingCode(true);
     }
   }
 
   /*
    * Check that we do collect the atoms zone if we triggered a GC for that
    * purpose.
    */
-  MOZ_ASSERT_IF(reason == JS::gcreason::DELAYED_ATOMS_GC,
+  MOZ_ASSERT_IF(reason == JS::GCReason::DELAYED_ATOMS_GC,
                 atomsZone->isGCMarking());
 
   /* Check that at least one zone is scheduled for collection. */
   return any;
 }
 
 static void DiscardJITCodeForGC(JSRuntime* rt) {
   js::CancelOffThreadIonCompile(rt, JS::Zone::MarkBlackOnly);
@@ -4264,18 +4263,17 @@ static void UnmarkCollectedZones(GCParal
     WeakMapBase::unmarkZone(zone);
   }
 }
 
 static void BufferGrayRoots(GCParallelTask* task) {
   task->runtime()->gc.bufferGrayRoots();
 }
 
-bool GCRuntime::beginMarkPhase(JS::gcreason::Reason reason,
-                               AutoGCSession& session) {
+bool GCRuntime::beginMarkPhase(JS::GCReason reason, AutoGCSession& session) {
 #ifdef DEBUG
   if (fullCompartmentChecks) {
     checkForCompartmentMismatches();
   }
 #endif
 
   if (!prepareZonesForCollection(reason, &isFull.ref())) {
     return false;
@@ -4926,17 +4924,17 @@ bool GCRuntime::findInterZoneEdges() {
     if (!WeakMapBase::findInterZoneEdges(zone)) {
       return false;
     }
   }
 
   return true;
 }
 
-void GCRuntime::groupZonesForSweeping(JS::gcreason::Reason reason) {
+void GCRuntime::groupZonesForSweeping(JS::GCReason reason) {
 #ifdef DEBUG
   for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
     MOZ_ASSERT(zone->gcSweepGroupEdges().empty());
   }
 #endif
 
   JSContext* cx = rt->mainContextFromOwnThread();
   Zone* maybeAtomsZone = atomsZone->wasGCStarted() ? atomsZone.ref() : nullptr;
@@ -5804,18 +5802,17 @@ IncrementalProgress GCRuntime::endSweepi
     zones.append(atomsZone);
   }
 
   queueZonesAndStartBackgroundSweep(zones);
 
   return Finished;
 }
 
-void GCRuntime::beginSweepPhase(JS::gcreason::Reason reason,
-                                AutoGCSession& session) {
+void GCRuntime::beginSweepPhase(JS::GCReason reason, AutoGCSession& session) {
   /*
    * Sweep phase.
    *
    * Finalize as we sweep, outside of lock but with RuntimeHeapIsBusy()
    * true so that any attempt to allocate a GC-thing from a finalizer will
    * fail, rather than nest badly and leave the unmarked newborn to be swept.
    */
 
@@ -6650,17 +6647,17 @@ void GCRuntime::beginCompactPhase() {
       zonesToMaybeCompact.ref().append(zone);
     }
   }
 
   MOZ_ASSERT(!relocatedArenasToRelease);
   startedCompacting = true;
 }
 
-IncrementalProgress GCRuntime::compactPhase(JS::gcreason::Reason reason,
+IncrementalProgress GCRuntime::compactPhase(JS::GCReason reason,
                                             SliceBudget& sliceBudget,
                                             AutoGCSession& session) {
   assertBackgroundSweepingFinished();
   MOZ_ASSERT(startedCompacting);
 
   gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT);
 
   // TODO: JSScripts can move. If the sampler interrupts the GC in the
@@ -6913,52 +6910,51 @@ void GCRuntime::pushZealSelectedObjects(
   /* Push selected objects onto the mark stack and clear the list. */
   for (JSObject** obj = selectedForMarking.ref().begin();
        obj != selectedForMarking.ref().end(); obj++) {
     TraceManuallyBarrieredEdge(&marker, obj, "selected obj");
   }
 #endif
 }
 
-static bool IsShutdownGC(JS::gcreason::Reason reason) {
-  return reason == JS::gcreason::SHUTDOWN_CC ||
-         reason == JS::gcreason::DESTROY_RUNTIME;
-}
-
-static bool ShouldCleanUpEverything(JS::gcreason::Reason reason,
+static bool IsShutdownGC(JS::GCReason reason) {
+  return reason == JS::GCReason::SHUTDOWN_CC ||
+         reason == JS::GCReason::DESTROY_RUNTIME;
+}
+
+static bool ShouldCleanUpEverything(JS::GCReason reason,
                                     JSGCInvocationKind gckind) {
   // During shutdown, we must clean everything up, for the sake of leak
   // detection. When a runtime has no contexts, or we're doing a GC before a
   // shutdown CC, those are strong indications that we're shutting down.
   return IsShutdownGC(reason) || gckind == GC_SHRINK;
 }
 
-static bool ShouldSweepOnBackgroundThread(JS::gcreason::Reason reason) {
-  return reason != JS::gcreason::DESTROY_RUNTIME && !gcTracer.traceEnabled() &&
+static bool ShouldSweepOnBackgroundThread(JS::GCReason reason) {
+  return reason != JS::GCReason::DESTROY_RUNTIME && !gcTracer.traceEnabled() &&
          CanUseExtraThreads();
 }
 
-void GCRuntime::incrementalSlice(SliceBudget& budget,
-                                 JS::gcreason::Reason reason,
+void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason,
                                  AutoGCSession& session) {
   AutoDisableBarriers disableBarriers(rt);
 
-  bool destroyingRuntime = (reason == JS::gcreason::DESTROY_RUNTIME);
+  bool destroyingRuntime = (reason == JS::GCReason::DESTROY_RUNTIME);
 
   number++;
 
   initialState = incrementalState;
 
 #ifdef JS_GC_ZEAL
   /*
    * Do the incremental collection type specified by zeal mode if the
    * collection was triggered by runDebugGC() and incremental GC has not been
    * cancelled by resetIncrementalGC().
    */
-  useZeal = reason == JS::gcreason::DEBUG_GC && !budget.isUnlimited();
+  useZeal = reason == JS::GCReason::DEBUG_GC && !budget.isUnlimited();
 #else
   bool useZeal = false;
 #endif
 
 #ifdef DEBUG
   {
     char budgetBuffer[32];
     budget.describe(budgetBuffer, 32);
@@ -7177,65 +7173,64 @@ gc::AbortReason gc::IsIncrementalGCUnsaf
 
   if (!rt->gc.isIncrementalGCAllowed()) {
     return gc::AbortReason::IncrementalDisabled;
   }
 
   return gc::AbortReason::None;
 }
 
-static inline void CheckZoneIsScheduled(Zone* zone, JS::gcreason::Reason reason,
+static inline void CheckZoneIsScheduled(Zone* zone, JS::GCReason reason,
                                         const char* trigger) {
 #ifdef DEBUG
   if (zone->isGCScheduled()) {
     return;
   }
 
   fprintf(stderr,
           "CheckZoneIsScheduled: Zone %p not scheduled as expected in %s GC "
           "for %s trigger\n",
-          zone, JS::gcreason::ExplainReason(reason), trigger);
+          zone, JS::ExplainGCReason(reason), trigger);
   JSRuntime* rt = zone->runtimeFromMainThread();
   for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
     fprintf(stderr, "  Zone %p:%s%s\n", zone.get(),
             zone->isAtomsZone() ? " atoms" : "",
             zone->isGCScheduled() ? " scheduled" : "");
   }
   fflush(stderr);
   MOZ_CRASH("Zone not scheduled");
 #endif
 }
 
 GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
-    bool nonincrementalByAPI, JS::gcreason::Reason reason,
-    SliceBudget& budget) {
+    bool nonincrementalByAPI, JS::GCReason reason, SliceBudget& budget) {
   if (nonincrementalByAPI) {
     stats().nonincremental(gc::AbortReason::NonIncrementalRequested);
     budget.makeUnlimited();
 
     // Reset any in progress incremental GC if this was triggered via the
     // API. This isn't required for correctness, but sometimes during tests
     // the caller expects this GC to collect certain objects, and we need
     // to make sure to collect everything possible.
-    if (reason != JS::gcreason::ALLOC_TRIGGER) {
+    if (reason != JS::GCReason::ALLOC_TRIGGER) {
       return resetIncrementalGC(gc::AbortReason::NonIncrementalRequested);
     }
 
     return IncrementalResult::Ok;
   }
 
-  if (reason == JS::gcreason::ABORT_GC) {
+  if (reason == JS::GCReason::ABORT_GC) {
     budget.makeUnlimited();
     stats().nonincremental(gc::AbortReason::AbortRequested);
     return resetIncrementalGC(gc::AbortReason::AbortRequested);
   }
 
   AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
   if (unsafeReason == AbortReason::None) {
-    if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
+    if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
       unsafeReason = gc::AbortReason::CompartmentRevived;
     } else if (mode != JSGC_MODE_INCREMENTAL) {
       unsafeReason = gc::AbortReason::ModeChange;
     }
   }
 
   if (unsafeReason != AbortReason::None) {
     budget.makeUnlimited();
@@ -7376,42 +7371,42 @@ void GCRuntime::maybeCallGCCallback(JSGC
 }
 
 /*
  * We disable inlining to ensure that the bottom of the stack with possible GC
  * roots recorded in MarkRuntime excludes any pointers we use during the marking
  * implementation.
  */
 MOZ_NEVER_INLINE GCRuntime::IncrementalResult GCRuntime::gcCycle(
-    bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) {
+    bool nonincrementalByAPI, SliceBudget budget, JS::GCReason reason) {
   // Assert if this is a GC unsafe region.
   rt->mainContextFromOwnThread()->verifyIsSafeToGC();
 
   // It's ok if threads other than the main thread have suppressGC set, as
   // they are operating on zones which will not be collected from here.
   MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
 
   // Note that GC callbacks are allowed to re-enter GC.
   AutoCallGCCallbacks callCallbacks(*this);
 
   gcstats::AutoGCSlice agc(stats(), scanZonesBeforeGC(), invocationKind, budget,
                            reason);
 
   auto result = budgetIncrementalGC(nonincrementalByAPI, reason, budget);
   if (result == IncrementalResult::ResetIncremental) {
-    reason = JS::gcreason::RESET;
+    reason = JS::GCReason::RESET;
   }
 
   if (shouldCollectNurseryForSlice(nonincrementalByAPI, budget)) {
     minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY_FOR_MAJOR_GC);
   }
 
   AutoGCSession session(rt, JS::HeapState::MajorCollecting);
 
-  majorGCTriggerReason = JS::gcreason::NO_REASON;
+  majorGCTriggerReason = JS::GCReason::NO_REASON;
 
   {
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
 
     // Background finalization and decommit are finished by defininition
     // before we can start a new GC session.
     if (!isIncrementalGCInProgress()) {
       assertBackgroundSweepingFinished();
@@ -7474,28 +7469,28 @@ bool GCRuntime::shouldCollectNurseryForS
     case State::MarkRoots:
       MOZ_CRASH("Unexpected GC state");
   }
 
   return false;
 }
 
 #ifdef JS_GC_ZEAL
-static bool IsDeterministicGCReason(JS::gcreason::Reason reason) {
+static bool IsDeterministicGCReason(JS::GCReason reason) {
   switch (reason) {
-    case JS::gcreason::API:
-    case JS::gcreason::DESTROY_RUNTIME:
-    case JS::gcreason::LAST_DITCH:
-    case JS::gcreason::TOO_MUCH_MALLOC:
-    case JS::gcreason::TOO_MUCH_WASM_MEMORY:
-    case JS::gcreason::ALLOC_TRIGGER:
-    case JS::gcreason::DEBUG_GC:
-    case JS::gcreason::CC_FORCED:
-    case JS::gcreason::SHUTDOWN_CC:
-    case JS::gcreason::ABORT_GC:
+    case JS::GCReason::API:
+    case JS::GCReason::DESTROY_RUNTIME:
+    case JS::GCReason::LAST_DITCH:
+    case JS::GCReason::TOO_MUCH_MALLOC:
+    case JS::GCReason::TOO_MUCH_WASM_MEMORY:
+    case JS::GCReason::ALLOC_TRIGGER:
+    case JS::GCReason::DEBUG_GC:
+    case JS::GCReason::CC_FORCED:
+    case JS::GCReason::SHUTDOWN_CC:
+    case JS::GCReason::ABORT_GC:
       return true;
 
     default:
       return false;
   }
 }
 #endif
 
@@ -7542,17 +7537,17 @@ void GCRuntime::maybeDoCycleCollection()
 
 void GCRuntime::checkCanCallAPI() {
   MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
   /* If we attempt to invoke the GC while we are running in the GC, assert. */
   MOZ_RELEASE_ASSERT(!JS::RuntimeHeapIsBusy());
 }
 
-bool GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) {
+bool GCRuntime::checkIfGCAllowedInCurrentState(JS::GCReason reason) {
   if (rt->mainContextFromOwnThread()->suppressGC) {
     return false;
   }
 
   // Only allow shutdown GCs when we're destroying the runtime. This keeps
   // the GC callback from triggering a nested GC and resetting global state.
   if (rt->isBeingDestroyed() && !IsShutdownGC(reason)) {
     return false;
@@ -7562,35 +7557,35 @@ bool GCRuntime::checkIfGCAllowedInCurren
   if (deterministicOnly && !IsDeterministicGCReason(reason)) {
     return false;
   }
 #endif
 
   return true;
 }
 
-bool GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) {
-  MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
+bool GCRuntime::shouldRepeatForDeadZone(JS::GCReason reason) {
+  MOZ_ASSERT_IF(reason == JS::GCReason::COMPARTMENT_REVIVED, !isIncremental);
   MOZ_ASSERT(!isIncrementalGCInProgress());
 
   if (!isIncremental) {
     return false;
   }
 
   for (CompartmentsIter c(rt); !c.done(); c.next()) {
     if (c->gcState.scheduledForDestruction) {
       return true;
     }
   }
 
   return false;
 }
 
 void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
-                        JS::gcreason::Reason reason) {
+                        JS::GCReason reason) {
   // Checks run for each request, even if we do not actually GC.
   checkCanCallAPI();
 
   // Check if we are allowed to GC at this time before proceeding.
   if (!checkIfGCAllowedInCurrentState(reason)) {
     return;
   }
 
@@ -7602,17 +7597,17 @@ void GCRuntime::collect(bool nonincremen
   AutoEnqueuePendingParseTasksAfterGC aept(*this);
   AutoScheduleZonesForGC asz(this);
 
   bool repeat;
   do {
     IncrementalResult cycleResult =
         gcCycle(nonincrementalByAPI, budget, reason);
 
-    if (reason == JS::gcreason::ABORT_GC) {
+    if (reason == JS::GCReason::ABORT_GC) {
       MOZ_ASSERT(!isIncrementalGCInProgress());
       stats().writeLogMessage("GC aborted by request");
       break;
     }
 
     /*
      * Sometimes when we finish a GC we need to immediately start a new one.
      * This happens in the following cases:
@@ -7624,34 +7619,34 @@ void GCRuntime::collect(bool nonincremen
     repeat = false;
     if (!isIncrementalGCInProgress()) {
       if (cycleResult == ResetIncremental) {
         repeat = true;
       } else if (rootsRemoved && IsShutdownGC(reason)) {
         /* Need to re-schedule all zones for GC. */
         JS::PrepareForFullGC(rt->mainContextFromOwnThread());
         repeat = true;
-        reason = JS::gcreason::ROOTS_REMOVED;
+        reason = JS::GCReason::ROOTS_REMOVED;
       } else if (shouldRepeatForDeadZone(reason)) {
         repeat = true;
-        reason = JS::gcreason::COMPARTMENT_REVIVED;
+        reason = JS::GCReason::COMPARTMENT_REVIVED;
       }
     }
   } while (repeat);
 
 #ifdef DEBUG
   if (!isIncrementalGCInProgress()) {
     for (ZonesIter zone(rt, WithAtoms); zone.done(); zone.next()) {
       MOZ_ASSERT(!zone->gcMallocCounter.triggered());
       MOZ_ASSERT(!zone->jitCodeCounter.triggered());
     }
   }
 #endif
 
-  if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
+  if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
     maybeDoCycleCollection();
   }
 
 #ifdef JS_GC_ZEAL
   if (hasZealMode(ZealMode::CheckHeapAfterGC)) {
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::TRACE_HEAP);
     CheckHeapAfterGC(rt);
   }
@@ -7664,59 +7659,58 @@ void GCRuntime::collect(bool nonincremen
 
 js::AutoEnqueuePendingParseTasksAfterGC::
     ~AutoEnqueuePendingParseTasksAfterGC() {
   if (!OffThreadParsingMustWaitForGC(gc_.rt)) {
     EnqueuePendingParseTasksAfterGC(gc_.rt);
   }
 }
 
-SliceBudget GCRuntime::defaultBudget(JS::gcreason::Reason reason,
-                                     int64_t millis) {
+SliceBudget GCRuntime::defaultBudget(JS::GCReason reason, int64_t millis) {
   if (millis == 0) {
-    if (reason == JS::gcreason::ALLOC_TRIGGER) {
+    if (reason == JS::GCReason::ALLOC_TRIGGER) {
       millis = defaultSliceBudget();
     } else if (schedulingState.inHighFrequencyGCMode() &&
                tunables.isDynamicMarkSliceEnabled()) {
       millis = defaultSliceBudget() * IGC_MARK_SLICE_MULTIPLIER;
     } else {
       millis = defaultSliceBudget();
     }
   }
 
   return SliceBudget(TimeBudget(millis));
 }
 
-void GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason) {
+void GCRuntime::gc(JSGCInvocationKind gckind, JS::GCReason reason) {
   // Watch out for calls to gc() that don't go through triggerGC().
   if (!RecordReplayCheckCanGC(reason)) {
     return;
   }
 
   invocationKind = gckind;
   collect(true, SliceBudget::unlimited(), reason);
 }
 
-void GCRuntime::startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason,
+void GCRuntime::startGC(JSGCInvocationKind gckind, JS::GCReason reason,
                         int64_t millis) {
   MOZ_ASSERT(!isIncrementalGCInProgress());
   if (!JS::IsIncrementalGCEnabled(rt->mainContextFromOwnThread())) {
     gc(gckind, reason);
     return;
   }
   invocationKind = gckind;
   collect(false, defaultBudget(reason, millis), reason);
 }
 
-void GCRuntime::gcSlice(JS::gcreason::Reason reason, int64_t millis) {
+void GCRuntime::gcSlice(JS::GCReason reason, int64_t millis) {
   MOZ_ASSERT(isIncrementalGCInProgress());
   collect(false, defaultBudget(reason, millis), reason);
 }
 
-void GCRuntime::finishGC(JS::gcreason::Reason reason) {
+void GCRuntime::finishGC(JS::GCReason reason) {
   MOZ_ASSERT(isIncrementalGCInProgress());
 
   // If we're not collecting because we're out of memory then skip the
   // compacting phase if we need to finish an ongoing incremental GC
   // non-incrementally to avoid janking the browser.
   if (!IsOOMReason(initialReason)) {
     if (incrementalState == State::Compact) {
       abortGC();
@@ -7729,17 +7723,17 @@ void GCRuntime::finishGC(JS::gcreason::R
   collect(false, SliceBudget::unlimited(), reason);
 }
 
 void GCRuntime::abortGC() {
   MOZ_ASSERT(isIncrementalGCInProgress());
   checkCanCallAPI();
   MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
 
-  collect(false, SliceBudget::unlimited(), JS::gcreason::ABORT_GC);
+  collect(false, SliceBudget::unlimited(), JS::GCReason::ABORT_GC);
 }
 
 static bool ZonesSelected(JSRuntime* rt) {
   for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
     if (zone->isGCScheduled()) {
       return true;
     }
   }
@@ -7747,25 +7741,25 @@ static bool ZonesSelected(JSRuntime* rt)
 }
 
 void GCRuntime::startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget) {
   MOZ_ASSERT(!isIncrementalGCInProgress());
   if (!ZonesSelected(rt)) {
     JS::PrepareForFullGC(rt->mainContextFromOwnThread());
   }
   invocationKind = gckind;
-  collect(false, budget, JS::gcreason::DEBUG_GC);
+  collect(false, budget, JS::GCReason::DEBUG_GC);
 }
 
 void GCRuntime::debugGCSlice(SliceBudget& budget) {
   MOZ_ASSERT(isIncrementalGCInProgress());
   if (!ZonesSelected(rt)) {
     JS::PrepareForIncrementalGC(rt->mainContextFromOwnThread());
   }
-  collect(false, budget, JS::gcreason::DEBUG_GC);
+  collect(false, budget, JS::GCReason::DEBUG_GC);
 }
 
 /* Schedule a full GC unless a zone will already be collected. */
 void js::PrepareForDebugGC(JSRuntime* rt) {
   if (!ZonesSelected(rt)) {
     JS::PrepareForFullGC(rt->mainContextFromOwnThread());
   }
 }
@@ -7793,20 +7787,20 @@ void GCRuntime::onOutOfMallocMemory(cons
   freeEmptyChunks(lock);
 
   // Immediately decommit as many arenas as possible in the hopes that this
   // might let the OS scrape together enough pages to satisfy the failing
   // malloc request.
   decommitAllWithoutUnlocking(lock);
 }
 
-void GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase) {
+void GCRuntime::minorGC(JS::GCReason reason, gcstats::PhaseKind phase) {
   MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
 
-  MOZ_ASSERT_IF(reason == JS::gcreason::EVICT_NURSERY,
+  MOZ_ASSERT_IF(reason == JS::GCReason::EVICT_NURSERY,
                 !rt->mainContextFromOwnThread()->suppressGC);
   if (rt->mainContextFromOwnThread()->suppressGC) {
     return;
   }
 
   // Note that we aren't collecting the updated alloc counts from any helper
   // threads.  We should be but I'm not sure where to add that
   // synchronisation.
@@ -7856,17 +7850,17 @@ void GCRuntime::startBackgroundFreeAfter
   }
 
   startBackgroundFree();
 }
 
 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSContext* cx)
     : cx(cx) {
   if (!cx->generationalDisabled) {
-    cx->runtime()->gc.evictNursery(JS::gcreason::API);
+    cx->runtime()->gc.evictNursery(JS::GCReason::API);
     cx->nursery().disable();
   }
   ++cx->generationalDisabled;
 }
 
 JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() {
   if (--cx->generationalDisabled == 0) {
     cx->nursery().enable();
@@ -7880,21 +7874,21 @@ JS_PUBLIC_API bool JS::IsGenerationalGCE
 bool GCRuntime::gcIfRequested() {
   // This method returns whether a major GC was performed.
 
   if (nursery().minorGCRequested()) {
     minorGC(nursery().minorGCTriggerReason());
   }
 
   if (majorGCRequested()) {
-    if (majorGCTriggerReason == JS::gcreason::DELAYED_ATOMS_GC &&
+    if (majorGCTriggerReason == JS::GCReason::DELAYED_ATOMS_GC &&
         !rt->mainContextFromOwnThread()->canCollectAtoms()) {
       // A GC was requested to collect the atoms zone, but it's no longer
       // possible. Skip this collection.
-      majorGCTriggerReason = JS::gcreason::NO_REASON;
+      majorGCTriggerReason = JS::GCReason::NO_REASON;
       return false;
     }
 
     if (!isIncrementalGCInProgress()) {
       startGC(GC_NORMAL, majorGCTriggerReason);
     } else {
       gcSlice(majorGCTriggerReason);
     }
@@ -7902,17 +7896,17 @@ bool GCRuntime::gcIfRequested() {
   }
 
   return false;
 }
 
 void js::gc::FinishGC(JSContext* cx) {
   if (JS::IsIncrementalGCInProgress(cx)) {
     JS::PrepareForIncrementalGC(cx);
-    JS::FinishIncrementalGC(cx, JS::gcreason::API);
+    JS::FinishIncrementalGC(cx, JS::GCReason::API);
   }
 
   cx->runtime()->gc.waitBackgroundFreeEnd();
 }
 
 Realm* js::NewRealm(JSContext* cx, JSPrincipals* principals,
                     const JS::RealmOptions& options) {
   JSRuntime* rt = cx->runtime();
@@ -8183,17 +8177,17 @@ void GCRuntime::mergeRealms(Realm* sourc
 
 void GCRuntime::runDebugGC() {
 #ifdef JS_GC_ZEAL
   if (rt->mainContextFromOwnThread()->suppressGC) {
     return;
   }
 
   if (hasZealMode(ZealMode::GenerationalGC)) {
-    return minorGC(JS::gcreason::DEBUG_GC);
+    return minorGC(JS::GCReason::DEBUG_GC);
   }
 
   PrepareForDebugGC(rt);
 
   auto budget = SliceBudget::unlimited();
   if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
     /*
      * Start with a small slice limit and double it every slice. This
@@ -8206,36 +8200,36 @@ void GCRuntime::runDebugGC() {
       incrementalLimit *= 2;
     }
     budget = SliceBudget(WorkBudget(incrementalLimit));
 
     js::gc::State initialState = incrementalState;
     if (!isIncrementalGCInProgress()) {
       invocationKind = GC_SHRINK;
     }
-    collect(false, budget, JS::gcreason::DEBUG_GC);
+    collect(false, budget, JS::GCReason::DEBUG_GC);
 
     /* Reset the slice size when we get to the sweep or compact phases. */
     if ((initialState == State::Mark && incrementalState == State::Sweep) ||
         (initialState == State::Sweep && incrementalState == State::Compact)) {
       incrementalLimit = zealFrequency / 2;
     }
   } else if (hasIncrementalTwoSliceZealMode()) {
     // These modes trigger incremental GC that happens in two slices and the
     // supplied budget is ignored by incrementalSlice.
     budget = SliceBudget(WorkBudget(1));
 
     if (!isIncrementalGCInProgress()) {
       invocationKind = GC_NORMAL;
     }
-    collect(false, budget, JS::gcreason::DEBUG_GC);
+    collect(false, budget, JS::GCReason::DEBUG_GC);
   } else if (hasZealMode(ZealMode::Compact)) {
-    gc(GC_SHRINK, JS::gcreason::DEBUG_GC);
+    gc(GC_SHRINK, JS::GCReason::DEBUG_GC);
   } else {
-    gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
+    gc(GC_NORMAL, JS::GCReason::DEBUG_GC);
   }
 
 #endif
 }
 
 void GCRuntime::setFullCompartmentChecks(bool enabled) {
   MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
   fullCompartmentChecks = enabled;
@@ -8521,37 +8515,34 @@ JS_PUBLIC_API bool JS::IsGCScheduled(JSC
 
   return false;
 }
 
 JS_PUBLIC_API void JS::SkipZoneForGC(Zone* zone) { zone->unscheduleGC(); }
 
 JS_PUBLIC_API void JS::NonIncrementalGC(JSContext* cx,
                                         JSGCInvocationKind gckind,
-                                        gcreason::Reason reason) {
+                                        GCReason reason) {
   MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
   cx->runtime()->gc.gc(gckind, reason);
 }
 
 JS_PUBLIC_API void JS::StartIncrementalGC(JSContext* cx,
                                           JSGCInvocationKind gckind,
-                                          gcreason::Reason reason,
-                                          int64_t millis) {
+                                          GCReason reason, int64_t millis) {
   MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
   cx->runtime()->gc.startGC(gckind, reason, millis);
 }
 
-JS_PUBLIC_API void JS::IncrementalGCSlice(JSContext* cx,
-                                          gcreason::Reason reason,
+JS_PUBLIC_API void JS::IncrementalGCSlice(JSContext* cx, GCReason reason,
                                           int64_t millis) {
   cx->runtime()->gc.gcSlice(reason, millis);
 }
 
-JS_PUBLIC_API void JS::FinishIncrementalGC(JSContext* cx,
-                                           gcreason::Reason reason) {
+JS_PUBLIC_API void JS::FinishIncrementalGC(JSContext* cx, GCReason reason) {
   cx->runtime()->gc.finishGC(reason);
 }
 
 JS_PUBLIC_API void JS::AbortIncrementalGC(JSContext* cx) {
   if (IsIncrementalGCInProgress(cx)) {
     cx->runtime()->gc.abortGC();
   }
 }
@@ -8916,17 +8907,17 @@ void AutoAssertEmptyNursery::checkCondit
   }
   this->cx = cx;
   MOZ_ASSERT(cx->nursery().isEmpty());
 }
 
 AutoEmptyNursery::AutoEmptyNursery(JSContext* cx) : AutoAssertEmptyNursery() {
   MOZ_ASSERT(!cx->suppressGC);
   cx->runtime()->gc.stats().suspendPhases();
-  cx->runtime()->gc.evictNursery(JS::gcreason::EVICT_NURSERY);
+  cx->runtime()->gc.evictNursery(JS::GCReason::EVICT_NURSERY);
   cx->runtime()->gc.stats().resumePhases();
   checkCondition(cx);
 }
 
 } /* namespace gc */
 } /* namespace js */
 
 #ifdef DEBUG
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -277,19 +277,19 @@ class MOZ_RAII AutoAssertEmptyNursery {
  */
 class MOZ_RAII AutoEmptyNursery : public AutoAssertEmptyNursery {
  public:
   explicit AutoEmptyNursery(JSContext* cx);
 };
 
 extern void DelayCrossCompartmentGrayMarking(JSObject* src);
 
-inline bool IsOOMReason(JS::gcreason::Reason reason) {
-  return reason == JS::gcreason::LAST_DITCH ||
-         reason == JS::gcreason::MEM_PRESSURE;
+inline bool IsOOMReason(JS::GCReason reason) {
+  return reason == JS::GCReason::LAST_DITCH ||
+         reason == JS::GCReason::MEM_PRESSURE;
 }
 
 TenuredCell* AllocateCellInGC(JS::Zone* zone, AllocKind thingKind);
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_GCInternals_h */
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -241,29 +241,29 @@ class GCRuntime {
   void removeRoot(Value* vp);
   void setMarkStackLimit(size_t limit, AutoLockGC& lock);
 
   MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value,
                                  AutoLockGC& lock);
   void resetParameter(JSGCParamKey key, AutoLockGC& lock);
   uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
 
-  MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
+  MOZ_MUST_USE bool triggerGC(JS::GCReason reason);
   void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
   // The return value indicates if we were able to do the GC.
-  bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, size_t usedBytes,
+  bool triggerZoneGC(Zone* zone, JS::GCReason reason, size_t usedBytes,
                      size_t thresholdBytes);
   void maybeGC(Zone* zone);
   // The return value indicates whether a major GC was performed.
   bool gcIfRequested();
-  void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
-  void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason,
+  void gc(JSGCInvocationKind gckind, JS::GCReason reason);
+  void startGC(JSGCInvocationKind gckind, JS::GCReason reason,
                int64_t millis = 0);
-  void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
-  void finishGC(JS::gcreason::Reason reason);
+  void gcSlice(JS::GCReason reason, int64_t millis = 0);
+  void finishGC(JS::GCReason reason);
   void abortGC();
   void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
   void debugGCSlice(SliceBudget& budget);
 
   void triggerFullGCForAtoms(JSContext* cx);
 
   void runDebugGC();
   void notifyRootsRemoved();
@@ -351,17 +351,17 @@ class GCRuntime {
   bool updateMallocCounter(size_t nbytes) {
     mallocCounter.update(nbytes);
     TriggerKind trigger = mallocCounter.shouldTriggerGC(tunables);
     if (MOZ_LIKELY(trigger == NoTrigger) ||
         trigger <= mallocCounter.triggered()) {
       return false;
     }
 
-    if (!triggerGC(JS::gcreason::TOO_MUCH_MALLOC)) {
+    if (!triggerGC(JS::GCReason::TOO_MUCH_MALLOC)) {
       return false;
     }
 
     // Even though this method may be called off the main thread it is safe
     // to access mallocCounter here since triggerGC() will return false in
     // that case.
     stats().recordTrigger(mallocCounter.bytes(), mallocCounter.maxBytes());
 
@@ -415,17 +415,17 @@ class GCRuntime {
   bool isIncrementalGc() const { return isIncremental; }
   bool isFullGc() const { return isFull; }
   bool isCompactingGc() const { return isCompacting; }
 
   bool areGrayBitsValid() const { return grayBitsValid; }
   void setGrayBitsInvalid() { grayBitsValid = false; }
 
   bool majorGCRequested() const {
-    return majorGCTriggerReason != JS::gcreason::NO_REASON;
+    return majorGCTriggerReason != JS::GCReason::NO_REASON;
   }
 
   bool fullGCForAtomsRequested() const { return fullGCForAtomsRequested_; }
 
   double computeHeapGrowthFactor(size_t lastBytes);
   size_t computeTriggerBytes(double growthFactor, size_t lastBytes);
 
   JSGCMode gcMode() const { return mode; }
@@ -545,65 +545,63 @@ class GCRuntime {
   ChunkPool expireEmptyChunkPool(const AutoLockGC& lock);
   void freeEmptyChunks(const AutoLockGC& lock);
   void prepareToFreeChunk(ChunkInfo& info);
 
   friend class BackgroundAllocTask;
   bool wantBackgroundAllocation(const AutoLockGC& lock) const;
   bool startBackgroundAllocTaskIfIdle();
 
-  void requestMajorGC(JS::gcreason::Reason reason);
-  SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
+  void requestMajorGC(JS::GCReason reason);
+  SliceBudget defaultBudget(JS::GCReason reason, int64_t millis);
   IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI,
-                                        JS::gcreason::Reason reason,
+                                        JS::GCReason reason,
                                         SliceBudget& budget);
   IncrementalResult resetIncrementalGC(AbortReason reason);
 
   // Assert if the system state is such that we should never
   // receive a request to do GC work.
   void checkCanCallAPI();
 
   // Check if the system state is such that GC has been supressed
   // or otherwise delayed.
-  MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason);
+  MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::GCReason reason);
 
   gcstats::ZoneGCStats scanZonesBeforeGC();
   void collect(bool nonincrementalByAPI, SliceBudget budget,
-               JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
+               JS::GCReason reason) JS_HAZ_GC_CALL;
 
   /*
    * Run one GC "cycle" (either a slice of incremental GC or an entire
    * non-incremental GC).
    *
    * Returns:
    *  * ResetIncremental if we "reset" an existing incremental GC, which would
    *    force us to run another cycle or
    *  * Ok otherwise.
    */
   MOZ_MUST_USE IncrementalResult gcCycle(bool nonincrementalByAPI,
                                          SliceBudget budget,
-                                         JS::gcreason::Reason reason);
-  bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
-  void incrementalSlice(SliceBudget& budget, JS::gcreason::Reason reason,
+                                         JS::GCReason reason);
+  bool shouldRepeatForDeadZone(JS::GCReason reason);
+  void incrementalSlice(SliceBudget& budget, JS::GCReason reason,
                         AutoGCSession& session);
   MOZ_MUST_USE bool shouldCollectNurseryForSlice(bool nonincrementalByAPI,
                                                  SliceBudget& budget);
 
   friend class AutoCallGCCallbacks;
   void maybeCallGCCallback(JSGCStatus status);
 
   void pushZealSelectedObjects();
   void purgeRuntime();
-  MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason,
-                                   AutoGCSession& session);
-  bool prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut);
+  MOZ_MUST_USE bool beginMarkPhase(JS::GCReason reason, AutoGCSession& session);
+  bool prepareZonesForCollection(JS::GCReason reason, bool* isFullOut);
   bool shouldPreserveJITCode(JS::Realm* realm,
                              const mozilla::TimeStamp& currentTime,
-                             JS::gcreason::Reason reason,
-                             bool canAllocateMoreCode);
+                             JS::GCReason reason, bool canAllocateMoreCode);
   void startBackgroundFreeAfterMinorGC();
   void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
   void traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& atomsAccess);
   void traceKeptAtoms(JSTracer* trc);
   void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark);
   void maybeDoCycleCollection();
   void markCompartments();
   IncrementalProgress markUntilBudgetExhausted(SliceBudget& sliceBudget,
@@ -613,18 +611,18 @@ class GCRuntime {
   void markWeakReferences(gcstats::PhaseKind phase);
   void markWeakReferencesInCurrentGroup(gcstats::PhaseKind phase);
   template <class ZoneIterT>
   void markGrayRoots(gcstats::PhaseKind phase);
   void markBufferedGrayRoots(JS::Zone* zone);
   void markAllWeakReferences(gcstats::PhaseKind phase);
   void markAllGrayReferences(gcstats::PhaseKind phase);
 
-  void beginSweepPhase(JS::gcreason::Reason reason, AutoGCSession& session);
-  void groupZonesForSweeping(JS::gcreason::Reason reason);
+  void beginSweepPhase(JS::GCReason reason, AutoGCSession& session);
+  void groupZonesForSweeping(JS::GCReason reason);
   MOZ_MUST_USE bool findInterZoneEdges();
   void getNextSweepGroup();
   IncrementalProgress markGrayReferencesInCurrentGroup(FreeOp* fop,
                                                        SliceBudget& budget);
   IncrementalProgress endMarkingSweepGroup(FreeOp* fop, SliceBudget& budget);
   void markIncomingCrossCompartmentPointers(MarkColor color);
   IncrementalProgress beginSweepingSweepGroup(FreeOp* fop, SliceBudget& budget);
   void sweepDebuggerOnMainThread(FreeOp* fop);
@@ -650,23 +648,23 @@ class GCRuntime {
   void queueZonesAndStartBackgroundSweep(ZoneList& zones);
   void sweepFromBackgroundThread(AutoLockHelperThreadState& lock);
   void startBackgroundFree();
   void freeFromBackgroundThread(AutoLockHelperThreadState& lock);
   void sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks);
   void assertBackgroundSweepingFinished();
   bool shouldCompact();
   void beginCompactPhase();
-  IncrementalProgress compactPhase(JS::gcreason::Reason reason,
+  IncrementalProgress compactPhase(JS::GCReason reason,
                                    SliceBudget& sliceBudget,
                                    AutoGCSession& session);
   void endCompactPhase();
   void sweepTypesAfterCompacting(Zone* zone);
   void sweepZoneAfterCompacting(Zone* zone);
-  MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::gcreason::Reason reason,
+  MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::GCReason reason,
                                    Arena*& relocatedListOut,
                                    SliceBudget& sliceBudget);
   void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
   void updateCellPointers(Zone* zone, AllocKinds kinds, size_t bgTaskCount);
   void updateAllCellPointers(MovingTracer* trc, Zone* zone);
   void updateZonePointersToRelocatedCells(Zone* zone);
   void updateRuntimePointersToRelocatedCells(AutoGCSession& session);
   void protectAndHoldArenas(Arena* arenaList);
@@ -799,17 +797,17 @@ class GCRuntime {
   }
 
   /*
    * The gray bits can become invalid if UnmarkGray overflows the stack. A
    * full GC will reset this bit, since it fills in all the gray bits.
    */
   UnprotectedData<bool> grayBitsValid;
 
-  mozilla::Atomic<JS::gcreason::Reason, mozilla::Relaxed,
+  mozilla::Atomic<JS::GCReason, mozilla::Relaxed,
                   mozilla::recordreplay::Behavior::DontPreserve>
       majorGCTriggerReason;
 
  private:
   /* Perform full GC if rt->keepAtoms() becomes false. */
   MainThreadData<bool> fullGCForAtomsRequested_;
 
   /* Incremented at the start of every minor GC. */
@@ -829,17 +827,17 @@ class GCRuntime {
 
   /* Whether the heap will be compacted at the end of GC. */
   MainThreadData<bool> isCompacting;
 
   /* The invocation kind of the current GC, taken from the first slice. */
   MainThreadData<JSGCInvocationKind> invocationKind;
 
   /* The initial GC reason, taken from the first slice. */
-  MainThreadData<JS::gcreason::Reason> initialReason;
+  MainThreadData<JS::GCReason> initialReason;
 
   /*
    * The current incremental GC phase. This is also used internally in
    * non-incremental GC.
    */
   MainThreadOrGCTaskData<State> incrementalState;
 
   /* The incremental state at the start of this slice. */
@@ -1036,20 +1034,20 @@ class GCRuntime {
   }
   const void* addressOfStringNurseryCurrentEnd() {
     return nursery_.refNoCheck().addressOfCurrentStringEnd();
   }
   uint32_t* addressOfNurseryAllocCount() {
     return stats().addressOfAllocsSinceMinorGCNursery();
   }
 
-  void minorGC(JS::gcreason::Reason reason,
+  void minorGC(JS::GCReason reason,
                gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC)
       JS_HAZ_GC_CALL;
-  void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
+  void evictNursery(JS::GCReason reason = JS::GCReason::EVICT_NURSERY) {
     minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
   }
 
   friend class MarkingValidator;
   friend class AutoEnterIteration;
 };
 
 /* Prevent compartments and zones from being collected during iteration. */
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -90,30 +90,30 @@ using mozilla::PodCopy;
 //                           '-----------------'                                                //
 //                              /          \                                                    //
 //                             /            \                                                   //
 //                       .---------.   .----------.         .-----------------.                 //
 //                       |DoMarking|   |DoCallback|-------> |<JSTraceCallback>|----------->     //
 //                       '---------'   '----------'         '-----------------'                 //
 //                            |                                                                 //
 //                            |                                                                 //
-//                        .--------.                                                            //
-//      o---------------->|traverse| .                                                          //
-//     /_\                '--------'   ' .                                                      //
-//      |                     .     .      ' .                                                  //
-//      |                     .       .        ' .                                              //
-//      |                     .         .          ' .                                          //
-//      |             .-----------.    .-----------.   ' .     .--------------------.           //
-//      |             |markAndScan|    |markAndPush|       ' - |markAndTraceChildren|---->      //
-//      |             '-----------'    '-----------'           '--------------------'           //
-//      |                   |                  \                                                //
-//      |                   |                   \                                               //
-//      |       .----------------------.     .----------------.                                 //
-//      |       |T::eagerlyMarkChildren|     |pushMarkStackTop|<===Oo                           //
-//      |       '----------------------'     '----------------'    ||                           //
+//                     .-----------.                                                            //
+//      o------------->|traverse(T)| .                                                          //
+//     /_\             '-----------'   ' .                                                      //
+//      |                   .       .      ' .                                                  //
+//      |                   .         .        ' .                                              //
+//      |                   .           .          ' .                                          //
+//      |          .--------------.  .--------------.  ' .     .-----------------------.        //
+//      |          |markAndScan(T)|  |markAndPush(T)|      ' - |markAndTraceChildren(T)|        //
+//      |          '--------------'  '--------------'          '-----------------------'        //
+//      |                   |                  \                               |                //
+//      |                   |                   \                              |                //
+//      |       .----------------------.     .----------------.         .------------------.    //
+//      |       |eagerlyMarkChildren(T)|     |pushMarkStackTop|<===Oo   |T::traceChildren()|--> //
+//      |       '----------------------'     '----------------'    ||   '------------------'    //
 //      |                  |                         ||            ||                           //
 //      |                  |                         ||            ||                           //
 //      |                  |                         ||            ||                           //
 //      o<-----------------o<========================OO============Oo                           //
 //                                                                                              //
 //                                                                                              //
 //   Legend:                                                                                    //
 //     ------  Direct calls                                                                     //
@@ -842,17 +842,16 @@ void js::GCMarker::markAndScan(T* thing)
 namespace js {
 template <>
 void GCMarker::traverse(JSString* thing) {
   markAndScan(thing);
 }
 template <>
 void GCMarker::traverse(LazyScript* thing) {
   markAndScan(thing);
-  markImplicitEdges(thing);
 }
 template <>
 void GCMarker::traverse(Shape* thing) {
   markAndScan(thing);
 }
 template <>
 void GCMarker::traverse(js::Scope* thing) {
   markAndScan(thing);
@@ -1027,17 +1026,17 @@ void LazyScript::traceChildren(JSTracer*
   }
 
   GCPtrFunction* innerFunctions = this->innerFunctions();
   for (auto i : IntegerRange(numInnerFunctions())) {
     TraceEdge(trc, &innerFunctions[i], "lazyScriptInnerFunction");
   }
 
   if (trc->isMarkingTracer()) {
-    return GCMarker::fromTracer(trc)->markImplicitEdges(this);
+    GCMarker::fromTracer(trc)->markImplicitEdges(this);
   }
 }
 inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
   if (thing->script_) {
     noteWeakEdge(thing->script_.unsafeUnbarrieredForTracing());
   }
 
   if (thing->function_) {
@@ -1063,16 +1062,18 @@ inline void js::GCMarker::eagerlyMarkChi
       traverseEdge(thing, static_cast<JSString*>(closedOverBindings[i]));
     }
   }
 
   GCPtrFunction* innerFunctions = thing->innerFunctions();
   for (auto i : IntegerRange(thing->numInnerFunctions())) {
     traverseEdge(thing, static_cast<JSObject*>(innerFunctions[i]));
   }
+
+  markImplicitEdges(thing);
 }
 
 void Shape::traceChildren(JSTracer* trc) {
   TraceEdge(trc, &base_, "base");
   TraceEdge(trc, &propidRef(), "propid");
   if (parent) {
     TraceEdge(trc, &parent, "parent");
   }
@@ -1096,17 +1097,17 @@ inline void js::GCMarker::eagerlyMarkChi
     CheckTraversedEdge(shape, base);
     if (mark(base)) {
       MOZ_ASSERT(base->canSkipMarkingShapeTable(shape));
       base->traceChildrenSkipShapeTable(this);
     }
 
     traverseEdge(shape, shape->propidRef().get());
 
-    // When triggered between slices on belhalf of a barrier, these
+    // When triggered between slices on behalf of a barrier, these
     // objects may reside in the nursery, so require an extra check.
     // FIXME: Bug 1157967 - remove the isTenured checks.
     if (shape->hasGetterObject() && shape->getterObject()->isTenured()) {
       traverseEdge(shape, shape->getterObject());
     }
     if (shape->hasSetterObject() && shape->setterObject()->isTenured()) {
       traverseEdge(shape, shape->setterObject());
     }
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -107,17 +107,17 @@ js::Nursery::Nursery(JSRuntime* rt)
       currentChunk_(0),
       maxChunkCount_(0),
       chunkCountLimit_(0),
       timeInChunkAlloc_(0),
       profileThreshold_(0),
       enableProfiling_(false),
       canAllocateStrings_(false),
       reportTenurings_(0),
-      minorGCTriggerReason_(JS::gcreason::NO_REASON)
+      minorGCTriggerReason_(JS::GCReason::NO_REASON)
 #ifdef JS_GC_ZEAL
       ,
       lastCanary_(nullptr)
 #endif
 {
   const char* env = getenv("MOZ_NURSERY_STRINGS");
   if (env && *env) {
     canAllocateStrings_ = (*env == '1');
@@ -583,32 +583,32 @@ inline float js::Nursery::calcPromotionR
 void js::Nursery::renderProfileJSON(JSONPrinter& json) const {
   if (!isEnabled()) {
     json.beginObject();
     json.property("status", "nursery disabled");
     json.endObject();
     return;
   }
 
-  if (previousGC.reason == JS::gcreason::NO_REASON) {
+  if (previousGC.reason == JS::GCReason::NO_REASON) {
     // If the nursery was empty when the last minorGC was requested, then
     // no nursery collection will have been performed but JSON may still be
     // requested. (And as a public API, this function should not crash in
     // such a case.)
     json.beginObject();
     json.property("status", "nursery empty");
     json.endObject();
     return;
   }
 
   json.beginObject();
 
   json.property("status", "complete");
 
-  json.property("reason", JS::gcreason::ExplainReason(previousGC.reason));
+  json.property("reason", JS::ExplainGCReason(previousGC.reason));
   json.property("bytes_tenured", previousGC.tenuredBytes);
   json.property("cells_tenured", previousGC.tenuredCells);
   json.property("strings_tenured",
                 stats().getStat(gcstats::STAT_STRINGS_TENURED));
   json.property("bytes_used", previousGC.nurseryUsedBytes);
   json.property("cur_capacity", previousGC.nurseryCapacity);
   const size_t newCapacity = spaceToEnd(maxChunkCount());
   if (newCapacity != previousGC.nurseryCapacity) {
@@ -697,26 +697,26 @@ inline void js::Nursery::endProfile(Prof
   totalDurations_[key] += profileDurations_[key];
 }
 
 bool js::Nursery::needIdleTimeCollection() const {
   uint32_t threshold = tunables().nurseryFreeThresholdForIdleCollection();
   return minorGCRequested() || freeSpace() < threshold;
 }
 
-static inline bool IsFullStoreBufferReason(JS::gcreason::Reason reason) {
-  return reason == JS::gcreason::FULL_WHOLE_CELL_BUFFER ||
-         reason == JS::gcreason::FULL_GENERIC_BUFFER ||
-         reason == JS::gcreason::FULL_VALUE_BUFFER ||
-         reason == JS::gcreason::FULL_CELL_PTR_BUFFER ||
-         reason == JS::gcreason::FULL_SLOT_BUFFER ||
-         reason == JS::gcreason::FULL_SHAPE_BUFFER;
+static inline bool IsFullStoreBufferReason(JS::GCReason reason) {
+  return reason == JS::GCReason::FULL_WHOLE_CELL_BUFFER ||
+         reason == JS::GCReason::FULL_GENERIC_BUFFER ||
+         reason == JS::GCReason::FULL_VALUE_BUFFER ||
+         reason == JS::GCReason::FULL_CELL_PTR_BUFFER ||
+         reason == JS::GCReason::FULL_SLOT_BUFFER ||
+         reason == JS::GCReason::FULL_SHAPE_BUFFER;
 }
 
-void js::Nursery::collect(JS::gcreason::Reason reason) {
+void js::Nursery::collect(JS::GCReason reason) {
   JSRuntime* rt = runtime();
   MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
 
   mozilla::recordreplay::AutoDisallowThreadEvents disallow;
 
   if (!isEnabled() || isEmpty()) {
     // Our barriers are not always exact, and there may be entries in the
     // storebuffer even when the nursery is disabled or empty. It's not safe
@@ -745,17 +745,17 @@ void js::Nursery::collect(JS::gcreason::
   startProfile(ProfileKey::Total);
 
   // The analysis marks TenureCount as not problematic for GC hazards because
   // it is only used here, and ObjectGroup pointers are never
   // nursery-allocated.
   MOZ_ASSERT(!IsNurseryAllocable(AllocKind::OBJECT_GROUP));
 
   TenureCountCache tenureCounts;
-  previousGC.reason = JS::gcreason::NO_REASON;
+  previousGC.reason = JS::GCReason::NO_REASON;
   if (!isEmpty()) {
     doCollection(reason, tenureCounts);
   } else {
     previousGC.nurseryUsedBytes = 0;
     previousGC.nurseryCapacity = spaceToEnd(maxChunkCount());
     previousGC.nurseryLazyCapacity = spaceToEnd(allocatedChunkCount());
     previousGC.tenuredBytes = 0;
     previousGC.tenuredCells = 0;
@@ -838,49 +838,48 @@ void js::Nursery::collect(JS::gcreason::
     disable();
   }
 
   endProfile(ProfileKey::Total);
   rt->gc.incMinorGcNumber();
 
   TimeDuration totalTime = profileDurations_[ProfileKey::Total];
   rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime.ToMicroseconds());
-  rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason);
+  rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, uint32_t(reason));
   if (totalTime.ToMilliseconds() > 1.0) {
-    rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, reason);
+    rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, uint32_t(reason));
   }
   rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted());
   rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount);
   rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_PROMOTION_RATE, promotionRate * 100);
 
   stats().endNurseryCollection(reason);
   gcTracer.traceMinorGCEnd();
   timeInChunkAlloc_ = mozilla::TimeDuration();
 
   if (enableProfiling_ && totalTime >= profileThreshold_) {
     stats().maybePrintProfileHeaders();
 
     fprintf(stderr, "MinorGC: %20s %5.1f%% %4u        ",
-            JS::gcreason::ExplainReason(reason), promotionRate * 100,
-            maxChunkCount());
+            JS::ExplainGCReason(reason), promotionRate * 100, maxChunkCount());
     printProfileDurations(profileDurations_);
 
     if (reportTenurings_) {
       for (auto& entry : tenureCounts.entries) {
         if (entry.count >= reportTenurings_) {
           fprintf(stderr, "  %d x ", entry.count);
           AutoSweepObjectGroup sweep(entry.group);
           entry.group->print(sweep);
         }
       }
     }
   }
 }
 
-void js::Nursery::doCollection(JS::gcreason::Reason reason,
+void js::Nursery::doCollection(JS::GCReason reason,
                                TenureCountCache& tenureCounts) {
   JSRuntime* rt = runtime();
   AutoGCSession session(rt, JS::HeapState::MinorCollecting);
   AutoSetThreadIsPerformingGC performingGC;
   AutoStopVerifyingBarriers av(rt, false);
   AutoDisableProxyCheck disableStrictProxyChecking;
   mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion;
 
@@ -1114,17 +1113,17 @@ bool js::Nursery::allocateNextChunk(cons
   return true;
 }
 
 MOZ_ALWAYS_INLINE void js::Nursery::setStartPosition() {
   currentStartChunk_ = currentChunk_;
   currentStartPosition_ = position();
 }
 
-void js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) {
+void js::Nursery::maybeResizeNursery(JS::GCReason reason) {
   static const double GrowThreshold = 0.03;
   static const double ShrinkThreshold = 0.01;
   unsigned newMaxNurseryChunks;
 
   // Shrink the nursery to its minimum size of we ran out of memory or
   // received a memory pressure event.
   if (gc::IsOOMReason(reason)) {
     minimizeAllocableSpace();
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -266,17 +266,17 @@ class Nursery {
 
   /* Free an object buffer. */
   void freeBuffer(void* buffer);
 
   /* The maximum number of bytes allowed to reside in nursery buffers. */
   static const size_t MaxNurseryBufferSize = 1024;
 
   /* Do a minor collection. */
-  void collect(JS::gcreason::Reason reason);
+  void collect(JS::GCReason reason);
 
   /*
    * If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
    * the new location and return true. Otherwise return false and leave
    * |*ref| unset.
    */
   MOZ_ALWAYS_INLINE MOZ_MUST_USE static bool getForwardedPointer(
       js::gc::Cell** ref);
@@ -347,26 +347,24 @@ class Nursery {
   void printTotalProfileTimes();
 
   void* addressOfPosition() const { return (void**)&position_; }
   const void* addressOfCurrentEnd() const { return (void**)&currentEnd_; }
   const void* addressOfCurrentStringEnd() const {
     return (void*)&currentStringEnd_;
   }
 
-  void requestMinorGC(JS::gcreason::Reason reason) const;
+  void requestMinorGC(JS::GCReason reason) const;
 
   bool minorGCRequested() const {
-    return minorGCTriggerReason_ != JS::gcreason::NO_REASON;
+    return minorGCTriggerReason_ != JS::GCReason::NO_REASON;
   }
-  JS::gcreason::Reason minorGCTriggerReason() const {
-    return minorGCTriggerReason_;
-  }
+  JS::GCReason minorGCTriggerReason() const { return minorGCTriggerReason_; }
   void clearMinorGCRequest() {
-    minorGCTriggerReason_ = JS::gcreason::NO_REASON;
+    minorGCTriggerReason_ = JS::GCReason::NO_REASON;
   }
 
   bool needIdleTimeCollection() const;
 
   bool enableProfiling() const { return enableProfiling_; }
 
   bool addMapWithNurseryMemory(MapObject* obj) {
     MOZ_ASSERT_IF(!mapsWithNurseryMemory_.empty(),
@@ -437,17 +435,17 @@ class Nursery {
   /* Report ObjectGroups with at least this many instances tenured. */
   int64_t reportTenurings_;
 
   /*
    * Whether and why a collection of this nursery has been requested. This is
    * mutable as it is set by the store buffer, which otherwise cannot modify
    * anything in the nursery.
    */
-  mutable JS::gcreason::Reason minorGCTriggerReason_;
+  mutable JS::GCReason minorGCTriggerReason_;
 
   /* Profiling data. */
 
   enum class ProfileKey {
 #define DEFINE_TIME_KEY(name, text) name,
     FOR_EACH_NURSERY_PROFILE_TIME(DEFINE_TIME_KEY)
 #undef DEFINE_TIME_KEY
         KeyCount
@@ -460,17 +458,17 @@ class Nursery {
       mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount,
                                mozilla::TimeDuration>;
 
   ProfileTimes startTimes_;
   ProfileDurations profileDurations_;
   ProfileDurations totalDurations_;
 
   struct {
-    JS::gcreason::Reason reason = JS::gcreason::NO_REASON;
+    JS::GCReason reason = JS::GCReason::NO_REASON;
     size_t nurseryCapacity = 0;
     size_t nurseryLazyCapacity = 0;
     size_t nurseryUsedBytes = 0;
     size_t tenuredBytes = 0;
     size_t tenuredCells = 0;
   } previousGC;
 
   /*
@@ -557,18 +555,17 @@ class Nursery {
   JSRuntime* runtime() const { return runtime_; }
   gcstats::Statistics& stats() const;
 
   const js::gc::GCSchedulingTunables& tunables() const;
 
   /* Common internal allocator function. */
   void* allocate(size_t size);
 
-  void doCollection(JS::gcreason::Reason reason,
-                    gc::TenureCountCache& tenureCounts);
+  void doCollection(JS::GCReason reason, gc::TenureCountCache& tenureCounts);
 
   /*
    * Move the object at |src| in the Nursery to an already-allocated cell
    * |dst| in Tenured.
    */
   void collectToFixedPoint(TenuringTracer& trc,
                            gc::TenureCountCache& tenureCounts);
 
@@ -595,17 +592,17 @@ class Nursery {
    * collection.
    */
   void clear();
 
   void sweepDictionaryModeObjects();
   void sweepMapAndSetObjects();
 
   /* Change the allocable space provided by the nursery. */
-  void maybeResizeNursery(JS::gcreason::Reason reason);
+  void maybeResizeNursery(JS::GCReason reason);
   void growAllocableSpace();
   void shrinkAllocableSpace(unsigned newCount);
   void minimizeAllocableSpace();
 
   // Free the chunks starting at firstFreeChunk until the end of the chunks
   // vector. Shrinks the vector but does not update maxChunkCount().
   void freeChunksFrom(unsigned firstFreeChunk);
 
--- a/js/src/gc/Scheduling.h
+++ b/js/src/gc/Scheduling.h
@@ -85,23 +85,23 @@
  *     OOMing.
  *
  *
  * Reasons for scheduling GC
  * -------------------------
  *
  *  While code generally takes the above factors into account in only an ad-hoc
  *  fashion, the API forces the user to pick a "reason" for the GC. We have a
- *  bunch of JS::gcreason reasons in GCAPI.h. These fall into a few categories
+ *  bunch of JS::GCReason reasons in GCAPI.h. These fall into a few categories
  *  that generally coincide with one or more of the above factors.
  *
  *  Embedding reasons:
  *
  *   1) Do a GC now because the embedding knows something useful about the
- *      zone's memory retention state. These are gcreasons like LOAD_END,
+ *      zone's memory retention state. These are GCReasons like LOAD_END,
  *      PAGE_HIDE, SET_NEW_DOCUMENT, DOM_UTILS. Mostly, Gecko uses these to
  *      indicate that a significant fraction of the scheduled zone's memory is
  *      probably reclaimable.
  *
  *   2) Do some known amount of GC work now because the embedding knows now is
  *      a good time to do a long, unblockable operation of a known duration.
  *      These are INTER_SLICE_GC and REFRESH_FRAME.
  *
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -35,18 +35,18 @@ using mozilla::EnumeratedArray;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
 /*
  * If this fails, then you can either delete this assertion and allow all
  * larger-numbered reasons to pile up in the last telemetry bucket, or switch
  * to GC_REASON_3 and bump the max value.
  */
-JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >=
-                 JS::gcreason::NUM_REASONS);
+JS_STATIC_ASSERT(JS::GCReason::NUM_TELEMETRY_REASONS >=
+                 JS::GCReason::NUM_REASONS);
 
 using PhaseKindRange =
     decltype(mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT));
 
 static inline PhaseKindRange AllPhaseKinds() {
   return mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT);
 }
 
@@ -59,21 +59,20 @@ const char* js::gcstats::ExplainInvocati
   MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
   if (gckind == GC_NORMAL) {
     return "Normal";
   } else {
     return "Shrinking";
   }
 }
 
-JS_PUBLIC_API const char* JS::gcreason::ExplainReason(
-    JS::gcreason::Reason reason) {
+JS_PUBLIC_API const char* JS::ExplainGCReason(JS::GCReason reason) {
   switch (reason) {
 #define SWITCH_REASON(name, _) \
-  case JS::gcreason::name:     \
+  case JS::GCReason::name:     \
     return #name;
     GCREASONS(SWITCH_REASON)
 
     default:
       MOZ_CRASH("bad GC reason");
 #undef SWITCH_REASON
   }
 }
@@ -274,17 +273,18 @@ UniqueChars Statistics::formatCompactSli
   char budgetDescription[200];
   slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
 
   const char* format =
       "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: "
       "%s%s; Times: ";
   char buffer[1024];
   SprintfLiteral(buffer, format, index, t(slice.duration()), budgetDescription,
-                 t(slice.start - slices_[0].start), ExplainReason(slice.reason),
+                 t(slice.start - slices_[0].start),
+                 ExplainGCReason(slice.reason),
                  slice.wasReset() ? "yes - " : "no",
                  slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "");
 
   FragmentVector fragments;
   if (!fragments.append(DuplicateString(buffer)) ||
       !fragments.append(
           formatCompactSlicePhaseTimes(slices_[index].phaseTimes))) {
     return UniqueChars(nullptr);
@@ -437,17 +437,17 @@ UniqueChars Statistics::formatDetailedDe
     SprintfLiteral(thresholdBuffer, "%.3f MiB of %.3f MiB threshold\n",
                    triggerAmount / 1024.0 / 1024.0,
                    triggerThreshold / 1024.0 / 1024.0);
   }
 
   char buffer[1024];
   SprintfLiteral(
       buffer, format, ExplainInvocationKind(gckind),
-      ExplainReason(slices_[0].reason), nonincremental() ? "no - " : "yes",
+      ExplainGCReason(slices_[0].reason), nonincremental() ? "no - " : "yes",
       nonincremental() ? ExplainAbortReason(nonincrementalReason_) : "",
       zoneStats.collectedZoneCount, zoneStats.zoneCount,
       zoneStats.sweptZoneCount, zoneStats.collectedCompartmentCount,
       zoneStats.compartmentCount, zoneStats.sweptCompartmentCount,
       getCount(COUNT_MINOR_GC), getCount(COUNT_STOREBUFFER_OVERFLOW),
       mmu20 * 100., mmu50 * 100., t(sccTotal), t(sccLongest),
       double(preHeapSize) / bytesPerMiB,
       getCount(COUNT_NEW_CHUNK) - getCount(COUNT_DESTROY_CHUNK),
@@ -470,17 +470,17 @@ UniqueChars Statistics::formatDetailedSl
     Reset: %s%s\n\
     State: %s -> %s\n\
     Page Faults: %" PRIu64
       "\n\
     Pause: %.3fms of %s budget (@ %.3fms)\n\
 ";
   char buffer[1024];
   SprintfLiteral(
-      buffer, format, i, ExplainReason(slice.reason),
+      buffer, format, i, ExplainGCReason(slice.reason),
       slice.wasReset() ? "yes - " : "no",
       slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "",
       gc::StateName(slice.initialState), gc::StateName(slice.finalState),
       uint64_t(slice.endFaults - slice.startFaults), t(slice.duration()),
       budgetDescription, t(slice.start - slices_[0].start));
   return DuplicateString(buffer);
 }
 
@@ -645,17 +645,17 @@ void Statistics::formatJsonDescription(u
   json.property("timestamp", timestamp);  // # JSON Key #2
 
   TimeDuration total, longest;
   gcDuration(&total, &longest);
   json.property("max_pause", longest, JSONPrinter::MILLISECONDS);  // #3
   json.property("total_time", total, JSONPrinter::MILLISECONDS);   // #4
   // We might be able to omit reason if perf.html was able to retrive it
   // from the first slice.  But it doesn't do this yet.
-  json.property("reason", ExplainReason(slices_[0].reason));        // #5
+  json.property("reason", ExplainGCReason(slices_[0].reason));      // #5
   json.property("zones_collected", zoneStats.collectedZoneCount);   // #6
   json.property("total_zones", zoneStats.zoneCount);                // #7
   json.property("total_compartments", zoneStats.compartmentCount);  // #8
   json.property("minor_gcs", getCount(COUNT_MINOR_GC));             // #9
   uint32_t storebufferOverflows = getCount(COUNT_STOREBUFFER_OVERFLOW);
   if (storebufferOverflows) {
     json.property("store_buffer_overflows", storebufferOverflows);  // #10
   }
@@ -708,17 +708,17 @@ void Statistics::formatJsonSliceDescript
   //   https://github.com/devtools-html/perf.html
   //
   char budgetDescription[200];
   slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
   TimeStamp originTime = TimeStamp::ProcessCreation();
 
   json.property("slice", i);  // JSON Property #1
   json.property("pause", slice.duration(), JSONPrinter::MILLISECONDS);  // #2
-  json.property("reason", ExplainReason(slice.reason));                 // #3
+  json.property("reason", ExplainGCReason(slice.reason));               // #3
   json.property("initial_state", gc::StateName(slice.initialState));    // #4
   json.property("final_state", gc::StateName(slice.finalState));        // #5
   json.property("budget", budgetDescription);                           // #6
   json.property("major_gc_number", startingMajorGCNumber);              // #7
   if (thresholdTriggered) {
     json.floatProperty("trigger_amount", triggerAmount, 0);        // #8
     json.floatProperty("trigger_threshold", triggerThreshold, 0);  // #9
   }
@@ -1019,39 +1019,39 @@ void Statistics::endGC() {
   runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total));
   runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS_2, t(longest));
 
   const double mmu50 = computeMMU(TimeDuration::FromMilliseconds(50));
   runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
   thresholdTriggered = false;
 }
 
-void Statistics::beginNurseryCollection(JS::gcreason::Reason reason) {
+void Statistics::beginNurseryCollection(JS::GCReason reason) {
   count(COUNT_MINOR_GC);
   startingMinorGCNumber = runtime->gc.minorGCCount();
   if (nurseryCollectionCallback) {
     (*nurseryCollectionCallback)(
         runtime->mainContextFromOwnThread(),
         JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START, reason);
   }
 }
 
-void Statistics::endNurseryCollection(JS::gcreason::Reason reason) {
+void Statistics::endNurseryCollection(JS::GCReason reason) {
   if (nurseryCollectionCallback) {
     (*nurseryCollectionCallback)(
         runtime->mainContextFromOwnThread(),
         JS::GCNurseryProgress::GC_NURSERY_COLLECTION_END, reason);
   }
 
   allocsSinceMinorGC = {0, 0};
 }
 
 void Statistics::beginSlice(const ZoneGCStats& zoneStats,
                             JSGCInvocationKind gckind, SliceBudget budget,
-                            JS::gcreason::Reason reason) {
+                            JS::GCReason reason) {
   MOZ_ASSERT(phaseStack.empty() ||
              (phaseStack.length() == 1 && phaseStack[0] == Phase::MUTATOR));
 
   this->zoneStats = zoneStats;
 
   bool first = !runtime->gc.isIncrementalGCInProgress();
   if (first) {
     beginGC(gckind);
@@ -1059,17 +1059,17 @@ void Statistics::beginSlice(const ZoneGC
 
   if (!slices_.emplaceBack(budget, reason, ReallyNow(), GetPageFaultCount(),
                            runtime->gc.state())) {
     // If we are OOM, set a flag to indicate we have missing slice data.
     aborted = true;
     return;
   }
 
-  runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
+  runtime->addTelemetry(JS_TELEMETRY_GC_REASON, uint32_t(reason));
 
   // Slice callbacks should only fire for the outermost level.
   bool wasFullGC = zoneStats.isFullCollection();
   if (sliceCallback) {
     JSContext* cx = runtime->mainContextFromOwnThread();
     JS::GCDescription desc(!wasFullGC, false, gckind, reason);
     if (first) {
       (*sliceCallback)(cx, JS::GC_CYCLE_BEGIN, desc);
@@ -1480,17 +1480,17 @@ void Statistics::printSliceProfile() {
   maybePrintProfileHeaders();
 
   bool shrinking = gckind == GC_SHRINK;
   bool reset = slice.resetReason != AbortReason::None;
   bool nonIncremental = nonincrementalReason_ != AbortReason::None;
   bool full = zoneStats.isFullCollection();
 
   fprintf(stderr, "MajorGC: %20s %1d -> %1d %1s%1s%1s%1s ",
-          ExplainReason(slice.reason), int(slice.initialState),
+          ExplainGCReason(slice.reason), int(slice.initialState),
           int(slice.finalState), full ? "F" : "", shrinking ? "S" : "",
           nonIncremental ? "N" : "", reset ? "R" : "");
 
   if (!nonIncremental && !slice.budget.isUnlimited() &&
       slice.budget.isTimeBudget()) {
     fprintf(stderr, " %6" PRIi64,
             static_cast<int64_t>(slice.budget.timeBudget.budget));
   } else {
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -158,17 +158,17 @@ struct Statistics {
   // until that inner stack is complete, at which time it will automatically
   // resume the non-GC phase. Explicit suspensions do not get auto-resumed.
   void suspendPhases(PhaseKind suspension = PhaseKind::EXPLICIT_SUSPENSION);
 
   // Resume a suspended stack of phases.
   void resumePhases();
 
   void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
-                  SliceBudget budget, JS::gcreason::Reason reason);
+                  SliceBudget budget, JS::GCReason reason);
   void endSlice();
 
   MOZ_MUST_USE bool startTimingMutator();
   MOZ_MUST_USE bool stopTimingMutator(double& mutator_ms, double& gc_ms);
 
   // Note when we sweep a zone or compartment.
   void sweptZone() { ++zoneStats.sweptZoneCount; }
   void sweptCompartment() { ++zoneStats.sweptCompartmentCount; }
@@ -218,18 +218,18 @@ struct Statistics {
   uint32_t allocsSinceMinorGCNursery() { return allocsSinceMinorGC.nursery; }
 
   uint32_t allocsSinceMinorGCTenured() { return allocsSinceMinorGC.tenured; }
 
   uint32_t* addressOfAllocsSinceMinorGCNursery() {
     return &allocsSinceMinorGC.nursery;
   }
 
-  void beginNurseryCollection(JS::gcreason::Reason reason);
-  void endNurseryCollection(JS::gcreason::Reason reason);
+  void beginNurseryCollection(JS::GCReason reason);
+  void endNurseryCollection(JS::GCReason reason);
 
   TimeStamp beginSCC();
   void endSCC(unsigned scc, TimeStamp start);
 
   UniqueChars formatCompactSliceMessage() const;
   UniqueChars formatCompactSummaryMessage() const;
   UniqueChars formatDetailedMessage() const;
 
@@ -240,29 +240,29 @@ struct Statistics {
   TimeDuration clearMaxGCPauseAccumulator();
   TimeDuration getMaxGCPauseSinceClear();
 
   PhaseKind currentPhaseKind() const;
 
   static const size_t MAX_SUSPENDED_PHASES = MAX_PHASE_NESTING * 3;
 
   struct SliceData {
-    SliceData(SliceBudget budget, JS::gcreason::Reason reason, TimeStamp start,
+    SliceData(SliceBudget budget, JS::GCReason reason, TimeStamp start,
               size_t startFaults, gc::State initialState)
         : budget(budget),
           reason(reason),
           initialState(initialState),
           finalState(gc::State::NotActive),
           resetReason(gc::AbortReason::None),
           start(start),
           startFaults(startFaults),
           endFaults(0) {}
 
     SliceBudget budget;
-    JS::gcreason::Reason reason;
+    JS::GCReason reason;
     gc::State initialState, finalState;
     gc::AbortReason resetReason;
     TimeStamp start, end;
     size_t startFaults, endFaults;
     PhaseTimeTable phaseTimes;
     PhaseTimeTable parallelTimes;
 
     TimeDuration duration() const { return end - start; }
@@ -452,17 +452,17 @@ struct Statistics {
 
   void printSliceProfile();
   static void printProfileTimes(const ProfileDurations& times);
 };
 
 struct MOZ_RAII AutoGCSlice {
   AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats,
               JSGCInvocationKind gckind, SliceBudget budget,
-              JS::gcreason::Reason reason)
+              JS::GCReason reason)
       : stats(stats) {
     stats.beginSlice(zoneStats, gckind, budget, reason);
   }
   ~AutoGCSlice() { stats.endSlice(); }
 
   Statistics& stats;
 };
 
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -76,17 +76,17 @@ void StoreBuffer::clear() {
 
   bufferVal.clear();
   bufferCell.clear();
   bufferSlot.clear();
   bufferWholeCell.clear();
   bufferGeneric.clear();
 }
 
-void StoreBuffer::setAboutToOverflow(JS::gcreason::Reason reason) {
+void StoreBuffer::setAboutToOverflow(JS::GCReason reason) {
   if (!aboutToOverflow_) {
     aboutToOverflow_ = true;
     runtime_->gc.stats().count(gcstats::COUNT_STOREBUFFER_OVERFLOW);
   }
   nursery_.requestMinorGC(reason);
 }
 
 void StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
@@ -127,17 +127,17 @@ ArenaCellSet* StoreBuffer::WholeCellBuff
     oomUnsafe.crash("Failed to allocate ArenaCellSet");
   }
 
   arena->bufferedCells() = cells;
   head_ = cells;
 
   if (isAboutToOverflow()) {
     rt->gc.storeBuffer().setAboutToOverflow(
-        JS::gcreason::FULL_WHOLE_CELL_BUFFER);
+        JS::GCReason::FULL_WHOLE_CELL_BUFFER);
   }
 
   return cells;
 }
 
 void StoreBuffer::WholeCellBuffer::clear() {
   for (ArenaCellSet* set = head_; set; set = set->next) {
     set->arena->bufferedCells() = &ArenaCellSet::Empty;
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -232,17 +232,17 @@ class StoreBuffer {
       *sizep = size;
 
       T* tp = storage_->new_<T>(t);
       if (!tp) {
         oomUnsafe.crash("Failed to allocate for GenericBuffer::put.");
       }
 
       if (isAboutToOverflow()) {
-        owner->setAboutToOverflow(JS::gcreason::FULL_GENERIC_BUFFER);
+        owner->setAboutToOverflow(JS::GCReason::FULL_GENERIC_BUFFER);
       }
     }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
       return storage_ ? storage_->sizeOfIncludingThis(mallocSizeOf) : 0;
     }
 
     bool isEmpty() const { return !storage_ || storage_->isEmpty(); }
@@ -287,17 +287,17 @@ class StoreBuffer {
       return CellPtrEdge((Cell**)(uintptr_t(edge) & ~1));
     }
     bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
     explicit operator bool() const { return edge != nullptr; }
 
     typedef PointerEdgeHasher<CellPtrEdge> Hasher;
 
-    static const auto FullBufferReason = JS::gcreason::FULL_CELL_PTR_BUFFER;
+    static const auto FullBufferReason = JS::GCReason::FULL_CELL_PTR_BUFFER;
   };
 
   struct ValueEdge {
     JS::Value* edge;
 
     ValueEdge() : edge(nullptr) {}
     explicit ValueEdge(JS::Value* v) : edge(v) {}
     bool operator==(const ValueEdge& other) const { return edge == other.edge; }
@@ -322,17 +322,17 @@ class StoreBuffer {
       return ValueEdge((JS::Value*)(uintptr_t(edge) & ~1));
     }
     bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
     explicit operator bool() const { return edge != nullptr; }
 
     typedef PointerEdgeHasher<ValueEdge> Hasher;
 
-    static const auto FullBufferReason = JS::gcreason::FULL_VALUE_BUFFER;
+    static const auto FullBufferReason = JS::GCReason::FULL_VALUE_BUFFER;
   };
 
   struct SlotsEdge {
     // These definitions must match those in HeapSlot::Kind.
     const static int SlotKind = 0;
     const static int ElementKind = 1;
 
     uintptr_t objectAndKind_;  // NativeObject* | Kind
@@ -405,17 +405,17 @@ class StoreBuffer {
     typedef struct {
       typedef SlotsEdge Lookup;
       static HashNumber hash(const Lookup& l) {
         return mozilla::HashGeneric(l.objectAndKind_, l.start_, l.count_);
       }
       static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; }
     } Hasher;
 
-    static const auto FullBufferReason = JS::gcreason::FULL_SLOT_BUFFER;
+    static const auto FullBufferReason = JS::GCReason::FULL_SLOT_BUFFER;
   };
 
   template <typename Buffer, typename Edge>
   void unput(Buffer& buffer, const Edge& edge) {
     MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
     if (!isEnabled()) {
       return;
@@ -515,17 +515,17 @@ class StoreBuffer {
   void traceCells(TenuringTracer& mover) { bufferCell.trace(this, mover); }
   void traceSlots(TenuringTracer& mover) { bufferSlot.trace(this, mover); }
   void traceWholeCells(TenuringTracer& mover) {
     bufferWholeCell.trace(this, mover);
   }
   void traceGenericEntries(JSTracer* trc) { bufferGeneric.trace(this, trc); }
 
   /* For use by our owned buffers and for testing. */
-  void setAboutToOverflow(JS::gcreason::Reason);
+  void setAboutToOverflow(JS::GCReason);
 
   void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                               JS::GCSizes* sizes);
 
   void checkEmpty() const;
 };
 
 // A set of cells in an arena used to implement the whole cell store buffer.
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -484,17 +484,17 @@ void JS::Zone::maybeTriggerGCForTooMuchM
     return;
   }
 
   bool wouldInterruptGC = rt->gc.isIncrementalGCInProgress() && !isCollecting();
   if (wouldInterruptGC && !counter.shouldResetIncrementalGC(rt->gc.tunables)) {
     return;
   }
 
-  if (!rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
+  if (!rt->gc.triggerZoneGC(this, JS::GCReason::TOO_MUCH_MALLOC,
                             counter.bytes(), counter.maxBytes())) {
     return;
   }
 
   counter.recordTrigger(trigger);
 }
 
 ZoneList::ZoneList() : head(nullptr), tail(nullptr) {}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1520778.js
@@ -0,0 +1,18 @@
+// |jit-test| error: ReferenceError
+gczeal(0);
+gcparam("markStackLimit", 1);
+var g = newGlobal({
+    newCompartment: true
+});
+var dbg = new Debugger;
+var gw = dbg.addDebuggee(g);
+dbg.onDebuggerStatement = function(frame) {
+  frame.environment.parent.getVariable('y')
+};
+g.eval(`
+  let y = 1;
+  g = function () { debugger; };
+  g();
+`);
+gczeal(9, 10);
+f4();
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -240,17 +240,17 @@ void runTestFromPath(JSContext* cx, cons
       continue;
     }
 
     {
       // Make sure that we run GC between two tests. Otherwise, since we're
       // running everything from the same cx and without returning to JS, there
       // is nothing to deallocate the ASTs.
       JS::PrepareForFullGC(cx);
-      cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::NO_REASON);
+      cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::NO_REASON);
     }
     LifoAllocScope allocScope(&cx->tempLifoAlloc());
 
     // Find files whose name ends with ".binjs".
     fprintf(stderr, "Considering %s\n", d_name);
     if (namlen < sizeof(BIN_SUFFIX)) {
       continue;
     }
--- a/js/src/jsapi-tests/testErrorInterceptorGC.cpp
+++ b/js/src/jsapi-tests/testErrorInterceptorGC.cpp
@@ -3,17 +3,17 @@
 #include "jsapi-tests/tests.h"
 
 namespace {
 
 // An interceptor that triggers GC:
 struct ErrorInterceptorWithGC : JSErrorInterceptor {
   void interceptError(JSContext* cx, JS::HandleValue val) override {
     JS::PrepareForFullGC(cx);
-    JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::DEBUG_GC);
+    JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::DEBUG_GC);
   }
 };
 
 }  // namespace
 
 BEGIN_TEST(testErrorInterceptorGC) {
   JSErrorInterceptor* original = JS_GetErrorInterceptorCallback(cx->runtime());
 
--- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp
+++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp
@@ -16,20 +16,20 @@ BEGIN_TEST(testGCFinalizeCallback) {
   JS_GC(cx);
   CHECK(cx->runtime()->gc.isFullGc());
   CHECK(checkSingleGroup());
   CHECK(checkFinalizeStatus());
 
   /* Full GC, incremental. */
   FinalizeCalls = 0;
   JS::PrepareForFullGC(cx);
-  JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
+  JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
   while (cx->runtime()->gc.isIncrementalGCInProgress()) {
     JS::PrepareForFullGC(cx);
-    JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
+    JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
   }
   CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
   CHECK(cx->runtime()->gc.isFullGc());
   CHECK(checkMultipleGroups());
   CHECK(checkFinalizeStatus());
 
 #ifdef JS_GC_ZEAL
   // Bug 1377593 - the below tests want to control how many zones are GC'ing,
@@ -42,55 +42,55 @@ BEGIN_TEST(testGCFinalizeCallback) {
   JS::RootedObject global3(cx, createTestGlobal());
   CHECK(global1);
   CHECK(global2);
   CHECK(global3);
 
   /* Zone GC, non-incremental, single zone. */
   FinalizeCalls = 0;
   JS::PrepareZoneForGC(global1->zone());
-  JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
+  JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
   CHECK(!cx->runtime()->gc.isFullGc());
   CHECK(checkSingleGroup());
   CHECK(checkFinalizeStatus());
 
   /* Zone GC, non-incremental, multiple zones. */
   FinalizeCalls = 0;
   JS::PrepareZoneForGC(global1->zone());
   JS::PrepareZoneForGC(global2->zone());
   JS::PrepareZoneForGC(global3->zone());
-  JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
+  JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
   CHECK(!cx->runtime()->gc.isFullGc());
   CHECK(checkSingleGroup());
   CHECK(checkFinalizeStatus());
 
   /* Zone GC, incremental, single zone. */
   FinalizeCalls = 0;
   JS::PrepareZoneForGC(global1->zone());
-  JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
+  JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
   while (cx->runtime()->gc.isIncrementalGCInProgress()) {
     JS::PrepareZoneForGC(global1->zone());
-    JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
+    JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
   }
   CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
   CHECK(!cx->runtime()->gc.isFullGc());
   CHECK(checkSingleGroup());
   CHECK(checkFinalizeStatus());
 
   /* Zone GC, incremental, multiple zones. */
   FinalizeCalls = 0;
   JS::PrepareZoneForGC(global1->zone());
   JS::PrepareZoneForGC(global2->zone());
   JS::PrepareZoneForGC(global3->zone());
-  JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
+  JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
   while (cx->runtime()->gc.isIncrementalGCInProgress()) {
     JS::PrepareZoneForGC(global1->zone());
     JS::PrepareZoneForGC(global2->zone());
     JS::PrepareZoneForGC(global3->zone());
-    JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
+    JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
   }
   CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
   CHECK(!cx->runtime()->gc.isFullGc());
   CHECK(checkMultipleGroups());
   CHECK(checkFinalizeStatus());
 
 #ifdef JS_GC_ZEAL
 
--- a/js/src/jsapi-tests/testGCGrayMarking.cpp
+++ b/js/src/jsapi-tests/testGCGrayMarking.cpp
@@ -459,17 +459,17 @@ bool TestCCWs() {
   CHECK(JS::IsIncrementalGCInProgress(cx));
 
   CHECK(!IsMarkedBlack(wrapper));
   CHECK(wrapper->zone()->isGCMarkingBlackOnly());
 
   CHECK(GetCrossCompartmentWrapper(target) == wrapper);
   CHECK(IsMarkedBlack(wrapper));
 
-  JS::FinishIncrementalGC(cx, JS::gcreason::API);
+  JS::FinishIncrementalGC(cx, JS::GCReason::API);
 
   // Test behaviour of gray CCWs marked black by a barrier during incremental
   // GC.
 
   // Initial state: source and target are gray.
   blackRoot = nullptr;
   grayRoots.grayRoot1 = wrapper;
   grayRoots.grayRoot2 = nullptr;
@@ -495,17 +495,17 @@ bool TestCCWs() {
   // that target is not marked gray; AssertObjectIsNotGray() will
   // assert.
   grayRoots.grayRoot1.get();
   CHECK(IsMarkedBlack(wrapper));
   CHECK(IsMarkedGray(target));
   CHECK(!JS::ObjectIsMarkedGray(target));
 
   // Final state: source and target are black.
-  JS::FinishIncrementalGC(cx, JS::gcreason::API);
+  JS::FinishIncrementalGC(cx, JS::GCReason::API);
   CHECK(IsMarkedBlack(wrapper));
   CHECK(IsMarkedBlack(target));
 
   grayRoots.grayRoot1 = nullptr;
   grayRoots.grayRoot2 = nullptr;
 
   return true;
 }
@@ -734,15 +734,15 @@ static bool CheckCellColor(Cell* cell, M
 }
 
 void EvictNursery() { cx->runtime()->gc.evictNursery(); }
 
 bool ZoneGC(JS::Zone* zone) {
   uint32_t oldMode = JS_GetGCParameter(cx, JSGC_MODE);
   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_ZONE);
   JS::PrepareZoneForGC(zone);
-  cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::API);
+  cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::API);
   CHECK(!cx->runtime()->gc.isFullGc());
   JS_SetGCParameter(cx, JSGC_MODE, oldMode);
   return true;
 }
 
 END_TEST(testGCGrayMarking)
--- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
+++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
@@ -126,26 +126,26 @@ bool TestHeapPostBarrierUpdate() {
     W& wrapper = testStruct->wrapper;
     CHECK(wrapper.get() == nullptr);
     wrapper = initialObj;
     CHECK(wrapper == initialObj);
 
     ptr = testStruct.release();
   }
 
-  cx->minorGC(JS::gcreason::API);
+  cx->minorGC(JS::GCReason::API);
 
   W& wrapper = ptr->wrapper;
   CHECK(uintptr_t(wrapper.get()) != initialObjAsInt);
   CHECK(!js::gc::IsInsideNursery(wrapper.get()));
   CHECK(CanAccessObject(wrapper.get()));
 
   JS::DeletePolicy<TestStruct<W>>()(ptr);
 
-  cx->minorGC(JS::gcreason::API);
+  cx->minorGC(JS::GCReason::API);
 
   return true;
 }
 
 template <typename T, typename W>
 bool TestHeapPostBarrierInitFailure() {
   // Failure case - allocate a heap object, write a nursery pointer into it
   // and fail to complete initialization.
@@ -161,17 +161,17 @@ bool TestHeapPostBarrierInitFailure() {
     W& wrapper = testStruct->wrapper;
     CHECK(wrapper.get() == nullptr);
     wrapper = initialObj;
     CHECK(wrapper == initialObj);
 
     // testStruct deleted here, as if we left this block due to an error.
   }
 
-  cx->minorGC(JS::gcreason::API);
+  cx->minorGC(JS::GCReason::API);
 
   return true;
 }
 
 END_TEST(testGCHeapPostBarriers)
 
 BEGIN_TEST(testUnbarrieredEquality) {
 #ifdef JS_GC_ZEAL
--- a/js/src/jsapi-tests/testGCHooks.cpp
+++ b/js/src/jsapi-tests/testGCHooks.cpp
@@ -15,17 +15,17 @@ static void NonIncrementalGCSliceCallbac
   using namespace JS;
   static GCProgress expect[] = {GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END,
                                 GC_CYCLE_END};
 
   MOZ_RELEASE_ASSERT(gSliceCallbackCount < mozilla::ArrayLength(expect));
   MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
   MOZ_RELEASE_ASSERT(desc.isZone_ == false);
   MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
-  MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
+  MOZ_RELEASE_ASSERT(desc.reason_ == JS::GCReason::API);
   if (progress == GC_CYCLE_END) {
     mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
     mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
     mozilla::UniquePtr<char16_t> json(desc.formatJSONTelemetry(cx, 0));
   }
 }
 
 BEGIN_TEST(testGCSliceCallback) {
@@ -36,26 +36,27 @@ BEGIN_TEST(testGCSliceCallback) {
   CHECK(gSliceCallbackCount == 4);
   return true;
 }
 END_TEST(testGCSliceCallback)
 
 static void RootsRemovedGCSliceCallback(JSContext* cx, JS::GCProgress progress,
                                         const JS::GCDescription& desc) {
   using namespace JS;
-  using namespace JS::gcreason;
 
   static GCProgress expectProgress[] = {
       GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END,   GC_SLICE_BEGIN,
       GC_SLICE_END,   GC_CYCLE_END,   GC_CYCLE_BEGIN, GC_SLICE_BEGIN,
       GC_SLICE_END,   GC_CYCLE_END};
 
-  static Reason expectReasons[] = {
-      DEBUG_GC, DEBUG_GC,      DEBUG_GC,      DEBUG_GC,      DEBUG_GC,
-      DEBUG_GC, ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED};
+  static GCReason expectReasons[] = {
+      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,
+      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,      GCReason::DEBUG_GC,
+      GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED,
+      GCReason::ROOTS_REMOVED};
 
   static_assert(
       mozilla::ArrayLength(expectProgress) ==
           mozilla::ArrayLength(expectReasons),
       "expectProgress and expectReasons arrays should be the same length");
 
   MOZ_RELEASE_ASSERT(gSliceCallbackCount <
                      mozilla::ArrayLength(expectProgress));
@@ -82,17 +83,17 @@ BEGIN_TEST(testGCRootsRemoved) {
   JS::PrepareForFullGC(cx);
   js::SliceBudget budget(js::WorkBudget(1));
   cx->runtime()->gc.startDebugGC(GC_SHRINK, budget);
   CHECK(JS::IsIncrementalGCInProgress(cx));
 
   // Trigger another GC after the current one in shrinking / shutdown GCs.
   cx->runtime()->gc.notifyRootsRemoved();
 
-  JS::FinishIncrementalGC(cx, JS::gcreason::DEBUG_GC);
+  JS::FinishIncrementalGC(cx, JS::GCReason::DEBUG_GC);
   CHECK(!JS::IsIncrementalGCInProgress(cx));
 
   JS::SetGCSliceCallback(cx, nullptr);
 
   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_GLOBAL);
 
   return true;
 }
--- a/js/src/jsapi-tests/testGCMarking.cpp
+++ b/js/src/jsapi-tests/testGCMarking.cpp
@@ -336,17 +336,17 @@ BEGIN_TEST(testIncrementalRoots) {
   // This is marked during markRuntime
   JS::AutoObjectVector vec(cx);
   if (!vec.append(root)) {
     return false;
   }
 
   // Tenure everything so intentionally unrooted objects don't move before we
   // can use them.
-  cx->runtime()->gc.minorGC(JS::gcreason::API);
+  cx->runtime()->gc.minorGC(JS::GCReason::API);
 
   // Release all roots except for the AutoObjectVector.
   obj = root = nullptr;
 
   // We need to manipulate interior nodes, but the JSAPI understandably wants
   // to make it difficult to do that without rooting things on the stack (by
   // requiring Handle parameters). We can do it anyway by using
   // fromMarkedLocation. The hazard analysis is OK with this because the
--- a/js/src/jsapi-tests/testGCUniqueId.cpp
+++ b/js/src/jsapi-tests/testGCUniqueId.cpp
@@ -105,17 +105,17 @@ BEGIN_TEST(testGCUID) {
   CHECK(obj);
   CHECK(!js::gc::IsInsideNursery(obj));
   tenuredAddr = uintptr_t(obj.get());
   CHECK(obj->zone()->getOrCreateUniqueId(obj, &uid));
 
   // Force a compaction to move the object and check that the uid moved to
   // the new tenured heap location.
   JS::PrepareForFullGC(cx);
-  JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::API);
+  JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
 
   // There's a very low probability that this check could fail, but it is
   // possible.  If it becomes an annoying intermittent then we should make
   // this test more robust by recording IDs of many objects and then checking
   // that some have moved.
   CHECK(uintptr_t(obj.get()) != tenuredAddr);
   CHECK(obj->zone()->hasUniqueId(obj));
   CHECK(obj->zone()->getOrCreateUniqueId(obj, &tmp));
--- a/js/src/jsapi-tests/testGCWeakCache.cpp
+++ b/js/src/jsapi-tests/testGCWeakCache.cpp
@@ -244,17 +244,17 @@ bool GCUntilCacheSweep(JSContext* cx, co
   return true;
 }
 
 template <typename Cache>
 bool SweepCacheAndFinishGC(JSContext* cx, const Cache& cache) {
   CHECK(IsIncrementalGCInProgress(cx));
 
   PrepareForIncrementalGC(cx);
-  IncrementalGCSlice(cx, JS::gcreason::API);
+  IncrementalGCSlice(cx, JS::GCReason::API);
 
   JS::Zone* zone = JS::GetObjectZone(global);
   CHECK(!IsIncrementalGCInProgress(cx));
   CHECK(!zone->isCollecting());
   CHECK(!cache.needsIncrementalBarrier());
 
   return true;
 }
--- a/js/src/jsapi-tests/testGCWeakRef.cpp
+++ b/js/src/jsapi-tests/testGCWeakRef.cpp
@@ -23,17 +23,17 @@ BEGIN_TEST(testGCWeakRef) {
   JS::RootedObject obj(cx, JS_NewPlainObject(cx));
   CHECK(obj);
   CHECK(JS_DefineProperty(cx, obj, "x", 42, 0));
 
   // Store the object behind a weak pointer and remove other references.
   JS::Rooted<MyHeap> heap(cx, MyHeap(obj));
   obj = nullptr;
 
-  cx->runtime()->gc.minorGC(JS::gcreason::API);
+  cx->runtime()->gc.minorGC(JS::GCReason::API);
 
   // The minor collection should have treated the weak ref as a strong ref,
   // so the object should still be live, despite not having any other live
   // references.
   CHECK(heap.get().weak.unbarrieredGet() != nullptr);
   obj = heap.get().weak;
   JS::RootedValue v(cx);
   CHECK(JS_GetProperty(cx, obj, "x", &v));
--- a/js/src/jsapi-tests/testPreserveJitCode.cpp
+++ b/js/src/jsapi-tests/testPreserveJitCode.cpp
@@ -70,20 +70,20 @@ bool testPreserveJitCode(bool preserveJi
   RootedValue value(cx);
   for (unsigned i = 0; i < 1500; ++i) {
     CHECK(JS_CallFunction(cx, global, fun, JS::HandleValueArray::empty(),
                           &value));
   }
   CHECK_EQUAL(value.toInt32(), 45);
   CHECK_EQUAL(countIonScripts(global), 1u);
 
-  NonIncrementalGC(cx, GC_NORMAL, gcreason::API);
+  NonIncrementalGC(cx, GC_NORMAL, GCReason::API);
   CHECK_EQUAL(countIonScripts(global), remainingIonScripts);
 
-  NonIncrementalGC(cx, GC_SHRINK, gcreason::API);
+  NonIncrementalGC(cx, GC_SHRINK, GCReason::API);
   CHECK_EQUAL(countIonScripts(global), 0u);
 
   return true;
 }
 
 JSObject* createTestGlobal(bool preserveJitCode) {
   JS::RealmOptions options;
   options.creationOptions().setPreserveJitCode(preserveJitCode);
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -493,17 +493,17 @@ class AutoLeaveZeal {
   uint32_t frequency_;
 
  public:
   explicit AutoLeaveZeal(JSContext* cx) : cx_(cx), zealBits_(0), frequency_(0) {
     uint32_t dummy;
     JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
     JS_SetGCZeal(cx_, 0, 0);
     JS::PrepareForFullGC(cx_);
-    JS::NonIncrementalGC(cx_, GC_SHRINK, JS::gcreason::DEBUG_GC);
+    JS::NonIncrementalGC(cx_, GC_SHRINK, JS::GCReason::DEBUG_GC);
   }
   ~AutoLeaveZeal() {
     JS_SetGCZeal(cx_, 0, 0);
     for (size_t i = 0; i < sizeof(zealBits_) * 8; i++) {
       if (zealBits_ & (1 << i)) {
         JS_SetGCZeal(cx_, i, frequency_);
       }
     }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1162,24 +1162,24 @@ JS_PUBLIC_API void JS_RemoveExtraGCRoots
 JS_PUBLIC_API bool JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
   // Currently, we only collect nursery during idle time.
   return rt->gc.nursery().needIdleTimeCollection();
 }
 
 JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
   gc::GCRuntime& gc = rt->gc;
   if (gc.nursery().needIdleTimeCollection()) {
-    gc.minorGC(JS::gcreason::IDLE_TIME_COLLECTION);
+    gc.minorGC(JS::GCReason::IDLE_TIME_COLLECTION);
   }
 }
 
 JS_PUBLIC_API void JS_GC(JSContext* cx) {
   AssertHeapIsIdle();
   JS::PrepareForFullGC(cx);
-  cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::API);
+  cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::API);
 }
 
 JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
   gc::GCRuntime& gc = cx->runtime()->gc;
   gc.maybeGC(cx->zone());
 }
 
 JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb,
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1113,17 +1113,17 @@ void DumpHeapTracer::onChild(const JS::G
   getTracingEdgeName(buffer, sizeof(buffer));
   fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(),
           MarkDescriptor(thing.asCell()), buffer);
 }
 
 void js::DumpHeap(JSContext* cx, FILE* fp,
                   js::DumpHeapNurseryBehaviour nurseryBehaviour) {
   if (nurseryBehaviour == js::CollectNurseryBeforeDump) {
-    cx->runtime()->gc.evictNursery(JS::gcreason::API);
+    cx->runtime()->gc.evictNursery(JS::GCReason::API);
   }
 
   DumpHeapTracer dtrc(fp, cx);
 
   fprintf(dtrc.output, "# Roots.\n");
   {
     JSRuntime* rt = cx->runtime();
     js::gc::AutoTraceSession session(rt);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1835,17 +1835,17 @@ static void my_LargeAllocFailCallback() 
   JSContext* cx = TlsContext.get();
   if (!cx || cx->helperThread()) {
     return;
   }
 
   MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
 
   JS::PrepareForFullGC(cx);
-  cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
+  cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::SHARED_MEMORY_LIMIT);
 }
 
 static const uint32_t CacheEntry_SOURCE = 0;
 static const uint32_t CacheEntry_BYTECODE = 1;
 
 static const JSClass CacheEntry_class = {"CacheEntryObject",
                                          JSCLASS_HAS_RESERVED_SLOTS(2)};
 
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -841,22 +841,22 @@ static bool CreateBuffer(
     return false;
   }
 
   maybeSharedObject.set(object);
 
   // See MaximumLiveMappedBuffers comment above.
   if (liveBufferCount > StartSyncFullGCAtLiveBufferCount) {
     JS::PrepareForFullGC(cx);
-    JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::TOO_MUCH_WASM_MEMORY);
+    JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::TOO_MUCH_WASM_MEMORY);
     allocatedSinceLastTrigger = 0;
   } else if (liveBufferCount > StartTriggeringAtLiveBufferCount) {
     allocatedSinceLastTrigger++;
     if (allocatedSinceLastTrigger > AllocatedBuffersPerTrigger) {
-      Unused << cx->runtime()->gc.triggerGC(JS::gcreason::TOO_MUCH_WASM_MEMORY);
+      Unused << cx->runtime()->gc.triggerGC(JS::GCReason::TOO_MUCH_WASM_MEMORY);
       allocatedSinceLastTrigger = 0;
     }
   } else {
     allocatedSinceLastTrigger = 0;
   }
 
   if (maxSize) {
 #ifdef WASM_HUGE_MEMORY
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -12390,17 +12390,17 @@ namespace dbg {
   data->nonincrementalReason = stats.nonincrementalReason();
 
   for (auto& slice : stats.slices()) {
     if (!data->reason) {
       // There is only one GC reason for the whole cycle, but for legacy
       // reasons this data is stored and replicated on each slice. Each
       // slice used to have its own GCReason, but now they are all the
       // same.
-      data->reason = gcreason::ExplainReason(slice.reason);
+      data->reason = ExplainGCReason(slice.reason);
       MOZ_ASSERT(data->reason);
     }
 
     if (!data->collections.growBy(1)) {
       return nullptr;
     }
 
     data->collections.back().startTimestamp = slice.start;
--- a/js/src/vm/JSContext-inl.h
+++ b/js/src/vm/JSContext-inl.h
@@ -300,17 +300,17 @@ MOZ_ALWAYS_INLINE bool CheckForInterrupt
 } /* namespace js */
 
 inline js::LifoAlloc& JSContext::typeLifoAlloc() {
   return zone()->types.typeLifoAlloc();
 }
 
 inline js::Nursery& JSContext::nursery() { return runtime()->gc.nursery(); }
 
-inline void JSContext::minorGC(JS::gcreason::Reason reason) {
+inline void JSContext::minorGC(JS::GCReason reason) {
   runtime()->gc.minorGC(reason);
 }
 
 inline void JSContext::setPendingException(JS::HandleValue v) {
 #if defined(NIGHTLY_BUILD)
   do {
     // Do not intercept exceptions if we are already
     // in the exception interceptor. That would lead
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -735,17 +735,17 @@ struct JSContext : public JS::RootingCon
    * overridden by passing AllowCrossRealm::Allow.
    */
   enum class AllowCrossRealm { DontAllow = false, Allow = true };
   inline JSScript* currentScript(
       jsbytecode** pc = nullptr,
       AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow) const;
 
   inline js::Nursery& nursery();
-  inline void minorGC(JS::gcreason::Reason reason);
+  inline void minorGC(JS::GCReason reason);
 
  public:
   bool isExceptionPending() const { return throwing; }
 
   MOZ_MUST_USE
   bool getPendingException(JS::MutableHandleValue rval);
 
   bool isThrowingOutOfMemory();
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -4197,16 +4197,20 @@ void JSObject::traceChildren(JSTracer* t
     } while (false);
   }
 
   // Call the trace hook at the end so that during a moving GC the trace hook
   // will see updated fields and slots.
   if (clasp->hasTrace()) {
     clasp->doTrace(trc, this);
   }
+
+  if (trc->isMarkingTracer()) {
+    GCMarker::fromTracer(trc)->markImplicitEdges(this);
+  }
 }
 
 static JSAtom* displayAtomFromObjectGroup(ObjectGroup& group) {
   AutoSweepObjectGroup sweep(&group);
   TypeNewScript* script = group.newScript(sweep);
   if (!script) {
     return nullptr;
   }
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -4406,17 +4406,17 @@ void JSScript::traceChildren(JSTracer* t
 
   if (trc->isMarkingTracer()) {
     realm()->mark();
   }
 
   jit::TraceJitScripts(trc, this);
 
   if (trc->isMarkingTracer()) {
-    return GCMarker::fromTracer(trc)->markImplicitEdges(this);
+    GCMarker::fromTracer(trc)->markImplicitEdges(this);
   }
 }
 
 void LazyScript::finalize(FreeOp* fop) { fop->free_(table_); }
 
 size_t JSScript::calculateLiveFixed(jsbytecode* pc) {
   size_t nlivefixed = numAlwaysLiveFixedSlots();
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -275,17 +275,17 @@ void JSRuntime::destroyRuntime() {
      * interned atoms and Ion trampolines.
      */
     beingDestroyed_ = true;
 
     /* Allow the GC to release scripts that were being profiled. */
     profilingScripts = false;
 
     JS::PrepareForFullGC(cx);
-    gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
+    gc.gc(GC_NORMAL, JS::GCReason::DESTROY_RUNTIME);
   }
 
   AutoNoteSingleThreadedRegion anstr;
 
   MOZ_ASSERT(!hasHelperThreadZones());
 
   /*
    * Even though all objects in the compartment are dead, we may have keep
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -146,17 +146,17 @@ static inline void GetterSetterWriteBarr
     if (!nurseryShapes.append(shape)) {
       oomUnsafe.crash("GetterSetterWriteBarrierPost");
     }
   }
 
   if (nurseryShapes.length() == 1) {
     sb->putGeneric(NurseryShapesRef(shape->zone()));
   } else if (nurseryShapes.length() == MaxShapeVectorLength) {
-    sb->setAboutToOverflow(JS::gcreason::FULL_SHAPE_BUFFER);
+    sb->setAboutToOverflow(JS::GCReason::FULL_SHAPE_BUFFER);
   }
 }
 
 inline AccessorShape::AccessorShape(const StackShape& other, uint32_t nfixed)
     : Shape(other, nfixed),
       rawGetter(other.rawGetter),
       rawSetter(other.rawSetter) {
   MOZ_ASSERT(getAllocKind() == gc::AllocKind::ACCESSOR_SHAPE);
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -1632,17 +1632,17 @@ nsXPCComponents_Utils::GetWeakReference(
   ref.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceGC() {
   JSContext* cx = XPCJSContext::Get()->Context();
   PrepareForFullGC(cx);
-  NonIncrementalGC(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
+  NonIncrementalGC(cx, GC_NORMAL, GCReason::COMPONENT_UTILS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) {
   nsJSContext::CycleCollectNow(listener);
   return NS_OK;
 }
@@ -1678,30 +1678,30 @@ nsXPCComponents_Utils::ClearMaxCCTime() 
   nsJSContext::ClearMaxCCSliceTime();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceShrinkingGC() {
   JSContext* cx = dom::danger::GetJSContext();
   PrepareForFullGC(cx);
-  NonIncrementalGC(cx, GC_SHRINK, gcreason::COMPONENT_UTILS);
+  NonIncrementalGC(cx, GC_SHRINK, GCReason::COMPONENT_UTILS);
   return NS_OK;
 }
 
 class PreciseGCRunnable : public Runnable {
  public:
   PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking)
       : mozilla::Runnable("PreciseGCRunnable"),
         mCallback(aCallback),
         mShrinking(aShrinking) {}
 
   NS_IMETHOD Run() override {
     nsJSContext::GarbageCollectNow(
-        gcreason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
+        GCReason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
         mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
 
     mCallback->Callback();
     return NS_OK;
   }
 
  private:
   RefPtr<ScheduledGCCallback> mCallback;
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -86,27 +86,27 @@ nsXPConnect::~nsXPConnect() {
   mRuntime->DeleteSingletonScopes();
 
   // In order to clean up everything properly, we need to GC twice: once now,
   // to clean anything that can go away on its own (like the Junk Scope, which
   // we unrooted above), and once after forcing a bunch of shutdown in
   // XPConnect, to clean the stuff we forcibly disconnected. The forced
   // shutdown code defaults to leaking in a number of situations, so we can't
   // get by with only the second GC. :-(
-  mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
+  mRuntime->GarbageCollect(JS::GCReason::XPCONNECT_SHUTDOWN);
 
   mShuttingDown = true;
   XPCWrappedNativeScope::SystemIsBeingShutDown();
   mRuntime->SystemIsBeingShutDown();
 
   // The above causes us to clean up a bunch of XPConnect data structures,
   // after which point we need to GC to clean everything up. We need to do
   // this before deleting the XPCJSContext, because doing so destroys the
   // maps that our finalize callback depends on.
-  mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
+  mRuntime->GarbageCollect(JS::GCReason::XPCONNECT_SHUTDOWN);
 
   NS_RELEASE(gSystemPrincipal);
   gScriptSecurityManager = nullptr;
 
   // shutdown the logging system
   XPC_LOG_FINISH();
 
   delete gPrimaryContext;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1151,17 +1151,17 @@ nsDocumentViewer::LoadComplete(nsresult 
   // Release the JS bytecode cache from its wait on the load event, and
   // potentially dispatch the encoding of the bytecode.
   if (mDocument && mDocument->ScriptLoader()) {
     mDocument->ScriptLoader()->LoadEventFired();
   }
 
   // It's probably a good idea to GC soon since we have finished loading.
   nsJSContext::PokeGC(
-      JS::gcreason::LOAD_END,
+      JS::GCReason::LOAD_END,
       mDocument ? mDocument->GetWrapperPreserveColor() : nullptr);
 
 #ifdef NS_PRINTING
   // Check to see if someone tried to print during the load
   if (mPrintIsPending) {
     mPrintIsPending = false;
     mPrintDocIsFullyLoaded = true;
     Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
@@ -1407,17 +1407,17 @@ nsDocumentViewer::PageHide(bool aIsUnloa
   mHidden = true;
 
   if (!mDocument) {
     return NS_ERROR_NULL_POINTER;
   }
 
   if (aIsUnload) {
     // Poke the GC. The window might be collectable garbage now.
-    nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
+    nsJSContext::PokeGC(JS::GCReason::PAGE_HIDE,
                         mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
   }
 
   mDocument->OnPageHide(!aIsUnload, nullptr);
 
   // inform the window so that the focus state is reset.
   NS_ENSURE_STATE(mDocument);
   nsPIDOMWindowOuter* window = mDocument->GetWindow();
@@ -2356,17 +2356,17 @@ UniquePtr<ServoStyleSet> nsDocumentViewe
   }
 
   return styleSet;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::ClearHistoryEntry() {
   if (mDocument) {
-    nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
+    nsJSContext::PokeGC(JS::GCReason::PAGE_HIDE,
                         mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
   }
 
   mSHEntry = nullptr;
   return NS_OK;
 }
 
 //-------------------------------------------------------
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -556,25 +556,25 @@ VARCACHE_PREF(
 )
 
 // Time in milliseconds between the time a network buffer is seen and the timer
 // firing when the timer hasn't fired previously in this parse in the
 // off-the-main-thread HTML5 parser.
 VARCACHE_PREF(
   "html5.flushtimer.initialdelay",
    html5_flushtimer_initialdelay,
-  RelaxedAtomicInt32, 120
+  RelaxedAtomicInt32, 16
 )
 
 // Time in milliseconds between the time a network buffer is seen and the timer
 // firing when the timer has already fired previously in this parse.
 VARCACHE_PREF(
   "html5.flushtimer.subsequentdelay",
    html5_flushtimer_subsequentdelay,
-  RelaxedAtomicInt32, 120
+  RelaxedAtomicInt32, 16
 )
 
 //---------------------------------------------------------------------------
 // Layout prefs
 //---------------------------------------------------------------------------
 
 // Debug-only pref to force enable the AccessibleCaret. If you want to
 // control AccessibleCaret by mouse, you'll need to set
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -858,17 +858,17 @@ void nsHtml5StreamParser::CommitLocalFil
 
 class MaybeRunCollector : public Runnable {
  public:
   explicit MaybeRunCollector(nsIDocShell* aDocShell)
       : Runnable("MaybeRunCollector"), mDocShell(aDocShell) {}
 
   NS_IMETHOD Run() override {
     nsJSContext::MaybeRunNextCollectorSlice(mDocShell,
-                                            JS::gcreason::HTML_PARSER);
+                                            JS::GCReason::HTML_PARSER);
     return NS_OK;
   }
 
   nsCOMPtr<nsIDocShell> mDocShell;
 };
 
 nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest,
                                              nsISupports* aContext) {
--- a/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py
+++ b/toolkit/components/telemetry/build_scripts/mozparsers/parse_histograms.py
@@ -542,17 +542,17 @@ the histogram."""
 
         # For the server-side, where _strict_type_checks==False, we want to
         # skip the stricter type checks for these fields for dealing with
         # historical data.
         coerce_fields = ["low", "high", "n_values", "n_buckets"]
         if not self._strict_type_checks:
             # This handles some old non-numeric expressions.
             EXPRESSIONS = {
-                "JS::gcreason::NUM_TELEMETRY_REASONS": 101,
+                "JS::GCReason::NUM_TELEMETRY_REASONS": 101,
                 "mozilla::StartupTimeline::MAX_EVENT_ID": 12,
             }
 
             def try_to_coerce_to_number(v):
                 if v in EXPRESSIONS:
                     return EXPRESSIONS[v]
                 try:
                     return eval(v, {})
--- a/toolkit/components/telemetry/core/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.cpp
@@ -2337,21 +2337,21 @@ void TelemetryHistogram::InitializeGloba
         new KeyedHistogram* [HistogramCount * size_t(ProcessID::Count)] {};
   }
 
   // Some Telemetry histograms depend on the value of C++ constants and hardcode
   // their values in Histograms.json.
   // We add static asserts here for those values to match so that future changes
   // don't go unnoticed.
   // clang-format off
-  static_assert((JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
+  static_assert((uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
       gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON].bucketCount &&
-      (JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
+      (uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
       gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON_LONG].bucketCount &&
-      (JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
+      (uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
       gHistogramInfos[mozilla::Telemetry::GC_REASON_2].bucketCount,
       "NUM_TELEMETRY_REASONS is assumed to be a fixed value in Histograms.json."
       " If this was an intentional change, update the n_values for the "
       "following in Histograms.json: GC_MINOR_REASON, GC_MINOR_REASON_LONG, "
       "GC_REASON_2");
 
   static_assert((mozilla::StartupTimeline::MAX_EVENT_ID + 1) ==
       gHistogramInfos[mozilla::Telemetry::STARTUP_MEASUREMENT_ERRORS].bucketCount,
--- a/toolkit/components/telemetry/tests/python/test_histogramtools_non_strict.py
+++ b/toolkit/components/telemetry/tests/python/test_histogramtools_non_strict.py
@@ -47,17 +47,17 @@ class TestParser(unittest.TestCase):
         self.assertEqual(hist.kind(), 'flag')
         self.assertEqual(hist.record_in_processes(), ["main", "content"])
 
     def test_non_numeric_expressions(self):
         SAMPLE_HISTOGRAM = {
             "TEST_NON_NUMERIC_HISTOGRAM": {
                 "kind": "linear",
                 "description": "sample",
-                "n_buckets": "JS::gcreason::NUM_TELEMETRY_REASONS",
+                "n_buckets": "JS::GCReason::NUM_TELEMETRY_REASONS",
                 "high": "mozilla::StartupTimeline::MAX_EVENT_ID"
                 }}
 
         histograms = load_histogram(SAMPLE_HISTOGRAM)
         hist = parse_histograms.Histogram('TEST_NON_NUMERIC_HISTOGRAM',
                                           histograms['TEST_NON_NUMERIC_HISTOGRAM'],
                                           strict_type_checks=False)
 
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -809,70 +809,70 @@ void CycleCollectedJSRuntime::TraverseNa
               aDesc.lastSliceStart(aContext), aDesc.lastSliceEnd(aContext),
               aDesc.sliceToJSONProfiler(aContext)));
     }
   }
 #endif
 
   if (aProgress == JS::GC_CYCLE_END &&
       JS::dbg::FireOnGarbageCollectionHookRequired(aContext)) {
-    JS::gcreason::Reason reason = aDesc.reason_;
+    JS::GCReason reason = aDesc.reason_;
     Unused << NS_WARN_IF(
         NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) &&
-        reason != JS::gcreason::SHUTDOWN_CC &&
-        reason != JS::gcreason::DESTROY_RUNTIME &&
-        reason != JS::gcreason::XPCONNECT_SHUTDOWN);
+        reason != JS::GCReason::SHUTDOWN_CC &&
+        reason != JS::GCReason::DESTROY_RUNTIME &&
+        reason != JS::GCReason::XPCONNECT_SHUTDOWN);
   }
 
   if (self->mPrevGCSliceCallback) {
     self->mPrevGCSliceCallback(aContext, aProgress, aDesc);
   }
 }
 
 class MinorGCMarker : public TimelineMarker {
  private:
-  JS::gcreason::Reason mReason;
+  JS::GCReason mReason;
 
  public:
-  MinorGCMarker(MarkerTracingType aTracingType, JS::gcreason::Reason aReason)
+  MinorGCMarker(MarkerTracingType aTracingType, JS::GCReason aReason)
       : TimelineMarker("MinorGC", aTracingType, MarkerStackRequest::NO_STACK),
         mReason(aReason) {
     MOZ_ASSERT(aTracingType == MarkerTracingType::START ||
                aTracingType == MarkerTracingType::END);
   }
 
-  MinorGCMarker(JS::GCNurseryProgress aProgress, JS::gcreason::Reason aReason)
+  MinorGCMarker(JS::GCNurseryProgress aProgress, JS::GCReason aReason)
       : TimelineMarker(
             "MinorGC",
             aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START
                 ? MarkerTracingType::START
                 : MarkerTracingType::END,
             MarkerStackRequest::NO_STACK),
         mReason(aReason) {}
 
   virtual void AddDetails(JSContext* aCx,
                           dom::ProfileTimelineMarker& aMarker) override {
     TimelineMarker::AddDetails(aCx, aMarker);
 
     if (GetTracingType() == MarkerTracingType::START) {
-      auto reason = JS::gcreason::ExplainReason(mReason);
+      auto reason = JS::ExplainGCReason(mReason);
       aMarker.mCauseName.Construct(NS_ConvertUTF8toUTF16(reason));
     }
   }
 
   virtual UniquePtr<AbstractTimelineMarker> Clone() override {
     auto clone = MakeUnique<MinorGCMarker>(GetTracingType(), mReason);
     clone->SetCustomTime(GetTime());
     return UniquePtr<AbstractTimelineMarker>(std::move(clone));
   }
 };
 
 /* static */ void CycleCollectedJSRuntime::GCNurseryCollectionCallback(
     JSContext* aContext, JS::GCNurseryProgress aProgress,
-    JS::gcreason::Reason aReason) {
+    JS::GCReason aReason) {
   CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
   MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext);
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
   if (timelines && !timelines->IsEmpty()) {
     UniquePtr<AbstractTimelineMarker> abstractMarker(
         MakeUnique<MinorGCMarker>(aProgress, aReason));
@@ -1120,23 +1120,20 @@ void CycleCollectedJSRuntime::CheckGrayB
   MOZ_ASSERT(CheckWeakMappingGrayBitsTracer::Check(mJSRuntime));
 #endif
 }
 
 bool CycleCollectedJSRuntime::AreGCGrayBitsValid() const {
   return js::AreGCGrayBitsValid(mJSRuntime);
 }
 
-void CycleCollectedJSRuntime::GarbageCollect(uint32_t aReason) const {
-  MOZ_ASSERT(aReason < JS::gcreason::NUM_REASONS);
-  JS::gcreason::Reason gcreason = static_cast<JS::gcreason::Reason>(aReason);
-
+void CycleCollectedJSRuntime::GarbageCollect(JS::GCReason aReason) const {
   JSContext* cx = CycleCollectedJSContext::Get()->Context();
   JS::PrepareForFullGC(cx);
-  JS::NonIncrementalGC(cx, GC_NORMAL, gcreason);
+  JS::NonIncrementalGC(cx, GC_NORMAL, aReason);
 }
 
 void CycleCollectedJSRuntime::JSObjectsTenured() {
   for (auto iter = mNurseryObjects.Iter(); !iter.Done(); iter.Next()) {
     nsWrapperCache* cache = iter.Get();
     JSObject* wrapper = cache->GetWrapperMaybeDead();
     MOZ_DIAGNOSTIC_ASSERT(wrapper || recordreplay::IsReplaying());
     if (!JS::ObjectIsTenured(wrapper)) {
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -152,17 +152,17 @@ class CycleCollectedJSRuntime {
 
   static void TraceBlackJS(JSTracer* aTracer, void* aData);
   static void TraceGrayJS(JSTracer* aTracer, void* aData);
   static void GCCallback(JSContext* aContext, JSGCStatus aStatus, void* aData);
   static void GCSliceCallback(JSContext* aContext, JS::GCProgress aProgress,
                               const JS::GCDescription& aDesc);
   static void GCNurseryCollectionCallback(JSContext* aContext,
                                           JS::GCNurseryProgress aProgress,
-                                          JS::gcreason::Reason aReason);
+                                          JS::GCReason aReason);
   static void OutOfMemoryCallback(JSContext* aContext, void* aData);
   /**
    * Callback for reporting external string memory.
    */
   static size_t SizeofExternalStringCallback(
       JSString* aStr, mozilla::MallocSizeOf aMallocSizeOf);
 
   static bool ContextCallback(JSContext* aCx, unsigned aOperation, void* aData);
@@ -259,17 +259,17 @@ class CycleCollectedJSRuntime {
   nsCycleCollectionParticipant* GCThingParticipant();
   nsCycleCollectionParticipant* ZoneParticipant();
 
   nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb);
   virtual bool UsefulToMergeZones() const;
   void FixWeakMappingGrayBits() const;
   void CheckGrayBits() const;
   bool AreGCGrayBitsValid() const;
-  void GarbageCollect(uint32_t aReason) const;
+  void GarbageCollect(JS::GCReason aReason) const;
 
   // This needs to be an nsWrapperCache, not a JSObject, because we need to know
   // when our object gets moved.  But we can't trace it (and hence update our
   // storage), because we do not want to keep it alive.  nsWrapperCache handles
   // this for us via its "object moved" handling.
   void NurseryWrapperAdded(nsWrapperCache* aCache);
   void NurseryWrapperPreserved(JSObject* aWrapper);
   void JSObjectsTenured();
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -3267,18 +3267,18 @@ void nsCycleCollector::FixGrayBits(bool 
     if (!needGC) {
       return;
     }
     mResults.mForcedGC = true;
   }
 
   uint32_t count = 0;
   do {
-    mCCJSRuntime->GarbageCollect(aForceGC ? JS::gcreason::SHUTDOWN_CC
-                                          : JS::gcreason::CC_FORCED);
+    mCCJSRuntime->GarbageCollect(aForceGC ? JS::GCReason::SHUTDOWN_CC
+                                          : JS::GCReason::CC_FORCED);
 
     mCCJSRuntime->FixWeakMappingGrayBits();
 
     // It's possible that FixWeakMappingGrayBits will hit OOM when unmarking
     // gray and we will have to go round again. The second time there should not
     // be any weak mappings to fix up so the loop body should run at most twice.
     MOZ_RELEASE_ASSERT(count < 2);
     count++;
@@ -3291,17 +3291,17 @@ bool nsCycleCollector::IsIncrementalGCIn
   return mCCJSRuntime && JS::IsIncrementalGCInProgress(mCCJSRuntime->Runtime());
 }
 
 void nsCycleCollector::FinishAnyIncrementalGCInProgress() {
   if (IsIncrementalGCInProgress()) {
     NS_WARNING("Finishing incremental GC in progress during CC");
     JSContext* cx = CycleCollectedJSContext::Get()->Context();
     JS::PrepareForIncrementalGC(cx);
-    JS::FinishIncrementalGC(cx, JS::gcreason::CC_FORCED);
+    JS::FinishIncrementalGC(cx, JS::GCReason::CC_FORCED);
   }
 }
 
 void nsCycleCollector::CleanupAfterCollection() {
   TimeLog timeLog;
   MOZ_ASSERT(mIncrementalPhase == CleanupPhase);
   MOZ_RELEASE_ASSERT(!mScanInProgress);
   mGraph.Clear();