Fix for bug 368774 (Make cycle collector work with refcounted non-XPCOM objects). r=dbaron, sr=sicking.

This commit is contained in:
peterv@propagandism.org 2007-05-24 07:10:02 -07:00
Родитель c5b4f250f3
Коммит 418a6ec9e1
32 изменённых файлов: 572 добавлений и 326 удалений

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

@ -996,6 +996,10 @@ public:
}
return rv;
}
void traverse(nsCycleCollectionTraversalCallback &cb)
{
cb.NoteScriptChild(mLangID, mObject);
}
PRUint32 mLangID;
void *mObject;
};

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

@ -1062,7 +1062,7 @@ NS_NewHTML##_elementName##Element(nsINodeInfo *aNodeInfo, PRBool aFromParser)\
{ \
NS_ENSURE_ARG_POINTER(aInstancePtr); \
\
if ( aIID.Equals(NS_GET_IID(nsCycleCollectionParticipant)) ) { \
if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \
*aInstancePtr = &NS_CYCLE_COLLECTION_NAME(_class); \
return NS_OK; \
} \

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

@ -87,12 +87,14 @@
// = nsAnonymousContentList
// ==================================================================
class nsAnonymousContentList : public nsGenericDOMNodeList
class nsAnonymousContentList : public nsIDOMNodeList
{
public:
nsAnonymousContentList(nsInsertionPointList* aElements);
virtual ~nsAnonymousContentList();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsAnonymousContentList)
// nsIDOMNodeList interface
NS_DECL_NSIDOMNODELIST
@ -120,6 +122,29 @@ nsAnonymousContentList::~nsAnonymousContentList()
delete mElements;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsAnonymousContentList)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
NS_INTERFACE_MAP_BEGIN(nsAnonymousContentList)
NS_INTERFACE_MAP_ENTRY(nsIDOMNodeList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NodeList)
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsAnonymousContentList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsAnonymousContentList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAnonymousContentList)
{
PRInt32 i, count = tmp->mElements->Length();
for (i = 0; i < count; ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mElements->ElementAt(i),
nsXBLInsertionPoint);
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMETHODIMP
nsAnonymousContentList::GetLength(PRUint32* aLength)
{
@ -309,7 +334,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
PL_DHashTableFinish(&(tmp->mWrapperTable));
tmp->mWrapperTable.ops = nsnull;
tmp->mAttachedStack.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mAttachedStack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -341,6 +366,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
tmp->mDocumentTable.EnumerateRead(&DocumentInfoHashtableTraverser, &cb);
if (tmp->mLoadingDocTable.IsInitialized())
tmp->mLoadingDocTable.EnumerateRead(&LoadingDocHashtableTraverser, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mAttachedStack,
nsXBLBinding)
// No need to traverse mProcessAttachedQueueEvent, since it'll just
// fire at some point.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -1365,9 +1392,8 @@ nsBindingManager::Traverse(nsIContent *aContent,
nsXBLBinding *binding = GetBinding(aContent);
if (binding) {
// XXX nsXBLBinding isn't nsISupports but it is refcounted, so we can't
// traverse it.
cb.NoteXPCOMChild(aContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(binding, nsXBLBinding)
}
nsISupports *value;
if (mContentListTable.ops &&

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

@ -173,6 +173,36 @@ nsXBLBinding::~nsXBLBinding(void)
NS_RELEASE(info);
}
PR_STATIC_CALLBACK(PLDHashOperator)
TraverseKey(nsISupports* aKey, nsInsertionPointList* aData, void* aClosure)
{
nsCycleCollectionTraversalCallback &cb =
*NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, aClosure);
cb.NoteXPCOMChild(aKey);
if (aData) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(*aData, nsXBLInsertionPoint)
}
return PL_DHASH_NEXT;
}
NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLBinding)
// XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
// mPrototypeBinding is weak.
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContent)
// XXX What about mNextBinding and mInsertionPointTable?
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLBinding)
cb.NoteXPCOMChild(tmp->mPrototypeBinding->XBLDocumentInfo());
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNextBinding, nsXBLBinding)
if (tmp->mInsertionPointTable)
tmp->mInsertionPointTable->EnumerateRead(TraverseKey, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLBinding, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLBinding, Release)
void
nsXBLBinding::SetBaseBinding(nsXBLBinding* aBinding)
{

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

@ -45,6 +45,7 @@
#include "nsIStyleRuleProcessor.h"
#include "nsClassHashtable.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
class nsXBLPrototypeBinding;
class nsIContent;
@ -95,6 +96,8 @@ public:
return mRefCnt;
}
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
nsXBLPrototypeBinding* PrototypeBinding() { return mPrototypeBinding; }
nsIContent* GetAnonymousContent() { return mContent.get(); }

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

@ -64,6 +64,20 @@ nsXBLInsertionPoint::Release()
return mRefCnt;
}
NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPoint)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPoint)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDefaultContentTemplate)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDefaultContent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLInsertionPoint)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDefaultContentTemplate)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDefaultContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLInsertionPoint, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLInsertionPoint, Release)
already_AddRefed<nsIContent>
nsXBLInsertionPoint::GetInsertionParent()
{

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

@ -42,6 +42,7 @@
#include "nsCOMArray.h"
#include "nsIContent.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
class nsXBLInsertionPoint
{
@ -59,6 +60,8 @@ public:
nsrefcnt Release();
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPoint)
already_AddRefed<nsIContent> GetInsertionParent();
PRInt32 GetInsertionIndex() { return mIndex; }

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

@ -198,6 +198,15 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding)
return NS_OK;
}
void
nsXBLProtoImpl::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
nsXBLProtoImplMember *member;
for (member = mMembers; member; member = member->GetNext()) {
member->Traverse(cb);
}
}
void
nsXBLProtoImpl::DestroyMembers(nsXBLProtoImplMember* aBrokenMember)
{

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

@ -76,6 +76,8 @@ public:
void SetMemberList(nsXBLProtoImplMember* aMemberList) { delete mMembers; mMembers = aMemberList; }
void Traverse(nsCycleCollectionTraversalCallback &cb) const;
protected:
// Function to call if compilation of a member fails. When this is called,
// all members before aBrokenMember are compiled, compilation of

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

@ -151,3 +151,8 @@ nsXBLProtoImplField::CompileMember(nsIScriptContext* aContext, const nsCString&
{
return NS_OK;
}
void
nsXBLProtoImplField::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
}

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

@ -67,6 +67,8 @@ public:
const nsCString& aClassStr,
void* aClassObject);
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
protected:
PRUnichar* mFieldText;
PRUint32 mFieldTextLength;

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

