Bug 770535, part 1 - Remove map lock from XPConnect. r=bholley

This commit is contained in:
Andrew McCreight 2013-11-24 10:27:51 -08:00
parent dc8784b476
commit 6f82d37a93
12 changed files with 217 additions and 531 deletions

View File

@ -17,19 +17,19 @@
inline void
XPCJSRuntime::AddVariantRoot(XPCTraceableVariant* variant)
{
variant->AddToRootSet(GetMapLock(), &mVariantRoots);
variant->AddToRootSet(&mVariantRoots);
}
inline void
XPCJSRuntime::AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS)
{
wrappedJS->AddToRootSet(GetMapLock(), &mWrappedJSRoots);
wrappedJS->AddToRootSet(&mWrappedJSRoots);
}
inline void
XPCJSRuntime::AddObjectHolderRoot(XPCJSObjectHolder* holder)
{
holder->AddToRootSet(GetMapLock(), &mObjectHolderRoots);
holder->AddToRootSet(&mObjectHolderRoots);
}
/***************************************************************************/

View File

@ -629,15 +629,11 @@ void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
roots->TraceJSAll(trc);
}
{
XPCAutoLock lock(mMapLock);
// XPCJSObjectHolders don't participate in cycle collection, so always
// trace them here.
XPCRootSetElem *e;
for (e = mObjectHolderRoots; e; e = e->GetNextRoot())
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
}
// XPCJSObjectHolders don't participate in cycle collection, so always
// trace them here.
XPCRootSetElem *e;
for (e = mObjectHolderRoots; e; e = e->GetNextRoot())
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
dom::TraceBlackJS(trc, JS_GetGCParameter(Runtime(), JSGC_NUMBER),
nsXPConnect::XPConnect()->IsShuttingDown());
@ -645,8 +641,6 @@ void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer *trc)
{
XPCAutoLock lock(mMapLock);
XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(trc, this);
for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
@ -706,8 +700,6 @@ CanSkipWrappedJS(nsXPCWrappedJS *wrappedJS)
void
XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback &cb)
{
XPCAutoLock lock(mMapLock);
XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) {
@ -735,7 +727,6 @@ XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback &c
void
XPCJSRuntime::UnmarkSkippableJSHolders()
{
XPCAutoLock lock(mMapLock);
CycleCollectedJSRuntime::UnmarkSkippableJSHolders();
}
@ -840,11 +831,8 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCo
MOZ_ASSERT(!self->mDoingFinalization, "bad state");
// mThreadRunningGC indicates that GC is running
{ // scoped lock
XPCAutoLock lock(self->GetMapLock());
MOZ_ASSERT(!self->mThreadRunningGC, "bad state");
self->mThreadRunningGC = PR_GetCurrentThread();
}
MOZ_ASSERT(!self->mThreadRunningGC, "bad state");
self->mThreadRunningGC = PR_GetCurrentThread();
nsTArray<nsXPCWrappedJS*>* dyingWrappedJSArray =
&self->mWrappedJSToReleaseArray;
@ -877,23 +865,16 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCo
// mThreadRunningGC indicates that GC is running.
// Clear it and notify waiters.
{ // scoped lock
XPCAutoLock lock(self->GetMapLock());
MOZ_ASSERT(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
self->mThreadRunningGC = nullptr;
xpc_NotifyAll(self->GetMapLock());
}
MOZ_ASSERT(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
self->mThreadRunningGC = nullptr;
break;
}
case JSFINALIZE_COLLECTION_END:
{
// mThreadRunningGC indicates that GC is running
{ // scoped lock
XPCAutoLock lock(self->GetMapLock());
MOZ_ASSERT(!self->mThreadRunningGC, "bad state");
self->mThreadRunningGC = PR_GetCurrentThread();
}
MOZ_ASSERT(!self->mThreadRunningGC, "bad state");
self->mThreadRunningGC = PR_GetCurrentThread();
// We use this occasion to mark and sweep NativeInterfaces,
// NativeSets, and the WrappedNativeJSClasses...
@ -1032,12 +1013,8 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCo
// mThreadRunningGC indicates that GC is running.
// Clear it and notify waiters.
{ // scoped lock
XPCAutoLock lock(self->GetMapLock());
MOZ_ASSERT(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
self->mThreadRunningGC = nullptr;
xpc_NotifyAll(self->GetMapLock());
}
MOZ_ASSERT(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
self->mThreadRunningGC = nullptr;
break;
}
@ -1590,9 +1567,6 @@ XPCJSRuntime::~XPCJSRuntime()
if (mNativeSetMap)
delete mNativeSetMap;
if (mMapLock)
XPCAutoLock::DestroyLock(mMapLock);
if (mThisTranslatorMap)
delete mThisTranslatorMap;
@ -2956,7 +2930,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_SIZE)),
mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_SIZE)),
mDetachedWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DETACHED_NATIVE_PROTO_MAP_SIZE)),
mMapLock(XPCAutoLock::NewLock("XPCJSRuntime::mMapLock")),
mThreadRunningGC(nullptr),
mWrappedJSToReleaseArray(),
mNativesToReleaseArray(),
@ -3145,7 +3118,6 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
self->GetThisTranslatorMap() &&
self->GetNativeScriptableSharedMap() &&
self->GetDyingWrappedNativeProtoMap() &&
self->GetMapLock() &&
self->mWatchdogManager) {
return self;
}
@ -3261,7 +3233,6 @@ XPCJSRuntime::DebugDump(int16_t depth)
XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
XPC_LOG_INDENT();
XPC_LOG_ALWAYS(("mJSRuntime @ %x", Runtime()));
XPC_LOG_ALWAYS(("mMapLock @ %x", mMapLock));
XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
&mWrappedJSToReleaseArray,
@ -3330,12 +3301,10 @@ XPCJSRuntime::DebugDump(int16_t depth)
/***************************************************************************/
void
XPCRootSetElem::AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead)
XPCRootSetElem::AddToRootSet(XPCRootSetElem **listHead)
{
MOZ_ASSERT(!mSelfp, "Must be not linked");
XPCAutoLock autoLock(lock);
mSelfp = listHead;
mNext = *listHead;
if (mNext) {
@ -3346,15 +3315,13 @@ XPCRootSetElem::AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead)
}
void
XPCRootSetElem::RemoveFromRootSet(XPCLock *lock)
XPCRootSetElem::RemoveFromRootSet()
{
nsXPConnect *xpc = nsXPConnect::XPConnect();
JS::PokeGC(xpc->GetRuntime()->Runtime());
MOZ_ASSERT(mSelfp, "Must be linked");
XPCAutoLock autoLock(lock);
MOZ_ASSERT(*mSelfp == this, "Link invariant");
*mSelfp = mNext;
if (mNext)

View File

@ -63,7 +63,7 @@ XPCTraceableVariant::~XPCTraceableVariant()
nsVariant::Cleanup(&mData);
if (!JSVAL_IS_NULL(val))
RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
RemoveFromRootSet();
}
void XPCTraceableVariant::TraceJS(JSTracer* trc)
@ -103,7 +103,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
if (val.isMarkable()) {
XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp);
v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
v->RemoveFromRootSet();
}
tmp->mJSVal = JS::NullValue();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

