Fix for bug 407034 (JS_Assert "!rt->gcRunning" unbinding link elements in cycle collector with JS protocol handlers), r/sr=dbaron.

This commit is contained in:
peterv@propagandism.org 2008-01-29 12:48:32 -08:00
parent 122cc4ab89
commit 55896575d9
18 changed files with 150 additions and 72 deletions

View File

@ -445,10 +445,10 @@ TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
}
static PRIntn PR_CALLBACK
UnlinkProtos(nsHashKey *aKey, void *aData, void* aClosure)
UnlinkProtoJSObjects(nsHashKey *aKey, void *aData, void* aClosure)
{
nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
proto->Unlink();
proto->UnlinkJSObjects();
return kHashEnumerateNext;
}
@ -468,10 +468,12 @@ TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsXBLDocumentInfo)
if (tmp->mBindingTable) {
tmp->mBindingTable->Enumerate(UnlinkProtos, nsnull);
tmp->mBindingTable->Enumerate(UnlinkProtoJSObjects, nsnull);
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObject)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

View File

@ -216,7 +216,7 @@ nsXBLProtoImpl::Trace(TraceCallback aCallback, void *aClosure) const
}
void
nsXBLProtoImpl::Unlink()
nsXBLProtoImpl::UnlinkJSObjects()
{
if (mClassObject) {
DestroyMembers(nsnull);

View File

@ -91,7 +91,7 @@ public:
}
void Trace(TraceCallback aCallback, void *aClosure) const;
void Unlink();
void UnlinkJSObjects();
nsXBLProtoImplField* FindField(const nsString& aFieldName) const;

View File

@ -364,14 +364,14 @@ nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
}
void
nsXBLPrototypeBinding::Unlink()
nsXBLPrototypeBinding::UnlinkJSObjects()
{
if (mImplementation)
mImplementation->Unlink();
mImplementation->UnlinkJSObjects();
nsXBLPrototypeHandler* curr = mPrototypeHandler;
while (curr) {
curr->Unlink();
curr->UnlinkJSObjects();
curr = curr->GetNextHandler();
}
}

View File

@ -197,7 +197,7 @@ public:
nsIContent* aElement);
void Traverse(nsCycleCollectionTraversalCallback &cb) const;
void Unlink();
void UnlinkJSObjects();
void Trace(TraceCallback aCallback, void *aClosure) const;
// Static members

View File

@ -169,7 +169,7 @@ nsXBLPrototypeHandler::Trace(TraceCallback aCallback, void *aClosure) const
}
void
nsXBLPrototypeHandler::Unlink()
nsXBLPrototypeHandler::UnlinkJSObjects()
{
ForgetCachedHandler();
}

View File

@ -154,7 +154,7 @@ public:
}
void Trace(TraceCallback aCallback, void *aClosure) const;
void Unlink();
void UnlinkJSObjects();
public:
static PRUint32 gRefCnt;

View File

@ -2416,9 +2416,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXULPrototypeNode)
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
static_cast<nsXULPrototypeElement*>(tmp)->Unlink();
}
else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
static_cast<nsXULPrototypeScript*>(tmp)->Unlink();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode)
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
@ -2452,7 +2449,15 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode)
script->mScriptObject.mObject)
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN_NATIVE(nsXULPrototypeNode, AddRef)
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
static_cast<nsXULPrototypeElement*>(tmp)->UnlinkJSObjects();
}
else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
static_cast<nsXULPrototypeScript*>(tmp)->UnlinkJSObjects();
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
//NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release)
//----------------------------------------------------------------------
@ -2750,13 +2755,18 @@ nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
}
void
nsXULPrototypeElement::Unlink()
nsXULPrototypeElement::UnlinkJSObjects()
{
if (mHoldsScriptObject) {
nsContentUtils::DropScriptObjects(mScriptTypeID, this,
&NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
mHoldsScriptObject = PR_FALSE;
}
}
void
nsXULPrototypeElement::Unlink()
{
mNumAttributes = 0;
delete[] mAttributes;
mAttributes = nsnull;
@ -2784,7 +2794,7 @@ nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, P
nsXULPrototypeScript::~nsXULPrototypeScript()
{
Unlink();
UnlinkJSObjects();
}
nsresult

View File

@ -254,6 +254,7 @@ public:
virtual ~nsXULPrototypeElement()
{
UnlinkJSObjects();
Unlink();
NS_ASSERTION(!mChildren && mNumChildren == 0,
"ReleaseSubtree not called");
@ -289,6 +290,7 @@ public:
nsresult SetAttrAt(PRUint32 aPos, const nsAString& aValue, nsIURI* aDocumentURI);
void UnlinkJSObjects();
void Unlink();
PRUint32 mNumChildren;
@ -359,7 +361,7 @@ public:
nsIDocument* aDocument,
nsIScriptGlobalObjectOwner* aGlobalOwner);
void Unlink()
void UnlinkJSObjects()
{
if (mScriptObject.mObject) {
nsContentUtils::DropScriptObjects(mScriptObject.mLangID, this,

View File

@ -3841,9 +3841,10 @@ nsJSArgArray::ReleaseJSObjects()
// QueryInterface implementation for nsJSArgArray
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray)
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSArgArray)
tmp->ReleaseJSObjects();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsJSArgArray)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

View File

@ -112,9 +112,10 @@ private:
// nsJSScriptTimeoutHandler
// QueryInterface implementation for nsJSScriptTimeoutHandler
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSScriptTimeoutHandler)
tmp->ReleaseJSObjects();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgv)

View File