@ -51,6 +51,7 @@
class nsIScriptContext;
struct JSRuntime;
class nsIJSRuntimeService;
struct nsCycleCollectionTraversalCallback;
struct nsXBLTextWithLineNumber
{
@ -113,6 +114,8 @@ public:
const nsCString& aClassStr,
void* aClassObject)=0;
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const = 0;
protected:
friend class nsAutoGCRoot;

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

@ -276,6 +276,14 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
return rv;
}
void
nsXBLProtoImplMethod::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
if (mIsCompiled) {
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject);
}
}
nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{

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

@ -129,6 +129,8 @@ public:
const nsCString& aClassStr,
void* aClassObject);
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
protected:
union {
nsXBLUncompiledMethod* mUncompiledMethod; // An object that represents the method before being compiled.

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

@ -343,3 +343,15 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
return rv;
}
void
nsXBLProtoImplProperty::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
if (mJSAttributes & JSPROP_GETTER) {
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject);
}
if (mJSAttributes & JSPROP_SETTER) {
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject);
}
}

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

@ -72,6 +72,8 @@ public:
const nsCString& aClassStr,
void* aClassObject);
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
protected:
union {
// The raw text for the getter (prior to compilation).

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

@ -147,7 +147,9 @@ public:
mDefaultContent->UnbindFromTree();
}
}
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPointEntry)
nsIContent* GetInsertionParent() { return mInsertionParent; }
PRUint32 GetInsertionIndex() { return mInsertionIndex; }
void SetInsertionIndex(PRUint32 aIndex) { mInsertionIndex = aIndex; }
@ -188,12 +190,11 @@ protected:
nsCOMPtr<nsIContent> mInsertionParent;
nsCOMPtr<nsIContent> mDefaultContent;
PRUint32 mInsertionIndex;
nsrefcnt mRefCnt;
nsAutoRefCnt mRefCnt;
nsXBLInsertionPointEntry(nsIContent* aParent)
: mInsertionParent(aParent),
mInsertionIndex(0),
mRefCnt(0) { }
mInsertionIndex(0) { }
private:
// Hide so that only Create() and Destroy() can be used to
@ -202,6 +203,24 @@ private:
static void operator delete(void*, size_t) {}
};
NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPointEntry)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPointEntry)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInsertionParent)
if (tmp->mDefaultContent) {
// mDefaultContent is a sort of anonymous content within the XBL
// document, and we own and manage it. Unhook it here, since we're going
// away.
tmp->mDefaultContent->UnbindFromTree();
tmp->mDefaultContent = nsnull;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLInsertionPointEntry)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInsertionParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDefaultContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLInsertionPointEntry, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLInsertionPointEntry, Release)
// =============================================================================
// Static initialization
@ -279,13 +298,39 @@ nsXBLPrototypeBinding::Init(const nsACString& aID,
return NS_OK;
}
PR_STATIC_CALLBACK(PRIntn)
TraverseInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
{
nsCycleCollectionTraversalCallback &cb =
*NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, aClosure);
nsXBLInsertionPointEntry* entry =
NS_STATIC_CAST(nsXBLInsertionPointEntry*, aData);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(entry,
nsXBLInsertionPointEntry)
return kHashEnumerateNext;
}
PR_STATIC_CALLBACK(PRBool)
TraverseBinding(nsHashKey *aKey, void *aData, void* aClosure)
{
nsCycleCollectionTraversalCallback *cb =
NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, aClosure);
cb->NoteXPCOMChild(NS_STATIC_CAST(nsISupports*, aData));
return kHashEnumerateNext;
}
void
nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
cb.NoteXPCOMChild(mBinding);
// XXX mInsertionPointTable!
if (mImplementation)
mImplementation->Traverse(cb);
if (mResources)
cb.NoteXPCOMChild(mResources->mLoader);
if (mInsertionPointTable)
mInsertionPointTable->Enumerate(TraverseInsertionPoint, &cb);
if (mInterfaceTable)
mInterfaceTable->Enumerate(TraverseBinding, &cb);
}
void

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

@ -353,6 +353,13 @@ NS_NewXULElement(nsIContent** aResult, nsINodeInfo *aNodeInfo)
//----------------------------------------------------------------------
// nsISupports interface
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
nsGenericElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPrototype,
nsXULPrototypeElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsXULElement, nsGenericElement)
NS_IMPL_RELEASE_INHERITED(nsXULElement, nsGenericElement)
@ -362,6 +369,10 @@ nsXULElement::QueryInterface(REFNSIID aIID, void** aInstancePtr)
NS_ENSURE_ARG_POINTER(aInstancePtr);
*aInstancePtr = nsnull;
if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {
*aInstancePtr = &NS_CYCLE_COLLECTION_NAME(nsXULElement);
return NS_OK;
}
nsresult rv = nsGenericElement::QueryInterface(aIID, aInstancePtr);
if (NS_SUCCEEDED(rv))
@ -2278,6 +2289,29 @@ nsXULElement::RecompileScriptEventListeners()
}
}
NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXULPrototypeNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsXULPrototypeNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode)
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
nsXULPrototypeElement *elem =
NS_STATIC_CAST(nsXULPrototypeElement*, tmp);
PRUint32 i;
for (i = 0; i < elem->mNumAttributes; ++i) {
cb.NoteScriptChild(elem->mScriptTypeID,
elem->mAttributes[i].mEventHandler);
}
for (i = 0; i < elem->mNumChildren; ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(elem->mChildren[i],
nsXULPrototypeNode)
}
}
else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
NS_STATIC_CAST(nsXULPrototypeScript*, tmp)->mScriptObject.traverse(cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release)
//----------------------------------------------------------------------
//
// nsXULPrototypeAttribute

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

@ -193,7 +193,7 @@ public:
Type mType;
PRInt32 mRefCnt;
nsAutoRefCnt mRefCnt;
virtual ~nsXULPrototypeNode() {}
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
@ -222,6 +222,8 @@ public:
}
virtual void ReleaseSubtree() { Release(); }
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXULPrototypeNode)
protected:
nsXULPrototypeNode(Type aType)
: mType(aType), mRefCnt(1) {}
@ -476,6 +478,8 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXULElement,
nsGenericElement)
// nsINode
virtual PRUint32 GetChildCount() const;

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

@ -240,13 +240,14 @@ XULContentSinkImpl::~XULContentSinkImpl()
nsXULPrototypeNode* child =
NS_REINTERPRET_CAST(nsXULPrototypeNode*, children->ElementAt(i));
delete child;
child->Release();
}
}
nsXULPrototypeNode* node;
rv = mContextStack.GetTopNode(&node);
if (NS_SUCCEEDED(rv)) delete node;
if (NS_SUCCEEDED(rv))
node->Release();
State state;
mContextStack.Pop(&state);
@ -761,7 +762,7 @@ XULContentSinkImpl::ReportError(const PRUnichar* aErrorText,
nsXULPrototypeNode* child =
NS_REINTERPRET_CAST(nsXULPrototypeNode*, children->ElementAt(i));
delete child;
child->Release();
}
}
@ -909,7 +910,7 @@ XULContentSinkImpl::OpenRoot(const PRUnichar** aAttributes,
// containers will hook up to us as their parent.
rv = mContextStack.Push(element, mState);
if (NS_FAILED(rv)) {
delete element;
element->Release();
return rv;
}

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

@ -196,8 +196,9 @@ nsXULPrototypeDocument::~nsXULPrototypeDocument()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULPrototypeDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
// XXX Can't traverse tmp->mRoot, non-XPCOM refcounted object
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mRoot,
nsXULPrototypeElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)

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