View File

@ -175,11 +175,6 @@ nsXPCWrappedJS::Release(void)
MOZ_CRASH();
NS_PRECONDITION(0 != mRefCnt, "dup release");
// need to take the map lock here to prevent GetNewOrUsed from trying
// to reuse a wrapper on one thread while it's being destroyed on another
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
XPCAutoLock lock(rt->GetMapLock());
do_decrement:
nsrefcnt cnt = --mRefCnt;
@ -191,7 +186,7 @@ do_decrement:
}
if (1 == cnt) {
if (IsValid())
RemoveFromRootSet(rt->GetMapLock());
RemoveFromRootSet();
// If we are not the root wrapper or if we are not being used from a
// weak reference, then this extra ref is not needed and we can let
@ -274,18 +269,12 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj,
if (!rootJSObj)
goto return_wrapper;
// look for the root wrapper, and if found, hold the map lock until
// we've added our ref to prevent another thread from destroying it
// under us
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
root = map->Find(rootJSObj);
if (root) {
if ((nullptr != (wrapper = root->Find(aIID))) ||
(nullptr != (wrapper = root->FindInherited(aIID)))) {
NS_ADDREF(wrapper);
goto return_wrapper;
}
root = map->Find(rootJSObj);
if (root) {
if ((nullptr != (wrapper = root->Find(aIID))) ||
(nullptr != (wrapper = root->FindInherited(aIID)))) {
NS_ADDREF(wrapper);
goto return_wrapper;
}
}
@ -298,10 +287,7 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj,
if (!root)
goto return_wrapper;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
map->Add(cx, root);
}
map->Add(cx, root);
goto return_wrapper;
} else {
@ -320,11 +306,7 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj,
release_root = true;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
map->Add(cx, root);
}
map->Add(cx, root);
}
}
@ -387,10 +369,8 @@ nsXPCWrappedJS::~nsXPCWrappedJS()
// Remove this root wrapper from the map
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
if (map) {
XPCAutoLock lock(rt->GetMapLock());
if (map)
map->Remove(this);
}
}
Unlink();
}
@ -404,14 +384,12 @@ nsXPCWrappedJS::Unlink()
if (mRoot == this) {
// remove this root wrapper from the map
JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
if (map) {
XPCAutoLock lock(rt->GetMapLock());
if (map)
map->Remove(this);
}
}
if (mRefCnt > 1)
RemoveFromRootSet(rt->GetMapLock());
RemoveFromRootSet();
}
mJSObj = nullptr;

View File

