Bug 333078: XPCOM cycle collector

r=brendan, sicking, bz, dbaron, bsmedberg
This commit is contained in:
graydon%mozilla.com 2007-01-04 22:31:26 +00:00
Родитель 546f5b33f3
Коммит 4525ab79d9
67 изменённых файлов: 3467 добавлений и 1467 удалений

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

@ -55,7 +55,6 @@ nsContentPolicyUtils.h \
nsContentUtils.h \
nsIDocument.h \
nsIDocumentObserver.h \
nsIDOMGCParticipant.h \
nsIMutationObserver.h \
nsINameSpaceManager.h \
nsINode.h \

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

@ -764,6 +764,20 @@ public:
PRBool aCancelable,
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
* was created, aCreated is set to PR_TRUE.
@ -916,7 +930,9 @@ private:
static nsresult doReparentContentWrapper(nsIContent *aChild,
JSContext *cx,
JSObject *aOldGlobal,
JSObject *aNewGlobal);
JSObject *aNewGlobal,
nsIDocument *aOldDocument,
nsIDocument *aNewDocument);
static nsresult EnsureStringBundle(PropertiesFile aFile);

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

@ -785,4 +785,31 @@ public:
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___ */

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

@ -609,6 +609,10 @@ public:
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup* aLoadGroup,
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.
*/

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

@ -38,7 +38,6 @@
#ifndef nsINode_h___
#define nsINode_h___
#include "nsIDOMGCParticipant.h"
#include "nsEvent.h"
#include "nsPropertyTable.h"
#include "nsTObserverArray.h"
@ -97,11 +96,11 @@ class nsNodeSupportsWeakRefTearoff;
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x98470c4b, 0xe988, 0x4abf, \
{ 0xa4, 0x00, 0x39, 0xbd, 0x00, 0x38, 0x51, 0x4d } }
{ 0x0d2a583d, 0x7a99, 0x426b, \
{ 0x89, 0xfa, 0xca, 0x8d, 0x63, 0xbb, 0xd7, 0x3f } }
// hack to make egcs / gcc 2.95.2 happy
class nsINode_base : public nsIDOMGCParticipant {
class nsINode_base : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
};

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

@ -138,6 +138,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
#endif
#include "nsCycleCollectionParticipant.h"
// for ReportToConsole
#include "nsIStringBundle.h"
@ -726,7 +727,9 @@ nsresult
nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
JSContext *cx,
JSObject *aOldGlobal,
JSObject *aNewGlobal)
JSObject *aNewGlobal,
nsIDocument *aOldDocument,
nsIDocument *aNewDocument)
{
nsCOMPtr<nsIXPConnectJSObjectHolder> old_wrapper;
@ -737,6 +740,16 @@ nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
getter_AddRefs(old_wrapper));
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
// 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
@ -749,7 +762,9 @@ nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
nsIContent *child = aNode->GetChildAt(i);
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);
}
@ -803,7 +818,8 @@ nsContentUtils::ReparentContentWrapper(nsIContent *aContent,
return NS_OK;
}
return doReparentContentWrapper(aContent, cx, oldScope, newScope);
return doReparentContentWrapper(aContent, cx, oldScope, newScope,
aOldDocument, aNewDocument);
}
// static
@ -2874,6 +2890,24 @@ nsContentUtils::HasMutationListeners(nsINode* aNode,
}
/* 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
nsContentUtils::GetListenerManager(nsINode *aNode,
PRBool aCreateIfNotFound,

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

@ -72,12 +72,24 @@ nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap,
// 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
NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
NS_INTERFACE_MAP_ENTRY(nsIDOMAttr)
NS_INTERFACE_MAP_ENTRY(nsIAttribute)
NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
NS_INTERFACE_MAP_ENTRY(nsIDOM3Attr)
@ -85,34 +97,12 @@ NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
new nsNodeSupportsWeakRefTearoff(this))
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMAttr)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Attr)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDOMAttribute)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMAttribute)
NS_IMPL_RELEASE_WITH_DESTROY(nsDOMAttribute,
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());
}
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMAttribute, nsIDOMAttr)
NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsDOMAttribute, nsIDOMAttr,
nsNodeUtils::LastRelease(this, PR_TRUE))
void
nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)

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

@ -53,6 +53,7 @@
#include "nsIDOM3Node.h"
#include "nsIDOM3Attr.h"
#include "nsDOMAttributeMap.h"
#include "nsCycleCollectionParticipant.h"
class nsDOMAttribute;
@ -66,11 +67,7 @@ public:
nsDOMAttribute(nsDOMAttributeMap* aAttrMap, nsINodeInfo *aNodeInfo,
const nsAString& aValue);
NS_DECL_ISUPPORTS
// nsIDOMGCParticipant interface methods
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
// nsIDOMNode interface
NS_DECL_NSIDOMNODE
@ -108,6 +105,8 @@ public:
static void Initialize();
static void Shutdown();
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
protected:
static PRBool sInitialized;

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

@ -90,16 +90,40 @@ nsDOMAttributeMap::DropReference()
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
NS_INTERFACE_MAP_BEGIN(nsDOMAttributeMap)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMNamedNodeMap)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NamedNodeMap)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDOMAttributeMap)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMAttributeMap)
NS_IMPL_RELEASE(nsDOMAttributeMap)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMAttributeMap)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMAttributeMap)
PLDHashOperator
SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey, nsCOMPtr<nsIDOMNode>& aData,

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

@ -46,6 +46,7 @@
#include "nsIDOMNamedNodeMap.h"
#include "nsString.h"
#include "nsInterfaceHashtable.h"
#include "nsCycleCollectionParticipant.h"
class nsIAtom;
class nsIContent;
@ -126,7 +127,7 @@ public:
*/
PRBool Init();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
// nsIDOMNamedNodeMap interface
NS_DECL_NSIDOMNAMEDNODEMAP
@ -169,6 +170,8 @@ public:
*/
PRUint32 Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const;
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMAttributeMap)
private:
nsIContent* mContent; // Weak reference

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

@ -752,6 +752,7 @@ nsDocument::~nsDocument()
delete mHeaderData;
delete mBoxObjectTable;
delete mContentWrapperHash;
nsLayoutStatics::Release();
}
@ -767,6 +768,8 @@ nsDocument::LastRelease()
delete this;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
NS_INTERFACE_MAP_BEGIN(nsDocument)
NS_INTERFACE_MAP_ENTRY(nsIDocument)
NS_INTERFACE_MAP_ENTRY(nsIDOMDocument)
@ -781,7 +784,6 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL)
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
@ -792,6 +794,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsDocument)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument)
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
@ -808,8 +811,72 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
else
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
nsDocument::Init()
@ -3347,23 +3414,6 @@ nsDocument::SetDir(const nsAString& aDirection)
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
@ -4374,6 +4424,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*
nsDocument::GetScriptEventManager()
{
@ -5007,6 +5097,8 @@ nsDocument::Destroy()
mLayoutHistoryState = nsnull;
nsContentList::OnDocumentDestroy(this);
delete mContentWrapperHash;
mContentWrapperHash = nsnull;
}
already_AddRefed<nsILayoutHistoryState>

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

@ -91,6 +91,7 @@
#include "nsTObserverArray.h"
#include "nsStubMutationObserver.h"
#include "nsIChannel.h"
#include "nsCycleCollectionParticipant.h"
// Put these here so all document impls get them automatically
#include "nsHTMLStyleSheet.h"
@ -295,7 +296,7 @@ class nsDocument : public nsIDocument,
public nsStubMutationObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
@ -493,6 +494,9 @@ public:
nsIStyleRule* aStyleRule);
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 void SetXMLDeclaration(const PRUnichar *aVersion,
const PRUnichar *aEncoding,
@ -548,10 +552,6 @@ public:
nsresult GetRadioGroup(const nsAString& aName,
nsRadioGroupStruct **aRadioGroup);
// nsIDOMGCParticipant interface methods
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
// nsIDOMNode
NS_DECL_NSIDOMNODE
@ -643,6 +643,8 @@ public:
NS_HIDDEN_(void) ClearBoxObjectFor(nsIContent* aContent);
NS_DECL_CYCLE_COLLECTION_CLASS(nsDocument)
protected:
/**
@ -749,6 +751,7 @@ protected:
PRUint8 mDefaultElementType;
nsInterfaceHashtable<nsISupportsHashKey, nsPIBoxObject> *mBoxObjectTable;
nsInterfaceHashtable<nsVoidPtrHashKey, nsISupports> *mContentWrapperHash;
// The channel that got passed to StartDocumentLoad(), if any
nsCOMPtr<nsIChannel> mChannel;

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

@ -200,13 +200,9 @@ nsDocumentFragment::IsNodeOfType(PRUint32 aFlags) const
NS_INTERFACE_MAP_BEGIN(nsDocumentFragment)
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentFragment)
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_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentFragment)
NS_INTERFACE_MAP_END
NS_INTERFACE_MAP_END_INHERITING(nsGenericElement)
NS_IMPL_ADDREF_INHERITED(nsDocumentFragment, nsGenericElement)

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

@ -76,14 +76,20 @@ nsGenericDOMDataNode::~nsGenericDOMDataNode()
"Please remove this from the document properly");
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
NS_IMPL_ADDREF(nsGenericDOMDataNode)
NS_IMPL_RELEASE_WITH_DESTROY(nsGenericDOMDataNode,
nsNodeUtils::LastRelease(this, PR_TRUE))
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode, nsIContent)
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(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_ENTRY(nsIContent)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
nsDOMEventRTTearoff::Create(this))
@ -97,8 +103,13 @@ NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
new nsNodeSupportsWeakRefTearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGenericDOMDataNode)
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
nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
@ -526,38 +537,6 @@ nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
}
#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
nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,

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

@ -50,7 +50,7 @@
#include "nsDOMError.h"
#include "nsIEventListenerManager.h"
#include "nsGenericElement.h"
#include "nsCycleCollectionParticipant.h"
class nsIDOMAttr;
class nsIDOMEventListener;
@ -63,7 +63,7 @@ class nsURI;
class nsGenericDOMDataNode : public nsIContent
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
nsGenericDOMDataNode(nsINodeInfo *aNodeInfo);
virtual ~nsGenericDOMDataNode();
@ -168,10 +168,6 @@ public:
nsresult ReplaceData(PRUint32 aOffset, PRUint32 aCount,
const nsAString& aArg);
// nsIDOMGCParticipant interface methods
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
// nsINode methods
virtual PRUint32 GetChildCount() const;
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
@ -263,6 +259,8 @@ public:
void ToCString(nsAString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
#endif
NS_DECL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
protected:
/**
* There are a set of DOM- and scripting-specific instance variables

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

@ -115,6 +115,9 @@
#include "nsContentCreatorFunctions.h"
#include "nsIFocusController.h"
#include "nsCycleCollectionParticipant.h"
#ifdef MOZ_SVG
PRBool NS_SVG_TestFeature(const nsAString &fstr);
#endif /* MOZ_SVG */
@ -961,46 +964,6 @@ nsGenericElement::~nsGenericElement()
"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
nsGenericElement::GetNodeName(nsAString& aNodeName)
{
@ -3009,9 +2972,55 @@ nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIContent* aParent,
// 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_ENTRY(nsIContent)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
@ -3025,11 +3034,13 @@ NS_INTERFACE_MAP_BEGIN(nsGenericElement)
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
new nsNodeSupportsWeakRefTearoff(this))
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGenericElement)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsGenericElement)
NS_IMPL_RELEASE_WITH_DESTROY(nsGenericElement,
nsNodeUtils::LastRelease(this, PR_TRUE))
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericElement, nsIContent)
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsGenericElement,
nsIContent,
nsNodeUtils::LastRelease(this, PR_TRUE))
nsresult
nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr)

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

@ -61,6 +61,7 @@
#include "mozFlushType.h"
#include "nsDOMAttributeMap.h"
#include "nsIWeakReference.h"
#include "nsCycleCollectionParticipant.h"
class nsIDOMAttr;
class nsIDOMEventListener;
@ -352,7 +353,7 @@ public:
nsGenericElement(nsINodeInfo *aNodeInfo);
virtual ~nsGenericElement();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
/**
* Called during QueryInterface to give the binding manager a chance to
@ -360,10 +361,6 @@ public:
*/
nsresult PostQueryInterface(REFNSIID aIID, void** aInstancePtr);
// nsIDOMGCParticipant interface methods
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
// nsINode interface methods
virtual PRUint32 GetChildCount() const;
virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
@ -775,6 +772,8 @@ public:
{
}
NS_DECL_CYCLE_COLLECTION_CLASS(nsGenericElement)
protected:
/**
* Set attribute and (if needed) notify documentobservers and fire off

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

@ -102,7 +102,6 @@ static void PrintReqURL(imgIRequest* req) {
nsImageLoadingContent::nsImageLoadingContent()
: mObserverList(nsnull),
mImageBlockingStatus(nsIContentPolicy::ACCEPT),
mRootRefCount(0),
mLoadingEnabled(PR_TRUE),
mStartingLoad(PR_FALSE),
mLoading(PR_FALSE),
@ -128,19 +127,6 @@ nsImageLoadingContent::DestroyImageLoadingContent()
mPendingRequest->Cancel(NS_ERROR_FAILURE);
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()
@ -279,9 +265,6 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, PRBool aLastPart)
{
LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
if (aLastPart)
UnpreserveLoadHandlers();
return NS_OK;
}
@ -453,8 +436,6 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
return NS_OK;
}
PreserveLoadHandlers();
// Null out our mCurrentURI, in case we have no image requests right now.
mCurrentURI = nsnull;
@ -469,9 +450,6 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
// Make sure our state is up to date
UpdateImageState(PR_TRUE);
if (NS_FAILED(rv))
UnpreserveLoadHandlers();
return rv;
}
@ -589,8 +567,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
return NS_OK;
}
PreserveLoadHandlers();
nsCOMPtr<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
@ -599,7 +575,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
getter_AddRefs(req));
if (NS_FAILED(rv)) {
FireEvent(NS_LITERAL_STRING("error"));
UnpreserveLoadHandlers();
return NS_OK;
}
@ -740,7 +715,6 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgIRequest* aRequest,
NS_PRECONDITION(aRequest, "Must have a request here!");
AutoStateChanger changer(this, aNotify);
mCurrentURI = nsnull;
PreserveLoadHandlers();
CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT);
NS_ASSERTION(!mCurrentRequest, "We should not have a current request now");
@ -800,7 +774,6 @@ public:
~Event()
{
mDocument->UnblockOnload(PR_TRUE);
mContent->UnpreserveLoadHandlers();
}
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
// want to block now, even if posting will fail.
document->BlockOnload();
PreserveLoadHandlers();
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;
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 */
protected:
nsCOMPtr<imgIRequest> mCurrentRequest;
@ -265,12 +256,6 @@ private:
ImageObserver mObserverList;
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 mStartingLoad : 1;

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

@ -86,12 +86,11 @@ nsTreeWalker::nsTreeWalker(nsINode *aRoot,
PRBool aExpandEntityReferences) :
mRoot(aRoot),
mWhatToShow(aWhatToShow),
mFilter(aFilter),
mExpandEntityReferences(aExpandEntityReferences),
mCurrentNode(aRoot),
mPossibleIndexesPos(-1)
{
mFilter.Set(aFilter, this);
NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
}
@ -107,7 +106,6 @@ nsTreeWalker::~nsTreeWalker()
// QueryInterface implementation for nsTreeWalker
NS_INTERFACE_MAP_BEGIN(nsTreeWalker)
NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TreeWalker)
NS_INTERFACE_MAP_END
@ -143,7 +141,7 @@ NS_IMETHODIMP nsTreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
{
NS_ENSURE_ARG_POINTER(aFilter);
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter;
filter.swap((*aFilter = nsnull));
return NS_OK;
@ -307,28 +305,6 @@ NS_IMETHODIMP nsTreeWalker::NextNode(nsIDOMNode **_retval)
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
@ -635,13 +611,12 @@ nsresult nsTreeWalker::TestNode(nsINode* aNode, PRInt16* _filtered)
return NS_OK;
}
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
if (filter) {
if (mFilter) {
if (!domNode) {
domNode = do_QueryInterface(aNode);
}
return filter->AcceptNode(domNode, _filtered);
return mFilter->AcceptNode(domNode, _filtered);
}
*_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;

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

@ -47,23 +47,18 @@
#include "nsIDOMTreeWalker.h"
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsIDOMGCParticipant.h"
#include "nsJSUtils.h"
class nsINode;
class nsIDOMNode;
class nsIDOMNodeFilter;
class nsTreeWalker : public nsIDOMTreeWalker, public nsIDOMGCParticipant
class nsTreeWalker : public nsIDOMTreeWalker
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMTREEWALKER
// nsIDOMGCParticipant
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
nsTreeWalker(nsINode *aRoot,
PRUint32 aWhatToShow,
nsIDOMNodeFilter *aFilter,
@ -73,7 +68,7 @@ public:
private:
nsCOMPtr<nsINode> mRoot;
PRUint32 mWhatToShow;
nsMarkedJSFunctionHolder<nsIDOMNodeFilter> mFilter;
nsCOMPtr<nsIDOMNodeFilter> mFilter;
PRBool mExpandEntityReferences;
nsCOMPtr<nsINode> mCurrentNode;

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

@ -78,6 +78,7 @@
#include "nsCOMArray.h"
#include "nsDOMClassInfo.h"
#include "nsIScriptableUConv.h"
#include "nsCycleCollectionParticipant.h"
#define LOAD_STR "load"
#define ERROR_STR "error"
@ -287,6 +288,57 @@ nsXMLHttpRequest::~nsXMLHttpRequest()
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
NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
@ -300,14 +352,14 @@ NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLHttpRequest)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsXMLHttpRequest)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsXMLHttpRequest)
NS_IMPL_RELEASE(nsXMLHttpRequest)
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXMLHttpRequest, nsIXMLHttpRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXMLHttpRequest, nsIXMLHttpRequest)
/* void addEventListener (in string type, in nsIDOMEventListener
@ -319,7 +371,7 @@ nsXMLHttpRequest::AddEventListener(const nsAString& type,
{
NS_ENSURE_ARG(listener);
nsTArray<ListenerHolder*> *array;
nsCOMArray<nsIDOMEventListener> *array;
#define IMPL_ADD_LISTENER(_type, _member) \
if (type.EqualsLiteral(_type)) { \
@ -335,10 +387,7 @@ nsXMLHttpRequest::AddEventListener(const nsAString& type,
return NS_ERROR_INVALID_ARG;
}
ListenerHolder *holder = new ListenerHolder;
NS_ENSURE_TRUE(holder, NS_ERROR_OUT_OF_MEMORY);
holder->Set(listener, this);
array->AppendElement(holder);
array->AppendObject(listener);
mScriptContext = GetCurrentContext();
@ -356,7 +405,7 @@ nsXMLHttpRequest::RemoveEventListener(const nsAString & type,
{
NS_ENSURE_ARG(listener);
nsTArray<ListenerHolder*> *array;
nsCOMArray<nsIDOMEventListener> *array;
#define IMPL_REMOVE_LISTENER(_type, _member) \
if (type.EqualsLiteral(_type)) { \
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.
for (PRUint32 i = array->Length() - 1; i != PRUint32(-1); --i) {
ListenerHolder *holder = array->ElementAt(i);
if (nsCOMPtr<nsIDOMEventListener>(holder->Get()) == listener) {
array->RemoveElementAt(i);
delete holder;
for (PRUint32 i = array->Count() - 1; i != PRUint32(-1); --i) {
if (array->ObjectAt(i) == listener) {
array->RemoveObjectAt(i);
break;
}
}
@ -399,7 +446,7 @@ nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechan
{
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
mOnReadystatechangeListener.Get(aOnreadystatechange);
NS_IF_ADDREF(*aOnreadystatechange = mOnReadystatechangeListener);
return NS_OK;
}
@ -407,7 +454,7 @@ nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechan
NS_IMETHODIMP
nsXMLHttpRequest::SetOnreadystatechange(nsIDOMEventListener * aOnreadystatechange)
{
mOnReadystatechangeListener.Set(aOnreadystatechange, this);
mOnReadystatechangeListener = aOnreadystatechange;
mScriptContext = GetCurrentContext();
@ -421,7 +468,7 @@ nsXMLHttpRequest::GetOnload(nsIDOMEventListener * *aOnLoad)
{
NS_ENSURE_ARG_POINTER(aOnLoad);
mOnLoadListener.Get(aOnLoad);
NS_IF_ADDREF(*aOnLoad = mOnLoadListener);
return NS_OK;
}
@ -429,7 +476,7 @@ nsXMLHttpRequest::GetOnload(nsIDOMEventListener * *aOnLoad)
NS_IMETHODIMP
nsXMLHttpRequest::SetOnload(nsIDOMEventListener * aOnLoad)
{
mOnLoadListener.Set(aOnLoad, this);
mOnLoadListener = aOnLoad;
mScriptContext = GetCurrentContext();
@ -442,7 +489,7 @@ nsXMLHttpRequest::GetOnerror(nsIDOMEventListener * *aOnerror)
{
NS_ENSURE_ARG_POINTER(aOnerror);
mOnErrorListener.Get(aOnerror);
NS_IF_ADDREF(*aOnerror = mOnErrorListener);
return NS_OK;
}
@ -450,7 +497,7 @@ nsXMLHttpRequest::GetOnerror(nsIDOMEventListener * *aOnerror)
NS_IMETHODIMP
nsXMLHttpRequest::SetOnerror(nsIDOMEventListener * aOnerror)
{
mOnErrorListener.Set(aOnerror, this);
mOnErrorListener = aOnerror;
mScriptContext = GetCurrentContext();
@ -461,9 +508,9 @@ nsXMLHttpRequest::SetOnerror(nsIDOMEventListener * aOnerror)
NS_IMETHODIMP
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;
}
@ -471,7 +518,7 @@ nsXMLHttpRequest::GetOnprogress(nsIDOMEventListener * *aOnprogress)
NS_IMETHODIMP
nsXMLHttpRequest::SetOnprogress(nsIDOMEventListener * aOnprogress)
{
mOnProgressListener.Set(aOnprogress, this);
mOnProgressListener = aOnprogress;
mScriptContext = GetCurrentContext();
@ -482,9 +529,9 @@ nsXMLHttpRequest::SetOnprogress(nsIDOMEventListener * aOnprogress)
NS_IMETHODIMP
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;
}
@ -492,7 +539,7 @@ nsXMLHttpRequest::GetOnuploadprogress(nsIDOMEventListener * *aOnuploadprogress)
NS_IMETHODIMP
nsXMLHttpRequest::SetOnuploadprogress(nsIDOMEventListener * aOnuploadprogress)
{
mOnUploadProgressListener.Set(aOnuploadprogress, this);
mOnUploadProgressListener = aOnuploadprogress;
mScriptContext = GetCurrentContext();
@ -504,8 +551,7 @@ NS_IMETHODIMP
nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
{
NS_ENSURE_ARG_POINTER(aChannel);
*aChannel = mChannel;
NS_IF_ADDREF(*aChannel);
NS_IF_ADDREF(*aChannel = mChannel);
return NS_OK;
}
@ -848,18 +894,15 @@ nsXMLHttpRequest::CreateEvent(const nsAString& aType, nsIDOMEvent** aDOMEvent)
}
void
nsXMLHttpRequest::CopyEventListeners(ListenerHolder& aListener,
const nsTArray<ListenerHolder*>& aListenerArray,
nsXMLHttpRequest::CopyEventListeners(nsCOMPtr<nsIDOMEventListener>& aListener,
const nsCOMArray<nsIDOMEventListener>& aListenerArray,
nsCOMArray<nsIDOMEventListener>& aCopy)
{
NS_PRECONDITION(aCopy.Count() == 0, "aCopy should start off empty");
nsCOMPtr<nsIDOMEventListener> listener = aListener.Get();
if (listener)
aCopy.AppendObject(listener);
if (aListener)
aCopy.AppendObject(aListener);
PRUint32 count = aListenerArray.Length();
for (PRUint32 i = 0; i < count; ++i)
aCopy.AppendObject(nsCOMPtr<nsIDOMEventListener>(aListenerArray[i]->Get()));
aCopy.AppendObjects(aListenerArray);
}
void
@ -904,33 +947,25 @@ void
nsXMLHttpRequest::ClearEventListeners()
{
if (mState & XML_HTTP_REQUEST_ROOTED) {
nsDOMClassInfo::UnsetExternallyReferenced(this);
mState &= ~XML_HTTP_REQUEST_ROOTED;
}
// This isn't *really* needed anymore now that we use
// nsMarkedJSFunctionHolder, but we may as well keep it for safety
// (against leaks) and compatibility, and also for the code to clear
// the first 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();
// This isn't *really* needed anymore now that we use a cycle
// collector, but we may as well keep it for safety (against leaks)
// and compatibility, and also for the code to clear the first
// listener arrays (called from the destructor).
CLEAR_ARRAY(mLoadEventListeners)
CLEAR_ARRAY(mErrorEventListeners)
CLEAR_ARRAY(mProgressEventListeners)
CLEAR_ARRAY(mUploadProgressEventListeners)
CLEAR_ARRAY(mReadystatechangeEventListeners)
mLoadEventListeners.Clear();
mErrorEventListeners.Clear();
mProgressEventListeners.Clear();
mUploadProgressEventListeners.Clear();
mReadystatechangeEventListeners.Clear();
#undef CLEAR_ARRAY
mOnLoadListener.Set(nsnull, this);
mOnErrorListener.Set(nsnull, this);
mOnProgressListener.Set(nsnull, this);
mOnUploadProgressListener.Set(nsnull, this);
mOnReadystatechangeListener.Set(nsnull, this);
mOnLoadListener = nsnull;
mOnErrorListener = nsnull;
mOnProgressListener = nsnull;
mOnUploadProgressListener = nsnull;
mOnReadystatechangeListener = nsnull;
}
already_AddRefed<nsIHttpChannel>
@ -1025,10 +1060,10 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
// a progress event handler we must load with nsIRequest::LOAD_NORMAL or
// necko won't generate any progress notifications
nsLoadFlags loadFlags;
if (nsCOMPtr<nsIDOMEventListener>(mOnProgressListener.Get()) ||
nsCOMPtr<nsIDOMEventListener>(mOnUploadProgressListener.Get()) ||
mProgressEventListeners.Length() != 0 ||
mUploadProgressEventListeners.Length() != 0) {
if (mOnProgressListener ||
mOnUploadProgressListener ||
mProgressEventListeners.Count() != 0 ||
mUploadProgressEventListeners.Count() != 0) {
loadFlags = nsIRequest::LOAD_NORMAL;
} else {
loadFlags = nsIRequest::LOAD_BACKGROUND;
@ -1674,9 +1709,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// from being garbage collected even if this object becomes
// unreachable from script, since they can fire as a result of our
// reachability from the network stack.
rv = nsDOMClassInfo::SetExternallyReferenced(this);
if (NS_SUCCEEDED(rv))
mState |= XML_HTTP_REQUEST_ROOTED;
mState |= XML_HTTP_REQUEST_ROOTED;
}
if (!mChannel) {
@ -2070,23 +2103,6 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **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)

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

@ -59,6 +59,7 @@
#include "nsCOMArray.h"
#include "nsJSUtils.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMLSProgressEvent.h"
@ -72,14 +73,13 @@ class nsXMLHttpRequest : public nsIXMLHttpRequest,
public nsIChannelEventSink,
public nsIProgressEventSink,
public nsIInterfaceRequestor,
public nsIDOMGCParticipant,
public nsSupportsWeakReference
{
public:
nsXMLHttpRequest();
virtual ~nsXMLHttpRequest();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
// nsIXMLHttpRequest
NS_DECL_NSIXMLHTTPREQUEST
@ -115,12 +115,9 @@ public:
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
// nsIDOMGCParticipant
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
NS_DECL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
protected:
typedef nsMarkedJSFunctionHolder<nsIDOMEventListener> ListenerHolder;
nsresult DetectCharset(nsACString& aCharset);
nsresult ConvertBodyToText(nsAString& aOutBuffer);
@ -148,8 +145,8 @@ protected:
nsresult CreateEvent(const nsAString& aType, nsIDOMEvent** domevent);
// Make a copy of a pair of members to be passed to NotifyEventListeners.
void CopyEventListeners(ListenerHolder& aListener,
const nsTArray<ListenerHolder*>& aListenerArray,
void CopyEventListeners(nsCOMPtr<nsIDOMEventListener>& aListener,
const nsCOMArray<nsIDOMEventListener>& aListenerArray,
nsCOMArray<nsIDOMEventListener>& aCopy);
// aListeners must be a "non-live" list (i.e., addEventListener and
@ -165,19 +162,19 @@ protected:
nsCOMPtr<nsIRequest> mReadRequest;
nsCOMPtr<nsIDOMDocument> mDocument;
nsTArray<ListenerHolder*> mLoadEventListeners;
nsTArray<ListenerHolder*> mErrorEventListeners;
nsTArray<ListenerHolder*> mProgressEventListeners;
nsTArray<ListenerHolder*> mUploadProgressEventListeners;
nsTArray<ListenerHolder*> mReadystatechangeEventListeners;
nsCOMArray<nsIDOMEventListener> mLoadEventListeners;
nsCOMArray<nsIDOMEventListener> mErrorEventListeners;
nsCOMArray<nsIDOMEventListener> mProgressEventListeners;
nsCOMArray<nsIDOMEventListener> mUploadProgressEventListeners;
nsCOMArray<nsIDOMEventListener> mReadystatechangeEventListeners;
nsCOMPtr<nsIScriptContext> mScriptContext;
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnLoadListener;
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnErrorListener;
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnProgressListener;
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnUploadProgressListener;
nsMarkedJSFunctionHolder<nsIDOMEventListener> mOnReadystatechangeListener;
nsCOMPtr<nsIDOMEventListener> mOnLoadListener;
nsCOMPtr<nsIDOMEventListener> mOnErrorListener;
nsCOMPtr<nsIDOMEventListener> mOnProgressListener;
nsCOMPtr<nsIDOMEventListener> mOnUploadProgressListener;
nsCOMPtr<nsIDOMEventListener> mOnReadystatechangeListener;
nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;

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

@ -157,13 +157,6 @@ public:
* Tells the event listener manager that its target (which owns it) is
* 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
* |SetListenerTarget|.
*/

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

@ -393,8 +393,7 @@ nsEventListenerManager::Shutdown()
nsDOMEvent::Shutdown();
}
NS_IMPL_ADDREF(nsEventListenerManager)
NS_IMPL_RELEASE(nsEventListenerManager)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventListenerManager)
NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEventListenerManager)
@ -402,8 +401,28 @@ NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsEventListenerManager)
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*
nsEventListenerManager::GetTypeDataForIID(const nsIID& aIID)
{
@ -476,8 +495,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
PRInt32 count = mListeners.Count();
for (PRInt32 i = 0; i < count; i++) {
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
nsRefPtr<nsIDOMEventListener> listener = ls->mListener.Get();
if (listener == aListener && ls->mFlags == aFlags &&
if (ls->mListener == aListener && ls->mFlags == aFlags &&
ls->mGroupFlags == group &&
(EVENT_TYPE_EQUALS(ls, aType, aTypeAtom) ||
EVENT_TYPE_DATA_EQUALS(aTypeData, ls->mTypeData))) {
@ -491,9 +509,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
ls = new nsListenerStruct();
NS_ENSURE_TRUE(ls, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(mTarget);
NS_ASSERTION(participant, "must implement nsIDOMGCParticipant");
ls->mListener.Set(aListener, participant);
ls->mListener = aListener;
ls->mEventType = aType;
ls->mTypeAtom = aTypeAtom;
ls->mFlags = aFlags;
@ -597,8 +613,7 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
PRInt32 count = mListeners.Count();
for (PRInt32 i = 0; i < count; ++i) {
ls = NS_STATIC_CAST(nsListenerStruct*, mListeners.ElementAt(i));
nsRefPtr<nsIDOMEventListener> listener = ls->mListener.Get();
if (listener == aListener &&
if (ls->mListener == aListener &&
ls->mGroupFlags == group &&
((ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) &&
(EVENT_TYPE_EQUALS(ls, aType, aUserType) ||
@ -1360,9 +1375,7 @@ found:
// Check that the phase is same in event and event listener.
// Handle only trusted events, except when listener permits untrusted events.
if (useTypeInterface || useGenericInterface) {
nsRefPtr<nsIDOMEventListener> eventListener = ls->mListener.Get();
NS_ASSERTION(eventListener, "listener wasn't preserved properly");
if (eventListener) {
if (ls->mListener) {
hasListener = PR_TRUE;
if (ls->mFlags & aFlags &&
ls->mGroupFlags == currentGroup &&
@ -1374,10 +1387,10 @@ found:
}
if (*aDOMEvent) {
if (useTypeInterface) {
DispatchToInterface(*aDOMEvent, eventListener,
DispatchToInterface(*aDOMEvent, ls->mListener,
dispData->method, *typeData->iid);
} else if (useGenericInterface) {
HandleEventSubType(ls, eventListener, *aDOMEvent,
HandleEventSubType(ls, ls->mListener, *aDOMEvent,
aCurrentTarget, aFlags);
}
}
@ -1420,11 +1433,6 @@ NS_IMETHODIMP
nsEventListenerManager::Disconnect()
{
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();
}

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

@ -41,11 +41,12 @@
#include "nsIEventListenerManager.h"
#include "jsapi.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOM3EventTarget.h"
#include "nsHashtable.h"
#include "nsIScriptContext.h"
#include "nsJSUtils.h"
#include "nsCycleCollectionParticipant.h"
class nsIDOMEvent;
class nsVoidArray;
@ -53,21 +54,13 @@ class nsIAtom;
struct EventTypeData;
typedef struct {
// The nsMarkedJSFunctionHolder does magic to avoid holding strong
// 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;
nsCOMPtr<nsIAtom> mTypeAtom;
PRUint16 mFlags;
PRUint16 mGroupFlags;
PRBool mHandlerIsString;
const EventTypeData* mTypeData;
nsRefPtr<nsIDOMEventListener> mListener;
PRUint32 mEventType;
nsCOMPtr<nsIAtom> mTypeAtom;
PRUint16 mFlags;
PRUint16 mGroupFlags;
PRBool mHandlerIsString;
const EventTypeData* mTypeData;
} nsListenerStruct;
/*
@ -83,7 +76,7 @@ public:
nsEventListenerManager();
virtual ~nsEventListenerManager();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
/**
* Sets events listeners of all types.
@ -159,6 +152,8 @@ public:
static void Shutdown();
NS_DECL_CYCLE_COLLECTION_CLASS(nsEventListenerManager)
protected:
nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
nsIDOMEventListener* aListener,

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

@ -91,8 +91,8 @@ nsHTMLIFrameElement::~nsHTMLIFrameElement()
}
NS_IMPL_ADDREF_INHERITED(nsHTMLIFrameElement, nsGenericElement)
NS_IMPL_RELEASE_INHERITED(nsHTMLIFrameElement, nsGenericElement)
NS_IMPL_ADDREF_INHERITED(nsHTMLIFrameElement,nsGenericElement)
NS_IMPL_RELEASE_INHERITED(nsHTMLIFrameElement,nsGenericElement)
// QueryInterface implementation for nsHTMLIFrameElement
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLIFrameElement, nsGenericHTMLFrameElement)

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

@ -281,8 +281,96 @@ SetOrRemoveObject(PLDHashTable& table, nsISupports* aKey, nsISupports* aValue)
// Static member variable initialization
// Implement our nsISupports methods
NS_IMPL_ISUPPORTS3(nsBindingManager, nsIBindingManager, nsIStyleRuleSupplier,
nsIMutationObserver)
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.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
nsBindingManager::nsBindingManager(void)

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

@ -47,6 +47,7 @@
#include "nsInterfaceHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsURIHashKey.h"
#include "nsCycleCollectionParticipant.h"
class nsIContent;
class nsIXPConnectWrappedJS;
@ -66,7 +67,7 @@ class nsBindingManager : public nsIBindingManager,
public nsIMutationObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER
nsBindingManager();
@ -138,6 +139,8 @@ public:
RuleProcessorData* aData,
PRBool* aCutOffInheritance);
NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
protected:
nsresult GetXBLChildNodesInternal(nsIContent* aContent,
nsIDOMNodeList** aResult,

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

@ -104,8 +104,6 @@
#include "prprf.h"
#include "nsNodeUtils.h"
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
// Helper classes
/***********************************************************************/
@ -1178,9 +1176,8 @@ nsXBLBinding::InitClass(const nsCString& aClassName,
if (doc) {
nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
do_QueryInterface(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 */
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)
: mDocument(aDocument),

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

@ -39,6 +39,7 @@
#include "nsIScriptGlobalObjectOwner.h"
#include "nsWeakReference.h"
#include "nsIDocument.h"
#include "nsCycleCollectionParticipant.h"
class nsXBLPrototypeBinding;
class nsObjectHashtable;
@ -46,7 +47,7 @@ class nsObjectHashtable;
class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsIScriptGlobalObjectOwner, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
nsXBLDocumentInfo(nsIDocument* aDocument);
virtual ~nsXBLDocumentInfo();
@ -67,6 +68,8 @@ public:
// nsIScriptGlobalObjectOwner methods
virtual nsIScriptGlobalObject* GetScriptGlobalObject();
NS_DECL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
private:
nsCOMPtr<nsIDocument> mDocument;
PRPackedBool mScriptAccess;

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

@ -48,8 +48,6 @@
#include "nsIXBLDocumentInfo.h"
#include "nsIDOMNode.h"
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
nsresult
nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement)
{
@ -150,9 +148,8 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
nsIDocument* doc = aBoundElement->GetOwnerDoc();
if (doc) {
nsCOMPtr<nsIXPConnectWrappedNative> nativeWrapper(do_QueryInterface(wrapper));
if (nativeWrapper) {
NS_DOMClassInfo_PreserveNodeWrapper(nativeWrapper);
}
if (nativeWrapper)
doc->AddReference(aBoundElement, nativeWrapper);
}
wrapper.swap(*aScriptObjectHolder);

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

@ -753,6 +753,10 @@ nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
nsCOMPtr<nsIContent> templParent = aTemplChild->GetParent();
nsCOMPtr<nsIContent> childPoint;
// We may be disconnected from our parent during cycle collection.
if (!templParent)
return nsnull;
if (aBoundElement) {
if (templParent->NodeInfo()->Equals(nsGkAtoms::children,

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

@ -41,16 +41,15 @@
#define nsPIWindowRoot_h__
#include "nsISupports.h"
#include "nsIDOMGCParticipant.h"
class nsIFocusController;
// a22236a5-db06-4653-94b6-c4b6068e053c
// c18dee5a-dcf9-4391-a20c-581e769d095e
#define NS_IWINDOWROOT_IID \
{ 0xa22236a5, 0xdb06, 0x4653, \
{ 0x94, 0xb6, 0xc4, 0xb6, 0x06, 0x8e, 0x05, 0x3c } }
{ 0xc18dee5a, 0xdcf9, 0x4391, \
{ 0xa2, 0x0c, 0x58, 0x1e, 0x76, 0x9d, 0x09, 0x5e } }
class nsPIWindowRoot : public nsIDOMGCParticipant {
class nsPIWindowRoot : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)

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

@ -59,26 +59,9 @@ public:
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
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()
@ -98,20 +81,13 @@ public:
virtual void SetEventName(nsIAtom* aName) = 0;
#ifdef NS_DEBUG
static PRInt32 sNumJSEventListeners;
#endif
protected:
virtual ~nsIJSEventListener()
{
#ifdef NS_DEBUG
PR_AtomicDecrement(&sNumJSEventListeners);
#endif
}
nsCOMPtr<nsIScriptContext> mContext;
void *mScopeObject;
nsISupports *mTarget; // weak ref.
nsCOMPtr<nsISupports> mTarget;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)

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

@ -433,27 +433,20 @@ static const char kDOMStringBundleURL[] =
// NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
// are defined in nsIDOMClassInfo.h.
#define GCPARTICIPANT_SCRIPTABLE_FLAGS \
(DOM_DEFAULT_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_MARK)
#define WINDOW_SCRIPTABLE_FLAGS \
(nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
nsIXPCScriptable::WANT_DELPROPERTY | \
nsIXPCScriptable::WANT_NEWENUMERATE | \
nsIXPCScriptable::WANT_MARK | \
nsIXPCScriptable::WANT_EQUALITY | \
nsIXPCScriptable::WANT_OUTER_OBJECT | \
nsIXPCScriptable::WANT_INNER_OBJECT | \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
#define NODE_SCRIPTABLE_FLAGS \
((GCPARTICIPANT_SCRIPTABLE_FLAGS | \
((DOM_DEFAULT_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
@ -824,8 +817,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// DOM Traversal classes
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGCParticipantSH,
GCPARTICIPANT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// We are now trying to preserve binary compat in classinfo. No
// more putting things in those categories up there. New entries
@ -1130,7 +1123,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
// event listeners.
// We really don't want any of the default flags!
NS_DEFINE_CLASSINFO_DATA(WindowRoot, nsEventReceiverSH,
nsIXPCScriptable::WANT_MARK)
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DOMParser, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1139,8 +1132,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsDOMGCParticipantSH,
GCPARTICIPANT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// Define MOZ_SVG_FOREIGNOBJECT here so that when it gets switched on,
// we preserve binary compatibility. New classes should be added
@ -3671,24 +3664,6 @@ nsDOMClassInfo::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
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
nsIClassInfo *
nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoID aID)
@ -3744,24 +3719,36 @@ nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoData* aData)
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
void
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) {
PRUint32 i;
@ -5032,527 +5019,6 @@ nsDOMConstructor::ToString(nsAString &aResult)
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");
NS_ASSERTION(sExternallyReferencedTable.ops, "unbalanced call");
if (sExternallyReferencedTable.ops) {
#ifdef DEBUG
PRUint32 count = sExternallyReferencedTable.entryCount;
#endif
PL_DHashTableOperate(&sExternallyReferencedTable, aParticipant,
PL_DHASH_REMOVE);
#ifdef DEBUG
NS_ASSERTION(count == sExternallyReferencedTable.entryCount + 1,
"unbalanced call");
#endif
}
// 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
nsresult
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
@ -6869,11 +6335,7 @@ NS_IMETHODIMP
nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
{
// This can fail on out-of-memory, which should end up throwing a JS
// exception.
nsresult rv = nsDOMClassInfo::PreserveNodeWrapper(wrapper);
NS_ENSURE_SUCCESS(rv, rv);
nsDOMClassInfo::PreserveNodeWrapper(wrapper);
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval);
}
@ -7167,12 +6629,10 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsval id,
PRUint32 flags, JSObject **objp, PRBool *_retval)
{
if (id == sOnload_id || id == sOnerror_id) {
// Pass true for aRootWhenExternallyReferenced, so we make sure that
// this node can't go away while waiting for a network load that
// could fire an event handler.
nsresult rv = nsDOMClassInfo::PreserveNodeWrapper(wrapper, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
if (id == sOnload_id || id == sOnerror_id) {
// Make sure that this node can't go away while waiting for a
// network load that could fire an event handler.
nsDOMClassInfo::PreserveNodeWrapper(wrapper);
}
if (!JSVAL_IS_STRING(id)) {
@ -7223,8 +6683,8 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
*objp = obj;
}
return nsDOMGCParticipantSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
NS_IMETHODIMP
@ -7253,30 +6713,6 @@ nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper,
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

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

@ -51,10 +51,8 @@ class nsIDOMWindow;
class nsIDOMNSHTMLOptionCollection;
class nsIPluginInstance;
class nsIForm;
class nsIDOMNode;
class nsIDOMNodeList;
class nsIDOMDocument;
class nsIDOMGCParticipant;
class nsIHTMLDocument;
class nsGlobalWindow;
@ -175,87 +173,7 @@ public:
::JS_GetClass(cx, obj) == sXPCNativeWrapperClass;
}
/**
* 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();
static nsresult PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
protected:
const nsDOMClassInfoData* mData;
@ -407,39 +325,14 @@ public:
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
// all objects that should support things like
// obj.onclick=function{...}
class nsEventReceiverSH : public nsDOMGCParticipantSH
class nsEventReceiverSH : public nsDOMGenericSH
{
protected:
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGCParticipantSH(aData)
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
{
}

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

@ -642,6 +642,7 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
// nsGlobalWindow::nsISupports
//*****************************************************************************
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
// QueryInterface implementation for nsGlobalWindow
NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
@ -654,7 +655,6 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
@ -664,12 +664,105 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsGlobalWindow)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsGlobalWindow)
NS_IMPL_RELEASE(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
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
//*****************************************************************************
@ -5432,37 +5525,6 @@ nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
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
//*****************************************************************************

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

@ -50,6 +50,7 @@
#include "nsWeakReference.h"
#include "nsHashtable.h"
#include "nsDataHashtable.h"
#include "nsCycleCollectionParticipant.h"
// Interfaces Needed
#include "nsDOMWindowList.h"
@ -91,7 +92,6 @@
#include "nsSize.h"
#include "mozFlushType.h"
#include "prclist.h"
#include "nsIDOMGCParticipant.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageList.h"
#include "nsIDOMStorageWindow.h"
@ -217,7 +217,6 @@ class nsGlobalWindow : public nsPIDOMWindow,
public nsIDOMJSWindow,
public nsIScriptObjectPrincipal,
public nsIDOMEventReceiver,
public nsIDOMGCParticipant,
public nsIDOM3EventTarget,
public nsIDOMNSEventTarget,
public nsIDOMViewCSS,
@ -233,7 +232,7 @@ public:
void ReallyCloseWindow();
// nsISupports
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
// nsIScriptGlobalObject
virtual nsIScriptContext *GetContext();
@ -288,10 +287,6 @@ public:
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
// nsIDOMGCParticipant
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
// nsPIDOMWindow
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
virtual NS_HIDDEN_(nsresult) Activate();
@ -407,6 +402,8 @@ public:
friend class WindowStateHolder;
NS_DECL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
protected:
// Object Management
virtual ~nsGlobalWindow();

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

@ -82,7 +82,6 @@
#include "nsContentUtils.h"
#include "jscntxt.h"
#include "nsEventDispatcher.h"
#include "nsIDOMGCParticipant.h"
#include "nsIContent.h"
// For locale aware string methods
@ -3173,14 +3172,6 @@ DOMGCCallback(JSContext *cx, JSGCStatus status)
if (status == JSGC_BEGIN && !NS_IsMainThread())
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;
}

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

@ -55,9 +55,6 @@
#include "nsIXPConnect.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsIDOMGCParticipant.h"
#include "nsIWeakReference.h"
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
@ -196,101 +193,3 @@ nsJSUtils::GetDynamicScriptContext(JSContext *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 "jsapi.h"
#include "nsString.h"
#include "nsCOMPtr.h"
class nsIDOMEventListener;
class nsIScriptContext;
class nsIScriptGlobalObject;
class nsIDOMGCParticipant;
class nsIXPConnectJSObjectHolder;
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__ */

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

@ -52,8 +52,10 @@
#include "nsIDOMWindowInternal.h"
#include "nsFocusController.h"
#include "nsString.h"
#include "nsDOMClassInfo.h"
#include "nsEventDispatcher.h"
#include "nsIProgrammingLanguage.h"
#include "nsCycleCollectionParticipant.h"
static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID);
@ -65,10 +67,10 @@ nsWindowRoot::nsWindowRoot(nsIDOMWindow* aWindow)
nsFocusController::Create(getter_AddRefs(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("blur"), focusListener, PR_TRUE);
--mRefCnt;
mRefCnt.decr(NS_STATIC_CAST(nsIDOMEventReceiver*, this));
}
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_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
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_IMPL_ADDREF(nsWindowRoot)
NS_IMPL_RELEASE(nsWindowRoot)
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsWindowRoot, nsIDOMEventReceiver)
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsWindowRoot, nsIDOMEventReceiver)
NS_IMETHODIMP
nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
@ -234,16 +238,6 @@ nsWindowRoot::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
return NS_ERROR_FAILURE;
}
nsIDOMGCParticipant*
nsWindowRoot::GetSCCIndex()
{
return this;
}
void
nsWindowRoot::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
{
}
NS_IMETHODIMP
nsWindowRoot::PreHandleChromeEvent(nsEventChainPreVisitor& aVisitor)

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

@ -55,6 +55,7 @@ class nsEventChainPostVisitor;
#include "nsPIWindowRoot.h"
#include "nsIFocusController.h"
#include "nsIDOMEventTarget.h"
#include "nsCycleCollectionParticipant.h"
class nsWindowRoot : public nsIDOMEventReceiver,
public nsIDOM3EventTarget,
@ -66,7 +67,7 @@ public:
nsWindowRoot(nsIDOMWindow* aWindow);
virtual ~nsWindowRoot();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSIDOM3EVENTTARGET
NS_DECL_NSIDOMNSEVENTTARGET
@ -81,13 +82,11 @@ public:
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
// nsIDOMGCParticipant
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
// nsPIWindowRoot
NS_IMETHOD GetFocusController(nsIFocusController** aResult);
NS_DECL_CYCLE_COLLECTION_CLASS(nsWindowRoot)
protected:
// Members
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
PRInt32 nsIJSEventListener::sNumJSEventListeners = 0;
class EventListenerCounter
{
public:
~EventListenerCounter() {
if (nsIJSEventListener::sNumJSEventListeners) {
PR_fprintf(PR_STDERR,"WARNING: LEAKED %d nsIJSEventListeners\n",
nsIJSEventListener::sNumJSEventListeners);
}
}
};
@ -93,15 +87,17 @@ nsJSEventListener::~nsJSEventListener()
mContext->DropScriptObject(mScopeObject);
}
NS_IMPL_CYCLE_COLLECTION_1_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener, mTarget)
NS_INTERFACE_MAP_BEGIN(nsJSEventListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(nsJSEventListener)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsJSEventListener)
NS_IMPL_RELEASE(nsJSEventListener)
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSEventListener, nsIDOMEventListener)
//static nsString onPrefix = "on";
@ -276,4 +272,3 @@ NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
return NS_OK;
}

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

@ -45,6 +45,7 @@
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsIScriptContext.h"
#include "nsCycleCollectionParticipant.h"
// nsJSEventListener interface
// misnamed - JS no longer has exclusive rights over this interface!
@ -56,7 +57,7 @@ public:
nsISupports* aObject);
virtual ~nsJSEventListener();
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
// nsIDOMEventListener interface
NS_DECL_NSIDOMEVENTLISTENER
@ -64,6 +65,7 @@ public:
// nsIJSEventListener interface
virtual void SetEventName(nsIAtom* aName);
NS_DECL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
protected:
nsCOMPtr<nsIAtom> mEventName;

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

@ -1982,6 +1982,13 @@ JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
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_IsAboutToBeFinalized(JSContext *cx, void *thing)
{

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

@ -869,6 +869,9 @@ JS_SetGCCallback(JSContext *cx, JSGCCallback cb);
extern JS_PUBLIC_API(JSGCCallback)
JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
extern JS_PUBLIC_API(void)
JS_SetGCThingCallback(JSContext *cx, JSGCThingCallback cb, void *closure);
extern JS_PUBLIC_API(JSBool)
JS_IsAboutToBeFinalized(JSContext *cx, void *thing);

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

@ -198,6 +198,8 @@ struct JSRuntime {
uint16 gcPadding;
JSGCCallback gcCallback;
JSGCThingCallback gcThingCallback;
void *gcThingCallbackClosure;
uint32 gcMallocBytes;
JSGCArena *gcUnscannedArenaStackTop;
#ifdef DEBUG

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

@ -2103,9 +2103,13 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp,
if (!JSVAL_IS_GCTHING(v) || v == JSVAL_NULL)
continue;
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)
continue;
next_flagp = js_GetGCThingFlags(next_thing);
if (*next_flagp & GCF_MARK)
continue;
JS_ASSERT(*next_flagp != GCF_FINAL);
@ -2158,6 +2162,10 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp,
break;
thing = JSSTRDEP_BASE(str);
flagp = js_GetGCThingFlags(thing);
if (rt->gcThingCallback) {
rt->gcThingCallback(thing, *flagp,
rt->gcThingCallbackClosure);
}
if (*flagp & GCF_MARK)
break;
#ifdef GC_MARK_DEBUG
@ -2468,6 +2476,12 @@ js_MarkGCThing(JSContext *cx, void *thing)
flagp = js_GetGCThingFlags(thing);
JS_ASSERT(*flagp != GCF_FINAL);
if (cx->runtime->gcThingCallback) {
cx->runtime->gcThingCallback(thing, *flagp,
cx->runtime->gcThingCallbackClosure);
}
if (*flagp & GCF_MARK)
return;
*flagp |= GCF_MARK;

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

@ -39,6 +39,8 @@
#ifndef jslock_h__
#define jslock_h__
JS_BEGIN_EXTERN_C
#ifdef JS_THREADSAFE
#include "jstypes.h"
@ -263,4 +265,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_UNLOCK(P,CX) JS_UNLOCK0(P, CX_THINLOCK_ID(CX))
JS_END_EXTERN_C
#endif /* jslock_h___ */

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

@ -569,6 +569,9 @@ typedef enum JSGCStatus {
typedef JSBool
(* JS_DLL_CALLBACK JSGCCallback)(JSContext *cx, JSGCStatus status);
typedef void
(* JS_DLL_CALLBACK JSGCThingCallback)(void *thing, uint8 flags, void *closure);
typedef JSBool
(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);

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

@ -50,7 +50,6 @@
#include "nsIInterfaceInfoManager.idl"
#include "nsIExceptionService.idl"
#include "nsIVariant.idl"
#include "nsIWeakReference.idl"
%{ C++
#include "jspubtd.h"
@ -149,6 +148,10 @@ interface nsIInterfaceInfo;
interface nsIXPCSecurityManager;
interface nsIPrincipal;
%{C++
struct nsCycleCollectionTraversalCallback;
%}
/***************************************************************************/
[uuid(8916a320-d118-11d3-8f3a-0010a4e73d9a)]
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
{
/* attribute 'JSObject' inherited from nsIXPConnectJSObjectHolder */
@ -242,26 +245,6 @@ interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
void aggregatedQueryInterface(in nsIIDRef uuid,
[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 "XPCNativeWrapper.h"
#include "nsBaseHashtable.h"
#include "nsHashKeys.h"
#include "jsobj.h"
NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference)
@ -66,7 +69,8 @@ nsXPConnect::nsXPConnect()
mContextStack(nsnull),
mDefaultSecurityManager(nsnull),
mDefaultSecurityManagerFlags(0),
mShuttingDown(JS_FALSE)
mShuttingDown(JS_FALSE),
mObjRefcounts(nsnull)
{
// Ignore the result. If the runtime service is not ready to rumble
// then we'll set this up later as needed.
@ -74,6 +78,8 @@ nsXPConnect::nsXPConnect()
CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
#ifdef XPC_TOOLS_SUPPORT
{
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);
}
PRBool Get(void *obj, PRUint32 &refcount)
{
return mRefCounts.Get(obj, &refcount);
}
};
nsXPConnect::~nsXPConnect()
{
// 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
// 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;
{ // scoped callcontext
XPCCallContext ccx(NATIVE_CALLER);
@ -386,6 +430,130 @@ nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
return FindInfo(NameTester, name, mInterfaceInfoManager, info);
}
void XPCMarkNotification(void *thing, uint8 flags, void *closure)
{
uint8 ty = flags & GCF_TYPEMASK;
if (ty != GCX_OBJECT &&
ty != GCX_PRIVATE &&
ty != GCX_XML)
return;
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;
if (!mObjRefcounts->Get(p, refcount))
return NS_OK;
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 (uint32 i = JSSLOT_START(OBJ_GET_CLASS(cx, obj));
i < STOBJ_NSLOTS(obj); ++i)
{
jsval val = STOBJ_GET_SLOT(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...

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

@ -53,6 +53,8 @@
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCycleCollector.h"
#include "nsISupports.h"
#include "nsIServiceManager.h"
#include "nsIClassInfoImpl.h"
@ -420,9 +422,11 @@ private:
const PRBool OBJ_IS_GLOBAL = PR_TRUE;
const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
struct JSObjectRefcounts;
class nsXPConnect : public nsIXPConnect,
public nsSupportsWeakReference
public nsSupportsWeakReference,
public nsCycleCollectionLanguageRuntime
{
public:
// all the interface method declarations...
@ -470,6 +474,14 @@ public:
nsresult GetInfoForIID(const nsIID * aIID, 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
public:
static PRBool IsIDispatchEnabled();
@ -494,6 +506,7 @@ private:
nsIXPCSecurityManager* mDefaultSecurityManager;
PRUint16 mDefaultSecurityManagerFlags;
JSBool mShuttingDown;
JSObjectRefcounts* mObjRefcounts;
#ifdef XPC_TOOLS_SUPPORT
nsCOMPtr<nsIXPCToolsProfiler> mProfiler;
@ -1833,9 +1846,10 @@ private:
class XPCWrappedNative : public nsIXPConnectWrappedNative
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
#ifndef XPCONNECT_STANDALONE
virtual nsIPrincipal* GetObjectPrincipal() const;
@ -2227,7 +2241,7 @@ private:
// interface on the single underlying (possibly aggregate) JSObject.
class nsXPCWrappedJS : protected nsAutoXPTCStub,
public nsWeakRefToIXPConnectWrappedJS,
public nsIXPConnectWrappedJS,
public nsSupportsWeakReference,
public nsIPropertyBag
{
@ -2235,8 +2249,9 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
NS_DECL_NSIXPCONNECTWRAPPEDJS
//NS_DECL_NSISUPPORTSWEAKREFERENCE // methods also on nsIXPConnectWrappedJS
NS_DECL_NSISUPPORTSWEAKREFERENCE
NS_DECL_NSIPROPERTYBAG
NS_DECL_CYCLE_COLLECTION_CLASS(nsXPCWrappedJS)
NS_IMETHOD CallMethod(PRUint16 methodIndex,
const XPTMethodDescriptor *info,

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

@ -45,6 +45,56 @@
// 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
nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
{
@ -79,6 +129,11 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
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
// from us without recurring into a call to the outer's QI!
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
@ -88,13 +143,6 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
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();
if(outer)
return outer->QueryInterface(aIID, aInstancePtr);
@ -196,7 +244,10 @@ do_decrement:
NS_IMETHODIMP
nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
{
return mRoot->nsSupportsWeakReference::GetWeakReference(aInstancePtr);
if(mRoot != this)
return mRoot->GetWeakReference(aInstancePtr);
return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
}
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
static void DEBUG_CheckClassInfoClaims(XPCWrappedNative* wrapper);
#else
@ -828,6 +874,7 @@ NS_INTERFACE_MAP_BEGIN(XPCWrappedNative)
NS_INTERFACE_MAP_ENTRY(nsIXPConnectWrappedNative)
NS_INTERFACE_MAP_ENTRY(nsIXPConnectJSObjectHolder)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPConnectWrappedNative)
NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(XPCWrappedNative)
NS_INTERFACE_MAP_END_THREADSAFE
NS_IMPL_THREADSAFE_ADDREF(XPCWrappedNative)

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

@ -64,6 +64,8 @@ CPPSRCS = \
nsInterfaceRequestorAgg.cpp \
nsUUIDGenerator.cpp \
nsSystemInfo.cpp \
nsCycleCollector.cpp \
nsCycleCollectionParticipant.cpp \
$(NULL)
ifdef GC_LEAK_DETECTOR
@ -115,6 +117,8 @@ SDK_HEADERS = \
nsError.h \
nsISupportsBase.h \
nscore.h \
nsCycleCollector.h \
nsCycleCollectionParticipant.h
XPIDLSRCS = \
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 "nsStringBuffer.h"
#include "nsCategoryCache.h"
#include "nsCycleCollectionParticipant.h"
#include "nsThreadUtils.h"
#if !defined(WINCE) && !defined(XP_OS2)
@ -270,6 +271,8 @@ void XXXNeverCalled()
b.ToString(0, y);
}
nsCycleCollectionParticipant();
#if !defined(WINCE) && !defined(XP_OS2)
NS_NewWindowsRegKey(nsnull);
#endif

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

@ -226,6 +226,42 @@ private:
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
*

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

@ -62,6 +62,7 @@
#include "nsDebug.h"
#include "nsTraceRefcnt.h"
#include "nsCycleCollector.h"
////////////////////////////////////////////////////////////////////////////////
// Macros to help detect thread-safety:
@ -88,6 +89,109 @@ private:
#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 {
public:
@ -126,6 +230,17 @@ protected: \
NS_DECL_OWNINGTHREAD \
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 "nsAutoPtr.h"
#include "prlog.h"
#include "nsThreadUtils.h"
#include "nsCycleCollector.h"
#ifdef PR_LOGGING
static PRLogModuleInfo *sLog = PR_NewLogModule("nsEventQueue");
@ -64,31 +66,37 @@ nsEventQueue::~nsEventQueue()
PRBool
nsEventQueue::GetEvent(PRBool mayWait, nsIRunnable **result)
{
nsAutoMonitor mon(mMonitor);
while (IsEmpty()) {
if (!mayWait) {
if (result)
*result = nsnull;
return PR_FALSE;
{
nsAutoMonitor mon(mMonitor);
while (IsEmpty()) {
if (!mayWait) {
if (result)
*result = nsnull;
return PR_FALSE;
}
LOG(("EVENTQ(%p): wait begin\n", this));
mon.Wait();
LOG(("EVENTQ(%p): wait end\n", this));
}
LOG(("EVENTQ(%p): wait begin\n", this));
mon.Wait();
LOG(("EVENTQ(%p): wait end\n", this));
}
if (result) {
*result = mHead->mEvents[mOffsetHead++];
// Check if mHead points to empty Page
if (mOffsetHead == EVENTS_PER_PAGE) {
Page *dead = mHead;
mHead = mHead->mNext;
FreePage(dead);
mOffsetHead = 0;
if (result) {
*result = mHead->mEvents[mOffsetHead++];
// Check if mHead points to empty Page
if (mOffsetHead == EVENTS_PER_PAGE) {
Page *dead = mHead;
mHead = mHead->mNext;
FreePage(dead);
mOffsetHead = 0;
}
}
}
if (NS_IsMainThread()) {
nsCycleCollector_collect();
}
return PR_TRUE;
}