content/base/src/nsCCUncollectableMarker.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsCCUncollectableMarker.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,479 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsCCUncollectableMarker.h"
    1.10 +#include "nsIObserverService.h"
    1.11 +#include "nsIDocShell.h"
    1.12 +#include "nsServiceManagerUtils.h"
    1.13 +#include "nsIContentViewer.h"
    1.14 +#include "nsIDocument.h"
    1.15 +#include "XULDocument.h"
    1.16 +#include "nsIWindowMediator.h"
    1.17 +#include "nsPIDOMWindow.h"
    1.18 +#include "nsIWebNavigation.h"
    1.19 +#include "nsISHistory.h"
    1.20 +#include "nsISHEntry.h"
    1.21 +#include "nsISHContainer.h"
    1.22 +#include "nsIWindowWatcher.h"
    1.23 +#include "mozilla/Services.h"
    1.24 +#include "nsIXULWindow.h"
    1.25 +#include "nsIAppShellService.h"
    1.26 +#include "nsAppShellCID.h"
    1.27 +#include "nsContentUtils.h"
    1.28 +#include "nsGlobalWindow.h"
    1.29 +#include "nsJSEnvironment.h"
    1.30 +#include "nsInProcessTabChildGlobal.h"
    1.31 +#include "nsFrameLoader.h"
    1.32 +#include "mozilla/EventListenerManager.h"
    1.33 +#include "mozilla/dom/Element.h"
    1.34 +#include "xpcpublic.h"
    1.35 +#include "nsObserverService.h"
    1.36 +#include "nsFocusManager.h"
    1.37 +
    1.38 +using namespace mozilla;
    1.39 +using namespace mozilla::dom;
    1.40 +
    1.41 +static bool sInited = 0;
    1.42 +uint32_t nsCCUncollectableMarker::sGeneration = 0;
    1.43 +#ifdef MOZ_XUL
    1.44 +#include "nsXULPrototypeCache.h"
    1.45 +#endif
    1.46 +
    1.47 +NS_IMPL_ISUPPORTS(nsCCUncollectableMarker, nsIObserver)
    1.48 +
    1.49 +/* static */
    1.50 +nsresult
    1.51 +nsCCUncollectableMarker::Init()
    1.52 +{
    1.53 +  if (sInited) {
    1.54 +    return NS_OK;
    1.55 +  }
    1.56 +  
    1.57 +  nsCOMPtr<nsIObserver> marker = new nsCCUncollectableMarker;
    1.58 +  NS_ENSURE_TRUE(marker, NS_ERROR_OUT_OF_MEMORY);
    1.59 +
    1.60 +  nsCOMPtr<nsIObserverService> obs =
    1.61 +    mozilla::services::GetObserverService();
    1.62 +  if (!obs)
    1.63 +    return NS_ERROR_FAILURE;
    1.64 +
    1.65 +  nsresult rv;
    1.66 +
    1.67 +  // This makes the observer service hold an owning reference to the marker
    1.68 +  rv = obs->AddObserver(marker, "xpcom-shutdown", false);
    1.69 +  NS_ENSURE_SUCCESS(rv, rv);
    1.70 +
    1.71 +  rv = obs->AddObserver(marker, "cycle-collector-begin", false);
    1.72 +  NS_ENSURE_SUCCESS(rv, rv);
    1.73 +  rv = obs->AddObserver(marker, "cycle-collector-forget-skippable", false);
    1.74 +  NS_ENSURE_SUCCESS(rv, rv);
    1.75 +
    1.76 +  sInited = true;
    1.77 +
    1.78 +  return NS_OK;
    1.79 +}
    1.80 +
    1.81 +static void
    1.82 +MarkUserData(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
    1.83 +{
    1.84 +  nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
    1.85 +  if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
    1.86 +    Element::MarkUserData(aNode, aKey, aValue, aData);
    1.87 +  }
    1.88 +}
    1.89 +
    1.90 +static void
    1.91 +MarkUserDataHandler(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
    1.92 +{
    1.93 +  nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
    1.94 +  if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
    1.95 +    Element::MarkUserDataHandler(aNode, aKey, aValue, aData);
    1.96 +  }
    1.97 +}
    1.98 +
    1.99 +static void
   1.100 +MarkMessageManagers()
   1.101 +{
   1.102 +  // The global message manager only exists in the root process.
   1.103 +  if (XRE_GetProcessType() != GeckoProcessType_Default) {
   1.104 +    return;
   1.105 +  }
   1.106 +  nsCOMPtr<nsIMessageBroadcaster> strongGlobalMM =
   1.107 +    do_GetService("@mozilla.org/globalmessagemanager;1");
   1.108 +  if (!strongGlobalMM) {
   1.109 +    return;
   1.110 +  }
   1.111 +  nsIMessageBroadcaster* globalMM = strongGlobalMM;
   1.112 +  strongGlobalMM = nullptr;
   1.113 +
   1.114 +  globalMM->MarkForCC();
   1.115 +  uint32_t childCount = 0;
   1.116 +  globalMM->GetChildCount(&childCount);
   1.117 +  for (uint32_t i = 0; i < childCount; ++i) {
   1.118 +    nsCOMPtr<nsIMessageListenerManager> childMM;
   1.119 +    globalMM->GetChildAt(i, getter_AddRefs(childMM));
   1.120 +    if (!childMM) {
   1.121 +      continue;
   1.122 +    }
   1.123 +    nsCOMPtr<nsIMessageBroadcaster> strongWindowMM = do_QueryInterface(childMM);
   1.124 +    nsIMessageBroadcaster* windowMM = strongWindowMM;
   1.125 +    childMM = nullptr;
   1.126 +    strongWindowMM = nullptr;
   1.127 +    windowMM->MarkForCC();
   1.128 +    uint32_t tabChildCount = 0;
   1.129 +    windowMM->GetChildCount(&tabChildCount);
   1.130 +    for (uint32_t j = 0; j < tabChildCount; ++j) {
   1.131 +      nsCOMPtr<nsIMessageListenerManager> childMM;
   1.132 +      windowMM->GetChildAt(j, getter_AddRefs(childMM));
   1.133 +      if (!childMM) {
   1.134 +        continue;
   1.135 +      }
   1.136 +      nsCOMPtr<nsIMessageSender> strongTabMM = do_QueryInterface(childMM);
   1.137 +      nsIMessageSender* tabMM = strongTabMM;
   1.138 +      childMM = nullptr;
   1.139 +      strongTabMM = nullptr;
   1.140 +      tabMM->MarkForCC();
   1.141 +      //XXX hack warning, but works, since we know that
   1.142 +      //    callback is frameloader.
   1.143 +      mozilla::dom::ipc::MessageManagerCallback* cb =
   1.144 +        static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
   1.145 +      if (cb) {
   1.146 +        nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
   1.147 +        EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
   1.148 +        if (!et) {
   1.149 +          continue;
   1.150 +        }
   1.151 +        static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
   1.152 +        EventListenerManager* elm = et->GetExistingListenerManager();
   1.153 +        if (elm) {
   1.154 +          elm->MarkForCC();
   1.155 +        }
   1.156 +      }
   1.157 +    }
   1.158 +  }
   1.159 +  if (nsFrameMessageManager::sParentProcessManager) {
   1.160 +    nsFrameMessageManager::sParentProcessManager->MarkForCC();
   1.161 +    uint32_t childCount = 0;
   1.162 +    nsFrameMessageManager::sParentProcessManager->GetChildCount(&childCount);
   1.163 +    for (uint32_t i = 0; i < childCount; ++i) {
   1.164 +      nsCOMPtr<nsIMessageListenerManager> childMM;
   1.165 +      nsFrameMessageManager::sParentProcessManager->
   1.166 +        GetChildAt(i, getter_AddRefs(childMM));
   1.167 +      if (!childMM) {
   1.168 +        continue;
   1.169 +      }
   1.170 +      nsIMessageListenerManager* child = childMM;
   1.171 +      childMM = nullptr;
   1.172 +      child->MarkForCC();
   1.173 +    }
   1.174 +  }
   1.175 +  if (nsFrameMessageManager::sSameProcessParentManager) {
   1.176 +    nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
   1.177 +  }
   1.178 +  if (nsFrameMessageManager::sChildProcessManager) {
   1.179 +    nsFrameMessageManager::sChildProcessManager->MarkForCC();
   1.180 +  }
   1.181 +}
   1.182 +
   1.183 +void
   1.184 +MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
   1.185 +                  bool aPrepareForCC)
   1.186 +{
   1.187 +  if (!aViewer) {
   1.188 +    return;
   1.189 +  }
   1.190 +
   1.191 +  nsIDocument *doc = aViewer->GetDocument();
   1.192 +  if (doc &&
   1.193 +      doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
   1.194 +    doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
   1.195 +    if (aCleanupJS) {
   1.196 +      EventListenerManager* elm = doc->GetExistingListenerManager();
   1.197 +      if (elm) {
   1.198 +        elm->MarkForCC();
   1.199 +      }
   1.200 +      nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
   1.201 +      if (win) {
   1.202 +        elm = win->GetExistingListenerManager();
   1.203 +        if (elm) {
   1.204 +          elm->MarkForCC();
   1.205 +        }
   1.206 +        static_cast<nsGlobalWindow*>(win.get())->UnmarkGrayTimers();
   1.207 +      }
   1.208 +
   1.209 +      doc->PropertyTable(DOM_USER_DATA_HANDLER)->
   1.210 +        EnumerateAll(MarkUserDataHandler, &nsCCUncollectableMarker::sGeneration);
   1.211 +    } else if (aPrepareForCC) {
   1.212 +      // Unfortunately we need to still mark user data just before running CC so
   1.213 +      // that it has the right generation. 
   1.214 +      doc->PropertyTable(DOM_USER_DATA)->
   1.215 +        EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
   1.216 +    }
   1.217 +  }
   1.218 +  if (doc) {
   1.219 +    nsPIDOMWindow* inner = doc->GetInnerWindow();
   1.220 +    if (inner) {
   1.221 +      inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
   1.222 +    }
   1.223 +    nsPIDOMWindow* outer = doc->GetWindow();
   1.224 +    if (outer) {
   1.225 +      outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
   1.226 +    }
   1.227 +  }
   1.228 +}
   1.229 +
   1.230 +void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS,
   1.231 +                  bool aPrepareForCC);
   1.232 +
   1.233 +void
   1.234 +MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
   1.235 +{
   1.236 +  if (!aSHEntry) {
   1.237 +    return;
   1.238 +  }
   1.239 +
   1.240 +  nsCOMPtr<nsIContentViewer> cview;
   1.241 +  aSHEntry->GetContentViewer(getter_AddRefs(cview));
   1.242 +  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
   1.243 +
   1.244 +  nsCOMPtr<nsIDocShellTreeItem> child;
   1.245 +  int32_t i = 0;
   1.246 +  while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
   1.247 +         child) {
   1.248 +    MarkDocShell(child, aCleanupJS, aPrepareForCC);
   1.249 +  }
   1.250 +
   1.251 +  nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
   1.252 +  int32_t count;
   1.253 +  shCont->GetChildCount(&count);
   1.254 +  for (i = 0; i < count; ++i) {
   1.255 +    nsCOMPtr<nsISHEntry> childEntry;
   1.256 +    shCont->GetChildAt(i, getter_AddRefs(childEntry));
   1.257 +    MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
   1.258 +  }
   1.259 +  
   1.260 +}
   1.261 +
   1.262 +void
   1.263 +MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, bool aPrepareForCC)
   1.264 +{
   1.265 +  nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
   1.266 +  if (!shell) {
   1.267 +    return;
   1.268 +  }
   1.269 +
   1.270 +  nsCOMPtr<nsIContentViewer> cview;
   1.271 +  shell->GetContentViewer(getter_AddRefs(cview));
   1.272 +  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
   1.273 +
   1.274 +  nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
   1.275 +  nsCOMPtr<nsISHistory> history;
   1.276 +  webNav->GetSessionHistory(getter_AddRefs(history));
   1.277 +  if (history) {
   1.278 +    int32_t i, historyCount;
   1.279 +    history->GetCount(&historyCount);
   1.280 +    for (i = 0; i < historyCount; ++i) {
   1.281 +      nsCOMPtr<nsISHEntry> shEntry;
   1.282 +      history->GetEntryAtIndex(i, false, getter_AddRefs(shEntry));
   1.283 +
   1.284 +      MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
   1.285 +    }
   1.286 +  }
   1.287 +
   1.288 +  int32_t i, childCount;
   1.289 +  aNode->GetChildCount(&childCount);
   1.290 +  for (i = 0; i < childCount; ++i) {
   1.291 +    nsCOMPtr<nsIDocShellTreeItem> child;
   1.292 +    aNode->GetChildAt(i, getter_AddRefs(child));
   1.293 +    MarkDocShell(child, aCleanupJS, aPrepareForCC);
   1.294 +  }
   1.295 +}
   1.296 +
   1.297 +void
   1.298 +MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
   1.299 +               bool aPrepareForCC)
   1.300 +{
   1.301 +  nsCOMPtr<nsISupports> iter;
   1.302 +  while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
   1.303 +         iter) {
   1.304 +    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(iter);
   1.305 +    if (window) {
   1.306 +      nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
   1.307 +
   1.308 +      MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
   1.309 +    }
   1.310 +  }
   1.311 +}
   1.312 +
   1.313 +nsresult
   1.314 +nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
   1.315 +                                 const char16_t* aData)
   1.316 +{
   1.317 +  if (!strcmp(aTopic, "xpcom-shutdown")) {
   1.318 +    Element::ClearContentUnbinder();
   1.319 +
   1.320 +    nsCOMPtr<nsIObserverService> obs =
   1.321 +      mozilla::services::GetObserverService();
   1.322 +    if (!obs)
   1.323 +      return NS_ERROR_FAILURE;
   1.324 +
   1.325 +    // No need for kungFuDeathGrip here, yay observerservice!
   1.326 +    obs->RemoveObserver(this, "xpcom-shutdown");
   1.327 +    obs->RemoveObserver(this, "cycle-collector-begin");
   1.328 +    obs->RemoveObserver(this, "cycle-collector-forget-skippable");
   1.329 +    
   1.330 +    sGeneration = 0;
   1.331 +    
   1.332 +    return NS_OK;
   1.333 +  }
   1.334 +
   1.335 +  NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
   1.336 +               !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
   1.337 +
   1.338 +  // JS cleanup can be slow. Do it only if there has been a GC.
   1.339 +  bool cleanupJS =
   1.340 +    nsJSContext::CleanupsSinceLastGC() == 0 &&
   1.341 +    !strcmp(aTopic, "cycle-collector-forget-skippable");
   1.342 +
   1.343 +  bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
   1.344 +  if (prepareForCC) {
   1.345 +    Element::ClearContentUnbinder();
   1.346 +  }
   1.347 +
   1.348 +  // Increase generation to effectively unmark all current objects
   1.349 +  if (!++sGeneration) {
   1.350 +    ++sGeneration;
   1.351 +  }
   1.352 +
   1.353 +  nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
   1.354 +
   1.355 +  nsresult rv;
   1.356 +
   1.357 +  // Iterate all toplevel windows
   1.358 +  nsCOMPtr<nsISimpleEnumerator> windowList;
   1.359 +  nsCOMPtr<nsIWindowMediator> med =
   1.360 +    do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
   1.361 +  if (med) {
   1.362 +    rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
   1.363 +    NS_ENSURE_SUCCESS(rv, rv);
   1.364 +
   1.365 +    MarkWindowList(windowList, cleanupJS, prepareForCC);
   1.366 +  }
   1.367 +
   1.368 +  nsCOMPtr<nsIWindowWatcher> ww =
   1.369 +    do_GetService(NS_WINDOWWATCHER_CONTRACTID);
   1.370 +  if (ww) {
   1.371 +    rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
   1.372 +    NS_ENSURE_SUCCESS(rv, rv);
   1.373 +
   1.374 +    MarkWindowList(windowList, cleanupJS, prepareForCC);
   1.375 +  }
   1.376 +
   1.377 +  nsCOMPtr<nsIAppShellService> appShell = 
   1.378 +    do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
   1.379 +  if (appShell) {
   1.380 +    nsCOMPtr<nsIXULWindow> hw;
   1.381 +    appShell->GetHiddenWindow(getter_AddRefs(hw));
   1.382 +    if (hw) {
   1.383 +      nsCOMPtr<nsIDocShell> shell;
   1.384 +      hw->GetDocShell(getter_AddRefs(shell));
   1.385 +      MarkDocShell(shell, cleanupJS, prepareForCC);
   1.386 +    }
   1.387 +    bool hasHiddenPrivateWindow = false;
   1.388 +    appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
   1.389 +    if (hasHiddenPrivateWindow) {
   1.390 +      appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
   1.391 +      if (hw) {
   1.392 +        nsCOMPtr<nsIDocShell> shell;
   1.393 +        hw->GetDocShell(getter_AddRefs(shell));
   1.394 +        MarkDocShell(shell, cleanupJS, prepareForCC);
   1.395 +      }
   1.396 +    }
   1.397 +  }
   1.398 +
   1.399 +#ifdef MOZ_XUL
   1.400 +  nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
   1.401 +  if (xulCache) {
   1.402 +    xulCache->MarkInCCGeneration(sGeneration);
   1.403 +  }
   1.404 +#endif
   1.405 +
   1.406 +  static bool previousWasJSCleanup = false;
   1.407 +  if (cleanupJS) {
   1.408 +    nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration);
   1.409 +    MarkMessageManagers();
   1.410 +
   1.411 +    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   1.412 +    static_cast<nsObserverService *>(obs.get())->UnmarkGrayStrongObservers();
   1.413 +
   1.414 +    previousWasJSCleanup = true;
   1.415 +  } else if (previousWasJSCleanup) {
   1.416 +    previousWasJSCleanup = false;
   1.417 +    if (!prepareForCC) {
   1.418 +      xpc_UnmarkSkippableJSHolders();
   1.419 +    }
   1.420 +  }
   1.421 +
   1.422 +  return NS_OK;
   1.423 +}
   1.424 +
   1.425 +struct TraceClosure
   1.426 +{
   1.427 +  TraceClosure(JSTracer* aTrc, uint32_t aGCNumber)
   1.428 +    : mTrc(aTrc), mGCNumber(aGCNumber)
   1.429 +  {}
   1.430 +  JSTracer* mTrc;
   1.431 +  uint32_t mGCNumber;
   1.432 +};
   1.433 +
   1.434 +static PLDHashOperator
   1.435 +TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
   1.436 +{
   1.437 +  if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
   1.438 +    TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
   1.439 +    aWindow->TraceGlobalJSObject(closure->mTrc);
   1.440 +#ifdef MOZ_XUL
   1.441 +    nsIDocument* doc = aWindow->GetExtantDoc();
   1.442 +    if (doc && doc->IsXUL()) {
   1.443 +      XULDocument* xulDoc = static_cast<XULDocument*>(doc);
   1.444 +      xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
   1.445 +    }
   1.446 +#endif
   1.447 +  }
   1.448 +  return PL_DHASH_NEXT;
   1.449 +}
   1.450 +
   1.451 +void
   1.452 +mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
   1.453 +{
   1.454 +#ifdef MOZ_XUL
   1.455 +  // Mark the scripts held in the XULPrototypeCache. This is required to keep
   1.456 +  // the JS script in the cache live across GC.
   1.457 +  nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
   1.458 +  if (cache) {
   1.459 +    if (aIsShutdownGC) {
   1.460 +      cache->FlushScripts();
   1.461 +    } else {
   1.462 +      cache->MarkInGC(aTrc);
   1.463 +    }
   1.464 +  }
   1.465 +#endif
   1.466 +
   1.467 +  if (!nsCCUncollectableMarker::sGeneration) {
   1.468 +    return;
   1.469 +  }
   1.470 +
   1.471 +  TraceClosure closure(aTrc, aGCNumber);
   1.472 +
   1.473 +  // Mark globals of active windows black.
   1.474 +  nsGlobalWindow::WindowByIdTable* windowsById =
   1.475 +    nsGlobalWindow::GetWindowsTable();
   1.476 +  if (windowsById) {
   1.477 +    windowsById->Enumerate(TraceActiveWindowGlobal, &closure);
   1.478 +  }
   1.479 +
   1.480 +  // Mark the safe context black
   1.481 +  nsContentUtils::TraceSafeJSContext(aTrc);
   1.482 +}

mercurial