mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 770535, part 1 - Remove map lock from XPConnect. r=bholley
This commit is contained in:
parent
dc8784b476
commit
6f82d37a93
@ -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);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user