Bug 348156: Fix leaks by relying on cycle collector rather than calling UnbindFromTree on all nodes. r/sr=jst

This commit is contained in:
jonas@sicking.cc 2007-10-02 11:20:02 -07:00
Родитель 9ace39b434
Коммит 556991d5f5
13 изменённых файлов: 87 добавлений и 30 удалений

Просмотреть файл

@ -63,8 +63,8 @@ class nsIDocShell;
// IID for the nsIContent interface // IID for the nsIContent interface
#define NS_ICONTENT_IID \ #define NS_ICONTENT_IID \
{ 0x36b375cb, 0xf01e, 0x4c18, \ { 0xe0c5d967, 0x2c15, 0x4097, \
{ 0xbf, 0x9e, 0xba, 0xad, 0x77, 0x1d, 0xce, 0x22 } } { 0xb0, 0xdc, 0x75, 0xa3, 0xa7, 0xfc, 0xcd, 0x1a } }
// hack to make egcs / gcc 2.95.2 happy // hack to make egcs / gcc 2.95.2 happy
class nsIContent_base : public nsINode { class nsIContent_base : public nsINode {
@ -793,6 +793,12 @@ public:
*/ */
virtual void UpdateEditableState(); virtual void UpdateEditableState();
/**
* Destroy this node and it's children. Ideally this shouldn't be needed
* but for now we need to do it to break cycles.
*/
virtual void DestroyContent() = 0;
#ifdef DEBUG #ifdef DEBUG
/** /**
* List the content (and anything it contains) out to the given * List the content (and anything it contains) out to the given

Просмотреть файл

@ -2058,7 +2058,10 @@ SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry); SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
NS_RELEASE(e->mKey); NS_RELEASE(e->mKey);
NS_IF_RELEASE(e->mSubDocument); if (e->mSubDocument) {
e->mSubDocument->SetParentDocument(nsnull);
NS_RELEASE(e->mSubDocument);
}
} }
PR_STATIC_CALLBACK(PRBool) PR_STATIC_CALLBACK(PRBool)
@ -2091,8 +2094,6 @@ nsDocument::SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc)
PL_DHASH_LOOKUP)); PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) { if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
entry->mSubDocument->SetParentDocument(nsnull);
PL_DHashTableRawRemove(mSubDocuments, entry); PL_DHashTableRawRemove(mSubDocuments, entry);
} }
} }
@ -5572,26 +5573,16 @@ nsDocument::Destroy()
if (mIsGoingAway) if (mIsGoingAway)
return; return;
PRInt32 count = mChildren.ChildCount();
mIsGoingAway = PR_TRUE; mIsGoingAway = PR_TRUE;
DestroyLinkMap();
for (PRInt32 indx = 0; indx < count; ++indx) { PRUint32 i, count = mChildren.ChildCount();
// XXXbz what we _should_ do here is to clear mChildren and null out for (i = 0; i < count; ++i) {
// mRootContent. If we did this (or at least the latter), we could remove mChildren.ChildAt(i)->DestroyContent();
// the silly null-checks in nsHTMLDocument::MatchLinks. Unfortunately,
// doing that introduces several problems:
// 1) Focus issues (see bug 341730). The fix for bug 303260 may fix these.
// 2) Crashes in OnPageHide if it fires after Destroy. See bug 303260
// comments 9 and 10.
// So we're just creating an inconsistent DOM for now and hoping. :(
mChildren.ChildAt(indx)->UnbindFromTree();
} }
mLayoutHistoryState = nsnull; mLayoutHistoryState = nsnull;
nsContentList::OnDocumentDestroy(this); nsContentList::OnDocumentDestroy(this);
delete mContentWrapperHash;
mContentWrapperHash = nsnull;
} }
already_AddRefed<nsILayoutHistoryState> already_AddRefed<nsILayoutHistoryState>

Просмотреть файл

@ -811,6 +811,10 @@ nsGenericDOMDataNode::IsNodeOfType(PRUint32 aFlags) const
return !(aFlags & ~(eCONTENT | eDATA_NODE)); return !(aFlags & ~(eCONTENT | eDATA_NODE));
} }
void
nsGenericDOMDataNode::DestroyContent()
{
}
#ifdef DEBUG #ifdef DEBUG
void void

Просмотреть файл

@ -225,6 +225,7 @@ public:
PRBool aNotify); PRBool aNotify);
virtual PRBool TextIsOnlyWhitespace(); virtual PRBool TextIsOnlyWhitespace();
virtual void AppendTextTo(nsAString& aResult); virtual void AppendTextTo(nsAString& aResult);
virtual void DestroyContent();
#ifdef DEBUG #ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const; virtual void List(FILE* out, PRInt32 aIndent) const;
virtual void DumpContent(FILE* out, PRInt32 aIndent, PRBool aDumpAll) const; virtual void DumpContent(FILE* out, PRInt32 aIndent, PRBool aDumpAll) const;

Просмотреть файл

@ -2857,6 +2857,22 @@ nsGenericElement::GetPrimaryFrameFor(nsIContent* aContent,
return presShell->GetPrimaryFrameFor(aContent); return presShell->GetPrimaryFrameFor(aContent);
} }
void
nsGenericElement::DestroyContent()
{
nsIDocument *document = GetOwnerDoc();
if (document) {
document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
document->ClearBoxObjectFor(this);
}
PRUint32 i, count = mAttrsAndChildren.ChildCount();
for (i = 0; i < count; ++i) {
// The child can remove itself from the parent in BindToTree.
mAttrsAndChildren.ChildAt(i)->DestroyContent();
}
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Generic DOMNode implementations // Generic DOMNode implementations
@ -3348,8 +3364,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
// Unlink any DOM slots of interest. // Unlink any DOM slots of interest.
{ {
nsDOMSlots *slots = tmp->GetExistingDOMSlots(); nsDOMSlots *slots = tmp->GetExistingDOMSlots();
if (slots) if (slots) {
slots->mAttributeMap = nsnull; slots->mAttributeMap = nsnull;
if (tmp->IsNodeOfType(nsINode::eXUL))
NS_IF_RELEASE(slots->mControllers);
}
} }
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END

Просмотреть файл

@ -434,6 +434,7 @@ public:
virtual PRUint32 GetScriptTypeID() const; virtual PRUint32 GetScriptTypeID() const;
virtual nsresult SetScriptTypeID(PRUint32 aLang); virtual nsresult SetScriptTypeID(PRUint32 aLang);
virtual void DestroyContent();
#ifdef DEBUG #ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const virtual void List(FILE* out, PRInt32 aIndent) const
{ {

Просмотреть файл

@ -3065,6 +3065,17 @@ nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
return rv; return rv;
} }
void
nsGenericHTMLFrameElement::DestroyContent()
{
if (mFrameLoader) {
mFrameLoader->Destroy();
mFrameLoader = nsnull;
}
nsGenericHTMLElement::DestroyContent();
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void

Просмотреть файл

@ -919,6 +919,7 @@ public:
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue, nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify); PRBool aNotify);
virtual void DestroyContent();
// nsIDOMNSHTMLElement // nsIDOMNSHTMLElement
NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex); NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);

Просмотреть файл

@ -323,7 +323,7 @@ protected:
/** The request currently being submitted */ /** The request currently being submitted */
nsCOMPtr<nsIRequest> mSubmittingRequest; nsCOMPtr<nsIRequest> mSubmittingRequest;
/** The web progress object we are currently listening to */ /** The web progress object we are currently listening to */
nsCOMPtr<nsIWebProgress> mWebProgress; nsWeakPtr mWebProgress;
/** The default submit element -- WEAK */ /** The default submit element -- WEAK */
nsIFormControl* mDefaultSubmitElement; nsIFormControl* mDefaultSubmitElement;
@ -1025,10 +1025,12 @@ nsHTMLFormElement::SubmitSubmission(nsIFormSubmission* aFormSubmission)
PRBool pending = PR_FALSE; PRBool pending = PR_FALSE;
mSubmittingRequest->IsPending(&pending); mSubmittingRequest->IsPending(&pending);
if (pending && !schemeIsJavaScript) { if (pending && !schemeIsJavaScript) {
mWebProgress = do_GetInterface(docShell); nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
NS_ASSERTION(mWebProgress, "nsIDocShell not converted to nsIWebProgress!"); NS_ASSERTION(webProgress, "nsIDocShell not converted to nsIWebProgress!");
rv = mWebProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL); rv = webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL);
NS_ENSURE_SUBMIT_SUCCESS(rv); NS_ENSURE_SUBMIT_SUCCESS(rv);
mWebProgress = do_GetWeakReference(webProgress);
NS_ASSERTION(mWebProgress, "can't hold weak ref to webprogress!");
} else { } else {
ForgetCurrentSubmission(); ForgetCurrentSubmission();
} }
@ -1645,10 +1647,11 @@ nsHTMLFormElement::ForgetCurrentSubmission()
mNotifiedObservers = PR_FALSE; mNotifiedObservers = PR_FALSE;
mIsSubmitting = PR_FALSE; mIsSubmitting = PR_FALSE;
mSubmittingRequest = nsnull; mSubmittingRequest = nsnull;
if (mWebProgress) { nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress);
mWebProgress->RemoveProgressListener(this); if (webProgress) {
mWebProgress = nsnull; webProgress->RemoveProgressListener(this);
} }
mWebProgress = nsnull;
} }
// nsIWebProgressListener // nsIWebProgressListener

