2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
#include "nsCCUncollectableMarker.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsIContentViewer.h"
|
|
|
|
#include "nsIDocument.h"
|
2013-03-26 19:31:53 +04:00
|
|
|
#include "XULDocument.h"
|
2007-05-08 03:45:25 +04:00
|
|
|
#include "nsIWindowMediator.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIWebNavigation.h"
|
|
|
|
#include "nsISHistory.h"
|
|
|
|
#include "nsISHEntry.h"
|
|
|
|
#include "nsISHContainer.h"
|
|
|
|
#include "nsIWindowWatcher.h"
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
#include "mozilla/Services.h"
|
2011-11-29 21:19:08 +04:00
|
|
|
#include "nsIXULWindow.h"
|
|
|
|
#include "nsIAppShellService.h"
|
|
|
|
#include "nsAppShellCID.h"
|
2012-01-31 00:07:42 +04:00
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsGlobalWindow.h"
|
|
|
|
#include "nsJSEnvironment.h"
|
|
|
|
#include "nsInProcessTabChildGlobal.h"
|
|
|
|
#include "nsFrameLoader.h"
|
2016-09-28 21:27:35 +03:00
|
|
|
#include "mozilla/CycleCollectedJSContext.h"
|
2017-05-08 12:58:00 +03:00
|
|
|
#include "mozilla/CycleCollectedJSRuntime.h"
|
2014-03-17 10:56:53 +04:00
|
|
|
#include "mozilla/EventListenerManager.h"
|
2018-04-16 16:18:48 +03:00
|
|
|
#include "mozilla/dom/ChromeMessageBroadcaster.h"
|
2012-11-15 02:10:08 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2018-04-16 16:18:48 +03:00
|
|
|
#include "mozilla/dom/ParentProcessMessageManager.h"
|
2015-07-11 16:45:49 +03:00
|
|
|
#include "mozilla/dom/ProcessGlobal.h"
|
2018-03-01 22:19:56 +03:00
|
|
|
#include "mozilla/dom/TabChild.h"
|
2016-12-03 01:22:48 +03:00
|
|
|
#include "mozilla/dom/TimeoutManager.h"
|
2012-02-10 23:50:37 +04:00
|
|
|
#include "xpcpublic.h"
|
2012-04-30 23:01:11 +04:00
|
|
|
#include "nsObserverService.h"
|
2013-11-24 23:35:34 +04:00
|
|
|
#include "nsFocusManager.h"
|
2015-07-01 16:56:00 +03:00
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2014-03-17 10:56:53 +04:00
|
|
|
using namespace mozilla;
|
2012-11-15 02:10:08 +04:00
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool sInited = 0;
|
Bug 1300210 - Initialize nsCCUncollectableMarker::sGeneration to 1. r=smaug
The immediate reason we need to change this is that bug 1299911
proposes adding a verifier to check that there are no black-gray edges
in the JS heap, and sGeneration being 0 causes that to fail, due to
mozilla::dom::TraceBlackJS(). If something is a black root, I believe
the verifier requires that it be marked black. This makes sense,
because a black root is something that is definitely alive, and if the
object is marked gray, the CC might free it, as far as the GC knows.
This fails because when the browser starts, it GCs and marks the stuff
at the bottom of TraceBlackJS grey. Then it runs the CC, which flips
sGeneration to 1. Now, the verifier runs (before the GC runs!), and it
sees that the stuff in TraceBlackJS claims to be black, but is grey,
causing a verification failure.
In this particular case the code is actually safe. The purpose of the
black-gray invariant is to ensure that the CC does not incorrectly
unlink any gray C++ objects that are reachable from black JS
roots. The JS objects in TraceBlackJS should all be reachable directly
from a C++ object, and the CC knows that those C++ objects are alive
(because of refcounting). Therefore, the CC will not unlink any
objects that are reachable from black JS roots.
MozReview-Commit-ID: 8PrRkjqWBL
--HG--
extra : rebase_source : f9c2971bf71475202a1a6bbc719ab9ce19f94bc5
2016-09-03 01:51:05 +03:00
|
|
|
// The initial value of sGeneration should not be the same as the
|
|
|
|
// value it is given at xpcom-shutdown, because this will make any GCs
|
|
|
|
// before we first CC benignly violate the black-gray invariant, due
|
|
|
|
// to dom::TraceBlackJS().
|
|
|
|
uint32_t nsCCUncollectableMarker::sGeneration = 1;
|
2011-12-29 18:34:05 +04:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
#include "nsXULPrototypeCache.h"
|
|
|
|
#endif
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsCCUncollectableMarker, nsIObserver)
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsresult
|
|
|
|
nsCCUncollectableMarker::Init()
|
|
|
|
{
|
|
|
|
if (sInited) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-11-13 18:11:54 +03:00
|
|
|
|
2007-05-08 03:45:25 +04:00
|
|
|
nsCOMPtr<nsIObserver> marker = new nsCCUncollectableMarker;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs =
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (!obs)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsresult rv;
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
// This makes the observer service hold an owning reference to the marker
|
2011-10-17 18:59:28 +04:00
|
|
|
rv = obs->AddObserver(marker, "xpcom-shutdown", false);
|
2007-05-11 00:21:12 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
rv = obs->AddObserver(marker, "cycle-collector-begin", false);
|
2007-05-08 03:45:25 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-01-31 00:07:42 +04:00
|
|
|
rv = obs->AddObserver(marker, "cycle-collector-forget-skippable", false);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
sInited = true;
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-05-23 16:52:36 +04:00
|
|
|
static void
|
2018-04-16 16:18:48 +03:00
|
|
|
MarkChildMessageManagers(MessageBroadcaster* aMM)
|
2014-05-23 16:52:36 +04:00
|
|
|
{
|
|
|
|
aMM->MarkForCC();
|
|
|
|
|
2018-02-14 19:35:39 +03:00
|
|
|
uint32_t tabChildCount = aMM->ChildCount();
|
2014-05-23 16:52:36 +04:00
|
|
|
for (uint32_t j = 0; j < tabChildCount; ++j) {
|
2018-02-14 19:35:39 +03:00
|
|
|
RefPtr<MessageListenerManager> childMM = aMM->GetChildAt(j);
|
2014-05-23 16:52:36 +04:00
|
|
|
if (!childMM) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-16 16:18:48 +03:00
|
|
|
RefPtr<MessageBroadcaster> strongNonLeafMM = MessageBroadcaster::From(childMM);
|
|
|
|
MessageBroadcaster* nonLeafMM = strongNonLeafMM;
|
2014-05-23 16:52:36 +04:00
|
|
|
|
2018-02-16 12:34:21 +03:00
|
|
|
MessageListenerManager* tabMM = childMM;
|
2014-05-23 16:52:36 +04:00
|
|
|
|
|
|
|
strongNonLeafMM = nullptr;
|
|
|
|
childMM = nullptr;
|
|
|
|
|
|
|
|
if (nonLeafMM) {
|
|
|
|
MarkChildMessageManagers(nonLeafMM);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tabMM->MarkForCC();
|
|
|
|
|
|
|
|
//XXX hack warning, but works, since we know that
|
|
|
|
// callback is frameloader.
|
2018-02-16 12:34:21 +03:00
|
|
|
mozilla::dom::ipc::MessageManagerCallback* cb = tabMM->GetCallback();
|
2014-05-23 16:52:36 +04:00
|
|
|
if (cb) {
|
|
|
|
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
|
|
|
|
EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
|
|
|
|
if (!et) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
|
|
|
|
EventListenerManager* elm = et->GetExistingListenerManager();
|
|
|
|
if (elm) {
|
|
|
|
elm->MarkForCC();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-31 00:07:42 +04:00
|
|
|
static void
|
|
|
|
MarkMessageManagers()
|
|
|
|
{
|
2015-07-11 16:45:49 +03:00
|
|
|
if (nsFrameMessageManager::GetChildProcessManager()) {
|
|
|
|
// ProcessGlobal's MarkForCC marks also ChildProcessManager.
|
|
|
|
ProcessGlobal* pg = ProcessGlobal::Get();
|
|
|
|
if (pg) {
|
|
|
|
pg->MarkForCC();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 01:05:36 +04:00
|
|
|
// The global message manager only exists in the root process.
|
2015-07-04 04:29:00 +03:00
|
|
|
if (!XRE_IsParentProcess()) {
|
2013-06-08 01:05:36 +04:00
|
|
|
return;
|
|
|
|
}
|
2018-02-14 19:35:39 +03:00
|
|
|
RefPtr<ChromeMessageBroadcaster> strongGlobalMM =
|
|
|
|
nsFrameMessageManager::GetGlobalMessageManager();
|
2012-10-17 05:22:02 +04:00
|
|
|
if (!strongGlobalMM) {
|
2012-01-31 00:07:42 +04:00
|
|
|
return;
|
|
|
|
}
|
2018-02-14 19:35:39 +03:00
|
|
|
ChromeMessageBroadcaster* globalMM = strongGlobalMM;
|
2012-10-17 05:22:02 +04:00
|
|
|
strongGlobalMM = nullptr;
|
2014-05-23 16:52:36 +04:00
|
|
|
MarkChildMessageManagers(globalMM);
|
2012-01-31 00:07:42 +04:00
|
|
|
|
2012-10-17 05:22:02 +04:00
|
|
|
if (nsFrameMessageManager::sParentProcessManager) {
|
|
|
|
nsFrameMessageManager::sParentProcessManager->MarkForCC();
|
2018-02-14 19:35:39 +03:00
|
|
|
uint32_t childCount = nsFrameMessageManager::sParentProcessManager->ChildCount();
|
2012-10-17 05:22:02 +04:00
|
|
|
for (uint32_t i = 0; i < childCount; ++i) {
|
2018-02-14 19:35:39 +03:00
|
|
|
RefPtr<MessageListenerManager> childMM =
|
|
|
|
nsFrameMessageManager::sParentProcessManager->GetChildAt(i);
|
2012-10-17 05:22:02 +04:00
|
|
|
if (!childMM) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-02-14 19:35:39 +03:00
|
|
|
MessageListenerManager* child = childMM;
|
2012-10-17 05:22:02 +04:00
|
|
|
childMM = nullptr;
|
|
|
|
child->MarkForCC();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nsFrameMessageManager::sSameProcessParentManager) {
|
|
|
|
nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
|
|
|
|
}
|
2012-01-31 00:07:42 +04:00
|
|
|
}
|
|
|
|
|
2007-05-08 03:45:25 +04:00
|
|
|
void
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS)
|
2007-05-08 03:45:25 +04:00
|
|
|
{
|
|
|
|
if (!aViewer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-07 16:58:08 +04:00
|
|
|
nsIDocument *doc = aViewer->GetDocument();
|
2012-01-31 00:07:42 +04:00
|
|
|
if (doc &&
|
|
|
|
doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
|
2007-05-08 03:45:25 +04:00
|
|
|
doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
|
2012-01-31 00:07:42 +04:00
|
|
|
if (aCleanupJS) {
|
2014-03-17 10:56:53 +04:00
|
|
|
EventListenerManager* elm = doc->GetExistingListenerManager();
|
2012-01-31 00:07:42 +04:00
|
|
|
if (elm) {
|
2012-10-17 05:22:02 +04:00
|
|
|
elm->MarkForCC();
|
2012-01-31 00:07:42 +04:00
|
|
|
}
|
2013-04-06 04:44:15 +04:00
|
|
|
nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
|
2012-01-31 00:07:42 +04:00
|
|
|
if (win) {
|
2013-10-23 03:32:04 +04:00
|
|
|
elm = win->GetExistingListenerManager();
|
2012-01-31 00:07:42 +04:00
|
|
|
if (elm) {
|
2012-10-17 05:22:02 +04:00
|
|
|
elm->MarkForCC();
|
2012-01-31 00:07:42 +04:00
|
|
|
}
|
2017-11-04 01:25:38 +03:00
|
|
|
static_cast<nsGlobalWindowInner*>(win.get())->AsInner()->
|
2016-12-03 01:22:48 +03:00
|
|
|
TimeoutManager().UnmarkGrayTimers();
|
2012-01-31 00:07:42 +04:00
|
|
|
}
|
|
|
|
}
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
2013-11-24 23:35:34 +04:00
|
|
|
if (doc) {
|
2016-01-30 20:05:36 +03:00
|
|
|
if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) {
|
2013-11-24 23:35:34 +04:00
|
|
|
inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
|
|
|
|
}
|
2016-01-30 20:05:36 +03:00
|
|
|
if (nsPIDOMWindowOuter* outer = doc->GetWindow()) {
|
2013-11-24 23:35:34 +04:00
|
|
|
outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
|
|
|
|
}
|
|
|
|
}
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
void
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS)
|
2007-05-08 03:45:25 +04:00
|
|
|
{
|
|
|
|
if (!aSHEntry) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentViewer> cview;
|
|
|
|
aSHEntry->GetContentViewer(getter_AddRefs(cview));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkContentViewer(cview, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> child;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i = 0;
|
2007-05-08 03:45:25 +04:00
|
|
|
while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
|
|
|
|
child) {
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(child, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t count;
|
2007-05-08 03:45:25 +04:00
|
|
|
shCont->GetChildCount(&count);
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
nsCOMPtr<nsISHEntry> childEntry;
|
|
|
|
shCont->GetChildAt(i, getter_AddRefs(childEntry));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkSHEntry(childEntry, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
2014-11-13 18:11:54 +03:00
|
|
|
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS)
|
2007-05-08 03:45:25 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
|
|
|
|
if (!shell) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentViewer> cview;
|
|
|
|
shell->GetContentViewer(getter_AddRefs(cview));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkContentViewer(cview, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
|
2018-02-02 01:35:47 +03:00
|
|
|
RefPtr<ChildSHistory> history = webNav->GetSessionHistory();
|
2007-05-08 03:45:25 +04:00
|
|
|
if (history) {
|
2018-02-02 01:35:47 +03:00
|
|
|
int32_t historyCount = history->Count();
|
|
|
|
for (int32_t i = 0; i < historyCount; ++i) {
|
2013-08-30 08:14:59 +04:00
|
|
|
nsCOMPtr<nsISHEntry> shEntry;
|
2018-02-02 01:35:47 +03:00
|
|
|
history->LegacySHistory()->GetEntryAtIndex(
|
|
|
|
i, false, getter_AddRefs(shEntry));
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkSHEntry(shEntry, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i, childCount;
|
2007-05-08 03:45:25 +04:00
|
|
|
aNode->GetChildCount(&childCount);
|
|
|
|
for (i = 0; i < childCount; ++i) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> child;
|
|
|
|
aNode->GetChildAt(i, getter_AddRefs(child));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(child, aCleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS)
|
2007-05-08 03:45:25 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> iter;
|
|
|
|
while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
|
|
|
|
iter) {
|
2016-01-30 20:05:36 +03:00
|
|
|
if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
|
2014-01-07 02:34:15 +04:00
|
|
|
nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(rootDocShell, aCleanupJS);
|
2015-02-25 01:25:34 +03:00
|
|
|
|
2018-03-01 22:19:56 +03:00
|
|
|
RefPtr<TabChild> tabChild = TabChild::GetFrom(rootDocShell);
|
2015-02-25 01:25:34 +03:00
|
|
|
if (tabChild) {
|
2018-02-16 17:28:31 +03:00
|
|
|
RefPtr<TabChildGlobal> mm = tabChild->GetMessageManager();
|
2015-02-25 01:25:34 +03:00
|
|
|
if (mm) {
|
2016-09-28 21:27:35 +03:00
|
|
|
// MarkForCC ends up calling UnmarkGray on message listeners, which
|
|
|
|
// TraceBlackJS can't do yet.
|
2015-02-25 01:25:34 +03:00
|
|
|
mm->MarkForCC();
|
|
|
|
}
|
|
|
|
}
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t* aData)
|
2007-05-08 03:45:25 +04:00
|
|
|
{
|
2007-05-11 00:21:12 +04:00
|
|
|
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
2015-07-02 13:34:00 +03:00
|
|
|
Element::ClearContentUnbinder();
|
|
|
|
|
2007-05-11 00:21:12 +04:00
|
|
|
nsCOMPtr<nsIObserverService> obs =
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (!obs)
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-05-11 00:21:12 +04:00
|
|
|
|
|
|
|
// No need for kungFuDeathGrip here, yay observerservice!
|
|
|
|
obs->RemoveObserver(this, "xpcom-shutdown");
|
|
|
|
obs->RemoveObserver(this, "cycle-collector-begin");
|
2012-01-31 00:07:42 +04:00
|
|
|
obs->RemoveObserver(this, "cycle-collector-forget-skippable");
|
2014-11-13 18:11:54 +03:00
|
|
|
|
2007-05-11 00:21:12 +04:00
|
|
|
sGeneration = 0;
|
2014-11-13 18:11:54 +03:00
|
|
|
|
2007-05-11 00:21:12 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 00:07:42 +04:00
|
|
|
NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
|
|
|
|
!strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
|
|
|
|
|
|
|
|
// JS cleanup can be slow. Do it only if there has been a GC.
|
2018-03-17 07:30:49 +03:00
|
|
|
const bool cleanupJS =
|
2012-05-03 20:17:01 +04:00
|
|
|
nsJSContext::CleanupsSinceLastGC() == 0 &&
|
2012-01-31 00:07:42 +04:00
|
|
|
!strcmp(aTopic, "cycle-collector-forget-skippable");
|
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
const bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
|
2015-07-02 13:34:00 +03:00
|
|
|
if (prepareForCC) {
|
|
|
|
Element::ClearContentUnbinder();
|
|
|
|
}
|
2007-05-11 00:21:12 +04:00
|
|
|
|
2013-02-22 06:10:59 +04:00
|
|
|
// Increase generation to effectively unmark all current objects
|
2007-05-11 00:21:12 +04:00
|
|
|
if (!++sGeneration) {
|
|
|
|
++sGeneration;
|
|
|
|
}
|
2007-05-08 03:45:25 +04:00
|
|
|
|
2013-11-24 23:35:34 +04:00
|
|
|
nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
|
|
|
|
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
nsresult rv;
|
|
|
|
|
2007-05-08 03:45:25 +04:00
|
|
|
// Iterate all toplevel windows
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> windowList;
|
|
|
|
nsCOMPtr<nsIWindowMediator> med =
|
|
|
|
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
|
|
|
|
if (med) {
|
2012-07-30 18:20:58 +04:00
|
|
|
rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
|
2007-05-08 03:45:25 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkWindowList(windowList, cleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWindowWatcher> ww =
|
|
|
|
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
|
|
|
|
if (ww) {
|
|
|
|
rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkWindowList(windowList, cleanupJS);
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
2007-05-11 00:21:12 +04:00
|
|
|
|
2014-11-13 18:11:54 +03:00
|
|
|
nsCOMPtr<nsIAppShellService> appShell =
|
2011-11-29 21:19:08 +04:00
|
|
|
do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
|
|
|
|
if (appShell) {
|
|
|
|
nsCOMPtr<nsIXULWindow> hw;
|
|
|
|
appShell->GetHiddenWindow(getter_AddRefs(hw));
|
|
|
|
if (hw) {
|
|
|
|
nsCOMPtr<nsIDocShell> shell;
|
|
|
|
hw->GetDocShell(getter_AddRefs(shell));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(shell, cleanupJS);
|
2011-11-29 21:19:08 +04:00
|
|
|
}
|
2013-01-07 06:16:48 +04:00
|
|
|
bool hasHiddenPrivateWindow = false;
|
|
|
|
appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
|
|
|
|
if (hasHiddenPrivateWindow) {
|
|
|
|
appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
|
|
|
|
if (hw) {
|
|
|
|
nsCOMPtr<nsIDocShell> shell;
|
|
|
|
hw->GetDocShell(getter_AddRefs(shell));
|
2018-03-17 07:30:49 +03:00
|
|
|
MarkDocShell(shell, cleanupJS);
|
2013-01-07 06:16:48 +04:00
|
|
|
}
|
2012-12-11 08:49:17 +04:00
|
|
|
}
|
2011-11-29 21:19:08 +04:00
|
|
|
}
|
|
|
|
|
2011-12-29 18:34:05 +04:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
|
|
|
|
if (xulCache) {
|
|
|
|
xulCache->MarkInCCGeneration(sGeneration);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-11-12 22:33:50 +03:00
|
|
|
enum ForgetSkippableCleanupState
|
|
|
|
{
|
|
|
|
eInitial = 0,
|
|
|
|
eUnmarkJSEventListeners = 1,
|
|
|
|
eUnmarkMessageManagers = 2,
|
|
|
|
eUnmarkStrongObservers = 3,
|
|
|
|
eUnmarkJSHolders = 4,
|
|
|
|
eDone = 5
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(eDone == NS_MAJOR_FORGET_SKIPPABLE_CALLS,
|
|
|
|
"There must be one forgetSkippable call per cleanup state.");
|
|
|
|
|
|
|
|
static uint32_t sFSState = eDone;
|
|
|
|
if (prepareForCC) {
|
|
|
|
sFSState = eDone;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-04-30 23:01:11 +04:00
|
|
|
|
2014-11-12 22:33:50 +03:00
|
|
|
if (cleanupJS) {
|
|
|
|
// After a GC we start clean up phases from the beginning,
|
|
|
|
// but we don't want to do the additional clean up phases here
|
|
|
|
// since we have done already plenty of gray unmarking while going through
|
|
|
|
// frame message managers and docshells.
|
|
|
|
sFSState = eInitial;
|
|
|
|
return NS_OK;
|
|
|
|
} else {
|
|
|
|
++sFSState;
|
|
|
|
}
|
2012-04-30 23:01:11 +04:00
|
|
|
|
2014-11-12 22:33:50 +03:00
|
|
|
switch(sFSState) {
|
|
|
|
case eUnmarkJSEventListeners: {
|
2015-06-10 23:07:40 +03:00
|
|
|
nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments();
|
2014-11-12 22:33:50 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eUnmarkMessageManagers: {
|
|
|
|
MarkMessageManagers();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eUnmarkStrongObservers: {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
static_cast<nsObserverService *>(obs.get())->UnmarkGrayStrongObservers();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eUnmarkJSHolders: {
|
2012-04-25 17:43:18 +04:00
|
|
|
xpc_UnmarkSkippableJSHolders();
|
2014-11-12 22:33:50 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
break;
|
2012-04-25 17:43:18 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-11 00:21:12 +04:00
|
|
|
return NS_OK;
|
2007-05-08 03:45:25 +04:00
|
|
|
}
|
|
|
|
|
2012-03-27 23:22:10 +04:00
|
|
|
void
|
2017-11-14 20:10:30 +03:00
|
|
|
mozilla::dom::TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC)
|
2012-03-27 23:22:10 +04:00
|
|
|
{
|
2013-03-19 21:20:21 +04:00
|
|
|
#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
|
|
|
|
|
2012-03-27 23:22:10 +04:00
|
|
|
if (!nsCCUncollectableMarker::sGeneration) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-26 17:54:00 +03:00
|
|
|
if (ProcessGlobal::WasCreated() && nsFrameMessageManager::GetChildProcessManager()) {
|
2018-02-09 18:02:37 +03:00
|
|
|
ProcessGlobal* pg = ProcessGlobal::Get();
|
2016-09-28 21:27:35 +03:00
|
|
|
if (pg) {
|
2018-02-09 18:02:37 +03:00
|
|
|
mozilla::TraceScriptHolder(ToSupports(pg), aTrc);
|
2016-09-28 21:27:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-27 23:22:10 +04:00
|
|
|
// Mark globals of active windows black.
|
2017-11-07 01:59:12 +03:00
|
|
|
nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
|
|
|
|
nsGlobalWindowOuter::GetWindowsTable();
|
2012-03-27 23:22:10 +04:00
|
|
|
if (windowsById) {
|
2016-01-29 01:08:19 +03:00
|
|
|
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
2017-11-07 01:59:12 +03:00
|
|
|
nsGlobalWindowOuter* window = iter.Data();
|
|
|
|
if (!window->IsCleanedUp()) {
|
2017-11-30 02:24:46 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2016-01-29 01:08:19 +03:00
|
|
|
}
|
|
|
|
|
2016-09-28 21:27:35 +03:00
|
|
|
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) {
|
2018-03-01 22:19:56 +03:00
|
|
|
nsCOMPtr<nsISupports> mm;
|
2016-09-28 21:27:35 +03:00
|
|
|
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.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-29 01:08:19 +03:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
nsIDocument* doc = window->GetExtantDoc();
|
|
|
|
if (doc && doc->IsXULDocument()) {
|
|
|
|
XULDocument* xulDoc = static_cast<XULDocument*>(doc);
|
2017-11-14 20:10:30 +03:00
|
|
|
xulDoc->TraceProtos(aTrc);
|
2016-01-29 01:08:19 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2012-03-27 23:22:10 +04:00
|
|
|
}
|
|
|
|
}
|