static PLDHashOperator
TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
{
  if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
    TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
    aWindow->TraceGlobalJSObject(closure->mTrc);
#ifdef MOZ_XUL
    nsIDocument* doc = aWindow->GetExtantDoc();
    if (doc && doc->IsXUL()) {
      XULDocument* xulDoc = static_cast<XULDocument*>(doc);
      xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
    }
#endif
  }
  return PL_DHASH_NEXT;
}
void
mozilla::dom::TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC)
{
#ifdef MOZ_XUL
  // Mark the scripts held in the XULPrototypeCache. This is required to keep
  // the JS script in the cache live across GC.
  nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
  if (cache) {
    if (aIsShutdownGC) {
      cache->FlushScripts();
    } else {
      cache->MarkInGC(aTrc);
    }
  }
#endif

  if (!nsCCUncollectableMarker::sGeneration) {
    return;
  }

  if (ContentProcessMessageManager::WasCreated() &&
      nsFrameMessageManager::GetChildProcessManager()) {
    auto* pg = ContentProcessMessageManager::Get();
    if (pg) {
      mozilla::TraceScriptHolder(ToSupports(pg), aTrc);
    }
  }

  // Mark globals of active windows black.
  nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
    nsGlobalWindowOuter::GetWindowsTable();
  if (windowsById) {
    for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
      nsGlobalWindowOuter* window = iter.Data();
      if (!window->IsCleanedUp()) {
        nsGlobalWindowInner* inner = nullptr;
        for (PRCList* win = PR_LIST_HEAD(window);
             win != window;
             win = PR_NEXT_LINK(inner)) {
          inner = static_cast<nsGlobalWindowInner*>(win);
          if (inner->IsCurrentInnerWindow() ||
              (inner->GetExtantDoc() &&
               inner->GetExtantDoc()->GetBFCacheEntry())) {
            inner->TraceGlobalJSObject(aTrc);
            EventListenerManager* elm = inner->GetExistingListenerManager();
            if (elm) {
              elm->TraceListeners(aTrc);
            }
          }
        }

        if (window->IsRootOuterWindow()) {
          // In child process trace all the TabChildMessageManagers.
          // Since there is one root outer window per TabChildMessageManager, we need
          // to look for only those windows, not all.
          nsIDocShell* ds = window->GetDocShell();
          if (ds) {
            nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild();
            if (tabChild) {
              RefPtr<ContentFrameMessageManager> mm;
              tabChild->GetMessageManager(getter_AddRefs(mm));
              if (mm) {
                nsCOMPtr<nsISupports> tabChildAsSupports =
                  do_QueryInterface(tabChild);
                mozilla::TraceScriptHolder(tabChildAsSupports, aTrc);
                EventListenerManager* elm = mm->GetExistingListenerManager();
                if (elm) {
                  elm->TraceListeners(aTrc);
                }
                // As of now there isn't an easy way to trace message listeners.
              }
            }
          }
        }

#ifdef MOZ_XUL
        nsIDocument* doc = window->GetExtantDoc();
        if (doc && doc->IsXULDocument()) {
          XULDocument* xulDoc = static_cast<XULDocument*>(doc);
          xulDoc->TraceProtos(aTrc);
        }
#endif
      }
    }
  }
}
void
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
{
#ifdef MOZ_XUL
  // Mark the scripts held in the XULPrototypeCache. This is required to keep
  // the JS script in the cache live across GC.
  nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
  if (cache) {
    if (aIsShutdownGC) {
      cache->FlushScripts();
    } else {
      cache->MarkInGC(aTrc);
    }
  }
#endif

  if (!nsCCUncollectableMarker::sGeneration) {
    return;
  }

  if (nsFrameMessageManager::GetChildProcessManager()) {
    nsIContentProcessMessageManager* pg = ProcessGlobal::Get();
    if (pg) {
      mozilla::TraceScriptHolder(pg, aTrc);
    }
  }

  // Mark globals of active windows black.
  nsGlobalWindow::WindowByIdTable* windowsById =
    nsGlobalWindow::GetWindowsTable();
  if (windowsById) {
    for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
      nsGlobalWindow* window = iter.Data();
      if (window->GetDocShell() && window->IsOuterWindow()) {
        window->TraceGlobalJSObject(aTrc);
        EventListenerManager* elm = window->GetExistingListenerManager();
        if (elm) {
          elm->TraceListeners(aTrc);
        }

        if (window->IsRootOuterWindow()) {
          // In child process trace all the TabChildGlobals.
          // Since there is one root outer window per TabChildGlobal, we need
          // to look for only those windows, not all.
          nsIDocShell* ds = window->GetDocShell();
          if (ds) {
            nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild();
            if (tabChild) {
              nsCOMPtr<nsIContentFrameMessageManager> mm;
              tabChild->GetMessageManager(getter_AddRefs(mm));
              nsCOMPtr<EventTarget> et = do_QueryInterface(mm);
              if (et) {
                nsCOMPtr<nsISupports> tabChildAsSupports =
                  do_QueryInterface(tabChild);
                mozilla::TraceScriptHolder(tabChildAsSupports, aTrc);
                EventListenerManager* elm = et->GetExistingListenerManager();
                if (elm) {
                  elm->TraceListeners(aTrc);
                }
                // As of now there isn't an easy way to trace message listeners.
              }
            }
          }
        }

#ifdef MOZ_XUL
        nsIDocument* doc = window->GetExtantDoc();
        if (doc && doc->IsXULDocument()) {
          XULDocument* xulDoc = static_cast<XULDocument*>(doc);
          xulDoc->TraceProtos(aTrc, aGCNumber);
        }
#endif
      }
    }
  }
}