зеркало из https://github.com/mozilla/gecko-dev.git
b=333078, xpcom cycle collector -- patch from graydon@mozilla.com, r=many
This commit is contained in:
Родитель
bc3036afa7
Коммит
3748c8bf4f
|
@ -55,7 +55,6 @@ nsContentPolicyUtils.h \
|
||||||
nsContentUtils.h \
|
nsContentUtils.h \
|
||||||
nsIDocument.h \
|
nsIDocument.h \
|
||||||
nsIDocumentObserver.h \
|
nsIDocumentObserver.h \
|
||||||
nsIDOMGCParticipant.h \
|
|
||||||
nsIMutationObserver.h \
|
nsIMutationObserver.h \
|
||||||
nsINameSpaceManager.h \
|
nsINameSpaceManager.h \
|
||||||
nsINode.h \
|
nsINode.h \
|
||||||
|
|
|
@ -781,6 +781,20 @@ public:
|
||||||
PRBool aCancelable,
|
PRBool aCancelable,
|
||||||
PRBool *aDefaultAction = nsnull);
|
PRBool *aDefaultAction = nsnull);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only during traversal of the XPCOM graph by the cycle
|
||||||
|
* collector: push a pointer to the listener manager onto the
|
||||||
|
* children deque, if it exists. Do nothing if there is no listener
|
||||||
|
* manager.
|
||||||
|
*
|
||||||
|
* Crucially: does not perform any refcounting operations.
|
||||||
|
*
|
||||||
|
* @param aNode The node to traverse.
|
||||||
|
* @param children The buffer to push a listener manager pointer into.
|
||||||
|
*/
|
||||||
|
static void TraverseListenerManager(nsINode *aNode,
|
||||||
|
nsCycleCollectionTraversalCallback &cb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the eventlistener manager for aNode. If a new eventlistener manager
|
* Get the eventlistener manager for aNode. If a new eventlistener manager
|
||||||
* was created, aCreated is set to PR_TRUE.
|
* was created, aCreated is set to PR_TRUE.
|
||||||
|
@ -933,7 +947,9 @@ private:
|
||||||
static nsresult doReparentContentWrapper(nsIContent *aChild,
|
static nsresult doReparentContentWrapper(nsIContent *aChild,
|
||||||
JSContext *cx,
|
JSContext *cx,
|
||||||
JSObject *aOldGlobal,
|
JSObject *aOldGlobal,
|
||||||
JSObject *aNewGlobal);
|
JSObject *aNewGlobal,
|
||||||
|
nsIDocument *aOldDocument,
|
||||||
|
nsIDocument *aNewDocument);
|
||||||
|
|
||||||
static nsresult EnsureStringBundle(PropertiesFile aFile);
|
static nsresult EnsureStringBundle(PropertiesFile aFile);
|
||||||
|
|
||||||
|
|
|
@ -769,4 +769,31 @@ public:
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID)
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID)
|
||||||
|
|
||||||
|
// Some cycle-collecting helper macros for nsIContent subclasses
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER \
|
||||||
|
if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) { \
|
||||||
|
nsContentUtils::TraverseListenerManager(tmp, cb); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER \
|
||||||
|
{ \
|
||||||
|
nsISupports *preservedWrapper = nsnull; \
|
||||||
|
if (tmp->GetOwnerDoc()) \
|
||||||
|
preservedWrapper = tmp->GetOwnerDoc()->GetReference(tmp); \
|
||||||
|
if (preservedWrapper) \
|
||||||
|
cb.NoteXPCOMChild(preservedWrapper); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER \
|
||||||
|
if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) { \
|
||||||
|
nsContentUtils::RemoveListenerManager(tmp); \
|
||||||
|
tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
|
||||||
|
if (tmp->GetOwnerDoc()) \
|
||||||
|
tmp->GetOwnerDoc()->RemoveReference(tmp);
|
||||||
|
|
||||||
|
|
||||||
#endif /* nsIContent_h___ */
|
#endif /* nsIContent_h___ */
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* ***** BEGIN LICENSE BLOCK *****
|
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing rights and limitations under the
|
|
||||||
* License.
|
|
||||||
*
|
|
||||||
* The Original Code is mozilla.org code.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is
|
|
||||||
* Netscape Communications Corporation.
|
|
||||||
* Portions created by the Initial Developer are Copyright (C) 1998-1999
|
|
||||||
* the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
||||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
||||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
||||||
* of those above. If you wish to allow use of your version of this file only
|
|
||||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
||||||
* use your version of this file under the terms of the MPL, indicate your
|
|
||||||
* decision by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
||||||
* the provisions above, a recipient may use your version of this file under
|
|
||||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
||||||
*
|
|
||||||
* ***** END LICENSE BLOCK ***** */
|
|
||||||
|
|
||||||
#ifndef nsIDOMGCParticipant_h_
|
|
||||||
#define nsIDOMGCParticipant_h_
|
|
||||||
|
|
||||||
#include "nsISupports.h"
|
|
||||||
|
|
||||||
template<class E> class nsCOMArray;
|
|
||||||
|
|
||||||
// 0e2a5a8d-28fd-4a5c-8bf1-5b0067ff3286
|
|
||||||
#define NS_IDOMGCPARTICIPANT_IID \
|
|
||||||
{ 0x0e2a5a8d, 0x28fd, 0x4a5c, \
|
|
||||||
{0x8b, 0xf1, 0x5b, 0x00, 0x67, 0xff, 0x32, 0x86} }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DOM GC Participants are objects that expose information about
|
|
||||||
* reachability in the native object graphs to help prevent script ->
|
|
||||||
* native -> script cyclical reference from causing leaks due to the
|
|
||||||
* creation of garbage collection roots and native/script boundaries.
|
|
||||||
*
|
|
||||||
* Some implementations of nsIDOMGCParticipant may be responsible for
|
|
||||||
* enforcing the requirement that callers of
|
|
||||||
* |nsDOMClassInfo::PreserveWrapper| must call
|
|
||||||
* |nsDOMClassInfo::ReleaseWrapper| before the nsIDOMGCParticipant
|
|
||||||
* argument to the former is destroyed.
|
|
||||||
*/
|
|
||||||
class nsIDOMGCParticipant : public nsISupports
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMGCPARTICIPANT_IID)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a reference node for what is known to be a strongly connected
|
|
||||||
* component of nsIDOMGCParticipants. For example, DOM trees are
|
|
||||||
* strongly connected, so can return the root node to greatly reduce
|
|
||||||
* the number of nodes on which we need to run graph algorithms.
|
|
||||||
*
|
|
||||||
* Note that it's acceptable for nodes in a single strongly connected
|
|
||||||
* component to return different values for GetSCCIndex, as long as
|
|
||||||
* those two values claim that they're reachable from each other in
|
|
||||||
* AppendReachableList.
|
|
||||||
*/
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append the list of nsIDOMGCPartipants reachable from this one via
|
|
||||||
* C++ getters exposed to script that return a different result from
|
|
||||||
* |GetSCCIndex|. The caller is responsible for taking the transitive
|
|
||||||
* closure of |AppendReachableList|.
|
|
||||||
*
|
|
||||||
* This will only be called on objects that are returned by GetSCCIndex.
|
|
||||||
*
|
|
||||||
* null pointers may be appended; they will be ignored by the caller.
|
|
||||||
*/
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMGCParticipant, NS_IDOMGCPARTICIPANT_IID)
|
|
||||||
|
|
||||||
#endif // !defined(nsIDOMGCParticipant_h_)
|
|
|
@ -607,6 +607,10 @@ public:
|
||||||
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup* aLoadGroup,
|
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup* aLoadGroup,
|
||||||
nsIPrincipal* aPrincipal) = 0;
|
nsIPrincipal* aPrincipal) = 0;
|
||||||
|
|
||||||
|
virtual void AddReference(void *aKey, nsISupports *aReference) = 0;
|
||||||
|
virtual nsISupports *GetReference(void *aKey) = 0;
|
||||||
|
virtual already_AddRefed<nsISupports> RemoveReference(void *aKey) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the container (docshell) for this document.
|
* Set the container (docshell) for this document.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
#ifndef nsINode_h___
|
#ifndef nsINode_h___
|
||||||
#define nsINode_h___
|
#define nsINode_h___
|
||||||
|
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
#include "nsEvent.h"
|
#include "nsEvent.h"
|
||||||
#include "nsPropertyTable.h"
|
#include "nsPropertyTable.h"
|
||||||
#include "nsTObserverArray.h"
|
#include "nsTObserverArray.h"
|
||||||
|
@ -97,11 +96,11 @@ class nsNodeSupportsWeakRefTearoff;
|
||||||
|
|
||||||
// IID for the nsINode interface
|
// IID for the nsINode interface
|
||||||
#define NS_INODE_IID \
|
#define NS_INODE_IID \
|
||||||
{ 0x98470c4b, 0xe988, 0x4abf, \
|
{ 0x0d2a583d, 0x7a99, 0x426b, \
|
||||||
{ 0xa4, 0x00, 0x39, 0xbd, 0x00, 0x38, 0x51, 0x4d } }
|
{ 0x89, 0xfa, 0xca, 0x8d, 0x63, 0xbb, 0xd7, 0x3f } }
|
||||||
|
|
||||||
// hack to make egcs / gcc 2.95.2 happy
|
// hack to make egcs / gcc 2.95.2 happy
|
||||||
class nsINode_base : public nsIDOMGCParticipant {
|
class nsINode_base : public nsISupports {
|
||||||
public:
|
public:
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
|
||||||
};
|
};
|
||||||
|
|
|
@ -143,6 +143,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||||
#ifdef IBMBIDI
|
#ifdef IBMBIDI
|
||||||
#include "nsIBidiKeyboard.h"
|
#include "nsIBidiKeyboard.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
// for ReportToConsole
|
// for ReportToConsole
|
||||||
#include "nsIStringBundle.h"
|
#include "nsIStringBundle.h"
|
||||||
|
@ -731,7 +732,9 @@ nsresult
|
||||||
nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
|
nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
|
||||||
JSContext *cx,
|
JSContext *cx,
|
||||||
JSObject *aOldGlobal,
|
JSObject *aOldGlobal,
|
||||||
JSObject *aNewGlobal)
|
JSObject *aNewGlobal,
|
||||||
|
nsIDocument *aOldDocument,
|
||||||
|
nsIDocument *aNewDocument)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIXPConnectJSObjectHolder> old_wrapper;
|
nsCOMPtr<nsIXPConnectJSObjectHolder> old_wrapper;
|
||||||
|
|
||||||
|
@ -742,6 +745,16 @@ nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
|
||||||
getter_AddRefs(old_wrapper));
|
getter_AddRefs(old_wrapper));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (aOldDocument) {
|
||||||
|
nsCOMPtr<nsISupports> old_ref = aOldDocument->RemoveReference(aNode);
|
||||||
|
|
||||||
|
if (old_ref) {
|
||||||
|
// Transfer the reference from aOldDocument to aNewDocument
|
||||||
|
|
||||||
|
aNewDocument->AddReference(aNode, old_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Whether or not aChild is already wrapped we must iterate through
|
// Whether or not aChild is already wrapped we must iterate through
|
||||||
// its descendants since there's no guarantee that a descendant isn't
|
// its descendants since there's no guarantee that a descendant isn't
|
||||||
// wrapped even if this child is not wrapped. That used to be true
|
// wrapped even if this child is not wrapped. That used to be true
|
||||||
|
@ -754,7 +767,9 @@ nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
|
||||||
nsIContent *child = aNode->GetChildAt(i);
|
nsIContent *child = aNode->GetChildAt(i);
|
||||||
NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
rv = doReparentContentWrapper(child, cx, aOldGlobal, aNewGlobal);
|
rv = doReparentContentWrapper(child, cx,
|
||||||
|
aOldGlobal, aNewGlobal,
|
||||||
|
aOldDocument, aNewDocument);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +823,8 @@ nsContentUtils::ReparentContentWrapper(nsIContent *aContent,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return doReparentContentWrapper(aContent, cx, oldScope, newScope);
|
return doReparentContentWrapper(aContent, cx, oldScope, newScope,
|
||||||
|
aOldDocument, aNewDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -2925,6 +2941,24 @@ nsContentUtils::HasMutationListeners(nsINode* aNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
void
|
||||||
|
nsContentUtils::TraverseListenerManager(nsINode *aNode,
|
||||||
|
nsCycleCollectionTraversalCallback &cb)
|
||||||
|
{
|
||||||
|
if (!sEventListenerManagersHash.ops) {
|
||||||
|
// We're already shut down, just return.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventListenerManagerMapEntry *entry =
|
||||||
|
NS_STATIC_CAST(EventListenerManagerMapEntry *,
|
||||||
|
PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
|
||||||
|
PL_DHASH_LOOKUP));
|
||||||
|
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
||||||
|
cb.NoteXPCOMChild(entry->mListenerManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsContentUtils::GetListenerManager(nsINode *aNode,
|
nsContentUtils::GetListenerManager(nsINode *aNode,
|
||||||
PRBool aCreateIfNotFound,
|
PRBool aCreateIfNotFound,
|
||||||
|
|
|
@ -72,12 +72,24 @@ nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap,
|
||||||
// to drop our reference when it goes away.
|
// to drop our reference when it goes away.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttribute, nsIDOMAttr)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChild)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttribute, nsIDOMAttr)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChild)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
// QueryInterface implementation for nsDOMAttribute
|
// QueryInterface implementation for nsDOMAttribute
|
||||||
NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
|
NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMAttr)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMAttr)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIAttribute)
|
NS_INTERFACE_MAP_ENTRY(nsIAttribute)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsINode)
|
NS_INTERFACE_MAP_ENTRY(nsINode)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3Attr)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3Attr)
|
||||||
|
@ -85,35 +97,13 @@ NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
|
||||||
new nsNodeSupportsWeakRefTearoff(this))
|
new nsNodeSupportsWeakRefTearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMAttr)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMAttr)
|
||||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Attr)
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Attr)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDOMAttribute)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMAttribute, nsIDOMAttr)
|
||||||
NS_IMPL_ADDREF(nsDOMAttribute)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsDOMAttribute, nsIDOMAttr,
|
||||||
NS_IMPL_RELEASE_WITH_DESTROY(nsDOMAttribute,
|
|
||||||
nsNodeUtils::LastRelease(this, PR_TRUE))
|
nsNodeUtils::LastRelease(this, PR_TRUE))
|
||||||
|
|
||||||
// nsIDOMGCParticipant methods
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsDOMAttribute::GetSCCIndex()
|
|
||||||
{
|
|
||||||
nsIContent *owner = GetContentInternal();
|
|
||||||
|
|
||||||
return owner ? owner->GetSCCIndex() : this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsDOMAttribute::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
NS_ASSERTION(GetContentInternal() == nsnull,
|
|
||||||
"shouldn't be an SCC index if we're in an element");
|
|
||||||
|
|
||||||
// This node is the root of a subtree that's been removed from the
|
|
||||||
// document (since AppendReachableList is only called on SCC index
|
|
||||||
// nodes). The document is reachable from it (through
|
|
||||||
// .ownerDocument), but it's not reachable from the document.
|
|
||||||
aArray.AppendObject(GetOwnerDoc());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)
|
nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "nsIDOM3Node.h"
|
#include "nsIDOM3Node.h"
|
||||||
#include "nsIDOM3Attr.h"
|
#include "nsIDOM3Attr.h"
|
||||||
#include "nsDOMAttributeMap.h"
|
#include "nsDOMAttributeMap.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsDOMAttribute;
|
class nsDOMAttribute;
|
||||||
|
|
||||||
|
@ -66,11 +67,7 @@ public:
|
||||||
nsDOMAttribute(nsDOMAttributeMap* aAttrMap, nsINodeInfo *aNodeInfo,
|
nsDOMAttribute(nsDOMAttributeMap* aAttrMap, nsINodeInfo *aNodeInfo,
|
||||||
const nsAString& aValue);
|
const nsAString& aValue);
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
// nsIDOMGCParticipant interface methods
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsIDOMNode interface
|
// nsIDOMNode interface
|
||||||
NS_DECL_NSIDOMNODE
|
NS_DECL_NSIDOMNODE
|
||||||
|
@ -108,6 +105,8 @@ public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static PRBool sInitialized;
|
static PRBool sInitialized;
|
||||||
|
|
||||||
|
|
|
@ -90,16 +90,40 @@ nsDOMAttributeMap::DropReference()
|
||||||
mContent = nsnull;
|
mContent = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttributeMap)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttributeMap, nsIDOMNamedNodeMap)
|
||||||
|
tmp->DropReference();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
|
PLDHashOperator
|
||||||
|
TraverseMapEntry(nsAttrHashKey::KeyType aKey, nsCOMPtr<nsIDOMNode>& aData, void* aUserArg)
|
||||||
|
{
|
||||||
|
nsCycleCollectionTraversalCallback *cb =
|
||||||
|
NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, aUserArg);
|
||||||
|
|
||||||
|
if (aData.get())
|
||||||
|
cb->NoteXPCOMChild(aData.get());
|
||||||
|
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap, nsIDOMNamedNodeMap)
|
||||||
|
tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
|
||||||
// QueryInterface implementation for nsDOMAttributeMap
|
// QueryInterface implementation for nsDOMAttributeMap
|
||||||
NS_INTERFACE_MAP_BEGIN(nsDOMAttributeMap)
|
NS_INTERFACE_MAP_BEGIN(nsDOMAttributeMap)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNamedNodeMap)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNamedNodeMap)
|
||||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NamedNodeMap)
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NamedNodeMap)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDOMAttributeMap)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsDOMAttributeMap)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMAttributeMap)
|
||||||
NS_IMPL_RELEASE(nsDOMAttributeMap)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMAttributeMap)
|
||||||
|
|
||||||
PLDHashOperator
|
PLDHashOperator
|
||||||
SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey, nsCOMPtr<nsIDOMNode>& aData,
|
SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey, nsCOMPtr<nsIDOMNode>& aData,
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "nsIDOMNamedNodeMap.h"
|
#include "nsIDOMNamedNodeMap.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsInterfaceHashtable.h"
|
#include "nsInterfaceHashtable.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsIAtom;
|
class nsIAtom;
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
|
@ -126,7 +127,7 @@ public:
|
||||||
*/
|
*/
|
||||||
PRBool Init();
|
PRBool Init();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
// nsIDOMNamedNodeMap interface
|
// nsIDOMNamedNodeMap interface
|
||||||
NS_DECL_NSIDOMNAMEDNODEMAP
|
NS_DECL_NSIDOMNAMEDNODEMAP
|
||||||
|
@ -169,6 +170,8 @@ public:
|
||||||
*/
|
*/
|
||||||
PRUint32 Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const;
|
PRUint32 Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const;
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMAttributeMap)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsIContent* mContent; // Weak reference
|
nsIContent* mContent; // Weak reference
|
||||||
|
|
||||||
|
|
|
@ -753,6 +753,7 @@ nsDocument::~nsDocument()
|
||||||
|
|
||||||
delete mHeaderData;
|
delete mHeaderData;
|
||||||
delete mBoxObjectTable;
|
delete mBoxObjectTable;
|
||||||
|
delete mContentWrapperHash;
|
||||||
nsLayoutStatics::Release();
|
nsLayoutStatics::Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,6 +769,8 @@ nsDocument::LastRelease()
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsDocument)
|
NS_INTERFACE_MAP_BEGIN(nsDocument)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDocument)
|
NS_INTERFACE_MAP_ENTRY(nsIDocument)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDocument)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMDocument)
|
||||||
|
@ -782,7 +785,6 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||||
|
@ -793,6 +795,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
|
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsINode)
|
NS_INTERFACE_MAP_ENTRY(nsINode)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDocument)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument)
|
||||||
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
|
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
|
||||||
aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
|
aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
|
||||||
|
@ -809,8 +812,72 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
|
||||||
else
|
else
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsDocument)
|
|
||||||
NS_IMPL_RELEASE_WITH_DESTROY(nsDocument, LastRelease())
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDocument, nsIDocument)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDocument,
|
||||||
|
nsIDocument,
|
||||||
|
LastRelease())
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument, nsIDocument)
|
||||||
|
// Traverse the mChildren nsAttrAndChildArray.
|
||||||
|
for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()); indx > 0; --indx) {
|
||||||
|
cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse all nsIDocument nsCOMPtrs.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBindingManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
|
||||||
|
|
||||||
|
// Traverse all nsDocument nsCOMPtrs.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptGlobalObject)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMStyleSheets)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStyleAttrStyleSheet)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptEventManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXPathEvaluatorTearoff)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker)
|
||||||
|
|
||||||
|
// Traverse all our nsCOMArrays.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mVisitednessChangedURIs)
|
||||||
|
|
||||||
|
// Traverse any associated preserved wrapper.
|
||||||
|
{
|
||||||
|
nsISupports *preservedWrapper = tmp->GetReference(tmp);
|
||||||
|
if (preservedWrapper)
|
||||||
|
cb.NoteXPCOMChild(preservedWrapper);
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument, nsIDocument)
|
||||||
|
// Unlink the mChildren nsAttrAndChildArray.
|
||||||
|
for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1;
|
||||||
|
indx >= 0; --indx) {
|
||||||
|
tmp->mChildren.ChildAt(indx)->UnbindFromTree();
|
||||||
|
tmp->mChildren.RemoveChildAt(indx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlink any associated preserved wrapper.
|
||||||
|
tmp->RemoveReference(tmp);
|
||||||
|
|
||||||
|
tmp->mParentDocument = nsnull;
|
||||||
|
tmp->mRootContent = nsnull;
|
||||||
|
|
||||||
|
// nsDocument has a pretty complex destructor, so we're going to
|
||||||
|
// assume that *most* cycles you actually want to break somewhere
|
||||||
|
// else, and not unlink an awful lot here.
|
||||||
|
//
|
||||||
|
// In rare cases where you think an unlink will help here, add one
|
||||||
|
// manually.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsDocument::Init()
|
nsDocument::Init()
|
||||||
|
@ -3348,23 +3415,6 @@ nsDocument::SetDir(const nsAString& aDirection)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// nsIDOMGCParticipant methods
|
|
||||||
//
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsDocument::GetSCCIndex()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsDocument::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> gcp = do_QueryInterface(mScriptGlobalObject);
|
|
||||||
if (gcp)
|
|
||||||
aArray.AppendObject(gcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// nsIDOMNode methods
|
// nsIDOMNode methods
|
||||||
|
@ -4375,6 +4425,46 @@ nsDocument::FlushPendingNotifications(mozFlushType aType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsDocument::AddReference(void *aKey, nsISupports *aReference)
|
||||||
|
{
|
||||||
|
if (mScriptGlobalObject) {
|
||||||
|
if (!mContentWrapperHash) {
|
||||||
|
mContentWrapperHash = new nsInterfaceHashtable<nsVoidPtrHashKey, nsISupports>;
|
||||||
|
if (mContentWrapperHash) {
|
||||||
|
mContentWrapperHash->Init(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mContentWrapperHash)
|
||||||
|
mContentWrapperHash->Put(aKey, aReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsISupports*
|
||||||
|
nsDocument::GetReference(void *aKey)
|
||||||
|
{
|
||||||
|
// NB: This method is part of content cycle collection,
|
||||||
|
// and must *not* Addref its return value.
|
||||||
|
|
||||||
|
if (mContentWrapperHash)
|
||||||
|
return mContentWrapperHash->GetWeak(aKey);
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsISupports>
|
||||||
|
nsDocument::RemoveReference(void *aKey)
|
||||||
|
{
|
||||||
|
nsISupports* oldReference = nsnull;
|
||||||
|
|
||||||
|
if (mContentWrapperHash) {
|
||||||
|
mContentWrapperHash->Get(aKey, &oldReference);
|
||||||
|
mContentWrapperHash->Remove(aKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldReference;
|
||||||
|
}
|
||||||
|
|
||||||
nsIScriptEventManager*
|
nsIScriptEventManager*
|
||||||
nsDocument::GetScriptEventManager()
|
nsDocument::GetScriptEventManager()
|
||||||
{
|
{
|
||||||
|
@ -5008,6 +5098,8 @@ nsDocument::Destroy()
|
||||||
mLayoutHistoryState = nsnull;
|
mLayoutHistoryState = nsnull;
|
||||||
|
|
||||||
nsContentList::OnDocumentDestroy(this);
|
nsContentList::OnDocumentDestroy(this);
|
||||||
|
delete mContentWrapperHash;
|
||||||
|
mContentWrapperHash = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsILayoutHistoryState>
|
already_AddRefed<nsILayoutHistoryState>
|
||||||
|
|
|
@ -91,6 +91,7 @@
|
||||||
#include "nsTObserverArray.h"
|
#include "nsTObserverArray.h"
|
||||||
#include "nsStubMutationObserver.h"
|
#include "nsStubMutationObserver.h"
|
||||||
#include "nsIChannel.h"
|
#include "nsIChannel.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
// Put these here so all document impls get them automatically
|
// Put these here so all document impls get them automatically
|
||||||
#include "nsHTMLStyleSheet.h"
|
#include "nsHTMLStyleSheet.h"
|
||||||
|
@ -295,7 +296,7 @@ class nsDocument : public nsIDocument,
|
||||||
public nsStubMutationObserver
|
public nsStubMutationObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
|
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
|
||||||
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
||||||
|
@ -493,6 +494,9 @@ public:
|
||||||
nsIStyleRule* aStyleRule);
|
nsIStyleRule* aStyleRule);
|
||||||
|
|
||||||
virtual void FlushPendingNotifications(mozFlushType aType);
|
virtual void FlushPendingNotifications(mozFlushType aType);
|
||||||
|
virtual void AddReference(void *aKey, nsISupports *aReference);
|
||||||
|
virtual nsISupports *GetReference(void *aKey);
|
||||||
|
virtual already_AddRefed<nsISupports> RemoveReference(void *aKey);
|
||||||
virtual nsIScriptEventManager* GetScriptEventManager();
|
virtual nsIScriptEventManager* GetScriptEventManager();
|
||||||
virtual void SetXMLDeclaration(const PRUnichar *aVersion,
|
virtual void SetXMLDeclaration(const PRUnichar *aVersion,
|
||||||
const PRUnichar *aEncoding,
|
const PRUnichar *aEncoding,
|
||||||
|
@ -548,10 +552,6 @@ public:
|
||||||
nsresult GetRadioGroup(const nsAString& aName,
|
nsresult GetRadioGroup(const nsAString& aName,
|
||||||
nsRadioGroupStruct **aRadioGroup);
|
nsRadioGroupStruct **aRadioGroup);
|
||||||
|
|
||||||
// nsIDOMGCParticipant interface methods
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsIDOMNode
|
// nsIDOMNode
|
||||||
NS_DECL_NSIDOMNODE
|
NS_DECL_NSIDOMNODE
|
||||||
|
|
||||||
|
@ -643,6 +643,8 @@ public:
|
||||||
|
|
||||||
NS_HIDDEN_(void) ClearBoxObjectFor(nsIContent* aContent);
|
NS_HIDDEN_(void) ClearBoxObjectFor(nsIContent* aContent);
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsDocument)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -749,6 +751,7 @@ protected:
|
||||||
PRUint8 mDefaultElementType;
|
PRUint8 mDefaultElementType;
|
||||||
|
|
||||||
nsInterfaceHashtable<nsISupportsHashKey, nsPIBoxObject> *mBoxObjectTable;
|
nsInterfaceHashtable<nsISupportsHashKey, nsPIBoxObject> *mBoxObjectTable;
|
||||||
|
nsInterfaceHashtable<nsVoidPtrHashKey, nsISupports> *mContentWrapperHash;
|
||||||
|
|
||||||
// The channel that got passed to StartDocumentLoad(), if any
|
// The channel that got passed to StartDocumentLoad(), if any
|
||||||
nsCOMPtr<nsIChannel> mChannel;
|
nsCOMPtr<nsIChannel> mChannel;
|
||||||
|
|
|
@ -200,13 +200,9 @@ nsDocumentFragment::IsNodeOfType(PRUint32 aFlags) const
|
||||||
NS_INTERFACE_MAP_BEGIN(nsDocumentFragment)
|
NS_INTERFACE_MAP_BEGIN(nsDocumentFragment)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentFragment)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentFragment)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsINode)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
|
||||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentFragment)
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentFragment)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END_INHERITING(nsGenericElement)
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(nsDocumentFragment, nsGenericElement)
|
NS_IMPL_ADDREF_INHERITED(nsDocumentFragment, nsGenericElement)
|
||||||
|
|
|
@ -76,14 +76,20 @@ nsGenericDOMDataNode::~nsGenericDOMDataNode()
|
||||||
"Please remove this from the document properly");
|
"Please remove this from the document properly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsGenericDOMDataNode)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode, nsIContent)
|
||||||
NS_IMPL_RELEASE_WITH_DESTROY(nsGenericDOMDataNode,
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
|
||||||
nsNodeUtils::LastRelease(this, PR_TRUE))
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode, nsIContent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
|
NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsINode)
|
NS_INTERFACE_MAP_ENTRY(nsINode)
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
||||||
nsDOMEventRTTearoff::Create(this))
|
nsDOMEventRTTearoff::Create(this))
|
||||||
|
@ -97,8 +103,13 @@ NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
|
||||||
new nsNodeSupportsWeakRefTearoff(this))
|
new nsNodeSupportsWeakRefTearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGenericDOMDataNode)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericDOMDataNode, nsIContent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsGenericDOMDataNode, nsIContent,
|
||||||
|
nsNodeUtils::LastRelease(this, PR_TRUE))
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
|
nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
|
||||||
|
@ -526,38 +537,6 @@ nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* See comment for nsGenericElement::GetSCCIndex
|
|
||||||
*/
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsGenericDOMDataNode::GetSCCIndex()
|
|
||||||
{
|
|
||||||
// This is an optimized way of walking nsIDOMNode::GetParentNode to
|
|
||||||
// the top of the tree.
|
|
||||||
nsINode *top = GetCurrentDoc();
|
|
||||||
if (!top) {
|
|
||||||
top = this;
|
|
||||||
nsINode *parent;
|
|
||||||
while ((parent = top->GetNodeParent())) {
|
|
||||||
top = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsGenericDOMDataNode::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
NS_ASSERTION(GetCurrentDoc() == nsnull,
|
|
||||||
"shouldn't be an SCC index if we're in a doc");
|
|
||||||
|
|
||||||
// This node is the root of a subtree that's been removed from the
|
|
||||||
// document (since AppendReachableList is only called on SCC index
|
|
||||||
// nodes). The document is reachable from it (through
|
|
||||||
// .ownerDocument), but it's not reachable from the document.
|
|
||||||
aArray.AppendObject(GetOwnerDoc());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
#include "nsDOMError.h"
|
#include "nsDOMError.h"
|
||||||
#include "nsIEventListenerManager.h"
|
#include "nsIEventListenerManager.h"
|
||||||
#include "nsGenericElement.h"
|
#include "nsGenericElement.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsIDOMAttr;
|
class nsIDOMAttr;
|
||||||
class nsIDOMEventListener;
|
class nsIDOMEventListener;
|
||||||
|
@ -63,7 +63,7 @@ class nsURI;
|
||||||
class nsGenericDOMDataNode : public nsIContent
|
class nsGenericDOMDataNode : public nsIContent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
nsGenericDOMDataNode(nsINodeInfo *aNodeInfo);
|
nsGenericDOMDataNode(nsINodeInfo *aNodeInfo);
|
||||||
virtual ~nsGenericDOMDataNode();
|
virtual ~nsGenericDOMDataNode();
|
||||||
|
@ -168,10 +168,6 @@ public:
|
||||||
nsresult ReplaceData(PRUint32 aOffset, PRUint32 aCount,
|
nsresult ReplaceData(PRUint32 aOffset, PRUint32 aCount,
|
||||||
const nsAString& aArg);
|
const nsAString& aArg);
|
||||||
|
|
||||||
// nsIDOMGCParticipant interface methods
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsINode methods
|
// nsINode methods
|
||||||
virtual PRUint32 GetChildCount() const;
|
virtual PRUint32 GetChildCount() const;
|
||||||
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
|
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
|
||||||
|
@ -262,6 +258,8 @@ public:
|
||||||
void ToCString(nsAString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
|
void ToCString(nsAString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* There are a set of DOM- and scripting-specific instance variables
|
* There are a set of DOM- and scripting-specific instance variables
|
||||||
|
|
|
@ -114,6 +114,9 @@
|
||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
#include "nsContentCreatorFunctions.h"
|
#include "nsContentCreatorFunctions.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
#ifdef MOZ_SVG
|
#ifdef MOZ_SVG
|
||||||
PRBool NS_SVG_TestFeature(const nsAString &fstr);
|
PRBool NS_SVG_TestFeature(const nsAString &fstr);
|
||||||
#endif /* MOZ_SVG */
|
#endif /* MOZ_SVG */
|
||||||
|
@ -960,46 +963,6 @@ nsGenericElement::~nsGenericElement()
|
||||||
"Please remove this from the document properly");
|
"Please remove this from the document properly");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* During the Mark phase of the GC, we need to mark all of the preserved
|
|
||||||
* wrappers that are reachable via DOM APIs. Since reachability for DOM
|
|
||||||
* nodes is symmetric, if one DOM node is reachable from another via DOM
|
|
||||||
* APIs, then they are in the same strongly connected component.
|
|
||||||
* (Strongly connected components are never reachable from each other
|
|
||||||
* via DOM APIs.) We can refer to each strongly connected component by
|
|
||||||
* walking up to the top of the parent chain. This function finds that
|
|
||||||
* root node for any DOM node.
|
|
||||||
*/
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsGenericElement::GetSCCIndex()
|
|
||||||
{
|
|
||||||
// This is an optimized way of walking nsIDOMNode::GetParentNode to
|
|
||||||
// the top of the tree.
|
|
||||||
nsINode *top = GetCurrentDoc();
|
|
||||||
if (!top) {
|
|
||||||
top = this;
|
|
||||||
nsINode *parent;
|
|
||||||
while ((parent = top->GetNodeParent())) {
|
|
||||||
top = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsGenericElement::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
NS_ASSERTION(GetCurrentDoc() == nsnull,
|
|
||||||
"shouldn't be an SCC index if we're in a doc");
|
|
||||||
|
|
||||||
// This node is the root of a subtree that's been removed from the
|
|
||||||
// document (since AppendReachableList is only called on SCC index
|
|
||||||
// nodes). The document is reachable from it (through
|
|
||||||
// .ownerDocument), but it's not reachable from the document.
|
|
||||||
aArray.AppendObject(GetOwnerDoc());
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsGenericElement::GetNodeName(nsAString& aNodeName)
|
nsGenericElement::GetNodeName(nsAString& aNodeName)
|
||||||
{
|
{
|
||||||
|
@ -2970,9 +2933,55 @@ nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIContent* aParent,
|
||||||
|
|
||||||
// nsISupports implementation
|
// nsISupports implementation
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement, nsIContent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
|
|
||||||
|
// Unlink child content (and unbind our subtree).
|
||||||
|
{
|
||||||
|
PRUint32 i;
|
||||||
|
PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
|
||||||
|
for (i = kids; i > 0; i--) {
|
||||||
|
tmp->mAttrsAndChildren.ChildAt(i-1)->UnbindFromTree();
|
||||||
|
tmp->mAttrsAndChildren.RemoveChildAt(i-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlink any DOM slots of interest.
|
||||||
|
{
|
||||||
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
||||||
|
if (slots)
|
||||||
|
slots->mAttributeMap = nsnull;
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericElement, nsIContent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER
|
||||||
|
|
||||||
|
// Traverse child content.
|
||||||
|
{
|
||||||
|
PRUint32 i;
|
||||||
|
PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
|
||||||
|
for (i = 0; i < kids; i++)
|
||||||
|
cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse any DOM slots of interest.
|
||||||
|
{
|
||||||
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
||||||
|
if (slots) {
|
||||||
|
if (slots->mAttributeMap.get())
|
||||||
|
cb.NoteXPCOMChild(slots->mAttributeMap.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsGenericElement)
|
NS_INTERFACE_MAP_BEGIN(nsGenericElement)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsINode)
|
NS_INTERFACE_MAP_ENTRY(nsINode)
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
||||||
|
@ -2986,10 +2995,12 @@ NS_INTERFACE_MAP_BEGIN(nsGenericElement)
|
||||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
|
||||||
new nsNodeSupportsWeakRefTearoff(this))
|
new nsNodeSupportsWeakRefTearoff(this))
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGenericElement)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsGenericElement)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericElement, nsIContent)
|
||||||
NS_IMPL_RELEASE_WITH_DESTROY(nsGenericElement,
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsGenericElement,
|
||||||
|
nsIContent,
|
||||||
nsNodeUtils::LastRelease(this, PR_TRUE))
|
nsNodeUtils::LastRelease(this, PR_TRUE))
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#include "mozFlushType.h"
|
#include "mozFlushType.h"
|
||||||
#include "nsDOMAttributeMap.h"
|
#include "nsDOMAttributeMap.h"
|
||||||
#include "nsIWeakReference.h"
|
#include "nsIWeakReference.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsIDOMAttr;
|
class nsIDOMAttr;
|
||||||
class nsIDOMEventListener;
|
class nsIDOMEventListener;
|
||||||
|
@ -352,7 +353,7 @@ public:
|
||||||
nsGenericElement(nsINodeInfo *aNodeInfo);
|
nsGenericElement(nsINodeInfo *aNodeInfo);
|
||||||
virtual ~nsGenericElement();
|
virtual ~nsGenericElement();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called during QueryInterface to give the binding manager a chance to
|
* Called during QueryInterface to give the binding manager a chance to
|
||||||
|
@ -360,10 +361,6 @@ public:
|
||||||
*/
|
*/
|
||||||
nsresult PostQueryInterface(REFNSIID aIID, void** aInstancePtr);
|
nsresult PostQueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||||
|
|
||||||
// nsIDOMGCParticipant interface methods
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsINode interface methods
|
// nsINode interface methods
|
||||||
virtual PRUint32 GetChildCount() const;
|
virtual PRUint32 GetChildCount() const;
|
||||||
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
|
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
|
||||||
|
@ -769,6 +766,8 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsGenericElement)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Set attribute and (if needed) notify documentobservers and fire off
|
* Set attribute and (if needed) notify documentobservers and fire off
|
||||||
|
|
|
@ -102,7 +102,6 @@ static void PrintReqURL(imgIRequest* req) {
|
||||||
nsImageLoadingContent::nsImageLoadingContent()
|
nsImageLoadingContent::nsImageLoadingContent()
|
||||||
: mObserverList(nsnull),
|
: mObserverList(nsnull),
|
||||||
mImageBlockingStatus(nsIContentPolicy::ACCEPT),
|
mImageBlockingStatus(nsIContentPolicy::ACCEPT),
|
||||||
mRootRefCount(0),
|
|
||||||
mLoadingEnabled(PR_TRUE),
|
mLoadingEnabled(PR_TRUE),
|
||||||
mStartingLoad(PR_FALSE),
|
mStartingLoad(PR_FALSE),
|
||||||
mLoading(PR_FALSE),
|
mLoading(PR_FALSE),
|
||||||
|
@ -128,19 +127,6 @@ nsImageLoadingContent::DestroyImageLoadingContent()
|
||||||
mPendingRequest->Cancel(NS_ERROR_FAILURE);
|
mPendingRequest->Cancel(NS_ERROR_FAILURE);
|
||||||
mPendingRequest = nsnull;
|
mPendingRequest = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can actually fire for multipart/x-mixed-replace, since if the
|
|
||||||
// load is canceled between parts (e.g., by cancelling the load
|
|
||||||
// group), we won't get any notification. See bug 321054 comment 31
|
|
||||||
// and bug 339610. *If* that multipart/x-mixed-replace image has
|
|
||||||
// event handlers, we won't even get to this warning; we'll leak
|
|
||||||
// instead.
|
|
||||||
NS_WARN_IF_FALSE(mRootRefCount == 0,
|
|
||||||
"unbalanced handler preservation refcount");
|
|
||||||
if (mRootRefCount != 0) {
|
|
||||||
mRootRefCount = 1;
|
|
||||||
UnpreserveLoadHandlers();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsImageLoadingContent::~nsImageLoadingContent()
|
nsImageLoadingContent::~nsImageLoadingContent()
|
||||||
|
@ -279,9 +265,6 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, PRBool aLastPart)
|
||||||
{
|
{
|
||||||
LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
|
LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
|
||||||
|
|
||||||
if (aLastPart)
|
|
||||||
UnpreserveLoadHandlers();
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,8 +436,6 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreserveLoadHandlers();
|
|
||||||
|
|
||||||
// Null out our mCurrentURI, in case we have no image requests right now.
|
// Null out our mCurrentURI, in case we have no image requests right now.
|
||||||
mCurrentURI = nsnull;
|
mCurrentURI = nsnull;
|
||||||
|
|
||||||
|
@ -469,9 +450,6 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||||
// Make sure our state is up to date
|
// Make sure our state is up to date
|
||||||
UpdateImageState(PR_TRUE);
|
UpdateImageState(PR_TRUE);
|
||||||
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
UnpreserveLoadHandlers();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,8 +567,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreserveLoadHandlers();
|
|
||||||
|
|
||||||
nsCOMPtr<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
|
nsCOMPtr<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
|
||||||
|
|
||||||
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
||||||
|
@ -599,7 +575,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
getter_AddRefs(req));
|
getter_AddRefs(req));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
FireEvent(NS_LITERAL_STRING("error"));
|
FireEvent(NS_LITERAL_STRING("error"));
|
||||||
UnpreserveLoadHandlers();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,7 +715,6 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgIRequest* aRequest,
|
||||||
NS_PRECONDITION(aRequest, "Must have a request here!");
|
NS_PRECONDITION(aRequest, "Must have a request here!");
|
||||||
AutoStateChanger changer(this, aNotify);
|
AutoStateChanger changer(this, aNotify);
|
||||||
mCurrentURI = nsnull;
|
mCurrentURI = nsnull;
|
||||||
PreserveLoadHandlers();
|
|
||||||
CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT);
|
CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT);
|
||||||
|
|
||||||
NS_ASSERTION(!mCurrentRequest, "We should not have a current request now");
|
NS_ASSERTION(!mCurrentRequest, "We should not have a current request now");
|
||||||
|
@ -800,7 +774,6 @@ public:
|
||||||
~Event()
|
~Event()
|
||||||
{
|
{
|
||||||
mDocument->UnblockOnload(PR_TRUE);
|
mDocument->UnblockOnload(PR_TRUE);
|
||||||
mContent->UnpreserveLoadHandlers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run();
|
NS_IMETHOD Run();
|
||||||
|
@ -860,39 +833,7 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType)
|
||||||
// Block onload for our event. Since we unblock in the event destructor, we
|
// Block onload for our event. Since we unblock in the event destructor, we
|
||||||
// want to block now, even if posting will fail.
|
// want to block now, even if posting will fail.
|
||||||
document->BlockOnload();
|
document->BlockOnload();
|
||||||
PreserveLoadHandlers();
|
|
||||||
|
|
||||||
return NS_DispatchToCurrentThread(evt);
|
return NS_DispatchToCurrentThread(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nsImageLoadingContent::PreserveLoadHandlers()
|
|
||||||
{
|
|
||||||
++mRootRefCount;
|
|
||||||
NS_LOG_ADDREF(&mRootRefCount, mRootRefCount,
|
|
||||||
"nsImageLoadingContent::mRootRefCount", sizeof(mRootRefCount));
|
|
||||||
if (mRootRefCount == 1) {
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> part = do_QueryInterface(this);
|
|
||||||
nsresult rv = nsDOMClassInfo::SetExternallyReferenced(part);
|
|
||||||
// The worst that will happen if we ignore this failure is that
|
|
||||||
// onload or onerror will fail to fire. I suppose we could fire
|
|
||||||
// onerror now as a result of that, but the only reason it would
|
|
||||||
// actually fail is out-of-memory, and it seems silly to bother and
|
|
||||||
// unlikely to work in that case.
|
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "ignoring failure to root participant");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsImageLoadingContent::UnpreserveLoadHandlers()
|
|
||||||
{
|
|
||||||
NS_ASSERTION(mRootRefCount != 0,
|
|
||||||
"load handler preservation refcount underflow");
|
|
||||||
--mRootRefCount;
|
|
||||||
NS_LOG_RELEASE(&mRootRefCount, mRootRefCount,
|
|
||||||
"nsImageLoadingContent::mRootRefCount");
|
|
||||||
if (mRootRefCount == 0) {
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> part = do_QueryInterface(this);
|
|
||||||
nsDOMClassInfo::UnsetExternallyReferenced(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -238,15 +238,6 @@ private:
|
||||||
class Event;
|
class Event;
|
||||||
friend class Event;
|
friend class Event;
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage the rooting and un-rooting in nsDOMClassInfo of the content
|
|
||||||
* node, so that things reachable from the node are protected from
|
|
||||||
* garbage collection while the onload or onerror handlers (which can
|
|
||||||
* make it reachable again) could fire.
|
|
||||||
*/
|
|
||||||
void PreserveLoadHandlers();
|
|
||||||
void UnpreserveLoadHandlers();
|
|
||||||
|
|
||||||
/* MEMBERS */
|
/* MEMBERS */
|
||||||
protected:
|
protected:
|
||||||
nsCOMPtr<imgIRequest> mCurrentRequest;
|
nsCOMPtr<imgIRequest> mCurrentRequest;
|
||||||
|
@ -265,12 +256,6 @@ private:
|
||||||
ImageObserver mObserverList;
|
ImageObserver mObserverList;
|
||||||
|
|
||||||
PRInt16 mImageBlockingStatus;
|
PRInt16 mImageBlockingStatus;
|
||||||
// This counts the number of operations that we're currently doing
|
|
||||||
// that require us to root in nsDOMClassInfo to say that there is
|
|
||||||
// currently network or other activity that could trigger onload or
|
|
||||||
// onerror handlers. The number of things a single node can do at
|
|
||||||
// once is quite limited, so a PRUint8 should be quite sufficient.
|
|
||||||
PRUint8 mRootRefCount;
|
|
||||||
PRPackedBool mLoadingEnabled : 1;
|
PRPackedBool mLoadingEnabled : 1;
|
||||||
PRPackedBool mStartingLoad : 1;
|
PRPackedBool mStartingLoad : 1;
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,11 @@ nsTreeWalker::nsTreeWalker(nsINode *aRoot,
|
||||||
PRBool aExpandEntityReferences) :
|
PRBool aExpandEntityReferences) :
|
||||||
mRoot(aRoot),
|
mRoot(aRoot),
|
||||||
mWhatToShow(aWhatToShow),
|
mWhatToShow(aWhatToShow),
|
||||||
|
mFilter(aFilter),
|
||||||
mExpandEntityReferences(aExpandEntityReferences),
|
mExpandEntityReferences(aExpandEntityReferences),
|
||||||
mCurrentNode(aRoot),
|
mCurrentNode(aRoot),
|
||||||
mPossibleIndexesPos(-1)
|
mPossibleIndexesPos(-1)
|
||||||
{
|
{
|
||||||
mFilter.Set(aFilter, this);
|
|
||||||
|
|
||||||
NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
|
NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +106,6 @@ nsTreeWalker::~nsTreeWalker()
|
||||||
// QueryInterface implementation for nsTreeWalker
|
// QueryInterface implementation for nsTreeWalker
|
||||||
NS_INTERFACE_MAP_BEGIN(nsTreeWalker)
|
NS_INTERFACE_MAP_BEGIN(nsTreeWalker)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
|
||||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TreeWalker)
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TreeWalker)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
@ -143,7 +141,7 @@ NS_IMETHODIMP nsTreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aFilter);
|
NS_ENSURE_ARG_POINTER(aFilter);
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
|
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter;
|
||||||
filter.swap((*aFilter = nsnull));
|
filter.swap((*aFilter = nsnull));
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -307,28 +305,6 @@ NS_IMETHODIMP nsTreeWalker::NextNode(nsIDOMNode **_retval)
|
||||||
return result ? CallQueryInterface(result, _retval) : NS_OK;
|
return result ? CallQueryInterface(result, _retval) : NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* nsIDOMGCParticipant functions
|
|
||||||
*/
|
|
||||||
/* virtual */ nsIDOMGCParticipant*
|
|
||||||
nsTreeWalker::GetSCCIndex()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* virtual */ void
|
|
||||||
nsTreeWalker::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> gcp;
|
|
||||||
|
|
||||||
gcp = do_QueryInterface(mRoot);
|
|
||||||
if (gcp)
|
|
||||||
aArray.AppendObject(gcp);
|
|
||||||
|
|
||||||
gcp = do_QueryInterface(mCurrentNode);
|
|
||||||
if (gcp)
|
|
||||||
aArray.AppendObject(gcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nsTreeWalker helper functions
|
* nsTreeWalker helper functions
|
||||||
|
@ -635,13 +611,12 @@ nsresult nsTreeWalker::TestNode(nsINode* aNode, PRInt16* _filtered)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
|
if (mFilter) {
|
||||||
if (filter) {
|
|
||||||
if (!domNode) {
|
if (!domNode) {
|
||||||
domNode = do_QueryInterface(aNode);
|
domNode = do_QueryInterface(aNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filter->AcceptNode(domNode, _filtered);
|
return mFilter->AcceptNode(domNode, _filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
*_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
|
*_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
|
||||||
|
|
|
@ -47,23 +47,18 @@
|
||||||
#include "nsIDOMTreeWalker.h"
|
#include "nsIDOMTreeWalker.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsVoidArray.h"
|
#include "nsVoidArray.h"
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
class nsINode;
|
class nsINode;
|
||||||
class nsIDOMNode;
|
class nsIDOMNode;
|
||||||
class nsIDOMNodeFilter;
|
class nsIDOMNodeFilter;
|
||||||
|
|
||||||
class nsTreeWalker : public nsIDOMTreeWalker, public nsIDOMGCParticipant
|
class nsTreeWalker : public nsIDOMTreeWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIDOMTREEWALKER
|
NS_DECL_NSIDOMTREEWALKER
|
||||||
|
|
||||||
// nsIDOMGCParticipant
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
nsTreeWalker(nsINode *aRoot,
|
nsTreeWalker(nsINode *aRoot,
|
||||||
PRUint32 aWhatToShow,
|
PRUint32 aWhatToShow,
|
||||||
nsIDOMNodeFilter *aFilter,
|
nsIDOMNodeFilter *aFilter,
|
||||||
|
@ -73,7 +68,7 @@ public:
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsINode> mRoot;
|
nsCOMPtr<nsINode> mRoot;
|
||||||
PRUint32 mWhatToShow;
|
PRUint32 mWhatToShow;
|
||||||
nsMarkedJSFunctionHolder<nsIDOMNodeFilter> mFilter;
|
nsCOMPtr<nsIDOMNodeFilter> mFilter;
|
||||||
PRBool mExpandEntityReferences;
|
PRBool mExpandEntityReferences;
|
||||||
nsCOMPtr<nsINode> mCurrentNode;
|
nsCOMPtr<nsINode> mCurrentNode;
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsDOMClassInfo.h"
|
#include "nsDOMClassInfo.h"
|
||||||
#include "nsIScriptableUConv.h"
|
#include "nsIScriptableUConv.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
#define LOAD_STR "load"
|
#define LOAD_STR "load"
|
||||||
#define ERROR_STR "error"
|
#define ERROR_STR "error"
|
||||||
|
@ -287,6 +288,57 @@ nsXMLHttpRequest::~nsXMLHttpRequest()
|
||||||
ClearEventListeners();
|
ClearEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpRequest, nsIXMLHttpRequest)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mLoadEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mErrorEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mProgressEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mUploadProgressEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mReadystatechangeEventListeners);
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXMLParserStreamListener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpRequest, nsIXMLHttpRequest)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mLoadEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mErrorEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mProgressEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mUploadProgressEventListeners);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mReadystatechangeEventListeners);
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnProgressListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXMLParserStreamListener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannelEventSink)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressEventSink)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
// QueryInterface implementation for nsXMLHttpRequest
|
// QueryInterface implementation for nsXMLHttpRequest
|
||||||
NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
|
NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
|
||||||
|
@ -300,14 +352,14 @@ NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
|
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
|
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLHttpRequest)
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLHttpRequest)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsXMLHttpRequest)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsXMLHttpRequest)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXMLHttpRequest, nsIXMLHttpRequest)
|
||||||
NS_IMPL_RELEASE(nsXMLHttpRequest)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXMLHttpRequest, nsIXMLHttpRequest)
|
||||||
|
|
||||||
|
|
||||||
/* void addEventListener (in string type, in nsIDOMEventListener
|
/* void addEventListener (in string type, in nsIDOMEventListener
|
||||||
|
@ -319,7 +371,7 @@ nsXMLHttpRequest::AddEventListener(const nsAString& type,
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG(listener);
|
NS_ENSURE_ARG(listener);
|
||||||
|
|
||||||
nsTArray<ListenerHolder*> *array;
|
nsCOMArray<nsIDOMEventListener> *array;
|
||||||
|
|
||||||
#define IMPL_ADD_LISTENER(_type, _member) \
|
#define IMPL_ADD_LISTENER(_type, _member) \
|
||||||
if (type.EqualsLiteral(_type)) { \
|
if (type.EqualsLiteral(_type)) { \
|
||||||
|
@ -335,10 +387,7 @@ nsXMLHttpRequest::AddEventListener(const nsAString& type,
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListenerHolder *holder = new ListenerHolder;
|
array->AppendObject(listener);
|
||||||
NS_ENSURE_TRUE(holder, NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
holder->Set(listener, this);
|
|
||||||
array->AppendElement(holder);
|
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -356,7 +405,7 @@ nsXMLHttpRequest::RemoveEventListener(const nsAString & type,
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG(listener);
|
NS_ENSURE_ARG(listener);
|
||||||
|
|
||||||
nsTArray<ListenerHolder*> *array;
|
nsCOMArray<nsIDOMEventListener> *array;
|
||||||
#define IMPL_REMOVE_LISTENER(_type, _member) \
|
#define IMPL_REMOVE_LISTENER(_type, _member) \
|
||||||
if (type.EqualsLiteral(_type)) { \
|
if (type.EqualsLiteral(_type)) { \
|
||||||
array = &(_member); \
|
array = &(_member); \
|
||||||
|
@ -372,11 +421,9 @@ nsXMLHttpRequest::RemoveEventListener(const nsAString & type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow a caller to remove O(N^2) behavior by removing end-to-start.
|
// Allow a caller to remove O(N^2) behavior by removing end-to-start.
|
||||||
for (PRUint32 i = array->Length() - 1; i != PRUint32(-1); --i) {
|
for (PRUint32 i = array->Count() - 1; i != PRUint32(-1); --i) {
|
||||||
ListenerHolder *holder = array->ElementAt(i);
|
if (array->ObjectAt(i) == listener) {
|
||||||
if (nsCOMPtr<nsIDOMEventListener>(holder->Get()) == listener) {
|
array->RemoveObjectAt(i);
|
||||||
array->RemoveElementAt(i);
|
|
||||||
delete holder;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +446,7 @@ nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechan
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
|
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
|
||||||
|
|
||||||
mOnReadystatechangeListener.Get(aOnreadystatechange);
|
NS_IF_ADDREF(*aOnreadystatechange = mOnReadystatechangeListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +454,7 @@ nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechan
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::SetOnreadystatechange(nsIDOMEventListener * aOnreadystatechange)
|
nsXMLHttpRequest::SetOnreadystatechange(nsIDOMEventListener * aOnreadystatechange)
|
||||||
{
|
{
|
||||||
mOnReadystatechangeListener.Set(aOnreadystatechange, this);
|
mOnReadystatechangeListener = aOnreadystatechange;
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -421,7 +468,7 @@ nsXMLHttpRequest::GetOnload(nsIDOMEventListener * *aOnLoad)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aOnLoad);
|
NS_ENSURE_ARG_POINTER(aOnLoad);
|
||||||
|
|
||||||
mOnLoadListener.Get(aOnLoad);
|
NS_IF_ADDREF(*aOnLoad = mOnLoadListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -429,7 +476,7 @@ nsXMLHttpRequest::GetOnload(nsIDOMEventListener * *aOnLoad)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::SetOnload(nsIDOMEventListener * aOnLoad)
|
nsXMLHttpRequest::SetOnload(nsIDOMEventListener * aOnLoad)
|
||||||
{
|
{
|
||||||
mOnLoadListener.Set(aOnLoad, this);
|
mOnLoadListener = aOnLoad;
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -442,7 +489,7 @@ nsXMLHttpRequest::GetOnerror(nsIDOMEventListener * *aOnerror)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aOnerror);
|
NS_ENSURE_ARG_POINTER(aOnerror);
|
||||||
|
|
||||||
mOnErrorListener.Get(aOnerror);
|
NS_IF_ADDREF(*aOnerror = mOnErrorListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -450,7 +497,7 @@ nsXMLHttpRequest::GetOnerror(nsIDOMEventListener * *aOnerror)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::SetOnerror(nsIDOMEventListener * aOnerror)
|
nsXMLHttpRequest::SetOnerror(nsIDOMEventListener * aOnerror)
|
||||||
{
|
{
|
||||||
mOnErrorListener.Set(aOnerror, this);
|
mOnErrorListener = aOnerror;
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -463,7 +510,7 @@ nsXMLHttpRequest::GetOnprogress(nsIDOMEventListener * *aOnprogress)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aOnprogress);
|
NS_ENSURE_ARG_POINTER(aOnprogress);
|
||||||
|
|
||||||
mOnProgressListener.Get(aOnprogress);
|
NS_IF_ADDREF(*aOnprogress = mOnProgressListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -471,7 +518,7 @@ nsXMLHttpRequest::GetOnprogress(nsIDOMEventListener * *aOnprogress)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::SetOnprogress(nsIDOMEventListener * aOnprogress)
|
nsXMLHttpRequest::SetOnprogress(nsIDOMEventListener * aOnprogress)
|
||||||
{
|
{
|
||||||
mOnProgressListener.Set(aOnprogress, this);
|
mOnProgressListener = aOnprogress;
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -484,7 +531,7 @@ nsXMLHttpRequest::GetOnuploadprogress(nsIDOMEventListener * *aOnuploadprogress)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aOnuploadprogress);
|
NS_ENSURE_ARG_POINTER(aOnuploadprogress);
|
||||||
|
|
||||||
mOnUploadProgressListener.Get(aOnuploadprogress);
|
NS_IF_ADDREF(*aOnuploadprogress = mOnUploadProgressListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +539,7 @@ nsXMLHttpRequest::GetOnuploadprogress(nsIDOMEventListener * *aOnuploadprogress)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::SetOnuploadprogress(nsIDOMEventListener * aOnuploadprogress)
|
nsXMLHttpRequest::SetOnuploadprogress(nsIDOMEventListener * aOnuploadprogress)
|
||||||
{
|
{
|
||||||
mOnUploadProgressListener.Set(aOnuploadprogress, this);
|
mOnUploadProgressListener = aOnuploadprogress;
|
||||||
|
|
||||||
mScriptContext = GetCurrentContext();
|
mScriptContext = GetCurrentContext();
|
||||||
|
|
||||||
|
@ -504,8 +551,7 @@ NS_IMETHODIMP
|
||||||
nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
|
nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aChannel);
|
NS_ENSURE_ARG_POINTER(aChannel);
|
||||||
*aChannel = mChannel;
|
NS_IF_ADDREF(*aChannel = mChannel);
|
||||||
NS_IF_ADDREF(*aChannel);
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -844,18 +890,15 @@ nsXMLHttpRequest::CreateEvent(nsEvent* aEvent, const nsAString& aType,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsXMLHttpRequest::CopyEventListeners(ListenerHolder& aListener,
|
nsXMLHttpRequest::CopyEventListeners(nsCOMPtr<nsIDOMEventListener>& aListener,
|
||||||
const nsTArray<ListenerHolder*>& aListenerArray,
|
const nsCOMArray<nsIDOMEventListener>& aListenerArray,
|
||||||
nsCOMArray<nsIDOMEventListener>& aCopy)
|
nsCOMArray<nsIDOMEventListener>& aCopy)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aCopy.Count() == 0, "aCopy should start off empty");
|
NS_PRECONDITION(aCopy.Count() == 0, "aCopy should start off empty");
|
||||||
nsCOMPtr<nsIDOMEventListener> listener = aListener.Get();
|
if (aListener)
|
||||||
if (listener)
|
aCopy.AppendObject(aListener);
|
||||||
aCopy.AppendObject(listener);
|
|
||||||
|
|
||||||
PRUint32 count = aListenerArray.Length();
|
aCopy.AppendObjects(aListenerArray);
|
||||||
for (PRUint32 i = 0; i < count; ++i)
|
|
||||||
aCopy.AppendObject(nsCOMPtr<nsIDOMEventListener>(aListenerArray[i]->Get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -900,33 +943,25 @@ void
|
||||||
nsXMLHttpRequest::ClearEventListeners()
|
nsXMLHttpRequest::ClearEventListeners()
|
||||||
{
|
{
|
||||||
if (mState & XML_HTTP_REQUEST_ROOTED) {
|
if (mState & XML_HTTP_REQUEST_ROOTED) {
|
||||||
nsDOMClassInfo::UnsetExternallyReferenced(this);
|
|
||||||
mState &= ~XML_HTTP_REQUEST_ROOTED;
|
mState &= ~XML_HTTP_REQUEST_ROOTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This isn't *really* needed anymore now that we use
|
// This isn't *really* needed anymore now that we use a cycle
|
||||||
// nsMarkedJSFunctionHolder, but we may as well keep it for safety
|
// collector, but we may as well keep it for safety (against leaks)
|
||||||
// (against leaks) and compatibility, and also for the code to clear
|
// and compatibility, and also for the code to clear the first
|
||||||
// the first listener arrays (called from the destructor).
|
// listener arrays (called from the destructor).
|
||||||
PRUint32 i, i_end;
|
|
||||||
#define CLEAR_ARRAY(member_) \
|
|
||||||
for (i = 0, i_end = (member_).Length(); i < i_end; ++i) \
|
|
||||||
delete (member_)[i]; \
|
|
||||||
(member_).Clear();
|
|
||||||
|
|
||||||
CLEAR_ARRAY(mLoadEventListeners)
|
mLoadEventListeners.Clear();
|
||||||
CLEAR_ARRAY(mErrorEventListeners)
|
mErrorEventListeners.Clear();
|
||||||
CLEAR_ARRAY(mProgressEventListeners)
|
mProgressEventListeners.Clear();
|
||||||
CLEAR_ARRAY(mUploadProgressEventListeners)
|
mUploadProgressEventListeners.Clear();
|
||||||
CLEAR_ARRAY(mReadystatechangeEventListeners)
|
mReadystatechangeEventListeners.Clear();
|
||||||
|
|
||||||
#undef CLEAR_ARRAY
|
mOnLoadListener = nsnull;
|
||||||
|
mOnErrorListener = nsnull;
|
||||||
mOnLoadListener.Set(nsnull, this);
|
mOnProgressListener = nsnull;
|
||||||
mOnErrorListener.Set(nsnull, this);
|
mOnUploadProgressListener = nsnull;
|
||||||
mOnProgressListener.Set(nsnull, this);
|
mOnReadystatechangeListener = nsnull;
|
||||||
mOnUploadProgressListener.Set(nsnull, this);
|
|
||||||
mOnReadystatechangeListener.Set(nsnull, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIHttpChannel>
|
already_AddRefed<nsIHttpChannel>
|
||||||
|
@ -1021,10 +1056,10 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
|
||||||
// a progress event handler we must load with nsIRequest::LOAD_NORMAL or
|
// a progress event handler we must load with nsIRequest::LOAD_NORMAL or
|
||||||
// necko won't generate any progress notifications
|
// necko won't generate any progress notifications
|
||||||
nsLoadFlags loadFlags;
|
nsLoadFlags loadFlags;
|
||||||
if (nsCOMPtr<nsIDOMEventListener>(mOnProgressListener.Get()) ||
|
if (mOnProgressListener ||
|
||||||
nsCOMPtr<nsIDOMEventListener>(mOnUploadProgressListener.Get()) ||
|
mOnUploadProgressListener ||
|
||||||
mProgressEventListeners.Length() != 0 ||
|
mProgressEventListeners.Count() != 0 ||
|
||||||
mUploadProgressEventListeners.Length() != 0) {
|
mUploadProgressEventListeners.Count() != 0) {
|
||||||
loadFlags = nsIRequest::LOAD_NORMAL;
|
loadFlags = nsIRequest::LOAD_NORMAL;
|
||||||
} else {
|
} else {
|
||||||
loadFlags = nsIRequest::LOAD_BACKGROUND;
|
loadFlags = nsIRequest::LOAD_BACKGROUND;
|
||||||
|
@ -1659,8 +1694,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||||
// from being garbage collected even if this object becomes
|
// from being garbage collected even if this object becomes
|
||||||
// unreachable from script, since they can fire as a result of our
|
// unreachable from script, since they can fire as a result of our
|
||||||
// reachability from the network stack.
|
// reachability from the network stack.
|
||||||
rv = nsDOMClassInfo::SetExternallyReferenced(this);
|
|
||||||
if (NS_SUCCEEDED(rv))
|
|
||||||
mState |= XML_HTTP_REQUEST_ROOTED;
|
mState |= XML_HTTP_REQUEST_ROOTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2056,23 +2089,6 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
|
||||||
return QueryInterface(aIID, aResult);
|
return QueryInterface(aIID, aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
// nsIDOMGCParticipant methods:
|
|
||||||
//
|
|
||||||
/* virtual */ nsIDOMGCParticipant*
|
|
||||||
nsXMLHttpRequest::GetSCCIndex()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* virtual */ void
|
|
||||||
nsXMLHttpRequest::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> gcp = do_QueryInterface(mDocument);
|
|
||||||
if (gcp)
|
|
||||||
aArray.AppendObject(gcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
|
NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
#include "nsIDOMLSProgressEvent.h"
|
#include "nsIDOMLSProgressEvent.h"
|
||||||
|
|
||||||
|
@ -72,14 +73,13 @@ class nsXMLHttpRequest : public nsIXMLHttpRequest,
|
||||||
public nsIChannelEventSink,
|
public nsIChannelEventSink,
|
||||||
public nsIProgressEventSink,
|
public nsIProgressEventSink,
|
||||||
public nsIInterfaceRequestor,
|
public nsIInterfaceRequestor,
|
||||||
public nsIDOMGCParticipant,
|
|
||||||
public nsSupportsWeakReference
|
public nsSupportsWeakReference
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsXMLHttpRequest();
|
nsXMLHttpRequest();
|
||||||
virtual ~nsXMLHttpRequest();
|
virtual ~nsXMLHttpRequest();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
// nsIXMLHttpRequest
|
// nsIXMLHttpRequest
|
||||||
NS_DECL_NSIXMLHTTPREQUEST
|
NS_DECL_NSIXMLHTTPREQUEST
|
||||||
|
@ -115,12 +115,9 @@ public:
|
||||||
// nsIInterfaceRequestor
|
// nsIInterfaceRequestor
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
|
|
||||||
// nsIDOMGCParticipant
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef nsMarkedJSFunctionHolder<nsIDOMEventListener> ListenerHolder;
|
|
||||||
|
|
||||||
nsresult DetectCharset(nsACString& aCharset);
|
nsresult DetectCharset(nsACString& aCharset);
|
||||||
nsresult ConvertBodyToText(nsAString& aOutBuffer);
|
nsresult ConvertBodyToText(nsAString& aOutBuffer);
|
||||||
|
@ -150,8 +147,8 @@ protected:
|
||||||
nsIDOMEvent** domevent);
|
nsIDOMEvent** domevent);
|
||||||
|
|
||||||
// Make a copy of a pair of members to be passed to NotifyEventListeners.
|
// Make a copy of a pair of members to be passed to NotifyEventListeners.
|
||||||
void CopyEventListeners(ListenerHolder& aListener,
|
void CopyEventListeners(nsCOMPtr<nsIDOMEventListener>& aListener,
|
||||||
const nsTArray<ListenerHolder*>& aListenerArray,
|
const nsCOMArray<nsIDOMEventListener>& aListenerArray,
|
||||||
nsCOMArray<nsIDOMEventListener>& aCopy);
|
nsCOMArray<nsIDOMEventListener>& aCopy);
|
||||||
|
|
||||||
// aListeners must be a "non-live" list (i.e., addEventListener and
|
// aListeners must be a "non-live" list (i.e., addEventListener and
|
||||||
|
@ -167,19 +164,19 @@ protected:
|
||||||
nsCOMPtr<nsIRequest> mReadRequest;
|
nsCOMPtr<nsIRequest> mReadRequest;
|
||||||
nsCOMPtr<nsIDOMDocument> mDocument;
|
nsCOMPtr<nsIDOMDocument> mDocument;
|
||||||
|
|
||||||
nsTArray<ListenerHolder*> mLoadEventListeners;
|
nsCOMArray<nsIDOMEventListener> mLoadEventListeners;
|
||||||
nsTArray<ListenerHolder*> mErrorEventListeners;
|
nsCOMArray<nsIDOMEventListener> mErrorEventListeners;
|
||||||
nsTArray<ListenerHolder*> mProgressEventListeners;
|
nsCOMArray<nsIDOMEventListener> mProgressEventListeners;
|
||||||
nsTArray<ListenerHolder*> mUploadProgressEventListeners;
|
nsCOMArray<nsIDOMEventListener> mUploadProgressEventListeners;
|
||||||
nsTArray<ListenerHolder*> mReadystatechangeEventListeners;
|
nsCOMArray<nsIDOMEventListener> mReadystatechangeEventListeners;
|
||||||
|
|
||||||
nsCOMPtr<nsIScriptContext> mScriptContext;
|
nsCOMPtr<nsIScriptContext> mScriptContext;
|
||||||
|
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnLoadListener;
|
nsCOMPtr<nsIDOMEventListener> mOnLoadListener;
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnErrorListener;
|
nsCOMPtr<nsIDOMEventListener> mOnErrorListener;
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnProgressListener;
|
nsCOMPtr<nsIDOMEventListener> mOnProgressListener;
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnUploadProgressListener;
|
nsCOMPtr<nsIDOMEventListener> mOnUploadProgressListener;
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnReadystatechangeListener;
|
nsCOMPtr<nsIDOMEventListener> mOnReadystatechangeListener;
|
||||||
|
|
||||||
nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
|
nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
|
||||||
|
|
||||||
|
|
|
@ -157,13 +157,6 @@ public:
|
||||||
* Tells the event listener manager that its target (which owns it) is
|
* Tells the event listener manager that its target (which owns it) is
|
||||||
* no longer using it (and could go away).
|
* no longer using it (and could go away).
|
||||||
*
|
*
|
||||||
* This causes the removal of all event listeners registered by this
|
|
||||||
* instance of the listener manager. This is important for Bug 323807,
|
|
||||||
* since nsDOMClassInfo::PreserveWrapper (and nsIDOMGCParticipant)
|
|
||||||
* require that we remove all event listeners to remove any weak
|
|
||||||
* references in the nsDOMClassInfo's preserved wrapper table to the
|
|
||||||
* target.
|
|
||||||
*
|
|
||||||
* It also clears the weak pointer set by the call to
|
* It also clears the weak pointer set by the call to
|
||||||
* |SetListenerTarget|.
|
* |SetListenerTarget|.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -394,8 +394,7 @@ nsEventListenerManager::Shutdown()
|
||||||
nsDOMEvent::Shutdown();
|
nsDOMEvent::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsEventListenerManager)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventListenerManager)
|
||||||
NS_IMPL_RELEASE(nsEventListenerManager)
|
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
|
NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEventListenerManager)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEventListenerManager)
|
||||||
|
@ -403,8 +402,28 @@ NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsEventListenerManager)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsEventListenerManager, nsIEventListenerManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsEventListenerManager, nsIEventListenerManager)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEventListenerManager, nsIEventListenerManager)
|
||||||
|
PRInt32 i, count = tmp->mListeners.Count();
|
||||||
|
nsListenerStruct *ls;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
ls = NS_STATIC_CAST(nsListenerStruct*, tmp->mListeners.ElementAt(i));
|
||||||
|
if (ls && ls->mListener.get()) {
|
||||||
|
cb.NoteXPCOMChild(ls->mListener.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEventListenerManager, nsIEventListenerManager)
|
||||||
|
tmp->Disconnect();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
const EventTypeData*
|
const EventTypeData*
|
||||||
nsEventListenerManager::GetTypeDataForIID(const nsIID& aIID)
|
nsEventListenerManager::GetTypeDataForIID(const nsIID& aIID)
|
||||||
{
|
{
|
||||||
|
@ -477,8 +496,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
||||||
PRInt32 count = mListeners.Count();
|
PRInt32 count = mListeners.Count();
|
||||||
for (PRInt32 i = 0; i < count; i++) {
|
for (PRInt32 i = 0; i < count; i++) {
|
||||||
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
|
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
|
||||||
nsRefPtr<nsIDOMEventListener> listener = ls->mListener.Get();
|
if (ls->mListener == aListener && ls->mFlags == aFlags &&
|
||||||
if (listener == aListener && ls->mFlags == aFlags &&
|
|
||||||
ls->mGroupFlags == group &&
|
ls->mGroupFlags == group &&
|
||||||
(EVENT_TYPE_EQUALS(ls, aType, aTypeAtom) ||
|
(EVENT_TYPE_EQUALS(ls, aType, aTypeAtom) ||
|
||||||
EVENT_TYPE_DATA_EQUALS(aTypeData, ls->mTypeData))) {
|
EVENT_TYPE_DATA_EQUALS(aTypeData, ls->mTypeData))) {
|
||||||
|
@ -492,9 +510,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
||||||
ls = new nsListenerStruct();
|
ls = new nsListenerStruct();
|
||||||
NS_ENSURE_TRUE(ls, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(ls, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(mTarget);
|
ls->mListener = aListener;
|
||||||
NS_ASSERTION(participant, "must implement nsIDOMGCParticipant");
|
|
||||||
ls->mListener.Set(aListener, participant);
|
|
||||||
ls->mEventType = aType;
|
ls->mEventType = aType;
|
||||||
ls->mTypeAtom = aTypeAtom;
|
ls->mTypeAtom = aTypeAtom;
|
||||||
ls->mFlags = aFlags;
|
ls->mFlags = aFlags;
|
||||||
|
@ -598,8 +614,7 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
|
||||||
PRInt32 count = mListeners.Count();
|
PRInt32 count = mListeners.Count();
|
||||||
for (PRInt32 i = 0; i < count; ++i) {
|
for (PRInt32 i = 0; i < count; ++i) {
|
||||||
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
|
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
|
||||||
nsRefPtr<nsIDOMEventListener> listener = ls->mListener.Get();
|
if (ls->mListener == aListener &&
|
||||||
if (listener == aListener &&
|
|
||||||
ls->mGroupFlags == group &&
|
ls->mGroupFlags == group &&
|
||||||
((ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) &&
|
((ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) &&
|
||||||
(EVENT_TYPE_EQUALS(ls, aType, aUserType) ||
|
(EVENT_TYPE_EQUALS(ls, aType, aUserType) ||
|
||||||
|
@ -1361,9 +1376,7 @@ found:
|
||||||
// Check that the phase is same in event and event listener.
|
// Check that the phase is same in event and event listener.
|
||||||
// Handle only trusted events, except when listener permits untrusted events.
|
// Handle only trusted events, except when listener permits untrusted events.
|
||||||
if (useTypeInterface || useGenericInterface) {
|
if (useTypeInterface || useGenericInterface) {
|
||||||
nsRefPtr<nsIDOMEventListener> eventListener = ls->mListener.Get();
|
if (ls->mListener) {
|
||||||
NS_ASSERTION(eventListener, "listener wasn't preserved properly");
|
|
||||||
if (eventListener) {
|
|
||||||
hasListener = PR_TRUE;
|
hasListener = PR_TRUE;
|
||||||
if (ls->mFlags & aFlags &&
|
if (ls->mFlags & aFlags &&
|
||||||
ls->mGroupFlags == currentGroup &&
|
ls->mGroupFlags == currentGroup &&
|
||||||
|
@ -1375,10 +1388,10 @@ found:
|
||||||
}
|
}
|
||||||
if (*aDOMEvent) {
|
if (*aDOMEvent) {
|
||||||
if (useTypeInterface) {
|
if (useTypeInterface) {
|
||||||
DispatchToInterface(*aDOMEvent, eventListener,
|
DispatchToInterface(*aDOMEvent, ls->mListener,
|
||||||
dispData->method, *typeData->iid);
|
dispData->method, *typeData->iid);
|
||||||
} else if (useGenericInterface) {
|
} else if (useGenericInterface) {
|
||||||
HandleEventSubType(ls, eventListener, *aDOMEvent,
|
HandleEventSubType(ls, ls->mListener, *aDOMEvent,
|
||||||
aCurrentTarget, aFlags);
|
aCurrentTarget, aFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1421,11 +1434,6 @@ NS_IMETHODIMP
|
||||||
nsEventListenerManager::Disconnect()
|
nsEventListenerManager::Disconnect()
|
||||||
{
|
{
|
||||||
mTarget = nsnull;
|
mTarget = nsnull;
|
||||||
|
|
||||||
// Bug 323807: nsDOMClassInfo::PreserveWrapper (and
|
|
||||||
// nsIDOMGCParticipant) require that we remove all event listeners now
|
|
||||||
// to remove any weak references in the nsDOMClassInfo's preserved
|
|
||||||
// wrapper table to the target.
|
|
||||||
return RemoveAllListeners();
|
return RemoveAllListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,12 @@
|
||||||
#include "nsIEventListenerManager.h"
|
#include "nsIEventListenerManager.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
#include "nsIDOMEventReceiver.h"
|
#include "nsIDOMEventReceiver.h"
|
||||||
#include "nsIDOM3EventTarget.h"
|
#include "nsIDOM3EventTarget.h"
|
||||||
#include "nsHashtable.h"
|
#include "nsHashtable.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
#include "nsJSUtils.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsIDOMEvent;
|
class nsIDOMEvent;
|
||||||
class nsVoidArray;
|
class nsVoidArray;
|
||||||
|
@ -53,15 +54,7 @@ class nsIAtom;
|
||||||
struct EventTypeData;
|
struct EventTypeData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// The nsMarkedJSFunctionHolder does magic to avoid holding strong
|
nsRefPtr<nsIDOMEventListener> mListener;
|
||||||
// references to listeners implemented in JS. Instead, it protects
|
|
||||||
// them from garbage collection using nsDOMClassInfo::PreserveWrapper,
|
|
||||||
// which protects the event listener from garbage collection as long
|
|
||||||
// as it is still reachable from JS using C++ getters. (It exposes
|
|
||||||
// reachability information to the JS GC instead of treating the C++
|
|
||||||
// reachability information as own-in root-out, which creates roots
|
|
||||||
// that cause reference cycles to entrain garbage.)
|
|
||||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mListener;
|
|
||||||
PRUint32 mEventType;
|
PRUint32 mEventType;
|
||||||
nsCOMPtr<nsIAtom> mTypeAtom;
|
nsCOMPtr<nsIAtom> mTypeAtom;
|
||||||
PRUint16 mFlags;
|
PRUint16 mFlags;
|
||||||
|
@ -83,7 +76,7 @@ public:
|
||||||
nsEventListenerManager();
|
nsEventListenerManager();
|
||||||
virtual ~nsEventListenerManager();
|
virtual ~nsEventListenerManager();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets events listeners of all types.
|
* Sets events listeners of all types.
|
||||||
|
@ -159,6 +152,8 @@ public:
|
||||||
|
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsEventListenerManager)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
|
nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||||
nsIDOMEventListener* aListener,
|
nsIDOMEventListener* aListener,
|
||||||
|
|
|
@ -91,8 +91,8 @@ nsHTMLIFrameElement::~nsHTMLIFrameElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(nsHTMLIFrameElement, nsGenericElement)
|
NS_IMPL_ADDREF_INHERITED(nsHTMLIFrameElement,nsGenericElement)
|
||||||
NS_IMPL_RELEASE_INHERITED(nsHTMLIFrameElement, nsGenericElement)
|
NS_IMPL_RELEASE_INHERITED(nsHTMLIFrameElement,nsGenericElement)
|
||||||
|
|
||||||
// QueryInterface implementation for nsHTMLIFrameElement
|
// QueryInterface implementation for nsHTMLIFrameElement
|
||||||
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLIFrameElement, nsGenericHTMLFrameElement)
|
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLIFrameElement, nsGenericHTMLFrameElement)
|
||||||
|
|
|
@ -281,8 +281,100 @@ SetOrRemoveObject(PLDHashTable& table, nsISupports* aKey, nsISupports* aValue)
|
||||||
// Static member variable initialization
|
// Static member variable initialization
|
||||||
|
|
||||||
// Implement our nsISupports methods
|
// Implement our nsISupports methods
|
||||||
NS_IMPL_ISUPPORTS3(nsBindingManager, nsIBindingManager, nsIStyleRuleSupplier,
|
|
||||||
nsIMutationObserver)
|
static PRBool PR_CALLBACK
|
||||||
|
ReleaseBindings(void *aElement, void *aData);
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager, nsIBindingManager)
|
||||||
|
tmp->mBindingTable.Clear();
|
||||||
|
tmp->mDocumentTable.Clear();
|
||||||
|
tmp->mLoadingDocTable.Clear();
|
||||||
|
|
||||||
|
if (tmp->mContentListTable.ops)
|
||||||
|
PL_DHashTableFinish(&(tmp->mContentListTable));
|
||||||
|
tmp->mContentListTable.ops = nsnull;
|
||||||
|
|
||||||
|
if (tmp->mAnonymousNodesTable.ops)
|
||||||
|
PL_DHashTableFinish(&(tmp->mAnonymousNodesTable));
|
||||||
|
tmp->mAnonymousNodesTable.ops = nsnull;
|
||||||
|
|
||||||
|
if (tmp->mInsertionParentTable.ops)
|
||||||
|
PL_DHashTableFinish(&(tmp->mInsertionParentTable));
|
||||||
|
tmp->mInsertionParentTable.ops = nsnull;
|
||||||
|
|
||||||
|
if (tmp->mWrapperTable.ops)
|
||||||
|
PL_DHashTableFinish(&(tmp->mWrapperTable));
|
||||||
|
tmp->mWrapperTable.ops = nsnull;
|
||||||
|
|
||||||
|
tmp->mAttachedStack.EnumerateForwards(ReleaseBindings, nsnull);
|
||||||
|
tmp->mAttachedStack.Clear();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
DocumentInfoHashtableTraverser(nsIURI* key,
|
||||||
|
nsIXBLDocumentInfo* di,
|
||||||
|
void* userArg)
|
||||||
|
{
|
||||||
|
nsCycleCollectionTraversalCallback *cb =
|
||||||
|
NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, userArg);
|
||||||
|
cb->NoteXPCOMChild(di);
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
LoadingDocHashtableTraverser(nsIURI* key,
|
||||||
|
nsIStreamListener* sl,
|
||||||
|
void* userArg)
|
||||||
|
{
|
||||||
|
nsCycleCollectionTraversalCallback *cb =
|
||||||
|
NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, userArg);
|
||||||
|
cb->NoteXPCOMChild(sl);
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
XBLBindingHashtableTraverser(nsISupports* key,
|
||||||
|
nsXBLBinding* binding,
|
||||||
|
void* userArg)
|
||||||
|
{
|
||||||
|
nsCycleCollectionTraversalCallback *cb =
|
||||||
|
NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, userArg);
|
||||||
|
|
||||||
|
// XBLBindings aren't nsISupports, so we don't tell the cycle collector
|
||||||
|
// about them explicitly. Instead, we traverse their contents directly
|
||||||
|
// here.
|
||||||
|
|
||||||
|
while (binding) {
|
||||||
|
nsISupports *c = binding->GetAnonymousContent();
|
||||||
|
if (c)
|
||||||
|
cb->NoteXPCOMChild(c);
|
||||||
|
binding = binding->GetBaseBinding();
|
||||||
|
}
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager, nsIBindingManager)
|
||||||
|
if (tmp->mBindingTable.IsInitialized())
|
||||||
|
tmp->mBindingTable.EnumerateRead(&XBLBindingHashtableTraverser, &cb);
|
||||||
|
if (tmp->mDocumentTable.IsInitialized())
|
||||||
|
tmp->mDocumentTable.EnumerateRead(&DocumentInfoHashtableTraverser, &cb);
|
||||||
|
if (tmp->mLoadingDocTable.IsInitialized())
|
||||||
|
tmp->mLoadingDocTable.EnumerateRead(&LoadingDocHashtableTraverser, &cb);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN(nsBindingManager)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIBindingManager)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIStyleRuleSupplier)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBindingManager)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsBindingManager)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsBindingManager, nsIBindingManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsBindingManager, nsIBindingManager)
|
||||||
|
|
||||||
// Constructors/Destructors
|
// Constructors/Destructors
|
||||||
nsBindingManager::nsBindingManager(void)
|
nsBindingManager::nsBindingManager(void)
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "nsInterfaceHashtable.h"
|
#include "nsInterfaceHashtable.h"
|
||||||
#include "nsRefPtrHashtable.h"
|
#include "nsRefPtrHashtable.h"
|
||||||
#include "nsURIHashKey.h"
|
#include "nsURIHashKey.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
class nsIXPConnectWrappedJS;
|
class nsIXPConnectWrappedJS;
|
||||||
|
@ -64,7 +65,7 @@ class nsBindingManager : public nsIBindingManager,
|
||||||
public nsIMutationObserver
|
public nsIMutationObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_NSIMUTATIONOBSERVER
|
NS_DECL_NSIMUTATIONOBSERVER
|
||||||
|
|
||||||
nsBindingManager();
|
nsBindingManager();
|
||||||
|
@ -136,6 +137,8 @@ public:
|
||||||
RuleProcessorData* aData,
|
RuleProcessorData* aData,
|
||||||
PRBool* aCutOffInheritance);
|
PRBool* aCutOffInheritance);
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult GetXBLChildNodesInternal(nsIContent* aContent,
|
nsresult GetXBLChildNodesInternal(nsIContent* aContent,
|
||||||
nsIDOMNodeList** aResult,
|
nsIDOMNodeList** aResult,
|
||||||
|
|
|
@ -105,8 +105,6 @@
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "nsNodeUtils.h"
|
#include "nsNodeUtils.h"
|
||||||
|
|
||||||
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
|
||||||
|
|
||||||
// Helper classes
|
// Helper classes
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
@ -1179,9 +1177,8 @@ nsXBLBinding::InitClass(const nsCString& aClassName,
|
||||||
if (doc) {
|
if (doc) {
|
||||||
nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
|
nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
|
||||||
do_QueryInterface(wrapper);
|
do_QueryInterface(wrapper);
|
||||||
|
|
||||||
if (native_wrapper) {
|
if (native_wrapper) {
|
||||||
NS_DOMClassInfo_PreserveNodeWrapper(native_wrapper);
|
doc->AddReference(mBoundElement, native_wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,19 @@ static PRBool IsChromeURI(nsIURI* aURI)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implementation file */
|
/* Implementation file */
|
||||||
NS_IMPL_ISUPPORTS3(nsXBLDocumentInfo, nsIXBLDocumentInfo, nsIScriptGlobalObjectOwner, nsISupportsWeakReference)
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_2_AMBIGUOUS(nsXBLDocumentInfo, nsIXBLDocumentInfo, mDocument, mGlobalObject)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN(nsXBLDocumentInfo)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIXBLDocumentInfo)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXBLDocumentInfo)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsXBLDocumentInfo)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXBLDocumentInfo, nsIXBLDocumentInfo)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXBLDocumentInfo, nsIXBLDocumentInfo)
|
||||||
|
|
||||||
nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
|
nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
|
||||||
: mDocument(aDocument),
|
: mDocument(aDocument),
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "nsIScriptGlobalObjectOwner.h"
|
#include "nsIScriptGlobalObjectOwner.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsXBLPrototypeBinding;
|
class nsXBLPrototypeBinding;
|
||||||
class nsObjectHashtable;
|
class nsObjectHashtable;
|
||||||
|
@ -46,7 +47,7 @@ class nsObjectHashtable;
|
||||||
class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsIScriptGlobalObjectOwner, public nsSupportsWeakReference
|
class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsIScriptGlobalObjectOwner, public nsSupportsWeakReference
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
nsXBLDocumentInfo(nsIDocument* aDocument);
|
nsXBLDocumentInfo(nsIDocument* aDocument);
|
||||||
virtual ~nsXBLDocumentInfo();
|
virtual ~nsXBLDocumentInfo();
|
||||||
|
@ -67,6 +68,8 @@ public:
|
||||||
// nsIScriptGlobalObjectOwner methods
|
// nsIScriptGlobalObjectOwner methods
|
||||||
virtual nsIScriptGlobalObject* GetScriptGlobalObject();
|
virtual nsIScriptGlobalObject* GetScriptGlobalObject();
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsIDocument> mDocument;
|
nsCOMPtr<nsIDocument> mDocument;
|
||||||
PRPackedBool mScriptAccess;
|
PRPackedBool mScriptAccess;
|
||||||
|
|
|
@ -48,8 +48,6 @@
|
||||||
#include "nsIXBLDocumentInfo.h"
|
#include "nsIXBLDocumentInfo.h"
|
||||||
#include "nsIDOMNode.h"
|
#include "nsIDOMNode.h"
|
||||||
|
|
||||||
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement)
|
nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement)
|
||||||
{
|
{
|
||||||
|
@ -150,9 +148,8 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
|
||||||
nsIDocument* doc = aBoundElement->GetOwnerDoc();
|
nsIDocument* doc = aBoundElement->GetOwnerDoc();
|
||||||
if (doc) {
|
if (doc) {
|
||||||
nsCOMPtr<nsIXPConnectWrappedNative> nativeWrapper(do_QueryInterface(wrapper));
|
nsCOMPtr<nsIXPConnectWrappedNative> nativeWrapper(do_QueryInterface(wrapper));
|
||||||
if (nativeWrapper) {
|
if (nativeWrapper)
|
||||||
NS_DOMClassInfo_PreserveNodeWrapper(nativeWrapper);
|
doc->AddReference(aBoundElement, nativeWrapper);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper.swap(*aScriptObjectHolder);
|
wrapper.swap(*aScriptObjectHolder);
|
||||||
|
|
|
@ -756,6 +756,10 @@ nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
|
||||||
nsCOMPtr<nsIContent> templParent = aTemplChild->GetParent();
|
nsCOMPtr<nsIContent> templParent = aTemplChild->GetParent();
|
||||||
nsCOMPtr<nsIContent> childPoint;
|
nsCOMPtr<nsIContent> childPoint;
|
||||||
|
|
||||||
|
// We may be disconnected from our parent during cycle collection.
|
||||||
|
if (!templParent)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
if (aBoundElement) {
|
if (aBoundElement) {
|
||||||
if (templParent->NodeInfo()->Equals(nsXBLAtoms::children,
|
if (templParent->NodeInfo()->Equals(nsXBLAtoms::children,
|
||||||
kNameSpaceID_XBL)) {
|
kNameSpaceID_XBL)) {
|
||||||
|
|
|
@ -41,16 +41,15 @@
|
||||||
#define nsPIWindowRoot_h__
|
#define nsPIWindowRoot_h__
|
||||||
|
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
|
|
||||||
class nsIFocusController;
|
class nsIFocusController;
|
||||||
|
|
||||||
// a22236a5-db06-4653-94b6-c4b6068e053c
|
// c18dee5a-dcf9-4391-a20c-581e769d095e
|
||||||
#define NS_IWINDOWROOT_IID \
|
#define NS_IWINDOWROOT_IID \
|
||||||
{ 0xa22236a5, 0xdb06, 0x4653, \
|
{ 0xc18dee5a, 0xdcf9, 0x4391, \
|
||||||
{ 0x94, 0xb6, 0xc4, 0xb6, 0x06, 0x8e, 0x05, 0x3c } }
|
{ 0xa2, 0x0c, 0x58, 0x1e, 0x76, 0x9d, 0x09, 0x5e } }
|
||||||
|
|
||||||
class nsPIWindowRoot : public nsIDOMGCParticipant {
|
class nsPIWindowRoot : public nsISupports {
|
||||||
public:
|
public:
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
|
||||||
|
|
||||||
|
|
|
@ -59,26 +59,9 @@ public:
|
||||||
|
|
||||||
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
|
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
|
||||||
nsISupports *aTarget)
|
nsISupports *aTarget)
|
||||||
: mContext(aContext), mScopeObject(aScopeObject), mTarget(nsnull)
|
: mContext(aContext), mScopeObject(aScopeObject),
|
||||||
|
mTarget(do_QueryInterface(aTarget))
|
||||||
{
|
{
|
||||||
// We keep a weak-ref to the event target to prevent cycles that prevent
|
|
||||||
// GC from cleaning up our global in all cases. However, as this is a
|
|
||||||
// weak-ref, we must ensure it is the identity of the event target and
|
|
||||||
// not a "tear-off" or similar that may not live as long as we expect.
|
|
||||||
aTarget->QueryInterface(NS_GET_IID(nsISupports),
|
|
||||||
NS_REINTERPRET_CAST(void **, &mTarget));
|
|
||||||
if (mTarget)
|
|
||||||
// We keep a weak-ref, so remove the reference the QI added.
|
|
||||||
mTarget->Release();
|
|
||||||
else {
|
|
||||||
NS_ERROR("Failed to get identity pointer");
|
|
||||||
}
|
|
||||||
// To help debug such leaks, we keep a counter of the event listeners
|
|
||||||
// currently alive. If you change |mTarget| to a strong-ref, this never
|
|
||||||
// hits zero (running seamonkey.)
|
|
||||||
#ifdef NS_DEBUG
|
|
||||||
PR_AtomicIncrement(&sNumJSEventListeners);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIScriptContext *GetEventContext()
|
nsIScriptContext *GetEventContext()
|
||||||
|
@ -98,20 +81,13 @@ public:
|
||||||
|
|
||||||
virtual void SetEventName(nsIAtom* aName) = 0;
|
virtual void SetEventName(nsIAtom* aName) = 0;
|
||||||
|
|
||||||
#ifdef NS_DEBUG
|
|
||||||
static PRInt32 sNumJSEventListeners;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsIJSEventListener()
|
virtual ~nsIJSEventListener()
|
||||||
{
|
{
|
||||||
#ifdef NS_DEBUG
|
|
||||||
PR_AtomicDecrement(&sNumJSEventListeners);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIScriptContext> mContext;
|
nsCOMPtr<nsIScriptContext> mContext;
|
||||||
void *mScopeObject;
|
void *mScopeObject;
|
||||||
nsISupports *mTarget; // weak ref.
|
nsCOMPtr<nsISupports> mTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
|
||||||
|
|
|
@ -432,28 +432,20 @@ static const char kDOMStringBundleURL[] =
|
||||||
// NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
|
// NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
|
||||||
// are defined in nsIDOMClassInfo.h.
|
// are defined in nsIDOMClassInfo.h.
|
||||||
|
|
||||||
#define GCPARTICIPANT_SCRIPTABLE_FLAGS \
|
|
||||||
(DOM_DEFAULT_SCRIPTABLE_FLAGS | \
|
|
||||||
nsIXPCScriptable::WANT_FINALIZE | \
|
|
||||||
nsIXPCScriptable::WANT_MARK)
|
|
||||||
|
|
||||||
#define WINDOW_SCRIPTABLE_FLAGS \
|
#define WINDOW_SCRIPTABLE_FLAGS \
|
||||||
(nsIXPCScriptable::WANT_GETPROPERTY | \
|
(nsIXPCScriptable::WANT_GETPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_SETPROPERTY | \
|
nsIXPCScriptable::WANT_SETPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_PRECREATE | \
|
nsIXPCScriptable::WANT_PRECREATE | \
|
||||||
nsIXPCScriptable::WANT_FINALIZE | \
|
|
||||||
nsIXPCScriptable::WANT_ADDPROPERTY | \
|
nsIXPCScriptable::WANT_ADDPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_DELPROPERTY | \
|
nsIXPCScriptable::WANT_DELPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_NEWENUMERATE | \
|
nsIXPCScriptable::WANT_NEWENUMERATE | \
|
||||||
nsIXPCScriptable::WANT_MARK | \
|
|
||||||
nsIXPCScriptable::WANT_EQUALITY | \
|
nsIXPCScriptable::WANT_EQUALITY | \
|
||||||
nsIXPCScriptable::WANT_OUTER_OBJECT | \
|
nsIXPCScriptable::WANT_OUTER_OBJECT | \
|
||||||
nsIXPCScriptable::WANT_INNER_OBJECT | \
|
nsIXPCScriptable::WANT_INNER_OBJECT | \
|
||||||
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
|
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
|
||||||
|
|
||||||
#define NODE_SCRIPTABLE_FLAGS \
|
#define NODE_SCRIPTABLE_FLAGS \
|
||||||
((GCPARTICIPANT_SCRIPTABLE_FLAGS | \
|
((nsIXPCScriptable::WANT_GETPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_GETPROPERTY | \
|
|
||||||
nsIXPCScriptable::WANT_PRECREATE | \
|
nsIXPCScriptable::WANT_PRECREATE | \
|
||||||
nsIXPCScriptable::WANT_ADDPROPERTY | \
|
nsIXPCScriptable::WANT_ADDPROPERTY | \
|
||||||
nsIXPCScriptable::WANT_SETPROPERTY) & \
|
nsIXPCScriptable::WANT_SETPROPERTY) & \
|
||||||
|
@ -823,8 +815,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
|
||||||
// DOM Traversal classes
|
// DOM Traversal classes
|
||||||
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGCParticipantSH,
|
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGenericSH,
|
||||||
GCPARTICIPANT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
|
||||||
// We are now trying to preserve binary compat in classinfo. No
|
// We are now trying to preserve binary compat in classinfo. No
|
||||||
// more putting things in those categories up there. New entries
|
// more putting things in those categories up there. New entries
|
||||||
|
@ -1125,7 +1117,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
// event listeners.
|
// event listeners.
|
||||||
// We really don't want any of the default flags!
|
// We really don't want any of the default flags!
|
||||||
NS_DEFINE_CLASSINFO_DATA(WindowRoot, nsEventReceiverSH,
|
NS_DEFINE_CLASSINFO_DATA(WindowRoot, nsEventReceiverSH,
|
||||||
nsIXPCScriptable::WANT_MARK)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(DOMParser, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(DOMParser, nsDOMGenericSH,
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
@ -1134,8 +1126,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH,
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsDOMGCParticipantSH,
|
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsDOMGenericSH,
|
||||||
GCPARTICIPANT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
|
||||||
// Define MOZ_SVG_FOREIGNOBJECT here so that when it gets switched on,
|
// Define MOZ_SVG_FOREIGNOBJECT here so that when it gets switched on,
|
||||||
// we preserve binary compatibility. New classes should be added
|
// we preserve binary compatibility. New classes should be added
|
||||||
|
@ -3644,24 +3636,6 @@ nsDOMClassInfo::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are declared here so we can assert that they're empty in ShutDown.
|
|
||||||
/**
|
|
||||||
* Every XPConnect wrapper that needs to be preserved (a wrapped native
|
|
||||||
* with JS properties set on it or used by XBL or a wrapped JS event
|
|
||||||
* handler function) as long as the element it wraps is reachable from
|
|
||||||
* script (via JS or via DOM APIs accessible from JS) gets an entry in
|
|
||||||
* this table.
|
|
||||||
*
|
|
||||||
* See PreservedWrapperEntry.
|
|
||||||
*/
|
|
||||||
static PLDHashTable sPreservedWrapperTable;
|
|
||||||
|
|
||||||
// See ExternallyReferencedEntry.
|
|
||||||
static PLDHashTable sExternallyReferencedTable;
|
|
||||||
|
|
||||||
// See RootWhenExternallyReferencedEntry
|
|
||||||
static PLDHashTable sRootWhenExternallyReferencedTable;
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsIClassInfo *
|
nsIClassInfo *
|
||||||
nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoID aID)
|
nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoID aID)
|
||||||
|
@ -3717,24 +3691,36 @@ nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoData* aData)
|
||||||
return GET_CLEAN_CI_PTR(aData->mCachedClassInfo);
|
return GET_CLEAN_CI_PTR(aData->mCachedClassInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
nsresult
|
||||||
|
nsDOMClassInfo::PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||||
|
{
|
||||||
|
nsISupports *native = aWrapper->Native();
|
||||||
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(native));
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocument> doc;
|
||||||
|
if (node) {
|
||||||
|
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||||
|
node->GetOwnerDocument(getter_AddRefs(domdoc));
|
||||||
|
doc = do_QueryInterface(domdoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
doc = do_QueryInterface(native);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc) {
|
||||||
|
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
|
||||||
|
doc->AddReference(content, aWrapper);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void
|
void
|
||||||
nsDOMClassInfo::ShutDown()
|
nsDOMClassInfo::ShutDown()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(sPreservedWrapperTable.ops == 0,
|
|
||||||
"preserved wrapper table not empty at shutdown");
|
|
||||||
NS_ASSERTION(sExternallyReferencedTable.ops == 0 ||
|
|
||||||
sExternallyReferencedTable.entryCount == 0,
|
|
||||||
"rooted participant table not empty at shutdown");
|
|
||||||
NS_ASSERTION(sRootWhenExternallyReferencedTable.ops == 0,
|
|
||||||
"root when externally referenced table not empty at shutdown");
|
|
||||||
|
|
||||||
if (sExternallyReferencedTable.ops &&
|
|
||||||
sExternallyReferencedTable.entryCount == 0) {
|
|
||||||
PL_DHashTableFinish(&sExternallyReferencedTable);
|
|
||||||
sExternallyReferencedTable.ops = nsnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sClassInfoData[0].u.mConstructorFptr) {
|
if (sClassInfoData[0].u.mConstructorFptr) {
|
||||||
PRUint32 i;
|
PRUint32 i;
|
||||||
|
|
||||||
|
@ -5003,517 +4989,6 @@ nsDOMConstructor::ToString(nsAString &aResult)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The problem of how to deal with garbage collection in a system where:
|
|
||||||
* 1. the GC runtime contains lazily-created wrappers for other data
|
|
||||||
* structures not participating in the GC,
|
|
||||||
* 2. where those data structures are reachable from each other in a
|
|
||||||
* way that is reflected through the wrappers, and
|
|
||||||
* 3. where the wrappers can carry additional information that is not
|
|
||||||
* in the wrapped object
|
|
||||||
* is a difficult one. XPConnect is such a system. It creates wrappers
|
|
||||||
* around native objects that do not participate in the JS GC and which
|
|
||||||
* are reachable from each other outside of the knowledge of the JS
|
|
||||||
* engine (but through getters or functions that are accessible to JS
|
|
||||||
* users) and it allows these wrappers to be decorated with JS
|
|
||||||
* properties. It is worth noting one very important use case for our
|
|
||||||
* toolkit: XBL, which uses JS properties on the bound element for
|
|
||||||
* storing fields.
|
|
||||||
*
|
|
||||||
* For DOM nodes, compatibility with behavior in other browsers requires
|
|
||||||
* that we preserve JS properties on wrappers across garbage collection.
|
|
||||||
* To do this in a way that the garbage collector is still effective, we
|
|
||||||
* have to incorporate knowledge of reachability in the underlying
|
|
||||||
* (wrapped) data structures into the garbage collector's mark phase.
|
|
||||||
*
|
|
||||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=283129 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(DEBUG_dbaron)
|
|
||||||
#define DEBUG_PRESERVE_WRAPPERS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct RootWhenExternallyReferencedEntry : public PLDHashEntryHdr {
|
|
||||||
// must be first to line up with PLDHashEntryStub
|
|
||||||
nsIDOMGCParticipant *participant;
|
|
||||||
PRUint32 refcnt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PreservedWrapperEntry : public PLDHashEntryHdr {
|
|
||||||
void *key; // must be first to line up with PLDHashEntryStub
|
|
||||||
nsIXPConnectJSObjectHolder* (*keyToWrapperFunc)(void* aKey);
|
|
||||||
nsIDOMGCParticipant *participant;
|
|
||||||
PRBool rootWhenExternallyReferenced;
|
|
||||||
|
|
||||||
// See |WrapperSCCEntry::first|. Valid only during mark phase of GC.
|
|
||||||
PreservedWrapperEntry *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(void)
|
|
||||||
PreservedWrapperClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
|
|
||||||
{
|
|
||||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*, hdr);
|
|
||||||
|
|
||||||
if (entry->rootWhenExternallyReferenced) {
|
|
||||||
NS_ASSERTION(sRootWhenExternallyReferencedTable.ops,
|
|
||||||
"must have been added to rwer table");
|
|
||||||
RootWhenExternallyReferencedEntry *rwerEntry =
|
|
||||||
NS_STATIC_CAST(RootWhenExternallyReferencedEntry*,
|
|
||||||
PL_DHashTableOperate(&sRootWhenExternallyReferencedTable,
|
|
||||||
entry->participant, PL_DHASH_LOOKUP));
|
|
||||||
NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(rwerEntry),
|
|
||||||
"boolean vs. table mismatch");
|
|
||||||
if (PL_DHASH_ENTRY_IS_BUSY(rwerEntry) && --rwerEntry->refcnt == 0) {
|
|
||||||
PL_DHashTableRawRemove(&sRootWhenExternallyReferencedTable, rwerEntry);
|
|
||||||
if (sRootWhenExternallyReferencedTable.entryCount == 0) {
|
|
||||||
PL_DHashTableFinish(&sRootWhenExternallyReferencedTable);
|
|
||||||
sRootWhenExternallyReferencedTable.ops = nsnull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(hdr, 0, table->entrySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PLDHashTableOps sPreservedWrapperTableOps = {
|
|
||||||
PL_DHashAllocTable,
|
|
||||||
PL_DHashFreeTable,
|
|
||||||
PL_DHashGetKeyStub,
|
|
||||||
PL_DHashVoidPtrKeyStub,
|
|
||||||
PL_DHashMatchEntryStub,
|
|
||||||
PL_DHashMoveEntryStub,
|
|
||||||
PreservedWrapperClearEntry,
|
|
||||||
PL_DHashFinalizeStub,
|
|
||||||
nsnull
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* At the beginning of the mark phase of the GC, we sort all the
|
|
||||||
* wrappers into their strongly connected components. We maintain this
|
|
||||||
* information for the duration of the mark phase, during which time
|
|
||||||
* |sWrapperSCCTable| maps the SCC roots to a list of the wrappers in
|
|
||||||
* the SCC. This allows the mark callback for any wrapper (preserved or
|
|
||||||
* not) to quickly mark all of the preserved wrappers in its SCC.
|
|
||||||
*
|
|
||||||
* Many of these roots are documents. We know that a document will be
|
|
||||||
* marked if it is still being displayed since the document is reachable
|
|
||||||
* by a JS property on the global object.
|
|
||||||
*/
|
|
||||||
static PLDHashTable sWrapperSCCTable;
|
|
||||||
|
|
||||||
// If we run out of memory constructing sWrapperSCCTable, its |ops|
|
|
||||||
// member holds this value for the remainder of that GC cycle.
|
|
||||||
#define WRAPPER_SCC_OPS_OOM_MARKER ((PLDHashTableOps*)1)
|
|
||||||
|
|
||||||
struct WrapperSCCEntry : public PLDHashEntryHdr {
|
|
||||||
// This could probably be a weak pointer (which would avoid the
|
|
||||||
// need for hash table ops), but it seems safer this way.
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> key; // must be first to line up with PLDHashEntryStub
|
|
||||||
|
|
||||||
// Linked list of preserved wrappers in the strongly connected
|
|
||||||
// component, to be traversed using |PreservedWrapperEntry::next|.
|
|
||||||
PreservedWrapperEntry *first;
|
|
||||||
|
|
||||||
PRBool marked;
|
|
||||||
|
|
||||||
WrapperSCCEntry(nsIDOMGCParticipant *aKey)
|
|
||||||
: key(aKey), first(nsnull), marked(PR_FALSE) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(void)
|
|
||||||
WrapperSCCsClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
|
|
||||||
{
|
|
||||||
WrapperSCCEntry *entry = NS_STATIC_CAST(WrapperSCCEntry*, hdr);
|
|
||||||
entry->~WrapperSCCEntry();
|
|
||||||
memset(hdr, 0, table->entrySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PRBool)
|
|
||||||
WrapperSCCsInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
||||||
const void *key)
|
|
||||||
{
|
|
||||||
WrapperSCCEntry *entry = NS_STATIC_CAST(WrapperSCCEntry*, hdr);
|
|
||||||
new (entry) WrapperSCCEntry(NS_STATIC_CAST(nsIDOMGCParticipant*,
|
|
||||||
NS_CONST_CAST(void*, key)));
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PLDHashTableOps sWrapperSCCTableOps = {
|
|
||||||
PL_DHashAllocTable,
|
|
||||||
PL_DHashFreeTable,
|
|
||||||
PL_DHashGetKeyStub,
|
|
||||||
PL_DHashVoidPtrKeyStub,
|
|
||||||
PL_DHashMatchEntryStub,
|
|
||||||
PL_DHashMoveEntryStub,
|
|
||||||
WrapperSCCsClearEntry,
|
|
||||||
PL_DHashFinalizeStub,
|
|
||||||
WrapperSCCsInitEntry
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult
|
|
||||||
nsDOMClassInfo::PreserveWrapper(void *aKey,
|
|
||||||
nsIXPConnectJSObjectHolder* (*aKeyToWrapperFunc)(void* aKey),
|
|
||||||
nsIDOMGCParticipant *aParticipant,
|
|
||||||
PRBool aRootWhenExternallyReferenced)
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(aKey, "unexpected null pointer");
|
|
||||||
NS_PRECONDITION(aKeyToWrapperFunc, "unexpected null pointer");
|
|
||||||
NS_PRECONDITION(aParticipant, "unexpected null pointer");
|
|
||||||
NS_ASSERTION(!sWrapperSCCTable.ops,
|
|
||||||
"cannot change preserved wrapper table during mark phase");
|
|
||||||
|
|
||||||
if (!sPreservedWrapperTable.ops &&
|
|
||||||
!PL_DHashTableInit(&sPreservedWrapperTable, &sPreservedWrapperTableOps,
|
|
||||||
nsnull, sizeof(PreservedWrapperEntry), 16)) {
|
|
||||||
sPreservedWrapperTable.ops = nsnull;
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*,
|
|
||||||
PL_DHashTableOperate(&sPreservedWrapperTable, aKey, PL_DHASH_ADD));
|
|
||||||
if (!entry)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
NS_ASSERTION(!entry->key ||
|
|
||||||
(entry->key == aKey &&
|
|
||||||
entry->keyToWrapperFunc == aKeyToWrapperFunc &&
|
|
||||||
entry->participant == aParticipant),
|
|
||||||
"preservation key already used");
|
|
||||||
|
|
||||||
PRBool wasExternallyReferenced = entry->rootWhenExternallyReferenced;
|
|
||||||
entry->key = aKey;
|
|
||||||
entry->keyToWrapperFunc = aKeyToWrapperFunc;
|
|
||||||
entry->participant = aParticipant;
|
|
||||||
entry->rootWhenExternallyReferenced =
|
|
||||||
aRootWhenExternallyReferenced || wasExternallyReferenced;
|
|
||||||
|
|
||||||
if (aRootWhenExternallyReferenced && !wasExternallyReferenced) {
|
|
||||||
if (!sRootWhenExternallyReferencedTable.ops &&
|
|
||||||
!PL_DHashTableInit(&sRootWhenExternallyReferencedTable,
|
|
||||||
PL_DHashGetStubOps(), nsnull,
|
|
||||||
sizeof(RootWhenExternallyReferencedEntry), 16)) {
|
|
||||||
PL_DHashTableRawRemove(&sPreservedWrapperTable, entry);
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootWhenExternallyReferencedEntry *rwerEntry =
|
|
||||||
NS_STATIC_CAST(RootWhenExternallyReferencedEntry*,
|
|
||||||
PL_DHashTableOperate(&sRootWhenExternallyReferencedTable,
|
|
||||||
aParticipant, PL_DHASH_ADD));
|
|
||||||
if (!rwerEntry) {
|
|
||||||
PL_DHashTableRawRemove(&sPreservedWrapperTable, entry);
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
NS_ASSERTION(rwerEntry->refcnt == 0 ||
|
|
||||||
rwerEntry->participant == aParticipant,
|
|
||||||
"entry mismatch");
|
|
||||||
rwerEntry->participant = aParticipant;
|
|
||||||
++rwerEntry->refcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static nsIXPConnectJSObjectHolder* IdentityKeyToWrapperFunc(void* aKey)
|
|
||||||
{
|
|
||||||
return NS_STATIC_CAST(nsIXPConnectJSObjectHolder*, aKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult
|
|
||||||
nsDOMClassInfo::PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper,
|
|
||||||
PRBool aRootWhenExternallyReferenced)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> participant =
|
|
||||||
do_QueryInterface(aWrapper->Native());
|
|
||||||
if (!participant)
|
|
||||||
// nsJSContext::PreserveWrapper needs us to null-check
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
nsCOMPtr<nsIClassInfo> info = do_QueryInterface(participant);
|
|
||||||
NS_ASSERTION(info, "Must have classinfo");
|
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> sup;
|
|
||||||
info->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
|
|
||||||
getter_AddRefs(sup));
|
|
||||||
|
|
||||||
nsCOMPtr<nsIXPCScriptable> scriptable = do_QueryInterface(sup);
|
|
||||||
NS_ASSERTION(scriptable, "Must have scriptable");
|
|
||||||
|
|
||||||
PRUint32 flags;
|
|
||||||
scriptable->GetScriptableFlags(&flags);
|
|
||||||
NS_ASSERTION(flags & nsIXPCScriptable::WANT_FINALIZE,
|
|
||||||
"We'll never get cleaned up!");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return nsDOMClassInfo::PreserveWrapper(aWrapper, IdentityKeyToWrapperFunc,
|
|
||||||
participant,
|
|
||||||
aRootWhenExternallyReferenced);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void
|
|
||||||
nsDOMClassInfo::ReleaseWrapper(void *aKey)
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(aKey, "unexpected null pointer");
|
|
||||||
NS_ASSERTION(!sWrapperSCCTable.ops,
|
|
||||||
"cannot change preserved wrapper table during mark phase");
|
|
||||||
|
|
||||||
if (sPreservedWrapperTable.ops) {
|
|
||||||
PL_DHashTableOperate(&sPreservedWrapperTable, aKey, PL_DHASH_REMOVE);
|
|
||||||
if (sPreservedWrapperTable.entryCount == 0) {
|
|
||||||
PL_DHashTableFinish(&sPreservedWrapperTable);
|
|
||||||
sPreservedWrapperTable.ops = nsnull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MarkAllWrappersData {
|
|
||||||
JSContext *cx;
|
|
||||||
void *arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
|
||||||
MarkAllWrappers(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
||||||
PRUint32 number, void *arg)
|
|
||||||
{
|
|
||||||
MarkAllWrappersData *data = NS_STATIC_CAST(MarkAllWrappersData*, arg);
|
|
||||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*, hdr);
|
|
||||||
|
|
||||||
nsIXPConnectJSObjectHolder *wrapper;
|
|
||||||
JSObject *wrapper_obj;
|
|
||||||
if ((wrapper = entry->keyToWrapperFunc(entry->key)) &&
|
|
||||||
NS_SUCCEEDED(wrapper->GetJSObject(&wrapper_obj)))
|
|
||||||
JS_MarkGCThing(data->cx, wrapper_obj,
|
|
||||||
"nsDOMClassInfo::sPreservedWrapperTable_OOM", data->arg);
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void
|
|
||||||
nsDOMClassInfo::MarkReachablePreservedWrappers(nsIDOMGCParticipant *aParticipant,
|
|
||||||
JSContext *cx, void *arg)
|
|
||||||
{
|
|
||||||
// Magic value indicating we've hit out-of-memory earlier in this GC.
|
|
||||||
if (sWrapperSCCTable.ops == WRAPPER_SCC_OPS_OOM_MARKER)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The JS engine doesn't have a notification for the beginning of
|
|
||||||
// the mark phase. However, we can determine that the mark phase
|
|
||||||
// has begun by detecting the first mark and lazily call
|
|
||||||
// BeginGCMark.
|
|
||||||
if (!sWrapperSCCTable.ops && !nsDOMClassInfo::BeginGCMark(cx)) {
|
|
||||||
// We didn't have enough memory to create the temporary data
|
|
||||||
// structures we needed.
|
|
||||||
sWrapperSCCTable.ops = WRAPPER_SCC_OPS_OOM_MARKER;
|
|
||||||
|
|
||||||
// Just mark all the preserved wrappers. It won't help the GC free
|
|
||||||
// up memory, but there's nothing better to do.
|
|
||||||
if (sPreservedWrapperTable.ops) {
|
|
||||||
MarkAllWrappersData data;
|
|
||||||
data.cx = cx;
|
|
||||||
data.arg = arg;
|
|
||||||
PL_DHashTableEnumerate(&sPreservedWrapperTable, MarkAllWrappers, &data);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIDOMGCParticipant *SCCIndex = aParticipant->GetSCCIndex();
|
|
||||||
WrapperSCCEntry *entry = NS_STATIC_CAST(WrapperSCCEntry*,
|
|
||||||
PL_DHashTableOperate(&sWrapperSCCTable, SCCIndex, PL_DHASH_LOOKUP));
|
|
||||||
if (!PL_DHASH_ENTRY_IS_BUSY(entry) || entry->marked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
|
||||||
{
|
|
||||||
nsAutoString nodeName;
|
|
||||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(entry->key);
|
|
||||||
if (node)
|
|
||||||
node->GetNodeName(nodeName);
|
|
||||||
else
|
|
||||||
nodeName.AssignLiteral("##not-node##");
|
|
||||||
printf(" marking entries for SCC root %p \"%s\"\n",
|
|
||||||
NS_STATIC_CAST(void*, entry->key.get()),
|
|
||||||
NS_ConvertUTF16toUTF8(nodeName).get());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
entry->marked = PR_TRUE;
|
|
||||||
|
|
||||||
// Do the reachable list first to encourage shorter call stacks
|
|
||||||
// (perhaps slightly less recursion through JS marking).
|
|
||||||
nsCOMArray<nsIDOMGCParticipant> reachable;
|
|
||||||
SCCIndex->AppendReachableList(reachable);
|
|
||||||
for (PRInt32 i = 0, i_end = reachable.Count(); i < i_end; ++i) {
|
|
||||||
if (reachable[i])
|
|
||||||
MarkReachablePreservedWrappers(reachable[i], cx, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PreservedWrapperEntry *pwe = entry->first; pwe; pwe = pwe->next) {
|
|
||||||
nsIXPConnectJSObjectHolder *wrapper;
|
|
||||||
JSObject *wrapper_obj;
|
|
||||||
if ((wrapper = pwe->keyToWrapperFunc(pwe->key)) &&
|
|
||||||
NS_SUCCEEDED(wrapper->GetJSObject(&wrapper_obj)))
|
|
||||||
::JS_MarkGCThing(cx, wrapper_obj,
|
|
||||||
"nsDOMClassInfo::sPreservedWrapperTable", arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ExternallyReferencedEntry : public PLDHashEntryHdr {
|
|
||||||
nsIDOMGCParticipant* key; // must be first to line up with PLDHashEntryStub
|
|
||||||
};
|
|
||||||
|
|
||||||
/* static */ nsresult
|
|
||||||
nsDOMClassInfo::SetExternallyReferenced(nsIDOMGCParticipant *aParticipant)
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(aParticipant, "unexpected null pointer");
|
|
||||||
|
|
||||||
if (!sExternallyReferencedTable.ops &&
|
|
||||||
!PL_DHashTableInit(&sExternallyReferencedTable, PL_DHashGetStubOps(),
|
|
||||||
nsnull, sizeof(ExternallyReferencedEntry), 16)) {
|
|
||||||
sExternallyReferencedTable.ops = nsnull;
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternallyReferencedEntry *entry = NS_STATIC_CAST(ExternallyReferencedEntry*,
|
|
||||||
PL_DHashTableOperate(&sExternallyReferencedTable, aParticipant, PL_DHASH_ADD));
|
|
||||||
if (!entry)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
NS_ASSERTION(!entry->key, "participant already rooted");
|
|
||||||
entry->key = aParticipant;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
nsDOMClassInfo::UnsetExternallyReferenced(nsIDOMGCParticipant *aParticipant)
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(aParticipant, "unexpected null pointer");
|
|
||||||
|
|
||||||
PL_DHashTableOperate(&sExternallyReferencedTable, aParticipant,
|
|
||||||
PL_DHASH_REMOVE);
|
|
||||||
|
|
||||||
// Don't destroy the table when the entryCount hits zero, since that
|
|
||||||
// is expected to happen often. Instead, destroy it at shutdown.
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
|
||||||
ClassifyWrapper(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
||||||
PRUint32 number, void *arg)
|
|
||||||
{
|
|
||||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*, hdr);
|
|
||||||
|
|
||||||
WrapperSCCEntry *SCCEntry = NS_STATIC_CAST(WrapperSCCEntry*,
|
|
||||||
PL_DHashTableOperate(&sWrapperSCCTable, entry->participant->GetSCCIndex(),
|
|
||||||
PL_DHASH_ADD));
|
|
||||||
if (!SCCEntry) {
|
|
||||||
*NS_STATIC_CAST(PRBool*, arg) = PR_TRUE;
|
|
||||||
return PL_DHASH_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
|
||||||
if (!SCCEntry->first) {
|
|
||||||
nsAutoString nodeName;
|
|
||||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(SCCEntry->key);
|
|
||||||
if (node)
|
|
||||||
node->GetNodeName(nodeName);
|
|
||||||
else
|
|
||||||
nodeName.AssignLiteral("##not-node##");
|
|
||||||
printf(" new SCC root %p \"%s\"\n",
|
|
||||||
NS_STATIC_CAST(void*, SCCEntry->key.get()),
|
|
||||||
NS_ConvertUTF16toUTF8(nodeName).get());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
entry->next = SCCEntry->first;
|
|
||||||
SCCEntry->first = entry;
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
|
||||||
MarkExternallyReferenced(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
||||||
PRUint32 number, void *arg)
|
|
||||||
{
|
|
||||||
ExternallyReferencedEntry *entry =
|
|
||||||
NS_STATIC_CAST(ExternallyReferencedEntry*, hdr);
|
|
||||||
JSContext *cx = NS_STATIC_CAST(JSContext*, arg);
|
|
||||||
|
|
||||||
nsIDOMGCParticipant *erParticipant = entry->key;
|
|
||||||
|
|
||||||
if (sRootWhenExternallyReferencedTable.ops) {
|
|
||||||
RootWhenExternallyReferencedEntry *rwerEntry =
|
|
||||||
NS_STATIC_CAST(RootWhenExternallyReferencedEntry*,
|
|
||||||
PL_DHashTableOperate(&sRootWhenExternallyReferencedTable,
|
|
||||||
erParticipant, PL_DHASH_LOOKUP));
|
|
||||||
if (PL_DHASH_ENTRY_IS_BUSY(rwerEntry)) {
|
|
||||||
NS_ASSERTION(rwerEntry->refcnt > 0, "bad reference count");
|
|
||||||
// XXX Construct something to say where the mark is coming from?
|
|
||||||
nsDOMClassInfo::MarkReachablePreservedWrappers(entry->key, cx, nsnull);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
PRBool
|
|
||||||
nsDOMClassInfo::BeginGCMark(JSContext *cx)
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(!sWrapperSCCTable.ops, "table already initialized");
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
|
||||||
printf("Classifying preserved wrappers into SCCs:\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!PL_DHashTableInit(&sWrapperSCCTable, &sWrapperSCCTableOps, nsnull,
|
|
||||||
sizeof(WrapperSCCEntry), 16)) {
|
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool failure = PR_FALSE;
|
|
||||||
if (sPreservedWrapperTable.ops) {
|
|
||||||
PL_DHashTableEnumerate(&sPreservedWrapperTable, ClassifyWrapper, &failure);
|
|
||||||
}
|
|
||||||
if (failure) {
|
|
||||||
PL_DHashTableFinish(&sWrapperSCCTable);
|
|
||||||
// caller will reset table ops
|
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
|
||||||
printf("Marking:\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (sExternallyReferencedTable.ops) {
|
|
||||||
PL_DHashTableEnumerate(&sExternallyReferencedTable,
|
|
||||||
MarkExternallyReferenced, cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void
|
|
||||||
nsDOMClassInfo::EndGCMark()
|
|
||||||
{
|
|
||||||
if (sWrapperSCCTable.ops) {
|
|
||||||
if (sWrapperSCCTable.ops != WRAPPER_SCC_OPS_OOM_MARKER)
|
|
||||||
PL_DHashTableFinish(&sWrapperSCCTable);
|
|
||||||
sWrapperSCCTable.ops = nsnull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hack to give XBL access to nsDOMClassInfo::PreserveNodeWrapper
|
|
||||||
nsresult
|
|
||||||
NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper)
|
|
||||||
{
|
|
||||||
return nsDOMClassInfo::PreserveNodeWrapper(aWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||||
|
@ -6830,11 +6305,7 @@ NS_IMETHODIMP
|
||||||
nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||||
JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
|
JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
|
||||||
{
|
{
|
||||||
// This can fail on out-of-memory, which should end up throwing a JS
|
nsDOMClassInfo::PreserveNodeWrapper(wrapper);
|
||||||
// exception.
|
|
||||||
nsresult rv = nsDOMClassInfo::PreserveNodeWrapper(wrapper);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval);
|
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7129,11 +6600,9 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
||||||
PRUint32 flags, JSObject **objp, PRBool *_retval)
|
PRUint32 flags, JSObject **objp, PRBool *_retval)
|
||||||
{
|
{
|
||||||
if (id == sOnload_id || id == sOnerror_id) {
|
if (id == sOnload_id || id == sOnerror_id) {
|
||||||
// Pass true for aRootWhenExternallyReferenced, so we make sure that
|
// Make sure that this node can't go away while waiting for a
|
||||||
// this node can't go away while waiting for a network load that
|
// network load that could fire an event handler.
|
||||||
// could fire an event handler.
|
nsDOMClassInfo::PreserveNodeWrapper(wrapper);
|
||||||
nsresult rv = nsDOMClassInfo::PreserveNodeWrapper(wrapper, PR_TRUE);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JSVAL_IS_STRING(id)) {
|
if (!JSVAL_IS_STRING(id)) {
|
||||||
|
@ -7184,7 +6653,7 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
||||||
*objp = obj;
|
*objp = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsDOMGCParticipantSH::NewResolve(wrapper, cx, obj, id, flags, objp,
|
return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
|
||||||
_retval);
|
_retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7214,30 +6683,6 @@ nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper,
|
||||||
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
|
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX nsEventReceiverSH::Finalize: clear event handlers in mListener...
|
|
||||||
|
|
||||||
// DOMGCParticipant helper
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsDOMGCParticipantSH::Finalize(nsIXPConnectWrappedNative *wrapper,
|
|
||||||
JSContext *cx, JSObject *obj)
|
|
||||||
{
|
|
||||||
nsDOMClassInfo::ReleaseWrapper(wrapper);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsDOMGCParticipantSH::Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|
||||||
JSObject *obj, void *arg, PRUint32 *_retval)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> participant(do_QueryWrappedNative(wrapper));
|
|
||||||
|
|
||||||
nsDOMClassInfo::MarkReachablePreservedWrappers(participant, cx, arg);
|
|
||||||
|
|
||||||
*_retval = 1;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Element helper
|
// Element helper
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,8 @@ class nsIDOMWindow;
|
||||||
class nsIDOMNSHTMLOptionCollection;
|
class nsIDOMNSHTMLOptionCollection;
|
||||||
class nsIPluginInstance;
|
class nsIPluginInstance;
|
||||||
class nsIForm;
|
class nsIForm;
|
||||||
class nsIDOMNode;
|
|
||||||
class nsIDOMNodeList;
|
class nsIDOMNodeList;
|
||||||
class nsIDOMDocument;
|
class nsIDOMDocument;
|
||||||
class nsIDOMGCParticipant;
|
|
||||||
class nsIHTMLDocument;
|
class nsIHTMLDocument;
|
||||||
class nsGlobalWindow;
|
class nsGlobalWindow;
|
||||||
|
|
||||||
|
@ -175,87 +173,7 @@ public:
|
||||||
::JS_GetClass(cx, obj) == sXPCNativeWrapperClass;
|
::JS_GetClass(cx, obj) == sXPCNativeWrapperClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static nsresult PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||||
* Note that the XPConnect wrapper should be protected from garbage
|
|
||||||
* collection as long as the GC participant is reachable.
|
|
||||||
*
|
|
||||||
* A preservation with a given key overwrites any previous
|
|
||||||
* preservation with that key.
|
|
||||||
*
|
|
||||||
* No strong references are held as a result of this function call, so
|
|
||||||
* the caller is responsible for calling |ReleaseWrapper| sometime
|
|
||||||
* before |aParticipant|'s destructor runs.
|
|
||||||
*
|
|
||||||
* aRootWhenExternallyReferenced should be true if the preservation is
|
|
||||||
* for an event handler that could be triggered by the participant
|
|
||||||
* being externally referenced by a network load.
|
|
||||||
*/
|
|
||||||
static nsresult PreserveWrapper(void* aKey,
|
|
||||||
nsIXPConnectJSObjectHolder* (*aKeyToWrapperFunc)(void* aKey),
|
|
||||||
nsIDOMGCParticipant *aParticipant,
|
|
||||||
PRBool aRootWhenExternallyReferenced);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Easier way to call the above just for DOM nodes (and better, since
|
|
||||||
* we get the performance benefits of having the same identity function).
|
|
||||||
* The call to |PreserveWrapper| is made with |aKey| == |aWrapper|.
|
|
||||||
*
|
|
||||||
* The caller need not call |ReleaseWrapper| since the node's
|
|
||||||
* wrapper's scriptable helper does so in its finalize callback.
|
|
||||||
*/
|
|
||||||
static nsresult PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper,
|
|
||||||
PRBool aRootWhenExternallyReferenced =
|
|
||||||
PR_FALSE);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Undoes the effects of any prior |PreserveWrapper| calls made with
|
|
||||||
* |aKey|.
|
|
||||||
*/
|
|
||||||
static void ReleaseWrapper(void* aKey);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark all preserved wrappers reachable from |aDOMNode| via DOM APIs.
|
|
||||||
*/
|
|
||||||
static void MarkReachablePreservedWrappers(nsIDOMGCParticipant *aParticipant,
|
|
||||||
JSContext *cx, void *arg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add/remove |aParticipant| from the table of externally referenced
|
|
||||||
* participants. Does not maintain a count, so an object should not
|
|
||||||
* be added when it is already in the table.
|
|
||||||
*
|
|
||||||
* The table of externally referenced participants is a list of
|
|
||||||
* participants that should be marked at GC-time **if they are a
|
|
||||||
* participant in the preserved wrapper table added with
|
|
||||||
* aRootWhenExternallyReferenced**, whether or not they are reachable
|
|
||||||
* from marked participants. This should be used for participants
|
|
||||||
* that hold onto scripts (typically onload or onerror handlers) that
|
|
||||||
* can be triggered at the end of a currently-ongoing operation
|
|
||||||
* (typically a network request) and that could thus expose the
|
|
||||||
* participant to script again in the future even though it is not
|
|
||||||
* otherwise reachable.
|
|
||||||
*
|
|
||||||
* The caller is responsible for ensuring that the GC participant is
|
|
||||||
* alive while it is in this table; the table does not own a reference.
|
|
||||||
*
|
|
||||||
* UnsetExternallyReferenced must be called exactly once for every
|
|
||||||
* successful SetExternallyReferenced call, and in no other cases.
|
|
||||||
*/
|
|
||||||
static nsresult SetExternallyReferenced(nsIDOMGCParticipant *aParticipant);
|
|
||||||
static void UnsetExternallyReferenced(nsIDOMGCParticipant *aParticipant);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classify the wrappers for use by |MarkReachablePreservedWrappers|
|
|
||||||
* during the GC. Returns false to indicate failure (out-of-memory).
|
|
||||||
*/
|
|
||||||
static PRBool BeginGCMark(JSContext *cx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clean up data structures (and strong references) created by
|
|
||||||
* |BeginGCMark|.
|
|
||||||
*/
|
|
||||||
static void EndGCMark();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const nsDOMClassInfoData* mData;
|
const nsDOMClassInfoData* mData;
|
||||||
|
@ -407,39 +325,14 @@ public:
|
||||||
|
|
||||||
typedef nsDOMClassInfo nsDOMGenericSH;
|
typedef nsDOMClassInfo nsDOMGenericSH;
|
||||||
|
|
||||||
// Scriptable helper for implementations of nsIDOMGCParticipant that
|
|
||||||
// need a mark callback.
|
|
||||||
class nsDOMGCParticipantSH : public nsDOMGenericSH
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
nsDOMGCParticipantSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~nsDOMGCParticipantSH()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|
||||||
JSObject *obj);
|
|
||||||
NS_IMETHOD Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|
||||||
JSObject *obj, void *arg, PRUint32 *_retval);
|
|
||||||
|
|
||||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
|
||||||
{
|
|
||||||
return new nsDOMGCParticipantSH(aData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// EventProp scriptable helper, this class should be the base class of
|
// EventProp scriptable helper, this class should be the base class of
|
||||||
// all objects that should support things like
|
// all objects that should support things like
|
||||||
// obj.onclick=function{...}
|
// obj.onclick=function{...}
|
||||||
|
|
||||||
class nsEventReceiverSH : public nsDOMGCParticipantSH
|
class nsEventReceiverSH : public nsDOMGenericSH
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGCParticipantSH(aData)
|
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -642,6 +642,7 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
|
||||||
// nsGlobalWindow::nsISupports
|
// nsGlobalWindow::nsISupports
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
|
||||||
|
|
||||||
// QueryInterface implementation for nsGlobalWindow
|
// QueryInterface implementation for nsGlobalWindow
|
||||||
NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
|
NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
|
||||||
|
@ -654,7 +655,6 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
|
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||||
|
@ -664,12 +664,105 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGlobalWindow)
|
||||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsGlobalWindow)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
|
||||||
NS_IMPL_RELEASE(nsGlobalWindow)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow, nsIScriptGlobalObject)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
|
||||||
|
|
||||||
|
// Strange bug: If you uncomment this line you will find that
|
||||||
|
// the cycle collector crashes when working with multiple open
|
||||||
|
// top-level windows. It is as though the windows somehow
|
||||||
|
// race with one another. How can this be? Curious.
|
||||||
|
//
|
||||||
|
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
|
||||||
|
|
||||||
|
for (PRUint32 i = 0; i < NS_STID_ARRAY_UBOUND; ++i) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContexts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(gGlobalStorageList)
|
||||||
|
|
||||||
|
for (PRUint32 i = 0; i < NS_STID_ARRAY_UBOUND; ++i) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolders[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
|
||||||
|
|
||||||
|
// Traverse any associated preserved wrappers.
|
||||||
|
{
|
||||||
|
nsISupports *preservedWrapper = nsnull;
|
||||||
|
if (tmp->mDoc) {
|
||||||
|
preservedWrapper = tmp->mDoc->GetReference(tmp);
|
||||||
|
if (preservedWrapper)
|
||||||
|
cb.NoteXPCOMChild(preservedWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse our possibly-inner window.
|
||||||
|
if (tmp->IsOuterWindow()
|
||||||
|
&& tmp->GetCurrentInnerWindowInternal()) {
|
||||||
|
cb.NoteXPCOMChild(NS_STATIC_CAST(nsIScriptGlobalObject*,
|
||||||
|
tmp->GetCurrentInnerWindowInternal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: somewhere in these commented lines lies a bug that causes
|
||||||
|
// a segfault. So we have disabled them, even though it seems wrong
|
||||||
|
// to do so. Other matters are more pressing at the moment.
|
||||||
|
|
||||||
|
// Traverse stuff from nsPIDOMWindow
|
||||||
|
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
|
||||||
|
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow, nsIScriptGlobalObject)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
|
||||||
|
|
||||||
|
// See comment about traversing mOpener above.
|
||||||
|
// NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpener)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
|
||||||
|
|
||||||
|
for (PRUint32 i = 0; i < NS_STID_ARRAY_UBOUND; ++i) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContexts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(gGlobalStorageList)
|
||||||
|
|
||||||
|
for (PRUint32 i = 0; i < NS_STID_ARRAY_UBOUND; ++i) {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolders[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDoc)
|
||||||
|
|
||||||
|
// Unlink any associated preserved wrapper.
|
||||||
|
if (tmp->mDoc)
|
||||||
|
tmp->mDoc->RemoveReference(tmp->mDoc.get());
|
||||||
|
|
||||||
|
// Unlink stuff from nsPIDOMWindow
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
@ -5430,37 +5523,6 @@ nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
|
||||||
// nsGlobalWindow::nsIDOMGCParticipant
|
|
||||||
//*****************************************************************************
|
|
||||||
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsGlobalWindow::GetSCCIndex()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AppendToReachableList(nsISupports *aObject,
|
|
||||||
nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMGCParticipant> p = do_QueryInterface(aObject);
|
|
||||||
if (p)
|
|
||||||
aArray.AppendObject(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsGlobalWindow::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
AppendToReachableList(mChromeEventHandler, aArray);
|
|
||||||
AppendToReachableList(mDocument, aArray);
|
|
||||||
// XXXldb Do we want this to go both ways?
|
|
||||||
if (IsOuterWindow()) {
|
|
||||||
AppendToReachableList(mInnerWindow, aArray);
|
|
||||||
} else {
|
|
||||||
AppendToReachableList(mOuterWindow, aArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// nsGlobalWindow::nsPIDOMWindow
|
// nsGlobalWindow::nsPIDOMWindow
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
#include "nsHashtable.h"
|
#include "nsHashtable.h"
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
// Interfaces Needed
|
// Interfaces Needed
|
||||||
#include "nsDOMWindowList.h"
|
#include "nsDOMWindowList.h"
|
||||||
|
@ -91,7 +92,6 @@
|
||||||
#include "nsSize.h"
|
#include "nsSize.h"
|
||||||
#include "mozFlushType.h"
|
#include "mozFlushType.h"
|
||||||
#include "prclist.h"
|
#include "prclist.h"
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
#include "nsIDOMStorage.h"
|
#include "nsIDOMStorage.h"
|
||||||
#include "nsIDOMStorageList.h"
|
#include "nsIDOMStorageList.h"
|
||||||
#include "nsIDOMStorageWindow.h"
|
#include "nsIDOMStorageWindow.h"
|
||||||
|
@ -217,7 +217,6 @@ class nsGlobalWindow : public nsPIDOMWindow,
|
||||||
public nsIDOMJSWindow,
|
public nsIDOMJSWindow,
|
||||||
public nsIScriptObjectPrincipal,
|
public nsIScriptObjectPrincipal,
|
||||||
public nsIDOMEventReceiver,
|
public nsIDOMEventReceiver,
|
||||||
public nsIDOMGCParticipant,
|
|
||||||
public nsIDOM3EventTarget,
|
public nsIDOM3EventTarget,
|
||||||
public nsIDOMNSEventTarget,
|
public nsIDOMNSEventTarget,
|
||||||
public nsIDOMViewCSS,
|
public nsIDOMViewCSS,
|
||||||
|
@ -233,7 +232,7 @@ public:
|
||||||
void ReallyCloseWindow();
|
void ReallyCloseWindow();
|
||||||
|
|
||||||
// nsISupports
|
// nsISupports
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
// nsIScriptGlobalObject
|
// nsIScriptGlobalObject
|
||||||
virtual nsIScriptContext *GetContext();
|
virtual nsIScriptContext *GetContext();
|
||||||
|
@ -288,10 +287,6 @@ public:
|
||||||
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
||||||
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
||||||
|
|
||||||
// nsIDOMGCParticipant
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsPIDOMWindow
|
// nsPIDOMWindow
|
||||||
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
|
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
|
||||||
virtual NS_HIDDEN_(nsresult) Activate();
|
virtual NS_HIDDEN_(nsresult) Activate();
|
||||||
|
@ -407,6 +402,8 @@ public:
|
||||||
|
|
||||||
friend class WindowStateHolder;
|
friend class WindowStateHolder;
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Object Management
|
// Object Management
|
||||||
virtual ~nsGlobalWindow();
|
virtual ~nsGlobalWindow();
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
#include "nsIContent.h"
|
#include "nsIContent.h"
|
||||||
|
|
||||||
// For locale aware string methods
|
// For locale aware string methods
|
||||||
|
@ -3159,14 +3158,6 @@ DOMGCCallback(JSContext *cx, JSGCStatus status)
|
||||||
if (status == JSGC_BEGIN && !NS_IsMainThread())
|
if (status == JSGC_BEGIN && !NS_IsMainThread())
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
// XPCJSRuntime::GCCallback does marking from the JSGC_MARK_END callback.
|
|
||||||
// we need to call EndGCMark *after* marking is finished.
|
|
||||||
// XXX This relies on our callback being registered after
|
|
||||||
// XPCJSRuntime's, although if they were registered the other way
|
|
||||||
// around the ordering there would be correct.
|
|
||||||
if (status == JSGC_MARK_END)
|
|
||||||
nsDOMClassInfo::EndGCMark();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,6 @@
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsDOMClassInfo.h"
|
|
||||||
#include "nsIDOMGCParticipant.h"
|
|
||||||
#include "nsIWeakReference.h"
|
|
||||||
|
|
||||||
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
|
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
|
||||||
|
|
||||||
|
@ -196,101 +193,3 @@ nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
|
||||||
{
|
{
|
||||||
return GetScriptContextFromJSContext(aContext);
|
return GetScriptContextFromJSContext(aContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MARKED_OBJECT_BIT (PRWord(1<<0))
|
|
||||||
|
|
||||||
void
|
|
||||||
nsMarkedJSFunctionHolder_base::Set(nsISupports *aPotentialFunction,
|
|
||||||
nsIDOMGCParticipant *aParticipant)
|
|
||||||
{
|
|
||||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
|
||||||
nsDOMClassInfo::ReleaseWrapper(this);
|
|
||||||
}
|
|
||||||
nsISupports *oldVal = (nsISupports*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
|
||||||
if (!TryMarkedSet(aPotentialFunction, aParticipant)) {
|
|
||||||
NS_ASSERTION((PRWord(aPotentialFunction) & MARKED_OBJECT_BIT) == 0,
|
|
||||||
"low bit set");
|
|
||||||
NS_IF_ADDREF(aPotentialFunction);
|
|
||||||
mObject = aPotentialFunction;
|
|
||||||
}
|
|
||||||
NS_IF_RELEASE(oldVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static nsIXPConnectJSObjectHolder* HolderToWrappedJS(void *aKey)
|
|
||||||
{
|
|
||||||
nsMarkedJSFunctionHolder_base *holder = NS_STATIC_CAST(
|
|
||||||
nsMarkedJSFunctionHolder_base*, aKey);
|
|
||||||
|
|
||||||
NS_ASSERTION(PRWord(holder->mObject) & MARKED_OBJECT_BIT,
|
|
||||||
"yikes, not a marked object");
|
|
||||||
|
|
||||||
nsIWeakReference* weakRef =
|
|
||||||
(nsIWeakReference*)(PRWord(holder->mObject) & ~MARKED_OBJECT_BIT);
|
|
||||||
|
|
||||||
// This entire interface is a hack to avoid reference counting, so
|
|
||||||
// this actually doesn't do any reference counting, and we don't leak
|
|
||||||
// anything. This is needed so we don't add and remove GC roots in
|
|
||||||
// the middle of GC.
|
|
||||||
nsWeakRefToIXPConnectWrappedJS *result;
|
|
||||||
if (NS_FAILED(CallQueryReferent(weakRef, &result)))
|
|
||||||
result = nsnull;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool
|
|
||||||
nsMarkedJSFunctionHolder_base::TryMarkedSet(nsISupports *aPotentialFunction,
|
|
||||||
nsIDOMGCParticipant *aParticipant)
|
|
||||||
{
|
|
||||||
if (!aParticipant)
|
|
||||||
return PR_FALSE;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
|
|
||||||
do_QueryInterface(aPotentialFunction);
|
|
||||||
if (!wrappedJS) // a non-JS implementation
|
|
||||||
return PR_FALSE;
|
|
||||||
|
|
||||||
// XXX We really only need to pass PR_TRUE for
|
|
||||||
// root-if-externally-referenced if this is an onload, onerror,
|
|
||||||
// onreadystatechange, etc., so we could pass the responsibility for
|
|
||||||
// choosing that to the caller.
|
|
||||||
nsresult rv =
|
|
||||||
nsDOMClassInfo::PreserveWrapper(this, HolderToWrappedJS, aParticipant,
|
|
||||||
PR_TRUE);
|
|
||||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
||||||
|
|
||||||
nsIWeakReference* weakRef; // [STRONG]
|
|
||||||
wrappedJS->GetWeakReference(&weakRef);
|
|
||||||
NS_ENSURE_TRUE(weakRef, PR_FALSE);
|
|
||||||
|
|
||||||
NS_ASSERTION((PRWord(weakRef) & MARKED_OBJECT_BIT) == 0, "low bit set");
|
|
||||||
mObject = (nsISupports*)(PRWord(weakRef) | MARKED_OBJECT_BIT);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsISupports>
|
|
||||||
nsMarkedJSFunctionHolder_base::Get(REFNSIID aIID)
|
|
||||||
{
|
|
||||||
nsISupports *result;
|
|
||||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
|
||||||
nsIWeakReference* weakRef =
|
|
||||||
(nsIWeakReference*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
|
||||||
nsresult rv =
|
|
||||||
weakRef->QueryReferent(aIID, NS_REINTERPRET_CAST(void**, &result));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
NS_NOTREACHED("GC preservation didn't work");
|
|
||||||
result = nsnull;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NS_IF_ADDREF(result = mObject);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsMarkedJSFunctionHolder_base::~nsMarkedJSFunctionHolder_base()
|
|
||||||
{
|
|
||||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
|
||||||
nsDOMClassInfo::ReleaseWrapper(this);
|
|
||||||
}
|
|
||||||
nsISupports *obj = (nsISupports*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
|
||||||
NS_IF_RELEASE(obj);
|
|
||||||
}
|
|
||||||
|
|
|
@ -48,13 +48,10 @@
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
|
|
||||||
class nsIDOMEventListener;
|
class nsIDOMEventListener;
|
||||||
class nsIScriptContext;
|
class nsIScriptContext;
|
||||||
class nsIScriptGlobalObject;
|
class nsIScriptGlobalObject;
|
||||||
class nsIDOMGCParticipant;
|
|
||||||
class nsIXPConnectJSObjectHolder;
|
|
||||||
|
|
||||||
class nsJSUtils
|
class nsJSUtils
|
||||||
{
|
{
|
||||||
|
@ -102,48 +99,4 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* nsMarkedJSFunctionHolder<T> is used to store objects of XPCOM
|
|
||||||
* interface T.
|
|
||||||
*
|
|
||||||
* If the object stored is an XPConnect wrapped JS object and the
|
|
||||||
* wrapper can be preserved through nsDOMClassInfo, the holder will hold
|
|
||||||
* a weak reference and preserve the object from garbage collection as
|
|
||||||
* long as the garbage collector can reach |aParticipant|; once both
|
|
||||||
* |aParticipant| and the object are unreachable it will be garbage
|
|
||||||
* collected and the holder will hold null.
|
|
||||||
*
|
|
||||||
* Otherwise, it holds a strong reference.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class nsMarkedJSFunctionHolder_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Set(nsISupports *aPotentialFunction, nsIDOMGCParticipant *aParticipant);
|
|
||||||
already_AddRefed<nsISupports> Get(REFNSIID aIID);
|
|
||||||
|
|
||||||
nsMarkedJSFunctionHolder_base() : mObject(nsnull) {}
|
|
||||||
~nsMarkedJSFunctionHolder_base();
|
|
||||||
|
|
||||||
PRBool TryMarkedSet(nsISupports *aPotentialFunction, nsIDOMGCParticipant *aParticipant);
|
|
||||||
|
|
||||||
nsISupports *mObject;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class nsMarkedJSFunctionHolder : protected nsMarkedJSFunctionHolder_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Set(T *aPotentialFunction, nsIDOMGCParticipant *aParticipant) {
|
|
||||||
nsMarkedJSFunctionHolder_base::Set(aPotentialFunction, aParticipant);
|
|
||||||
}
|
|
||||||
already_AddRefed<T> Get() {
|
|
||||||
return already_AddRefed<T>(NS_STATIC_CAST(T*, nsMarkedJSFunctionHolder_base::Get(NS_GET_TEMPLATE_IID(T)).get()));
|
|
||||||
}
|
|
||||||
// An overloaded version that's more useful for XPCOM getters
|
|
||||||
void Get(T** aResult) {
|
|
||||||
*aResult = Get().get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* nsJSUtils_h__ */
|
#endif /* nsJSUtils_h__ */
|
||||||
|
|
|
@ -52,8 +52,10 @@
|
||||||
#include "nsIDOMWindowInternal.h"
|
#include "nsIDOMWindowInternal.h"
|
||||||
#include "nsFocusController.h"
|
#include "nsFocusController.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsDOMClassInfo.h"
|
|
||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
|
#include "nsIProgrammingLanguage.h"
|
||||||
|
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID);
|
static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID);
|
||||||
|
|
||||||
|
@ -65,10 +67,10 @@ nsWindowRoot::nsWindowRoot(nsIDOMWindow* aWindow)
|
||||||
nsFocusController::Create(getter_AddRefs(mFocusController));
|
nsFocusController::Create(getter_AddRefs(mFocusController));
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMFocusListener> focusListener(do_QueryInterface(mFocusController));
|
nsCOMPtr<nsIDOMFocusListener> focusListener(do_QueryInterface(mFocusController));
|
||||||
++mRefCnt;
|
mRefCnt.incr(NS_STATIC_CAST(nsIDOMEventReceiver*, this));
|
||||||
AddEventListener(NS_LITERAL_STRING("focus"), focusListener, PR_TRUE);
|
AddEventListener(NS_LITERAL_STRING("focus"), focusListener, PR_TRUE);
|
||||||
AddEventListener(NS_LITERAL_STRING("blur"), focusListener, PR_TRUE);
|
AddEventListener(NS_LITERAL_STRING("blur"), focusListener, PR_TRUE);
|
||||||
--mRefCnt;
|
mRefCnt.decr(NS_STATIC_CAST(nsIDOMEventReceiver*, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsWindowRoot::~nsWindowRoot()
|
nsWindowRoot::~nsWindowRoot()
|
||||||
|
@ -78,20 +80,22 @@ nsWindowRoot::~nsWindowRoot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_2_AMBIGUOUS(nsWindowRoot, nsIDOMEventReceiver,
|
||||||
|
mListenerManager, mFocusController)
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsWindowRoot)
|
NS_INTERFACE_MAP_BEGIN(nsWindowRoot)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
|
NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
|
NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WindowRoot) // XXX right name?
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsWindowRoot)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsWindowRoot)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsWindowRoot, nsIDOMEventReceiver)
|
||||||
NS_IMPL_RELEASE(nsWindowRoot)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsWindowRoot, nsIDOMEventReceiver)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
|
nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
|
||||||
|
@ -234,16 +238,6 @@ nsWindowRoot::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIDOMGCParticipant*
|
|
||||||
nsWindowRoot::GetSCCIndex()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsWindowRoot::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWindowRoot::PreHandleChromeEvent(nsEventChainPreVisitor& aVisitor)
|
nsWindowRoot::PreHandleChromeEvent(nsEventChainPreVisitor& aVisitor)
|
||||||
|
|
|
@ -55,6 +55,7 @@ class nsEventChainPostVisitor;
|
||||||
#include "nsPIWindowRoot.h"
|
#include "nsPIWindowRoot.h"
|
||||||
#include "nsIFocusController.h"
|
#include "nsIFocusController.h"
|
||||||
#include "nsIDOMEventTarget.h"
|
#include "nsIDOMEventTarget.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
class nsWindowRoot : public nsIDOMEventReceiver,
|
class nsWindowRoot : public nsIDOMEventReceiver,
|
||||||
public nsIDOM3EventTarget,
|
public nsIDOM3EventTarget,
|
||||||
|
@ -66,7 +67,7 @@ public:
|
||||||
nsWindowRoot(nsIDOMWindow* aWindow);
|
nsWindowRoot(nsIDOMWindow* aWindow);
|
||||||
virtual ~nsWindowRoot();
|
virtual ~nsWindowRoot();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_NSIDOMEVENTTARGET
|
NS_DECL_NSIDOMEVENTTARGET
|
||||||
NS_DECL_NSIDOM3EVENTTARGET
|
NS_DECL_NSIDOM3EVENTTARGET
|
||||||
NS_DECL_NSIDOMNSEVENTTARGET
|
NS_DECL_NSIDOMNSEVENTTARGET
|
||||||
|
@ -81,13 +82,11 @@ public:
|
||||||
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
||||||
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
||||||
|
|
||||||
// nsIDOMGCParticipant
|
|
||||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
|
||||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
|
||||||
|
|
||||||
// nsPIWindowRoot
|
// nsPIWindowRoot
|
||||||
NS_IMETHOD GetFocusController(nsIFocusController** aResult);
|
NS_IMETHOD GetFocusController(nsIFocusController** aResult);
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsWindowRoot)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Members
|
// Members
|
||||||
nsIDOMWindow* mWindow; // [Weak]. The window will hold on to us and let go when it dies.
|
nsIDOMWindow* mWindow; // [Weak]. The window will hold on to us and let go when it dies.
|
||||||
|
|
|
@ -56,16 +56,10 @@
|
||||||
|
|
||||||
#include "nspr.h" // PR_fprintf
|
#include "nspr.h" // PR_fprintf
|
||||||
|
|
||||||
PRInt32 nsIJSEventListener::sNumJSEventListeners = 0;
|
|
||||||
|
|
||||||
class EventListenerCounter
|
class EventListenerCounter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~EventListenerCounter() {
|
~EventListenerCounter() {
|
||||||
if (nsIJSEventListener::sNumJSEventListeners) {
|
|
||||||
PR_fprintf(PR_STDERR,"WARNING: LEAKED %d nsIJSEventListeners\n",
|
|
||||||
nsIJSEventListener::sNumJSEventListeners);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,15 +87,17 @@ nsJSEventListener::~nsJSEventListener()
|
||||||
mContext->DropScriptObject(mScopeObject);
|
mContext->DropScriptObject(mScopeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_1_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener, mTarget)
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsJSEventListener)
|
NS_INTERFACE_MAP_BEGIN(nsJSEventListener)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
|
NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsJSEventListener)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_ADDREF(nsJSEventListener)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
|
||||||
NS_IMPL_RELEASE(nsJSEventListener)
|
|
||||||
|
|
||||||
//static nsString onPrefix = "on";
|
//static nsString onPrefix = "on";
|
||||||
|
|
||||||
|
@ -276,4 +272,3 @@ NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
// nsJSEventListener interface
|
// nsJSEventListener interface
|
||||||
// misnamed - JS no longer has exclusive rights over this interface!
|
// misnamed - JS no longer has exclusive rights over this interface!
|
||||||
|
@ -56,7 +57,7 @@ public:
|
||||||
nsISupports* aObject);
|
nsISupports* aObject);
|
||||||
virtual ~nsJSEventListener();
|
virtual ~nsJSEventListener();
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
||||||
// nsIDOMEventListener interface
|
// nsIDOMEventListener interface
|
||||||
NS_DECL_NSIDOMEVENTLISTENER
|
NS_DECL_NSIDOMEVENTLISTENER
|
||||||
|
@ -64,6 +65,7 @@ public:
|
||||||
// nsIJSEventListener interface
|
// nsIJSEventListener interface
|
||||||
virtual void SetEventName(nsIAtom* aName);
|
virtual void SetEventName(nsIAtom* aName);
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
|
||||||
protected:
|
protected:
|
||||||
nsCOMPtr<nsIAtom> mEventName;
|
nsCOMPtr<nsIAtom> mEventName;
|
||||||
|
|
||||||
|
|
|
@ -1972,6 +1972,13 @@ JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
|
||||||
return oldcb;
|
return oldcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
JS_SetGCThingCallback(JSContext *cx, JSGCThingCallback cb, void *closure)
|
||||||
|
{
|
||||||
|
cx->runtime->gcThingCallback = cb;
|
||||||
|
cx->runtime->gcThingCallbackClosure = closure;
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
|
JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
|
||||||
{
|
{
|
||||||
|
|
|
@ -869,6 +869,9 @@ JS_SetGCCallback(JSContext *cx, JSGCCallback cb);
|
||||||
extern JS_PUBLIC_API(JSGCCallback)
|
extern JS_PUBLIC_API(JSGCCallback)
|
||||||
JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
|
JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(void)
|
||||||
|
JS_SetGCThingCallback(JSContext *cx, JSGCThingCallback cb, void *closure);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_IsAboutToBeFinalized(JSContext *cx, void *thing);
|
JS_IsAboutToBeFinalized(JSContext *cx, void *thing);
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,8 @@ struct JSRuntime {
|
||||||
uint16 gcPadding;
|
uint16 gcPadding;
|
||||||
|
|
||||||
JSGCCallback gcCallback;
|
JSGCCallback gcCallback;
|
||||||
|
JSGCThingCallback gcThingCallback;
|
||||||
|
void *gcThingCallbackClosure;
|
||||||
uint32 gcMallocBytes;
|
uint32 gcMallocBytes;
|
||||||
JSGCArena *gcUnscannedArenaStackTop;
|
JSGCArena *gcUnscannedArenaStackTop;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -2079,9 +2079,13 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp,
|
||||||
if (!JSVAL_IS_GCTHING(v) || v == JSVAL_NULL)
|
if (!JSVAL_IS_GCTHING(v) || v == JSVAL_NULL)
|
||||||
continue;
|
continue;
|
||||||
next_thing = JSVAL_TO_GCTHING(v);
|
next_thing = JSVAL_TO_GCTHING(v);
|
||||||
|
next_flagp = js_GetGCThingFlags(next_thing);
|
||||||
|
if (rt->gcThingCallback) {
|
||||||
|
rt->gcThingCallback(next_thing, *next_flagp,
|
||||||
|
rt->gcThingCallbackClosure);
|
||||||
|
}
|
||||||
if (next_thing == thing)
|
if (next_thing == thing)
|
||||||
continue;
|
continue;
|
||||||
next_flagp = js_GetGCThingFlags(next_thing);
|
|
||||||
if (*next_flagp & GCF_MARK)
|
if (*next_flagp & GCF_MARK)
|
||||||
continue;
|
continue;
|
||||||
JS_ASSERT(*next_flagp != GCF_FINAL);
|
JS_ASSERT(*next_flagp != GCF_FINAL);
|
||||||
|
@ -2134,6 +2138,10 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp,
|
||||||
break;
|
break;
|
||||||
thing = JSSTRDEP_BASE(str);
|
thing = JSSTRDEP_BASE(str);
|
||||||
flagp = js_GetGCThingFlags(thing);
|
flagp = js_GetGCThingFlags(thing);
|
||||||
|
if (rt->gcThingCallback) {
|
||||||
|
rt->gcThingCallback(thing, *flagp,
|
||||||
|
rt->gcThingCallbackClosure);
|
||||||
|
}
|
||||||
if (*flagp & GCF_MARK)
|
if (*flagp & GCF_MARK)
|
||||||
break;
|
break;
|
||||||
#ifdef GC_MARK_DEBUG
|
#ifdef GC_MARK_DEBUG
|
||||||
|
@ -2444,6 +2452,12 @@ js_MarkGCThing(JSContext *cx, void *thing)
|
||||||
|
|
||||||
flagp = js_GetGCThingFlags(thing);
|
flagp = js_GetGCThingFlags(thing);
|
||||||
JS_ASSERT(*flagp != GCF_FINAL);
|
JS_ASSERT(*flagp != GCF_FINAL);
|
||||||
|
|
||||||
|
if (cx->runtime->gcThingCallback) {
|
||||||
|
cx->runtime->gcThingCallback(thing, *flagp,
|
||||||
|
cx->runtime->gcThingCallbackClosure);
|
||||||
|
}
|
||||||
|
|
||||||
if (*flagp & GCF_MARK)
|
if (*flagp & GCF_MARK)
|
||||||
return;
|
return;
|
||||||
*flagp |= GCF_MARK;
|
*flagp |= GCF_MARK;
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#ifndef jslock_h__
|
#ifndef jslock_h__
|
||||||
#define jslock_h__
|
#define jslock_h__
|
||||||
|
|
||||||
|
JS_BEGIN_EXTERN_C
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
|
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
|
@ -260,4 +262,6 @@ extern JS_INLINE void js_Unlock(JSThinLock *tl, jsword me);
|
||||||
#define JS_LOCK(P,CX) JS_LOCK0(P, CX_THINLOCK_ID(CX))
|
#define JS_LOCK(P,CX) JS_LOCK0(P, CX_THINLOCK_ID(CX))
|
||||||
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P, CX_THINLOCK_ID(CX))
|
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P, CX_THINLOCK_ID(CX))
|
||||||
|
|
||||||
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jslock_h___ */
|
#endif /* jslock_h___ */
|
||||||
|
|
|
@ -569,6 +569,9 @@ typedef enum JSGCStatus {
|
||||||
typedef JSBool
|
typedef JSBool
|
||||||
(* JS_DLL_CALLBACK JSGCCallback)(JSContext *cx, JSGCStatus status);
|
(* JS_DLL_CALLBACK JSGCCallback)(JSContext *cx, JSGCStatus status);
|
||||||
|
|
||||||
|
typedef void
|
||||||
|
(* JS_DLL_CALLBACK JSGCThingCallback)(void *thing, uint8 flags, void *closure);
|
||||||
|
|
||||||
typedef JSBool
|
typedef JSBool
|
||||||
(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);
|
(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
#include "nsIInterfaceInfoManager.idl"
|
#include "nsIInterfaceInfoManager.idl"
|
||||||
#include "nsIExceptionService.idl"
|
#include "nsIExceptionService.idl"
|
||||||
#include "nsIVariant.idl"
|
#include "nsIVariant.idl"
|
||||||
#include "nsIWeakReference.idl"
|
|
||||||
|
|
||||||
%{ C++
|
%{ C++
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
|
@ -149,6 +148,10 @@ interface nsIInterfaceInfo;
|
||||||
interface nsIXPCSecurityManager;
|
interface nsIXPCSecurityManager;
|
||||||
interface nsIPrincipal;
|
interface nsIPrincipal;
|
||||||
|
|
||||||
|
%{C++
|
||||||
|
struct nsCycleCollectionTraversalCallback;
|
||||||
|
%}
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
[uuid(8916a320-d118-11d3-8f3a-0010a4e73d9a)]
|
[uuid(8916a320-d118-11d3-8f3a-0010a4e73d9a)]
|
||||||
interface nsIXPConnectJSObjectHolder : nsISupports
|
interface nsIXPConnectJSObjectHolder : nsISupports
|
||||||
|
@ -230,7 +233,7 @@ do_QueryWrappedNative(nsIXPConnectWrappedNative *aWrappedNative,
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
[uuid(a052e197-7ba4-494e-b735-8786ac091164)]
|
[uuid(BED52030-BCA6-11d2-BA79-00805F8A5DD7)]
|
||||||
interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
||||||
{
|
{
|
||||||
/* attribute 'JSObject' inherited from nsIXPConnectJSObjectHolder */
|
/* attribute 'JSObject' inherited from nsIXPConnectJSObjectHolder */
|
||||||
|
@ -242,26 +245,6 @@ interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
||||||
void aggregatedQueryInterface(in nsIIDRef uuid,
|
void aggregatedQueryInterface(in nsIIDRef uuid,
|
||||||
[iid_is(uuid),retval] out nsQIResult result);
|
[iid_is(uuid),retval] out nsQIResult result);
|
||||||
|
|
||||||
/* This method has the same signature and the same semantics as the
|
|
||||||
* one method on nsISupportsWeakReference. However, it exists here
|
|
||||||
* so that callers who need to manage JS garbage collection for
|
|
||||||
* wrapped objects themselves can get a weak reference to the
|
|
||||||
* wrapped JS object: in other words, it's for callers who know
|
|
||||||
* that they're dealing with a wrapper, and want a weak reference to
|
|
||||||
* the wrapper rather than the wrapped object.
|
|
||||||
*/
|
|
||||||
nsIWeakReference GetWeakReference();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface is a complete hack. It is used by the DOM code to
|
|
||||||
* call QueryReferent on a weak reference to a wrapped JS object without
|
|
||||||
* causing reference counting, which would add and remove GC roots
|
|
||||||
* (which can't be done in the middle of GC).
|
|
||||||
*/
|
|
||||||
[uuid(3f32871c-d014-4f91-b358-3ece74cbebaa)]
|
|
||||||
interface nsWeakRefToIXPConnectWrappedJS : nsIXPConnectWrappedJS
|
|
||||||
{
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
|
|
||||||
#include "xpcprivate.h"
|
#include "xpcprivate.h"
|
||||||
#include "XPCNativeWrapper.h"
|
#include "XPCNativeWrapper.h"
|
||||||
|
#include "nsBaseHashtable.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
#include "jsobj.h"
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference)
|
NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference)
|
||||||
|
|
||||||
|
@ -66,7 +69,8 @@ nsXPConnect::nsXPConnect()
|
||||||
mContextStack(nsnull),
|
mContextStack(nsnull),
|
||||||
mDefaultSecurityManager(nsnull),
|
mDefaultSecurityManager(nsnull),
|
||||||
mDefaultSecurityManagerFlags(0),
|
mDefaultSecurityManagerFlags(0),
|
||||||
mShuttingDown(JS_FALSE)
|
mShuttingDown(JS_FALSE),
|
||||||
|
mObjRefcounts(nsnull)
|
||||||
{
|
{
|
||||||
// Ignore the result. If the runtime service is not ready to rumble
|
// Ignore the result. If the runtime service is not ready to rumble
|
||||||
// then we'll set this up later as needed.
|
// then we'll set this up later as needed.
|
||||||
|
@ -74,6 +78,8 @@ nsXPConnect::nsXPConnect()
|
||||||
|
|
||||||
CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
|
CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
|
||||||
|
|
||||||
|
nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
|
||||||
|
|
||||||
#ifdef XPC_TOOLS_SUPPORT
|
#ifdef XPC_TOOLS_SUPPORT
|
||||||
{
|
{
|
||||||
char* filename = PR_GetEnv("MOZILLA_JS_PROFILER_OUTPUT");
|
char* filename = PR_GetEnv("MOZILLA_JS_PROFILER_OUTPUT");
|
||||||
|
@ -101,6 +107,37 @@ nsXPConnect::nsXPConnect()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef nsBaseHashtable<nsClearingVoidPtrHashKey, PRUint32, PRUint32> PointerSet;
|
||||||
|
|
||||||
|
struct JSObjectRefcounts
|
||||||
|
{
|
||||||
|
PointerSet mRefCounts;
|
||||||
|
JSObjectRefcounts()
|
||||||
|
{
|
||||||
|
mRefCounts.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
mRefCounts.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ref(void *obj, uint8 flags)
|
||||||
|
{
|
||||||
|
PRUint32 refs;
|
||||||
|
if (mRefCounts.Get(obj, &refs))
|
||||||
|
refs++;
|
||||||
|
else
|
||||||
|
refs = 1;
|
||||||
|
mRefCounts.Put(obj, refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Get(void *obj, PRUint32 &refcount)
|
||||||
|
{
|
||||||
|
mRefCounts.Get(obj, &refcount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
nsXPConnect::~nsXPConnect()
|
nsXPConnect::~nsXPConnect()
|
||||||
{
|
{
|
||||||
// XXX It would be nice if we could get away with doing a GC here and also
|
// XXX It would be nice if we could get away with doing a GC here and also
|
||||||
|
@ -108,6 +145,13 @@ nsXPConnect::~nsXPConnect()
|
||||||
// noted all over the place, this makes bad things happen since shutdown is
|
// noted all over the place, this makes bad things happen since shutdown is
|
||||||
// an unstable time for so many modules who have not planned well for it.
|
// an unstable time for so many modules who have not planned well for it.
|
||||||
|
|
||||||
|
nsCycleCollector_forgetRuntime(nsIProgrammingLanguage::JAVASCRIPT);
|
||||||
|
if (mObjRefcounts)
|
||||||
|
{
|
||||||
|
delete mObjRefcounts;
|
||||||
|
mObjRefcounts = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
mShuttingDown = JS_TRUE;
|
mShuttingDown = JS_TRUE;
|
||||||
{ // scoped callcontext
|
{ // scoped callcontext
|
||||||
XPCCallContext ccx(NATIVE_CALLER);
|
XPCCallContext ccx(NATIVE_CALLER);
|
||||||
|
@ -386,6 +430,122 @@ nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
|
||||||
return FindInfo(NameTester, name, mInterfaceInfoManager, info);
|
return FindInfo(NameTester, name, mInterfaceInfoManager, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XPCMarkNotification(void *thing, uint8 flags, void *closure)
|
||||||
|
{
|
||||||
|
JSObjectRefcounts* jsr = NS_STATIC_CAST(JSObjectRefcounts*, closure);
|
||||||
|
jsr->Ref(thing, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::BeginCycleCollection()
|
||||||
|
{
|
||||||
|
if (!mObjRefcounts)
|
||||||
|
mObjRefcounts = new JSObjectRefcounts;
|
||||||
|
|
||||||
|
mObjRefcounts->Clear();
|
||||||
|
XPCCallContext cx(NATIVE_CALLER);
|
||||||
|
JS_SetGCThingCallback(cx, XPCMarkNotification, mObjRefcounts);
|
||||||
|
JS_GC(cx);
|
||||||
|
JS_SetGCThingCallback(cx, nsnull, nsnull);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::FinishCycleCollection()
|
||||||
|
{
|
||||||
|
if (mObjRefcounts)
|
||||||
|
mObjRefcounts->Clear();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::Root(const nsDeque &nodes)
|
||||||
|
{
|
||||||
|
XPCCallContext cx(NATIVE_CALLER);
|
||||||
|
for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
|
||||||
|
{
|
||||||
|
void *p = nodes.ObjectAt(i);
|
||||||
|
if (!p)
|
||||||
|
continue;
|
||||||
|
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
|
||||||
|
if (!JS_LockGCThing(cx, obj))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::Unlink(const nsDeque &nodes)
|
||||||
|
{
|
||||||
|
XPCCallContext cx(NATIVE_CALLER);
|
||||||
|
|
||||||
|
for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
|
||||||
|
{
|
||||||
|
void *p = nodes.ObjectAt(i);
|
||||||
|
if (!p)
|
||||||
|
continue;
|
||||||
|
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
|
||||||
|
JS_ClearScope(cx, obj);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::Unroot(const nsDeque &nodes)
|
||||||
|
{
|
||||||
|
XPCCallContext cx(NATIVE_CALLER);
|
||||||
|
for (PRInt32 i = 0; i < nodes.GetSize(); ++i)
|
||||||
|
{
|
||||||
|
void *p = nodes.ObjectAt(i);
|
||||||
|
if (!p)
|
||||||
|
continue;
|
||||||
|
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
|
||||||
|
if (!JS_UnlockGCThing(cx, obj))
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
|
||||||
|
{
|
||||||
|
XPCCallContext cx(NATIVE_CALLER);
|
||||||
|
|
||||||
|
PRUint32 refcount = 0;
|
||||||
|
mObjRefcounts->Get(p, refcount);
|
||||||
|
cb.DescribeNode(refcount, sizeof(JSObject), "JS Object");
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
|
||||||
|
|
||||||
|
if (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE
|
||||||
|
&& OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)
|
||||||
|
{
|
||||||
|
void *v = JS_GetPrivate(cx, obj);
|
||||||
|
if (v)
|
||||||
|
cb.NoteXPCOMChild(NS_STATIC_CAST(nsISupports*, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = JSSLOT_START(OBJ_GET_CLASS(cx, obj));
|
||||||
|
i < JS_MIN(obj->slots[-1], JS_MIN(obj->map->freeslot, obj->map->nslots)); ++i)
|
||||||
|
{
|
||||||
|
jsval val = OBJ_GET_SLOT(cx, obj, i);
|
||||||
|
if (!JSVAL_IS_NULL(val)
|
||||||
|
&& JSVAL_IS_OBJECT(val))
|
||||||
|
{
|
||||||
|
JSObject *child = JSVAL_TO_OBJECT(val);
|
||||||
|
if (child)
|
||||||
|
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
// nsIXPConnect interface methods...
|
// nsIXPConnect interface methods...
|
||||||
|
|
|
@ -53,6 +53,8 @@
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "nsXPCOM.h"
|
#include "nsXPCOM.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsCycleCollector.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsIClassInfoImpl.h"
|
#include "nsIClassInfoImpl.h"
|
||||||
|
@ -420,9 +422,11 @@ private:
|
||||||
|
|
||||||
const PRBool OBJ_IS_GLOBAL = PR_TRUE;
|
const PRBool OBJ_IS_GLOBAL = PR_TRUE;
|
||||||
const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
|
const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
|
||||||
|
struct JSObjectRefcounts;
|
||||||
|
|
||||||
class nsXPConnect : public nsIXPConnect,
|
class nsXPConnect : public nsIXPConnect,
|
||||||
public nsSupportsWeakReference
|
public nsSupportsWeakReference,
|
||||||
|
public nsCycleCollectionLanguageRuntime
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// all the interface method declarations...
|
// all the interface method declarations...
|
||||||
|
@ -470,6 +474,14 @@ public:
|
||||||
nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
|
nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
|
||||||
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
|
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
|
||||||
|
|
||||||
|
// from nsCycleCollectionLanguageRuntime
|
||||||
|
nsresult BeginCycleCollection();
|
||||||
|
nsresult Root(const nsDeque &nodes);
|
||||||
|
nsresult Unlink(const nsDeque &nodes);
|
||||||
|
nsresult Unroot(const nsDeque &nodes);
|
||||||
|
nsresult Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
|
||||||
|
nsresult FinishCycleCollection();
|
||||||
|
|
||||||
#ifdef XPC_IDISPATCH_SUPPORT
|
#ifdef XPC_IDISPATCH_SUPPORT
|
||||||
public:
|
public:
|
||||||
static PRBool IsIDispatchEnabled();
|
static PRBool IsIDispatchEnabled();
|
||||||
|
@ -494,6 +506,7 @@ private:
|
||||||
nsIXPCSecurityManager* mDefaultSecurityManager;
|
nsIXPCSecurityManager* mDefaultSecurityManager;
|
||||||
PRUint16 mDefaultSecurityManagerFlags;
|
PRUint16 mDefaultSecurityManagerFlags;
|
||||||
JSBool mShuttingDown;
|
JSBool mShuttingDown;
|
||||||
|
JSObjectRefcounts* mObjRefcounts;
|
||||||
|
|
||||||
#ifdef XPC_TOOLS_SUPPORT
|
#ifdef XPC_TOOLS_SUPPORT
|
||||||
nsCOMPtr<nsIXPCToolsProfiler> mProfiler;
|
nsCOMPtr<nsIXPCToolsProfiler> mProfiler;
|
||||||
|
@ -1833,9 +1846,10 @@ private:
|
||||||
class XPCWrappedNative : public nsIXPConnectWrappedNative
|
class XPCWrappedNative : public nsIXPConnectWrappedNative
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
|
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
|
||||||
NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
|
NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
|
||||||
|
|
||||||
#ifndef XPCONNECT_STANDALONE
|
#ifndef XPCONNECT_STANDALONE
|
||||||
virtual nsIPrincipal* GetObjectPrincipal() const;
|
virtual nsIPrincipal* GetObjectPrincipal() const;
|
||||||
|
@ -2227,7 +2241,7 @@ private:
|
||||||
// interface on the single underlying (possibly aggregate) JSObject.
|
// interface on the single underlying (possibly aggregate) JSObject.
|
||||||
|
|
||||||
class nsXPCWrappedJS : protected nsAutoXPTCStub,
|
class nsXPCWrappedJS : protected nsAutoXPTCStub,
|
||||||
public nsWeakRefToIXPConnectWrappedJS,
|
public nsIXPConnectWrappedJS,
|
||||||
public nsSupportsWeakReference,
|
public nsSupportsWeakReference,
|
||||||
public nsIPropertyBag
|
public nsIPropertyBag
|
||||||
{
|
{
|
||||||
|
@ -2235,8 +2249,9 @@ public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
|
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
|
||||||
NS_DECL_NSIXPCONNECTWRAPPEDJS
|
NS_DECL_NSIXPCONNECTWRAPPEDJS
|
||||||
//NS_DECL_NSISUPPORTSWEAKREFERENCE // methods also on nsIXPConnectWrappedJS
|
NS_DECL_NSISUPPORTSWEAKREFERENCE
|
||||||
NS_DECL_NSIPROPERTYBAG
|
NS_DECL_NSIPROPERTYBAG
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(nsXPCWrappedJS)
|
||||||
|
|
||||||
NS_IMETHOD CallMethod(PRUint16 methodIndex,
|
NS_IMETHOD CallMethod(PRUint16 methodIndex,
|
||||||
const XPTMethodDescriptor *info,
|
const XPTMethodDescriptor *info,
|
||||||
|
|
|
@ -45,6 +45,56 @@
|
||||||
|
|
||||||
// NOTE: much of the fancy footwork is done in xpcstubs.cpp
|
// NOTE: much of the fancy footwork is done in xpcstubs.cpp
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXPCWrappedJS)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
|
||||||
|
(nsISupports *s, nsCycleCollectionTraversalCallback &cb)
|
||||||
|
{
|
||||||
|
// REVIEW ME PLEASE: this is a very odd area and it's easy to get
|
||||||
|
// it wrong. I'm not sure I got it right.
|
||||||
|
//
|
||||||
|
// We *might* have a stub that's not actually connected to an
|
||||||
|
// nsXPCWrappedJS, so we begin by QI'ing over to a "real"
|
||||||
|
// nsIXPConnectWrappedJS. Since that's a mostly-empty class, we
|
||||||
|
// then downcast from there to the "true" nsXPCWrappedJS.
|
||||||
|
//
|
||||||
|
// Is this right? It's hard to know. It seems to work, but who
|
||||||
|
// knows for how long.
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIXPConnectWrappedJS> owner = do_QueryInterface(s, &rv);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
nsIXPConnectWrappedJS *base = owner.get();
|
||||||
|
nsXPCWrappedJS *tmp = NS_STATIC_CAST(nsXPCWrappedJS*, base);
|
||||||
|
|
||||||
|
// REVIEW ME PLEASE:
|
||||||
|
//
|
||||||
|
// I am not sure when this represents the true refcount.
|
||||||
|
|
||||||
|
cb.DescribeNode(tmp->mRefCnt.get(), sizeof(nsXPCWrappedJS),
|
||||||
|
"nsXPCWrappedJS");
|
||||||
|
|
||||||
|
if (tmp->IsValid())
|
||||||
|
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
|
||||||
|
tmp->GetJSObject());
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Unlink(nsISupports *s)
|
||||||
|
{
|
||||||
|
// NB: We might unlink our outgoing references in the future; for
|
||||||
|
// now we do nothing. This is a harmless conservative behavior; it
|
||||||
|
// just means that we rely on the cycle being broken by some of
|
||||||
|
// the external XPCOM objects' unlink() methods, not our
|
||||||
|
// own. Typically *any* unlinking will break the cycle.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
|
nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +129,11 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( aIID.Equals(NS_GET_IID(nsCycleCollectionParticipant)) ) {
|
||||||
|
*aInstancePtr = & NS_CYCLE_COLLECTION_NAME(nsXPCWrappedJS);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Always check for this first so that our 'outer' can get this interface
|
// Always check for this first so that our 'outer' can get this interface
|
||||||
// from us without recurring into a call to the outer's QI!
|
// from us without recurring into a call to the outer's QI!
|
||||||
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
|
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
|
||||||
|
@ -88,13 +143,6 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This interface is a hack that says "don't AddRef me".
|
|
||||||
if(aIID.Equals(NS_GET_IID(nsWeakRefToIXPConnectWrappedJS)))
|
|
||||||
{
|
|
||||||
*aInstancePtr = NS_STATIC_CAST(nsWeakRefToIXPConnectWrappedJS*, this);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsISupports* outer = GetAggregatedNativeObject();
|
nsISupports* outer = GetAggregatedNativeObject();
|
||||||
if(outer)
|
if(outer)
|
||||||
return outer->QueryInterface(aIID, aInstancePtr);
|
return outer->QueryInterface(aIID, aInstancePtr);
|
||||||
|
@ -196,7 +244,10 @@ do_decrement:
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
|
nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||||
{
|
{
|
||||||
return mRoot->nsSupportsWeakReference::GetWeakReference(aInstancePtr);
|
if(mRoot != this)
|
||||||
|
return mRoot->GetWeakReference(aInstancePtr);
|
||||||
|
|
||||||
|
return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
@ -47,6 +47,52 @@
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(nsISupports *s,
|
||||||
|
nsCycleCollectionTraversalCallback &cb)
|
||||||
|
{
|
||||||
|
XPCWrappedNative *tmp = NS_STATIC_CAST(XPCWrappedNative*, s);
|
||||||
|
cb.DescribeNode(tmp->mRefCnt.get(), sizeof(XPCWrappedNative), "XPCWrappedNative");
|
||||||
|
|
||||||
|
if (tmp->mRefCnt.get() > 1) {
|
||||||
|
|
||||||
|
// If our refcount is > 1, our reference to the flat JS object is
|
||||||
|
// considered "strong", and we're going to traverse it.
|
||||||
|
//
|
||||||
|
// If our refcount is <= 1, our reference to the flat JS object is
|
||||||
|
// considered "weak", and we're *not* going to traverse it.
|
||||||
|
//
|
||||||
|
// This reasoning is in line with the slightly confusing lifecycle rules
|
||||||
|
// for XPCWrappedNatives, described in a larger comment below and also
|
||||||
|
// on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping
|
||||||
|
|
||||||
|
JSObject *obj = nsnull;
|
||||||
|
nsresult rv = tmp->GetJSObject(&obj);
|
||||||
|
if (NS_SUCCEEDED(rv) && obj) {
|
||||||
|
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp->GetIdentityObject()) {
|
||||||
|
cb.NoteXPCOMChild(tmp->GetIdentityObject());
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Unlink(nsISupports *s)
|
||||||
|
{
|
||||||
|
// NB: We might unlink our outgoing references in the future; for
|
||||||
|
// now we do nothing. This is a harmless conservative behavior; it
|
||||||
|
// just means that we rely on the cycle being broken by some of
|
||||||
|
// the external XPCOM objects' unlink() methods, not our
|
||||||
|
// own. Typically *any* unlinking will break the cycle.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef XPC_CHECK_CLASSINFO_CLAIMS
|
#ifdef XPC_CHECK_CLASSINFO_CLAIMS
|
||||||
static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper);
|
static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper);
|
||||||
#else
|
#else
|
||||||
|
@ -828,6 +874,7 @@ NS_INTERFACE_MAP_BEGIN(XPCWrappedNative)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIXPConnectWrappedNative)
|
NS_INTERFACE_MAP_ENTRY(nsIXPConnectWrappedNative)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIXPConnectJSObjectHolder)
|
NS_INTERFACE_MAP_ENTRY(nsIXPConnectJSObjectHolder)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPConnectWrappedNative)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPConnectWrappedNative)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(XPCWrappedNative)
|
||||||
NS_INTERFACE_MAP_END_THREADSAFE
|
NS_INTERFACE_MAP_END_THREADSAFE
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ADDREF(XPCWrappedNative)
|
NS_IMPL_THREADSAFE_ADDREF(XPCWrappedNative)
|
||||||
|
|
|
@ -64,6 +64,8 @@ CPPSRCS = \
|
||||||
nsInterfaceRequestorAgg.cpp \
|
nsInterfaceRequestorAgg.cpp \
|
||||||
nsUUIDGenerator.cpp \
|
nsUUIDGenerator.cpp \
|
||||||
nsSystemInfo.cpp \
|
nsSystemInfo.cpp \
|
||||||
|
nsCycleCollector.cpp \
|
||||||
|
nsCycleCollectionParticipant.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ifdef GC_LEAK_DETECTOR
|
ifdef GC_LEAK_DETECTOR
|
||||||
|
@ -115,6 +117,8 @@ SDK_HEADERS = \
|
||||||
nsError.h \
|
nsError.h \
|
||||||
nsISupportsBase.h \
|
nsISupportsBase.h \
|
||||||
nscore.h \
|
nscore.h \
|
||||||
|
nsCycleCollector.h \
|
||||||
|
nsCycleCollectionParticipant.h
|
||||||
|
|
||||||
XPIDLSRCS = \
|
XPIDLSRCS = \
|
||||||
nsIConsoleListener.idl \
|
nsIConsoleListener.idl \
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "xpcom/nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN(nsCycleCollectionParticipant)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsCycleCollectionParticipant)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(nsrefcnt) nsCycleCollectionParticipant::AddRef(void)
|
||||||
|
{
|
||||||
|
// Do nothing, it's a singleton.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(nsrefcnt) nsCycleCollectionParticipant::Release(void)
|
||||||
|
{
|
||||||
|
// Do nothing, it's a singleton.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsCycleCollectionParticipant::Unlink(nsISupports *n)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCycleCollectionParticipant::Traverse(nsISupports *n,
|
||||||
|
nsCycleCollectionTraversalCallback &cb)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
|
@ -0,0 +1,223 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef nsCycleCollectionParticipant_h__
|
||||||
|
#define nsCycleCollectionParticipant_h__
|
||||||
|
|
||||||
|
#include "nsISupports.h"
|
||||||
|
|
||||||
|
#define NS_CYCLECOLLECTIONPARTICIPANT_IID \
|
||||||
|
{ /* 407bbd61-13b2-4f85-bdc6-23a59d881f80 */ \
|
||||||
|
0x407bbd61, \
|
||||||
|
0x13b2, \
|
||||||
|
0x4f85, \
|
||||||
|
{ 0xbd, 0xc6, 0x23, 0xa5, 0x9d, 0x88, 0x1f, 0x80 } \
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef IMETHOD_VISIBILITY
|
||||||
|
#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT
|
||||||
|
|
||||||
|
struct nsCycleCollectionTraversalCallback
|
||||||
|
{
|
||||||
|
// You must call DescribeNode() with an accurate refcount,
|
||||||
|
// otherwise cycle collection will fail, and probably crash.
|
||||||
|
// Providing an accurate objsz or objname is optional.
|
||||||
|
virtual void DescribeNode(size_t refcount,
|
||||||
|
size_t objsz,
|
||||||
|
const char *objname) = 0;
|
||||||
|
virtual void NoteScriptChild(PRUint32 langID, void *child) = 0;
|
||||||
|
virtual void NoteXPCOMChild(nsISupports *child) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NS_COM nsCycleCollectionParticipant
|
||||||
|
: public nsISupports
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CYCLECOLLECTIONPARTICIPANT_IID)
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
NS_IMETHOD Unlink(nsISupports *p);
|
||||||
|
NS_IMETHOD Traverse(nsISupports *p,
|
||||||
|
nsCycleCollectionTraversalCallback &cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
|
||||||
|
NS_CYCLECOLLECTIONPARTICIPANT_IID)
|
||||||
|
|
||||||
|
#undef IMETHOD_VISIBILITY
|
||||||
|
#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers for implementing a QI to nsCycleCollectionParticipant
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define NS_CYCLE_COLLECTION_INNERCLASS \
|
||||||
|
cycleCollection
|
||||||
|
|
||||||
|
#define NS_CYCLE_COLLECTION_CLASSNAME(_class) \
|
||||||
|
_class::NS_CYCLE_COLLECTION_INNERCLASS
|
||||||
|
|
||||||
|
#define NS_CYCLE_COLLECTION_NAME(_class) \
|
||||||
|
_class##_cycleCollectorGlobal
|
||||||
|
|
||||||
|
#define NS_IMPL_QUERY_CYCLE_COLLECTION(_class) \
|
||||||
|
if ( aIID.Equals(NS_GET_IID(nsCycleCollectionParticipant)) ) { \
|
||||||
|
foundInterface = & NS_CYCLE_COLLECTION_NAME(_class); \
|
||||||
|
} else
|
||||||
|
|
||||||
|
#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) \
|
||||||
|
NS_IMPL_QUERY_CYCLE_COLLECTION(_class)
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers for implementing nsCycleCollectionParticipant::Unlink
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class, _base) \
|
||||||
|
NS_IMETHODIMP \
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(nsISupports *s) \
|
||||||
|
{ \
|
||||||
|
_class *tmp = NS_STATIC_CAST(_class*, NS_STATIC_CAST(_base*, s));
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_field) \
|
||||||
|
tmp->_field = NULL;
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(_field) \
|
||||||
|
tmp->_field.Clear();
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
|
||||||
|
return NS_OK; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers for implementing nsCycleCollectionParticipant::Traverse
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class) \
|
||||||
|
cb.DescribeNode(tmp->mRefCnt.get(), sizeof(_class), #_class);
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class, _base) \
|
||||||
|
NS_IMETHODIMP \
|
||||||
|
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
|
||||||
|
(nsISupports *s, \
|
||||||
|
nsCycleCollectionTraversalCallback &cb) \
|
||||||
|
{ \
|
||||||
|
_class *tmp = NS_STATIC_CAST(_class*, NS_STATIC_CAST(_base*, s)); \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_field) \
|
||||||
|
if (tmp->_field) { cb.NoteXPCOMChild(tmp->_field.get()); }
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(_field) \
|
||||||
|
{ \
|
||||||
|
PRInt32 i; \
|
||||||
|
for (i = 0; i < tmp->_field.Count(); ++i) \
|
||||||
|
if (tmp->_field[i]) \
|
||||||
|
cb.NoteXPCOMChild(tmp->_field[i]); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
|
||||||
|
return NS_OK; \
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers for implementing a concrete nsCycleCollectionParticipant
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define NS_DECL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
class NS_CYCLE_COLLECTION_INNERCLASS \
|
||||||
|
: public nsCycleCollectionParticipant \
|
||||||
|
{ \
|
||||||
|
NS_IMETHOD Unlink(nsISupports *n); \
|
||||||
|
NS_IMETHOD Traverse(nsISupports *n, \
|
||||||
|
nsCycleCollectionTraversalCallback &cb); \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
static NS_CYCLE_COLLECTION_CLASSNAME(_class) \
|
||||||
|
NS_CYCLE_COLLECTION_NAME(_class);
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_0_AMBIGUOUS(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_1_AMBIGUOUS(_class, _base, _f) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_2_AMBIGUOUS(_class, _base, _f1, _f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_3_AMBIGUOUS(_class, _base, _f1, _f2, _f3) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class, _base) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_0(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_0_AMBIGUOUS(_class, _class)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_1(_class, _f) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_1_AMBIGUOUS(_class, _class, _f)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_2(_class, _f1, _f2) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_2_AMBIGUOUS(_class, _class, _f1, _f2)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTION_3(_class, _f1, _f2, _f3) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_3_AMBIGUOUS(_class, _class, _f1, _f2, _f3)
|
||||||
|
|
||||||
|
#endif // nsCycleCollectionParticipant_h__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,67 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef nsCycleCollector_h__
|
||||||
|
#define nsCycleCollector_h__
|
||||||
|
|
||||||
|
class nsISupports;
|
||||||
|
class nsDeque;
|
||||||
|
struct nsCycleCollectionTraversalCallback;
|
||||||
|
|
||||||
|
// An nsCycleCollectionLanguageRuntime is a per-language object that
|
||||||
|
// implements language-specific aspects of the cycle collection task.
|
||||||
|
|
||||||
|
struct nsCycleCollectionLanguageRuntime
|
||||||
|
{
|
||||||
|
virtual nsresult BeginCycleCollection() = 0;
|
||||||
|
|
||||||
|
virtual nsresult Traverse(void *p, nsCycleCollectionTraversalCallback &cb) = 0;
|
||||||
|
|
||||||
|
virtual nsresult Root(const nsDeque &nodes) = 0;
|
||||||
|
virtual nsresult Unlink(const nsDeque &nodes) = 0;
|
||||||
|
virtual nsresult Unroot(const nsDeque &nodes) = 0;
|
||||||
|
|
||||||
|
virtual nsresult FinishCycleCollection() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
NS_COM PRBool nsCycleCollector_isScanSafe(nsISupports *n);
|
||||||
|
NS_COM void nsCycleCollector_suspect(nsISupports *n);
|
||||||
|
NS_COM void nsCycleCollector_forget(nsISupports *n);
|
||||||
|
NS_COM void nsCycleCollector_collect();
|
||||||
|
|
||||||
|
// Helpers for interacting with language-identified scripts
|
||||||
|
|
||||||
|
NS_COM void nsCycleCollector_registerRuntime(PRUint32 langID, nsCycleCollectionLanguageRuntime *rt);
|
||||||
|
NS_COM void nsCycleCollector_forgetRuntime(PRUint32 langID);
|
||||||
|
|
||||||
|
#endif // nsCycleCollector_h__
|
|
@ -95,6 +95,7 @@
|
||||||
#include "nsXPCOMStrings.h"
|
#include "nsXPCOMStrings.h"
|
||||||
#include "nsStringBuffer.h"
|
#include "nsStringBuffer.h"
|
||||||
#include "nsCategoryCache.h"
|
#include "nsCategoryCache.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
#if !defined(WINCE) && !defined(XP_OS2)
|
#if !defined(WINCE) && !defined(XP_OS2)
|
||||||
|
@ -270,6 +271,8 @@ void XXXNeverCalled()
|
||||||
b.ToString(0, y);
|
b.ToString(0, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCycleCollectionParticipant();
|
||||||
|
|
||||||
#if !defined(WINCE) && !defined(XP_OS2)
|
#if !defined(WINCE) && !defined(XP_OS2)
|
||||||
NS_NewWindowsRegKey(nsnull);
|
NS_NewWindowsRegKey(nsnull);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -226,6 +226,42 @@ private:
|
||||||
const void* mKey;
|
const void* mKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hashkey wrapper using void* KeyType, that sets key to NULL upon
|
||||||
|
* destruction. Relevant only in cases where a memory pointer-scanner
|
||||||
|
* like valgrind might get confused about stale references.
|
||||||
|
*
|
||||||
|
* @see nsTHashtable::EntryType for specification
|
||||||
|
*/
|
||||||
|
|
||||||
|
class nsClearingVoidPtrHashKey : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef const void* KeyType;
|
||||||
|
typedef const void* KeyTypePointer;
|
||||||
|
|
||||||
|
nsClearingVoidPtrHashKey(const void* key) :
|
||||||
|
mKey(key) { }
|
||||||
|
nsClearingVoidPtrHashKey(const nsClearingVoidPtrHashKey& toCopy) :
|
||||||
|
mKey(toCopy.mKey) { }
|
||||||
|
~nsClearingVoidPtrHashKey() { mKey = NULL; }
|
||||||
|
|
||||||
|
KeyType GetKey() const { return mKey; }
|
||||||
|
KeyTypePointer GetKeyPointer() const { return mKey; }
|
||||||
|
|
||||||
|
PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
|
||||||
|
|
||||||
|
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
|
||||||
|
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||||
|
{
|
||||||
|
return NS_PTR_TO_INT32(aKey) >>2;
|
||||||
|
}
|
||||||
|
enum { ALLOW_MEMMOVE = PR_TRUE };
|
||||||
|
|
||||||
|
private:
|
||||||
|
const void* mKey;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashkey wrapper using nsID KeyType
|
* hashkey wrapper using nsID KeyType
|
||||||
*
|
*
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
|
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
#include "nsTraceRefcnt.h"
|
#include "nsTraceRefcnt.h"
|
||||||
|
#include "nsCycleCollector.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Macros to help detect thread-safety:
|
// Macros to help detect thread-safety:
|
||||||
|
@ -88,6 +89,109 @@ private:
|
||||||
|
|
||||||
#endif // NS_DEBUG
|
#endif // NS_DEBUG
|
||||||
|
|
||||||
|
#if PR_BITS_PER_WORD == 32
|
||||||
|
#define NS_PURPLE_BIT ((PRUint32)(1 << 31))
|
||||||
|
#elif PR_BITS_PER_WORD == 64
|
||||||
|
#define NS_PURPLE_BIT ((PRUint64)(1 << 63))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NS_PURPLE_MASK (~NS_PURPLE_BIT)
|
||||||
|
#define NS_PURPLE_BIT_SET(x) ((x) & (NS_PURPLE_BIT))
|
||||||
|
#define NS_SET_PURPLE_BIT(x) ((x) |= (NS_PURPLE_BIT))
|
||||||
|
#define NS_CLEAR_PURPLE_BIT(x) ((x) &= (NS_PURPLE_MASK))
|
||||||
|
#define NS_VALUE_WITHOUT_PURPLE_BIT(x) ((x) & (NS_PURPLE_MASK))
|
||||||
|
|
||||||
|
|
||||||
|
// Support for ISupports classes which interact with cycle collector.
|
||||||
|
|
||||||
|
class nsCycleCollectingAutoRefCnt {
|
||||||
|
|
||||||
|
public:
|
||||||
|
nsCycleCollectingAutoRefCnt()
|
||||||
|
: mValue(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
nsCycleCollectingAutoRefCnt(nsrefcnt aValue)
|
||||||
|
: mValue(aValue)
|
||||||
|
{
|
||||||
|
NS_CLEAR_PURPLE_BIT(mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt incr(nsISupports *owner)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (NS_UNLIKELY(mValue == NS_PURPLE_BIT))
|
||||||
|
{
|
||||||
|
// The sentinel value "purple bit alone, refcount 0" means
|
||||||
|
// that we're stabilized, during finalization. In this
|
||||||
|
// state we lie about our actual refcount if anyone asks
|
||||||
|
// and say it's 1, which is basically true: the caller who
|
||||||
|
// is deleting us has a reference still.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt tmp = get();
|
||||||
|
PRBool purple = NS_STATIC_CAST(PRBool, NS_PURPLE_BIT_SET(mValue));
|
||||||
|
|
||||||
|
if (NS_UNLIKELY(purple)) {
|
||||||
|
NS_ASSERTION(tmp != 0, "purple ISupports pointer with zero refcnt");
|
||||||
|
nsCycleCollector_forget(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
mValue = tmp + 1;
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stabilizeForDeletion(nsISupports *owner)
|
||||||
|
{
|
||||||
|
mValue = NS_PURPLE_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt decr(nsISupports *owner)
|
||||||
|
{
|
||||||
|
if (NS_UNLIKELY(mValue == NS_PURPLE_BIT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nsrefcnt tmp = get();
|
||||||
|
PRBool purple = NS_STATIC_CAST(PRBool, NS_PURPLE_BIT_SET(mValue));
|
||||||
|
|
||||||
|
if (NS_UNLIKELY(tmp > 1 && !purple)) {
|
||||||
|
nsCycleCollector_suspect(owner);
|
||||||
|
purple = PR_TRUE;
|
||||||
|
|
||||||
|
} else if (NS_UNLIKELY(tmp == 1 && purple)) {
|
||||||
|
nsCycleCollector_forget(owner);
|
||||||
|
purple = PR_FALSE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
NS_ASSERTION(tmp >= 1, "decr() called with zero refcnt");
|
||||||
|
}
|
||||||
|
|
||||||
|
mValue = tmp - 1;
|
||||||
|
|
||||||
|
if (purple)
|
||||||
|
NS_SET_PURPLE_BIT(mValue);
|
||||||
|
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt get() const
|
||||||
|
{
|
||||||
|
if (NS_UNLIKELY(mValue == NS_PURPLE_BIT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return NS_VALUE_WITHOUT_PURPLE_BIT(mValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator nsrefcnt() const
|
||||||
|
{
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsrefcnt mValue;
|
||||||
|
};
|
||||||
|
|
||||||
class nsAutoRefCnt {
|
class nsAutoRefCnt {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -126,6 +230,17 @@ protected: \
|
||||||
NS_DECL_OWNINGTHREAD \
|
NS_DECL_OWNINGTHREAD \
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
|
||||||
|
public: \
|
||||||
|
NS_IMETHOD QueryInterface(REFNSIID aIID, \
|
||||||
|
void** aInstancePtr); \
|
||||||
|
NS_IMETHOD_(nsrefcnt) AddRef(void); \
|
||||||
|
NS_IMETHOD_(nsrefcnt) Release(void); \
|
||||||
|
protected: \
|
||||||
|
nsCycleCollectingAutoRefCnt mRefCnt; \
|
||||||
|
NS_DECL_OWNINGTHREAD \
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -229,6 +344,46 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(_class, _basetype) \
|
||||||
|
NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \
|
||||||
|
{ \
|
||||||
|
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \
|
||||||
|
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||||
|
mRefCnt.incr(NS_STATIC_CAST(_basetype *, this)); \
|
||||||
|
NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
|
||||||
|
return mRefCnt; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(_class, _class)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(_class, _basetype, _destroy) \
|
||||||
|
NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \
|
||||||
|
{ \
|
||||||
|
NS_PRECONDITION(0 != mRefCnt, "dup release"); \
|
||||||
|
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||||
|
mRefCnt.decr(NS_STATIC_CAST(_basetype *, this)); \
|
||||||
|
NS_LOG_RELEASE(this, mRefCnt, #_class); \
|
||||||
|
if (mRefCnt == 0) { \
|
||||||
|
mRefCnt.stabilizeForDeletion(NS_STATIC_CAST(_basetype *, this)); \
|
||||||
|
_destroy; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
return mRefCnt; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(_class, _class, _destroy)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(_class, _basetype, _destroy) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(_class, _basetype, _destroy)
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(_class, _basetype) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(_class, _basetype, NS_DELETEXPCOM(this))
|
||||||
|
|
||||||
|
#define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(_class, _class, NS_DELETEXPCOM(this))
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include "nsAutoLock.h"
|
#include "nsAutoLock.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
#include "nsCycleCollector.h"
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
static PRLogModuleInfo *sLog = PR_NewLogModule("nsEventQueue");
|
static PRLogModuleInfo *sLog = PR_NewLogModule("nsEventQueue");
|
||||||
|
@ -64,6 +66,7 @@ nsEventQueue::~nsEventQueue()
|
||||||
PRBool
|
PRBool
|
||||||
nsEventQueue::GetEvent(PRBool mayWait, nsIRunnable **result)
|
nsEventQueue::GetEvent(PRBool mayWait, nsIRunnable **result)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
nsAutoMonitor mon(mMonitor);
|
nsAutoMonitor mon(mMonitor);
|
||||||
|
|
||||||
while (IsEmpty()) {
|
while (IsEmpty()) {
|
||||||
|
@ -88,6 +91,11 @@ nsEventQueue::GetEvent(PRBool mayWait, nsIRunnable **result)
|
||||||
mOffsetHead = 0;
|
mOffsetHead = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
nsCycleCollector_collect();
|
||||||
|
}
|
||||||
|
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче