зеркало из https://github.com/mozilla/gecko-dev.git
Bug 414977 - "insufficient unlink methods in some DOM classes?". Allow the cycle collector to unlink XPCWrappedNatives in one cycle instead of two. r=peterv, sr=jst, a1.9b4+=schrep.
This commit is contained in:
Родитель
c6fbe64265
Коммит
05abaea802
|
@ -1088,8 +1088,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
|
||||
|
||||
// Unlink any associated preserved wrapper.
|
||||
tmp->RemoveReference(tmp);
|
||||
// Drop the content hash.
|
||||
delete tmp->mContentWrapperHash;
|
||||
tmp->mContentWrapperHash = nsnull;
|
||||
|
||||
tmp->mParentDocument = nsnull;
|
||||
|
||||
|
|
|
@ -2079,7 +2079,16 @@ public:
|
|||
// Root/Unroot methods, to avoid root/unrooting the JS objects from
|
||||
// addrefing/releasing the XPCWrappedNative during unlinking, which would
|
||||
// make the JS objects uncollectable to the JS GC.
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_NO_UNLINK(XPCWrappedNative)
|
||||
class NS_CYCLE_COLLECTION_INNERCLASS
|
||||
: public nsXPCOMCycleCollectionParticipant
|
||||
{
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(XPCWrappedNative,
|
||||
XPCWrappedNative)
|
||||
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
|
||||
NS_IMETHOD Unlink(void *p) { return NS_OK; }
|
||||
NS_IMETHOD Unroot(void *p) { return NS_OK; }
|
||||
};
|
||||
NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
|
||||
NS_DECL_CYCLE_COLLECTION_UNMARK_PURPLE_STUB(XPCWrappedNative)
|
||||
|
||||
#ifndef XPCONNECT_STANDALONE
|
||||
|
@ -2089,8 +2098,10 @@ public:
|
|||
JSBool
|
||||
IsValid() const {return nsnull != mFlatJSObject;}
|
||||
|
||||
#define XPC_SCOPE_TAG ((jsword)0x1)
|
||||
#define XPC_SCOPE_WORD(s) ((jsword)(s))
|
||||
#define XPC_SCOPE_MASK ((jsword)0x3)
|
||||
#define XPC_SCOPE_TAG ((jsword)0x1)
|
||||
#define XPC_WRAPPER_EXPIRED ((jsword)0x2)
|
||||
|
||||
static inline JSBool
|
||||
IsTaggedScope(XPCWrappedNativeScope* s)
|
||||
|
@ -2105,15 +2116,29 @@ public:
|
|||
UnTagScope(XPCWrappedNativeScope* s)
|
||||
{return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) & ~XPC_SCOPE_TAG);}
|
||||
|
||||
inline JSBool
|
||||
IsWrapperExpired() const
|
||||
{return XPC_SCOPE_WORD(mMaybeScope) & XPC_WRAPPER_EXPIRED;}
|
||||
|
||||
JSBool
|
||||
HasProto() const {return !IsTaggedScope(mMaybeScope);}
|
||||
|
||||
XPCWrappedNativeProto*
|
||||
GetProto() const {return HasProto() ? mMaybeProto : nsnull;}
|
||||
GetProto() const
|
||||
{return HasProto() ?
|
||||
(XPCWrappedNativeProto*)
|
||||
(XPC_SCOPE_WORD(mMaybeProto) & ~XPC_SCOPE_MASK) : nsnull;}
|
||||
|
||||
void
|
||||
SetProto(XPCWrappedNativeProto* p)
|
||||
{NS_ASSERTION(!IsWrapperExpired(), "bad ptr!");
|
||||
mMaybeProto = p;}
|
||||
|
||||
XPCWrappedNativeScope*
|
||||
GetScope() const {return HasProto() ?
|
||||
mMaybeProto->GetScope() : UnTagScope(mMaybeScope);}
|
||||
GetScope() const
|
||||
{return GetProto() ? GetProto()->GetScope() :
|
||||
(XPCWrappedNativeScope*)
|
||||
(XPC_SCOPE_WORD(mMaybeScope) & ~XPC_SCOPE_MASK);}
|
||||
|
||||
nsISupports*
|
||||
GetIdentityObject() const {return mIdentity;}
|
||||
|
@ -2123,7 +2148,7 @@ public:
|
|||
|
||||
XPCLock*
|
||||
GetLock() const {return IsValid() && HasProto() ?
|
||||
mMaybeProto->GetLock() : nsnull;}
|
||||
GetProto()->GetLock() : nsnull;}
|
||||
|
||||
XPCNativeSet*
|
||||
GetSet() const {XPCAutoLock al(GetLock()); return mSet;}
|
||||
|
@ -2131,6 +2156,12 @@ public:
|
|||
private:
|
||||
void
|
||||
SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;}
|
||||
|
||||
inline void
|
||||
ExpireWrapper()
|
||||
{mMaybeScope = (XPCWrappedNativeScope*)
|
||||
(XPC_SCOPE_WORD(mMaybeScope) | XPC_WRAPPER_EXPIRED);}
|
||||
|
||||
public:
|
||||
|
||||
XPCNativeScriptableInfo*
|
||||
|
@ -2141,20 +2172,20 @@ public:
|
|||
|
||||
void**
|
||||
GetSecurityInfoAddr() {return HasProto() ?
|
||||
mMaybeProto->GetSecurityInfoAddr() : nsnull;}
|
||||
GetProto()->GetSecurityInfoAddr() : nsnull;}
|
||||
|
||||
nsIClassInfo*
|
||||
GetClassInfo() const {return IsValid() && HasProto() ?
|
||||
mMaybeProto->GetClassInfo() : nsnull;}
|
||||
GetProto()->GetClassInfo() : nsnull;}
|
||||
|
||||
JSBool
|
||||
HasSharedProto() const {return IsValid() && HasProto() &&
|
||||
mMaybeProto->IsShared();}
|
||||
GetProto()->IsShared();}
|
||||
|
||||
JSBool
|
||||
HasMutatedSet() const {return IsValid() &&
|
||||
(!HasProto() ||
|
||||
GetSet() != mMaybeProto->GetSet());}
|
||||
GetSet() != GetProto()->GetSet());}
|
||||
|
||||
XPCJSRuntime*
|
||||
GetRuntime() const {XPCWrappedNativeScope* scope = GetScope();
|
||||
|
@ -2240,7 +2271,7 @@ public:
|
|||
{
|
||||
mSet->Mark();
|
||||
if(mScriptableInfo) mScriptableInfo->Mark();
|
||||
if(HasProto()) mMaybeProto->Mark();
|
||||
if(HasProto()) GetProto()->Mark();
|
||||
}
|
||||
|
||||
// Yes, we *do* need to mark the mScriptableInfo in both cases.
|
||||
|
@ -2248,7 +2279,7 @@ public:
|
|||
{
|
||||
if(mScriptableInfo && JS_IsGCMarkingTracer(trc))
|
||||
mScriptableInfo->Mark();
|
||||
if(HasProto()) mMaybeProto->TraceJS(trc);
|
||||
if(HasProto()) GetProto()->TraceJS(trc);
|
||||
if(mWrapper)
|
||||
JS_CALL_OBJECT_TRACER(trc, mWrapper, "XPCWrappedNative::mWrapper");
|
||||
TraceOtherWrapper(trc);
|
||||
|
@ -2271,7 +2302,7 @@ public:
|
|||
#ifdef DEBUG
|
||||
void ASSERT_SetsNotMarked() const
|
||||
{mSet->ASSERT_NotMarked();
|
||||
if(HasProto()){mMaybeProto->ASSERT_SetNotMarked();}}
|
||||
if(HasProto()){GetProto()->ASSERT_SetNotMarked();}}
|
||||
|
||||
int DEBUG_CountOfTearoffChunks() const
|
||||
{int i = 0; const XPCWrappedNativeTearOffChunk* to;
|
||||
|
|
|
@ -50,6 +50,15 @@
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::RootAndUnlinkJSObjects(void *p)
|
||||
{
|
||||
XPCWrappedNative *tmp = static_cast<XPCWrappedNative*>(p);
|
||||
tmp->ExpireWrapper();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
|
||||
nsCycleCollectionTraversalCallback &cb)
|
||||
|
@ -655,8 +664,12 @@ XPCWrappedNative::~XPCWrappedNative()
|
|||
delete mScriptableInfo;
|
||||
}
|
||||
|
||||
Native2WrappedNativeMap* map = GetScope()->GetWrappedNativeMap();
|
||||
{ // scoped lock
|
||||
XPCWrappedNativeScope *scope = GetScope();
|
||||
if(scope)
|
||||
{
|
||||
Native2WrappedNativeMap* map = scope->GetWrappedNativeMap();
|
||||
|
||||
// scoped lock
|
||||
XPCAutoLock lock(GetRuntime()->GetMapLock());
|
||||
map->Remove(this);
|
||||
}
|
||||
|
@ -1031,6 +1044,23 @@ XPCWrappedNative::FlatJSObjectFinalized(JSContext *cx)
|
|||
|
||||
GetScope()->GetWrapperMap()->Remove(mFlatJSObject);
|
||||
|
||||
if(IsWrapperExpired())
|
||||
{
|
||||
GetScope()->GetWrappedNativeMap()->Remove(this);
|
||||
|
||||
XPCWrappedNativeProto* proto = GetProto();
|
||||
|
||||
if(mScriptableInfo &&
|
||||
(!HasProto() ||
|
||||
(proto && proto->GetScriptableInfo() != mScriptableInfo)))
|
||||
{
|
||||
delete mScriptableInfo;
|
||||
mScriptableInfo = nsnull;
|
||||
}
|
||||
|
||||
mMaybeScope = nsnull;
|
||||
}
|
||||
|
||||
// This makes IsValid return false from now on...
|
||||
mFlatJSObject = nsnull;
|
||||
|
||||
|
@ -1218,7 +1248,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
|||
oldMap->Remove(wrapper);
|
||||
|
||||
if(wrapper->HasProto())
|
||||
wrapper->mMaybeProto = newProto;
|
||||
wrapper->SetProto(newProto);
|
||||
|
||||
// If the wrapper has no scriptable or it has a non-shared
|
||||
// scriptable, then we don't need to mess with it.
|
||||
|
@ -2662,7 +2692,7 @@ NS_IMETHODIMP XPCWrappedNative::RefreshPrototype()
|
|||
if(!JS_SetPrototype(ccx, GetFlatJSObject(), newProto->GetJSProtoObject()))
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
|
||||
mMaybeProto = newProto;
|
||||
SetProto(newProto);
|
||||
|
||||
if(mScriptableInfo == oldProto->GetScriptableInfo())
|
||||
mScriptableInfo = newProto->GetScriptableInfo();
|
||||
|
@ -2687,13 +2717,14 @@ NS_IMETHODIMP XPCWrappedNative::DebugDump(PRInt16 depth)
|
|||
|
||||
if(HasProto())
|
||||
{
|
||||
if(depth && mMaybeProto)
|
||||
mMaybeProto->DebugDump(depth);
|
||||
XPCWrappedNativeProto* proto = GetProto();
|
||||
if(depth && proto)
|
||||
proto->DebugDump(depth);
|
||||
else
|
||||
XPC_LOG_ALWAYS(("mMaybeProto @ %x", mMaybeProto));
|
||||
XPC_LOG_ALWAYS(("mMaybeProto @ %x", proto));
|
||||
}
|
||||
else
|
||||
XPC_LOG_ALWAYS(("Scope @ %x", UnTagScope(mMaybeScope)));
|
||||
XPC_LOG_ALWAYS(("Scope @ %x", GetScope()));
|
||||
|
||||
if(depth && mSet)
|
||||
mSet->DebugDump(depth);
|
||||
|
|
|
@ -355,7 +355,7 @@ WrappedNativeJSGCThingTracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
|||
uint32 number, void *arg)
|
||||
{
|
||||
XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
|
||||
if(wrapper->HasExternalReference())
|
||||
if(wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
|
||||
{
|
||||
JSTracer* trc = (JSTracer *)arg;
|
||||
JS_CALL_OBJECT_TRACER(trc, wrapper->GetFlatJSObject(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче