LCOV - code coverage report
Current view: top level - dom/base - nsCCUncollectableMarker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 42 264 15.9 %
Date: 2017-07-14 16:53:18 Functions: 5 13 38.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsCCUncollectableMarker.h"
       8             : #include "nsIObserverService.h"
       9             : #include "nsIDocShell.h"
      10             : #include "nsServiceManagerUtils.h"
      11             : #include "nsIContentViewer.h"
      12             : #include "nsIDocument.h"
      13             : #include "XULDocument.h"
      14             : #include "nsIWindowMediator.h"
      15             : #include "nsPIDOMWindow.h"
      16             : #include "nsIWebNavigation.h"
      17             : #include "nsISHistory.h"
      18             : #include "nsISHEntry.h"
      19             : #include "nsISHContainer.h"
      20             : #include "nsITabChild.h"
      21             : #include "nsIWindowWatcher.h"
      22             : #include "mozilla/Services.h"
      23             : #include "nsIXULWindow.h"
      24             : #include "nsIAppShellService.h"
      25             : #include "nsAppShellCID.h"
      26             : #include "nsContentUtils.h"
      27             : #include "nsGlobalWindow.h"
      28             : #include "nsJSEnvironment.h"
      29             : #include "nsInProcessTabChildGlobal.h"
      30             : #include "nsFrameLoader.h"
      31             : #include "mozilla/CycleCollectedJSContext.h"
      32             : #include "mozilla/CycleCollectedJSRuntime.h"
      33             : #include "mozilla/EventListenerManager.h"
      34             : #include "mozilla/dom/Element.h"
      35             : #include "mozilla/dom/ProcessGlobal.h"
      36             : #include "mozilla/dom/TimeoutManager.h"
      37             : #include "xpcpublic.h"
      38             : #include "nsObserverService.h"
      39             : #include "nsFocusManager.h"
      40             : #include "nsIInterfaceRequestorUtils.h"
      41             : 
      42             : using namespace mozilla;
      43             : using namespace mozilla::dom;
      44             : 
      45             : static bool sInited = 0;
      46             : // The initial value of sGeneration should not be the same as the
      47             : // value it is given at xpcom-shutdown, because this will make any GCs
      48             : // before we first CC benignly violate the black-gray invariant, due
      49             : // to dom::TraceBlackJS().
      50             : uint32_t nsCCUncollectableMarker::sGeneration = 1;
      51             : #ifdef MOZ_XUL
      52             : #include "nsXULPrototypeCache.h"
      53             : #endif
      54             : 
      55          24 : NS_IMPL_ISUPPORTS(nsCCUncollectableMarker, nsIObserver)
      56             : 
      57             : /* static */
      58             : nsresult
      59           3 : nsCCUncollectableMarker::Init()
      60             : {
      61           3 :   if (sInited) {
      62           0 :     return NS_OK;
      63             :   }
      64             : 
      65           6 :   nsCOMPtr<nsIObserver> marker = new nsCCUncollectableMarker;
      66             : 
      67             :   nsCOMPtr<nsIObserverService> obs =
      68           6 :     mozilla::services::GetObserverService();
      69           3 :   if (!obs)
      70           0 :     return NS_ERROR_FAILURE;
      71             : 
      72             :   nsresult rv;
      73             : 
      74             :   // This makes the observer service hold an owning reference to the marker
      75           3 :   rv = obs->AddObserver(marker, "xpcom-shutdown", false);
      76           3 :   NS_ENSURE_SUCCESS(rv, rv);
      77             : 
      78           3 :   rv = obs->AddObserver(marker, "cycle-collector-begin", false);
      79           3 :   NS_ENSURE_SUCCESS(rv, rv);
      80           3 :   rv = obs->AddObserver(marker, "cycle-collector-forget-skippable", false);
      81           3 :   NS_ENSURE_SUCCESS(rv, rv);
      82             : 
      83           3 :   sInited = true;
      84             : 
      85           3 :   return NS_OK;
      86             : }
      87             : 
      88             : static void
      89           0 : MarkUserData(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
      90             : {
      91           0 :   nsIDocument* d = static_cast<nsINode*>(aNode)->GetUncomposedDoc();
      92           0 :   if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
      93           0 :     Element::MarkUserData(aNode, aKey, aValue, aData);
      94             :   }
      95           0 : }
      96             : 
      97             : static void
      98           0 : MarkChildMessageManagers(nsIMessageBroadcaster* aMM)
      99             : {
     100           0 :   aMM->MarkForCC();
     101             : 
     102           0 :   uint32_t tabChildCount = 0;
     103           0 :   aMM->GetChildCount(&tabChildCount);
     104           0 :   for (uint32_t j = 0; j < tabChildCount; ++j) {
     105           0 :     nsCOMPtr<nsIMessageListenerManager> childMM;
     106           0 :     aMM->GetChildAt(j, getter_AddRefs(childMM));
     107           0 :     if (!childMM) {
     108           0 :       continue;
     109             :     }
     110             : 
     111           0 :     nsCOMPtr<nsIMessageBroadcaster> strongNonLeafMM = do_QueryInterface(childMM);
     112           0 :     nsIMessageBroadcaster* nonLeafMM = strongNonLeafMM;
     113             : 
     114           0 :     nsCOMPtr<nsIMessageSender> strongTabMM = do_QueryInterface(childMM);
     115           0 :     nsIMessageSender* tabMM = strongTabMM;
     116             : 
     117           0 :     strongNonLeafMM = nullptr;
     118           0 :     strongTabMM = nullptr;
     119           0 :     childMM = nullptr;
     120             : 
     121           0 :     if (nonLeafMM) {
     122           0 :       MarkChildMessageManagers(nonLeafMM);
     123           0 :       continue;
     124             :     }
     125             : 
     126           0 :     tabMM->MarkForCC();
     127             : 
     128             :     //XXX hack warning, but works, since we know that
     129             :     //    callback is frameloader.
     130             :     mozilla::dom::ipc::MessageManagerCallback* cb =
     131           0 :       static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
     132           0 :     if (cb) {
     133           0 :       nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
     134           0 :       EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
     135           0 :       if (!et) {
     136           0 :         continue;
     137             :       }
     138           0 :       static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
     139           0 :       EventListenerManager* elm = et->GetExistingListenerManager();
     140           0 :       if (elm) {
     141           0 :         elm->MarkForCC();
     142             :       }
     143             :     }
     144             :   }
     145           0 : }
     146             : 
     147             : static void
     148           0 : MarkMessageManagers()
     149             : {
     150           0 :   if (nsFrameMessageManager::GetChildProcessManager()) {
     151             :     // ProcessGlobal's MarkForCC marks also ChildProcessManager.
     152           0 :     ProcessGlobal* pg = ProcessGlobal::Get();
     153           0 :     if (pg) {
     154           0 :       pg->MarkForCC();
     155             :     }
     156             :   }
     157             : 
     158             :   // The global message manager only exists in the root process.
     159           0 :   if (!XRE_IsParentProcess()) {
     160           0 :     return;
     161             :   }
     162             :   nsCOMPtr<nsIMessageBroadcaster> strongGlobalMM =
     163           0 :     do_GetService("@mozilla.org/globalmessagemanager;1");
     164           0 :   if (!strongGlobalMM) {
     165           0 :     return;
     166             :   }
     167           0 :   nsIMessageBroadcaster* globalMM = strongGlobalMM;
     168           0 :   strongGlobalMM = nullptr;
     169           0 :   MarkChildMessageManagers(globalMM);
     170             : 
     171           0 :   if (nsFrameMessageManager::sParentProcessManager) {
     172           0 :     nsFrameMessageManager::sParentProcessManager->MarkForCC();
     173           0 :     uint32_t childCount = 0;
     174           0 :     nsFrameMessageManager::sParentProcessManager->GetChildCount(&childCount);
     175           0 :     for (uint32_t i = 0; i < childCount; ++i) {
     176           0 :       nsCOMPtr<nsIMessageListenerManager> childMM;
     177             :       nsFrameMessageManager::sParentProcessManager->
     178           0 :         GetChildAt(i, getter_AddRefs(childMM));
     179           0 :       if (!childMM) {
     180           0 :         continue;
     181             :       }
     182           0 :       nsIMessageListenerManager* child = childMM;
     183           0 :       childMM = nullptr;
     184           0 :       child->MarkForCC();
     185             :     }
     186             :   }
     187           0 :   if (nsFrameMessageManager::sSameProcessParentManager) {
     188           0 :     nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
     189             :   }
     190             : }
     191             : 
     192             : void
     193           0 : MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
     194             :                   bool aPrepareForCC)
     195             : {
     196           0 :   if (!aViewer) {
     197           0 :     return;
     198             :   }
     199             : 
     200           0 :   nsIDocument *doc = aViewer->GetDocument();
     201           0 :   if (doc &&
     202           0 :       doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
     203           0 :     doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     204           0 :     if (aCleanupJS) {
     205           0 :       EventListenerManager* elm = doc->GetExistingListenerManager();
     206           0 :       if (elm) {
     207           0 :         elm->MarkForCC();
     208             :       }
     209           0 :       nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
     210           0 :       if (win) {
     211           0 :         elm = win->GetExistingListenerManager();
     212           0 :         if (elm) {
     213           0 :           elm->MarkForCC();
     214             :         }
     215           0 :         static_cast<nsGlobalWindow*>(win.get())->AsInner()->
     216           0 :           TimeoutManager().UnmarkGrayTimers();
     217             :       }
     218           0 :     } else if (aPrepareForCC) {
     219             :       // Unfortunately we need to still mark user data just before running CC so
     220             :       // that it has the right generation.
     221             :       doc->PropertyTable(DOM_USER_DATA)->
     222           0 :         EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
     223             :     }
     224             :   }
     225           0 :   if (doc) {
     226           0 :     if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) {
     227           0 :       inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     228             :     }
     229           0 :     if (nsPIDOMWindowOuter* outer = doc->GetWindow()) {
     230           0 :       outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     231             :     }
     232             :   }
     233             : }
     234             : 
     235             : void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS,
     236             :                   bool aPrepareForCC);
     237             : 
     238             : void
     239           0 : MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
     240             : {
     241           0 :   if (!aSHEntry) {
     242           0 :     return;
     243             :   }
     244             : 
     245           0 :   nsCOMPtr<nsIContentViewer> cview;
     246           0 :   aSHEntry->GetContentViewer(getter_AddRefs(cview));
     247           0 :   MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
     248             : 
     249           0 :   nsCOMPtr<nsIDocShellTreeItem> child;
     250           0 :   int32_t i = 0;
     251           0 :   while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
     252           0 :          child) {
     253           0 :     MarkDocShell(child, aCleanupJS, aPrepareForCC);
     254             :   }
     255             : 
     256           0 :   nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
     257             :   int32_t count;
     258           0 :   shCont->GetChildCount(&count);
     259           0 :   for (i = 0; i < count; ++i) {
     260           0 :     nsCOMPtr<nsISHEntry> childEntry;
     261           0 :     shCont->GetChildAt(i, getter_AddRefs(childEntry));
     262           0 :     MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
     263             :   }
     264             : 
     265             : }
     266             : 
     267             : void
     268           0 : MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, bool aPrepareForCC)
     269             : {
     270           0 :   nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
     271           0 :   if (!shell) {
     272           0 :     return;
     273             :   }
     274             : 
     275           0 :   nsCOMPtr<nsIContentViewer> cview;
     276           0 :   shell->GetContentViewer(getter_AddRefs(cview));
     277           0 :   MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
     278             : 
     279           0 :   nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
     280           0 :   nsCOMPtr<nsISHistory> history;
     281           0 :   webNav->GetSessionHistory(getter_AddRefs(history));
     282           0 :   if (history) {
     283             :     int32_t i, historyCount;
     284           0 :     history->GetCount(&historyCount);
     285           0 :     for (i = 0; i < historyCount; ++i) {
     286           0 :       nsCOMPtr<nsISHEntry> shEntry;
     287           0 :       history->GetEntryAtIndex(i, false, getter_AddRefs(shEntry));
     288             : 
     289           0 :       MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
     290             :     }
     291             :   }
     292             : 
     293             :   int32_t i, childCount;
     294           0 :   aNode->GetChildCount(&childCount);
     295           0 :   for (i = 0; i < childCount; ++i) {
     296           0 :     nsCOMPtr<nsIDocShellTreeItem> child;
     297           0 :     aNode->GetChildAt(i, getter_AddRefs(child));
     298           0 :     MarkDocShell(child, aCleanupJS, aPrepareForCC);
     299             :   }
     300             : }
     301             : 
     302             : void
     303           0 : MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
     304             :                bool aPrepareForCC)
     305             : {
     306           0 :   nsCOMPtr<nsISupports> iter;
     307           0 :   while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
     308           0 :          iter) {
     309           0 :     if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
     310           0 :       nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
     311             : 
     312           0 :       MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
     313             : 
     314             :       nsCOMPtr<nsITabChild> tabChild =
     315           0 :         rootDocShell ? rootDocShell->GetTabChild() : nullptr;
     316           0 :       if (tabChild) {
     317           0 :         nsCOMPtr<nsIContentFrameMessageManager> mm;
     318           0 :         tabChild->GetMessageManager(getter_AddRefs(mm));
     319           0 :         if (mm) {
     320             :           // MarkForCC ends up calling UnmarkGray on message listeners, which
     321             :           // TraceBlackJS can't do yet.
     322           0 :           mm->MarkForCC();
     323             :         }
     324             :       }
     325             :     }
     326             :   }
     327           0 : }
     328             : 
     329             : nsresult
     330           0 : nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
     331             :                                  const char16_t* aData)
     332             : {
     333           0 :   if (!strcmp(aTopic, "xpcom-shutdown")) {
     334           0 :     Element::ClearContentUnbinder();
     335             : 
     336             :     nsCOMPtr<nsIObserverService> obs =
     337           0 :       mozilla::services::GetObserverService();
     338           0 :     if (!obs)
     339           0 :       return NS_ERROR_FAILURE;
     340             : 
     341             :     // No need for kungFuDeathGrip here, yay observerservice!
     342           0 :     obs->RemoveObserver(this, "xpcom-shutdown");
     343           0 :     obs->RemoveObserver(this, "cycle-collector-begin");
     344           0 :     obs->RemoveObserver(this, "cycle-collector-forget-skippable");
     345             : 
     346           0 :     sGeneration = 0;
     347             : 
     348           0 :     return NS_OK;
     349             :   }
     350             : 
     351           0 :   NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
     352             :                !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
     353             : 
     354             :   // JS cleanup can be slow. Do it only if there has been a GC.
     355             :   bool cleanupJS =
     356           0 :     nsJSContext::CleanupsSinceLastGC() == 0 &&
     357           0 :     !strcmp(aTopic, "cycle-collector-forget-skippable");
     358             : 
     359           0 :   bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
     360           0 :   if (prepareForCC) {
     361           0 :     Element::ClearContentUnbinder();
     362             :   }
     363             : 
     364             :   // Increase generation to effectively unmark all current objects
     365           0 :   if (!++sGeneration) {
     366           0 :     ++sGeneration;
     367             :   }
     368             : 
     369           0 :   nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
     370             : 
     371             :   nsresult rv;
     372             : 
     373             :   // Iterate all toplevel windows
     374           0 :   nsCOMPtr<nsISimpleEnumerator> windowList;
     375             :   nsCOMPtr<nsIWindowMediator> med =
     376           0 :     do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
     377           0 :   if (med) {
     378           0 :     rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
     379           0 :     NS_ENSURE_SUCCESS(rv, rv);
     380             : 
     381           0 :     MarkWindowList(windowList, cleanupJS, prepareForCC);
     382             :   }
     383             : 
     384             :   nsCOMPtr<nsIWindowWatcher> ww =
     385           0 :     do_GetService(NS_WINDOWWATCHER_CONTRACTID);
     386           0 :   if (ww) {
     387           0 :     rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
     388           0 :     NS_ENSURE_SUCCESS(rv, rv);
     389             : 
     390           0 :     MarkWindowList(windowList, cleanupJS, prepareForCC);
     391             :   }
     392             : 
     393             :   nsCOMPtr<nsIAppShellService> appShell =
     394           0 :     do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
     395           0 :   if (appShell) {
     396           0 :     nsCOMPtr<nsIXULWindow> hw;
     397           0 :     appShell->GetHiddenWindow(getter_AddRefs(hw));
     398           0 :     if (hw) {
     399           0 :       nsCOMPtr<nsIDocShell> shell;
     400           0 :       hw->GetDocShell(getter_AddRefs(shell));
     401           0 :       MarkDocShell(shell, cleanupJS, prepareForCC);
     402             :     }
     403           0 :     bool hasHiddenPrivateWindow = false;
     404           0 :     appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
     405           0 :     if (hasHiddenPrivateWindow) {
     406           0 :       appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
     407           0 :       if (hw) {
     408           0 :         nsCOMPtr<nsIDocShell> shell;
     409           0 :         hw->GetDocShell(getter_AddRefs(shell));
     410           0 :         MarkDocShell(shell, cleanupJS, prepareForCC);
     411             :       }
     412             :     }
     413             :   }
     414             : 
     415             : #ifdef MOZ_XUL
     416           0 :   nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
     417           0 :   if (xulCache) {
     418           0 :     xulCache->MarkInCCGeneration(sGeneration);
     419             :   }
     420             : #endif
     421             : 
     422             :   enum ForgetSkippableCleanupState
     423             :   {
     424             :     eInitial = 0,
     425             :     eUnmarkJSEventListeners = 1,
     426             :     eUnmarkMessageManagers = 2,
     427             :     eUnmarkStrongObservers = 3,
     428             :     eUnmarkJSHolders = 4,
     429             :     eDone = 5
     430             :   };
     431             : 
     432             :   static_assert(eDone == NS_MAJOR_FORGET_SKIPPABLE_CALLS,
     433             :                 "There must be one forgetSkippable call per cleanup state.");
     434             : 
     435             :   static uint32_t sFSState = eDone;
     436           0 :   if (prepareForCC) {
     437           0 :     sFSState = eDone;
     438           0 :     return NS_OK;
     439             :   }
     440             : 
     441           0 :   if (cleanupJS) {
     442             :     // After a GC we start clean up phases from the beginning,
     443             :     // but we don't want to do the additional clean up phases here
     444             :     // since we have done already plenty of gray unmarking while going through
     445             :     // frame message managers and docshells.
     446           0 :     sFSState = eInitial;
     447           0 :     return NS_OK;
     448             :   } else {
     449           0 :     ++sFSState;
     450             :   }
     451             : 
     452           0 :   switch(sFSState) {
     453             :     case eUnmarkJSEventListeners: {
     454           0 :       nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments();
     455           0 :       break;
     456             :     }
     457             :     case eUnmarkMessageManagers: {
     458           0 :       MarkMessageManagers();
     459           0 :       break;
     460             :     }
     461             :     case eUnmarkStrongObservers: {
     462           0 :       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     463           0 :       static_cast<nsObserverService *>(obs.get())->UnmarkGrayStrongObservers();
     464           0 :       break;
     465             :     }
     466             :     case eUnmarkJSHolders: {
     467           0 :       xpc_UnmarkSkippableJSHolders();
     468           0 :       break;
     469             :     }
     470             :     default: {
     471           0 :       break;
     472             :     }
     473             :   }
     474             : 
     475           0 :   return NS_OK;
     476             : }
     477             : 
     478             : void
     479           1 : mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
     480             : {
     481             : #ifdef MOZ_XUL
     482             :   // Mark the scripts held in the XULPrototypeCache. This is required to keep
     483             :   // the JS script in the cache live across GC.
     484           1 :   nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
     485           1 :   if (cache) {
     486           1 :     if (aIsShutdownGC) {
     487           0 :       cache->FlushScripts();
     488             :     } else {
     489           1 :       cache->MarkInGC(aTrc);
     490             :     }
     491             :   }
     492             : #endif
     493             : 
     494           1 :   if (!nsCCUncollectableMarker::sGeneration) {
     495           0 :     return;
     496             :   }
     497             : 
     498           1 :   if (nsFrameMessageManager::GetChildProcessManager()) {
     499           1 :     nsIContentProcessMessageManager* pg = ProcessGlobal::Get();
     500           1 :     if (pg) {
     501           1 :       mozilla::TraceScriptHolder(pg, aTrc);
     502             :     }
     503             :   }
     504             : 
     505             :   // Mark globals of active windows black.
     506             :   nsGlobalWindow::WindowByIdTable* windowsById =
     507           1 :     nsGlobalWindow::GetWindowsTable();
     508           1 :   if (windowsById) {
     509          10 :     for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     510           9 :       nsGlobalWindow* window = iter.Data();
     511           9 :       if (window->GetDocShell() && window->IsOuterWindow()) {
     512           3 :         window->TraceGlobalJSObject(aTrc);
     513           3 :         EventListenerManager* elm = window->GetExistingListenerManager();
     514           3 :         if (elm) {
     515           1 :           elm->TraceListeners(aTrc);
     516             :         }
     517             : 
     518           3 :         if (window->IsRootOuterWindow()) {
     519             :           // In child process trace all the TabChildGlobals.
     520             :           // Since there is one root outer window per TabChildGlobal, we need
     521             :           // to look for only those windows, not all.
     522           2 :           nsIDocShell* ds = window->GetDocShell();
     523           2 :           if (ds) {
     524           4 :             nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild();
     525           2 :             if (tabChild) {
     526           0 :               nsCOMPtr<nsIContentFrameMessageManager> mm;
     527           0 :               tabChild->GetMessageManager(getter_AddRefs(mm));
     528           0 :               nsCOMPtr<EventTarget> et = do_QueryInterface(mm);
     529           0 :               if (et) {
     530             :                 nsCOMPtr<nsISupports> tabChildAsSupports =
     531           0 :                   do_QueryInterface(tabChild);
     532           0 :                 mozilla::TraceScriptHolder(tabChildAsSupports, aTrc);
     533           0 :                 EventListenerManager* elm = et->GetExistingListenerManager();
     534           0 :                 if (elm) {
     535           0 :                   elm->TraceListeners(aTrc);
     536             :                 }
     537             :                 // As of now there isn't an easy way to trace message listeners.
     538             :               }
     539             :             }
     540             :           }
     541             :         }
     542             : 
     543             : #ifdef MOZ_XUL
     544           3 :         nsIDocument* doc = window->GetExtantDoc();
     545           3 :         if (doc && doc->IsXULDocument()) {
     546           1 :           XULDocument* xulDoc = static_cast<XULDocument*>(doc);
     547           1 :           xulDoc->TraceProtos(aTrc, aGCNumber);
     548             :         }
     549             : #endif
     550             :       }
     551             :     }
     552             :   }
     553             : }

Generated by: LCOV version 1.13