@ -105,12 +105,9 @@ nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID,
nsXPCWrappedJSClass* clazz = nullptr;
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
clazz = map->Find(aIID);
NS_IF_ADDREF(clazz);
}
IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
clazz = map->Find(aIID);
NS_IF_ADDREF(clazz);
if (!clazz) {
nsCOMPtr<nsIInterfaceInfo> info;
@ -141,10 +138,7 @@ nsXPCWrappedJSClass::nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
NS_ADDREF(mInfo);
NS_ADDREF_THIS();
{ // scoped lock
XPCAutoLock lock(mRuntime->GetMapLock());
mRuntime->GetWrappedJSClassMap()->Add(this);
}
mRuntime->GetWrappedJSClassMap()->Add(this);
uint16_t methodCount;
if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
@ -178,10 +172,8 @@ nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
if (mDescriptors && mDescriptors != &zero_methods_descriptor)
delete [] mDescriptors;
if (mRuntime)
{ // scoped lock
XPCAutoLock lock(mRuntime->GetMapLock());
mRuntime->GetWrappedJSClassMap()->Remove(this);
}
if (mName)
nsMemory::Free(mName);
NS_IF_RELEASE(mInfo);
@ -1215,10 +1207,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
IID2ThisTranslatorMap* map =
mRuntime->GetThisTranslatorMap();
{
XPCAutoLock lock(mRuntime->GetMapLock()); // scoped lock
translator = map->Find(mIID);
}
translator = map->Find(mIID);
if (translator) {
nsCOMPtr<nsISupports> newThis;

View File

@ -302,18 +302,13 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
return NS_ERROR_FAILURE;
}
XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
nsRefPtr<XPCWrappedNative> wrapper;
Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
// Some things are nsWrapperCache subclasses but never use the cache, so go
// ahead and check our map even if we have a cache and it has no existing
// wrapper: we might have an XPCWrappedNative anyway.
{ // scoped lock
XPCAutoLock lock(mapLock);
wrapper = map->Find(identity);
}
wrapper = map->Find(identity);
if (wrapper) {
if (!wrapper->FindTearOff(Interface, false, &rv)) {
@ -404,8 +399,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
if (cached)
wrapper = XPCWrappedNative::Get(cached);
} else {
// scoped lock
XPCAutoLock lock(mapLock);
wrapper = map->Find(identity);
}
@ -494,21 +487,16 @@ FinishCreate(XPCWrappedNativeScope* Scope,
AutoJSContext cx;
MOZ_ASSERT(inWrapper);
XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
nsRefPtr<XPCWrappedNative> wrapper;
{ // scoped lock
// Deal with the case where the wrapper got created as a side effect
// of one of our calls out of this code (or on another thread). Add()
// returns the (possibly pre-existing) wrapper that ultimately ends up
// in the map, which is what we want.
XPCAutoLock lock(mapLock);
wrapper = map->Add(inWrapper);
if (!wrapper)
return NS_ERROR_FAILURE;
}
// Deal with the case where the wrapper got created as a side effect
// of one of our calls out of this code. Add() returns the (possibly
// pre-existing) wrapper that ultimately ends up in the map, which is
// what we want.
wrapper = map->Add(inWrapper);
if (!wrapper)
return NS_ERROR_FAILURE;
if (wrapper == inWrapper) {
JSObject *flat = wrapper->GetFlatJSObject();
@ -539,10 +527,7 @@ FinishCreate(XPCWrappedNativeScope* Scope,
"cause a crash in combination with a JS GC. Fix the "
"failing PostCreate ASAP!");
{ // scoped lock
XPCAutoLock lock(mapLock);
map->Remove(wrapper);
}
map->Remove(wrapper);
// This would be a good place to tell the wrapper not to remove
// itself from the map when it dies... See bug 429442.
@ -591,13 +576,10 @@ XPCWrappedNative::GetUsedOnly(nsISupports* Object,
Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
{ // scoped lock
XPCAutoLock lock(Scope->GetRuntime()->GetMapLock());
wrapper = map->Find(identity);
if (!wrapper) {
*resultWrapper = nullptr;
return NS_OK;
}
wrapper = map->Find(identity);
if (!wrapper) {
*resultWrapper = nullptr;
return NS_OK;
}
}
@ -662,9 +644,6 @@ XPCWrappedNative::Destroy()
if (scope) {
Native2WrappedNativeMap* map = scope->GetWrappedNativeMap();
// scoped lock
XPCAutoLock lock(GetRuntime()->GetMapLock());
// Post-1.9 we should not remove this wrapper from the map if it is
// uninitialized.
map->Remove(this);
@ -1254,43 +1233,40 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
// Update scope maps. This section modifies global state, so from
// here on out we crash if anything fails.
{ // scoped lock
Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock());
Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
oldMap->Remove(wrapper);
oldMap->Remove(wrapper);
if (wrapper->HasProto())
wrapper->SetProto(newProto);
if (wrapper->HasProto())
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.
// Otherwise...
// If the wrapper has no scriptable or it has a non-shared
// scriptable, then we don't need to mess with it.
// Otherwise...
if (wrapper->mScriptableInfo &&
wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) {
// The new proto had better have the same JSClass stuff as
// the old one! We maintain a runtime wide unique map of
// this stuff. So, if these don't match then the caller is
// doing something bad here.
if (wrapper->mScriptableInfo &&
wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) {
// The new proto had better have the same JSClass stuff as
// the old one! We maintain a runtime wide unique map of
// this stuff. So, if these don't match then the caller is
// doing something bad here.
MOZ_ASSERT(oldProto->GetScriptableInfo()->GetScriptableShared() ==
newProto->GetScriptableInfo()->GetScriptableShared(),
"Changing proto is also changing JSObject Classname or "
"helper's nsIXPScriptable flags. This is not allowed!");
MOZ_ASSERT(oldProto->GetScriptableInfo()->GetScriptableShared() ==
newProto->GetScriptableInfo()->GetScriptableShared(),
"Changing proto is also changing JSObject Classname or "
"helper's nsIXPScriptable flags. This is not allowed!");
wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo());
}
// Crash if the wrapper is already in the new scope.
if (newMap->Find(wrapper->GetIdentityObject()))
MOZ_CRASH();
if (!newMap->Add(wrapper))
MOZ_CRASH();
wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo());
}
// Crash if the wrapper is already in the new scope.
if (newMap->Find(wrapper->GetIdentityObject()))
MOZ_CRASH();
if (!newMap->Add(wrapper))
MOZ_CRASH();
RootedObject ww(cx, wrapper->GetWrapper());
if (ww) {
RootedObject newwrapper(cx);
@ -1440,7 +1416,6 @@ bool
XPCWrappedNative::ExtendSet(XPCNativeInterface* aInterface)
{
AutoJSContext cx;
// This is only called while locked (during XPCWrappedNative::FindTearOff).
if (!mSet->HasInterface(aInterface)) {
AutoMarkingNativeSetPtr newSet(cx);
@ -1457,8 +1432,6 @@ XPCWrappedNative::ExtendSet(XPCNativeInterface* aInterface)
XPCWrappedNativeTearOff*
XPCWrappedNative::LocateTearOff(XPCNativeInterface* aInterface)
{
XPCAutoLock al(GetLock()); // hold the lock throughout
for (XPCWrappedNativeTearOffChunk* chunk = &mFirstChunk;
chunk != nullptr;
chunk = chunk->mNextChunk) {
@ -1482,8 +1455,6 @@ XPCWrappedNative::FindTearOff(XPCNativeInterface* aInterface,
nsresult* pError /* = nullptr */)
{
AutoJSContext cx;
XPCAutoLock al(GetLock()); // hold the lock throughout
nsresult rv = NS_OK;
XPCWrappedNativeTearOff* to;
XPCWrappedNativeTearOff* firstAvailable = nullptr;
@ -1559,8 +1530,6 @@ XPCWrappedNative::InitTearOff(XPCWrappedNativeTearOff* aTearOff,
{
AutoJSContext cx;
// This is only called while locked (during XPCWrappedNative::FindTearOff).
// Determine if the object really does this interface...
const nsIID* iid = aInterface->GetIID();
@ -1576,103 +1545,98 @@ XPCWrappedNative::InitTearOff(XPCWrappedNativeTearOff* aTearOff,
return NS_ERROR_NO_INTERFACE;
}
// We are about to call out to unlock and other code.
// We are about to call out to other code.
// So protect our intended tearoff.
aTearOff->SetReserved();
{ // scoped *un*lock
XPCAutoUnlock unlock(GetLock());
if (NS_FAILED(identity->QueryInterface(*iid, (void**)&obj)) || !obj) {
aTearOff->SetInterface(nullptr);
return NS_ERROR_NO_INTERFACE;
}
if (NS_FAILED(identity->QueryInterface(*iid, (void**)&obj)) || !obj) {
// Guard against trying to build a tearoff for a shared nsIClassInfo.
if (iid->Equals(NS_GET_IID(nsIClassInfo))) {
nsCOMPtr<nsISupports> alternate_identity(do_QueryInterface(obj));
if (alternate_identity.get() != identity) {
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_ERROR_NO_INTERFACE;
}
}
// Guard against trying to build a tearoff for a shared nsIClassInfo.
if (iid->Equals(NS_GET_IID(nsIClassInfo))) {
nsCOMPtr<nsISupports> alternate_identity(do_QueryInterface(obj));
if (alternate_identity.get() != identity) {
// Guard against trying to build a tearoff for an interface that is
// aggregated and is implemented as a nsIXPConnectWrappedJS using this
// self-same JSObject. The XBL system does this. If we mutate the set
// of this wrapper then we will shadow the method that XBL has added to
// the JSObject that it has inserted in the JS proto chain between our
// JSObject and our XPCWrappedNativeProto's JSObject. If we let this
// set mutation happen then the interface's methods will be added to
// our JSObject, but calls on those methods will get routed up to
// native code and into the wrappedJS - which will do a method lookup
// on *our* JSObject and find the same method and make another call
// into an infinite loop.
// see: http://bugzilla.mozilla.org/show_bug.cgi?id=96725
// The code in this block also does a check for the double wrapped
// nsIPropertyBag case.
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(obj));
if (wrappedJS) {
RootedObject jso(cx, wrappedJS->GetJSObject());
if (jso == mFlatJSObject) {
// The implementing JSObject is the same as ours! Just say OK
// without actually extending the set.
//
// XXX It is a little cheesy to have FindTearOff return an
// 'empty' tearoff. But this is the centralized place to do the
// QI activities on the underlying object. *And* most caller to
// FindTearOff only look for a non-null result and ignore the
// actual tearoff returned. The only callers that do use the
// returned tearoff make sure to check for either a non-null
// JSObject or a matching Interface before proceeding.
// I think we can get away with this bit of ugliness.
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_OK;
}
// Decide whether or not to expose nsIPropertyBag to calling
// JS code in the double wrapped case.
//
// Our rule here is that when JSObjects are double wrapped and
// exposed to other JSObjects then the nsIPropertyBag interface
// is only exposed on an 'opt-in' basis; i.e. if the underlying
// JSObject wants other JSObjects to be able to see this interface
// then it must implement QueryInterface and not throw an exception
// when asked for nsIPropertyBag. It need not actually *implement*
// nsIPropertyBag - xpconnect will do that work.
nsXPCWrappedJSClass* clazz;
if (iid->Equals(NS_GET_IID(nsIPropertyBag)) && jso &&
NS_SUCCEEDED(nsXPCWrappedJSClass::GetNewOrUsed(cx,*iid,&clazz))&&
clazz) {
RootedObject answer(cx,
clazz->CallQueryInterfaceOnJSObject(cx, jso, *iid));
NS_RELEASE(clazz);
if (!answer) {
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_ERROR_NO_INTERFACE;
}
}
// Guard against trying to build a tearoff for an interface that is
// aggregated and is implemented as a nsIXPConnectWrappedJS using this
// self-same JSObject. The XBL system does this. If we mutate the set
// of this wrapper then we will shadow the method that XBL has added to
// the JSObject that it has inserted in the JS proto chain between our
// JSObject and our XPCWrappedNativeProto's JSObject. If we let this
// set mutation happen then the interface's methods will be added to
// our JSObject, but calls on those methods will get routed up to
// native code and into the wrappedJS - which will do a method lookup
// on *our* JSObject and find the same method and make another call
// into an infinite loop.
// see: http://bugzilla.mozilla.org/show_bug.cgi?id=96725
// The code in this block also does a check for the double wrapped
// nsIPropertyBag case.
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(obj));
if (wrappedJS) {
RootedObject jso(cx, wrappedJS->GetJSObject());
if (jso == mFlatJSObject) {
// The implementing JSObject is the same as ours! Just say OK
// without actually extending the set.
//
// XXX It is a little cheesy to have FindTearOff return an
// 'empty' tearoff. But this is the centralized place to do the
// QI activities on the underlying object. *And* most caller to
// FindTearOff only look for a non-null result and ignore the
// actual tearoff returned. The only callers that do use the
// returned tearoff make sure to check for either a non-null
// JSObject or a matching Interface before proceeding.
// I think we can get away with this bit of ugliness.
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_OK;
}
// Decide whether or not to expose nsIPropertyBag to calling
// JS code in the double wrapped case.
//
// Our rule here is that when JSObjects are double wrapped and
// exposed to other JSObjects then the nsIPropertyBag interface
// is only exposed on an 'opt-in' basis; i.e. if the underlying
// JSObject wants other JSObjects to be able to see this interface
// then it must implement QueryInterface and not throw an exception
// when asked for nsIPropertyBag. It need not actually *implement*
// nsIPropertyBag - xpconnect will do that work.
nsXPCWrappedJSClass* clazz;
if (iid->Equals(NS_GET_IID(nsIPropertyBag)) && jso &&
NS_SUCCEEDED(nsXPCWrappedJSClass::GetNewOrUsed(cx,*iid,&clazz))&&
clazz) {
RootedObject answer(cx,
clazz->CallQueryInterfaceOnJSObject(cx, jso, *iid));
NS_RELEASE(clazz);
if (!answer) {
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_ERROR_NO_INTERFACE;
}
}
}
nsIXPCSecurityManager* sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
if (sm && NS_FAILED(sm->
CanCreateWrapper(cx, *iid, identity,
GetClassInfo(), GetSecurityInfoAddr()))) {
// the security manager vetoed. It should have set an exception.
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
}
// We are relocked from here on...
nsIXPCSecurityManager* sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
if (sm && NS_FAILED(sm->
CanCreateWrapper(cx, *iid, identity,
GetClassInfo(), GetSecurityInfoAddr()))) {
// the security manager vetoed. It should have set an exception.
NS_RELEASE(obj);
aTearOff->SetInterface(nullptr);
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
// If this is not already in our set we need to extend our set.
// Note: we do not cache the result of the previous call to HasInterface()
@ -1698,8 +1662,6 @@ XPCWrappedNative::InitTearOffJSObject(XPCWrappedNativeTearOff* to)
{
AutoJSContext cx;
// This is only called while locked (during XPCWrappedNative::FindTearOff).
JSObject* obj = JS_NewObject(cx, Jsvalify(&XPC_WN_Tearoff_JSClass),
JS_GetObjectPrototype(cx, mFlatJSObject),
mFlatJSObject);
@ -2881,7 +2843,7 @@ XPCJSObjectHolder::XPCJSObjectHolder(JSObject* obj)
XPCJSObjectHolder::~XPCJSObjectHolder()
{
RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
RemoveFromRootSet();
}
void

View File

@ -126,10 +126,7 @@ XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
if (!map)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
iface = map->Find(*iid);
}
iface = map->Find(*iid);
if (iface)
return iface;
@ -143,17 +140,14 @@ XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
if (!iface)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
XPCNativeInterface* iface2 = map->Add(iface);
if (!iface2) {
NS_ERROR("failed to add our interface!");
DestroyInstance(iface);
iface = nullptr;
} else if (iface2 != iface) {
DestroyInstance(iface);
iface = iface2;
}
XPCNativeInterface* iface2 = map->Add(iface);
if (!iface2) {
NS_ERROR("failed to add our interface!");
DestroyInstance(iface);
iface = nullptr;
} else if (iface2 != iface) {
DestroyInstance(iface);
iface = iface2;
}
return iface;
@ -176,10 +170,7 @@ XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
if (!map)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
iface = map->Find(*iid);
}
iface = map->Find(*iid);
if (iface)
return iface;
@ -188,17 +179,14 @@ XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
if (!iface)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
XPCNativeInterface* iface2 = map->Add(iface);
if (!iface2) {
NS_ERROR("failed to add our interface!");
DestroyInstance(iface);
iface = nullptr;
} else if (iface2 != iface) {
DestroyInstance(iface);
iface = iface2;
}
XPCNativeInterface* iface2 = map->Add(iface);
if (!iface2) {
NS_ERROR("failed to add our interface!");
DestroyInstance(iface);
iface = nullptr;
} else if (iface2 != iface) {
DestroyInstance(iface);
iface = iface2;
}
return iface;
@ -429,10 +417,7 @@ XPCNativeSet::GetNewOrUsed(const nsIID* iid)
if (!map)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
set = map->Find(&key);
}
set = map->Find(&key);
if (set)
return set;
@ -443,17 +428,14 @@ XPCNativeSet::GetNewOrUsed(const nsIID* iid)
if (!set)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
XPCNativeSet* set2 = map->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
} else if (set2 != set) {
DestroyInstance(set);
set = set2;
}
XPCNativeSet* set2 = map->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
} else if (set2 != set) {
DestroyInstance(set);
set = set2;
}
return set;
@ -471,10 +453,7 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
if (!map)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
set = map->Find(classInfo);
}
set = map->Find(classInfo);
if (set)
return set;
@ -537,19 +516,16 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
XPCNativeSetKey key(set, nullptr, 0);
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
XPCNativeSet* set2 = map2->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
goto out;
}
if (set2 != set) {
DestroyInstance(set);
set = set2;
}
XPCNativeSet* set2 = map2->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
goto out;
}
if (set2 != set) {
DestroyInstance(set);
set = set2;
}
}
} else
@ -557,10 +533,7 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
} else
set = GetNewOrUsed(&NS_GET_IID(nsISupports));
if (set)
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
if (set) {
#ifdef DEBUG
XPCNativeSet* set2 =
#endif
@ -585,10 +558,7 @@ XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
if (map)
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
map->Remove(classInfo);
}
}
// static
@ -606,10 +576,7 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet* otherSet,
XPCNativeSetKey key(otherSet, newInterface, position);
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
set = map->Find(&key);
}
set = map->Find(&key);
if (set)
return set;
@ -622,17 +589,14 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet* otherSet,
if (!set)
return nullptr;
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
XPCNativeSet* set2 = map->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
} else if (set2 != set) {
DestroyInstance(set);
set = set2;
}
XPCNativeSet* set2 = map->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
} else if (set2 != set) {
DestroyInstance(set);
set = set2;
}
return set;

View File

@ -1129,11 +1129,8 @@ XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci)
XPCJSRuntime* rt = XPCJSRuntime::Get();
XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap();
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
success = map->GetNewOrUsed(sci->GetFlags(), name,
sci->GetInterfacesBitmap(), newObj);
}
success = map->GetNewOrUsed(sci->GetFlags(), name,
sci->GetInterfacesBitmap(), newObj);
if (!success) {
delete newObj;

View File

@ -133,8 +133,6 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj)
{
MOZ_ASSERT(obj == mJSProtoObject, "huh?");
// Map locking is not necessary since we are running gc.
// Only remove this proto from the map if it is the one in the map.
ClassInfo2WrappedNativeProtoMap* map =
GetScope()->GetWrappedNativeProtoMap(ClassIsMainThreadOnly());
@ -173,7 +171,6 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
AutoMarkingWrappedNativeProtoPtr proto(cx);
ClassInfo2WrappedNativeProtoMap* map = nullptr;
XPCLock* lock = nullptr;
uint32_t ciFlags;
if (NS_FAILED(classInfo->GetFlags(&ciFlags)))
@ -181,13 +178,9 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
bool mainThreadOnly = !!(ciFlags & nsIClassInfo::MAIN_THREAD_ONLY);
map = scope->GetWrappedNativeProtoMap(mainThreadOnly);
lock = mainThreadOnly ? nullptr : scope->GetRuntime()->GetMapLock();
{ // scoped lock
XPCAutoLock al(lock);
proto = map->Find(classInfo);
if (proto)
return proto;
}
proto = map->Find(classInfo);
if (proto)
return proto;
AutoMarkingNativeSetPtr set(cx);
set = XPCNativeSet::GetNewOrUsed(classInfo);
@ -201,10 +194,7 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
return nullptr;
}
{ // scoped lock
XPCAutoLock al(lock);
map->Add(classInfo, proto);
}
map->Add(classInfo, proto);
return proto;
}