@ -599,59 +599,31 @@ nsXPConnect::FinishCycleCollection()
return NS_OK;
}
nsresult
nsXPConnect::Root(const nsDeque &nodes)
NS_IMETHODIMP
nsXPConnect::Root(void *p)
{
if(!mCycleCollectionContext)
if(!mCycleCollectionContext ||
!JS_LockGCThing(*mCycleCollectionContext, NS_STATIC_CAST(JSObject*, p)))
return NS_ERROR_FAILURE;
JSContext *cx = mCycleCollectionContext->GetJSContext();
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)
NS_IMETHODIMP
nsXPConnect::Unlink(void *p)
{
if(!mCycleCollectionContext)
return NS_ERROR_FAILURE;
JSContext *cx = mCycleCollectionContext->GetJSContext();
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);
}
JS_ClearScope(*mCycleCollectionContext, NS_STATIC_CAST(JSObject*, p));
return NS_OK;
}
nsresult
nsXPConnect::Unroot(const nsDeque &nodes)
NS_IMETHODIMP
nsXPConnect::Unroot(void *p)
{
if(!mCycleCollectionContext)
if(!mCycleCollectionContext ||
!JS_UnlockGCThing(*mCycleCollectionContext,
NS_STATIC_CAST(JSObject*, p)))
return NS_ERROR_FAILURE;
JSContext *cx = mCycleCollectionContext->GetJSContext();
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;
}
@ -671,8 +643,9 @@ TraverseJSScript(JSScript* script, nsCycleCollectionTraversalCallback& cb)
}
}
nsresult
nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
NS_IMETHODIMP
nsXPConnect::Traverse(void *p,
nsCycleCollectionTraversalCallback &cb)
{
if(!mCycleCollectionContext)
return NS_ERROR_FAILURE;

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

@ -427,7 +427,8 @@ struct JSObjectRefcounts;
class nsXPConnect : public nsIXPConnect,
public nsSupportsWeakReference,
public nsCycleCollectionLanguageRuntime
public nsCycleCollectionLanguageRuntime,
public nsCycleCollectionParticipant
{
public:
// all the interface method declarations...
@ -475,13 +476,16 @@ public:
nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
// from nsCycleCollectionLanguageRuntime
// from nsCycleCollectionLanguageRuntime and nsCycleCollectionParticipant
nsresult BeginCycleCollection();
nsresult Root(const nsDeque &nodes);
nsresult Unlink(const nsDeque &nodes);
nsresult Unroot(const nsDeque &nodes);
nsresult Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
NS_IMETHOD Root(void *p);
NS_IMETHOD Unlink(void *p);
NS_IMETHOD Unroot(void *p);
NS_IMETHOD Traverse(void *p,
nsCycleCollectionTraversalCallback &cb);
nsresult FinishCycleCollection();
nsCycleCollectionParticipant *ToParticipant(void *p) {return this;}
JSObjectRefcounts* GetJSObjectRefcounts() {return mObjRefcounts;}
#ifndef XPCONNECT_STANDALONE
void RecordTraversal(void *p, nsISupports *s);

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

@ -49,7 +49,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsXPCWrappedJS)
NS_IMETHODIMP
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
(nsISupports *s, nsCycleCollectionTraversalCallback &cb)
(void *p, 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.
@ -68,7 +68,8 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
{
// Put the nsCOMPtr in a local scope, to avoid messing up the refcount
// below.
nsCOMPtr<nsIXPConnectWrappedJS> owner = do_QueryInterface(s, &rv);
nsCOMPtr<nsIXPConnectWrappedJS> owner =
do_QueryInterface(NS_STATIC_CAST(nsISupports*, p), &rv);
if (NS_FAILED(rv))
return rv;
@ -112,7 +113,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
}
NS_IMETHODIMP
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Unlink(nsISupports *s)
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Unlink(void *p)
{
// NB: We might unlink our outgoing references in the future; for
// now we do nothing. This is a harmless conservative behavior; it
@ -156,7 +157,7 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
return NS_ERROR_NULL_POINTER;
}
if ( aIID.Equals(NS_GET_IID(nsCycleCollectionParticipant)) ) {
if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {
*aInstancePtr = & NS_CYCLE_COLLECTION_NAME(nsXPCWrappedJS);
return NS_OK;
}

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

@ -50,10 +50,10 @@
NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
NS_IMETHODIMP
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(nsISupports *s,
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
nsCycleCollectionTraversalCallback &cb)
{
XPCWrappedNative *tmp = NS_STATIC_CAST(XPCWrappedNative*, s);
XPCWrappedNative *tmp = NS_STATIC_CAST(XPCWrappedNative*, p);
if(!tmp->IsValid())
return NS_OK;
@ -113,7 +113,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(nsISupports *s,
}
NS_IMETHODIMP
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Unlink(nsISupports *s)
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Unlink(void *p)
{
// NB: We might unlink our outgoing references in the future; for
// now we do nothing. This is a harmless conservative behavior; it

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

@ -100,11 +100,11 @@ public: \
#define NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(_class) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsCycleCollectionParticipant \
: public nsXPCOMCycleCollectionParticipant \
{ \
public: \
NS_IMETHOD Unlink(nsISupports *p); \
NS_IMETHOD Traverse(nsISupports *p, \
NS_IMETHOD Unlink(void *p); \
NS_IMETHOD Traverse(void *p, \
nsCycleCollectionTraversalCallback &cb); \
NS_IMETHOD_(void) UnmarkPurple(nsISupports *p) \
{ \
@ -297,12 +297,13 @@ _class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr) \
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
(nsISupports *p, \
(void *p, \
nsCycleCollectionTraversalCallback &cb) \
{ \
NS_ASSERTION(CheckForRightISupports(p), \
nsISupports *s = NS_STATIC_CAST(nsISupports*, p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = NS_STATIC_CAST(_class*, Downcast(p)); \
_class *tmp = NS_STATIC_CAST(_class*, Downcast(s)); \
if (!tmp->IsPartOfAggregated()) \
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class)

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

@ -38,41 +38,43 @@
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
NS_INTERFACE_MAP_BEGIN(nsCycleCollectionParticipant)
NS_INTERFACE_MAP_ENTRY(nsCycleCollectionParticipant)
NS_INTERFACE_MAP_END
NS_IMETHODIMP_(nsrefcnt) nsCycleCollectionParticipant::AddRef(void)
NS_IMETHODIMP
nsXPCOMCycleCollectionParticipant::Root(void *p)
{
// Do nothing, it's a singleton.
return 1;
nsISupports *s = NS_STATIC_CAST(nsISupports*, p);
NS_ADDREF(s);
return NS_OK;
}
NS_IMETHODIMP_(nsrefcnt) nsCycleCollectionParticipant::Release(void)
{
// Do nothing, it's a singleton.
return 1;
}
NS_IMETHODIMP nsCycleCollectionParticipant::Unlink(nsISupports *n)
NS_IMETHODIMP
nsXPCOMCycleCollectionParticipant::Unlink(void *p)
{
return NS_OK;
}
NS_IMETHODIMP
nsXPCOMCycleCollectionParticipant::Unroot(void *p)
{
nsISupports *s = NS_STATIC_CAST(nsISupports*, p);
NS_RELEASE(s);
return NS_OK;
}
NS_IMETHODIMP
nsCycleCollectionParticipant::Traverse(nsISupports *n,
nsCycleCollectionTraversalCallback &cb)
nsXPCOMCycleCollectionParticipant::Traverse
(void *p, nsCycleCollectionTraversalCallback &cb)
{
return NS_OK;
}
NS_IMETHODIMP_(void) nsCycleCollectionParticipant::UnmarkPurple(nsISupports *n)
NS_IMETHODIMP_(void)
nsXPCOMCycleCollectionParticipant::UnmarkPurple(nsISupports *n)
{
}
#ifdef DEBUG
PRBool
nsCycleCollectionParticipant::CheckForRightISupports(nsISupports *s)
nsXPCOMCycleCollectionParticipant::CheckForRightISupports(nsISupports *s)
{
nsCOMPtr<nsISupports> foo;
s->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),

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

@ -78,6 +78,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionISupports,
#undef IMETHOD_VISIBILITY
#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT
struct nsCycleCollectionParticipant;
struct nsCycleCollectionTraversalCallback
{
// You must call DescribeNode() with an accurate refcount,
@ -91,18 +93,32 @@ struct nsCycleCollectionTraversalCallback
#endif
virtual void NoteScriptChild(PRUint32 langID, void *child) = 0;
virtual void NoteXPCOMChild(nsISupports *child) = 0;
virtual void NoteNativeChild(void *child,
nsCycleCollectionParticipant *helper) = 0;
};
class NS_COM nsCycleCollectionParticipant
: public nsISupports
class NS_NO_VTABLE nsCycleCollectionParticipant
{
public:
NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) = 0;
NS_IMETHOD Root(void *p) = 0;
NS_IMETHOD Unlink(void *p) = 0;
NS_IMETHOD Unroot(void *p) = 0;
};
class NS_COM nsXPCOMCycleCollectionParticipant
: public nsCycleCollectionParticipant
{
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_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
NS_IMETHOD Root(void *p);
NS_IMETHOD Unlink(void *p);
NS_IMETHOD Unroot(void *p);
NS_IMETHOD_(void) UnmarkPurple(nsISupports *p);
#ifdef DEBUG
@ -110,7 +126,7 @@ public:
#endif
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCycleCollectionParticipant,
NS_CYCLECOLLECTIONPARTICIPANT_IID)
#undef IMETHOD_VISIBILITY
@ -118,7 +134,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
///////////////////////////////////////////////////////////////////////////////
// Helpers for implementing a QI to nsCycleCollectionParticipant
// Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant
///////////////////////////////////////////////////////////////////////////////
#define NS_CYCLE_COLLECTION_INNERCLASS \
@ -131,8 +147,9 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
_class##_cycleCollectorGlobal
#define NS_IMPL_QUERY_CYCLE_COLLECTION(_class) \
if ( aIID.Equals(NS_GET_IID(nsCycleCollectionParticipant)) ) { \
foundInterface = & NS_CYCLE_COLLECTION_NAME(_class); \
if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \
*aInstancePtr = & NS_CYCLE_COLLECTION_NAME(_class); \
return NS_OK; \
} else
#define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class) \
@ -165,40 +182,58 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(nsISupports *s) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
{ \
nsISupports *s = NS_STATIC_CAST(nsISupports*, p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = Downcast(s);
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(nsISupports *s) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
{ \
nsISupports *s = NS_STATIC_CAST(nsISupports*, p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = NS_STATIC_CAST(_class*, Downcast(s)); \
NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s);
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
{ \
_class *tmp = NS_STATIC_CAST(_class*, p);
#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_NSTARRAY(_field) \
tmp->_field.Clear();
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
return NS_OK; \
}
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_0(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(nsISupports *s) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
{ \
NS_ASSERTION(CheckForRightISupports(s), \
NS_ASSERTION(CheckForRightISupports(NS_STATIC_CAST(nsISupports*, p)), \
"not the nsISupports pointer we expect"); \
return NS_OK; \
}
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
{ \
return NS_OK; \
}
///////////////////////////////////////////////////////////////////////////////
// Helpers for implementing nsCycleCollectionParticipant::Traverse
@ -215,9 +250,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
(nsISupports *s, \
(void *p, \
nsCycleCollectionTraversalCallback &cb) \
{ \
nsISupports *s = NS_STATIC_CAST(nsISupports*, p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = Downcast(s); \
@ -226,14 +262,24 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
(nsISupports *s, \
(void *p, \
nsCycleCollectionTraversalCallback &cb) \
{ \
nsISupports *s = NS_STATIC_CAST(nsISupports*, p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = NS_STATIC_CAST(_class*, Downcast(s)); \
NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Traverse(s, cb);
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
(void *p, \
nsCycleCollectionTraversalCallback &cb) \
{ \
_class *tmp = NS_STATIC_CAST(_class*, p); \
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field) \
cb.NoteXPCOMChild(tmp->_field);
@ -250,6 +296,24 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
cb.NoteXPCOMChild(tmp->_field[i]); \
}
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(_ptr, _ptr_class) \
cb.NoteNativeChild(_ptr, &NS_CYCLE_COLLECTION_NATIVE_NAME(_ptr_class));
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(_field, _field_class) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->_field, _field_class)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(_array, _element_class) \
{ \
PRUint32 i, length = (_array).Length(); \
for (i = 0; i < length; ++i) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR((_array)[i], \
_element_class); \
}
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(_field, \
_element_class) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(tmp->_field, _element_class)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
return NS_OK; \
}
@ -260,15 +324,15 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant,
#define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsCycleCollectionParticipant \
: public nsXPCOMCycleCollectionParticipant \
{ \
public: \
NS_IMETHOD Unlink(nsISupports *n); \
NS_IMETHOD Traverse(nsISupports *n, \
NS_IMETHOD Unlink(void *p); \
NS_IMETHOD Traverse(void *p, \
nsCycleCollectionTraversalCallback &cb); \
NS_IMETHOD_(void) UnmarkPurple(nsISupports *n) \
NS_IMETHOD_(void) UnmarkPurple(nsISupports *s) \
{ \
Downcast(n)->UnmarkPurple(); \
Downcast(s)->UnmarkPurple(); \
} \
static _class* Downcast(nsISupports* s) \
{ \
@ -288,8 +352,8 @@ class NS_CYCLE_COLLECTION_INNERCLASS \
: public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
{ \
public: \
NS_IMETHOD Unlink(nsISupports *n); \
NS_IMETHOD Traverse(nsISupports *n, \
NS_IMETHOD Unlink(void *p); \
NS_IMETHOD Traverse(void *p, \
nsCycleCollectionTraversalCallback &cb); \
static _class* Downcast(nsISupports* s) \
{ \
@ -304,7 +368,7 @@ class NS_CYCLE_COLLECTION_INNERCLASS \
: public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
{ \
public: \
NS_IMETHOD Traverse(nsISupports *n, \
NS_IMETHOD Traverse(void *p, \
nsCycleCollectionTraversalCallback &cb); \
static _class* Downcast(nsISupports* s) \
{ \
@ -320,7 +384,7 @@ public: \
* then you don't need this.
*/
#define NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(_class) \
void UnmarkPurple() \
NS_IMETHODIMP_(void) UnmarkPurple() \
{ \
} \
@ -328,6 +392,47 @@ public: \
static NS_CYCLE_COLLECTION_CLASSNAME(_class) \
NS_CYCLE_COLLECTION_NAME(_class);
#define NS_CYCLE_COLLECTION_NATIVE_INNERNAME \
_cycleCollectorGlobal
#define NS_CYCLE_COLLECTION_NATIVE_NAME(_class) \
_class::NS_CYCLE_COLLECTION_NATIVE_INNERNAME
#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsCycleCollectionParticipant \
{ \
public: \
NS_IMETHOD Root(void *n); \
NS_IMETHOD Unlink(void *n); \
NS_IMETHOD Unroot(void *n); \
NS_IMETHOD Traverse(void *n, \
nsCycleCollectionTraversalCallback &cb); \
}; \
static NS_CYCLE_COLLECTION_INNERCLASS \
NS_CYCLE_COLLECTION_NATIVE_INNERNAME;
#define NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(_class) \
NS_CYCLE_COLLECTION_CLASSNAME(_class) NS_CYCLE_COLLECTION_NATIVE_NAME(_class);
#define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Root(void *p) \
{ \
_class *tmp = NS_STATIC_CAST(_class*, p); \
tmp->_root_function(); \
return NS_OK; \
}
#define NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(_class, _unroot_function) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unroot(void *p) \
{ \
_class *tmp = NS_STATIC_CAST(_class*, p); \
tmp->_unroot_function(); \
return NS_OK; \
}
#define NS_IMPL_CYCLE_COLLECTION_0(_class) \
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \

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

@ -80,10 +80,10 @@
//
// An object is scan-safe if:
//
// - It can be QI'ed to |nsCycleCollectionParticipant|, though this
// - It can be QI'ed to |nsXPCOMCycleCollectionParticipant|, though this
// operation loses ISupports identity (like nsIClassInfo).
// - The operation |traverse| on the resulting
// nsCycleCollectionParticipant does not cause *any* refcount
// nsXPCOMCycleCollectionParticipant does not cause *any* refcount
// adjustment to occur (no AddRef / Release calls).
//
// An object is purple-safe if it satisfies the following properties:
@ -279,8 +279,22 @@ struct nsCycleCollectorStats
};
#endif
static void
ToParticipant(nsISupports *s, nsCycleCollectionParticipant **cp);
static inline void
ToParticipant(nsISupports *s, nsXPCOMCycleCollectionParticipant **cp)
{
// We use QI to move from an nsISupports to an
// nsXPCOMCycleCollectionParticipant, which is a per-class singleton helper
// object that implements traversal and unlinking logic for the nsISupports
// in question.
CallQueryInterface(s, cp);
#ifdef DEBUG_CC
if (cp)
++sCollector->mStats.mSuccessfulQI;
else
++sCollector->mStats.mFailedQI;
#endif
}
#ifdef DEBUG_CC
static PRBool
@ -429,11 +443,11 @@ enum NodeColor { black, white, grey };
struct PtrInfo
{
void *mPointer;
nsCycleCollectionParticipant *mParticipant;
PRUint32 mColor : 2;
PRUint32 mInternalRefs : 30;
// FIXME: mLang expands back to a full word when bug 368774 lands.
PRUint32 mLang : 2;
PRUint32 mRefCount : 30;
PRUint32 mRefCount : 31;
PRUint32 mWasPurple : 1;
EdgePool::Iterator mFirstChild; // first
EdgePool::Iterator mLastChild; // one after last
@ -442,12 +456,13 @@ struct PtrInfo
const char *mName;
#endif
PtrInfo(void *aPointer)
PtrInfo(void *aPointer, nsCycleCollectionParticipant *aParticipant)
: mPointer(aPointer),
mParticipant(aParticipant),
mColor(grey),
mInternalRefs(0),
mLang(nsIProgrammingLanguage::CPLUSPLUS),
mRefCount(0),
mWasPurple(PR_FALSE),
mFirstChild(),
mLastChild()
#ifdef DEBUG_CC
@ -506,7 +521,7 @@ public:
NS_ASSERTION(aPool.mBlocks == nsnull && aPool.mLast == nsnull,
"pool not empty");
}
PtrInfo *Add(void *aPointer)
PtrInfo *Add(void *aPointer, nsCycleCollectionParticipant *aParticipant)
{
if (mNext == mBlockEnd) {
Block *block;
@ -516,7 +531,7 @@ public:
mBlockEnd = block->mEntries + BlockSize;
mNextBlock = &block->mNext;
}
return new (mNext++) PtrInfo(aPointer);
return new (mNext++) PtrInfo(aPointer, aParticipant);
}
private:
Block **mNextBlock;
@ -775,75 +790,17 @@ struct nsCycleCollectionXPCOMRuntime :
return NS_OK;
}
nsresult Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
{
nsresult rv;
nsISupports *s = NS_STATIC_CAST(nsISupports *, p);
nsCycleCollectionParticipant *cp;
ToParticipant(s, &cp);
if (!cp) {
Fault("walking wrong type of pointer", s);
return NS_ERROR_FAILURE;
}
rv = cp->Traverse(s, cb);
if (NS_FAILED(rv)) {
Fault("XPCOM pointer traversal failed", s);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult Root(const nsDeque &nodes)
{
for (PRInt32 i = 0; i < nodes.GetSize(); ++i) {
void *p = nodes.ObjectAt(i);
nsISupports *s = NS_STATIC_CAST(nsISupports *, p);
NS_ADDREF(s);
}
return NS_OK;
}
nsresult Unlink(const nsDeque &nodes)
{
nsresult rv;
for (PRInt32 i = 0; i < nodes.GetSize(); ++i) {
void *p = nodes.ObjectAt(i);
nsISupports *s = NS_STATIC_CAST(nsISupports *, p);
nsCycleCollectionParticipant *cp;
ToParticipant(s, &cp);
if (!cp) {
Fault("unlinking wrong kind of pointer", s);
return NS_ERROR_FAILURE;
}
rv = cp->Unlink(s);
if (NS_FAILED(rv)) {
Fault("failed unlink", s);
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
nsresult Unroot(const nsDeque &nodes)
{
for (PRInt32 i = 0; i < nodes.GetSize(); ++i) {
void *p = nodes.ObjectAt(i);
nsISupports *s = NS_STATIC_CAST(nsISupports *, p);
NS_RELEASE(s);
}
return NS_OK;
}
nsresult FinishCycleCollection()
{
return NS_OK;
}
nsCycleCollectionParticipant *ToParticipant(void *p)
{
nsXPCOMCycleCollectionParticipant *cp;
::ToParticipant(NS_STATIC_CAST(nsISupports*, p), &cp);
return cp;
}
};
struct nsCycleCollector
@ -854,14 +811,11 @@ struct nsCycleCollector
nsCycleCollectionLanguageRuntime *mRuntimes[nsIProgrammingLanguage::MAX+1];
nsCycleCollectionXPCOMRuntime mXPCOMRuntime;
// The set of buffers |mBufs| serves a variety of purposes; mostly
// involving the transfer of pointers from a hashtable iterator
// routine to some outer logic that might also need to mutate the
// hashtable. In some contexts, only buffer 0 is used (as a
// set-of-all-pointers); in other contexts, one buffer is used
// per-language (as a set-of-pointers-in-language-N).
// The buffer |mBuf| serves a variety of purposes; mostly involving the
// transfer of pointers from a hashtable iterator routine to some outer
// logic that might also need to mutate the hashtable.
nsDeque mBufs[nsIProgrammingLanguage::MAX + 1];
nsDeque mBuf;
nsCycleCollectorParams mParams;
@ -1062,7 +1016,7 @@ public:
PRUint32 Count() const { return mPtrToNodeMap.entryCount; }
PtrInfo* AddNode(void *s);
PtrInfo* AddNode(void *s, nsCycleCollectionParticipant *aParticipant);
void Traverse(PtrInfo* aPtrInfo);
private:
@ -1073,6 +1027,8 @@ private:
void DescribeNode(size_t refCount);
#endif
void NoteXPCOMChild(nsISupports *child);
void NoteNativeChild(void *child,
nsCycleCollectionParticipant *participant);
void NoteScriptChild(PRUint32 langID, void *child);
};
@ -1094,14 +1050,14 @@ GCGraphBuilder::~GCGraphBuilder()
}
PtrInfo*
GCGraphBuilder::AddNode(void *s)
GCGraphBuilder::AddNode(void *s, nsCycleCollectionParticipant *aParticipant)
{
PtrToNodeEntry *e = NS_STATIC_CAST(PtrToNodeEntry*,
PL_DHashTableOperate(&mPtrToNodeMap, s, PL_DHASH_ADD));
PtrInfo *result;
if (!e->mNode) {
// New entry.
result = mNodeBuilder.Add(s);
result = mNodeBuilder.Add(s, aParticipant);
if (!result) {
PL_DHashTableRawRemove(&mPtrToNodeMap, e);
return nsnull;
@ -1109,6 +1065,8 @@ GCGraphBuilder::AddNode(void *s)
e->mNode = result;
} else {
result = e->mNode;
NS_ASSERTION(result->mParticipant == aParticipant,
"nsCycleCollectionParticipant shouldn't change!");
}
return result;
}
@ -1119,21 +1077,15 @@ GCGraphBuilder::Traverse(PtrInfo* aPtrInfo)
mCurrPi = aPtrInfo;
#ifdef DEBUG_CC
if (mCurrPi->mLang > nsIProgrammingLanguage::MAX ) {
Fault("unknown language during walk");
return;
}
if (!mRuntimes[mCurrPi->mLang]) {
Fault("script pointer for unregistered language");
if (!mCurrPi->mParticipant) {
Fault("unknown pointer during walk");
return;
}
#endif
mCurrPi->mFirstChild = mEdgeBuilder.Mark();
nsresult rv =
mRuntimes[aPtrInfo->mLang]->Traverse(aPtrInfo->mPointer, *this);
nsresult rv = aPtrInfo->mParticipant->Traverse(aPtrInfo->mPointer, *this);
if (NS_FAILED(rv)) {
Fault("script pointer traversal failed", aPtrInfo->mPointer);
}
@ -1159,7 +1111,7 @@ GCGraphBuilder::DescribeNode(size_t refCount)
mCurrPi->mRefCount = refCount;
#ifdef DEBUG_CC
sCollector->mStats.mVisitedNode++;
if (mCurrPi->mLang == nsIProgrammingLanguage::JAVASCRIPT)
if (mCurrPi->mParticipant == mRuntimes[nsIProgrammingLanguage::JAVASCRIPT])
sCollector->mStats.mVisitedJSNode++;
#endif
}
@ -1167,17 +1119,18 @@ GCGraphBuilder::DescribeNode(size_t refCount)
void
GCGraphBuilder::NoteXPCOMChild(nsISupports *child)
{
if (!child)
if (!child || !(child = canonicalize(child)))
return;
child = canonicalize(child);
PRBool scanSafe = nsCycleCollector_isScanSafe(child);
#ifdef DEBUG_CC
scanSafe &= !nsCycleCollector_shouldSuppress(child);
if (nsCycleCollector_shouldSuppress(child))
return;
#endif
if (scanSafe) {
PtrInfo *childPi = AddNode(child);
nsXPCOMCycleCollectionParticipant *cp;
ToParticipant(child, &cp);
if (cp) {
PtrInfo *childPi = AddNode(child, cp);
if (!childPi)
return;
mEdgeBuilder.Add(childPi);
@ -1185,6 +1138,22 @@ GCGraphBuilder::NoteXPCOMChild(nsISupports *child)
}
}
void
GCGraphBuilder::NoteNativeChild(void *child,
nsCycleCollectionParticipant *participant)
{
if (!child)
return;
NS_ASSERTION(participant, "Need a nsCycleCollectionParticipant!");
PtrInfo *childPi = AddNode(child, participant);
if (!childPi)
return;
mEdgeBuilder.Add(childPi);
++childPi->mInternalRefs;
}
void
GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child)
{
@ -1196,33 +1165,42 @@ GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child)
return;
}
PtrInfo *childPi = AddNode(child);
nsCycleCollectionParticipant *cp = mRuntimes[langID]->ToParticipant(child);
if (!cp)
return;
PtrInfo *childPi = AddNode(child, cp);
if (!childPi)
return;
mEdgeBuilder.Add(childPi);
++childPi->mInternalRefs;
childPi->mLang = langID;
}
void
nsCycleCollector::CollectPurple()
{
mPurpleBuf.SelectAgedPointers(&mBufs[0]);
mPurpleBuf.SelectAgedPointers(&mBuf);
}
void
nsCycleCollector::MarkRoots(GCGraph &graph)
{
if (mBufs[0].GetSize() == 0)
if (mBuf.GetSize() == 0)
return;
GCGraphBuilder builder(graph, mRuntimes);
int i;
for (i = 0; i < mBufs[0].GetSize(); ++i) {
nsISupports *s = NS_STATIC_CAST(nsISupports *, mBufs[0].ObjectAt(i));
PtrInfo *pi = builder.AddNode(canonicalize(s));
for (i = 0; i < mBuf.GetSize(); ++i) {
nsISupports *s = NS_STATIC_CAST(nsISupports *, mBuf.ObjectAt(i));
nsXPCOMCycleCollectionParticipant *cp;
ToParticipant(s, &cp);
if (cp) {
PtrInfo *pinfo = builder.AddNode(canonicalize(s), cp);
if (pinfo)
pinfo->mWasPurple = PR_TRUE;
}
}
graph.mRootCount = builder.Count();
@ -1330,11 +1308,9 @@ nsCycleCollector::CollectWhite(GCGraph &graph)
// - Unlink(whites), which drops outgoing links on each white.
// - Unroot(whites), which returns the whites to normal GC.
PRUint32 i;
nsresult rv;
for (i = 0; i < nsIProgrammingLanguage::MAX+1; ++i)
mBufs[i].Empty();
mBuf.Empty();
#if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
struct _CrtMemState ms1, ms2;
@ -1347,67 +1323,62 @@ nsCycleCollector::CollectWhite(GCGraph &graph)
PtrInfo *pinfo = etor.GetNext();
void *p = pinfo->mPointer;
NS_ASSERTION(pinfo->mLang == nsIProgrammingLanguage::CPLUSPLUS ||
!mPurpleBuf.Exists(p),
"Need to remove non-CPLUSPLUS objects from purple buffer!");
if (pinfo->mColor == white) {
if (pinfo->mLang > nsIProgrammingLanguage::MAX)
Fault("White node has bad language ID", p);
else
mBufs[pinfo->mLang].Push(p);
mBuf.Push(pinfo);
if (pinfo->mLang == nsIProgrammingLanguage::CPLUSPLUS) {
if (pinfo->mWasPurple) {
nsISupports* s = NS_STATIC_CAST(nsISupports*, p);
Forget(s);
}
}
else if (pinfo->mLang == nsIProgrammingLanguage::CPLUSPLUS) {
else if (pinfo->mWasPurple) {
nsISupports* s = NS_STATIC_CAST(nsISupports*, p);
nsCycleCollectionParticipant* cp;
CallQueryInterface(s, &cp);
if (cp)
cp->UnmarkPurple(s);
nsXPCOMCycleCollectionParticipant* cp =
NS_STATIC_CAST(nsXPCOMCycleCollectionParticipant*,
pinfo->mParticipant);
#ifdef DEBUG
nsXPCOMCycleCollectionParticipant* checkcp;
CallQueryInterface(s, &checkcp);
NS_ASSERTION(checkcp == cp,
"QI should return the same participant!");
#endif
cp->UnmarkPurple(s);
Forget(s);
}
}
for (i = 0; i < nsIProgrammingLanguage::MAX+1; ++i) {
if (mRuntimes[i] &&
mBufs[i].GetSize() > 0) {
rv = mRuntimes[i]->Root(mBufs[i]);
if (NS_FAILED(rv))
Fault("Failed root call while unlinking");
}
PRUint32 i, count = mBuf.GetSize();
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = NS_STATIC_CAST(PtrInfo*, mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Root(pinfo->mPointer);
if (NS_FAILED(rv))
Fault("Failed root call while unlinking");
}
for (i = 0; i < nsIProgrammingLanguage::MAX+1; ++i) {
if (mRuntimes[i] &&
mBufs[i].GetSize() > 0) {
rv = mRuntimes[i]->Unlink(mBufs[i]);
if (NS_FAILED(rv)) {
Fault("Failed unlink call while unlinking");
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = NS_STATIC_CAST(PtrInfo*, mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Unlink(pinfo->mPointer);
if (NS_FAILED(rv)) {
Fault("Failed unlink call while unlinking");
#ifdef DEBUG_CC
mStats.mFailedUnlink++;
mStats.mFailedUnlink++;
#endif
} else {
}
else {
#ifdef DEBUG_CC
mStats.mCollectedNode += mBufs[i].GetSize();
++mStats.mCollectedNode;
#endif
}
}
}
for (i = 0; i < nsIProgrammingLanguage::MAX+1; ++i) {
if (mRuntimes[i] &&
mBufs[i].GetSize() > 0) {
rv = mRuntimes[i]->Unroot(mBufs[i]);
if (NS_FAILED(rv))
Fault("Failed unroot call while unlinking");
}
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = NS_STATIC_CAST(PtrInfo*, mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Unroot(pinfo->mPointer);
if (NS_FAILED(rv))
Fault("Failed unroot call while unlinking");
}
for (i = 0; i < nsIProgrammingLanguage::MAX+1; ++i)
mBufs[i].Empty();
mBuf.Empty();
#if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
_CrtMemCheckpoint(&ms2);
@ -1636,9 +1607,6 @@ nsCycleCollector::nsCycleCollector() :
nsCycleCollector::~nsCycleCollector()
{
for (PRUint32 i = 0; i < nsIProgrammingLanguage::MAX+1; ++i) {
mRuntimes[i] = NULL;
}
}
@ -1770,7 +1738,8 @@ public:
mSuppressThisNode = PR_FALSE;
} else {
nsresult rv;
nsCOMPtr<nsCycleCollectionParticipant> cp = do_QueryInterface(s, &rv);
nsXPCOMCycleCollectionParticipant *cp;
rv = CallQueryInterface(s, &cp);
if (NS_FAILED(rv)) {
Fault("checking suppression on wrong type of pointer", s);
return PR_TRUE;
@ -1787,6 +1756,8 @@ public:
void NoteXPCOMChild(nsISupports *child) {}
void NoteScriptChild(PRUint32 langID, void *child) {}
void NoteNativeChild(void *child,
nsCycleCollectionParticipant *participant) {}
};
char *Suppressor::sSuppressionList = nsnull;
@ -1800,6 +1771,20 @@ nsCycleCollector_shouldSuppress(nsISupports *s)
}
#endif
#ifdef DEBUG
static PRBool
nsCycleCollector_isScanSafe(nsISupports *s)
{
if (!s)
return PR_FALSE;
nsXPCOMCycleCollectionParticipant *cp;
ToParticipant(s, &cp);
return cp != nsnull;
}
#endif
void
nsCycleCollector::Suspect(nsISupports *n, PRBool current)
{
@ -1836,7 +1821,7 @@ nsCycleCollector::Suspect(nsISupports *n, PRBool current)
#endif
if (current)
mBufs[0].Push(n);
mBuf.Push(n);
else
mPurpleBuf.Put(n);
}
@ -1931,10 +1916,10 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
// GC calls -- so it's essential that we actually execute this
// step!
//
// It is also essential to empty mBufs[0] here because starting up
// It is also essential to empty mBuf here because starting up
// collection in language runtimes may force some "current" suspects
// into mBufs[0].
mBufs[0].Empty();
// into mBuf.
mBuf.Empty();
#ifdef COLLECT_TIME_DEBUG
now = PR_Now();
@ -1963,7 +1948,7 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
(PR_Now() - now) / PR_USEC_PER_MSEC);
#endif
if (mBufs[0].GetSize() == 0) {
if (mBuf.GetSize() == 0) {
aTryCollections = 0;
} else {
if (mCollectionInProgress)
@ -2056,7 +2041,7 @@ nsCycleCollector::Shutdown()
#ifdef DEBUG_CC
CollectPurple();
if (mBufs[0].GetSize() != 0) {
if (mBuf.GetSize() != 0) {
printf("Might have been able to release more cycles if the cycle collector would "
"run once more at shutdown.\n");
}
@ -2072,7 +2057,7 @@ PR_STATIC_CALLBACK(PLDHashOperator)
AddExpectedGarbage(nsVoidPtrHashKey *p, void *arg)
{
nsCycleCollector *c = NS_STATIC_CAST(nsCycleCollector*, arg);
c->mBufs[0].Push(NS_CONST_CAST(void*, p->GetKey()));
c->mBuf.Push(NS_CONST_CAST(void*, p->GetKey()));
return PL_DHASH_NEXT;
}
@ -2098,9 +2083,9 @@ nsCycleCollector::ExplainLiveExpectedGarbage()
{
GCGraph graph;
mBufs[0].Empty();
mBuf.Empty();
// Instead of filling mBufs[0] from the purple buffer, we fill it
// Instead of filling mBuf from the purple buffer, we fill it
// from the list of nodes we were expected to collect.
mExpectedGarbage.EnumerateEntries(&AddExpectedGarbage, this);
@ -2243,31 +2228,3 @@ nsCycleCollector_DEBUG_wasFreed(nsISupports *n)
#endif
}
#endif
PRBool
nsCycleCollector_isScanSafe(nsISupports *s)
{
if (!s)
return PR_FALSE;
nsCycleCollectionParticipant *cp;
ToParticipant(s, &cp);
return cp != nsnull;
}
static void
ToParticipant(nsISupports *s, nsCycleCollectionParticipant **cp)
{
// We use QI to move from an nsISupports to an
// nsCycleCollectionParticipant, which is a per-class singleton helper
// object that implements traversal and unlinking logic for the nsISupports
// in question.
CallQueryInterface(s, cp);
#ifdef DEBUG_CC
if (cp)
++sCollector->mStats.mSuccessfulQI;
else
++sCollector->mStats.mFailedQI;
#endif
}

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

@ -39,8 +39,7 @@
#define nsCycleCollector_h__
class nsISupports;
class nsDeque;
struct nsCycleCollectionTraversalCallback;
class nsCycleCollectionParticipant;
// An nsCycleCollectionLanguageRuntime is a per-language object that
// implements language-specific aspects of the cycle collection task.
@ -48,18 +47,10 @@ struct nsCycleCollectionTraversalCallback;
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;
virtual nsCycleCollectionParticipant *ToParticipant(void *p) = 0;
};
NS_COM PRBool nsCycleCollector_isScanSafe(nsISupports *n);
NS_COM void nsCycleCollector_suspect(nsISupports *n);
NS_COM void nsCycleCollector_suspectCurrent(nsISupports *n);
NS_COM void nsCycleCollector_forget(nsISupports *n);

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

@ -280,7 +280,7 @@ void XXXNeverCalled()
b.ToString(0, y);
}
nsCycleCollectionParticipant();
nsXPCOMCycleCollectionParticipant();
nsCycleCollector_collect();
#if !defined(WINCE) && !defined(XP_OS2)

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

@ -43,6 +43,8 @@
#include "nsStringFwd.h"
#include "xpt_struct.h"
struct nsCycleCollectionTraversalCallback;
/**
* Map the nsAUTF8String, nsUTF8String classes to the nsACString and
* nsCString classes respectively for now. These defines need to be removed