diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index f552ede0f648..82a9e4216256 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -750,6 +750,42 @@ public: */ static nsIContentPolicy *GetContentPolicy(); + /** + * Make sure that whatever value *aPtr contains at any given moment is + * protected from JS GC until we remove the GC root. A call to this that + * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking. + */ + static nsresult AddJSGCRoot(jsval* aPtr, const char* aName) { + return AddJSGCRoot((void*)aPtr, aName); + } + + /** + * Make sure that whatever object *aPtr is pointing to at any given moment is + * protected from JS GC until we remove the GC root. A call to this that + * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking. + */ + static nsresult AddJSGCRoot(JSObject** aPtr, const char* aName) { + return AddJSGCRoot((void*)aPtr, aName); + } + + /** + * Make sure that whatever object *aPtr is pointing to at any given moment is + * protected from JS GC until we remove the GC root. A call to this that + * succeeds MUST be matched by a call to RemoveJSGCRoot to avoid leaking. + */ + static nsresult AddJSGCRoot(void* aPtr, const char* aName); + + /** + * Remove aPtr as a JS GC root + */ + static nsresult RemoveJSGCRoot(jsval* aPtr) { + return RemoveJSGCRoot((void*)aPtr); + } + static nsresult RemoveJSGCRoot(JSObject** aPtr) { + return RemoveJSGCRoot((void*)aPtr); + } + static nsresult RemoveJSGCRoot(void* aPtr); + /** * Quick helper to determine whether there are any mutation listeners * of a given type that apply to this content or any of its ancestors. @@ -964,73 +1000,40 @@ public: */ static void DestroyAnonymousContent(nsCOMPtr* aContent); - /** - * Keep script object aNewObject, held by aScriptObjectHolder, alive. - * - * NOTE: This currently only supports objects that hold script objects of one - * scripting language. - * - * @param aLangID script language ID of aNewObject - * @param aScriptObjectHolder the object that holds aNewObject - * @param aTracer the tracer for aScriptObject - * @param aNewObject the script object to hold - * @param aWasHoldingObjects whether aScriptObjectHolder was already holding - * script objects (ie. HoldScriptObject was called - * on it before, without a corresponding call to - * DropScriptObjects) - */ - static nsresult HoldScriptObject(PRUint32 aLangID, void* aScriptObjectHolder, - nsScriptObjectTracer* aTracer, - void* aNewObject, PRBool aWasHoldingObjects) + static nsresult HoldScriptObject(PRUint32 aLangID, void *aObject); + static nsresult DropScriptObject(PRUint32 aLangID, void *aObject); + + class ScriptObjectHolder { - if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) { - return aWasHoldingObjects ? NS_OK : - HoldJSObjects(aScriptObjectHolder, aTracer); + public: + ScriptObjectHolder(PRUint32 aLangID) : mLangID(aLangID), + mObject(nsnull) + { + MOZ_COUNT_CTOR(ScriptObjectHolder); } - - return HoldScriptObject(aLangID, aNewObject); - } - - /** - * Drop any script objects that aScriptObjectHolder is holding. - * - * NOTE: This currently only supports objects that hold script objects of one - * scripting language. - * - * @param aLangID script language ID of the objects that - * @param aScriptObjectHolder the object that holds script object that we want - * to drop - * @param aTracer the tracer for aScriptObject - */ - static nsresult DropScriptObjects(PRUint32 aLangID, void* aScriptObjectHolder, - nsScriptObjectTracer* aTracer) - { - if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) { - return DropJSObjects(aScriptObjectHolder); + ~ScriptObjectHolder() + { + MOZ_COUNT_DTOR(ScriptObjectHolder); + if (mObject) + DropScriptObject(mLangID, mObject); } - - aTracer->Trace(aScriptObjectHolder, DropScriptObject, nsnull); - - return NS_OK; - } - - /** - * Keep the JS objects held by aScriptObjectHolder alive. - * - * @param aScriptObjectHolder the object that holds JS objects that we want to - * keep alive - * @param aTracer the tracer for aScriptObject - */ - static nsresult HoldJSObjects(void* aScriptObjectHolder, - nsScriptObjectTracer* aTracer); - - /** - * Drop the JS objects held by aScriptObjectHolder. - * - * @param aScriptObjectHolder the object that holds JS objects that we want to - * drop - */ - static nsresult DropJSObjects(void* aScriptObjectHolder); + nsresult set(void *aObject) + { + NS_ASSERTION(aObject, "unexpected null object"); + NS_ASSERTION(!mObject, "already have an object"); + nsresult rv = HoldScriptObject(mLangID, aObject); + if (NS_SUCCEEDED(rv)) { + mObject = aObject; + } + return rv; + } + void traverse(nsCycleCollectionTraversalCallback &cb) + { + cb.NoteScriptChild(mLangID, mObject); + } + PRUint32 mLangID; + void *mObject; + }; /** * Convert nsIContent::IME_STATUS_* to nsIKBStateControll::IME_STATUS_* @@ -1117,10 +1120,6 @@ private: static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory(); - static nsresult HoldScriptObject(PRUint32 aLangID, void* aObject); - PR_STATIC_CALLBACK(void) DropScriptObject(PRUint32 aLangID, void *aObject, - void *aClosure); - static nsIDOMScriptObjectFactory *sDOMScriptObjectFactory; static nsIXPConnect *sXPConnect; @@ -1162,9 +1161,14 @@ private: // Holds pointers to nsISupports* that should be released at shutdown static nsVoidArray* sPtrsToPtrsToRelease; + // For now, we don't want to automatically clean this up in Shutdown(), since + // consumers might unfortunately end up wanting to use it after that + static nsIJSRuntimeService* sJSRuntimeService; + static JSRuntime* sJSScriptRuntime; + static PRInt32 sJSScriptRootCount; + static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND]; static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND]; - static PRUint32 sJSGCThingRootCount; #ifdef IBMBIDI static nsIBidiKeyboard* sBidiKeyboard; @@ -1174,14 +1178,6 @@ private: }; -#define NS_HOLD_JS_OBJECTS(obj, clazz) \ - nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz), \ - &NS_CYCLE_COLLECTION_NAME(clazz)) - -#define NS_DROP_JS_OBJECTS(obj, clazz) \ - nsContentUtils::DropJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz)) - - class nsCxPusher { public: @@ -1204,38 +1200,33 @@ public: nsAutoGCRoot(jsval* aPtr, nsresult* aResult) : mPtr(aPtr) { - mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot"); + mResult = *aResult = + nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot"); } // aPtr should be the pointer to the JSObject* we want to protect nsAutoGCRoot(JSObject** aPtr, nsresult* aResult) : mPtr(aPtr) { - mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot"); + mResult = *aResult = + nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot"); } // aPtr should be the pointer to the thing we want to protect nsAutoGCRoot(void* aPtr, nsresult* aResult) : mPtr(aPtr) { - mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot"); + mResult = *aResult = + nsContentUtils::AddJSGCRoot(aPtr, "nsAutoGCRoot"); } ~nsAutoGCRoot() { if (NS_SUCCEEDED(mResult)) { - RemoveJSGCRoot(mPtr); + nsContentUtils::RemoveJSGCRoot(mPtr); } } - static void Shutdown(); - private: - static nsresult AddJSGCRoot(void *aPtr, const char* aName); - static nsresult RemoveJSGCRoot(void *aPtr); - - static nsIJSRuntimeService* sJSRuntimeService; - static JSRuntime* sJSScriptRuntime; - void* mPtr; nsresult mResult; }; diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 394b807b4d12..db5143bfb6cc 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -180,15 +180,15 @@ nsILineBreaker *nsContentUtils::sLineBreaker; nsIWordBreaker *nsContentUtils::sWordBreaker; nsICaseConversion *nsContentUtils::sCaseConv; nsVoidArray *nsContentUtils::sPtrsToPtrsToRelease; +nsIJSRuntimeService *nsContentUtils::sJSRuntimeService; +JSRuntime *nsContentUtils::sJSScriptRuntime; +PRInt32 nsContentUtils::sJSScriptRootCount = 0; nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND]; PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND]; -PRUint32 nsContentUtils::sJSGCThingRootCount; #ifdef IBMBIDI nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull; #endif -nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService; -JSRuntime *nsAutoGCRoot::sJSScriptRuntime; PRBool nsContentUtils::sInitialized = PR_FALSE; @@ -671,8 +671,7 @@ nsContentUtils::Shutdown() NS_IF_RELEASE(sStringBundleService); NS_IF_RELEASE(sConsoleService); NS_IF_RELEASE(sDOMScriptObjectFactory); - if (sJSGCThingRootCount == 0 && sXPConnect) - NS_RELEASE(sXPConnect); + NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sSecurityManager); NS_IF_RELEASE(sThreadJSContextStack); NS_IF_RELEASE(sNameSpaceManager); @@ -722,8 +721,6 @@ nsContentUtils::Shutdown() sEventListenerManagersHash.ops = nsnull; } } - - nsAutoGCRoot::Shutdown(); } static PRBool IsCallerTrustedForCapability(const char* aCapability) @@ -2672,7 +2669,7 @@ nsContentUtils::GetContentPolicy() // static nsresult -nsAutoGCRoot::AddJSGCRoot(void* aPtr, const char* aName) +nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName) { if (!sJSScriptRuntime) { nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1", @@ -2690,16 +2687,25 @@ nsAutoGCRoot::AddJSGCRoot(void* aPtr, const char* aName) PRBool ok; ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName); if (!ok) { + if (sJSScriptRootCount == 0) { + // We just got the runtime... Just null things out, since no + // one's expecting us to have a runtime yet + NS_RELEASE(sJSRuntimeService); + sJSScriptRuntime = nsnull; + } NS_WARNING("JS_AddNamedRootRT failed"); return NS_ERROR_OUT_OF_MEMORY; } + // We now have one more root we added to the runtime + ++sJSScriptRootCount; + return NS_OK; } /* static */ nsresult -nsAutoGCRoot::RemoveJSGCRoot(void* aPtr) +nsContentUtils::RemoveJSGCRoot(void* aPtr) { if (!sJSScriptRuntime) { NS_NOTREACHED("Trying to remove a JS GC root when none were added"); @@ -2708,6 +2714,11 @@ nsAutoGCRoot::RemoveJSGCRoot(void* aPtr) ::JS_RemoveRootRT(sJSScriptRuntime, aPtr); + if (--sJSScriptRootCount == 0) { + NS_RELEASE(sJSRuntimeService); + sJSScriptRuntime = nsnull; + } + return NS_OK; } @@ -3511,8 +3522,6 @@ nsresult nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject) { NS_ASSERTION(aObject, "unexpected null object"); - NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT, - "Should use HoldJSObjects."); nsresult rv; PRUint32 langIndex = NS_STID_INDEX(aLangID); @@ -3539,47 +3548,17 @@ nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject) } /* static */ -void -nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject, - void *aClosure) +nsresult +nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject) { NS_ASSERTION(aObject, "unexpected null object"); - NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT, - "Should use DropJSObjects."); PRUint32 langIndex = NS_STID_INDEX(aLangID); NS_LOG_RELEASE(sScriptRuntimes[langIndex], sScriptRootCount[langIndex] - 1, "HoldScriptObject"); - sScriptRuntimes[langIndex]->DropScriptObject(aObject); + nsresult rv = sScriptRuntimes[langIndex]->DropScriptObject(aObject); if (--sScriptRootCount[langIndex] == 0) { NS_RELEASE(sScriptRuntimes[langIndex]); } -} - -/* static */ -nsresult -nsContentUtils::HoldJSObjects(void* aScriptObjectHolder, - nsScriptObjectTracer* aTracer) -{ - PRBool newHolder; - nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer); - NS_ENSURE_SUCCESS(rv, rv); - - ++sJSGCThingRootCount; - NS_LOG_ADDREF(sXPConnect, sJSGCThingRootCount, "HoldJSObjects", - sizeof(void*)); - - return NS_OK; -} - -/* static */ -nsresult -nsContentUtils::DropJSObjects(void* aScriptObjectHolder) -{ - NS_LOG_RELEASE(sXPConnect, sJSGCThingRootCount - 1, "HoldJSObjects"); - nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder); - if (--sJSGCThingRootCount == 0 && !sInitialized) { - NS_RELEASE(sXPConnect); - } return rv; } @@ -3735,11 +3714,3 @@ nsContentUtils::IsNativeAnonymous(nsIContent* aContent) return PR_FALSE; } - -/* static */ -void -nsAutoGCRoot::Shutdown() -{ - NS_RELEASE(sJSRuntimeService); - sJSScriptRuntime = nsnull; -} diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index debdb0e1e879..3a8db62f1c49 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -305,7 +305,7 @@ TraverseKey(nsISupports* aKey, nsInsertionPointList* aData, void* aClosure) return PL_DHASH_NEXT; } -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding) +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. diff --git a/content/xbl/src/nsXBLDocumentInfo.cpp b/content/xbl/src/nsXBLDocumentInfo.cpp index 5b4007f0deba..4da0e377fb1c 100644 --- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -452,21 +452,6 @@ UnlinkProtos(nsHashKey *aKey, void *aData, void* aClosure) return kHashEnumerateNext; } -struct ProtoTracer -{ - TraceCallback mCallback; - void *mClosure; -}; - -static PRIntn PR_CALLBACK -TraceProtos(nsHashKey *aKey, void *aData, void* aClosure) -{ - ProtoTracer* closure = static_cast(aClosure); - nsXBLPrototypeBinding *proto = static_cast(aData); - proto->Trace(closure->mCallback, closure->mClosure); - return kHashEnumerateNext; -} - NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo) if (tmp->mBindingTable) { @@ -481,14 +466,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo) tmp->mBindingTable->Enumerate(TraverseProtos, &cb); } cb.NoteXPCOMChild(static_cast(tmp->mGlobalObject)); - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo) - if (tmp->mBindingTable) { - ProtoTracer closure = { aCallback, aClosure }; - tmp->mBindingTable->Enumerate(TraceProtos, &closure); - } -NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo) NS_INTERFACE_MAP_ENTRY(nsIXBLDocumentInfo) @@ -529,10 +507,7 @@ nsXBLDocumentInfo::~nsXBLDocumentInfo() mGlobalObject->SetScriptContext(nsIProgrammingLanguage::JAVASCRIPT, nsnull); mGlobalObject->ClearGlobalObjectOwner(); // just in case } - if (mBindingTable) { - NS_DROP_JS_OBJECTS(this, nsXBLDocumentInfo); - delete mBindingTable; - } + delete mBindingTable; } NS_IMETHODIMP @@ -566,13 +541,8 @@ DeletePrototypeBinding(nsHashKey* aKey, void* aData, void* aClosure) NS_IMETHODIMP nsXBLDocumentInfo::SetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBinding* aBinding) { - if (!mBindingTable) { + if (!mBindingTable) mBindingTable = new nsObjectHashtable(nsnull, nsnull, DeletePrototypeBinding, nsnull); - if (!mBindingTable) - return NS_ERROR_OUT_OF_MEMORY; - - NS_HOLD_JS_OBJECTS(this, nsXBLDocumentInfo); - } const nsPromiseFlatCString& flat = PromiseFlatCString(aRef); nsCStringKey key(flat.get()); diff --git a/content/xbl/src/nsXBLDocumentInfo.h b/content/xbl/src/nsXBLDocumentInfo.h index 29054dd1e2bd..1f65e7168d6b 100644 --- a/content/xbl/src/nsXBLDocumentInfo.h +++ b/content/xbl/src/nsXBLDocumentInfo.h @@ -72,8 +72,8 @@ public: // nsIScriptGlobalObjectOwner methods virtual nsIScriptGlobalObject* GetScriptGlobalObject(); - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsXBLDocumentInfo, - nsIXBLDocumentInfo) + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXBLDocumentInfo, + nsIXBLDocumentInfo) private: nsCOMPtr mDocument; diff --git a/content/xbl/src/nsXBLInsertionPoint.cpp b/content/xbl/src/nsXBLInsertionPoint.cpp index 56d86fccabaf..c3c6dd6b500e 100644 --- a/content/xbl/src/nsXBLInsertionPoint.cpp +++ b/content/xbl/src/nsXBLInsertionPoint.cpp @@ -64,7 +64,7 @@ nsXBLInsertionPoint::Release() return mRefCnt; } -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPoint) +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) diff --git a/content/xbl/src/nsXBLProtoImpl.cpp b/content/xbl/src/nsXBLProtoImpl.cpp index a1860f98ded1..2cd341545373 100644 --- a/content/xbl/src/nsXBLProtoImpl.cpp +++ b/content/xbl/src/nsXBLProtoImpl.cpp @@ -200,7 +200,7 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding) } void -nsXBLProtoImpl::Trace(TraceCallback aCallback, void *aClosure) const +nsXBLProtoImpl::Traverse(nsCycleCollectionTraversalCallback &cb) const { // If we don't have a class object then we either didn't compile members // or we only have fields, in both cases there are no cycles through our @@ -211,7 +211,7 @@ nsXBLProtoImpl::Trace(TraceCallback aCallback, void *aClosure) const nsXBLProtoImplMember *member; for (member = mMembers; member; member = member->GetNext()) { - member->Trace(aCallback, aClosure); + member->Traverse(cb); } } diff --git a/content/xbl/src/nsXBLProtoImpl.h b/content/xbl/src/nsXBLProtoImpl.h index caa264360447..e9989f1e4371 100644 --- a/content/xbl/src/nsXBLProtoImpl.h +++ b/content/xbl/src/nsXBLProtoImpl.h @@ -90,7 +90,7 @@ public: mFields = aFieldList; } - void Trace(TraceCallback aCallback, void *aClosure) const; + void Traverse(nsCycleCollectionTraversalCallback &cb) const; void Unlink(); nsXBLProtoImplField* FindField(const nsString& aFieldName) const; diff --git a/content/xbl/src/nsXBLProtoImplMember.h b/content/xbl/src/nsXBLProtoImplMember.h index d8e12cd3181f..0ca62573a13e 100644 --- a/content/xbl/src/nsXBLProtoImplMember.h +++ b/content/xbl/src/nsXBLProtoImplMember.h @@ -47,11 +47,11 @@ #include "nsIJSRuntimeService.h" #include "nsIServiceManager.h" #include "nsReadableUtils.h" -#include "nsCycleCollectionParticipant.h" class nsIScriptContext; struct JSRuntime; class nsIJSRuntimeService; +class nsCycleCollectionTraversalCallback; struct nsXBLTextWithLineNumber { @@ -114,7 +114,7 @@ public: const nsCString& aClassStr, void* aClassObject)=0; - virtual void Trace(TraceCallback aCallback, void *aClosure) const = 0; + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const = 0; protected: friend class nsAutoGCRoot; diff --git a/content/xbl/src/nsXBLProtoImplMethod.cpp b/content/xbl/src/nsXBLProtoImplMethod.cpp index 3da1692c64ce..d18768118319 100644 --- a/content/xbl/src/nsXBLProtoImplMethod.cpp +++ b/content/xbl/src/nsXBLProtoImplMethod.cpp @@ -72,6 +72,8 @@ nsXBLProtoImplMethod::Destroy(PRBool aIsCompiled) NS_PRECONDITION(aIsCompiled == mIsCompiled, "Incorrect aIsCompiled in nsXBLProtoImplMethod::Destroy"); if (aIsCompiled) { + if (mJSMethodObject) + nsContentUtils::RemoveJSGCRoot(&mJSMethodObject); mJSMethodObject = nsnull; } else { @@ -261,6 +263,8 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& if (methodObject) { // Root the compiled prototype script object. + rv = nsContentUtils::AddJSGCRoot(&mJSMethodObject, + "nsXBLProtoImplMethod::mJSMethodObject"); if (NS_FAILED(rv)) { mJSMethodObject = nsnull; } @@ -273,13 +277,11 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& } void -nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const +nsXBLProtoImplMethod::Traverse(nsCycleCollectionTraversalCallback &cb) const { NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method"); - if (mJSMethodObject) { - aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, aClosure); - } + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject); } nsresult diff --git a/content/xbl/src/nsXBLProtoImplMethod.h b/content/xbl/src/nsXBLProtoImplMethod.h index bac2927b56f2..a1e665836397 100644 --- a/content/xbl/src/nsXBLProtoImplMethod.h +++ b/content/xbl/src/nsXBLProtoImplMethod.h @@ -129,7 +129,7 @@ public: const nsCString& aClassStr, void* aClassObject); - virtual void Trace(TraceCallback aCallback, void *aClosure) const; + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const; protected: union { diff --git a/content/xbl/src/nsXBLProtoImplProperty.cpp b/content/xbl/src/nsXBLProtoImplProperty.cpp index 407265f8acf7..76a5b44bec06 100644 --- a/content/xbl/src/nsXBLProtoImplProperty.cpp +++ b/content/xbl/src/nsXBLProtoImplProperty.cpp @@ -87,14 +87,14 @@ nsXBLProtoImplProperty::Destroy(PRBool aIsCompiled) "Incorrect aIsCompiled in nsXBLProtoImplProperty::Destroy"); if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) { - mJSGetterObject = nsnull; + nsContentUtils::RemoveJSGCRoot(&mJSGetterObject); } else { delete mGetterText; } if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) { - mJSSetterObject = nsnull; + nsContentUtils::RemoveJSGCRoot(&mJSSetterObject); } else { delete mSetterText; @@ -268,6 +268,9 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin if (mJSGetterObject && NS_SUCCEEDED(rv)) { mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED; + // Root the compiled prototype script object. + rv = nsContentUtils::AddJSGCRoot(&mJSGetterObject, + "nsXBLProtoImplProperty::mJSGetterObject"); } if (NS_FAILED(rv)) { mJSGetterObject = nsnull; @@ -317,6 +320,9 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin if (mJSSetterObject && NS_SUCCEEDED(rv)) { mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED; + // Root the compiled prototype script object. + rv = nsContentUtils::AddJSGCRoot(&mJSSetterObject, + "nsXBLProtoImplProperty::mJSSetterObject"); } if (NS_FAILED(rv)) { mJSSetterObject = nsnull; @@ -339,15 +345,15 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin } void -nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const +nsXBLProtoImplProperty::Traverse(nsCycleCollectionTraversalCallback &cb) const { NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method"); - if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) { - aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject, aClosure); + if (mJSAttributes & JSPROP_GETTER) { + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject); } - if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) { - aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject, aClosure); + if (mJSAttributes & JSPROP_SETTER) { + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject); } } diff --git a/content/xbl/src/nsXBLProtoImplProperty.h b/content/xbl/src/nsXBLProtoImplProperty.h index 9c10326c43de..f5ab70c79ace 100644 --- a/content/xbl/src/nsXBLProtoImplProperty.h +++ b/content/xbl/src/nsXBLProtoImplProperty.h @@ -72,7 +72,7 @@ public: const nsCString& aClassStr, void* aClassObject); - virtual void Trace(TraceCallback aCallback, void *aClosure) const; + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const; protected: union { diff --git a/content/xbl/src/nsXBLPrototypeBinding.cpp b/content/xbl/src/nsXBLPrototypeBinding.cpp index 725ec9a755f6..568945789b41 100644 --- a/content/xbl/src/nsXBLPrototypeBinding.cpp +++ b/content/xbl/src/nsXBLPrototypeBinding.cpp @@ -244,7 +244,7 @@ private: PRUint32 nsXBLInsertionPointEntry::gRefCnt = 0; nsFixedSizeAllocator* nsXBLInsertionPointEntry::kPool; -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPointEntry) +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) { @@ -355,6 +355,8 @@ void nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const { cb.NoteXPCOMChild(mBinding); + if (mImplementation) + mImplementation->Traverse(cb); if (mResources) cb.NoteXPCOMChild(mResources->mLoader); if (mInsertionPointTable) @@ -370,13 +372,6 @@ nsXBLPrototypeBinding::Unlink() mImplementation->Unlink(); } -void -nsXBLPrototypeBinding::Trace(TraceCallback aCallback, void *aClosure) const -{ - if (mImplementation) - mImplementation->Trace(aCallback, aClosure); -} - void nsXBLPrototypeBinding::Initialize() { diff --git a/content/xbl/src/nsXBLPrototypeBinding.h b/content/xbl/src/nsXBLPrototypeBinding.h index 3243bd254900..83ced720db47 100644 --- a/content/xbl/src/nsXBLPrototypeBinding.h +++ b/content/xbl/src/nsXBLPrototypeBinding.h @@ -198,7 +198,6 @@ public: void Traverse(nsCycleCollectionTraversalCallback &cb) const; void Unlink(); - void Trace(TraceCallback aCallback, void *aClosure) const; // Static members static PRUint32 gRefCnt; diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 2cc482e868cf..cc28aeda5117 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -55,6 +55,7 @@ * use in OS2 */ +#include "jsapi.h" // for JS_AddNamedRoot and JS_RemoveRootRT #include "nsCOMPtr.h" #include "nsDOMCID.h" #include "nsDOMError.h" @@ -701,8 +702,7 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler( nsCOMPtr xuldoc = do_QueryInterface(mElement->GetOwnerDoc()); nsIScriptContext *context; - nsXULPrototypeElement *elem = mElement->mPrototype; - if (elem && xuldoc) { + if (mElement->mPrototype && xuldoc) { // It'll be shared among the instances of the prototype. // Use the prototype document's special context. Because @@ -755,16 +755,9 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler( XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills); // take a copy of the event handler, and tell the language about it. if (aHandler) { - NS_ASSERTION(!attr->mEventHandler, "Leaking handler."); - rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), - elem, - &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode), - aHandler, - elem->mHoldsScriptObject); + aHandler); if (NS_FAILED(rv)) return rv; - - elem->mHoldsScriptObject = PR_TRUE; } attr->mEventHandler = (void *)aHandler; } @@ -2358,40 +2351,26 @@ nsXULElement::RecompileScriptEventListeners() } } -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode) +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 = static_cast(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) } } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode) - if (tmp->mType == nsXULPrototypeNode::eType_Element) { - nsXULPrototypeElement *elem = - static_cast(tmp); - if (elem->mHoldsScriptObject) { - PRUint32 i; - for (i = 0; i < elem->mNumAttributes; ++i) { - void *handler = elem->mAttributes[i].mEventHandler; - NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(elem->mScriptTypeID, - handler) - } - } - } else if (tmp->mType == nsXULPrototypeNode::eType_Script) { - nsXULPrototypeScript *script = - static_cast(tmp); - NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(script->mScriptObject.mLangID, - script->mScriptObject.mObject) + static_cast(tmp)->mScriptObject.traverse(cb); } -NS_IMPL_CYCLE_COLLECTION_TRACE_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release) @@ -2403,6 +2382,17 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release) nsXULPrototypeAttribute::~nsXULPrototypeAttribute() { MOZ_COUNT_DTOR(nsXULPrototypeAttribute); + NS_ASSERTION(!mEventHandler, "Finalize not called - language object leak!"); +} + +void +nsXULPrototypeAttribute::Finalize(PRUint32 aLangID) +{ + if (mEventHandler) { + if (NS_FAILED(nsContentUtils::DropScriptObject(aLangID, mEventHandler))) + NS_ERROR("Failed to drop script object"); + mEventHandler = nsnull; + } } @@ -2689,19 +2679,6 @@ nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue, return NS_OK; } -void -nsXULPrototypeElement::Unlink() -{ - if (mHoldsScriptObject) { - nsContentUtils::DropScriptObjects(mScriptTypeID, this, - &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode)); - mHoldsScriptObject = PR_FALSE; - } - mNumAttributes = 0; - delete[] mAttributes; - mAttributes = nsnull; -} - //---------------------------------------------------------------------- // // nsXULPrototypeScript @@ -2724,7 +2701,6 @@ nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, P nsXULPrototypeScript::~nsXULPrototypeScript() { - Unlink(); } nsresult @@ -2842,7 +2818,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream, NS_WARNING("Language deseralization failed"); return rv; } - Set(newScriptObject); + mScriptObject.set(newScriptObject); return NS_OK; } @@ -2895,7 +2871,7 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput, NS_ERROR("XUL cache gave different language?"); return NS_ERROR_UNEXPECTED; } - Set(newScriptObject); + mScriptObject.set(newScriptObject); } } } @@ -3021,7 +2997,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText, if (NS_FAILED(rv)) return rv; - Set(newScriptObject); + mScriptObject.set(newScriptObject); return rv; } diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index b4bd2f1d4ebf..1905e8582d79 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -3729,8 +3729,7 @@ public: ~nsJSArgArray(); // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray, - nsIJSArgArray) + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsJSArgArray, nsIJSArgArray) // nsIArray NS_DECL_NSIARRAY @@ -3760,14 +3759,16 @@ nsJSArgArray::nsJSArgArray(JSContext *aContext, PRUint32 argc, jsval *argv, return; } - // Callers are allowed to pass in a nutll argv even for argc > 0. They can - // then use GetArgs to initialized the values. - if (argv) { - for (PRUint32 i = 0; i < argc; ++i) + JSAutoRequest ar(aContext); + for (PRUint32 i = 0; i < argc; ++i) { + if (argv) mArgv[i] = argv[i]; + if (!::JS_AddNamedRoot(aContext, &mArgv[i], "nsJSArgArray.mArgv[i]")) { + *prv = NS_ERROR_UNEXPECTED; + return; + } } - if (argc > 0) - *prv = NS_HOLD_JS_OBJECTS(this, nsJSArgArray); + *prv = NS_OK; } nsJSArgArray::~nsJSArgArray() @@ -3778,9 +3779,13 @@ nsJSArgArray::~nsJSArgArray() void nsJSArgArray::ReleaseJSObjects() { - if (mArgc > 0) - NS_DROP_JS_OBJECTS(this, nsJSArgArray); if (mArgv) { + NS_ASSERTION(nsJSRuntime::sRuntime, "Where's the runtime gone?"); + if (nsJSRuntime::sRuntime) { + for (PRUint32 i = 0; i < mArgc; ++i) { + ::JS_RemoveRootRT(nsJSRuntime::sRuntime, &mArgv[i]); + } + } PR_DELETE(mArgv); } mArgc = 0; @@ -3792,20 +3797,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray) tmp->ReleaseJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray) - jsval *argv = tmp->mArgv; - if (argv) { - jsval *end; - for (end = argv + tmp->mArgc; argv < end; ++argv) { - if (JSVAL_IS_GCTHING(*argv)) - NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT, - JSVAL_TO_GCTHING(*argv)) + { + jsval *argv = tmp->mArgv; + if (argv) { + jsval *end; + for (end = argv + tmp->mArgc; argv < end; ++argv) { + if (JSVAL_IS_OBJECT(*argv)) + cb.NoteScriptChild(JAVASCRIPT, JSVAL_TO_OBJECT(*argv)); + } } } -NS_IMPL_CYCLE_COLLECTION_TRACE_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray) NS_INTERFACE_MAP_ENTRY(nsIArray) diff --git a/dom/src/base/nsJSTimeoutHandler.cpp b/dom/src/base/nsJSTimeoutHandler.cpp index 989f4dd3c0cb..b2dd3e89eb7f 100644 --- a/dom/src/base/nsJSTimeoutHandler.cpp +++ b/dom/src/base/nsJSTimeoutHandler.cpp @@ -59,7 +59,7 @@ class nsJSScriptTimeoutHandler: public nsIScriptTimeoutHandler public: // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSScriptTimeoutHandler) + NS_DECL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler) nsJSScriptTimeoutHandler(); ~nsJSScriptTimeoutHandler(); @@ -118,14 +118,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSScriptTimeoutHandler) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgv) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, tmp->mFunObj); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpr) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mFunObj) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSScriptTimeoutHandler) NS_INTERFACE_MAP_ENTRY(nsIScriptTimeoutHandler) NS_INTERFACE_MAP_ENTRY(nsISupports) @@ -151,11 +146,49 @@ void nsJSScriptTimeoutHandler::ReleaseJSObjects() { if (mExpr || mFunObj) { + nsCOMPtr scx = mContext; + JSRuntime *rt = nsnull; + + if (scx) { + JSContext *cx; + cx = (JSContext *)scx->GetNativeContext(); + rt = ::JS_GetRuntime(cx); + mContext = nsnull; + } else { + // XXX The timeout *must* be unrooted, even if !scx. This can be + // done without a JS context using the JSRuntime. This is safe + // enough, but it would be better to drop all a window's + // timeouts before its context is cleared. Bug 50705 describes a + // situation where we're not. In that case, at the time the + // context is cleared, a timeout (actually an Interval) is still + // active, but temporarily removed from the window's list of + // timers (placed instead on the timer manager's list). This + // makes the nearly handy ClearAllTimeouts routine useless, so + // we settled on using the JSRuntime rather than relying on the + // window having a context. It would be good to remedy this + // workable but clumsy situation someday. + + nsCOMPtr rtsvc = + do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); + + if (rtsvc) { + rtsvc->GetRuntime(&rt); + } + } + + if (!rt) { + // most unexpected. not much choice but to bail. + + NS_ERROR("nsTimeout::Release() with no JSRuntime. eek!"); + + return; + } + if (mExpr) { - NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler); + ::JS_RemoveRootRT(rt, &mExpr); mExpr = nsnull; } else if (mFunObj) { - NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler); + ::JS_RemoveRootRT(rt, &mFunObj); mFunObj = nsnull; } else { NS_WARNING("No func and no expr - roots may not have been removed"); @@ -247,8 +280,9 @@ nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool *aIsInterval, } if (expr) { - rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler); - NS_ENSURE_SUCCESS(rv, rv); + if (!::JS_AddNamedRoot(cx, &mExpr, "timeout.mExpr")) { + return NS_ERROR_OUT_OF_MEMORY; + } mExpr = expr; @@ -258,8 +292,9 @@ nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool *aIsInterval, mFileName.Assign(filename); } } else if (funobj) { - rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler); - NS_ENSURE_SUCCESS(rv, rv); + if (!::JS_AddNamedRoot(cx, &mFunObj, "timeout.mFunObj")) { + return NS_ERROR_OUT_OF_MEMORY; + } mFunObj = funobj; diff --git a/dom/src/events/nsJSEventListener.cpp b/dom/src/events/nsJSEventListener.cpp index 46ae7c366cec..414da25a809a 100644 --- a/dom/src/events/nsJSEventListener.cpp +++ b/dom/src/events/nsJSEventListener.cpp @@ -81,13 +81,12 @@ nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext, // until we are done with it. NS_ASSERTION(aScopeObject && aContext, "EventListener with no context or scope?"); - NS_HOLD_JS_OBJECTS(this, nsJSEventListener); + aContext->HoldScriptObject(aScopeObject); } nsJSEventListener::~nsJSEventListener() { - if (mContext) - NS_DROP_JS_OBJECTS(this, nsJSEventListener); + mContext->DropScriptObject(mScopeObject); } NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener) @@ -97,14 +96,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSEventListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, tmp->mScopeObject); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener) - NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(), - mScopeObject) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsIJSEventListener) diff --git a/dom/src/events/nsJSEventListener.h b/dom/src/events/nsJSEventListener.h index d7de952c1803..542d113d8384 100644 --- a/dom/src/events/nsJSEventListener.h +++ b/dom/src/events/nsJSEventListener.h @@ -65,8 +65,8 @@ public: // nsIJSEventListener interface virtual void SetEventName(nsIAtom* aName); - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSEventListener, - nsIDOMEventListener) + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsJSEventListener, + nsIDOMEventListener) protected: nsCOMPtr mEventName; diff --git a/js/src/xpconnect/idl/nsIXPCScriptable.idl b/js/src/xpconnect/idl/nsIXPCScriptable.idl index 00c8edd905cf..7c37283480ee 100644 --- a/js/src/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl @@ -41,8 +41,6 @@ #include "nsISupports.idl" #include "nsIXPConnect.idl" -[ptr] native JSTracerPtr(JSTracer); - %{ C++ #define NS_SUCCESS_I_DID_SOMETHING \ (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,1)) diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index 5a75871cd3d1..a523c7c7c104 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -64,7 +64,7 @@ native JSVal(jsval); native JSID(jsid); [ptr] native voidPtrPtr(void*); -[ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer); +[ptr] native JSTracerPtr(JSTracer); /***************************************************************************/ @@ -150,7 +150,7 @@ interface nsIXPCSecurityManager; interface nsIPrincipal; %{C++ -class nsScriptObjectTracer; +class nsCycleCollectionTraversalCallback; %} /***************************************************************************/ @@ -727,18 +727,4 @@ interface nsIXPConnect : nsISupports [noscript] JSVal getCrossOriginWrapperForObject(in JSContextPtr aJSContext, in JSObjectPtr aParent, in JSObjectPtr aWrappedObj); - - /** - * Root JS objects held by aHolder. - * @param aHolder The object that hold the JS objects that should be rooted. - * @param aTrace The tracer for aHolder. - */ - [noscript] void addJSHolder(in voidPtr aHolder, - in nsScriptObjectTracerPtr aTracer); - - /** - * Stop rooting the JS objects held by aHolder. - * @param aHolder The object that hold the rooted JS objects. - */ - [noscript] void removeJSHolder(in voidPtr aHolder); }; diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 839c6a3efb03..91e9f94551dd 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -695,31 +695,16 @@ NoteJSChild(JSTracer *trc, void *thing, uint32 kind) static uint8 GCTypeToTraceKindMap[GCX_NTYPES] = { JSTRACE_OBJECT, /* GCX_OBJECT */ - JSTRACE_STRING, /* GCX_STRING */ - JSTRACE_DOUBLE, /* GCX_DOUBLE */ - JSTRACE_FUNCTION, /* GCX_FUNCTION */ + JSTRACE_STRING, /* GCX_STRING (unused) */ + JSTRACE_DOUBLE, /* GCX_DOUBLE (unused) */ + JSTRACE_STRING, /* GCX_MUTABLE_STRING (unused) */ + JSTRACE_FUNCTION, /* GCX_FUNCTION (unused) */ JSTRACE_NAMESPACE, /* GCX_NAMESPACE */ JSTRACE_QNAME, /* GCX_QNAME */ - JSTRACE_XML, /* GCX_XML */ - (uint8)-1, /* unused */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 0 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 1 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 2 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 3 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 4 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 5 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 6 */ - JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 7 */ + JSTRACE_XML /* GCX_XML */ + // We don't care about JSTRACE_STRING, so stop here }; -// static -uint8 -nsXPConnect::GetTraceKind(void *thing) -{ - uint8 type = *js_GetGCThingFlags(thing) & GCF_TYPEMASK; - return GCTypeToTraceKindMap[type]; -} - NS_IMETHODIMP nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) { @@ -731,7 +716,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) PRUint32 refcount = mObjRefcounts->Get(p); NS_ASSERTION(refcount > 0, "JS object but unknown to the JS GC?"); - uint8 ty = GetTraceKind(p); + uint8 ty = *js_GetGCThingFlags(p) & GCF_TYPEMASK; if(ty != GCX_OBJECT && ty != GCX_NAMESPACE && ty != GCX_QNAME && ty != GCX_XML) return NS_OK; @@ -2112,18 +2097,6 @@ nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread) return NS_ERROR_UNEXPECTED; } -NS_IMETHODIMP -nsXPConnect::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) -{ - return mRuntime->AddJSHolder(aHolder, aTracer); -} - -NS_IMETHODIMP -nsXPConnect::RemoveJSHolder(void* aHolder) -{ - return mRuntime->RemoveJSHolder(aHolder); -} - #ifdef DEBUG /* These are here to be callable from a debugger */ JS_BEGIN_EXTERN_C diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index ced529b9ae79..b02612fc5ad7 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -251,42 +251,6 @@ ContextCallback(JSContext *cx, uintN operation) : JS_TRUE; } -struct ObjectHolder : public JSDHashEntryHdr -{ - void *holder; - nsScriptObjectTracer* tracer; -}; - -nsresult -XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) -{ - if(!mJSHolders.ops) - return NS_ERROR_OUT_OF_MEMORY; - - ObjectHolder *entry = - reinterpret_cast(JS_DHashTableOperate(&mJSHolders, - aHolder, - JS_DHASH_ADD)); - if(!entry) - return NS_ERROR_OUT_OF_MEMORY; - - entry->holder = aHolder; - entry->tracer = aTracer; - - return NS_OK; -} - -nsresult -XPCJSRuntime::RemoveJSHolder(void* aHolder) -{ - if(!mJSHolders.ops) - return NS_ERROR_OUT_OF_MEMORY; - - JS_DHashTableOperate(&mJSHolders, aHolder, JS_DHASH_REMOVE); - - return NS_OK; -} - // static void XPCJSRuntime::TraceJS(JSTracer* trc, void* data) { @@ -313,48 +277,16 @@ void XPCJSRuntime::TraceJS(JSTracer* trc, void* data) } } - // XPCJSObjectHolders don't participate in cycle collection, so always trace - // them here. - for(XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot()) - static_cast(e)->TraceJS(trc); - - self->TraceXPConnectRoots(trc); -} + XPCWrappedNativeScope::TraceJS(trc, self); -PR_STATIC_CALLBACK(void) -TraceJSObject(PRUint32 aLangID, void *aScriptThing, void *aClosure) -{ - if(aLangID == nsIProgrammingLanguage::JAVASCRIPT) - { - JS_CALL_TRACER(static_cast(aClosure), aScriptThing, - nsXPConnect::GetXPConnect()->GetTraceKind(aScriptThing), - "JSObjectHolder"); - } -} - -JS_STATIC_DLL_CALLBACK(JSDHashOperator) -TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, - void *arg) -{ - ObjectHolder* entry = reinterpret_cast(hdr); - - entry->tracer->Trace(entry->holder, TraceJSObject, arg); - - return JS_DHASH_NEXT; -} - -void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc) -{ - XPCWrappedNativeScope::TraceJS(trc, this); - - for(XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) + for (XPCRootSetElem *e = self->mVariantRoots; e ; e = e->GetNextRoot()) static_cast(e)->TraceJS(trc); - for(XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) + for (XPCRootSetElem *e = self->mWrappedJSRoots; e ; e = e->GetNextRoot()) static_cast(e)->TraceJS(trc); - if(mJSHolders.ops) - JS_DHashTableEnumerate(&mJSHolders, TraceJSHolder, trc); + for (XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot()) + static_cast(e)->TraceJS(trc); } // static @@ -877,12 +809,6 @@ XPCJSRuntime::~XPCJSRuntime() gOldJSGCCallback = NULL; gOldJSContextCallback = NULL; - - if(mJSHolders.ops) - { - JS_DHashTableFinish(&mJSHolders); - mJSHolders.ops = nsnull; - } } XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect, @@ -936,10 +862,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect, JS_SetExtraGCRoots(mJSRuntime, TraceJS, this); } - if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull, - sizeof(ObjectHolder), 512)) - mJSHolders.ops = nsnull; - // Install a JavaScript 'debugger' keyword handler in debug builds only #ifdef DEBUG if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler) diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 31ed95b2e080..0bcc64caaf14 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -498,9 +498,6 @@ public: #endif JSObjectRefcounts* GetJSObjectRefcounts() {return mObjRefcounts;} - - static uint8 GetTraceKind(void *thing); - #ifndef XPCONNECT_STANDALONE void RecordTraversal(void *p, nsISupports *s); #endif @@ -679,9 +676,6 @@ public: } static void JS_DLL_CALLBACK TraceJS(JSTracer* trc, void* data); - void TraceXPConnectRoots(JSTracer *trc); - void AddXPConnectRoots(JSContext* cx, - nsCycleCollectionTraversalCallback& cb); static JSBool JS_DLL_CALLBACK GCCallback(JSContext *cx, JSGCStatus status); @@ -689,9 +683,6 @@ public: inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS); inline void AddObjectHolderRoot(XPCJSObjectHolder* holder); - nsresult AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer); - nsresult RemoveJSHolder(void* aHolder); - void DebugDump(PRInt16 depth); void SystemIsBeingShutDown(JSContext* cx); @@ -755,7 +746,6 @@ private: XPCRootSetElem *mVariantRoots; XPCRootSetElem *mWrappedJSRoots; XPCRootSetElem *mObjectHolderRoots; - JSDHashTable mJSHolders; }; /***************************************************************************/ @@ -1201,6 +1191,8 @@ public: static void InitStatics() { gScopes = nsnull; gDyingScopes = nsnull; } + void Traverse(nsCycleCollectionTraversalCallback &cb); + #ifndef XPCONNECT_STANDALONE /** * Fills the hash mapping global object to principal. @@ -1939,11 +1931,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) - NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(XPCWrappedNative) #ifndef XPCONNECT_STANDALONE virtual nsIPrincipal* GetObjectPrincipal() const; @@ -2053,7 +2044,7 @@ public: nsISupports* aCOMObj, XPCWrappedNative** aWrapper); - void FlatJSObjectFinalized(JSContext *cx); + void FlatJSObjectFinalized(JSContext *cx, JSObject *obj); void SystemIsBeingShutDown(JSContext* cx); @@ -2205,10 +2196,8 @@ private: XPCWrappedNativeTearOffChunk mFirstChunk; JSObject* mWrapper; -#ifdef XPC_CHECK_WRAPPER_THREADSAFETY public: nsCOMPtr mThread; // Don't want to overload _mOwningThread -#endif }; /*************************************************************************** @@ -3039,6 +3028,7 @@ private: JSUint32 mWrappedNativeThreadsafetyReportDepth; #endif PRThread* mThread; + nsVoidArray mNativesToReleaseArray; static PRLock* gLock; static XPCPerThreadData* gThreads; diff --git a/js/src/xpconnect/src/xpcwrappedjs.cpp b/js/src/xpconnect/src/xpcwrappedjs.cpp index 8eed14c1d4fc..32cd5edcf712 100644 --- a/js/src/xpconnect/src/xpcwrappedjs.cpp +++ b/js/src/xpconnect/src/xpcwrappedjs.cpp @@ -589,6 +589,10 @@ nsXPCWrappedJS::SystemIsBeingShutDown(JSRuntime* rt) // work (and avoid crashing some platforms). mJSObj = nsnull; + // There is no reason to keep this root any longer. Since we've cleared + // mJSObj our dtor will not remove the root later. So, we do it now. + JS_RemoveRootRT(rt, &mJSObj); + // Notify other wrappers in the chain. if(mNext) mNext->SystemIsBeingShutDown(rt); diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index ed78d2add53a..2b1d3e88b820 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -961,7 +961,7 @@ NS_IMPL_THREADSAFE_RELEASE(XPCWrappedNative) */ void -XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx) +XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx, JSObject *obj) { if(!IsValid()) return; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 674e457af3c8..32d084a7cb6f 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -647,7 +647,7 @@ XPC_WN_NoHelper_Finalize(JSContext *cx, JSObject *obj) XPCWrappedNative* p = (XPCWrappedNative*) JS_GetPrivate(cx, obj); if(!p) return; - p->FlatJSObjectFinalized(cx); + p->FlatJSObjectFinalized(cx, obj); } static void @@ -658,7 +658,7 @@ TraceScopeJSObjects(JSTracer *trc, XPCWrappedNativeScope* scope) JSObject* obj; obj = scope->GetGlobalJSObject(); - NS_ASSERTION(obj, "bad scope JSObject"); + NS_ASSERTION(scope, "bad scope JSObject"); JS_CALL_OBJECT_TRACER(trc, obj, "XPCWrappedNativeScope::mGlobalJSObject"); obj = scope->GetPrototypeJSObject(); @@ -1035,7 +1035,7 @@ XPC_WN_Helper_Finalize(JSContext *cx, JSObject *obj) if(!wrapper) return; wrapper->GetScriptableCallback()->Finalize(wrapper, cx, obj); - wrapper->FlatJSObjectFinalized(cx); + wrapper->FlatJSObjectFinalized(cx, obj); } JS_STATIC_DLL_CALLBACK(void) diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp index e167780f0167..ea9c5b6d588f 100644 --- a/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -851,6 +851,16 @@ XPCWrappedNativeScope::DebugDump(PRInt16 depth) #endif } +void +XPCWrappedNativeScope::Traverse(nsCycleCollectionTraversalCallback &cb) +{ + // See TraceScopeJSObjects. + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mGlobalJSObject); + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, mPrototypeJSObject); + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + mPrototypeJSFunction); +} + #ifndef XPCONNECT_STANDALONE // static void diff --git a/xpcom/base/nsAgg.h b/xpcom/base/nsAgg.h index 294a50d97d77..2ba68b5477c8 100644 --- a/xpcom/base/nsAgg.h +++ b/xpcom/base/nsAgg.h @@ -118,8 +118,7 @@ public: \ { \ return p->InnerObject(); \ } \ -}; \ -NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE +}; // Put this in your class's constructor: #define NS_INIT_AGGREGATED(outer) \ diff --git a/xpcom/glue/nsCycleCollectionParticipant.cpp b/xpcom/glue/nsCycleCollectionParticipant.cpp index 4e0e3a2a3e7f..5a90aaf536ce 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.cpp +++ b/xpcom/glue/nsCycleCollectionParticipant.cpp @@ -38,21 +38,6 @@ #include "nsCycleCollectionParticipant.h" #include "nsCOMPtr.h" -PR_STATIC_CALLBACK(void) -NoteChild(PRUint32 aLangID, void *aScriptThing, void *aClosure) -{ - nsCycleCollectionTraversalCallback *cb = - static_cast(aClosure); - cb->NoteScriptChild(aLangID, aScriptThing); -} - -void -nsScriptObjectTracer::TraverseScriptObjects(void *p, - nsCycleCollectionTraversalCallback &cb) -{ - Trace(p, NoteChild, &cb); -} - nsresult nsXPCOMCycleCollectionParticipant::Root(void *p) { @@ -87,12 +72,6 @@ nsXPCOMCycleCollectionParticipant::UnmarkPurple(nsISupports *n) { } -NS_IMETHODIMP_(void) -nsXPCOMCycleCollectionParticipant::Trace(void *p, TraceCallback cb, - void *closure) -{ -} - PRBool nsXPCOMCycleCollectionParticipant::CheckForRightISupports(nsISupports *s) { diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index f81c42975f68..fdb54f2292dc 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -125,19 +125,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant, #undef IMETHOD_VISIBILITY #define IMETHOD_VISIBILITY NS_COM_GLUE -typedef void -(* PR_CALLBACK TraceCallback)(PRUint32 langID, void *p, void *closure); - -class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant -{ -public: - NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure) = 0; - void NS_COM_GLUE TraverseScriptObjects(void *p, - nsCycleCollectionTraversalCallback &cb); -}; - class NS_COM_GLUE nsXPCOMCycleCollectionParticipant - : public nsScriptObjectTracer + : public nsCycleCollectionParticipant { public: NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb); @@ -146,8 +135,6 @@ public: NS_IMETHOD Unlink(void *p); NS_IMETHOD Unroot(void *p); - NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); - NS_IMETHOD_(void) UnmarkPurple(nsISupports *p); PRBool CheckForRightISupports(nsISupports *s); @@ -166,11 +153,8 @@ public: #define NS_CYCLE_COLLECTION_CLASSNAME(_class) \ _class::NS_CYCLE_COLLECTION_INNERCLASS -#define NS_CYCLE_COLLECTION_INNERNAME \ - _cycleCollectorGlobal - #define NS_CYCLE_COLLECTION_NAME(_class) \ - _class::NS_CYCLE_COLLECTION_INNERNAME + _class##_cycleCollectorGlobal #define NS_IMPL_QUERY_CYCLE_COLLECTION(_class) \ if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \ @@ -217,8 +201,6 @@ public: } \ nsresult rv; -#define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \ - NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj) /////////////////////////////////////////////////////////////////////////////// // Helpers for implementing nsCycleCollectionParticipant::Unlink @@ -341,7 +323,7 @@ public: } #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(_ptr, _ptr_class) \ - cb.NoteNativeChild(_ptr, &NS_CYCLE_COLLECTION_NAME(_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) @@ -358,61 +340,18 @@ public: _element_class) \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(tmp->_field, _element_class) -#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - TraverseScriptObjects(tmp, cb); - #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ return NS_OK; \ } -/////////////////////////////////////////////////////////////////////////////// -// Helpers for implementing nsScriptObjectTracer::Trace -/////////////////////////////////////////////////////////////////////////////// - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \ - void \ - NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \ - TraceCallback aCallback, \ - void *aClosure) \ - { \ - nsISupports *s = static_cast(p); \ - NS_ASSERTION(CheckForRightISupports(s), \ - "not the nsISupports pointer we expect"); \ - _class *tmp = Downcast(s); - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(_class) \ - void \ - NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \ - TraceCallback aCallback, \ - void *aClosure) \ - { \ - _class *tmp = static_cast<_class*>(p); - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(_langID, _object) \ - if (_object) \ - aCallback(_langID, _object, aClosure); - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(_langID, _field) \ - NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(_langID, tmp->_field) - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(_object) \ - NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(nsIProgrammingLanguage::JAVASCRIPT, \ - _object); - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \ - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->_field) - -#define NS_IMPL_CYCLE_COLLECTION_TRACE_END \ - } - /////////////////////////////////////////////////////////////////////////////// // Helpers for implementing a concrete nsCycleCollectionParticipant /////////////////////////////////////////////////////////////////////////////// -#define NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE \ - static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; - -#define NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ +#define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base) \ +class NS_CYCLE_COLLECTION_INNERCLASS \ + : public nsXPCOMCycleCollectionParticipant \ +{ \ public: \ NS_IMETHOD Unlink(void *p); \ NS_IMETHOD Traverse(void *p, \ @@ -428,31 +367,12 @@ public: \ static nsISupports* Upcast(_class *p) \ { \ return NS_ISUPPORTS_CAST(_base*, p); \ - } - -#define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base) \ -class NS_CYCLE_COLLECTION_INNERCLASS \ - : public nsXPCOMCycleCollectionParticipant \ -{ \ - NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ -}; \ -NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE + } \ +}; #define NS_DECL_CYCLE_COLLECTION_CLASS(_class) \ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _class) -#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \ -class NS_CYCLE_COLLECTION_INNERCLASS \ - : public nsXPCOMCycleCollectionParticipant \ -{ \ - NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ - NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \ -}; \ -NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE - -#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(_class) \ - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class) - #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_class, _base_class) \ class NS_CYCLE_COLLECTION_INNERCLASS \ : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \ @@ -466,8 +386,7 @@ public: \ return static_cast<_class*>(static_cast<_base_class*>( \ NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s))); \ } \ -}; \ -NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE +}; #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(_class, \ _base_class) \ @@ -482,8 +401,7 @@ public: \ return static_cast<_class*>(static_cast<_base_class*>( \ NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s))); \ } \ -}; \ -NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE +}; /** * This implements a stub UnmarkPurple function for classes that want to be @@ -497,32 +415,31 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE } \ #define NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_CYCLE_COLLECTION_CLASSNAME(_class) NS_CYCLE_COLLECTION_NAME(_class); + static NS_CYCLE_COLLECTION_CLASSNAME(_class) \ + NS_CYCLE_COLLECTION_NAME(_class); -#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY \ - public: \ - NS_IMETHOD Root(void *n); \ - NS_IMETHOD Unlink(void *n); \ - NS_IMETHOD Unroot(void *n); \ - NS_IMETHOD Traverse(void *n, \ - nsCycleCollectionTraversalCallback &cb); +#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 \ { \ - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY \ + public: \ + NS_IMETHOD Root(void *n); \ + NS_IMETHOD Unlink(void *n); \ + NS_IMETHOD Unroot(void *n); \ + NS_IMETHOD Traverse(void *n, \ + nsCycleCollectionTraversalCallback &cb); \ }; \ - NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE + static NS_CYCLE_COLLECTION_INNERCLASS \ + NS_CYCLE_COLLECTION_NATIVE_INNERNAME; -#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class) \ - class NS_CYCLE_COLLECTION_INNERCLASS \ - : public nsScriptObjectTracer \ - { \ - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY \ - NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \ - }; \ - NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE +#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 \