View File

@ -79,9 +79,6 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx,
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
JSCLASS_HAS_PRIVATE));
// scoped lock
XPCAutoLock lock(XPCJSRuntime::Get()->GetMapLock());
#ifdef DEBUG
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
@ -298,10 +295,6 @@ WrappedNativeJSGCThingTracer(PLDHashTable *table, PLDHashEntryHdr *hdr,
void
XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt)
{
// FIXME The lock may not be necessary during tracing as that serializes
// access to JS runtime. See bug 380139.
XPCAutoLock lock(rt->GetMapLock());
// Do JS_CallTracer for all wrapped natives with external references, as
// well as any DOM expando objects.
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
@ -341,8 +334,6 @@ void
XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
nsCycleCollectionNoteRootCallback& cb)
{
XPCAutoLock lock(rt->GetMapLock());
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
cur->mWrappedNativeMap->Enumerate(WrappedNativeSuspecter, &cb);
if (cur->mDOMExpandoSet) {
@ -356,10 +347,6 @@ XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
void
XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt)
{
// FIXME The lock may not be necessary since we are inside JSGC_MARK_END
// callback and GX serializes access to JS runtime. See bug 380139.
XPCAutoLock lock(rt->GetMapLock());
// We are in JSGC_MARK_END and JSGC_FINALIZE_END must always follow it
// calling FinishedFinalizationPhaseOfGC and clearing gDyingScopes in
// KillDyingScopes.
@ -396,12 +383,6 @@ XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* r
void
XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC()
{
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
// FIXME The lock may not be necessary since we are inside
// JSGC_FINALIZE_END callback and at this point GC still serializes access
// to JS runtime. See bug 380139.
XPCAutoLock lock(rt->GetMapLock());
KillDyingScopes();
}
@ -483,7 +464,6 @@ XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
void
XPCWrappedNativeScope::KillDyingScopes()
{
// always called inside the lock!
XPCWrappedNativeScope* cur = gDyingScopes;
while (cur) {
XPCWrappedNativeScope* next = cur->mNext;
@ -589,9 +569,6 @@ WNProtoSecPolicyClearer(PLDHashTable *table, PLDHashEntryHdr *hdr,
nsresult
XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies()
{
// Hold the lock throughout.
XPCAutoLock lock(XPCJSRuntime::Get()->GetMapLock());
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
cur->mWrappedNativeProtoMap->Enumerate(WNProtoSecPolicyClearer, nullptr);
cur->mMainThreadWrappedNativeProtoMap->Enumerate(WNProtoSecPolicyClearer, nullptr);
@ -617,8 +594,6 @@ WNProtoRemover(PLDHashTable *table, PLDHashEntryHdr *hdr,
void
XPCWrappedNativeScope::RemoveWrappedNativeProtos()
{
XPCAutoLock al(XPCJSRuntime::Get()->GetMapLock());
mWrappedNativeProtoMap->Enumerate(WNProtoRemover,
GetRuntime()->GetDetachedWrappedNativeProtoMap());
mMainThreadWrappedNativeProtoMap->Enumerate(WNProtoRemover,
@ -714,9 +689,6 @@ XPCWrappedNativeScope::DebugDump(int16_t depth)
size_t
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(MallocSizeOf mallocSizeOf)
{
XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
XPCAutoLock lock(rt->GetMapLock());
size_t n = 0;
for (XPCWrappedNativeScope *cur = gScopes; cur; cur = cur->mNext) {
n += cur->SizeOfIncludingThis(mallocSizeOf);

View File

@ -791,12 +791,9 @@ nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScopeArg)
// might need to rescue.
nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
{ // scoped lock
XPCAutoLock lock(GetRuntime()->GetMapLock());
Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
wrappersToMove.SetCapacity(map->Count());
map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
}
Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
wrappersToMove.SetCapacity(map->Count());
map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
// Now that we have the wrappers, reparent them to the new scope.
for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
@ -875,10 +872,7 @@ nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
{
XPCJSRuntime* rt = GetRuntime();
IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
{
XPCAutoLock lock(rt->GetMapLock()); // scoped lock
map->Add(aIID, aTranslator);
}
map->Add(aIID, aTranslator);
return NS_OK;
}

View File

@ -81,8 +81,6 @@
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Util.h"
#include <math.h>
@ -251,120 +249,6 @@ inline JSObject* GetWNExpandoChain(JSObject *obj)
return JS_GetReservedSlot(obj, WN_XRAYEXPANDOCHAIN_SLOT).toObjectOrNull();
}
/***************************************************************************/
// Auto locking support class...
// We PROMISE to never screw this up.
#ifdef _MSC_VER
#pragma warning(disable : 4355) // OK to pass "this" in member initializer
#endif
typedef mozilla::ReentrantMonitor XPCLock;
static inline void xpc_Wait(XPCLock* lock)
{
MOZ_ASSERT(lock, "xpc_Wait called with null lock!");
lock->Wait();
}
static inline void xpc_NotifyAll(XPCLock* lock)
{
MOZ_ASSERT(lock, "xpc_NotifyAll called with null lock!");
lock->NotifyAll();
}
// This is a cloned subset of nsAutoMonitor. We want the use of a monitor -
// mostly because we need reenterability - but we also want to support passing
// a null monitor in without things blowing up. This is used for wrappers that
// are guaranteed to be used only on one thread. We avoid lock overhead by
// using a null monitor. By changing this class we can avoid having multiplte
// code paths or (conditional) manual calls to PR_{Enter,Exit}Monitor.
//
// Note that xpconnect only makes *one* monitor and *mostly* holds it locked
// only through very small critical sections.
class MOZ_STACK_CLASS XPCAutoLock {
public:
static XPCLock* NewLock(const char* name)
{return new mozilla::ReentrantMonitor(name);}
static void DestroyLock(XPCLock* lock)
{delete lock;}
XPCAutoLock(XPCLock* lock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mLock(lock)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mLock)
mLock->Enter();
}
~XPCAutoLock()
{
if (mLock) {
mLock->Exit();
}
}
private:
XPCLock* mLock;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
// Not meant to be implemented. This makes it a compiler error to
// construct or assign an XPCAutoLock object incorrectly.
XPCAutoLock(void) {}
XPCAutoLock(XPCAutoLock& /*aMon*/) {}
XPCAutoLock& operator =(XPCAutoLock& /*aMon*/) {
return *this;
}
// Not meant to be implemented. This makes it a compiler error to
// attempt to create an XPCAutoLock object on the heap.
static void* operator new(size_t /*size*/) CPP_THROW_NEW {
return nullptr;
}
static void operator delete(void* /*memory*/) {}
};
/************************************************/
class MOZ_STACK_CLASS XPCAutoUnlock {
public:
XPCAutoUnlock(XPCLock* lock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mLock(lock)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mLock) {
mLock->Exit();
}
}
~XPCAutoUnlock()
{
if (mLock)
mLock->Enter();
}
private:
XPCLock* mLock;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
// Not meant to be implemented. This makes it a compiler error to
// construct or assign an XPCAutoUnlock object incorrectly.
XPCAutoUnlock(void) {}
XPCAutoUnlock(XPCAutoUnlock& /*aMon*/) {}
XPCAutoUnlock& operator =(XPCAutoUnlock& /*aMon*/) {
return *this;
}
// Not meant to be implemented. This makes it a compiler error to
// attempt to create an XPCAutoUnlock object on the heap.
static void* operator new(size_t /*size*/) CPP_THROW_NEW {
return nullptr;
}
static void operator delete(void* /*memory*/) {}
};
/***************************************************************************
****************************************************************************
*
@ -507,8 +391,8 @@ public:
}
inline XPCRootSetElem* GetNextRoot() { return mNext; }
void AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead);
void RemoveFromRootSet(XPCLock *lock);
void AddToRootSet(XPCRootSetElem **listHead);
void RemoveFromRootSet();
private:
XPCRootSetElem *mNext;
@ -610,8 +494,6 @@ public:
XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const
{return mDetachedWrappedNativeProtoMap;}
XPCLock* GetMapLock() const {return mMapLock;}
bool OnJSContextNew(JSContext* cx);
virtual bool
@ -751,7 +633,6 @@ private:
XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap;
XPCLock* mMapLock;
PRThread* mThreadRunningGC;
nsTArray<nsXPCWrappedJS*> mWrappedJSToReleaseArray;
nsTArray<nsISupports*> mNativesToReleaseArray;
@ -1960,16 +1841,12 @@ public:
#define GET_IT(f_) const {return !!(mClassInfoFlags & nsIClassInfo:: f_ );}
bool ClassIsSingleton() GET_IT(SINGLETON)
bool ClassIsThreadSafe() GET_IT(THREADSAFE)
bool ClassIsMainThreadOnly() GET_IT(MAIN_THREAD_ONLY)
bool ClassIsDOMObject() GET_IT(DOM_OBJECT)
bool ClassIsPluginObject() GET_IT(PLUGIN_OBJECT)
#undef GET_IT
XPCLock* GetLock() const
{return ClassIsThreadSafe() ? GetRuntime()->GetMapLock() : nullptr;}
void SetScriptableInfo(XPCNativeScriptableInfo* si)
{MOZ_ASSERT(!mScriptableInfo, "leak here!"); mScriptableInfo = si;}
@ -2222,15 +2099,11 @@ public:
JSObject*
GetFlatJSObjectPreserveColor() const {return mFlatJSObject;}
XPCLock*
GetLock() const {return IsValid() && HasProto() ?
GetProto()->GetLock() : nullptr;}
XPCNativeSet*
GetSet() const {XPCAutoLock al(GetLock()); return mSet;}
GetSet() const {return mSet;}
void
SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;}
SetSet(XPCNativeSet* set) {mSet = set;}
static XPCWrappedNative* Get(JSObject *obj) {
MOZ_ASSERT(IS_WN_REFLECTOR(obj));