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