content/base/src/nsCCUncollectableMarker.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsCCUncollectableMarker.h"
michael@0 7 #include "nsIObserverService.h"
michael@0 8 #include "nsIDocShell.h"
michael@0 9 #include "nsServiceManagerUtils.h"
michael@0 10 #include "nsIContentViewer.h"
michael@0 11 #include "nsIDocument.h"
michael@0 12 #include "XULDocument.h"
michael@0 13 #include "nsIWindowMediator.h"
michael@0 14 #include "nsPIDOMWindow.h"
michael@0 15 #include "nsIWebNavigation.h"
michael@0 16 #include "nsISHistory.h"
michael@0 17 #include "nsISHEntry.h"
michael@0 18 #include "nsISHContainer.h"
michael@0 19 #include "nsIWindowWatcher.h"
michael@0 20 #include "mozilla/Services.h"
michael@0 21 #include "nsIXULWindow.h"
michael@0 22 #include "nsIAppShellService.h"
michael@0 23 #include "nsAppShellCID.h"
michael@0 24 #include "nsContentUtils.h"
michael@0 25 #include "nsGlobalWindow.h"
michael@0 26 #include "nsJSEnvironment.h"
michael@0 27 #include "nsInProcessTabChildGlobal.h"
michael@0 28 #include "nsFrameLoader.h"
michael@0 29 #include "mozilla/EventListenerManager.h"
michael@0 30 #include "mozilla/dom/Element.h"
michael@0 31 #include "xpcpublic.h"
michael@0 32 #include "nsObserverService.h"
michael@0 33 #include "nsFocusManager.h"
michael@0 34
michael@0 35 using namespace mozilla;
michael@0 36 using namespace mozilla::dom;
michael@0 37
michael@0 38 static bool sInited = 0;
michael@0 39 uint32_t nsCCUncollectableMarker::sGeneration = 0;
michael@0 40 #ifdef MOZ_XUL
michael@0 41 #include "nsXULPrototypeCache.h"
michael@0 42 #endif
michael@0 43
michael@0 44 NS_IMPL_ISUPPORTS(nsCCUncollectableMarker, nsIObserver)
michael@0 45
michael@0 46 /* static */
michael@0 47 nsresult
michael@0 48 nsCCUncollectableMarker::Init()
michael@0 49 {
michael@0 50 if (sInited) {
michael@0 51 return NS_OK;
michael@0 52 }
michael@0 53
michael@0 54 nsCOMPtr<nsIObserver> marker = new nsCCUncollectableMarker;
michael@0 55 NS_ENSURE_TRUE(marker, NS_ERROR_OUT_OF_MEMORY);
michael@0 56
michael@0 57 nsCOMPtr<nsIObserverService> obs =
michael@0 58 mozilla::services::GetObserverService();
michael@0 59 if (!obs)
michael@0 60 return NS_ERROR_FAILURE;
michael@0 61
michael@0 62 nsresult rv;
michael@0 63
michael@0 64 // This makes the observer service hold an owning reference to the marker
michael@0 65 rv = obs->AddObserver(marker, "xpcom-shutdown", false);
michael@0 66 NS_ENSURE_SUCCESS(rv, rv);
michael@0 67
michael@0 68 rv = obs->AddObserver(marker, "cycle-collector-begin", false);
michael@0 69 NS_ENSURE_SUCCESS(rv, rv);
michael@0 70 rv = obs->AddObserver(marker, "cycle-collector-forget-skippable", false);
michael@0 71 NS_ENSURE_SUCCESS(rv, rv);
michael@0 72
michael@0 73 sInited = true;
michael@0 74
michael@0 75 return NS_OK;
michael@0 76 }
michael@0 77
michael@0 78 static void
michael@0 79 MarkUserData(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
michael@0 80 {
michael@0 81 nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
michael@0 82 if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
michael@0 83 Element::MarkUserData(aNode, aKey, aValue, aData);
michael@0 84 }
michael@0 85 }
michael@0 86
michael@0 87 static void
michael@0 88 MarkUserDataHandler(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
michael@0 89 {
michael@0 90 nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
michael@0 91 if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
michael@0 92 Element::MarkUserDataHandler(aNode, aKey, aValue, aData);
michael@0 93 }
michael@0 94 }
michael@0 95
michael@0 96 static void
michael@0 97 MarkMessageManagers()
michael@0 98 {
michael@0 99 // The global message manager only exists in the root process.
michael@0 100 if (XRE_GetProcessType() != GeckoProcessType_Default) {
michael@0 101 return;
michael@0 102 }
michael@0 103 nsCOMPtr<nsIMessageBroadcaster> strongGlobalMM =
michael@0 104 do_GetService("@mozilla.org/globalmessagemanager;1");
michael@0 105 if (!strongGlobalMM) {
michael@0 106 return;
michael@0 107 }
michael@0 108 nsIMessageBroadcaster* globalMM = strongGlobalMM;
michael@0 109 strongGlobalMM = nullptr;
michael@0 110
michael@0 111 globalMM->MarkForCC();
michael@0 112 uint32_t childCount = 0;
michael@0 113 globalMM->GetChildCount(&childCount);
michael@0 114 for (uint32_t i = 0; i < childCount; ++i) {
michael@0 115 nsCOMPtr<nsIMessageListenerManager> childMM;
michael@0 116 globalMM->GetChildAt(i, getter_AddRefs(childMM));
michael@0 117 if (!childMM) {
michael@0 118 continue;
michael@0 119 }
michael@0 120 nsCOMPtr<nsIMessageBroadcaster> strongWindowMM = do_QueryInterface(childMM);
michael@0 121 nsIMessageBroadcaster* windowMM = strongWindowMM;
michael@0 122 childMM = nullptr;
michael@0 123 strongWindowMM = nullptr;
michael@0 124 windowMM->MarkForCC();
michael@0 125 uint32_t tabChildCount = 0;
michael@0 126 windowMM->GetChildCount(&tabChildCount);
michael@0 127 for (uint32_t j = 0; j < tabChildCount; ++j) {
michael@0 128 nsCOMPtr<nsIMessageListenerManager> childMM;
michael@0 129 windowMM->GetChildAt(j, getter_AddRefs(childMM));
michael@0 130 if (!childMM) {
michael@0 131 continue;
michael@0 132 }
michael@0 133 nsCOMPtr<nsIMessageSender> strongTabMM = do_QueryInterface(childMM);
michael@0 134 nsIMessageSender* tabMM = strongTabMM;
michael@0 135 childMM = nullptr;
michael@0 136 strongTabMM = nullptr;
michael@0 137 tabMM->MarkForCC();
michael@0 138 //XXX hack warning, but works, since we know that
michael@0 139 // callback is frameloader.
michael@0 140 mozilla::dom::ipc::MessageManagerCallback* cb =
michael@0 141 static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
michael@0 142 if (cb) {
michael@0 143 nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
michael@0 144 EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
michael@0 145 if (!et) {
michael@0 146 continue;
michael@0 147 }
michael@0 148 static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
michael@0 149 EventListenerManager* elm = et->GetExistingListenerManager();
michael@0 150 if (elm) {
michael@0 151 elm->MarkForCC();
michael@0 152 }
michael@0 153 }
michael@0 154 }
michael@0 155 }
michael@0 156 if (nsFrameMessageManager::sParentProcessManager) {
michael@0 157 nsFrameMessageManager::sParentProcessManager->MarkForCC();
michael@0 158 uint32_t childCount = 0;
michael@0 159 nsFrameMessageManager::sParentProcessManager->GetChildCount(&childCount);
michael@0 160 for (uint32_t i = 0; i < childCount; ++i) {
michael@0 161 nsCOMPtr<nsIMessageListenerManager> childMM;
michael@0 162 nsFrameMessageManager::sParentProcessManager->
michael@0 163 GetChildAt(i, getter_AddRefs(childMM));
michael@0 164 if (!childMM) {
michael@0 165 continue;
michael@0 166 }
michael@0 167 nsIMessageListenerManager* child = childMM;
michael@0 168 childMM = nullptr;
michael@0 169 child->MarkForCC();
michael@0 170 }
michael@0 171 }
michael@0 172 if (nsFrameMessageManager::sSameProcessParentManager) {
michael@0 173 nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
michael@0 174 }
michael@0 175 if (nsFrameMessageManager::sChildProcessManager) {
michael@0 176 nsFrameMessageManager::sChildProcessManager->MarkForCC();
michael@0 177 }
michael@0 178 }
michael@0 179
michael@0 180 void
michael@0 181 MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
michael@0 182 bool aPrepareForCC)
michael@0 183 {
michael@0 184 if (!aViewer) {
michael@0 185 return;
michael@0 186 }
michael@0 187
michael@0 188 nsIDocument *doc = aViewer->GetDocument();
michael@0 189 if (doc &&
michael@0 190 doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
michael@0 191 doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
michael@0 192 if (aCleanupJS) {
michael@0 193 EventListenerManager* elm = doc->GetExistingListenerManager();
michael@0 194 if (elm) {
michael@0 195 elm->MarkForCC();
michael@0 196 }
michael@0 197 nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
michael@0 198 if (win) {
michael@0 199 elm = win->GetExistingListenerManager();
michael@0 200 if (elm) {
michael@0 201 elm->MarkForCC();
michael@0 202 }
michael@0 203 static_cast<nsGlobalWindow*>(win.get())->UnmarkGrayTimers();
michael@0 204 }
michael@0 205
michael@0 206 doc->PropertyTable(DOM_USER_DATA_HANDLER)->
michael@0 207 EnumerateAll(MarkUserDataHandler, &nsCCUncollectableMarker::sGeneration);
michael@0 208 } else if (aPrepareForCC) {
michael@0 209 // Unfortunately we need to still mark user data just before running CC so
michael@0 210 // that it has the right generation.
michael@0 211 doc->PropertyTable(DOM_USER_DATA)->
michael@0 212 EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
michael@0 213 }
michael@0 214 }
michael@0 215 if (doc) {
michael@0 216 nsPIDOMWindow* inner = doc->GetInnerWindow();
michael@0 217 if (inner) {
michael@0 218 inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
michael@0 219 }
michael@0 220 nsPIDOMWindow* outer = doc->GetWindow();
michael@0 221 if (outer) {
michael@0 222 outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
michael@0 223 }
michael@0 224 }
michael@0 225 }
michael@0 226
michael@0 227 void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS,
michael@0 228 bool aPrepareForCC);
michael@0 229
michael@0 230 void
michael@0 231 MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
michael@0 232 {
michael@0 233 if (!aSHEntry) {
michael@0 234 return;
michael@0 235 }
michael@0 236
michael@0 237 nsCOMPtr<nsIContentViewer> cview;
michael@0 238 aSHEntry->GetContentViewer(getter_AddRefs(cview));
michael@0 239 MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
michael@0 240
michael@0 241 nsCOMPtr<nsIDocShellTreeItem> child;
michael@0 242 int32_t i = 0;
michael@0 243 while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
michael@0 244 child) {
michael@0 245 MarkDocShell(child, aCleanupJS, aPrepareForCC);
michael@0 246 }
michael@0 247
michael@0 248 nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
michael@0 249 int32_t count;
michael@0 250 shCont->GetChildCount(&count);
michael@0 251 for (i = 0; i < count; ++i) {
michael@0 252 nsCOMPtr<nsISHEntry> childEntry;
michael@0 253 shCont->GetChildAt(i, getter_AddRefs(childEntry));
michael@0 254 MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
michael@0 255 }
michael@0 256
michael@0 257 }
michael@0 258
michael@0 259 void
michael@0 260 MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, bool aPrepareForCC)
michael@0 261 {
michael@0 262 nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
michael@0 263 if (!shell) {
michael@0 264 return;
michael@0 265 }
michael@0 266
michael@0 267 nsCOMPtr<nsIContentViewer> cview;
michael@0 268 shell->GetContentViewer(getter_AddRefs(cview));
michael@0 269 MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
michael@0 270
michael@0 271 nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
michael@0 272 nsCOMPtr<nsISHistory> history;
michael@0 273 webNav->GetSessionHistory(getter_AddRefs(history));
michael@0 274 if (history) {
michael@0 275 int32_t i, historyCount;
michael@0 276 history->GetCount(&historyCount);
michael@0 277 for (i = 0; i < historyCount; ++i) {
michael@0 278 nsCOMPtr<nsISHEntry> shEntry;
michael@0 279 history->GetEntryAtIndex(i, false, getter_AddRefs(shEntry));
michael@0 280
michael@0 281 MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
michael@0 282 }
michael@0 283 }
michael@0 284
michael@0 285 int32_t i, childCount;
michael@0 286 aNode->GetChildCount(&childCount);
michael@0 287 for (i = 0; i < childCount; ++i) {
michael@0 288 nsCOMPtr<nsIDocShellTreeItem> child;
michael@0 289 aNode->GetChildAt(i, getter_AddRefs(child));
michael@0 290 MarkDocShell(child, aCleanupJS, aPrepareForCC);
michael@0 291 }
michael@0 292 }
michael@0 293
michael@0 294 void
michael@0 295 MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
michael@0 296 bool aPrepareForCC)
michael@0 297 {
michael@0 298 nsCOMPtr<nsISupports> iter;
michael@0 299 while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
michael@0 300 iter) {
michael@0 301 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(iter);
michael@0 302 if (window) {
michael@0 303 nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
michael@0 304
michael@0 305 MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
michael@0 306 }
michael@0 307 }
michael@0 308 }
michael@0 309
michael@0 310 nsresult
michael@0 311 nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
michael@0 312 const char16_t* aData)
michael@0 313 {
michael@0 314 if (!strcmp(aTopic, "xpcom-shutdown")) {
michael@0 315 Element::ClearContentUnbinder();
michael@0 316
michael@0 317 nsCOMPtr<nsIObserverService> obs =
michael@0 318 mozilla::services::GetObserverService();
michael@0 319 if (!obs)
michael@0 320 return NS_ERROR_FAILURE;
michael@0 321
michael@0 322 // No need for kungFuDeathGrip here, yay observerservice!
michael@0 323 obs->RemoveObserver(this, "xpcom-shutdown");
michael@0 324 obs->RemoveObserver(this, "cycle-collector-begin");
michael@0 325 obs->RemoveObserver(this, "cycle-collector-forget-skippable");
michael@0 326
michael@0 327 sGeneration = 0;
michael@0 328
michael@0 329 return NS_OK;
michael@0 330 }
michael@0 331
michael@0 332 NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
michael@0 333 !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
michael@0 334
michael@0 335 // JS cleanup can be slow. Do it only if there has been a GC.
michael@0 336 bool cleanupJS =
michael@0 337 nsJSContext::CleanupsSinceLastGC() == 0 &&
michael@0 338 !strcmp(aTopic, "cycle-collector-forget-skippable");
michael@0 339
michael@0 340 bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
michael@0 341 if (prepareForCC) {
michael@0 342 Element::ClearContentUnbinder();
michael@0 343 }
michael@0 344
michael@0 345 // Increase generation to effectively unmark all current objects
michael@0 346 if (!++sGeneration) {
michael@0 347 ++sGeneration;
michael@0 348 }
michael@0 349
michael@0 350 nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
michael@0 351
michael@0 352 nsresult rv;
michael@0 353
michael@0 354 // Iterate all toplevel windows
michael@0 355 nsCOMPtr<nsISimpleEnumerator> windowList;
michael@0 356 nsCOMPtr<nsIWindowMediator> med =
michael@0 357 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
michael@0 358 if (med) {
michael@0 359 rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
michael@0 360 NS_ENSURE_SUCCESS(rv, rv);
michael@0 361
michael@0 362 MarkWindowList(windowList, cleanupJS, prepareForCC);
michael@0 363 }
michael@0 364
michael@0 365 nsCOMPtr<nsIWindowWatcher> ww =
michael@0 366 do_GetService(NS_WINDOWWATCHER_CONTRACTID);
michael@0 367 if (ww) {
michael@0 368 rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
michael@0 369 NS_ENSURE_SUCCESS(rv, rv);
michael@0 370
michael@0 371 MarkWindowList(windowList, cleanupJS, prepareForCC);
michael@0 372 }
michael@0 373
michael@0 374 nsCOMPtr<nsIAppShellService> appShell =
michael@0 375 do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
michael@0 376 if (appShell) {
michael@0 377 nsCOMPtr<nsIXULWindow> hw;
michael@0 378 appShell->GetHiddenWindow(getter_AddRefs(hw));
michael@0 379 if (hw) {
michael@0 380 nsCOMPtr<nsIDocShell> shell;
michael@0 381 hw->GetDocShell(getter_AddRefs(shell));
michael@0 382 MarkDocShell(shell, cleanupJS, prepareForCC);
michael@0 383 }
michael@0 384 bool hasHiddenPrivateWindow = false;
michael@0 385 appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
michael@0 386 if (hasHiddenPrivateWindow) {
michael@0 387 appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
michael@0 388 if (hw) {
michael@0 389 nsCOMPtr<nsIDocShell> shell;
michael@0 390 hw->GetDocShell(getter_AddRefs(shell));
michael@0 391 MarkDocShell(shell, cleanupJS, prepareForCC);
michael@0 392 }
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 #ifdef MOZ_XUL
michael@0 397 nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
michael@0 398 if (xulCache) {
michael@0 399 xulCache->MarkInCCGeneration(sGeneration);
michael@0 400 }
michael@0 401 #endif
michael@0 402
michael@0 403 static bool previousWasJSCleanup = false;
michael@0 404 if (cleanupJS) {
michael@0 405 nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration);
michael@0 406 MarkMessageManagers();
michael@0 407
michael@0 408 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
michael@0 409 static_cast<nsObserverService *>(obs.get())->UnmarkGrayStrongObservers();
michael@0 410
michael@0 411 previousWasJSCleanup = true;
michael@0 412 } else if (previousWasJSCleanup) {
michael@0 413 previousWasJSCleanup = false;
michael@0 414 if (!prepareForCC) {
michael@0 415 xpc_UnmarkSkippableJSHolders();
michael@0 416 }
michael@0 417 }
michael@0 418
michael@0 419 return NS_OK;
michael@0 420 }
michael@0 421
michael@0 422 struct TraceClosure
michael@0 423 {
michael@0 424 TraceClosure(JSTracer* aTrc, uint32_t aGCNumber)
michael@0 425 : mTrc(aTrc), mGCNumber(aGCNumber)
michael@0 426 {}
michael@0 427 JSTracer* mTrc;
michael@0 428 uint32_t mGCNumber;
michael@0 429 };
michael@0 430
michael@0 431 static PLDHashOperator
michael@0 432 TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
michael@0 433 {
michael@0 434 if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
michael@0 435 TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
michael@0 436 aWindow->TraceGlobalJSObject(closure->mTrc);
michael@0 437 #ifdef MOZ_XUL
michael@0 438 nsIDocument* doc = aWindow->GetExtantDoc();
michael@0 439 if (doc && doc->IsXUL()) {
michael@0 440 XULDocument* xulDoc = static_cast<XULDocument*>(doc);
michael@0 441 xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
michael@0 442 }
michael@0 443 #endif
michael@0 444 }
michael@0 445 return PL_DHASH_NEXT;
michael@0 446 }
michael@0 447
michael@0 448 void
michael@0 449 mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
michael@0 450 {
michael@0 451 #ifdef MOZ_XUL
michael@0 452 // Mark the scripts held in the XULPrototypeCache. This is required to keep
michael@0 453 // the JS script in the cache live across GC.
michael@0 454 nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
michael@0 455 if (cache) {
michael@0 456 if (aIsShutdownGC) {
michael@0 457 cache->FlushScripts();
michael@0 458 } else {
michael@0 459 cache->MarkInGC(aTrc);
michael@0 460 }
michael@0 461 }
michael@0 462 #endif
michael@0 463
michael@0 464 if (!nsCCUncollectableMarker::sGeneration) {
michael@0 465 return;
michael@0 466 }
michael@0 467
michael@0 468 TraceClosure closure(aTrc, aGCNumber);
michael@0 469
michael@0 470 // Mark globals of active windows black.
michael@0 471 nsGlobalWindow::WindowByIdTable* windowsById =
michael@0 472 nsGlobalWindow::GetWindowsTable();
michael@0 473 if (windowsById) {
michael@0 474 windowsById->Enumerate(TraceActiveWindowGlobal, &closure);
michael@0 475 }
michael@0 476
michael@0 477 // Mark the safe context black
michael@0 478 nsContentUtils::TraceSafeJSContext(aTrc);
michael@0 479 }

mercurial