fix bug 59751 and bug 84600. This adds an AutoMarkingPtr scheme to protect partially built objects from gc. Also make sure we don't allow JS object to implement non-scriptable interfaces. r=dbradley sr=brendan a=drivers
git-svn-id: svn://10.0.0.236/trunk@97027 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
af67a36bda
commit
36346e8f41
@ -591,8 +591,8 @@ nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
|
||||
if(!scope)
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, &aIID);
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, &aIID);
|
||||
if(!iface)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -899,9 +899,9 @@ nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
|
||||
XPCNativeScriptableCreateInfo sciProto;
|
||||
XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, &sciProto);
|
||||
|
||||
XPCWrappedNativeProto* proto =
|
||||
XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo,
|
||||
&sciProto, JS_FALSE);
|
||||
AutoMarkingWrappedNativeProtoPtr proto(ccx);
|
||||
proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo,
|
||||
&sciProto, JS_FALSE);
|
||||
if(!proto)
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
|
||||
|
||||
@ -1731,9 +1731,8 @@ nsXPCComponents::AttachNewComponentsObject(XPCCallContext& ccx,
|
||||
|
||||
nsCOMPtr<nsIXPCComponents> cholder(components);
|
||||
|
||||
// XXX this should not be needed when we get a nsIClassInfo
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, &NS_GET_IID(nsIXPCComponents));
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, &NS_GET_IID(nsIXPCComponents));
|
||||
|
||||
if(!iface)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -785,8 +785,8 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
||||
if(!xpcscope)
|
||||
return JS_FALSE;
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
if(!iface)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -827,7 +827,6 @@ XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
|
||||
|
||||
nsISupports* iface;
|
||||
|
||||
|
||||
if(!aOuter)
|
||||
{
|
||||
// Note that if we have a non-null aOuter then it means that we are
|
||||
|
||||
@ -85,4 +85,6 @@ class nsXPCComponents_Exception;
|
||||
class nsXPCComponents_Constructor;
|
||||
class nsXPCConstructor;
|
||||
|
||||
class AutoMarkingPtr;
|
||||
|
||||
#endif /* xpcforwards_h___ */
|
||||
|
||||
@ -190,6 +190,12 @@ XPCCallContext::GetSet() const
|
||||
return mSet;
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
XPCCallContext::CanGetInterface() const
|
||||
{
|
||||
return mState >= HAVE_NAME;
|
||||
}
|
||||
|
||||
inline XPCNativeInterface*
|
||||
XPCCallContext::GetInterface() const
|
||||
{
|
||||
|
||||
@ -494,8 +494,8 @@ nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
||||
{
|
||||
XPCCallContext ccx(JS_CALLER, cx);
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
|
||||
if(!iface)
|
||||
return NS_OK;
|
||||
@ -532,8 +532,8 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
|
||||
|
||||
XPCCallContext ccx(JS_CALLER, cx);
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
|
||||
if(!iface)
|
||||
return NS_OK;
|
||||
@ -591,8 +591,8 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
// Otherwise, we'll end up Querying the native object to be sure.
|
||||
XPCCallContext ccx(JS_CALLER, cx);
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, mDetails.GetID());
|
||||
|
||||
if(iface && other_wrapper->FindTearOff(ccx, iface))
|
||||
*bp = JS_TRUE;
|
||||
|
||||
@ -224,6 +224,27 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
{
|
||||
NS_ASSERTION(!self->mDoingFinalization, "bad state");
|
||||
|
||||
// Skip this part if XPConnect is shutting down. We get into
|
||||
// bad locking problems with the thread iteration otherwise.
|
||||
if(!self->GetXPConnect()->IsShuttingDown())
|
||||
{
|
||||
PRLock* threadLock = XPCPerThreadData::GetLock();
|
||||
if(threadLock)
|
||||
{ // scoped lock
|
||||
nsAutoLock lock(threadLock);
|
||||
|
||||
XPCPerThreadData* iterp = nsnull;
|
||||
XPCPerThreadData* thread;
|
||||
|
||||
while(nsnull != (thread =
|
||||
XPCPerThreadData::IterateThreads(&iterp)))
|
||||
{
|
||||
// Mark those AutoMarkingPtr lists!
|
||||
thread->MarkAutoRootsBeforeJSFinalize(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dyingWrappedJSArray = &self->mWrappedJSToReleaseArray;
|
||||
{
|
||||
XPCLock* lock = self->GetMainThreadOnlyGC() ?
|
||||
@ -242,7 +263,10 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
Enumerate(WrappedJSDyingJSObjectFinder, &data);
|
||||
}
|
||||
|
||||
// Do cleanup in NativeInterfaces
|
||||
// Do cleanup in NativeInterfaces. This part just finds
|
||||
// member cloned function objects that are about to be
|
||||
// collected. It does not deal with collection of interfaces or
|
||||
// sets at this point.
|
||||
CX_AND_XPCRT_Data data = {cx, self};
|
||||
|
||||
self->mIID2NativeInterfaceMap->
|
||||
@ -293,9 +317,12 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
while(nsnull != (thread =
|
||||
XPCPerThreadData::IterateThreads(&iterp)))
|
||||
{
|
||||
// Mark those AutoMarkingPtr lists!
|
||||
thread->MarkAutoRootsAfterJSFinalize();
|
||||
|
||||
XPCCallContext* ccxp = thread->GetCallContext();
|
||||
while(ccxp)
|
||||
{
|
||||
{
|
||||
// Deal with the strictness of callcontext that
|
||||
// complains if you ask for a set when
|
||||
// it is in a state where the set could not
|
||||
@ -306,6 +333,12 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
if(set)
|
||||
set->Mark();
|
||||
}
|
||||
if(ccxp->CanGetInterface())
|
||||
{
|
||||
XPCNativeInterface* iface = ccxp->GetInterface();
|
||||
if(iface)
|
||||
iface->Mark();
|
||||
}
|
||||
ccxp = ccxp->GetPrevCallContext();
|
||||
}
|
||||
}
|
||||
@ -601,16 +634,25 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
|
||||
if(mThisTranslatorMap)
|
||||
{
|
||||
#ifdef XPC_DUMP_AT_SHUTDOWN
|
||||
uint32 count = mThisTranslatorMap->Count();
|
||||
if(count)
|
||||
printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count);
|
||||
#endif
|
||||
delete mThisTranslatorMap;
|
||||
}
|
||||
|
||||
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
|
||||
if(DEBUG_WrappedNativeHashtable)
|
||||
{
|
||||
int LiveWrapperCount = 0;
|
||||
JS_DHashTableEnumerate(DEBUG_WrappedNativeHashtable,
|
||||
DEBUG_WrapperChecker, &LiveWrapperCount);
|
||||
if(LiveWrapperCount)
|
||||
printf("deleting XPCJSRuntime with %d live XPCWrappedNative (found in wrapper check)\n", (int)LiveWrapperCount);
|
||||
JS_DHashTableDestroy(DEBUG_WrappedNativeHashtable);
|
||||
#endif
|
||||
delete mThisTranslatorMap;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(mNativeScriptableSharedMap)
|
||||
{
|
||||
|
||||
@ -598,7 +598,7 @@ XPCNativeScriptableSharedMap::GetNewOrUsed(JSUint32 flags,
|
||||
return JS_FALSE;
|
||||
shared->PopulateJSClass();
|
||||
}
|
||||
si->GetScriptableShared(shared);
|
||||
si->SetScriptableShared(shared);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
||||
@ -675,7 +675,6 @@ private:
|
||||
LangType mCallingLangType;
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#define NATIVE_CALLER XPCContext::LANG_NATIVE
|
||||
@ -741,6 +740,7 @@ public:
|
||||
inline XPCNativeScriptableInfo* GetScriptableInfo() const ;
|
||||
inline JSBool CanGetSet() const ;
|
||||
inline XPCNativeSet* GetSet() const ;
|
||||
inline JSBool CanGetInterface() const ;
|
||||
inline XPCNativeInterface* GetInterface() const ;
|
||||
inline XPCNativeMember* GetMember() const ;
|
||||
inline JSBool HasInterfaceAndMember() const ;
|
||||
@ -810,6 +810,9 @@ private:
|
||||
JSBool mContextPopRequired;
|
||||
|
||||
XPCContext::LangType mCallerLanguage;
|
||||
|
||||
// ctor does not necessarily init the following. BEWARE!
|
||||
|
||||
XPCContext::LangType mPrevCallerLanguage;
|
||||
|
||||
XPCCallContext* mPrevCallContext;
|
||||
@ -1088,6 +1091,9 @@ public:
|
||||
JSBool IsMarked() const
|
||||
{return 0 != (mMemberCount & XPC_NATIVE_IFACE_MARK_FLAG);}
|
||||
|
||||
// NOP. This is just here to make the AutoMarkingPtr code compile.
|
||||
inline void MarkBeforeJSFinalize(JSContext*) {};
|
||||
|
||||
static void DestroyInstance(JSContext* cx, XPCJSRuntime* rt,
|
||||
XPCNativeInterface* inst);
|
||||
|
||||
@ -1210,6 +1216,10 @@ public:
|
||||
#define XPC_NATIVE_SET_MARK_FLAG ((PRUint16)JS_BIT(15)) // only high bit of 16 is set
|
||||
|
||||
inline void Mark();
|
||||
|
||||
// NOP. This is just here to make the AutoMarkingPtr code compile.
|
||||
inline void MarkBeforeJSFinalize(JSContext*) {};
|
||||
|
||||
private:
|
||||
void MarkSelfOnly() {mInterfaceCount |= XPC_NATIVE_SET_MARK_FLAG;}
|
||||
public:
|
||||
@ -1378,7 +1388,9 @@ public:
|
||||
SetCallback(nsIXPCScriptable* s) {mCallback = s;}
|
||||
|
||||
void
|
||||
GetScriptableShared(XPCNativeScriptableShared* shared) {mShared = shared;}
|
||||
SetScriptableShared(XPCNativeScriptableShared* shared) {mShared = shared;}
|
||||
|
||||
void Mark() {if(mShared) mShared->Mark();}
|
||||
|
||||
protected:
|
||||
XPCNativeScriptableInfo(nsIXPCScriptable* scriptable = nsnull,
|
||||
@ -1499,9 +1511,16 @@ public:
|
||||
|
||||
void DebugDump(PRInt16 depth);
|
||||
|
||||
// This is called in the 'early' phase by AutoMarkingWrappedNativeProtoPtr.
|
||||
// 'early' meaning after JSGC_MARK_END and before JSGC_FINALIZE_END.
|
||||
// At this point in time we can still mark JSObjects in the JS gc heap.
|
||||
void MarkBeforeJSFinalize(JSContext* cx)
|
||||
{if(mJSProtoObject)
|
||||
JS_MarkGCThing(cx, mJSProtoObject,
|
||||
"XPCWrappedNativeProto::mJSProtoObject", nsnull);}
|
||||
void Mark() const
|
||||
{mSet->Mark();
|
||||
if(mScriptableInfo) mScriptableInfo->GetScriptableShared()->Mark();}
|
||||
{mSet->Mark();
|
||||
if(mScriptableInfo) mScriptableInfo->Mark();}
|
||||
|
||||
#ifdef DEBUG
|
||||
void ASSERT_SetNotMarked() const {mSet->ASSERT_NotMarked();}
|
||||
@ -1641,7 +1660,7 @@ public:
|
||||
GetProto() const {return HasProto() ? mMaybeProto : nsnull;}
|
||||
|
||||
XPCWrappedNativeScope*
|
||||
GetScope() const { return HasProto() ?
|
||||
GetScope() const {return HasProto() ?
|
||||
mMaybeProto->GetScope() : UnTagScope(mMaybeScope);}
|
||||
|
||||
nsISupports*
|
||||
@ -1764,9 +1783,12 @@ public:
|
||||
void
|
||||
Mark() const
|
||||
{mSet->Mark();
|
||||
if(mScriptableInfo) mScriptableInfo->GetScriptableShared()->Mark();
|
||||
if(mScriptableInfo) mScriptableInfo->Mark();
|
||||
if(HasProto()) mMaybeProto->Mark();}
|
||||
|
||||
// NOP. This is just here to make the AutoMarkingPtr code compile.
|
||||
inline void MarkBeforeJSFinalize(JSContext*) {};
|
||||
|
||||
#ifdef DEBUG
|
||||
void ASSERT_SetsNotMarked() const
|
||||
{mSet->ASSERT_NotMarked();
|
||||
@ -2530,6 +2552,11 @@ public:
|
||||
void ClearRecentContext()
|
||||
{mMostRecentJSContext = nsnull; mMostRecentXPCContext = nsnull;}
|
||||
|
||||
AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;}
|
||||
|
||||
void MarkAutoRootsBeforeJSFinalize(JSContext* cx);
|
||||
void MarkAutoRootsAfterJSFinalize();
|
||||
|
||||
#ifdef XPC_CHECK_WRAPPER_THREADSAFETY
|
||||
JSUint32 IncrementWrappedNativeThreadsafetyReportDepth()
|
||||
{return ++mWrappedNativeThreadsafetyReportDepth;}
|
||||
@ -2553,6 +2580,8 @@ private:
|
||||
nsIExceptionManager* mExceptionManager;
|
||||
nsIException* mException;
|
||||
JSBool mExceptionManagerNotAvailable;
|
||||
AutoMarkingPtr* mAutoRoots;
|
||||
|
||||
#ifdef XPC_CHECK_WRAPPER_THREADSAFETY
|
||||
JSUint32 mWrappedNativeThreadsafetyReportDepth;
|
||||
#endif
|
||||
@ -2823,6 +2852,88 @@ private:
|
||||
jsval mCheck;
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
// AutoMarkingPtr is the base class for the various AutoMarking pointer types
|
||||
// below. This system allows us to temporarily protect instances of our garbage
|
||||
// collected types after they are constructed but before they are safely
|
||||
// attached to other rooted objects.
|
||||
// This base class has pure virtual support for marking.
|
||||
|
||||
class AutoMarkingPtr
|
||||
{
|
||||
public:
|
||||
AutoMarkingPtr(XPCCallContext& ccx)
|
||||
: mNext(nsnull), mTLS(ccx.GetThreadData()) {Link();}
|
||||
|
||||
virtual ~AutoMarkingPtr() {Unlink();}
|
||||
|
||||
void Link()
|
||||
{if(!mTLS) return;
|
||||
AutoMarkingPtr** list = mTLS->GetAutoRootsAdr();
|
||||
mNext = *list; *list = this;}
|
||||
|
||||
void Unlink()
|
||||
{if(!mTLS) return;
|
||||
AutoMarkingPtr** cur = mTLS->GetAutoRootsAdr();
|
||||
while(*cur != this) {
|
||||
NS_ASSERTION(*cur, "This object not in list!");
|
||||
cur = &(*cur)->mNext;
|
||||
}
|
||||
*cur = mNext;
|
||||
mTLS = nsnull;
|
||||
}
|
||||
|
||||
virtual void MarkBeforeJSFinalize(JSContext* cx) = 0;
|
||||
virtual void MarkAfterJSFinalize() = 0;
|
||||
|
||||
protected:
|
||||
AutoMarkingPtr* mNext;
|
||||
XPCPerThreadData* mTLS;
|
||||
};
|
||||
|
||||
// More joy of macros...
|
||||
|
||||
#define DEFINE_AUTO_MARKING_PTR_TYPE(class_, type_) \
|
||||
class class_ : public AutoMarkingPtr \
|
||||
{ \
|
||||
public: \
|
||||
class_ (XPCCallContext& ccx, type_ * ptr = nsnull) \
|
||||
: AutoMarkingPtr(ccx), mPtr(ptr) {} \
|
||||
virtual ~ class_ () {} \
|
||||
\
|
||||
virtual void MarkBeforeJSFinalize(JSContext* cx) \
|
||||
{if(mPtr) mPtr->MarkBeforeJSFinalize(cx); \
|
||||
if(mNext) mNext->MarkBeforeJSFinalize(cx);} \
|
||||
\
|
||||
virtual void MarkAfterJSFinalize() \
|
||||
{if(mPtr) mPtr->Mark(); \
|
||||
if(mNext) mNext->MarkAfterJSFinalize();} \
|
||||
\
|
||||
type_ * get() const {return mPtr;} \
|
||||
operator type_ *() const {return mPtr;} \
|
||||
type_ * operator->() const {return mPtr;} \
|
||||
\
|
||||
class_ & operator =(type_ * p) \
|
||||
{mPtr = p; return *this;} \
|
||||
\
|
||||
protected: \
|
||||
type_ * mPtr; \
|
||||
};
|
||||
|
||||
// Use the macro above to define our AutoMarking types...
|
||||
|
||||
DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingNativeInterfacePtr, XPCNativeInterface)
|
||||
DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingNativeSetPtr, XPCNativeSet)
|
||||
DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingWrappedNativePtr, XPCWrappedNative)
|
||||
DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingWrappedNativeProtoPtr, XPCWrappedNativeProto)
|
||||
|
||||
// Note: It looked like I would need one of these AutoMarkingPtr types for
|
||||
// XPCNativeScriptableInfo in order to manage marking its
|
||||
// XPCNativeScriptableShared member during construction. But AFAICT we build
|
||||
// these and bind them to rooted things so immediately that this just is not
|
||||
// needed.
|
||||
|
||||
/***************************************************************************/
|
||||
// Inlines use the above - include last.
|
||||
|
||||
|
||||
@ -346,7 +346,8 @@ XPCPerThreadData::XPCPerThreadData()
|
||||
mMostRecentXPCContext(nsnull),
|
||||
mExceptionManager(nsnull),
|
||||
mException(nsnull),
|
||||
mExceptionManagerNotAvailable(JS_FALSE)
|
||||
mExceptionManagerNotAvailable(JS_FALSE),
|
||||
mAutoRoots(nsnull)
|
||||
#ifdef XPC_CHECK_WRAPPER_THREADSAFETY
|
||||
, mWrappedNativeThreadsafetyReportDepth(0)
|
||||
#endif
|
||||
@ -362,6 +363,8 @@ XPCPerThreadData::XPCPerThreadData()
|
||||
void
|
||||
XPCPerThreadData::Cleanup()
|
||||
{
|
||||
while(mAutoRoots)
|
||||
mAutoRoots->Unlink();
|
||||
NS_IF_RELEASE(mExceptionManager);
|
||||
NS_IF_RELEASE(mException);
|
||||
delete mJSContextStack;
|
||||
@ -411,6 +414,18 @@ xpc_ThreadDataDtorCB(void* ptr)
|
||||
delete data;
|
||||
}
|
||||
|
||||
void XPCPerThreadData::MarkAutoRootsBeforeJSFinalize(JSContext* cx)
|
||||
{
|
||||
if(mAutoRoots)
|
||||
mAutoRoots->MarkBeforeJSFinalize(cx);
|
||||
}
|
||||
|
||||
void XPCPerThreadData::MarkAutoRootsAfterJSFinalize()
|
||||
{
|
||||
if(mAutoRoots)
|
||||
mAutoRoots->MarkAfterJSFinalize();
|
||||
}
|
||||
|
||||
// static
|
||||
XPCPerThreadData*
|
||||
XPCPerThreadData::GetData()
|
||||
@ -513,4 +528,3 @@ XPCPerThreadData::IterateThreads(XPCPerThreadData** iteratorp)
|
||||
*iteratorp = (*iteratorp == nsnull) ? gThreads : (*iteratorp)->mNextThread;
|
||||
return *iteratorp;
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +102,9 @@ nsXPCWrappedJSClass::GetNewOrUsed(XPCCallContext& ccx, REFNSIID aIID,
|
||||
nsCOMPtr<nsIInterfaceInfo> info;
|
||||
if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info))))
|
||||
{
|
||||
if(nsXPConnect::IsISupportsDescendant(info))
|
||||
PRBool canScript;
|
||||
if(NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
|
||||
nsXPConnect::IsISupportsDescendant(info))
|
||||
{
|
||||
clazz = new nsXPCWrappedJSClass(ccx, aIID, info);
|
||||
if(!clazz->mDescriptors)
|
||||
@ -198,6 +200,25 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
|
||||
if(!OBJ_GET_PROPERTY(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
|
||||
return nsnull;
|
||||
|
||||
// Ensure that we are asking for a scriptable interface.
|
||||
// We so often ask for nsISupports that we can short-circuit the test...
|
||||
if(!aIID.Equals(NS_GET_IID(nsISupports)))
|
||||
{
|
||||
nsCOMPtr<nsIInterfaceInfoManager> iimgr;
|
||||
nsXPConnect::GetInterfaceInfoManager(getter_AddRefs(iimgr));
|
||||
if(!iimgr)
|
||||
return nsnull;
|
||||
nsCOMPtr<nsIInterfaceInfo> info;
|
||||
iimgr->GetInfoForIID(&aIID, getter_AddRefs(info));
|
||||
if(!info)
|
||||
return nsnull;
|
||||
PRBool canScript;
|
||||
if(NS_FAILED(info->IsScriptable(&canScript)) || !canScript)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// OK, it looks like we'll be calling into JS code.
|
||||
|
||||
DoPreScriptEvaluated(cx);
|
||||
|
||||
// XXX we should install an error reporter that will sent reports to
|
||||
|
||||
@ -74,6 +74,8 @@ static void DEBUG_TrackNewWrapper(XPCWrappedNative* wrapper)
|
||||
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
|
||||
if(wrapper->GetRuntime())
|
||||
wrapper->GetRuntime()->DEBUG_AddWrappedNative(wrapper);
|
||||
else
|
||||
NS_ERROR("failed to add wrapper");
|
||||
#endif
|
||||
#ifdef XPC_TRACK_WRAPPER_STATS
|
||||
DEBUG_TotalWrappedNativeCount++;
|
||||
@ -103,6 +105,8 @@ static void DEBUG_TrackDeleteWrapper(XPCWrappedNative* wrapper)
|
||||
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
|
||||
if(wrapper->GetRuntime())
|
||||
wrapper->GetRuntime()->DEBUG_RemoveWrappedNative(wrapper);
|
||||
else
|
||||
NS_ERROR("failed to remove wrapper");
|
||||
#endif
|
||||
#ifdef XPC_TRACK_WRAPPER_STATS
|
||||
DEBUG_TotalLiveWrappedNativeCount--;
|
||||
@ -210,13 +214,19 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
}
|
||||
|
||||
XPCLock* mapLock = Scope->GetRuntime()->GetMapLock();
|
||||
XPCWrappedNative* wrapper;
|
||||
|
||||
// We use an AutoMarkingPtr here because it is possible for JS gc to happen
|
||||
// after we have Init'd the wrapper but *before* we add it to the hashtable.
|
||||
// This would cause the mSet to get collected and we'd later crash. I've
|
||||
// *seen* this happen.
|
||||
AutoMarkingWrappedNativePtr wrapper(ccx);
|
||||
|
||||
Native2WrappedNativeMap* map = Scope->GetWrappedNativeMap();
|
||||
{ // scoped lock
|
||||
XPCAutoLock lock(mapLock);
|
||||
wrapper = map->Find(identity);
|
||||
NS_IF_ADDREF(wrapper);
|
||||
if(wrapper)
|
||||
wrapper->AddRef();
|
||||
}
|
||||
|
||||
if(wrapper)
|
||||
@ -282,7 +292,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
{ // scoped lock
|
||||
XPCAutoLock lock(mapLock);
|
||||
wrapper = map->Find(identity);
|
||||
NS_IF_ADDREF(wrapper);
|
||||
if(wrapper)
|
||||
wrapper->AddRef();
|
||||
}
|
||||
|
||||
if(wrapper)
|
||||
@ -299,7 +310,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
}
|
||||
}
|
||||
|
||||
XPCWrappedNativeProto* proto = nsnull;
|
||||
AutoMarkingWrappedNativeProtoPtr proto(ccx);
|
||||
|
||||
// If there is nsIClassInfo then we use a wrapper that needs a prototype.
|
||||
|
||||
@ -319,8 +330,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
}
|
||||
else
|
||||
{
|
||||
XPCNativeSet* set =
|
||||
XPCNativeSet::GetNewOrUsed(ccx, nsnull, Interface, 0);
|
||||
AutoMarkingNativeSetPtr set(ccx);
|
||||
set = XPCNativeSet::GetNewOrUsed(ccx, nsnull, Interface, 0);
|
||||
|
||||
if(!set)
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -979,8 +990,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
{
|
||||
// Oh, so now we need to move the wrapper to a different scope.
|
||||
|
||||
XPCWrappedNativeProto* oldProto = nsnull;
|
||||
XPCWrappedNativeProto* newProto = nsnull;
|
||||
AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
|
||||
AutoMarkingWrappedNativeProtoPtr newProto(ccx);
|
||||
|
||||
if(wrapper->HasProto())
|
||||
{
|
||||
@ -1175,9 +1186,9 @@ XPCWrappedNative::ExtendSet(XPCCallContext& ccx, XPCNativeInterface* aInterface)
|
||||
|
||||
if(!mSet->HasInterface(aInterface))
|
||||
{
|
||||
XPCNativeSet* newSet =
|
||||
XPCNativeSet::GetNewOrUsed(ccx, mSet, aInterface,
|
||||
mSet->GetInterfaceCount());
|
||||
AutoMarkingNativeSetPtr newSet(ccx);
|
||||
newSet = XPCNativeSet::GetNewOrUsed(ccx, mSet, aInterface,
|
||||
mSet->GetInterfaceCount());
|
||||
if(!newSet)
|
||||
return JS_FALSE;
|
||||
|
||||
|
||||
@ -171,8 +171,8 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface)
|
||||
XPCNativeInterface*
|
||||
XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
||||
{
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
XPCJSRuntime* rt = ccx.GetRuntime();
|
||||
XPCNativeInterface* iface;
|
||||
|
||||
IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
|
||||
if(!map)
|
||||
@ -222,7 +222,7 @@ XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
||||
XPCNativeInterface*
|
||||
XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, nsIInterfaceInfo* info)
|
||||
{
|
||||
XPCNativeInterface* iface;
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
|
||||
const nsIID* iid;
|
||||
if(NS_FAILED(info->GetIIDShared(&iid)) || !iid)
|
||||
@ -502,9 +502,10 @@ XPCNativeInterface::DebugDump(PRInt16 depth)
|
||||
XPCNativeSet*
|
||||
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
||||
{
|
||||
XPCNativeSet* set;
|
||||
AutoMarkingNativeSetPtr set(ccx);
|
||||
|
||||
XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
if(!iface)
|
||||
return nsnull;
|
||||
|
||||
@ -523,7 +524,9 @@ XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
||||
if(set)
|
||||
return set;
|
||||
|
||||
set = NewInstance(ccx, &iface, 1);
|
||||
// hacky way to get a XPCNativeInterface** using the AutoPtr
|
||||
XPCNativeInterface* temp[] = {iface};
|
||||
set = NewInstance(ccx, temp, 1);
|
||||
if(!set)
|
||||
return nsnull;
|
||||
|
||||
@ -550,7 +553,7 @@ XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
||||
XPCNativeSet*
|
||||
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, nsIClassInfo* classInfo)
|
||||
{
|
||||
XPCNativeSet* set;
|
||||
AutoMarkingNativeSetPtr set(ccx);
|
||||
XPCJSRuntime* rt = ccx.GetRuntime();
|
||||
|
||||
ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
|
||||
@ -598,8 +601,8 @@ XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx, nsIClassInfo* classInfo)
|
||||
{
|
||||
nsIID* iid = *(currentIID++);
|
||||
|
||||
XPCNativeInterface* iface =
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
|
||||
if(!iface)
|
||||
{
|
||||
@ -670,7 +673,7 @@ XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx,
|
||||
XPCNativeInterface* newInterface,
|
||||
PRUint16 position)
|
||||
{
|
||||
XPCNativeSet* set;
|
||||
AutoMarkingNativeSetPtr set(ccx);
|
||||
XPCJSRuntime* rt = ccx.GetRuntime();
|
||||
NativeSetMap* map = rt->GetNativeSetMap();
|
||||
if(!map)
|
||||
|
||||
@ -200,8 +200,9 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, JSObject *obj,
|
||||
nsIXPCSecurityManager::HOOK_GET_PROPERTY);
|
||||
if(sm)
|
||||
{
|
||||
XPCNativeInterface* iface = XPCNativeInterface::
|
||||
GetNewOrUsed(ccx, &NS_GET_IID(nsIXPCWrappedJSObjectGetter));
|
||||
AutoMarkingNativeInterfacePtr iface(ccx);
|
||||
iface = XPCNativeInterface::
|
||||
GetNewOrUsed(ccx, &NS_GET_IID(nsIXPCWrappedJSObjectGetter));
|
||||
|
||||
if(iface)
|
||||
{
|
||||
@ -315,14 +316,15 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
||||
|
||||
if(wrapperToReflectInterfaceNames)
|
||||
{
|
||||
AutoMarkingNativeInterfacePtr iface2(ccx);
|
||||
XPCWrappedNativeTearOff* to;
|
||||
JSObject* jso;
|
||||
|
||||
if(JSVAL_IS_STRING(idval) &&
|
||||
nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) &&
|
||||
nsnull != (iface = XPCNativeInterface::GetNewOrUsed(ccx, name)) &&
|
||||
(iface2 = XPCNativeInterface::GetNewOrUsed(ccx, name), iface2) &&
|
||||
nsnull != (to = wrapperToReflectInterfaceNames->
|
||||
FindTearOff(ccx, iface, JS_TRUE)) &&
|
||||
FindTearOff(ccx, iface2, JS_TRUE)) &&
|
||||
nsnull != (jso = to->GetJSObject()))
|
||||
|
||||
{
|
||||
@ -641,6 +643,15 @@ MarkScopeJSObjects(JSContext *cx, XPCWrappedNativeScope* scope, void *arg)
|
||||
static void
|
||||
MarkForValidWrapper(JSContext *cx, XPCWrappedNative* wrapper, void *arg)
|
||||
{
|
||||
// NOTE: It might be nice to also do the wrapper->Mark() call here too.
|
||||
// That call marks the wrapper's and wrapper's proto's interface sets.
|
||||
// We currently do that in the GC callback code. The reason we don't do that
|
||||
// here is because the bits used in that marking do unpleasant things to the
|
||||
// member counts in the interface and interface set objects. Those counts
|
||||
// are used in the DealWithDyingGCThings calls that are part of this JS GC
|
||||
// marking phase. By doing these calls later during our GC callback we
|
||||
// avoid that problem. Arguably this could be changed. But it ain't broke.
|
||||
|
||||
if(wrapper->HasProto())
|
||||
{
|
||||
JSObject* obj = wrapper->GetProto()->GetJSProtoObject();
|
||||
|
||||
@ -157,7 +157,7 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCCallContext& ccx,
|
||||
NS_ASSERTION(Scope, "bad param");
|
||||
NS_ASSERTION(ClassInfo, "bad param");
|
||||
|
||||
XPCWrappedNativeProto* proto;
|
||||
AutoMarkingWrappedNativeProtoPtr proto(ccx);
|
||||
ClassInfo2WrappedNativeProtoMap* map;
|
||||
XPCLock* lock;
|
||||
JSBool shared;
|
||||
@ -196,7 +196,8 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCCallContext& ccx,
|
||||
}
|
||||
}
|
||||
|
||||
XPCNativeSet* set = XPCNativeSet::GetNewOrUsed(ccx, ClassInfo);
|
||||
AutoMarkingNativeSetPtr set(ccx);
|
||||
set = XPCNativeSet::GetNewOrUsed(ccx, ClassInfo);
|
||||
if(!set)
|
||||
return nsnull;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user