Просмотреть файл

@ -104,8 +104,15 @@ nsXTFElementWrapper::Init()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// nsISupports implementation // nsISupports implementation
NS_IMPL_ADDREF_INHERITED(nsXTFElementWrapper,nsXTFElementWrapperBase) NS_IMPL_ADDREF_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase)
NS_IMPL_RELEASE_INHERITED(nsXTFElementWrapper,nsXTFElementWrapperBase) NS_IMPL_RELEASE_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXTFElementWrapper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXTFElementWrapper,
nsXTFElementWrapperBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXTFElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAttributeHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMETHODIMP NS_IMETHODIMP
nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr) nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr)

Просмотреть файл

@ -65,6 +65,8 @@ public:
// nsISupports interface // nsISupports interface
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXTFElementWrapper,
nsXTFElementWrapperBase)
// nsIXTFElementWrapper // nsIXTFElementWrapper
NS_DECL_NSIXTFELEMENTWRAPPER NS_DECL_NSIXTFELEMENTWRAPPER

Просмотреть файл

@ -1447,6 +1447,16 @@ nsXULElement::GetAttrCount() const
return count; return count;
} }
void
nsXULElement::DestroyContent()
{
nsDOMSlots* slots = GetExistingDOMSlots();
if (slots) {
NS_IF_RELEASE(slots->mControllers);
}
nsGenericElement::DestroyContent();
}
#ifdef DEBUG #ifdef DEBUG
void void

Просмотреть файл

@ -531,6 +531,7 @@ public:
PRBool aNotify); PRBool aNotify);
virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const; virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const;
virtual PRUint32 GetAttrCount() const; virtual PRUint32 GetAttrCount() const;
virtual void DestroyContent();
#ifdef DEBUG #ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const; virtual void List(FILE* out, PRInt32 aIndent) const;