@ -81,21 +81,34 @@ 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);
nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
aScopeObject, PR_FALSE);
}
nsJSEventListener::~nsJSEventListener()
{
if (mContext)
NS_DROP_JS_OBJECTS(this, nsJSEventListener);
nsContentUtils::DropScriptObjects(mContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSEventListener)
if (tmp->mContext &&
tmp->mContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {
NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
tmp->mScopeObject = nsnull;
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTarget)
if (tmp->mContext) {
tmp->mScopeObject = nsnull;
NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
if (tmp->mScopeObject) {
nsContentUtils::DropScriptObjects(tmp->mContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
tmp->mScopeObject = nsnull;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

View File

@ -679,7 +679,7 @@ nsXPConnect::ToParticipant(void *p)
}
NS_IMETHODIMP
nsXPConnect::Root(void *p)
nsXPConnect::RootAndUnlinkJSObjects(void *p)
{
return NS_OK;
}
@ -937,7 +937,7 @@ nsXPConnect::GetRequestDepth(JSContext* cx)
class JSContextParticipant : public nsCycleCollectionParticipant
{
public:
NS_IMETHOD Root(void *n)
NS_IMETHOD RootAndUnlinkJSObjects(void *n)
{
return NS_OK;
}

View File

@ -497,7 +497,7 @@ public:
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
// nsCycleCollectionParticipant
NS_IMETHOD Root(void *p);
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
NS_IMETHOD Unlink(void *p);
NS_IMETHOD Unroot(void *p);
NS_IMETHOD Traverse(void *p,
@ -2488,8 +2488,14 @@ public:
NS_DECL_NSIXPCONNECTWRAPPEDJS
NS_DECL_NSISUPPORTSWEAKREFERENCE
NS_DECL_NSIPROPERTYBAG
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXPCWrappedJS,
nsIXPConnectWrappedJS)
class NS_CYCLE_COLLECTION_INNERCLASS
: public nsXPCOMCycleCollectionParticipant
{
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
NS_DECL_CYCLE_COLLECTION_CLASS_BODY(nsXPCWrappedJS, nsIXPConnectWrappedJS)
};
NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(nsXPCWrappedJS)
NS_IMETHOD CallMethod(PRUint16 methodIndex,

View File

@ -112,17 +112,35 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsXPCWrappedJS)
if(tmp->mRoot && !tmp->mRoot->HasWeakReferences() && tmp->IsValid())
{
XPCJSRuntime* rt = nsXPConnect::GetRuntime();
if(rt)
{
if(tmp->mRoot == tmp)
{
// remove this root wrapper from the map
JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
if(map)
{
XPCAutoLock lock(rt->GetMapLock());
map->Remove(tmp);
}
}
if(tmp->mRefCnt > 1)
tmp->RemoveFromRootSet(rt->GetJSRuntime());
}
tmp->mJSObj = nsnull;
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXPCWrappedJS)
if(tmp->mRoot && !tmp->mRoot->HasWeakReferences())
{
tmp->Unlink();
if(tmp->IsValid())
{
XPCJSRuntime* rt = nsXPConnect::GetRuntime();
if(tmp->mRefCnt > 1)
tmp->RemoveFromRootSet(rt->GetJSRuntime());
tmp->mJSObj = nsnull;
}
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -151,9 +169,6 @@ nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
NS_IMETHODIMP
nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if(!IsValid())
return NS_ERROR_UNEXPECTED;
if(nsnull == aInstancePtr)
{
NS_PRECONDITION(0, "null pointer");
@ -173,6 +188,9 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
return NS_OK;
}
if(!IsValid())
return NS_ERROR_UNEXPECTED;
// Always check for this first so that our 'outer' can get this interface
// from us without recurring into a call to the outer's QI!
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
@ -453,17 +471,9 @@ nsXPCWrappedJS::~nsXPCWrappedJS()
{
// Let the nsWeakReference object (if present) know of our demise.
ClearWeakReferences();
}
Unlink();
}
void
nsXPCWrappedJS::Unlink()
{
XPCJSRuntime* rt = nsXPConnect::GetRuntime();
if(mRoot == this)
{
// remove this root wrapper from the map
// Remove this root wrapper from the map
XPCJSRuntime* rt = nsXPConnect::GetRuntime();
if(rt)
{
JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
@ -474,7 +484,13 @@ nsXPCWrappedJS::Unlink()
}
}
}
else if(mRoot)
Unlink();
}
void
nsXPCWrappedJS::Unlink()
{
if(mRoot != this && mRoot)
{
// unlink this wrapper
nsXPCWrappedJS* cur = mRoot;
@ -497,6 +513,7 @@ nsXPCWrappedJS::Unlink()
NS_IF_RELEASE(mClass);
if (mOuter)
{
XPCJSRuntime* rt = nsXPConnect::GetRuntime();
if (rt && rt->GetThreadRunningGC())
{
rt->DeferredRelease(mOuter);

View File

@ -878,8 +878,8 @@ struct nsCycleCollector
void SelectPurple();
void MarkRoots(GCGraphBuilder &builder);
void ScanRoots();
void CollectWhite();
PRBool UnrootWhite(); // returns whether anything was collected
void RootWhite();
PRBool CollectWhite(); // returns whether anything was collected
nsCycleCollector();
~nsCycleCollector();
@ -1525,7 +1525,7 @@ nsCycleCollector::ScanRoots()
////////////////////////////////////////////////////////////////////////
void
nsCycleCollector::CollectWhite()
nsCycleCollector::RootWhite()
{
// Explanation of "somewhat modified": we have no way to collect the
// set of whites "all at once", we have to ask each of them to drop
@ -1562,11 +1562,17 @@ nsCycleCollector::CollectWhite()
PRUint32 i, count = mBuf.GetSize();
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = static_cast<PtrInfo*>(mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Root(pinfo->mPointer);
rv = pinfo->mParticipant->RootAndUnlinkJSObjects(pinfo->mPointer);
if (NS_FAILED(rv))
Fault("Failed root call while unlinking", pinfo);
}
}
PRBool
nsCycleCollector::CollectWhite()
{
nsresult rv;
PRUint32 i, count = mBuf.GetSize();
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = static_cast<PtrInfo*>(mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Unlink(pinfo->mPointer);
@ -1582,13 +1588,7 @@ nsCycleCollector::CollectWhite()
#endif
}
}
}
PRBool
nsCycleCollector::UnrootWhite()
{
nsresult rv;
PRUint32 i, count = mBuf.GetSize();
for (i = 0; i < count; ++i) {
PtrInfo *pinfo = static_cast<PtrInfo*>(mBuf.ObjectAt(i));
rv = pinfo->mParticipant->Unroot(pinfo->mPointer);
@ -2286,7 +2286,7 @@ nsCycleCollector::BeginCollection()
#ifdef COLLECT_TIME_DEBUG
now = PR_Now();
#endif
CollectWhite();
RootWhite();
#ifdef COLLECT_TIME_DEBUG
printf("cc: CollectWhite() took %lldms\n",
@ -2300,7 +2300,7 @@ nsCycleCollector::BeginCollection()
PRBool
nsCycleCollector::FinishCollection()
{
PRBool collected = UnrootWhite();
PRBool collected = CollectWhite();
#ifdef DEBUG_CC
mStats.mCollection++;

View File

@ -54,7 +54,7 @@ nsScriptObjectTracer::TraverseScriptObjects(void *p,
}
nsresult
nsXPCOMCycleCollectionParticipant::Root(void *p)
nsXPCOMCycleCollectionParticipant::RootAndUnlinkJSObjects(void *p)
{
nsISupports *s = static_cast<nsISupports*>(p);
NS_ADDREF(s);

View File

@ -122,7 +122,7 @@ public:
NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) = 0;
NS_IMETHOD Root(void *p) = 0;
NS_IMETHOD RootAndUnlinkJSObjects(void *p) = 0;
NS_IMETHOD Unlink(void *p) = 0;
NS_IMETHOD Unroot(void *p) = 0;
};
@ -150,7 +150,7 @@ class NS_COM_GLUE nsXPCOMCycleCollectionParticipant
public:
NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
NS_IMETHOD Root(void *p);
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
NS_IMETHOD Unlink(void *p);
NS_IMETHOD Unroot(void *p);
@ -228,6 +228,31 @@ public:
#define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \
NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj)
///////////////////////////////////////////////////////////////////////////////
// Helpers for implementing nsCycleCollectionParticipant::RootAndUnlinkJSObjects
///////////////////////////////////////////////////////////////////////////////
#define NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(_class) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::RootAndUnlinkJSObjects(void *p) \
{ \
nsISupports *s = static_cast<nsISupports*>(p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
nsXPCOMCycleCollectionParticipant::RootAndUnlinkJSObjects(s); \
_class *tmp = Downcast(s);
#define NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN_NATIVE(_class, _root_function) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::RootAndUnlinkJSObjects(void *p) \
{ \
_class *tmp = static_cast<_class*>(p); \
tmp->_root_function();
#define NS_IMPL_CYCLE_COLLECTION_ROOT_END \
return NS_OK; \
}
///////////////////////////////////////////////////////////////////////////////
// Helpers for implementing nsCycleCollectionParticipant::Unlink
///////////////////////////////////////////////////////////////////////////////
@ -454,13 +479,13 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
// Cycle collector helper for classes that don't want to unlink anything.
// Note: if this is used a lot it might make sense to have a base class that
// doesn't do anything in Root/Unlink/Unroot.
// doesn't do anything in RootAndUnlinkJSObjects/Unlink/Unroot.
#define NS_DECL_CYCLE_COLLECTION_CLASS_NO_UNLINK(_class) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsXPCOMCycleCollectionParticipant \
{ \
NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(_class, _class) \
NS_IMETHOD Root(void *p) \
NS_IMETHOD RootAndUnlinkJSObjects(void *p) \
{ \
return NS_OK; \
} \
@ -479,6 +504,7 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsXPCOMCycleCollectionParticipant \
{ \
NS_IMETHOD RootAndUnlinkJSObjects(void *p); \
NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \
}; \
@ -535,7 +561,7 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY \
public: \
NS_IMETHOD Root(void *n); \
NS_IMETHOD RootAndUnlinkJSObjects(void *n); \
NS_IMETHOD Unlink(void *n); \
NS_IMETHOD Unroot(void *n); \
NS_IMETHOD Traverse(void *n, \
@ -560,7 +586,7 @@ NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
#define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function) \
NS_IMETHODIMP \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::Root(void *p) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::RootAndUnlinkJSObjects(void *p) \
{ \
_class *tmp = static_cast<_class*>(p); \
tmp->_root_function(); \